xref: /core/sc/source/ui/view/viewfunc.cxx (revision f9ffaeaf)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <address.hxx>
21 #include <config_features.h>
22 
23 #include <scitems.hxx>
24 
25 #include <sfx2/app.hxx>
26 #include <svx/algitem.hxx>
27 #include <editeng/boxitem.hxx>
28 #include <editeng/editobj.hxx>
29 #include <editeng/langitem.hxx>
30 #include <editeng/justifyitem.hxx>
31 #include <o3tl/unit_conversion.hxx>
32 #include <sfx2/bindings.hxx>
33 #include <svl/numformat.hxx>
34 #include <svl/zforlist.hxx>
35 #include <svl/zformat.hxx>
36 #include <vcl/weld.hxx>
37 #include <vcl/virdev.hxx>
38 #include <stdlib.h>
39 #include <unotools/charclass.hxx>
40 #include <vcl/uitest/logger.hxx>
41 #include <vcl/uitest/eventdescription.hxx>
42 #include <osl/diagnose.h>
43 
44 #include <viewfunc.hxx>
45 #include <tabvwsh.hxx>
46 #include <docsh.hxx>
47 #include <attrib.hxx>
48 #include <patattr.hxx>
49 #include <sc.hrc>
50 #include <undocell.hxx>
51 #include <undoblk.hxx>
52 #include <refundo.hxx>
53 #include <olinetab.hxx>
54 #include <rangenam.hxx>
55 #include <globstr.hrc>
56 #include <global.hxx>
57 #include <stlsheet.hxx>
58 #include <editutil.hxx>
59 #include <formulacell.hxx>
60 #include <scresid.hxx>
61 #include <inputhdl.hxx>
62 #include <scmod.hxx>
63 #include <inputopt.hxx>
64 #include <compiler.hxx>
65 #include <docfunc.hxx>
66 #include <appoptio.hxx>
67 #include <sizedev.hxx>
68 #include <editable.hxx>
69 #include <scui_def.hxx>
70 #include <funcdesc.hxx>
71 #include <docuno.hxx>
72 #include <cellsuno.hxx>
73 #include <tokenarray.hxx>
74 #include <rowheightcontext.hxx>
75 #include <comphelper/lok.hxx>
76 #include <conditio.hxx>
77 #include <columnspanset.hxx>
78 #include <stringutil.hxx>
79 #include <SparklineList.hxx>
80 
81 #include <memory>
82 
ShowFilteredRows(ScDocument & rDoc,SCTAB nTab,SCCOLROW nStartNo,SCCOLROW nEndNo,bool bShow)83 static void ShowFilteredRows(ScDocument& rDoc, SCTAB nTab, SCCOLROW nStartNo, SCCOLROW nEndNo,
84                              bool bShow)
85 {
86     SCROW nFirstRow = nStartNo;
87     SCROW nLastRow = nStartNo;
88     do
89     {
90         if (!rDoc.RowFiltered(nFirstRow, nTab, nullptr, &nLastRow))
91             rDoc.ShowRows(nFirstRow, nLastRow < nEndNo ? nLastRow : nEndNo, nTab, bShow);
92         nFirstRow = nLastRow + 1;
93     } while (nFirstRow <= nEndNo);
94 }
95 
lcl_PostRepaintCondFormat(const ScConditionalFormat * pCondFmt,ScDocShell * pDocSh)96 static void lcl_PostRepaintCondFormat( const ScConditionalFormat *pCondFmt, ScDocShell *pDocSh )
97 {
98     if( pCondFmt )
99     {
100         const ScRangeList& rRanges = pCondFmt->GetRange();
101 
102         pDocSh->PostPaint( rRanges, PaintPartFlags::All );
103     }
104 }
105 
lcl_PostRepaintSparkLine(sc::SparklineList * pSparklineList,const ScRange & rRange,ScDocShell * pDocSh)106 static void lcl_PostRepaintSparkLine(sc::SparklineList* pSparklineList, const ScRange& rRange,
107                                      ScDocShell* pDocSh)
108 {
109     if (pSparklineList)
110     {
111         for (auto& rSparkLineGroup : pSparklineList->getSparklineGroups())
112         {
113             for (auto& rSparkline : pSparklineList->getSparklinesFor(rSparkLineGroup))
114             {
115                 if (rSparkline->getInputRange().Contains(rRange))
116                 {
117                     pDocSh->PostPaint(
118                         ScRange(rSparkline->getColumn(), rSparkline->getRow(), rRange.aStart.Tab()),
119                         PaintPartFlags::All, SC_PF_TESTMERGE);
120                 }
121             }
122         }
123     }
124 }
125 
ScViewFunc(vcl::Window * pParent,ScDocShell & rDocSh,ScTabViewShell * pViewShell)126 ScViewFunc::ScViewFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
127     ScTabView( pParent, rDocSh, pViewShell ),
128     bFormatValid( false )
129 {
130 }
131 
~ScViewFunc()132 ScViewFunc::~ScViewFunc()
133 {
134 }
135 
136 namespace {
137 
138 struct FormulaProcessingContext
139 {
140     std::shared_ptr<ScAddress> aPos;
141     std::shared_ptr<ScCompiler> aComp;
142     std::shared_ptr<ScDocShellModificator> aModificator;
143     std::shared_ptr<ScTokenArray> pArr;
144     std::shared_ptr<ScTokenArray> pArrFirst;
145 
146     const EditTextObject* pData;
147     ScMarkData aMark;
148     ScViewFunc& rViewFunc;
149 
150     OUString aCorrectedFormula;
151     OUString aFormula;
152     OUString aString;
153 
154     SCCOL nCol;
155     SCROW nRow;
156     SCTAB nTab;
157 
158     bool bMatrixExpand;
159     bool bNumFmtChanged;
160     bool bRecord;
161 
GetViewData__anonf45594590111::FormulaProcessingContext162     ScViewData& GetViewData() const
163     {
164         return rViewFunc.GetViewData();
165     }
166 
GetDocFunc__anonf45594590111::FormulaProcessingContext167     ScDocFunc& GetDocFunc() const
168     {
169         return GetViewData().GetDocFunc();
170     }
171 
GetDoc__anonf45594590111::FormulaProcessingContext172     ScDocument& GetDoc() const
173     {
174         return GetViewData().GetDocument();
175     }
176 };
177 
collectUIInformation(std::map<OUString,OUString> && aParameters,const OUString & rAction)178 void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
179 {
180     EventDescription aDescription;
181     aDescription.aID = "grid_window";
182     aDescription.aAction = rAction;
183     aDescription.aParameters = std::move(aParameters);
184     aDescription.aParent = "MainWindow";
185     aDescription.aKeyWord = "ScGridWinUIObject";
186 
187     UITestLogger::getInstance().logEvent(aDescription);
188 }
189 
190 }
191 
StartFormatArea()192 void ScViewFunc::StartFormatArea()
193 {
194     //  anything to do?
195     if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
196         return;
197 
198     //  start only with single cell (marked or cursor position)
199     ScRange aMarkRange;
200     bool bOk = (GetViewData().GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE);
201     if ( bOk && aMarkRange.aStart != aMarkRange.aEnd )
202         bOk = false;
203 
204     if (bOk)
205     {
206         bFormatValid = true;
207         aFormatSource = aMarkRange.aStart;
208         aFormatArea = ScRange( aFormatSource );
209     }
210     else
211         bFormatValid = false;       // discard old range
212 }
213 
TestFormatArea(SCCOL nCol,SCROW nRow,SCTAB nTab,bool bAttrChanged)214 bool ScViewFunc::TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, bool bAttrChanged )
215 {
216     //  anything to do?
217     if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
218         return false;
219 
220     //  Test: treat input with numberformat (bAttrChanged) always as new Attribute
221     //  (discard old Area ). If not wanted, discard if-statement
222     if ( bAttrChanged )
223     {
224         StartFormatArea();
225         return false;
226     }
227 
228     //! Test if cell empty ???
229 
230     bool bFound = false;
231     ScRange aNewRange = aFormatArea;
232     if ( bFormatValid && nTab == aFormatSource.Tab() )
233     {
234         if ( nRow >= aFormatArea.aStart.Row() && nRow <= aFormatArea.aEnd.Row() )
235         {
236             //  within range?
237             if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
238             {
239                 bFound = true;          // do not change range
240             }
241             //  left ?
242             if ( nCol+1 == aFormatArea.aStart.Col() )
243             {
244                 bFound = true;
245                 aNewRange.aStart.SetCol( nCol );
246             }
247             //  right ?
248             if ( nCol == aFormatArea.aEnd.Col()+1 )
249             {
250                 bFound = true;
251                 aNewRange.aEnd.SetCol( nCol );
252             }
253         }
254         if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
255         {
256             //  top ?
257             if ( nRow+1 == aFormatArea.aStart.Row() )
258             {
259                 bFound = true;
260                 aNewRange.aStart.SetRow( nRow );
261             }
262             //  bottom ?
263             if ( nRow == aFormatArea.aEnd.Row()+1 )
264             {
265                 bFound = true;
266                 aNewRange.aEnd.SetRow( nRow );
267             }
268         }
269     }
270 
271     if (bFound)
272         aFormatArea = aNewRange;    // extend
273     else
274         bFormatValid = false;       // outside of range -> break
275 
276     return bFound;
277 }
278 
DoAutoAttributes(SCCOL nCol,SCROW nRow,SCTAB nTab,bool bAttrChanged)279 void ScViewFunc::DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
280                                    bool bAttrChanged )
281 {
282     ScDocShell* pDocSh = GetViewData().GetDocShell();
283     ScDocument& rDoc = pDocSh->GetDocument();
284 
285     const ScPatternAttr* pSource = rDoc.GetPattern(
286                             aFormatSource.Col(), aFormatSource.Row(), nTab );
287     if ( !pSource->GetItem(ATTR_MERGE).IsMerged() )
288     {
289         ScRange aRange( nCol, nRow, nTab, nCol, nRow, nTab );
290         ScMarkData aMark(rDoc.GetSheetLimits());
291         aMark.SetMarkArea( aRange );
292 
293         ScDocFunc &rFunc = GetViewData().GetDocFunc();
294 
295         // pOldPattern is only valid until call to ApplyAttributes!
296         const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
297         const ScStyleSheet* pSrcStyle = pSource->GetStyleSheet();
298         if ( pSrcStyle && pSrcStyle != pOldPattern->GetStyleSheet() )
299             rFunc.ApplyStyle( aMark, pSrcStyle->GetName(), false );
300 
301         rFunc.ApplyAttributes( aMark, *pSource, false );
302     }
303 
304     if ( bAttrChanged )                             // value entered with number format?
305         aFormatSource.Set( nCol, nRow, nTab );      // then set a new source
306 }
307 
308 //      additional routines
309 
setupSizeDeviceProviderForColWidth(ScSizeDeviceProvider & rProv,Fraction & rZoomX,Fraction & rZoomY,double & rPPTX,double & rPPTY)310 void ScViewData::setupSizeDeviceProviderForColWidth(ScSizeDeviceProvider& rProv, Fraction& rZoomX, Fraction& rZoomY, double& rPPTX, double &rPPTY)
311 {
312     if (rProv.IsPrinter())
313     {
314         rPPTX = rProv.GetPPTX();
315         rPPTY = rProv.GetPPTY();
316         rZoomX = rZoomY = Fraction(1, 1);
317     }
318     else
319     {
320         rPPTX = GetPPTX();
321         rPPTY = GetPPTY();
322         rZoomX = GetZoomX();
323         rZoomY = GetZoomY();
324     }
325 }
326 
GetOptimalColWidth(SCCOL nCol,SCTAB nTab,bool bFormula)327 sal_uInt16 ScViewFunc::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, bool bFormula )
328 {
329     ScDocShell* pDocSh = GetViewData().GetDocShell();
330     ScDocument& rDoc = pDocSh->GetDocument();
331     ScMarkData& rMark = GetViewData().GetMarkData();
332 
333     ScSizeDeviceProvider aProv(pDocSh);
334 
335     Fraction aZoomX, aZoomY;
336     double nPPTX, nPPTY;
337     GetViewData().setupSizeDeviceProviderForColWidth(aProv, aZoomX, aZoomY, nPPTX, nPPTY);
338 
339     sal_uInt16 nTwips = rDoc.GetOptimalColWidth( nCol, nTab, aProv.GetDevice(),
340                                 nPPTX, nPPTY, aZoomX, aZoomY, bFormula, &rMark );
341     return nTwips;
342 }
343 
SelectionEditable(bool * pOnlyNotBecauseOfMatrix)344 bool ScViewFunc::SelectionEditable( bool* pOnlyNotBecauseOfMatrix /* = NULL */ )
345 {
346     bool bRet;
347     ScDocument& rDoc = GetViewData().GetDocument();
348     ScMarkData& rMark = GetViewData().GetMarkData();
349     if (rMark.IsMarked() || rMark.IsMultiMarked())
350         bRet = rDoc.IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix );
351     else
352     {
353         SCCOL nCol = GetViewData().GetCurX();
354         SCROW nRow = GetViewData().GetCurY();
355         SCTAB nTab = GetViewData().GetTabNo();
356         bRet = rDoc.IsBlockEditable( nTab, nCol, nRow, nCol, nRow,
357             pOnlyNotBecauseOfMatrix );
358     }
359     return bRet;
360 }
361 
lcl_FunctionKnown(sal_uInt16 nOpCode)362 static bool lcl_FunctionKnown( sal_uInt16 nOpCode )
363 {
364     const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
365     if ( pFuncList )
366     {
367         sal_uLong nCount = pFuncList->GetCount();
368         for (sal_uLong i=0; i<nCount; i++)
369             if ( pFuncList->GetFunction(i)->nFIndex == nOpCode )
370                 return true;
371     }
372     return false;
373 }
374 
lcl_AddFunction(ScAppOptions & rAppOpt,sal_uInt16 nOpCode)375 static bool lcl_AddFunction( ScAppOptions& rAppOpt, sal_uInt16 nOpCode )
376 {
377     sal_uInt16 nOldCount = rAppOpt.GetLRUFuncListCount();
378     sal_uInt16* pOldList = rAppOpt.GetLRUFuncList();
379     sal_uInt16 nPos;
380     for (nPos=0; nPos<nOldCount; nPos++)
381         if (pOldList[nPos] == nOpCode)          // is the function already in the list?
382         {
383             if ( nPos == 0 )
384                 return false;                   // already at the top -> no change
385 
386             //  count doesn't change, so the original array is modified
387 
388             for (sal_uInt16 nCopy=nPos; nCopy>0; nCopy--)
389                 pOldList[nCopy] = pOldList[nCopy-1];
390             pOldList[0] = nOpCode;
391 
392             return true;                        // list has changed
393         }
394 
395     if ( !lcl_FunctionKnown( nOpCode ) )
396         return false;                           // not in function list -> no change
397 
398     sal_uInt16 nNewCount = std::min( static_cast<sal_uInt16>(nOldCount + 1), sal_uInt16(LRU_MAX) );
399     sal_uInt16 nNewList[LRU_MAX];
400     nNewList[0] = nOpCode;
401     for (nPos=1; nPos<nNewCount; nPos++)
402         nNewList[nPos] = pOldList[nPos-1];
403     rAppOpt.SetLRUFuncList( nNewList, nNewCount );
404 
405     return true;                                // list has changed
406 }
407 
408 namespace HelperNotifyChanges
409 {
NotifyIfChangesListeners(const ScDocShell & rDocShell,const ScMarkData & rMark,SCCOL nCol,SCROW nRow,const OUString & rType=u"cell-change"_ustr)410     static void NotifyIfChangesListeners(const ScDocShell &rDocShell, const ScMarkData& rMark,
411                                          SCCOL nCol, SCROW nRow, const OUString& rType = u"cell-change"_ustr)
412     {
413         ScModelObj* pModelObj = rDocShell.GetModel();
414 
415         ScRangeList aChangeRanges;
416         for (const auto& rTab : rMark)
417             aChangeRanges.push_back( ScRange( nCol, nRow, rTab ) );
418 
419         if (getMustPropagateChangesModel(pModelObj))
420             Notify(*pModelObj, aChangeRanges, rType);
421         else
422         {
423             Notify(*pModelObj, aChangeRanges, isDataAreaInvalidateType(rType)
424                     ? u"data-area-invalidate"_ustr : u"data-area-extend"_ustr);
425         }
426     }
427 }
428 
429 namespace
430 {
431     class AutoCorrectQuery : public weld::MessageDialogController
432     {
433     private:
434         std::unique_ptr<weld::TextView> m_xError;
435     public:
AutoCorrectQuery(weld::Window * pParent,const OUString & rFormula)436         AutoCorrectQuery(weld::Window* pParent, const OUString& rFormula)
437             : weld::MessageDialogController(pParent, u"modules/scalc/ui/warnautocorrect.ui"_ustr, u"WarnAutoCorrect"_ustr, u"grid"_ustr)
438             , m_xError(m_xBuilder->weld_text_view(u"error"_ustr))
439         {
440             m_xDialog->set_default_response(RET_YES);
441 
442             const int nMaxWidth = m_xError->get_approximate_digit_width() * 65;
443             const int nMaxHeight = m_xError->get_height_rows(6);
444             m_xError->set_size_request(nMaxWidth, nMaxHeight);
445 
446             m_xError->set_text(rFormula);
447         }
448     };
449 }
450 namespace
451 {
452     void runAutoCorrectQueryAsync(std::shared_ptr<FormulaProcessingContext> context);
453 
performAutoFormatAndUpdate(std::u16string_view rString,const ScMarkData & rMark,SCCOL nCol,SCROW nRow,SCTAB nTab,bool bNumFmtChanged,bool bRecord,const std::shared_ptr<ScDocShellModificator> & pModificator,ScViewFunc & rViewFunc)454     void performAutoFormatAndUpdate(std::u16string_view rString, const ScMarkData& rMark, SCCOL nCol,
455                                     SCROW nRow, SCTAB nTab, bool bNumFmtChanged, bool bRecord,
456                                     const std::shared_ptr<ScDocShellModificator>& pModificator,
457                                     ScViewFunc& rViewFunc)
458     {
459         bool bAutoFormat = rViewFunc.TestFormatArea(nCol, nRow, nTab, bNumFmtChanged);
460 
461         if (bAutoFormat)
462             rViewFunc.DoAutoAttributes(nCol, nRow, nTab, bNumFmtChanged);
463 
464         ScViewData& rViewData = rViewFunc.GetViewData();
465         ScDocShell* pDocSh = rViewData.GetDocShell();
466         pDocSh->UpdateOle(rViewData);
467 
468         const OUString aType(rString.empty() ? u"delete-content" : u"cell-change");
469         HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow, aType);
470 
471         if (bRecord)
472         {
473             ScDocFunc &rFunc = rViewData.GetDocFunc();
474             rFunc.EndListAction();
475         }
476 
477         pModificator->SetDocumentModified();
478         ScDocument& rDoc = rViewData.GetDocument();
479         lcl_PostRepaintCondFormat(rDoc.GetCondFormat(nCol, nRow, nTab), pDocSh);
480         lcl_PostRepaintSparkLine(rDoc.GetSparklineList(nTab), ScRange(nCol, nRow, nTab), pDocSh);
481     }
482 
finalizeFormulaProcessing(std::shared_ptr<FormulaProcessingContext> context)483     void finalizeFormulaProcessing(std::shared_ptr<FormulaProcessingContext> context)
484     {
485         // to be used in multiple tabs, the formula must be compiled anew
486         // via ScFormulaCell copy-ctor because of RangeNames,
487         // the same code-array for all cells is not possible.
488         // If the array has an error, (it) must be RPN-erased in the newly generated
489         // cells and the error be set explicitly, so that
490         // via FormulaCell copy-ctor and Interpreter it will be, when possible,
491         // ironed out again, too intelligent... e.g.: =1))
492         FormulaError nError = context->pArr->GetCodeError();
493         if ( nError == FormulaError::NONE )
494         {
495             //  update list of recent functions with all functions that
496             //  are not within parentheses
497 
498             ScModule* pScMod = SC_MOD();
499             ScAppOptions aAppOpt = pScMod->GetAppOptions();
500             bool bOptChanged = false;
501 
502             formula::FormulaToken** ppToken = context->pArr->GetArray();
503             sal_uInt16 nTokens = context->pArr->GetLen();
504             sal_uInt16 nLevel = 0;
505             for (sal_uInt16 nTP=0; nTP<nTokens; nTP++)
506             {
507                 formula::FormulaToken* pTok = ppToken[nTP];
508                 OpCode eOp = pTok->GetOpCode();
509                 if ( eOp == ocOpen )
510                     ++nLevel;
511                 else if ( eOp == ocClose && nLevel )
512                     --nLevel;
513                 if ( nLevel == 0 && pTok->IsFunction() &&
514                         lcl_AddFunction( aAppOpt, sal::static_int_cast<sal_uInt16>( eOp ) ) )
515                     bOptChanged = true;
516             }
517 
518             if ( bOptChanged )
519             {
520                 pScMod->SetAppOptions(aAppOpt);
521             }
522 
523             if (context->bMatrixExpand)
524             {
525                 // If the outer function/operator returns an array/matrix then
526                 // enter a matrix formula. ScViewFunc::EnterMatrix() takes care
527                 // of selection/mark of the result dimensions or preselected
528                 // mark. If the user wanted less or a single cell then should
529                 // mark such prior to entering the formula.
530                 const formula::FormulaToken* pToken = context->pArr->LastRPNToken();
531                 if (pToken && (formula::FormulaCompiler::IsMatrixFunction( pToken->GetOpCode())
532                             || pToken->IsInForceArray()))
533                 {
534                     // Discard this (still empty here) Undo action,
535                     // EnterMatrix() will create its own.
536                     if (context->bRecord)
537                         context->GetDocFunc().EndListAction();
538 
539                     // Use corrected formula string.
540                     context->rViewFunc.EnterMatrix( context->aFormula, context->GetDoc().GetGrammar());
541 
542                     return;
543                 }
544             }
545         }
546 
547         ScFormulaCell aCell(context->GetDoc(), *context->aPos, std::move(*context->pArr), formula::FormulaGrammar::GRAM_DEFAULT, ScMatrixMode::NONE);
548 
549         SCTAB i;
550         SvNumberFormatter* pFormatter = context->GetDoc().GetFormatTable();
551         for (const auto& rTab : context->aMark)
552         {
553             i = rTab;
554             context->aPos->SetTab( i );
555             const sal_uInt32 nIndex = context->GetDoc().GetAttr(
556                         context->nCol, context->nRow, i, ATTR_VALUE_FORMAT )->GetValue();
557             const SvNumFormatType nType = pFormatter->GetType( nIndex);
558             if (nType == SvNumFormatType::TEXT ||
559                     ((context->aString[0] == '+' || context->aString[0] == '-') && nError != FormulaError::NONE && context->aString == context->aFormula))
560             {
561                 if ( context->pData )
562                 {
563                     // A clone of context->pData will be stored in the cell.
564                     context->GetDocFunc().SetEditCell(*(context->aPos), *context->pData, true);
565                 }
566                 else
567                     context->GetDocFunc().SetStringCell(*(context->aPos), context->aFormula, true);
568             }
569             else
570             {
571                 ScFormulaCell* pCell = new ScFormulaCell( aCell, context->GetDoc(), *(context->aPos) );
572                 if ( nError != FormulaError::NONE )
573                 {
574                     pCell->GetCode()->DelRPN();
575                     pCell->SetErrCode( nError );
576                     if(pCell->GetCode()->IsHyperLink())
577                         pCell->GetCode()->SetHyperLink(false);
578                 }
579                 if (nType == SvNumFormatType::LOGICAL)
580                 {
581                     // Reset to General so the actual format can be determined
582                     // after the cell has been interpreted. A sticky boolean
583                     // number format is highly likely unwanted... see tdf#75650.
584                     // General of same locale as current number format.
585                     const SvNumberformat* pEntry = pFormatter->GetEntry( nIndex);
586                     const LanguageType nLang = (pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge);
587                     const sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::NUMBER, nLang);
588                     ScPatternAttr aPattern(context->GetDoc().getCellAttributeHelper());
589                     aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nFormat));
590                     ScMarkData aMark(context->GetDoc().GetSheetLimits());
591                     aMark.SelectTable( i, true);
592                     aMark.SetMarkArea( ScRange( *(context->aPos)));
593                     context->GetDocFunc().ApplyAttributes( aMark, aPattern, false);
594                     context->bNumFmtChanged = true;
595                 }
596                 context->GetDocFunc().SetFormulaCell(*(context->aPos), pCell, true);
597             }
598         }
599 
600         performAutoFormatAndUpdate(context->aString, context->aMark, context->nCol,
601                                    context->nRow, context->nTab, context->bNumFmtChanged,
602                                    context->bRecord, context->aModificator, context->rViewFunc);
603     }
604 
parseAndCorrectFormula(std::shared_ptr<FormulaProcessingContext> context)605     void parseAndCorrectFormula(std::shared_ptr<FormulaProcessingContext> context)
606     {
607         bool bAddEqual = false;
608         context->pArr = context->aComp->CompileString(context->aFormula);
609         bool bCorrected = context->aComp->IsCorrected();
610 
611         if (bCorrected) {
612             context->pArrFirst = context->pArr;
613             context->pArr = context->aComp->CompileString(context->aComp->GetCorrectedFormula());
614         }
615 
616         if (context->pArr->GetCodeError() == FormulaError::NONE) {
617             bAddEqual = true;
618             context->aComp->CompileTokenArray();
619             bCorrected |= context->aComp->IsCorrected();
620         }
621 
622         if (bCorrected) {
623             context->aCorrectedFormula = bAddEqual ? "=" + context->aComp->GetCorrectedFormula()
624                                                    : context->aComp->GetCorrectedFormula();
625             if (context->aCorrectedFormula.getLength() == 1) {
626                 // empty formula, just '='
627                 if (context->pArrFirst)
628                     context->pArr = context->pArrFirst;
629             }
630             else
631             {
632                 runAutoCorrectQueryAsync(context);
633                 return;
634             }
635         }
636         finalizeFormulaProcessing(context);
637     }
638 
runAutoCorrectQueryAsync(std::shared_ptr<FormulaProcessingContext> context)639     void runAutoCorrectQueryAsync(std::shared_ptr<FormulaProcessingContext> context)
640     {
641         auto aQueryBox = std::make_shared<AutoCorrectQuery>(context->GetViewData().GetDialogParent(), context->aCorrectedFormula);
642         weld::DialogController::runAsync(aQueryBox, [context] (int nResult)
643         {
644             if (nResult == RET_YES) {
645                 context->aFormula = context->aCorrectedFormula;
646                 parseAndCorrectFormula(context);
647             } else {
648                 if (context->pArrFirst)
649                     context->pArr = context->pArrFirst;
650 
651                 finalizeFormulaProcessing(context);
652             }
653         });
654     }
655 }
656 
657 //      actual functions
658 
659 //  input - undo OK
EnterData(SCCOL nCol,SCROW nRow,SCTAB nTab,const OUString & rString,const EditTextObject * pData,bool bMatrixExpand)660 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
661                             const OUString& rString,
662                             const EditTextObject* pData,
663                             bool bMatrixExpand )
664 {
665     ScDocument& rDoc = GetViewData().GetDocument();
666     ScMarkData rMark(GetViewData().GetMarkData());
667     bool bRecord = rDoc.IsUndoEnabled();
668     SCTAB i;
669 
670     ScDocShell* pDocSh = GetViewData().GetDocShell();
671     ScDocFunc &rFunc = GetViewData().GetDocFunc();
672     std::shared_ptr<ScDocShellModificator> xModificator = std::make_shared<ScDocShellModificator>(*pDocSh);
673 
674     ScEditableTester aTester( rDoc, nCol,nRow, nCol,nRow, rMark );
675     if (!aTester.IsEditable())
676     {
677         ErrorMessage(aTester.GetMessageId());
678         PaintArea(nCol, nRow, nCol, nRow);        // possibly the edit-engine is still painted there
679         return;
680     }
681 
682     if ( bRecord )
683         rFunc.EnterListAction( STR_UNDO_ENTERDATA );
684 
685     bool bFormula = false;
686 
687     // do not check formula if it is a text cell
688     sal_uInt32 format = rDoc.GetNumberFormat( nCol, nRow, nTab );
689     SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
690     // a single '=' character is handled as string (needed for special filters)
691     if ( pFormatter->GetType(format) != SvNumFormatType::TEXT && rString.getLength() > 1 )
692     {
693         if ( rString[0] == '=' )
694         {
695             // handle as formula
696             bFormula = true;
697         }
698         else if ( rString[0] == '+' || rString[0] == '-' )
699         {
700             // if there is more than one leading '+' or '-' character, remove the additional ones
701             sal_Int32 nIndex = 1;
702             sal_Int32 nLen = rString.getLength();
703             while ( nIndex < nLen && ( rString[ nIndex ] == '+' || rString[ nIndex ] == '-' ) )
704             {
705                 ++nIndex;
706             }
707             OUString aString = rString.replaceAt( 1, nIndex - 1, u"" );
708 
709             // if the remaining part without the leading '+' or '-' character
710             // is non-empty and not a number, handle as formula
711             if ( aString.getLength() > 1 )
712             {
713                 double fNumber = 0;
714                 if ( !pFormatter->IsNumberFormat( aString, format, fNumber ) )
715                 {
716                     bFormula = true;
717                 }
718             }
719         }
720     }
721 
722     bool bNumFmtChanged = false;
723     if ( bFormula )
724     {   // formula, compile with autoCorrection
725         i = rMark.GetFirstSelected();
726         auto aPosPtr = std::make_shared<ScAddress>(nCol, nRow, i);
727         auto aCompPtr = std::make_shared<ScCompiler>(rDoc, *aPosPtr, rDoc.GetGrammar(), true, false);
728 
729         //2do: enable/disable autoCorrection via calcoptions
730         aCompPtr->SetAutoCorrection( true );
731         if ( rString[0] == '+' || rString[0] == '-' )
732         {
733             aCompPtr->SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK );
734         }
735 
736         OUString aFormula( rString );
737 
738         FormulaProcessingContext context_instance{
739             aPosPtr, aCompPtr, xModificator,  nullptr,        nullptr,        pData,
740             rMark,   *this,    OUString(),    aFormula,       rString,        nCol,
741             nRow,    nTab,     bMatrixExpand, bNumFmtChanged, bRecord
742         };
743 
744         parseAndCorrectFormula(std::make_shared<FormulaProcessingContext>(context_instance));
745     }
746     else
747     {
748         ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
749         for (const auto& rTab : rMark)
750         {
751             bool bNumFmtSet = false;
752             const ScAddress aScAddress(nCol, nRow, rTab);
753 
754             // tdf#104902 - handle embedded newline
755             if (ScStringUtil::isMultiline(rString))
756             {
757                 rEngine.SetTextCurrentDefaults(rString);
758                 rDoc.SetEditText(aScAddress, rEngine.CreateTextObject());
759                 pDocSh->AdjustRowHeight(nRow, nRow, rTab);
760             }
761             else
762             {
763                 rFunc.SetNormalString(bNumFmtSet, aScAddress, rString, false);
764             }
765 
766             if (bNumFmtSet)
767             {
768                 /* FIXME: if set on any sheet results in changed only on
769                  * sheet nTab for TestFormatArea() and DoAutoAttributes() */
770                 bNumFmtChanged = true;
771             }
772         }
773         performAutoFormatAndUpdate(rString, rMark, nCol, nRow, nTab, bNumFmtChanged, bRecord, xModificator, *this);
774     }
775 }
776 
777 // enter value in single cell (on nTab only)
778 
EnterValue(SCCOL nCol,SCROW nRow,SCTAB nTab,const double & rValue)779 void ScViewFunc::EnterValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rValue )
780 {
781     ScDocument& rDoc = GetViewData().GetDocument();
782     ScDocShell* pDocSh = GetViewData().GetDocShell();
783 
784     if (!pDocSh)
785         return;
786 
787     bool bUndo(rDoc.IsUndoEnabled());
788     ScDocShellModificator aModificator( *pDocSh );
789 
790     ScEditableTester aTester( rDoc, nTab, nCol,nRow, nCol,nRow );
791     if (aTester.IsEditable())
792     {
793         ScAddress aPos( nCol, nRow, nTab );
794         ScCellValue aUndoCell;
795         if (bUndo)
796             aUndoCell.assign(rDoc, aPos);
797 
798         rDoc.SetValue( nCol, nRow, nTab, rValue );
799 
800         // because of ChangeTrack after change in document
801         if (bUndo)
802         {
803             pDocSh->GetUndoManager()->AddUndoAction(
804                 std::make_unique<ScUndoEnterValue>(pDocSh, aPos, aUndoCell, rValue));
805         }
806 
807         pDocSh->PostPaintCell( aPos );
808         pDocSh->UpdateOle(GetViewData());
809         aModificator.SetDocumentModified();
810     }
811     else
812         ErrorMessage(aTester.GetMessageId());
813 }
814 
EnterData(SCCOL nCol,SCROW nRow,SCTAB nTab,const EditTextObject & rData,bool bTestSimple)815 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
816                             const EditTextObject& rData, bool bTestSimple )
817 {
818     ScDocShell* pDocSh = GetViewData().GetDocShell();
819     ScMarkData& rMark = GetViewData().GetMarkData();
820     ScDocument& rDoc = pDocSh->GetDocument();
821     bool bRecord = rDoc.IsUndoEnabled();
822 
823     ScDocShellModificator aModificator( *pDocSh );
824 
825     ScEditableTester aTester( rDoc, nTab, nCol,nRow, nCol,nRow );
826     if (aTester.IsEditable())
827     {
828 
829         //      test for attribute
830 
831         bool bSimple = false;
832         bool bCommon = false;
833         std::unique_ptr<ScPatternAttr> pCellAttrs;
834         OUString aString;
835 
836         const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
837         ScTabEditEngine aEngine( *pOldPattern, rDoc.GetEnginePool(), &rDoc );
838         aEngine.SetTextCurrentDefaults(rData);
839 
840         if (bTestSimple)                    // test, if simple string without attribute
841         {
842             ScEditAttrTester aAttrTester( &aEngine );
843             bSimple = !aAttrTester.NeedsObject();
844             bCommon = aAttrTester.NeedsCellAttr();
845 
846             // formulas have to be recognized even if they're formatted
847             // (but common attributes are still collected)
848 
849             if (!bSimple)
850             {
851                 OUString aParStr(aEngine.GetText( 0 ));
852                 if ( aParStr[0] == '=' )
853                     bSimple = true;
854             }
855 
856             if (bCommon)                // attribute for tab
857             {
858                 pCellAttrs.reset(new ScPatternAttr( *pOldPattern ));
859                 pCellAttrs->GetFromEditItemSet( &aAttrTester.GetAttribs() );
860                 //! remove common attributes from EditEngine?
861             }
862         }
863 
864         // #i97726# always get text for "repeat" of undo action
865         aString = ScEditUtil::GetMultilineString(aEngine);
866 
867         //      undo
868 
869         std::unique_ptr<EditTextObject> pUndoData;
870         ScUndoEnterData::ValuesType aOldValues;
871 
872         if (bRecord && !bSimple)
873         {
874             for (const auto& rTab : rMark)
875             {
876                 ScUndoEnterData::Value aOldValue;
877                 aOldValue.mnTab = rTab;
878                 aOldValue.maCell.assign(rDoc, ScAddress(nCol, nRow, rTab));
879                 aOldValues.push_back(aOldValue);
880             }
881 
882             pUndoData = rData.Clone();
883         }
884 
885         //      enter data
886 
887         if (bCommon)
888             rDoc.ApplyPattern(nCol,nRow,nTab,*pCellAttrs);         //! undo
889 
890         if (bSimple)
891         {
892             if (bCommon)
893                 AdjustRowHeight(nRow,nRow,true);
894 
895             EnterData( nCol, nRow, nTab, aString, nullptr, true /*bMatrixExpand*/);
896         }
897         else
898         {
899             for (const auto& rTab : rMark)
900             {
901                 ScAddress aPos(nCol, nRow, rTab);
902                 rDoc.SetEditText(aPos, rData, rDoc.GetEditPool());
903             }
904 
905             if ( bRecord )
906             {   //  because of ChangeTrack current first
907                 pDocSh->GetUndoManager()->AddUndoAction(
908                     std::make_unique<ScUndoEnterData>(pDocSh, ScAddress(nCol,nRow,nTab), aOldValues, aString, std::move(pUndoData)));
909             }
910 
911             HideAllCursors();
912 
913             AdjustRowHeight(nRow,nRow,true);
914 
915             for (const auto& rTab : rMark)
916                 pDocSh->PostPaintCell( nCol, nRow, rTab );
917 
918             ShowAllCursors();
919 
920             pDocSh->UpdateOle(GetViewData());
921 
922             bool bIsEmpty = rData.GetParagraphCount() == 0
923                 || (rData.GetParagraphCount() == 1 && !rData.HasText(0));
924             const OUString aType(bIsEmpty ? u"delete-content" : u"cell-change");
925             HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow, aType);
926 
927             aModificator.SetDocumentModified();
928         }
929         lcl_PostRepaintCondFormat( rDoc.GetCondFormat( nCol, nRow, nTab ), pDocSh );
930     }
931     else
932     {
933         ErrorMessage(aTester.GetMessageId());
934         PaintArea( nCol, nRow, nCol, nRow );        // possibly the edit-engine is still painted there
935     }
936 }
937 
EnterDataAtCursor(const OUString & rString)938 void ScViewFunc::EnterDataAtCursor( const OUString& rString )
939 {
940     SCCOL nPosX = GetViewData().GetCurX();
941     SCROW nPosY = GetViewData().GetCurY();
942     SCTAB nTab = GetViewData().GetTabNo();
943 
944     EnterData( nPosX, nPosY, nTab, rString );
945     // tdf#154174: update repeated data in the cell
946     GetViewData().GetViewShell()->UpdateInputHandler();
947 }
948 
EnterMatrix(const OUString & rString,::formula::FormulaGrammar::Grammar eGram)949 void ScViewFunc::EnterMatrix( const OUString& rString, ::formula::FormulaGrammar::Grammar eGram )
950 {
951     ScViewData& rData = GetViewData();
952     const SCCOL nCol = rData.GetCurX();
953     const SCROW nRow = rData.GetCurY();
954     const ScMarkData& rMark = rData.GetMarkData();
955     if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
956     {
957         //  nothing marked -> temporarily calculate block
958         //  with size of result formula to get the size
959 
960         ScDocument& rDoc = rData.GetDocument();
961         SCTAB nTab = rData.GetTabNo();
962         ScFormulaCell aFormCell( rDoc, ScAddress(nCol,nRow,nTab), rString, eGram, ScMatrixMode::Formula );
963 
964         SCSIZE nSizeX;
965         SCSIZE nSizeY;
966         aFormCell.GetResultDimensions( nSizeX, nSizeY );
967         if ( nSizeX != 0 && nSizeY != 0 &&
968              nCol+nSizeX-1 <= sal::static_int_cast<SCSIZE>(rDoc.MaxCol()) &&
969              nRow+nSizeY-1 <= sal::static_int_cast<SCSIZE>(rDoc.MaxRow()) )
970         {
971             ScRange aResult( nCol, nRow, nTab,
972                              sal::static_int_cast<SCCOL>(nCol+nSizeX-1),
973                              sal::static_int_cast<SCROW>(nRow+nSizeY-1), nTab );
974             MarkRange( aResult, false );
975         }
976     }
977 
978     ScRange aRange;
979     if (rData.GetSimpleArea(aRange) == SC_MARK_SIMPLE)
980     {
981         ScDocShell* pDocSh = rData.GetDocShell();
982         bool bSuccess = pDocSh->GetDocFunc().EnterMatrix(
983             aRange, &rMark, nullptr, rString, false, false, OUString(), eGram );
984         if (bSuccess)
985             pDocSh->UpdateOle(GetViewData());
986         else
987             PaintArea(nCol, nRow, nCol, nRow);        // possibly the edit-engine is still painted there
988     }
989     else
990         ErrorMessage(STR_NOMULTISELECT);
991 }
992 
GetSelectionScriptType()993 SvtScriptType ScViewFunc::GetSelectionScriptType()
994 {
995     SvtScriptType nScript = SvtScriptType::NONE;
996 
997     ScDocument& rDoc = GetViewData().GetDocument();
998     const ScMarkData& rMark = GetViewData().GetMarkData();
999     if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
1000     {
1001         // no selection -> cursor
1002 
1003         nScript = rDoc.GetScriptType( GetViewData().GetCurX(),
1004                             GetViewData().GetCurY(), GetViewData().GetTabNo());
1005     }
1006     else
1007     {
1008         ScRangeList aRanges;
1009         rMark.FillRangeListWithMarks( &aRanges, false );
1010         nScript = rDoc.GetRangeScriptType(aRanges);
1011     }
1012 
1013     if (nScript == SvtScriptType::NONE)
1014         nScript = ScGlobal::GetDefaultScriptType();
1015 
1016     return nScript;
1017 }
1018 
1019 static void ShrinkToDataArea(ScMarkData& rFuncMark, ScDocument& rDoc);
1020 
GetSelectionPattern()1021 const ScPatternAttr* ScViewFunc::GetSelectionPattern()
1022 {
1023     // Don't use UnmarkFiltered in slot state functions, for performance reasons.
1024     // The displayed state is always that of the whole selection including filtered rows.
1025 
1026     ScMarkData aMark = GetViewData().GetMarkData();
1027     ScDocument& rDoc = GetViewData().GetDocument();
1028 
1029     // tdf#155368 if the selection is the whole sheet, we need to shrink the mark area, otherwise
1030     // we will not return a consistent result
1031     // (consistent compared to what happens in ScViewFunc::ApplySelectionPattern)
1032     ShrinkToDataArea( aMark, rDoc );
1033 
1034     if ( aMark.IsMarked() || aMark.IsMultiMarked() )
1035     {
1036         //  MarkToMulti is no longer necessary for rDoc.GetSelectionPattern
1037         const ScPatternAttr* pAttr = rDoc.GetSelectionPattern( aMark );
1038         return pAttr;
1039     }
1040     else
1041     {
1042         SCCOL  nCol = GetViewData().GetCurX();
1043         SCROW  nRow = GetViewData().GetCurY();
1044         SCTAB  nTab = GetViewData().GetTabNo();
1045 
1046         // copy sheet selection
1047         aMark.SetMarkArea( ScRange( nCol, nRow, nTab ) );
1048         const ScPatternAttr* pAttr = rDoc.GetSelectionPattern( aMark );
1049         return pAttr;
1050     }
1051 }
1052 
GetSelectionFrame(std::shared_ptr<SvxBoxItem> & rLineOuter,std::shared_ptr<SvxBoxInfoItem> & rLineInner)1053 void ScViewFunc::GetSelectionFrame(
1054     std::shared_ptr<SvxBoxItem>& rLineOuter,
1055     std::shared_ptr<SvxBoxInfoItem>& rLineInner )
1056 {
1057     ScDocument& rDoc = GetViewData().GetDocument();
1058     const ScMarkData& rMark = GetViewData().GetMarkData();
1059 
1060     if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1061     {
1062         rDoc.GetSelectionFrame( rMark, *rLineOuter, *rLineInner );
1063     }
1064     else
1065     {
1066         const ScPatternAttr* pAttrs =
1067                     rDoc.GetPattern( GetViewData().GetCurX(),
1068                                       GetViewData().GetCurY(),
1069                                       GetViewData().GetTabNo() );
1070 
1071         rLineOuter.reset(pAttrs->GetItem(ATTR_BORDER).Clone());
1072         rLineInner.reset(pAttrs->GetItem(ATTR_BORDER_INNER).Clone());
1073 
1074         rLineInner->SetTable(false);
1075         rLineInner->SetDist(true);
1076         rLineInner->SetMinDist(false);
1077     }
1078 }
1079 
1080 //  apply attribute - undo OK
1081 //
1082 //  complete set ( ATTR_STARTINDEX, ATTR_ENDINDEX )
1083 
ApplyAttributes(const SfxItemSet & rDialogSet,const SfxItemSet & rOldSet,bool bAdjustBlockHeight)1084 void ScViewFunc::ApplyAttributes( const SfxItemSet& rDialogSet,
1085                                   const SfxItemSet& rOldSet,
1086                                   bool bAdjustBlockHeight)
1087 {
1088     // not editable because of matrix only? attribute OK nonetheless
1089     bool bOnlyNotBecauseOfMatrix;
1090     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1091     {
1092         ErrorMessage(STR_PROTECTIONERR);
1093         return;
1094     }
1095 
1096     ScDocument& rDoc = GetViewData().GetDocument();
1097     ScPatternAttr aOldAttrs(rDoc.getCellAttributeHelper(), &rOldSet);
1098     ScPatternAttr aNewAttrs(rDoc.getCellAttributeHelper(), &rDialogSet);
1099     aNewAttrs.DeleteUnchanged( &aOldAttrs );
1100 
1101     if ( rDialogSet.GetItemState( ATTR_VALUE_FORMAT ) == SfxItemState::SET )
1102     {   // don't reset to default SYSTEM GENERAL if not intended
1103         sal_uInt32 nOldFormat =
1104             rOldSet.Get( ATTR_VALUE_FORMAT ).GetValue();
1105         sal_uInt32 nNewFormat =
1106             rDialogSet.Get( ATTR_VALUE_FORMAT ).GetValue();
1107         if ( nNewFormat != nOldFormat )
1108         {
1109             SvNumberFormatter* pFormatter =
1110                 GetViewData().GetDocument().GetFormatTable();
1111             const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
1112             LanguageType eOldLang =
1113                 pOldEntry ? pOldEntry->GetLanguage() : LANGUAGE_DONTKNOW;
1114             const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
1115             LanguageType eNewLang =
1116                 pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
1117             if ( eNewLang != eOldLang )
1118             {
1119                 aNewAttrs.GetItemSet().Put(
1120                     SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
1121 
1122                 //  only the language has changed -> do not touch numberformat-attribute
1123                 sal_uInt32 nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
1124                 if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
1125                      nNewMod <= SV_MAX_COUNT_STANDARD_FORMATS )
1126                     aNewAttrs.GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
1127             }
1128         }
1129     }
1130 
1131     if (rDialogSet.HasItem(ATTR_FONT_LANGUAGE))
1132         // font language has changed.  Redo the online spelling.
1133         ResetAutoSpell();
1134 
1135     const SvxBoxItem&     rOldOuter = rOldSet.Get(ATTR_BORDER);
1136     const SvxBoxItem&     rNewOuter = rDialogSet.Get(ATTR_BORDER);
1137     const SvxBoxInfoItem& rOldInner = rOldSet.Get(ATTR_BORDER_INNER);
1138     const SvxBoxInfoItem& rNewInner = rDialogSet.Get(ATTR_BORDER_INNER);
1139     SfxItemSet&           rNewSet   = aNewAttrs.GetItemSet();
1140 
1141     // protect referenced Items from disappearing (was: don't delete yet)
1142     const SfxPoolItemHolder aHoldOuter(*rDialogSet.GetPool() , &rNewOuter);
1143     const SfxPoolItemHolder aHoldInner(*rDialogSet.GetPool() , &rNewInner);
1144     (void)aHoldOuter;
1145     (void)aHoldInner;
1146 
1147     rNewSet.ClearItem( ATTR_BORDER );
1148     rNewSet.ClearItem( ATTR_BORDER_INNER );
1149 
1150     /*
1151      * establish whether border attribute is to be set:
1152      * 1. new != old
1153      * 2. is one of the borders not-DontCare (since 238.f: IsxxValid())
1154      *
1155      */
1156 
1157     bool bFrame =    (rDialogSet.GetItemState( ATTR_BORDER ) != SfxItemState::DEFAULT)
1158                   || (rDialogSet.GetItemState( ATTR_BORDER_INNER ) != SfxItemState::DEFAULT);
1159 
1160     if (SfxPoolItem::areSame(rNewOuter, rOldOuter) && SfxPoolItem::areSame(rNewInner, rOldInner))
1161         bFrame = false;
1162 
1163     //  this should be intercepted by the pool: ?!??!??
1164 
1165     if (bFrame && rNewOuter == rOldOuter && rNewInner == rOldInner)
1166         bFrame = false;
1167 
1168     bFrame =   bFrame
1169             && (   rNewInner.IsValid(SvxBoxInfoItemValidFlags::LEFT)
1170                 || rNewInner.IsValid(SvxBoxInfoItemValidFlags::RIGHT)
1171                 || rNewInner.IsValid(SvxBoxInfoItemValidFlags::TOP)
1172                 || rNewInner.IsValid(SvxBoxInfoItemValidFlags::BOTTOM)
1173                 || rNewInner.IsValid(SvxBoxInfoItemValidFlags::HORI)
1174                 || rNewInner.IsValid(SvxBoxInfoItemValidFlags::VERT) );
1175 
1176     if (!bFrame)
1177         ApplySelectionPattern( aNewAttrs );            // standard only
1178     else
1179     {
1180         // if new items are default-items, overwrite the old items:
1181 
1182         bool bDefNewOuter = IsStaticDefaultItem(&rNewOuter);
1183         bool bDefNewInner = IsStaticDefaultItem(&rNewInner);
1184 
1185         ApplyPatternLines( aNewAttrs,
1186                            bDefNewOuter ? rOldOuter : rNewOuter,
1187                            bDefNewInner ? &rOldInner : &rNewInner );
1188     }
1189 
1190     //  adjust height only if needed
1191     if (bAdjustBlockHeight)
1192         AdjustBlockHeight();
1193 
1194     // CellContentChanged is called in ApplySelectionPattern / ApplyPatternLines
1195 }
1196 
ApplyAttr(const SfxPoolItem & rAttrItem,bool bAdjustBlockHeight)1197 void ScViewFunc::ApplyAttr( const SfxPoolItem& rAttrItem, bool bAdjustBlockHeight )
1198 {
1199     // not editable because of matrix only? attribute OK nonetheless
1200     bool bOnlyNotBecauseOfMatrix;
1201     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1202     {
1203         ErrorMessage(STR_PROTECTIONERR);
1204         return;
1205     }
1206 
1207     ScDocument& rDoc = GetViewData().GetDocument();
1208     ScPatternAttr aNewAttrs(rDoc.getCellAttributeHelper());
1209 
1210     aNewAttrs.GetItemSet().Put( rAttrItem );
1211     //  if justify is set (with Buttons), always indentation 0
1212     if ( rAttrItem.Which() == ATTR_HOR_JUSTIFY )
1213         aNewAttrs.GetItemSet().Put( ScIndentItem( 0 ) );
1214     ApplySelectionPattern( aNewAttrs );
1215 
1216     // Prevent useless compute
1217     if (bAdjustBlockHeight)
1218         AdjustBlockHeight();
1219 
1220     // CellContentChanged is called in ApplySelectionPattern
1221 }
1222 
1223 //  patterns and borders
1224 
ApplyPatternLines(const ScPatternAttr & rAttr,const SvxBoxItem & rNewOuter,const SvxBoxInfoItem * pNewInner)1225 void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem& rNewOuter,
1226                                     const SvxBoxInfoItem* pNewInner )
1227 {
1228     ScDocument& rDoc = GetViewData().GetDocument();
1229     ScMarkData aFuncMark( GetViewData().GetMarkData() );       // local copy for UnmarkFiltered
1230     ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
1231     bool bRecord = true;
1232     if (!rDoc.IsUndoEnabled())
1233         bRecord = false;
1234 
1235     bool bRemoveAdjCellBorder = rNewOuter.IsRemoveAdjacentCellBorder();
1236     ScRange aMarkRange, aMarkRangeWithEnvelope;
1237     aFuncMark.MarkToSimple();
1238     bool bMulti = aFuncMark.IsMultiMarked();
1239     if (bMulti)
1240         aMarkRange = aFuncMark.GetMultiMarkArea();
1241     else if (aFuncMark.IsMarked())
1242         aMarkRange = aFuncMark.GetMarkArea();
1243     else
1244     {
1245         aMarkRange = ScRange( GetViewData().GetCurX(),
1246                             GetViewData().GetCurY(), GetViewData().GetTabNo() );
1247         DoneBlockMode();
1248         InitOwnBlockMode( aMarkRange );
1249         aFuncMark.SetMarkArea(aMarkRange);
1250         MarkDataChanged();
1251     }
1252     if( bRemoveAdjCellBorder )
1253         aFuncMark.GetSelectionCover( aMarkRangeWithEnvelope );
1254     else
1255         aMarkRangeWithEnvelope = aMarkRange;
1256 
1257     ScDocShell* pDocSh = GetViewData().GetDocShell();
1258 
1259     ScDocShellModificator aModificator( *pDocSh );
1260 
1261     if (bRecord)
1262     {
1263         ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
1264         SCTAB nStartTab = aMarkRange.aStart.Tab();
1265         SCTAB nTabCount = rDoc.GetTableCount();
1266         bool bCopyOnlyMarked = false;
1267         if( !bRemoveAdjCellBorder )
1268             bCopyOnlyMarked = bMulti;
1269         pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
1270         for (const auto& rTab : aFuncMark)
1271             if (rTab != nStartTab)
1272                 pUndoDoc->AddUndoTab( rTab, rTab );
1273 
1274         ScRange aCopyRange = aMarkRangeWithEnvelope;
1275         aCopyRange.aStart.SetTab(0);
1276         aCopyRange.aEnd.SetTab(nTabCount-1);
1277         rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bCopyOnlyMarked, *pUndoDoc, &aFuncMark );
1278 
1279         pDocSh->GetUndoManager()->AddUndoAction(
1280             std::make_unique<ScUndoSelectionAttr>(
1281                 pDocSh, aFuncMark,
1282                 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), aMarkRange.aStart.Tab(),
1283                 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), aMarkRange.aEnd.Tab(),
1284                 std::move(pUndoDoc), bCopyOnlyMarked, &rAttr, &rNewOuter, pNewInner, &aMarkRangeWithEnvelope ) );
1285     }
1286 
1287     sal_uInt16 nExt = SC_PF_TESTMERGE;
1288     pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content before the change
1289 
1290     rDoc.ApplySelectionFrame(aFuncMark, rNewOuter, pNewInner);
1291 
1292     pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content after the change
1293 
1294     aFuncMark.MarkToMulti();
1295     rDoc.ApplySelectionPattern( rAttr, aFuncMark );
1296 
1297     pDocSh->PostPaint( aMarkRange, PaintPartFlags::Grid, nExt );
1298     pDocSh->UpdateOle(GetViewData());
1299     aModificator.SetDocumentModified();
1300     CellContentChanged();
1301 
1302     StartFormatArea();
1303 }
1304 
1305 // tdf#147842 if the marked area is the entire sheet, then shrink it to the data area.
1306 // Otherwise ctrl-A, perform-action, will take a very long time as it tries to modify
1307 // cells that we are not using.
ShrinkToDataArea(ScMarkData & rFuncMark,ScDocument & rDoc)1308 static void ShrinkToDataArea(ScMarkData& rFuncMark, ScDocument& rDoc)
1309 {
1310     // do not make it marked if it is not already marked
1311     if (!rFuncMark.IsMarked())
1312         return;
1313     if (rFuncMark.IsMultiMarked())
1314         return;
1315     ScRange aMarkArea = rFuncMark.GetMarkArea();
1316     const ScSheetLimits& rLimits = rDoc.GetSheetLimits();
1317     if (aMarkArea.aStart.Row() != 0 || aMarkArea.aStart.Col() != 0)
1318         return;
1319     if (aMarkArea.aEnd.Row() != rLimits.MaxRow() || aMarkArea.aEnd.Col() != rLimits.MaxCol())
1320         return;
1321     if (aMarkArea.aStart.Tab() != aMarkArea.aEnd.Tab())
1322         return;
1323     SCCOL nStartCol = aMarkArea.aStart.Col();
1324     SCROW nStartRow = aMarkArea.aStart.Row();
1325     SCCOL nEndCol = aMarkArea.aEnd.Col();
1326     SCROW nEndRow = aMarkArea.aEnd.Row();
1327     rDoc.ShrinkToDataArea(aMarkArea.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow);
1328     aMarkArea.aStart.SetCol(nStartCol);
1329     aMarkArea.aStart.SetRow(nStartRow);
1330     aMarkArea.aEnd.SetCol(nEndCol);
1331     aMarkArea.aEnd.SetRow(nEndRow);
1332     rFuncMark.ResetMark();
1333     rFuncMark.SetMarkArea(aMarkArea);
1334 }
1335 
1336 //  pattern only
1337 
ApplySelectionPattern(const ScPatternAttr & rAttr,bool bCursorOnly)1338 void ScViewFunc::ApplySelectionPattern( const ScPatternAttr& rAttr, bool bCursorOnly )
1339 {
1340     ScViewData& rViewData   = GetViewData();
1341     ScDocShell* pDocSh      = rViewData.GetDocShell();
1342     ScDocument& rDoc        = pDocSh->GetDocument();
1343     ScMarkData aFuncMark( rViewData.GetMarkData() );       // local copy for UnmarkFiltered
1344     ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
1345 
1346     bool bRecord = true;
1347     if (!rDoc.IsUndoEnabled())
1348         bRecord = false;
1349 
1350     //  State from old ItemSet doesn't matter for paint flags, as any change will be
1351     //  from SfxItemState::SET in the new ItemSet (default is ignored in ApplyPattern).
1352     //  New alignment is checked (check in PostPaint isn't enough) in case a right
1353     //  alignment is changed to left.
1354     const SfxItemSet& rNewSet = rAttr.GetItemSet();
1355     bool bSetLines = rNewSet.GetItemState( ATTR_BORDER ) == SfxItemState::SET ||
1356                      rNewSet.GetItemState( ATTR_SHADOW ) == SfxItemState::SET;
1357     bool bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY ) == SfxItemState::SET;
1358 
1359     sal_uInt16 nExtFlags = 0;
1360     if ( bSetLines )
1361         nExtFlags |= SC_PF_LINES;
1362     if ( bSetAlign )
1363         nExtFlags |= SC_PF_WHOLEROWS;
1364 
1365     ScDocShellModificator aModificator( *pDocSh );
1366 
1367     bool bMulti = aFuncMark.IsMultiMarked();
1368     aFuncMark.MarkToMulti();
1369     bool bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && aFuncMark.GetSelectCount() > 1);
1370     if (bOnlyTab)
1371     {
1372         SCCOL nCol = rViewData.GetCurX();
1373         SCROW nRow = rViewData.GetCurY();
1374         SCTAB nTab = rViewData.GetTabNo();
1375         aFuncMark.SetMarkArea(ScRange(nCol,nRow,nTab));
1376         aFuncMark.MarkToMulti();
1377     }
1378 
1379     ScRangeList aChangeRanges;
1380 
1381     if (aFuncMark.IsMultiMarked() && !bCursorOnly)
1382     {
1383         const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
1384         SCTAB nTabCount = rDoc.GetTableCount();
1385         for (const auto& rTab : aFuncMark)
1386         {
1387             ScRange aChangeRange( aMarkRange );
1388             aChangeRange.aStart.SetTab( rTab );
1389             aChangeRange.aEnd.SetTab( rTab );
1390             aChangeRanges.push_back( aChangeRange );
1391         }
1392 
1393         SCCOL nStartCol = aMarkRange.aStart.Col();
1394         SCROW nStartRow = aMarkRange.aStart.Row();
1395         SCTAB nStartTab = aMarkRange.aStart.Tab();
1396         SCCOL nEndCol = aMarkRange.aEnd.Col();
1397         SCROW nEndRow = aMarkRange.aEnd.Row();
1398         SCTAB nEndTab = aMarkRange.aEnd.Tab();
1399 
1400         ScEditDataArray* pEditDataArray = nullptr;
1401         if (bRecord)
1402         {
1403             ScRange aCopyRange = aMarkRange;
1404             aCopyRange.aStart.SetTab(0);
1405             aCopyRange.aEnd.SetTab(nTabCount-1);
1406 
1407             ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
1408             pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
1409             for (const auto& rTab : aFuncMark)
1410                 if (rTab != nStartTab)
1411                     pUndoDoc->AddUndoTab( rTab, rTab );
1412             rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, *pUndoDoc, &aFuncMark );
1413 
1414             aFuncMark.MarkToMulti();
1415 
1416             ScUndoSelectionAttr* pUndoAttr = new ScUndoSelectionAttr(
1417                 pDocSh, aFuncMark, nStartCol, nStartRow, nStartTab,
1418                 nEndCol, nEndRow, nEndTab, std::move(pUndoDoc), bMulti, &rAttr );
1419             pDocSh->GetUndoManager()->AddUndoAction(std::unique_ptr<ScUndoSelectionAttr>(pUndoAttr));
1420             pEditDataArray = pUndoAttr->GetDataArray();
1421         }
1422 
1423         rDoc.ApplySelectionPattern( rAttr, aFuncMark, pEditDataArray );
1424 
1425         pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
1426                            nEndCol,   nEndRow,   nEndTab,
1427                            PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
1428         pDocSh->UpdateOle(GetViewData());
1429         aModificator.SetDocumentModified();
1430         CellContentChanged();
1431     }
1432     else                            // single cell - simpler undo
1433     {
1434         SCCOL nCol = rViewData.GetCurX();
1435         SCROW nRow = rViewData.GetCurY();
1436         SCTAB nTab = rViewData.GetTabNo();
1437 
1438         std::unique_ptr<EditTextObject> pOldEditData;
1439         std::unique_ptr<EditTextObject> pNewEditData;
1440         ScAddress aPos(nCol, nRow, nTab);
1441         ScRefCellValue aCell(rDoc, aPos);
1442         if (aCell.getType() == CELLTYPE_EDIT)
1443         {
1444             const EditTextObject* pEditObj = aCell.getEditText();
1445             pOldEditData = pEditObj->Clone();
1446             rDoc.RemoveEditTextCharAttribs(aPos, rAttr);
1447             pEditObj = rDoc.GetEditText(aPos);
1448             pNewEditData = pEditObj->Clone();
1449         }
1450 
1451         aChangeRanges.push_back(aPos);
1452         std::optional<ScPatternAttr> pOldPat(*rDoc.GetPattern( nCol, nRow, nTab ));
1453 
1454         rDoc.ApplyPattern( nCol, nRow, nTab, rAttr );
1455 
1456         const ScPatternAttr* pNewPat = rDoc.GetPattern( nCol, nRow, nTab );
1457 
1458         if (bRecord)
1459         {
1460             std::unique_ptr<ScUndoCursorAttr> pUndo(new ScUndoCursorAttr(
1461                 pDocSh, nCol, nRow, nTab, &*pOldPat, pNewPat, &rAttr ));
1462             pUndo->SetEditData(std::move(pOldEditData), std::move(pNewEditData));
1463             pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndo));
1464         }
1465         pOldPat.reset();     // is copied in undo (Pool)
1466 
1467         pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
1468         pDocSh->UpdateOle(GetViewData());
1469         aModificator.SetDocumentModified();
1470         CellContentChanged();
1471     }
1472 
1473     ScModelObj* pModelObj = pDocSh->GetModel();
1474 
1475     if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
1476     {
1477         css::uno::Sequence< css::beans::PropertyValue > aProperties;
1478         sal_Int32 nCount = 0;
1479         const SfxItemPropertyMap& rMap = ScCellObj::GetCellPropertyMap();
1480         for ( sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; ++nWhich )
1481         {
1482             const SfxPoolItem* pItem = nullptr;
1483             if ( rNewSet.GetItemState( nWhich, true, &pItem ) == SfxItemState::SET && pItem )
1484             {
1485                 for ( const auto pEntry : rMap.getPropertyEntries())
1486                 {
1487                     if ( pEntry->nWID == nWhich )
1488                     {
1489                         css::uno::Any aVal;
1490                         pItem->QueryValue( aVal, pEntry->nMemberId );
1491                         aProperties.realloc( nCount + 1 );
1492                         auto pProperties = aProperties.getArray();
1493                         pProperties[ nCount ].Name = pEntry->aName;
1494                         pProperties[ nCount ].Value = aVal;
1495                         ++nCount;
1496                     }
1497                 }
1498             }
1499         }
1500         HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"attribute"_ustr, aProperties);
1501     }
1502 
1503     StartFormatArea();
1504 }
1505 
ApplyUserItemSet(const SfxItemSet & rItemSet)1506 void ScViewFunc::ApplyUserItemSet( const SfxItemSet& rItemSet )
1507 {
1508     //  ItemSet from UI, may have different pool
1509 
1510     bool bOnlyNotBecauseOfMatrix;
1511     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1512     {
1513         ErrorMessage(STR_PROTECTIONERR);
1514         return;
1515     }
1516 
1517     ScPatternAttr aNewAttrs(GetViewData().GetDocument().getCellAttributeHelper());
1518     SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
1519     rNewSet.Put( rItemSet, false );
1520     ApplySelectionPattern( aNewAttrs );
1521 
1522     AdjustBlockHeight();
1523 }
1524 
GetStyleSheetFromMarked()1525 const SfxStyleSheet* ScViewFunc::GetStyleSheetFromMarked()
1526 {
1527     // Don't use UnmarkFiltered in slot state functions, for performance reasons.
1528     // The displayed state is always that of the whole selection including filtered rows.
1529 
1530     const ScStyleSheet* pSheet      = nullptr;
1531     ScViewData&         rViewData   = GetViewData();
1532     ScDocument&         rDoc        = rViewData.GetDocument();
1533     ScMarkData&         rMark       = rViewData.GetMarkData();
1534 
1535     if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1536         pSheet = rDoc.GetSelectionStyle( rMark );                  // MarkToMulti isn't necessary
1537     else
1538         pSheet = rDoc.GetStyle( rViewData.GetCurX(),
1539                                 rViewData.GetCurY(),
1540                                 rViewData.GetTabNo() );
1541 
1542     return pSheet;
1543 }
1544 
SetStyleSheetToMarked(const SfxStyleSheet * pStyleSheet)1545 void ScViewFunc::SetStyleSheetToMarked( const SfxStyleSheet* pStyleSheet )
1546 {
1547     // not editable because of matrix only? attribute OK nonetheless
1548     bool bOnlyNotBecauseOfMatrix;
1549     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1550     {
1551         ErrorMessage(STR_PROTECTIONERR);
1552         return;
1553     }
1554 
1555     if ( !pStyleSheet) return;
1556 
1557     ScViewData& rViewData   = GetViewData();
1558     ScDocShell* pDocSh      = rViewData.GetDocShell();
1559     ScDocument& rDoc        = pDocSh->GetDocument();
1560     ScMarkData aFuncMark( rViewData.GetMarkData() );       // local copy for UnmarkFiltered
1561     ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
1562     SCTAB nTabCount     = rDoc.GetTableCount();
1563     bool bRecord = true;
1564     if (!rDoc.IsUndoEnabled())
1565         bRecord = false;
1566 
1567     ScDocShellModificator aModificator( *pDocSh );
1568 
1569     if ( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() )
1570     {
1571         aFuncMark.MarkToMulti();
1572         const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
1573 
1574         if ( bRecord )
1575         {
1576             SCTAB nTab = rViewData.GetTabNo();
1577             ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
1578             pUndoDoc->InitUndo( rDoc, nTab, nTab );
1579             for (const auto& rTab : aFuncMark)
1580                 if (rTab != nTab)
1581                     pUndoDoc->AddUndoTab( rTab, rTab );
1582 
1583             ScRange aCopyRange = aMarkRange;
1584             aCopyRange.aStart.SetTab(0);
1585             aCopyRange.aEnd.SetTab(nTabCount-1);
1586             rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, true, *pUndoDoc, &aFuncMark );
1587             aFuncMark.MarkToMulti();
1588 
1589             OUString aName = pStyleSheet->GetName();
1590             pDocSh->GetUndoManager()->AddUndoAction(
1591                 std::make_unique<ScUndoSelectionStyle>( pDocSh, aFuncMark, aMarkRange, aName, std::move(pUndoDoc) ) );
1592         }
1593 
1594         rDoc.ApplySelectionStyle( static_cast<const ScStyleSheet&>(*pStyleSheet), aFuncMark );
1595 
1596         if (!AdjustBlockHeight())
1597             rViewData.GetDocShell()->PostPaint( aMarkRange, PaintPartFlags::Grid );
1598 
1599         aFuncMark.MarkToSimple();
1600     }
1601     else
1602     {
1603         SCCOL nCol = rViewData.GetCurX();
1604         SCROW nRow = rViewData.GetCurY();
1605         SCTAB nTab = rViewData.GetTabNo();
1606 
1607         if ( bRecord )
1608         {
1609             ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
1610             pUndoDoc->InitUndo( rDoc, nTab, nTab );
1611             for (const auto& rTab : aFuncMark)
1612                 if (rTab != nTab)
1613                     pUndoDoc->AddUndoTab( rTab, rTab );
1614 
1615             ScRange aCopyRange( nCol, nRow, 0, nCol, nRow, nTabCount-1 );
1616             rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc );
1617 
1618             ScRange aMarkRange ( nCol, nRow, nTab );
1619             ScMarkData aUndoMark = aFuncMark;
1620             aUndoMark.SetMultiMarkArea( aMarkRange );
1621 
1622             OUString aName = pStyleSheet->GetName();
1623             pDocSh->GetUndoManager()->AddUndoAction(
1624                 std::make_unique<ScUndoSelectionStyle>( pDocSh, aUndoMark, aMarkRange, aName, std::move(pUndoDoc) ) );
1625         }
1626 
1627         for (const auto& rTab : aFuncMark)
1628             rDoc.ApplyStyle( nCol, nRow, rTab, static_cast<const ScStyleSheet&>(*pStyleSheet) );
1629 
1630         if (!AdjustBlockHeight())
1631             rViewData.GetDocShell()->PostPaintCell( nCol, nRow, nTab );
1632 
1633     }
1634 
1635     aModificator.SetDocumentModified();
1636 
1637     StartFormatArea();
1638 }
1639 
RemoveStyleSheetInUse(const SfxStyleSheetBase * pStyleSheet)1640 void ScViewFunc::RemoveStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1641 {
1642     if ( !pStyleSheet) return;
1643 
1644     ScViewData& rViewData   = GetViewData();
1645     ScDocument& rDoc        = rViewData.GetDocument();
1646     ScDocShell* pDocSh      = rViewData.GetDocShell();
1647 
1648     ScDocShellModificator aModificator( *pDocSh );
1649 
1650     ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1651     pVirtDev->SetMapMode(MapMode(MapUnit::MapPixel));
1652     rDoc.StyleSheetChanged( pStyleSheet, true, pVirtDev,
1653                                 rViewData.GetPPTX(),
1654                                 rViewData.GetPPTY(),
1655                                 rViewData.GetZoomX(),
1656                                 rViewData.GetZoomY() );
1657 
1658     pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
1659     aModificator.SetDocumentModified();
1660 
1661     ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1662     if (pHdl)
1663         pHdl->ForgetLastPattern();
1664 }
1665 
UpdateStyleSheetInUse(const SfxStyleSheetBase * pStyleSheet)1666 void ScViewFunc::UpdateStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1667 {
1668     if ( !pStyleSheet) return;
1669 
1670     ScViewData& rViewData   = GetViewData();
1671     ScDocument& rDoc        = rViewData.GetDocument();
1672     ScDocShell* pDocSh      = rViewData.GetDocShell();
1673 
1674     ScDocShellModificator aModificator( *pDocSh );
1675 
1676     ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1677     pVirtDev->SetMapMode(MapMode(MapUnit::MapPixel));
1678     rDoc.StyleSheetChanged( pStyleSheet, false, pVirtDev,
1679                                 rViewData.GetPPTX(),
1680                                 rViewData.GetPPTY(),
1681                                 rViewData.GetZoomX(),
1682                                 rViewData.GetZoomY() );
1683 
1684     pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
1685     aModificator.SetDocumentModified();
1686 
1687     ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1688     if (pHdl)
1689         pHdl->ForgetLastPattern();
1690 }
1691 
1692 
OnLOKInsertDeleteColumn(SCCOL nStartCol,tools::Long nOffset)1693 void ScViewFunc::OnLOKInsertDeleteColumn(SCCOL nStartCol, tools::Long nOffset)
1694 {
1695     if (!comphelper::LibreOfficeKit::isActive() || nOffset == 0)
1696         return;
1697 
1698     SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
1699     SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
1700     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
1701     while (pViewShell)
1702     {
1703         ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
1704         if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
1705         {
1706             if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKWidthHelper(nCurrentTabIndex))
1707                 pPosHelper->invalidateByIndex(nStartCol);
1708 
1709             // if we remove a column the cursor position  and the current selection
1710             // in other views could need to be moved on the left by one column.
1711             if (pTabViewShell != this)
1712             {
1713                 if (pTabViewShell->getPart() == nCurrentTabIndex)
1714                 {
1715                     SCCOL nX = pTabViewShell->GetViewData().GetCurX();
1716                     if (nX > nStartCol)
1717                     {
1718                         tools::Long offset = nOffset;
1719                         if (nOffset + nStartCol > nX)
1720                             offset = nX - nStartCol;
1721                         else if (nOffset < 0 && nStartCol - nOffset > nX)
1722                             offset = -1 * (nX - nStartCol);
1723 
1724                         ScInputHandler* pInputHdl = pTabViewShell->GetInputHandler();
1725                         SCROW nY = pTabViewShell->GetViewData().GetCurY();
1726                         pTabViewShell->SetCursor(nX + offset, nY);
1727                         if (pInputHdl && pInputHdl->IsInputMode())
1728                         {
1729                             pInputHdl->SetModified();
1730                         }
1731                     }
1732 
1733                     ScMarkData aMultiMark( pTabViewShell->GetViewData().GetMarkData() );
1734                     aMultiMark.SetMarking( false );
1735 
1736                     if (aMultiMark.IsMultiMarked() || aMultiMark.IsMarked())
1737                     {
1738                         aMultiMark.ShiftCols(pTabViewShell->GetViewData().GetDocument(), nStartCol, nOffset);
1739                         pTabViewShell->SetMarkData(aMultiMark);
1740                     }
1741                 }
1742                 else
1743                 {
1744                     SCROW nX = pTabViewShell->GetViewData().GetCurXForTab(nCurrentTabIndex);
1745                     if (nX > nStartCol || (nX == nStartCol && nOffset > 0))
1746                     {
1747                         pTabViewShell->GetViewData().SetCurXForTab(nX + nOffset, nCurrentTabIndex);
1748                     }
1749                 }
1750             }
1751         }
1752         pViewShell = SfxViewShell::GetNext(*pViewShell);
1753     }
1754 }
1755 
OnLOKInsertDeleteRow(SCROW nStartRow,tools::Long nOffset)1756 void ScViewFunc::OnLOKInsertDeleteRow(SCROW nStartRow, tools::Long nOffset)
1757 {
1758     if (!comphelper::LibreOfficeKit::isActive() || nOffset == 0)
1759         return;
1760 
1761     SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
1762     SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
1763     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
1764     while (pViewShell)
1765     {
1766         ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
1767         if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
1768         {
1769             if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nCurrentTabIndex))
1770                 pPosHelper->invalidateByIndex(nStartRow);
1771 
1772             // if we remove a row the cursor position and the current selection
1773             // in other views could need to be moved up by one row.
1774             if (pTabViewShell != this)
1775             {
1776                 if (pTabViewShell->getPart() == nCurrentTabIndex)
1777                 {
1778                     SCROW nY = pTabViewShell->GetViewData().GetCurY();
1779                     if (nY > nStartRow)
1780                     {
1781                         tools::Long offset = nOffset;
1782                         if (nOffset + nStartRow > nY)
1783                             offset = nY - nStartRow;
1784                         else if (nOffset < 0 && nStartRow - nOffset > nY)
1785                             offset = -1 * (nY - nStartRow);
1786 
1787                         ScInputHandler* pInputHdl = pTabViewShell->GetInputHandler();
1788                         SCCOL nX = pTabViewShell->GetViewData().GetCurX();
1789                         pTabViewShell->SetCursor(nX, nY + offset);
1790                         if (pInputHdl && pInputHdl->IsInputMode())
1791                         {
1792                             pInputHdl->SetModified();
1793                         }
1794                     }
1795 
1796                     ScMarkData aMultiMark( pTabViewShell->GetViewData().GetMarkData() );
1797                     aMultiMark.SetMarking( false );
1798 
1799                     if (aMultiMark.IsMultiMarked() || aMultiMark.IsMarked())
1800                     {
1801                         aMultiMark.ShiftRows(pTabViewShell->GetViewData().GetDocument(), nStartRow, nOffset);
1802                         pTabViewShell->SetMarkData(aMultiMark);
1803                     }
1804                 }
1805                 else
1806                 {
1807                     SCROW nY = pTabViewShell->GetViewData().GetCurYForTab(nCurrentTabIndex);
1808                     if (nY > nStartRow || (nY == nStartRow && nOffset > 0))
1809                     {
1810                         pTabViewShell->GetViewData().SetCurYForTab(nY + nOffset, nCurrentTabIndex);
1811                     }
1812                 }
1813             }
1814         }
1815         pViewShell = SfxViewShell::GetNext(*pViewShell);
1816     }
1817 }
1818 
OnLOKSetWidthOrHeight(SCCOLROW nStart,bool bWidth)1819 void ScViewFunc::OnLOKSetWidthOrHeight(SCCOLROW nStart, bool bWidth)
1820 {
1821     if (!comphelper::LibreOfficeKit::isActive())
1822         return;
1823 
1824     SCTAB nCurTab = GetViewData().GetTabNo();
1825     SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
1826     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
1827     while (pViewShell)
1828     {
1829         ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
1830         if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
1831         {
1832             if (bWidth)
1833             {
1834                 if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKWidthHelper(nCurTab))
1835                     pPosHelper->invalidateByIndex(nStart);
1836             }
1837             else
1838             {
1839                 if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nCurTab))
1840                     pPosHelper->invalidateByIndex(nStart);
1841             }
1842         }
1843         pViewShell = SfxViewShell::GetNext(*pViewShell);
1844     }
1845 }
1846 
1847 //  insert cells - undo OK
1848 
InsertCells(InsCellCmd eCmd,bool bRecord,bool bPartOfPaste,size_t nCount)1849 bool ScViewFunc::InsertCells( InsCellCmd eCmd, bool bRecord, bool bPartOfPaste, size_t nCount )
1850 {
1851     ScRange aRange;
1852     ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
1853     if (eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED)
1854     {
1855         ScDocShell* pDocSh = GetViewData().GetDocShell();
1856         const ScMarkData& rMark = GetViewData().GetMarkData();
1857         bool bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, &rMark, eCmd, bRecord, false, bPartOfPaste, nCount );
1858         if (bSuccess)
1859         {
1860             ResetAutoSpellForContentChange();
1861             bool bInsertCols = ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER);
1862             bool bInsertRows = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER );
1863 
1864             pDocSh->UpdateOle(GetViewData());
1865             CellContentChanged();
1866 
1867             if ( bInsertCols || bInsertRows )
1868             {
1869                 OUString aOperation = bInsertRows ?
1870                     u"insert-rows"_ustr:
1871                     u"insert-columns"_ustr;
1872                 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange, aOperation);
1873             }
1874 
1875             if (comphelper::LibreOfficeKit::isActive())
1876             {
1877                 if (bInsertCols)
1878                     ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER, GetViewData().GetTabNo());
1879 
1880                 if (bInsertRows)
1881                     ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());
1882 
1883                 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
1884                                                                     bInsertCols, bInsertRows, true /* bSizes*/,
1885                                                                     true /* bHidden */, true /* bFiltered */,
1886                                                                     true /* bGroups */, GetViewData().GetTabNo());
1887             }
1888         }
1889         else
1890         {
1891             ErrorMessage(STR_ERR_INSERT_CELLS);
1892         }
1893 
1894         OUString aStartAddress =  aRange.aStart.GetColRowString();
1895         OUString aEndAddress = aRange.aEnd.GetColRowString();
1896         collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"INSERT_CELLS"_ustr);
1897         return bSuccess;
1898     }
1899     else
1900     {
1901         ErrorMessage(STR_NOMULTISELECT);
1902         return false;
1903     }
1904 }
1905 
1906 //  delete cells - undo OK
1907 
DeleteCells(DelCellCmd eCmd)1908 void ScViewFunc::DeleteCells( DelCellCmd eCmd )
1909 {
1910     ScRange aRange;
1911     if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
1912     {
1913         ScDocShell* pDocSh = GetViewData().GetDocShell();
1914         const ScMarkData& rMark = GetViewData().GetMarkData();
1915 
1916 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1917         // #i94841# [Collaboration] if deleting rows is rejected, the content is sometimes wrong
1918         if ( pDocSh->IsDocShared() && ( eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::Cols ) )
1919         {
1920             ScRange aDelRange( aRange.aStart );
1921             SCCOLROW nCount = 0;
1922             if ( eCmd == DelCellCmd::Rows )
1923             {
1924                 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
1925             }
1926             else
1927             {
1928                 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Col() - aRange.aStart.Col() + 1 );
1929             }
1930             while ( nCount > 0 )
1931             {
1932                 pDocSh->GetDocFunc().DeleteCells( aDelRange, &rMark, eCmd, false );
1933                 --nCount;
1934             }
1935         }
1936         else
1937 #endif
1938         {
1939             pDocSh->GetDocFunc().DeleteCells( aRange, &rMark, eCmd, false );
1940         }
1941 
1942         ResetAutoSpellForContentChange();
1943         pDocSh->UpdateOle(GetViewData());
1944         CellContentChanged();
1945 
1946         if ( eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::Cols )
1947         {
1948             OUString aOperation = ( eCmd == DelCellCmd::Rows) ?
1949               u"delete-rows"_ustr:
1950               u"delete-columns"_ustr;
1951             HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange, aOperation);
1952         }
1953 
1954         //  put cursor directly behind deleted range
1955         SCCOL nCurX = GetViewData().GetCurX();
1956         SCROW nCurY = GetViewData().GetCurY();
1957         if ( eCmd==DelCellCmd::CellsLeft || eCmd==DelCellCmd::Cols )
1958             nCurX = aRange.aStart.Col();
1959         else
1960             nCurY = aRange.aStart.Row();
1961         SetCursor( nCurX, nCurY );
1962 
1963         if (comphelper::LibreOfficeKit::isActive())
1964         {
1965             bool bColsDeleted = (eCmd == DelCellCmd::Cols);
1966             bool bRowsDeleted = (eCmd == DelCellCmd::Rows);
1967             if (bColsDeleted)
1968                 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER, GetViewData().GetTabNo());
1969 
1970             if (bRowsDeleted)
1971                 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());
1972 
1973             ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
1974                                                                 bColsDeleted, bRowsDeleted, true /* bSizes*/,
1975                                                                 true /* bHidden */, true /* bFiltered */,
1976                                                                 true /* bGroups */, GetViewData().GetTabNo());
1977         }
1978     }
1979     else
1980     {
1981         if (eCmd == DelCellCmd::Cols)
1982             DeleteMulti( false );
1983         else if (eCmd == DelCellCmd::Rows)
1984             DeleteMulti( true );
1985         else
1986             ErrorMessage(STR_NOMULTISELECT);
1987     }
1988 
1989     OUString aStartAddress =  aRange.aStart.GetColRowString();
1990     OUString aEndAddress = aRange.aEnd.GetColRowString();
1991     collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"DELETE_CELLS"_ustr);
1992 
1993     Unmark();
1994 }
1995 
DeleteMulti(bool bRows)1996 void ScViewFunc::DeleteMulti( bool bRows )
1997 {
1998     ScDocShell* pDocSh = GetViewData().GetDocShell();
1999     ScDocShellModificator aModificator( *pDocSh );
2000     SCTAB nTab = GetViewData().GetTabNo();
2001     ScDocument& rDoc = pDocSh->GetDocument();
2002     ScMarkData aFuncMark( GetViewData().GetMarkData() );       // local copy for UnmarkFiltered
2003     ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
2004 
2005     bool bRecord = true;
2006     if (!rDoc.IsUndoEnabled())
2007         bRecord = false;
2008 
2009     std::vector<sc::ColRowSpan> aSpans;
2010     if (bRows)
2011         aSpans = aFuncMark.GetMarkedRowSpans();
2012     else
2013         aSpans = aFuncMark.GetMarkedColSpans();
2014 
2015     if (aSpans.empty())
2016     {
2017         SCCOLROW nCurPos = bRows ? GetViewData().GetCurY() : GetViewData().GetCurX();
2018         aSpans.emplace_back(nCurPos, nCurPos);
2019     }
2020 
2021     //  test if allowed
2022 
2023     TranslateId pErrorId;
2024     bool bNeedRefresh = false;
2025     for (size_t i = 0, n = aSpans.size(); i < n && !pErrorId; ++i)
2026     {
2027         SCCOLROW nStart = aSpans[i].mnStart;
2028         SCCOLROW nEnd = aSpans[i].mnEnd;
2029 
2030         SCCOL nStartCol, nEndCol;
2031         SCROW nStartRow, nEndRow;
2032         if ( bRows )
2033         {
2034             nStartCol = 0;
2035             nEndCol   = rDoc.MaxCol();
2036             nStartRow = static_cast<SCROW>(nStart);
2037             nEndRow   = static_cast<SCROW>(nEnd);
2038         }
2039         else
2040         {
2041             nStartCol = static_cast<SCCOL>(nStart);
2042             nEndCol   = static_cast<SCCOL>(nEnd);
2043             nStartRow = 0;
2044             nEndRow   = rDoc.MaxRow();
2045         }
2046 
2047         // cell protection (only needed for first range, as all following cells are moved)
2048         if (i == 0)
2049         {
2050             // test to the end of the sheet
2051             ScEditableTester aTester( rDoc, nTab, nStartCol, nStartRow, rDoc.MaxCol(), rDoc.MaxRow() );
2052             if (!aTester.IsEditable())
2053                 pErrorId = aTester.GetMessageId();
2054         }
2055 
2056         // merged cells
2057         SCCOL nMergeStartX = nStartCol;
2058         SCROW nMergeStartY = nStartRow;
2059         SCCOL nMergeEndX   = nEndCol;
2060         SCROW nMergeEndY   = nEndRow;
2061         rDoc.ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
2062         rDoc.ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
2063 
2064         if ( nMergeStartX != nStartCol || nMergeStartY != nStartRow )
2065         {
2066             // Disallow deleting parts of a merged cell.
2067             // Deleting the start is allowed (merge is removed), so the end doesn't have to be checked.
2068 
2069             pErrorId = STR_MSSG_DELETECELLS_0;
2070         }
2071         if ( nMergeEndX != nEndCol || nMergeEndY != nEndRow )
2072         {
2073             // detect if the start of a merged cell is deleted, so the merge flags can be refreshed
2074 
2075             bNeedRefresh = true;
2076         }
2077     }
2078 
2079     if (pErrorId)
2080     {
2081         ErrorMessage(pErrorId);
2082         return;
2083     }
2084 
2085     //  proceed
2086 
2087     weld::WaitObject aWait(GetViewData().GetDialogParent());      // important for TrackFormulas in UpdateReference
2088 
2089     ResetAutoSpellForContentChange();
2090 
2091     ScDocumentUniquePtr pUndoDoc;
2092     std::unique_ptr<ScRefUndoData> pUndoData;
2093     if (bRecord)
2094     {
2095         pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2096         pUndoDoc->InitUndo( rDoc, nTab, nTab, !bRows, bRows );      // row height
2097 
2098         for (const sc::ColRowSpan & rSpan : aSpans)
2099         {
2100             SCCOLROW nStart = rSpan.mnStart;
2101             SCCOLROW nEnd = rSpan.mnEnd;
2102             if (bRows)
2103                 rDoc.CopyToDocument( 0,nStart,nTab, rDoc.MaxCol(), nEnd,nTab, InsertDeleteFlags::ALL,false,*pUndoDoc );
2104             else
2105                 rDoc.CopyToDocument( static_cast<SCCOL>(nStart),0,nTab,
2106                         static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab,
2107                         InsertDeleteFlags::ALL,false,*pUndoDoc );
2108         }
2109 
2110         //  all Formulas because of references
2111         SCTAB nTabCount = rDoc.GetTableCount();
2112         pUndoDoc->AddUndoTab( 0, nTabCount-1 );
2113         rDoc.CopyToDocument( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, InsertDeleteFlags::FORMULA,false,*pUndoDoc );
2114 
2115         pUndoData.reset(new ScRefUndoData( &rDoc ));
2116 
2117         rDoc.BeginDrawUndo();
2118     }
2119 
2120     std::vector<sc::ColRowSpan>::const_reverse_iterator ri = aSpans.rbegin(), riEnd = aSpans.rend();
2121     aFuncMark.SelectOneTable(nTab);
2122     for (; ri != riEnd; ++ri)
2123     {
2124         SCCOLROW nEnd = ri->mnEnd;
2125         SCCOLROW nStart = ri->mnStart;
2126 
2127         if (bRows)
2128         {
2129             rDoc.DeleteObjectsInArea(0, nStart, rDoc.MaxCol(), nEnd, aFuncMark, true);
2130             rDoc.DeleteRow(0, nTab, rDoc.MaxCol(), nTab, nStart, static_cast<SCSIZE>(nEnd - nStart + 1));
2131         }
2132         else
2133         {
2134             rDoc.DeleteObjectsInArea(nStart, 0, nEnd, rDoc.MaxRow(), aFuncMark, true);
2135             rDoc.DeleteCol(0, nTab, rDoc.MaxRow(), nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd - nStart + 1));
2136         }
2137     }
2138 
2139     if (bNeedRefresh)
2140     {
2141         SCCOLROW nFirstStart = aSpans[0].mnStart;
2142         SCCOL nStartCol = bRows ? 0 : static_cast<SCCOL>(nFirstStart);
2143         SCROW nStartRow = bRows ? static_cast<SCROW>(nFirstStart) : 0;
2144         SCCOL nEndCol = rDoc.MaxCol();
2145         SCROW nEndRow = rDoc.MaxRow();
2146 
2147         rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
2148         rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
2149     }
2150 
2151     if (bRecord)
2152     {
2153         pDocSh->GetUndoManager()->AddUndoAction(
2154             std::make_unique<ScUndoDeleteMulti>(
2155                 pDocSh, bRows, bNeedRefresh, nTab, std::vector(aSpans), std::move(pUndoDoc), std::move(pUndoData)));
2156     }
2157 
2158     if (!AdjustRowHeight(0, rDoc.MaxRow(), true))
2159     {
2160         if (bRows)
2161         {
2162             pDocSh->PostPaint(
2163                 0, aSpans[0].mnStart, nTab,
2164                 rDoc.MaxCol(), rDoc.MaxRow(), nTab, (PaintPartFlags::Grid | PaintPartFlags::Left));
2165         }
2166         else
2167         {
2168             pDocSh->PostPaint(
2169                 static_cast<SCCOL>(aSpans[0].mnStart), 0, nTab,
2170                 rDoc.MaxCol(), rDoc.MaxRow(), nTab, (PaintPartFlags::Grid | PaintPartFlags::Top));
2171         }
2172     }
2173 
2174     aModificator.SetDocumentModified();
2175 
2176     CellContentChanged();
2177 
2178     //  put cursor directly behind the first deleted range
2179     SCCOL nCurX = GetViewData().GetCurX();
2180     SCROW nCurY = GetViewData().GetCurY();
2181     if ( bRows )
2182         nCurY = aSpans[0].mnStart;
2183     else
2184         nCurX = static_cast<SCCOL>(aSpans[0].mnStart);
2185     SetCursor( nCurX, nCurY );
2186 
2187     SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
2188 }
2189 
2190 //  delete contents
2191 
DeleteContents(InsertDeleteFlags nFlags)2192 void ScViewFunc::DeleteContents( InsertDeleteFlags nFlags )
2193 {
2194     ScViewData& rViewData = GetViewData();
2195     rViewData.SetPasteMode( ScPasteFlags::NONE );
2196     rViewData.GetViewShell()->UpdateCopySourceOverlay();
2197 
2198     // not editable because of matrix only? attribute OK nonetheless
2199     bool bOnlyNotBecauseOfMatrix;
2200     bool bEditable = SelectionEditable( &bOnlyNotBecauseOfMatrix );
2201     if ( !bEditable )
2202     {
2203         if ( !(bOnlyNotBecauseOfMatrix &&
2204                 ((nFlags & (InsertDeleteFlags::ATTRIB | InsertDeleteFlags::EDITATTR)) == nFlags)) )
2205         {
2206             ErrorMessage(bOnlyNotBecauseOfMatrix ? STR_MATRIXFRAGMENTERR : STR_PROTECTIONERR);
2207             return;
2208         }
2209     }
2210 
2211     ScRange aMarkRange;
2212     bool bSimple = false;
2213 
2214     ScDocument& rDoc = GetViewData().GetDocument();
2215     ScDocShell* pDocSh = GetViewData().GetDocShell();
2216     ScMarkData aFuncMark( GetViewData().GetMarkData() );       // local copy for UnmarkFiltered
2217     ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
2218 
2219     bool bRecord =true;
2220     if (!rDoc.IsUndoEnabled())
2221         bRecord = false;
2222 
2223     if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
2224     {
2225         aMarkRange.aStart.SetCol(GetViewData().GetCurX());
2226         aMarkRange.aStart.SetRow(GetViewData().GetCurY());
2227         aMarkRange.aStart.SetTab(GetViewData().GetTabNo());
2228         aMarkRange.aEnd = aMarkRange.aStart;
2229         if ( rDoc.HasAttrib( aMarkRange, HasAttrFlags::Merged ) )
2230         {
2231             aFuncMark.SetMarkArea( aMarkRange );
2232         }
2233         else
2234             bSimple = true;
2235     }
2236 
2237     HideAllCursors();   // for if summary is cancelled
2238 
2239     ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
2240 
2241     // Can we really be sure that we can pass the bApi parameter as false to DeleteCell() and
2242     // DeleteContents() here? (Meaning that this is interactive use.) Is this never invoked from
2243     // scripting and whatnot?
2244     if (bSimple)
2245         rDocFunc.DeleteCell(aMarkRange.aStart, aFuncMark, nFlags, bRecord, /*bApi=*/ false);
2246     else
2247         rDocFunc.DeleteContents(aFuncMark, nFlags, bRecord, /*bApi=*/ false);
2248 
2249     pDocSh->UpdateOle(GetViewData());
2250 
2251     if (ScModelObj* pModelObj = pDocSh->GetModel())
2252     {
2253         ScRangeList aChangeRanges;
2254         if ( bSimple )
2255         {
2256             aChangeRanges.push_back( aMarkRange );
2257         }
2258         else
2259         {
2260             aFuncMark.FillRangeListWithMarks( &aChangeRanges, false );
2261         }
2262 
2263         if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
2264             HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"delete-content"_ustr);
2265         else if (pModelObj)
2266             HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"data-area-invalidate"_ustr);
2267     }
2268 
2269     CellContentChanged();
2270     ShowAllCursors();
2271 
2272     if ( nFlags & InsertDeleteFlags::ATTRIB )
2273     {
2274         if ( nFlags & InsertDeleteFlags::CONTENTS )
2275             bFormatValid = false;
2276         else
2277             StartFormatArea();              // delete attribute is also attribute-change
2278     }
2279     OUString aStartAddress =  aMarkRange.aStart.GetColRowString();
2280     OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
2281     collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"DELETE"_ustr);
2282 }
2283 
2284 //  column width/row height (via header) - undo OK
2285 
SetWidthOrHeight(bool bWidth,const std::vector<sc::ColRowSpan> & rRanges,ScSizeMode eMode,sal_uInt16 nSizeTwips,bool bRecord,const ScMarkData * pMarkData)2286 void ScViewFunc::SetWidthOrHeight(
2287     bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, ScSizeMode eMode,
2288     sal_uInt16 nSizeTwips, bool bRecord, const ScMarkData* pMarkData )
2289 {
2290     if (rRanges.empty())
2291         return;
2292 
2293     // Use view's mark if none specified, but do not modify the original data,
2294     // i.e. no MarkToMulti() on that.
2295     ScMarkData aMarkData( pMarkData ? *pMarkData : GetViewData().GetMarkData());
2296 
2297     ScDocShell* pDocSh = GetViewData().GetDocShell();
2298     ScDocument& rDoc = pDocSh->GetDocument();
2299     SCCOL nCurX = GetViewData().GetCurX();
2300     SCROW nCurY = GetViewData().GetCurY();
2301     SCTAB nFirstTab = aMarkData.GetFirstSelected();
2302     SCTAB nCurTab = GetViewData().GetTabNo();
2303     if (bRecord && !rDoc.IsUndoEnabled())
2304         bRecord = false;
2305 
2306     ScDocShellModificator aModificator( *pDocSh );
2307 
2308     bool bAllowed = true;
2309     for (const SCTAB& nTab : aMarkData)
2310     {
2311         bAllowed = std::all_of(rRanges.begin(), rRanges.end(),
2312             [&bWidth, &rDoc, &nTab](const sc::ColRowSpan& rRange) {
2313                 bool bOnlyMatrix;
2314                 bool bIsBlockEditable;
2315                 if (bWidth)
2316                     bIsBlockEditable = rDoc.IsBlockEditable(nTab, rRange.mnStart, 0, rRange.mnEnd, rDoc.MaxRow(), &bOnlyMatrix);
2317                 else
2318                     bIsBlockEditable = rDoc.IsBlockEditable(nTab, 0, rRange.mnStart, rDoc.MaxCol(), rRange.mnEnd, &bOnlyMatrix);
2319                 return bIsBlockEditable || bOnlyMatrix;
2320             });
2321         if (!bAllowed)
2322             break;
2323     }
2324 
2325     // Allow users to resize cols/rows in readonly docs despite the r/o state.
2326     // It is frustrating to be unable to see content in mis-sized cells.
2327     if( !bAllowed && !pDocSh->IsReadOnly() )
2328     {
2329         ErrorMessage(STR_PROTECTIONERR);
2330         return;
2331     }
2332 
2333     SCCOLROW nStart = rRanges.front().mnStart;
2334     SCCOLROW nEnd = rRanges.back().mnEnd;
2335 
2336     OnLOKSetWidthOrHeight(nStart, bWidth);
2337 
2338     bool bFormula = false;
2339     if ( eMode == SC_SIZE_OPTIMAL )
2340     {
2341         const ScViewOptions& rOpts = GetViewData().GetOptions();
2342         bFormula = rOpts.GetOption( VOPT_FORMULAS );
2343     }
2344 
2345     ScDocumentUniquePtr pUndoDoc;
2346     std::unique_ptr<ScOutlineTable> pUndoTab;
2347     std::vector<sc::ColRowSpan> aUndoRanges;
2348 
2349     if ( bRecord )
2350     {
2351         rDoc.BeginDrawUndo();                          // Drawing Updates
2352 
2353         pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2354         for (const SCTAB& nTab : aMarkData)
2355         {
2356             if (bWidth)
2357             {
2358                 if ( nTab == nFirstTab )
2359                     pUndoDoc->InitUndo( rDoc, nTab, nTab, true );
2360                 else
2361                     pUndoDoc->AddUndoTab( nTab, nTab, true );
2362                 rDoc.CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab,
2363                         static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE,
2364                         false, *pUndoDoc );
2365             }
2366             else
2367             {
2368                 if ( nTab == nFirstTab )
2369                     pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
2370                 else
2371                     pUndoDoc->AddUndoTab( nTab, nTab, false, true );
2372                 rDoc.CopyToDocument( 0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
2373             }
2374         }
2375 
2376         aUndoRanges = rRanges;
2377 
2378         //! outlines from all tab?
2379         ScOutlineTable* pTable = rDoc.GetOutlineTable( nCurTab );
2380         if (pTable)
2381             pUndoTab.reset(new ScOutlineTable( *pTable ));
2382     }
2383 
2384     if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2385         aMarkData.MarkToMulti();
2386 
2387     bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
2388     bool bOutline = false;
2389 
2390     for (const SCTAB& nTab : aMarkData)
2391     {
2392         for (const sc::ColRowSpan & rRange : rRanges)
2393         {
2394             SCCOLROW nStartNo = rRange.mnStart;
2395             SCCOLROW nEndNo = rRange.mnEnd;
2396 
2397             if ( !bWidth )                      // height always blockwise
2398             {
2399                 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2400                 {
2401                     bool bAll = ( eMode==SC_SIZE_OPTIMAL );
2402                     bool bFiltered = false;
2403                     if (!bAll)
2404                     {
2405                         //  delete CRFlags::ManualSize for all in range,
2406                         //  then SetOptimalHeight with bShrink = FALSE
2407                         for (SCROW nRow = nStartNo; nRow <= nEndNo; ++nRow)
2408                         {
2409                             SCROW nLastRow = nRow;
2410                             if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
2411                             {
2412                                 nRow = nLastRow;
2413                                 continue;
2414                             }
2415 
2416                             CRFlags nOld = rDoc.GetRowFlags(nRow, nTab);
2417                             if (nOld & CRFlags::ManualSize)
2418                                 rDoc.SetRowFlags(nRow, nTab, nOld & ~CRFlags::ManualSize);
2419                         }
2420                     }
2421                     else
2422                     {
2423                         SCROW nLastRow = nStartNo;
2424                         if (rDoc.RowFiltered(nStartNo, nTab, nullptr, &nLastRow)
2425                             || nLastRow < nEndNo)
2426                             bFiltered = true;
2427                     }
2428 
2429 
2430                     double nPPTX = GetViewData().GetPPTX();
2431                     double nPPTY = GetViewData().GetPPTY();
2432                     Fraction aZoomX = GetViewData().GetZoomX();
2433                     Fraction aZoomY = GetViewData().GetZoomY();
2434 
2435                     ScSizeDeviceProvider aProv(pDocSh);
2436                     if (aProv.IsPrinter())
2437                     {
2438                         nPPTX = aProv.GetPPTX();
2439                         nPPTY = aProv.GetPPTY();
2440                         aZoomX = aZoomY = Fraction( 1, 1 );
2441                     }
2442 
2443                     sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, aProv.GetDevice());
2444                     aCxt.setForceAutoSize(bAll);
2445                     aCxt.setExtraHeight(nSizeTwips);
2446                     rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab, true);
2447 
2448                     if (bFiltered)
2449                         ShowFilteredRows(rDoc, nTab, nStartNo, nEndNo, bShow);
2450 
2451                     //  Manual-Flag already (re)set in SetOptimalHeight in case of bAll=sal_True
2452                     //  (set for Extra-Height, else reset).
2453                 }
2454                 else if ( eMode==SC_SIZE_DIRECT )
2455                 {
2456                     if (nSizeTwips)
2457                     {
2458                         rDoc.SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
2459                         rDoc.SetManualHeight( nStartNo, nEndNo, nTab, true );          // height was set manually
2460                     }
2461 
2462                     // tdf#36383 - Skip consecutive rows hidden by AutoFilter
2463                     ShowFilteredRows(rDoc, nTab, nStartNo, nEndNo, nSizeTwips != 0);
2464 
2465                     if (!bShow && nStartNo <= nCurY && nCurY <= nEndNo && nTab == nCurTab)
2466                     {
2467                         nCurY = -1;
2468                     }
2469                 }
2470                 else if ( eMode==SC_SIZE_SHOW )
2471                 {
2472                     rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
2473                 }
2474             }
2475             else                                // column width
2476             {
2477                 for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
2478                 {
2479                     const bool bIsColHidden = rDoc.ColHidden(nCol, nTab);
2480                     if ( eMode != SC_SIZE_VISOPT || !bIsColHidden )
2481                     {
2482                         sal_uInt16 nThisSize = nSizeTwips;
2483 
2484                         if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2485                             nThisSize = nSizeTwips + GetOptimalColWidth( nCol, nTab, bFormula );
2486                         if ( nThisSize )
2487                             rDoc.SetColWidth( nCol, nTab, nThisSize );
2488 
2489                         // tdf#131073 - Don't show hidden cols after setting optimal col width
2490                         if (eMode == SC_SIZE_OPTIMAL)
2491                             rDoc.ShowCol(nCol, nTab, !bIsColHidden);
2492                         else
2493                             rDoc.ShowCol( nCol, nTab, bShow );
2494 
2495                         if (!bShow && nCol == nCurX && nTab == nCurTab)
2496                         {
2497                             nCurX = -1;
2498                         }
2499                     }
2500                 }
2501             }
2502 
2503             //  adjust outline
2504             if (bWidth)
2505             {
2506                 if ( rDoc.UpdateOutlineCol( static_cast<SCCOL>(nStartNo),
2507                             static_cast<SCCOL>(nEndNo), nTab, bShow ) )
2508                     bOutline = true;
2509             }
2510             else
2511             {
2512                 if ( rDoc.UpdateOutlineRow( nStartNo, nEndNo, nTab, bShow ) )
2513                     bOutline = true;
2514             }
2515         }
2516         rDoc.SetDrawPageSize(nTab);
2517     }
2518 
2519     if (!bOutline)
2520         pUndoTab.reset();
2521 
2522     if (bRecord)
2523     {
2524         pDocSh->GetUndoManager()->AddUndoAction(
2525             std::make_unique<ScUndoWidthOrHeight>(
2526                 pDocSh, aMarkData, nStart, nCurTab, nEnd, nCurTab,
2527                 std::move(pUndoDoc), std::move(aUndoRanges), std::move(pUndoTab), eMode, nSizeTwips, bWidth));
2528     }
2529 
2530     if (nCurX < 0)
2531     {
2532         MoveCursorRel( 1, 0, SC_FOLLOW_LINE, false );
2533     }
2534 
2535     if (nCurY < 0)
2536     {
2537         MoveCursorRel( 0, 1, SC_FOLLOW_LINE, false );
2538     }
2539 
2540     // fdo#36247 Ensure that the drawing layer's map mode scaling factors match
2541     // the new heights and widths.
2542     GetViewData().GetView()->RefreshZoom();
2543 
2544     for (const SCTAB& nTab : aMarkData)
2545         rDoc.UpdatePageBreaks( nTab );
2546 
2547     bool bAffectsVisibility = (eMode != SC_SIZE_ORIGINAL && eMode != SC_SIZE_VISOPT);
2548     ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
2549             bWidth /* bColumns */, !bWidth /* bRows */,
2550             true /* bSizes*/, bAffectsVisibility /* bHidden */, bAffectsVisibility /* bFiltered */,
2551             false /* bGroups */, nCurTab);
2552     GetViewData().GetView()->UpdateScrollBars(bWidth ? COLUMN_HEADER : ROW_HEADER);
2553 
2554     {
2555         for (const SCTAB& nTab : aMarkData)
2556         {
2557             if (bWidth)
2558             {
2559                 if (rDoc.HasAttrib( static_cast<SCCOL>(nStart),0,nTab,
2560                             static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab,
2561                             HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
2562                     nStart = 0;
2563                 if (nStart > 0)             // go upwards because of Lines and cursor
2564                     --nStart;
2565                 pDocSh->PostPaint( static_cast<SCCOL>(nStart), 0, nTab,
2566                         rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid | PaintPartFlags::Top );
2567             }
2568             else
2569             {
2570                 if (rDoc.HasAttrib( 0,nStart,nTab, rDoc.MaxCol(), nEnd,nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
2571                     nStart = 0;
2572                 if (nStart != 0)
2573                     --nStart;
2574                 pDocSh->PostPaint( 0, nStart, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid | PaintPartFlags::Left );
2575             }
2576         }
2577 
2578         pDocSh->UpdateOle(GetViewData());
2579         if( !pDocSh->IsReadOnly() )
2580             aModificator.SetDocumentModified();
2581     }
2582 
2583     if ( !bWidth )
2584         return;
2585 
2586     ScModelObj* pModelObj = pDocSh->GetModel();
2587 
2588     if (!HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
2589         return;
2590 
2591     ScRangeList aChangeRanges;
2592     for (const SCTAB& nTab : aMarkData)
2593     {
2594         for (const sc::ColRowSpan & rRange : rRanges)
2595         {
2596             SCCOL nStartCol = rRange.mnStart;
2597             SCCOL nEndCol   = rRange.mnEnd;
2598             for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
2599             {
2600                 aChangeRanges.push_back( ScRange( nCol, 0, nTab ) );
2601             }
2602         }
2603     }
2604     HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"column-resize"_ustr);
2605 }
2606 
2607 //  column width/row height (via marked range)
2608 
SetMarkedWidthOrHeight(bool bWidth,ScSizeMode eMode,sal_uInt16 nSizeTwips)2609 void ScViewFunc::SetMarkedWidthOrHeight( bool bWidth, ScSizeMode eMode, sal_uInt16 nSizeTwips )
2610 {
2611     ScMarkData& rMark = GetViewData().GetMarkData();
2612 
2613     rMark.MarkToMulti();
2614     if (!rMark.IsMultiMarked())
2615     {
2616         SCCOL nCol = GetViewData().GetCurX();
2617         SCROW nRow = GetViewData().GetCurY();
2618         SCTAB nTab = GetViewData().GetTabNo();
2619         const ScRange aMarkRange( nCol, nRow, nTab);
2620         DoneBlockMode();
2621         InitOwnBlockMode( aMarkRange );
2622         rMark.SetMultiMarkArea( aMarkRange );
2623         MarkDataChanged();
2624     }
2625 
2626     std::vector<sc::ColRowSpan> aRanges =
2627         bWidth ? rMark.GetMarkedColSpans() : rMark.GetMarkedRowSpans();
2628 
2629     SetWidthOrHeight(bWidth, aRanges, eMode, nSizeTwips);
2630 
2631     rMark.MarkToSimple();
2632 }
2633 
ModifyCellSize(ScDirection eDir,bool bOptimal)2634 void ScViewFunc::ModifyCellSize( ScDirection eDir, bool bOptimal )
2635 {
2636     ScModule* pScMod = SC_MOD();
2637     bool bAnyEdit = pScMod->IsInputMode();
2638     SCCOL nCol = GetViewData().GetCurX();
2639     SCROW nRow = GetViewData().GetCurY();
2640     SCTAB nTab = GetViewData().GetTabNo();
2641     ScDocShell* pDocSh = GetViewData().GetDocShell();
2642     ScDocument& rDoc = pDocSh->GetDocument();
2643 
2644     bool bAllowed, bOnlyMatrix;
2645     if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2646         bAllowed = rDoc.IsBlockEditable( nTab, nCol,0, nCol,rDoc.MaxRow(), &bOnlyMatrix );
2647     else
2648         bAllowed = rDoc.IsBlockEditable( nTab, 0,nRow, rDoc.MaxCol(), nRow, &bOnlyMatrix );
2649     if ( !bAllowed && !bOnlyMatrix )
2650     {
2651         ErrorMessage(STR_PROTECTIONERR);
2652         return;
2653     }
2654 
2655     HideAllCursors();
2656 
2657     //! step size adjustable
2658     //  step size is also minimum
2659     constexpr sal_uInt16 nStepX = STD_COL_WIDTH / 5;
2660     const sal_uInt16 nStepY = rDoc.GetSheetOptimalMinRowHeight(nTab);
2661 
2662     sal_uInt16 nWidth = rDoc.GetColWidth( nCol, nTab );
2663     sal_uInt16 nHeight = rDoc.GetRowHeight( nRow, nTab );
2664     std::vector<sc::ColRowSpan> aRange(1, sc::ColRowSpan(0,0));
2665     if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2666     {
2667         if (bOptimal)               // width of this single cell
2668         {
2669             if ( bAnyEdit )
2670             {
2671                 //  when editing the actual entered width
2672                 ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData().GetViewShell() );
2673                 if (pHdl)
2674                 {
2675                     tools::Long nEdit = pHdl->GetTextSize().Width();       // in 0.01 mm
2676 
2677                     const ScPatternAttr* pPattern = rDoc.GetPattern( nCol, nRow, nTab );
2678                     const SvxMarginItem& rMItem = pPattern->GetItem(ATTR_MARGIN);
2679                     sal_uInt16 nMargin = rMItem.GetLeftMargin() + rMItem.GetRightMargin();
2680                     if ( pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Left )
2681                         nMargin = sal::static_int_cast<sal_uInt16>(
2682                             nMargin + pPattern->GetItem(ATTR_INDENT).GetValue() );
2683 
2684                     nWidth = std::round(o3tl::convert(nEdit * pDocSh->GetOutputFactor(),
2685                                                       o3tl::Length::mm100, o3tl::Length::twip))
2686                                 + nMargin + STD_EXTRA_WIDTH;
2687                 }
2688             }
2689             else
2690             {
2691                 double nPPTX = GetViewData().GetPPTX();
2692                 double nPPTY = GetViewData().GetPPTY();
2693                 Fraction aZoomX = GetViewData().GetZoomX();
2694                 Fraction aZoomY = GetViewData().GetZoomY();
2695 
2696                 ScSizeDeviceProvider aProv(pDocSh);
2697                 if (aProv.IsPrinter())
2698                 {
2699                     nPPTX = aProv.GetPPTX();
2700                     nPPTY = aProv.GetPPTY();
2701                     aZoomX = aZoomY = Fraction( 1, 1 );
2702                 }
2703 
2704                 tools::Long nPixel = rDoc.GetNeededSize( nCol, nRow, nTab, aProv.GetDevice(),
2705                                             nPPTX, nPPTY, aZoomX, aZoomY, true );
2706                 sal_uInt16 nTwips = static_cast<sal_uInt16>( nPixel / nPPTX );
2707                 if (nTwips != 0)
2708                     nWidth = nTwips + STD_EXTRA_WIDTH;
2709                 else
2710                     nWidth = STD_COL_WIDTH;
2711             }
2712         }
2713         else                        // increment / decrement
2714         {
2715             if ( eDir == DIR_RIGHT )
2716                 nWidth = sal::static_int_cast<sal_uInt16>( nWidth + nStepX );
2717             else if ( nWidth > nStepX )
2718                 nWidth = sal::static_int_cast<sal_uInt16>( nWidth - nStepX );
2719             if ( nWidth < nStepX ) nWidth = nStepX;
2720             if ( nWidth > MAX_COL_WIDTH ) nWidth = MAX_COL_WIDTH;
2721         }
2722         aRange[0].mnStart = nCol;
2723         aRange[0].mnEnd = nCol;
2724         SetWidthOrHeight(true, aRange, SC_SIZE_DIRECT, nWidth);
2725 
2726         //  adjust height of this row if width demands/allows this
2727 
2728         if (!bAnyEdit)
2729         {
2730             const ScPatternAttr* pPattern = rDoc.GetPattern( nCol, nRow, nTab );
2731             bool bNeedHeight =
2732                     pPattern->GetItem( ATTR_LINEBREAK ).GetValue() ||
2733                     pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Block;
2734             if (bNeedHeight)
2735                 AdjustRowHeight( nRow, nRow, true );
2736         }
2737     }
2738     else
2739     {
2740         ScSizeMode eMode;
2741         if (bOptimal)
2742         {
2743             eMode = SC_SIZE_OPTIMAL;
2744             nHeight = 0;
2745         }
2746         else
2747         {
2748             eMode = SC_SIZE_DIRECT;
2749             if ( eDir == DIR_BOTTOM )
2750                 nHeight = sal::static_int_cast<sal_uInt16>( nHeight + nStepY );
2751             else if ( nHeight > nStepY )
2752                 nHeight = sal::static_int_cast<sal_uInt16>( nHeight - nStepY );
2753             if ( nHeight < nStepY ) nHeight = nStepY;
2754             if ( nHeight > MAX_ROW_HEIGHT ) nHeight = MAX_ROW_HEIGHT;
2755         }
2756         aRange[0].mnStart = nRow;
2757         aRange[0].mnEnd = nRow;
2758         SetWidthOrHeight(false, aRange, eMode, nHeight);
2759     }
2760 
2761     if ( bAnyEdit )
2762     {
2763         UpdateEditView();
2764         if ( rDoc.HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HasAttrFlags::NeedHeight ) )
2765         {
2766             ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData().GetViewShell() );
2767             if (pHdl)
2768                 pHdl->SetModified();    // so that the height is adjusted with Enter
2769         }
2770     }
2771 
2772     ShowAllCursors();
2773 }
2774 
ProtectSheet(SCTAB nTab,const ScTableProtection & rProtect)2775 void ScViewFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
2776 {
2777     if (nTab == TABLEID_DOC)
2778         return;
2779 
2780     ScMarkData& rMark = GetViewData().GetMarkData();
2781     ScDocShell* pDocSh = GetViewData().GetDocShell();
2782     ScDocument& rDoc = pDocSh->GetDocument();
2783     ScDocFunc &rFunc = pDocSh->GetDocFunc();
2784     bool bUndo(rDoc.IsUndoEnabled());
2785 
2786     //  modifying several tabs is handled here
2787 
2788     if (bUndo)
2789     {
2790         OUString aUndo = ScResId( STR_UNDO_PROTECT_TAB );
2791         pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
2792     }
2793 
2794     for (const auto& rTab : rMark)
2795     {
2796         rFunc.ProtectSheet(rTab, rProtect);
2797     }
2798 
2799     if (bUndo)
2800         pDocSh->GetUndoManager()->LeaveListAction();
2801 
2802     UpdateLayerLocks();         //! broadcast to all views
2803 }
2804 
ProtectDoc(const OUString & rPassword)2805 void ScViewFunc::ProtectDoc( const OUString& rPassword )
2806 {
2807     ScDocShell* pDocSh = GetViewData().GetDocShell();
2808     ScDocFunc &rFunc = pDocSh->GetDocFunc();
2809 
2810     rFunc.Protect( TABLEID_DOC, rPassword );
2811 
2812     UpdateLayerLocks();         //! broadcast to all views
2813 }
2814 
Unprotect(SCTAB nTab,const OUString & rPassword)2815 bool ScViewFunc::Unprotect( SCTAB nTab, const OUString& rPassword )
2816 {
2817     ScMarkData& rMark = GetViewData().GetMarkData();
2818     ScDocShell* pDocSh = GetViewData().GetDocShell();
2819     ScDocument& rDoc = pDocSh->GetDocument();
2820     ScDocFunc &rFunc = pDocSh->GetDocFunc();
2821     bool bChanged = false;
2822     bool bUndo (rDoc.IsUndoEnabled());
2823 
2824     if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
2825     {
2826         bChanged = rFunc.Unprotect( nTab, rPassword, false );
2827         if (bChanged && nTab != TABLEID_DOC)
2828             SetTabProtectionSymbol(nTab, false);
2829     }
2830     else
2831     {
2832         //  modifying several tabs is handled here
2833 
2834         if (bUndo)
2835         {
2836             OUString aUndo = ScResId( STR_UNDO_UNPROTECT_TAB );
2837             pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
2838         }
2839 
2840         for (const auto& rTab : rMark)
2841         {
2842             if ( rFunc.Unprotect( rTab, rPassword, false ) )
2843             {
2844                 bChanged = true;
2845                 SetTabProtectionSymbol( rTab, false);
2846             }
2847         }
2848 
2849         if (bUndo)
2850             pDocSh->GetUndoManager()->LeaveListAction();
2851     }
2852 
2853     if (bChanged)
2854         UpdateLayerLocks();     //! broadcast to all views
2855 
2856     return bChanged;
2857 }
2858 
SetNoteText(const ScAddress & rPos,const OUString & rNoteText)2859 void ScViewFunc::SetNoteText( const ScAddress& rPos, const OUString& rNoteText )
2860 {
2861     GetViewData().GetDocShell()->GetDocFunc().SetNoteText( rPos, rNoteText, false );
2862 }
2863 
ReplaceNote(const ScAddress & rPos,const OUString & rNoteText,const OUString * pAuthor,const OUString * pDate)2864 void ScViewFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate )
2865 {
2866     GetViewData().GetDocShell()->GetDocFunc().ReplaceNote( rPos, rNoteText, pAuthor, pDate, false );
2867 }
2868 
SetNumberFormat(SvNumFormatType nFormatType,sal_uLong nAdd)2869 void ScViewFunc::SetNumberFormat( SvNumFormatType nFormatType, sal_uLong nAdd )
2870 {
2871     // not editable because of matrix only? attribute OK nonetheless
2872     bool bOnlyNotBecauseOfMatrix;
2873     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2874     {
2875         ErrorMessage(STR_PROTECTIONERR);
2876         return;
2877     }
2878 
2879     sal_uInt32          nNumberFormat = 0;
2880     ScViewData&         rViewData = GetViewData();
2881     ScDocument&         rDoc = rViewData.GetDocument();
2882     SvNumberFormatter*  pNumberFormatter = rDoc.GetFormatTable();
2883     LanguageType        eLanguage = ScGlobal::eLnge;
2884     ScPatternAttr       aNewAttrs(rDoc.getCellAttributeHelper());
2885 
2886     //  always take language from cursor position, even if there is a selection
2887 
2888     sal_uInt32 nCurrentNumberFormat = rDoc.GetNumberFormat( rViewData.GetCurX(),
2889                                                             rViewData.GetCurY(),
2890                                                             rViewData.GetTabNo());
2891     const SvNumberformat* pEntry = pNumberFormatter->GetEntry( nCurrentNumberFormat );
2892     if (pEntry)
2893         eLanguage = pEntry->GetLanguage();      // else keep ScGlobal::eLnge
2894 
2895     nNumberFormat = pNumberFormatter->GetStandardFormat( nFormatType, eLanguage ) + nAdd;
2896 
2897     SfxItemSet& rSet = aNewAttrs.GetItemSet();
2898     rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2899     //  ATTR_LANGUAGE_FORMAT not
2900     ApplySelectionPattern( aNewAttrs );
2901 }
2902 
SetNumFmtByStr(const OUString & rCode)2903 void ScViewFunc::SetNumFmtByStr( const OUString& rCode )
2904 {
2905     // not editable because of matrix only? attribute OK nonetheless
2906     bool bOnlyNotBecauseOfMatrix;
2907     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2908     {
2909         ErrorMessage(STR_PROTECTIONERR);
2910         return;
2911     }
2912 
2913     ScViewData&         rViewData = GetViewData();
2914     ScDocument&         rDoc = rViewData.GetDocument();
2915     SvNumberFormatter*  pFormatter = rDoc.GetFormatTable();
2916 
2917     //  language always from cursor position
2918 
2919     sal_uInt32 nCurrentNumberFormat = rDoc.GetNumberFormat( rViewData.GetCurX(), rViewData.GetCurY(),
2920                                                             rViewData.GetTabNo());
2921     const SvNumberformat* pEntry = pFormatter->GetEntry( nCurrentNumberFormat );
2922     LanguageType eLanguage = pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge;
2923 
2924     //  determine index for String
2925 
2926     bool bOk = true;
2927     sal_uInt32 nNumberFormat = pFormatter->GetEntryKey( rCode, eLanguage );
2928     if ( nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
2929     {
2930         //  enter new
2931 
2932         OUString    aFormat = rCode;    // will be changed
2933         sal_Int32   nErrPos = 0;
2934         SvNumFormatType nType   = SvNumFormatType::ALL;        //! ???
2935         bOk = pFormatter->PutEntry( aFormat, nErrPos, nType, nNumberFormat, eLanguage );
2936     }
2937 
2938     if ( bOk )          // valid format?
2939     {
2940         ScPatternAttr aNewAttrs(rDoc.getCellAttributeHelper());
2941         SfxItemSet& rSet = aNewAttrs.GetItemSet();
2942         rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2943         rSet.Put( SvxLanguageItem( eLanguage, ATTR_LANGUAGE_FORMAT ) );
2944         ApplySelectionPattern( aNewAttrs );
2945     }
2946 
2947     //! else return error / issue warning ???
2948 }
2949 
ChangeNumFmtDecimals(bool bIncrement)2950 void ScViewFunc::ChangeNumFmtDecimals( bool bIncrement )
2951 {
2952     // not editable because of matrix only? attribute OK nonetheless
2953     bool bOnlyNotBecauseOfMatrix;
2954     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2955     {
2956         ErrorMessage(STR_PROTECTIONERR);
2957         return;
2958     }
2959 
2960     ScDocument&         rDoc = GetViewData().GetDocument();
2961     SvNumberFormatter*  pFormatter = rDoc.GetFormatTable();
2962 
2963     SCCOL nCol = GetViewData().GetCurX();
2964     SCROW nRow = GetViewData().GetCurY();
2965     SCTAB nTab = GetViewData().GetTabNo();
2966 
2967     sal_uInt32 nOldFormat = rDoc.GetNumberFormat( nCol, nRow, nTab );
2968     const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
2969     if (!pOldEntry)
2970     {
2971         OSL_FAIL("numberformat not found !!!");
2972         return;
2973     }
2974 
2975     //  what have we got here?
2976 
2977     sal_uInt32 nNewFormat = nOldFormat;
2978     bool bError = false;
2979 
2980     LanguageType eLanguage = pOldEntry->GetLanguage();
2981     bool bThousand, bNegRed;
2982     sal_uInt16 nPrecision, nLeading;
2983     pOldEntry->GetFormatSpecialInfo( bThousand, bNegRed, nPrecision, nLeading );
2984 
2985     SvNumFormatType nOldType = pOldEntry->GetType();
2986     if ( SvNumFormatType::ALL == ( nOldType & (
2987                 SvNumFormatType::NUMBER |  SvNumFormatType::CURRENCY | SvNumFormatType::PERCENT | SvNumFormatType::SCIENTIFIC | SvNumFormatType::TIME ) ) )
2988     {
2989         //  date, fraction, logical, text can not be changed
2990         bError = true;
2991     }
2992 
2993     //! SvNumberformat has a Member bStandard, but doesn't disclose it
2994     bool bWasStandard = ( nOldFormat == pFormatter->GetStandardIndex( eLanguage ) );
2995     OUString sExponentialStandardFormat = u""_ustr;
2996     if (bWasStandard)
2997     {
2998         //  with "Standard" the decimal places depend on cell content
2999         //  0 if empty or text -> no decimal places
3000         double nVal = rDoc.GetValue( ScAddress( nCol, nRow, nTab ) );
3001 
3002         //  the ways of the Numberformatters are unfathomable, so try:
3003         OUString aOut;
3004         const Color* pCol;
3005         pOldEntry->GetOutputString( nVal, aOut, &pCol, pFormatter->GetNatNum(), pFormatter->GetROLanguageData() );
3006 
3007         nPrecision = 0;
3008         // 'E' for exponential is fixed in Numberformatter
3009         sal_Int32 nIndexE = aOut.indexOf('E');
3010         if ( nIndexE >= 0 )
3011         {
3012           sExponentialStandardFormat = aOut.copy( nIndexE ).replace( '-', '+' );
3013           for ( sal_Int32 i=1 ; i<sExponentialStandardFormat.getLength() ; i++ )
3014           {
3015             if ( sExponentialStandardFormat[i] >= '1' && sExponentialStandardFormat[i] <= '9' )
3016               sExponentialStandardFormat = sExponentialStandardFormat.replaceAt( i, 1, u"0" );
3017           }
3018           aOut = aOut.copy( 0, nIndexE ); // remove exponential part
3019         }
3020         OUString aDecSep( pFormatter->GetFormatDecimalSep( nOldFormat ) );
3021         sal_Int32 nPos = aOut.indexOf( aDecSep );
3022         if ( nPos >= 0 )
3023             nPrecision = aOut.getLength() - nPos - aDecSep.getLength();
3024         // else keep 0
3025     }
3026     else
3027     {
3028         if ( (nOldType & SvNumFormatType::SCIENTIFIC) && !bThousand &&
3029              (pOldEntry->GetFormatIntegerDigits()%3 == 0) && pOldEntry->GetFormatIntegerDigits() > 0 )
3030             bThousand =  true;
3031     }
3032 
3033     if (!bError)
3034     {
3035         if (bIncrement)
3036         {
3037             if (nPrecision<20)
3038                 ++nPrecision;           // increment
3039             else
3040                 bError = true;          // 20 is maximum
3041         }
3042         else
3043         {
3044             if (nPrecision)
3045                 --nPrecision;           // decrement
3046             else
3047                 bError = true;          // 0 is minimum
3048         }
3049     }
3050 
3051     if (!bError)
3052     {
3053         OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLanguage,
3054                                                           bThousand, bNegRed,
3055                                                           nPrecision, nLeading)
3056                                 + sExponentialStandardFormat;
3057 
3058         nNewFormat = pFormatter->GetEntryKey( aNewPicture, eLanguage );
3059         if ( nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3060         {
3061             sal_Int32 nErrPos = 0;
3062             SvNumFormatType nNewType = SvNumFormatType::ALL;
3063             bool bOk = pFormatter->PutEntry( aNewPicture, nErrPos,
3064                                                 nNewType, nNewFormat, eLanguage );
3065             OSL_ENSURE( bOk, "incorrect numberformat generated" );
3066             if (!bOk)
3067                 bError = true;
3068         }
3069     }
3070 
3071     if (!bError)
3072     {
3073         ScPatternAttr aNewAttrs(rDoc.getCellAttributeHelper());
3074         SfxItemSet& rSet = aNewAttrs.GetItemSet();
3075         rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
3076         //  ATTR_LANGUAGE_FORMAT not
3077         ApplySelectionPattern( aNewAttrs );
3078     }
3079 }
3080 
ChangeIndent(bool bIncrement)3081 void ScViewFunc::ChangeIndent( bool bIncrement )
3082 {
3083     ScViewData& rViewData = GetViewData();
3084     ScDocShell* pDocSh  = rViewData.GetDocShell();
3085     ScMarkData& rMark   = rViewData.GetMarkData();
3086 
3087     ScMarkData aWorkMark = rMark;
3088     ScViewUtil::UnmarkFiltered( aWorkMark, pDocSh->GetDocument() );
3089     aWorkMark.MarkToMulti();
3090     if (!aWorkMark.IsMultiMarked())
3091     {
3092         SCCOL nCol = rViewData.GetCurX();
3093         SCROW nRow = rViewData.GetCurY();
3094         SCTAB nTab = rViewData.GetTabNo();
3095         aWorkMark.SetMultiMarkArea( ScRange(nCol,nRow,nTab) );
3096     }
3097 
3098     bool bSuccess = pDocSh->GetDocFunc().ChangeIndent( aWorkMark, bIncrement, false );
3099     if (bSuccess)
3100     {
3101         pDocSh->UpdateOle(rViewData);
3102         StartFormatArea();
3103 
3104         // stuff for sidebar panels
3105         SfxBindings& rBindings = GetViewData().GetBindings();
3106         rBindings.Invalidate( SID_H_ALIGNCELL );
3107         rBindings.Invalidate( SID_ATTR_ALIGN_INDENT );
3108     }
3109 }
3110 
InsertName(const OUString & rName,const OUString & rSymbol,const OUString & rType)3111 bool ScViewFunc::InsertName( const OUString& rName, const OUString& rSymbol,
3112                                 const OUString& rType )
3113 {
3114     //  Type = P,R,C,F (and combinations)
3115     //! undo...
3116 
3117     bool bOk = false;
3118     ScDocShell* pDocSh = GetViewData().GetDocShell();
3119     ScDocument& rDoc = pDocSh->GetDocument();
3120     SCTAB nTab = GetViewData().GetTabNo();
3121     ScRangeName* pList = rDoc.GetRangeName();
3122 
3123     ScRangeData::Type nType = ScRangeData::Type::Name;
3124     auto pNewEntry = std::make_unique<ScRangeData>(
3125         rDoc, rName, rSymbol, ScAddress( GetViewData().GetCurX(),
3126         GetViewData().GetCurY(), nTab), nType );
3127     OUString aUpType = rType.toAsciiUpperCase();
3128     if ( aUpType.indexOf( 'P' ) != -1 )
3129         nType |= ScRangeData::Type::PrintArea;
3130     if ( aUpType.indexOf( 'R' ) != -1 )
3131         nType |= ScRangeData::Type::RowHeader;
3132     if ( aUpType.indexOf( 'C' ) != -1 )
3133         nType |= ScRangeData::Type::ColHeader;
3134     if ( aUpType.indexOf( 'F' ) != -1 )
3135         nType |= ScRangeData::Type::Criteria;
3136     pNewEntry->AddType(nType);
3137 
3138     if ( pNewEntry->GetErrCode() == FormulaError::NONE )     //  text valid?
3139     {
3140         ScDocShellModificator aModificator( *pDocSh );
3141 
3142         rDoc.PreprocessRangeNameUpdate();
3143 
3144         // input available yet? Then remove beforehand (=change)
3145         ScRangeData* pData = pList->findByUpperName(ScGlobal::getCharClass().uppercase(rName));
3146         if (pData)
3147         {                                   // take old Index
3148             pNewEntry->SetIndex(pData->GetIndex());
3149             pList->erase(*pData);
3150         }
3151 
3152         // don't delete, insert took ownership, even on failure!
3153         if ( pList->insert( pNewEntry.release() ) )
3154             bOk = true;
3155 
3156         rDoc.CompileHybridFormula();
3157 
3158         aModificator.SetDocumentModified();
3159         SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
3160     }
3161 
3162     return bOk;
3163 }
3164 
CreateNames(CreateNameFlags nFlags)3165 void ScViewFunc::CreateNames( CreateNameFlags nFlags )
3166 {
3167     bool bDone = false;
3168     ScRange aRange;
3169     if ( GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE )
3170         bDone = GetViewData().GetDocShell()->GetDocFunc().CreateNames( aRange, nFlags, false );
3171 
3172     if (!bDone)
3173         ErrorMessage(STR_CREATENAME_MARKERR);
3174 }
3175 
GetCreateNameFlags()3176 CreateNameFlags ScViewFunc::GetCreateNameFlags()
3177 {
3178     CreateNameFlags nFlags = CreateNameFlags::NONE;
3179 
3180     SCCOL nStartCol, nEndCol;
3181     SCROW nStartRow, nEndRow;
3182     SCTAB nDummy;
3183     if (GetViewData().GetSimpleArea(nStartCol,nStartRow,nDummy,nEndCol,nEndRow,nDummy) == SC_MARK_SIMPLE)
3184     {
3185         ScDocument& rDoc = GetViewData().GetDocument();
3186         SCTAB nTab = GetViewData().GetTabNo();
3187         bool bOk;
3188         SCCOL i;
3189         SCROW j;
3190 
3191         bOk = true;
3192         SCCOL nFirstCol = nStartCol;
3193         SCCOL nLastCol  = nEndCol;
3194         if (nStartCol+1 < nEndCol) { ++nFirstCol; --nLastCol; }
3195         for (i=nFirstCol; i<=nLastCol && bOk; i++)
3196             if (!rDoc.HasStringData( i,nStartRow,nTab ))
3197                 bOk = false;
3198         if (bOk)
3199             nFlags |= CreateNameFlags::Top;
3200         else                            // Bottom only if not Top
3201         {
3202             bOk = true;
3203             for (i=nFirstCol; i<=nLastCol && bOk; i++)
3204                 if (!rDoc.HasStringData( i,nEndRow,nTab ))
3205                     bOk = false;
3206             if (bOk)
3207                 nFlags |= CreateNameFlags::Bottom;
3208         }
3209 
3210         bOk = true;
3211         SCROW nFirstRow = nStartRow;
3212         SCROW nLastRow  = nEndRow;
3213         if (nStartRow+1 < nEndRow) { ++nFirstRow; --nLastRow; }
3214         for (j=nFirstRow; j<=nLastRow && bOk; j++)
3215             if (!rDoc.HasStringData( nStartCol,j,nTab ))
3216                 bOk = false;
3217         if (bOk)
3218             nFlags |= CreateNameFlags::Left;
3219         else                            // Right only if not Left
3220         {
3221             bOk = true;
3222             for (j=nFirstRow; j<=nLastRow && bOk; j++)
3223                 if (!rDoc.HasStringData( nEndCol,j,nTab ))
3224                     bOk = false;
3225             if (bOk)
3226                 nFlags |= CreateNameFlags::Right;
3227         }
3228     }
3229 
3230     if (nStartCol == nEndCol)
3231         nFlags &= ~CreateNameFlags( CreateNameFlags::Left | CreateNameFlags::Right );
3232     if (nStartRow == nEndRow)
3233         nFlags &= ~CreateNameFlags( CreateNameFlags::Top | CreateNameFlags::Bottom );
3234 
3235     return nFlags;
3236 }
3237 
InsertNameList()3238 void ScViewFunc::InsertNameList()
3239 {
3240     ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
3241     ScDocShell* pDocSh = GetViewData().GetDocShell();
3242     if ( pDocSh->GetDocFunc().InsertNameList( aPos, false ) )
3243         pDocSh->UpdateOle(GetViewData());
3244 }
3245 
UpdateSelectionArea(const ScMarkData & rSel,ScPatternAttr * pAttr)3246 void ScViewFunc::UpdateSelectionArea( const ScMarkData& rSel, ScPatternAttr* pAttr  )
3247 {
3248     ScDocShell* pDocShell = GetViewData().GetDocShell();
3249     ScRange aMarkRange;
3250     if (rSel.IsMultiMarked() )
3251         aMarkRange = rSel.GetMultiMarkArea();
3252     else
3253         aMarkRange = rSel.GetMarkArea();
3254 
3255     bool bSetLines = false;
3256     bool bSetAlign = false;
3257     if ( pAttr )
3258     {
3259         const SfxItemSet& rNewSet = pAttr->GetItemSet();
3260         bSetLines = rNewSet.GetItemState( ATTR_BORDER ) == SfxItemState::SET ||
3261         rNewSet.GetItemState( ATTR_SHADOW ) == SfxItemState::SET;
3262         bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY ) == SfxItemState::SET;
3263     }
3264 
3265     sal_uInt16 nExtFlags = 0;
3266     if ( bSetLines )
3267         nExtFlags |= SC_PF_LINES;
3268     if ( bSetAlign )
3269         nExtFlags |= SC_PF_WHOLEROWS;
3270 
3271     SCCOL nStartCol = aMarkRange.aStart.Col();
3272     SCROW nStartRow = aMarkRange.aStart.Row();
3273     SCTAB nStartTab = aMarkRange.aStart.Tab();
3274     SCCOL nEndCol = aMarkRange.aEnd.Col();
3275     SCROW nEndRow = aMarkRange.aEnd.Row();
3276     SCTAB nEndTab = aMarkRange.aEnd.Tab();
3277     pDocShell->PostPaint( nStartCol, nStartRow, nStartTab,
3278         nEndCol,   nEndRow,   nEndTab,
3279         PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
3280     ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
3281     pTabViewShell->AdjustBlockHeight(false, const_cast<ScMarkData*>(&rSel));
3282 }
3283 
3284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3285