Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / ui / view / viewfunc.cxx
blobad5741df3fdf868f9ecfe3ad8f32e60487663783
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include "scitems.hxx"
23 #include <editeng/eeitem.hxx>
25 #include <sfx2/app.hxx>
26 #include <svx/algitem.hxx>
27 #include <editeng/boxitem.hxx>
28 #include <editeng/editobj.hxx>
29 #include <editeng/editview.hxx>
30 #include <editeng/langitem.hxx>
31 #include <editeng/scripttypeitem.hxx>
32 #include <editeng/justifyitem.hxx>
33 #include <sfx2/bindings.hxx>
34 #include <svl/zforlist.hxx>
35 #include <svl/zformat.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/waitobj.hxx>
39 #include <vcl/wrkwin.hxx>
40 #include <stdlib.h>
42 #include "viewfunc.hxx"
43 #include "tabvwsh.hxx"
44 #include "docsh.hxx"
45 #include "attrib.hxx"
46 #include "patattr.hxx"
47 #include "docpool.hxx"
48 #include "uiitems.hxx"
49 #include "sc.hrc"
50 #include "undocell.hxx"
51 #include "undoblk.hxx"
52 #include "undotab.hxx"
53 #include "refundo.hxx"
54 #include "dbdata.hxx"
55 #include "olinetab.hxx"
56 #include "rangeutl.hxx"
57 #include "rangenam.hxx"
58 #include "globstr.hrc"
59 #include "global.hxx"
60 #include "stlsheet.hxx"
61 #include "editutil.hxx"
62 #include "formulacell.hxx"
63 #include "scresid.hxx"
64 #include "inputhdl.hxx"
65 #include "scmod.hxx"
66 #include "inputopt.hxx"
67 #include "compiler.hxx"
68 #include "docfunc.hxx"
69 #include "appoptio.hxx"
70 #include "dociter.hxx"
71 #include "sizedev.hxx"
72 #include "editable.hxx"
73 #include "scui_def.hxx"
74 #include "funcdesc.hxx"
75 #include "docuno.hxx"
76 #include "cellsuno.hxx"
77 #include "tokenarray.hxx"
78 #include <rowheightcontext.hxx>
79 #include <docfuncutil.hxx>
81 #include <memory>
83 static void lcl_PostRepaintCondFormat( const ScConditionalFormat *pCondFmt, ScDocShell *pDocSh )
85 if( pCondFmt )
87 const ScRangeList& rRanges = pCondFmt->GetRange();
89 pDocSh->PostPaint( rRanges, PAINT_ALL );
93 ScViewFunc::ScViewFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
94 ScTabView( pParent, rDocSh, pViewShell ),
95 bFormatValid( false )
99 ScViewFunc::~ScViewFunc()
103 void ScViewFunc::StartFormatArea()
105 // anything to do?
106 if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
107 return;
109 // start only with single cell (marked or cursor position)
110 ScRange aMarkRange;
111 bool bOk = (GetViewData().GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE);
112 if ( bOk && aMarkRange.aStart != aMarkRange.aEnd )
113 bOk = false;
115 if (bOk)
117 bFormatValid = true;
118 aFormatSource = aMarkRange.aStart;
119 aFormatArea = ScRange( aFormatSource );
121 else
122 bFormatValid = false; // discard old range
125 bool ScViewFunc::TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, bool bAttrChanged )
127 // anything to do?
128 if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
129 return false;
131 // Test: treat input with numberformat (bAttrChanged) always as new Attribute
132 // (discard old Area ). If not wanted, discard if-statement
133 if ( bAttrChanged )
135 StartFormatArea();
136 return false;
139 //! Test if cell empty ???
141 bool bFound = false;
142 ScRange aNewRange = aFormatArea;
143 if ( bFormatValid && nTab == aFormatSource.Tab() )
145 if ( nRow >= aFormatArea.aStart.Row() && nRow <= aFormatArea.aEnd.Row() )
147 // within range?
148 if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
150 bFound = true; // do not change range
152 // left ?
153 if ( nCol+1 == aFormatArea.aStart.Col() )
155 bFound = true;
156 aNewRange.aStart.SetCol( nCol );
158 // right ?
159 if ( nCol == aFormatArea.aEnd.Col()+1 )
161 bFound = true;
162 aNewRange.aEnd.SetCol( nCol );
165 if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
167 // top ?
168 if ( nRow+1 == aFormatArea.aStart.Row() )
170 bFound = true;
171 aNewRange.aStart.SetRow( nRow );
173 // bottom ?
174 if ( nRow == aFormatArea.aEnd.Row()+1 )
176 bFound = true;
177 aNewRange.aEnd.SetRow( nRow );
182 if (bFound)
183 aFormatArea = aNewRange; // extend
184 else
185 bFormatValid = false; // outside of range -> break
187 return bFound;
190 void ScViewFunc::DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
191 bool bAttrChanged )
193 ScDocShell* pDocSh = GetViewData().GetDocShell();
194 ScDocument& rDoc = pDocSh->GetDocument();
196 const ScPatternAttr* pSource = rDoc.GetPattern(
197 aFormatSource.Col(), aFormatSource.Row(), nTab );
198 if ( !static_cast<const ScMergeAttr&>(pSource->GetItem(ATTR_MERGE)).IsMerged() )
200 ScRange aRange( nCol, nRow, nTab, nCol, nRow, nTab );
201 ScMarkData aMark;
202 aMark.SetMarkArea( aRange );
204 ScDocFunc &rFunc = GetViewData().GetDocFunc();
206 // pOldPattern is only valid until call to ApplyAttributes!
207 const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
208 const ScStyleSheet* pSrcStyle = pSource->GetStyleSheet();
209 if ( pSrcStyle && pSrcStyle != pOldPattern->GetStyleSheet() )
210 rFunc.ApplyStyle( aMark, pSrcStyle->GetName(), false );
212 rFunc.ApplyAttributes( aMark, *pSource, false );
215 if ( bAttrChanged ) // value entered with number format?
216 aFormatSource.Set( nCol, nRow, nTab ); // then set a new source
219 // additional routines
221 sal_uInt16 ScViewFunc::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, bool bFormula )
223 ScDocShell* pDocSh = GetViewData().GetDocShell();
224 ScDocument& rDoc = pDocSh->GetDocument();
225 ScMarkData& rMark = GetViewData().GetMarkData();
227 double nPPTX = GetViewData().GetPPTX();
228 double nPPTY = GetViewData().GetPPTY();
229 Fraction aZoomX = GetViewData().GetZoomX();
230 Fraction aZoomY = GetViewData().GetZoomY();
232 ScSizeDeviceProvider aProv(pDocSh);
233 if (aProv.IsPrinter())
235 nPPTX = aProv.GetPPTX();
236 nPPTY = aProv.GetPPTY();
237 aZoomX = aZoomY = Fraction( 1, 1 );
240 sal_uInt16 nTwips = rDoc.GetOptimalColWidth( nCol, nTab, aProv.GetDevice(),
241 nPPTX, nPPTY, aZoomX, aZoomY, bFormula, &rMark );
242 return nTwips;
245 bool ScViewFunc::SelectionEditable( bool* pOnlyNotBecauseOfMatrix /* = NULL */ )
247 bool bRet;
248 ScDocument* pDoc = GetViewData().GetDocument();
249 ScMarkData& rMark = GetViewData().GetMarkData();
250 if (rMark.IsMarked() || rMark.IsMultiMarked())
251 bRet = pDoc->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix );
252 else
254 SCCOL nCol = GetViewData().GetCurX();
255 SCROW nRow = GetViewData().GetCurY();
256 SCTAB nTab = GetViewData().GetTabNo();
257 bRet = pDoc->IsBlockEditable( nTab, nCol, nRow, nCol, nRow,
258 pOnlyNotBecauseOfMatrix );
260 return bRet;
263 #ifndef LRU_MAX
264 #define LRU_MAX 10
265 #endif
267 static bool lcl_FunctionKnown( sal_uInt16 nOpCode )
269 const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
270 if ( pFuncList )
272 sal_uLong nCount = pFuncList->GetCount();
273 for (sal_uLong i=0; i<nCount; i++)
274 if ( pFuncList->GetFunction(i)->nFIndex == nOpCode )
275 return true;
277 return false;
280 static bool lcl_AddFunction( ScAppOptions& rAppOpt, sal_uInt16 nOpCode )
282 sal_uInt16 nOldCount = rAppOpt.GetLRUFuncListCount();
283 sal_uInt16* pOldList = rAppOpt.GetLRUFuncList();
284 sal_uInt16 nPos;
285 for (nPos=0; nPos<nOldCount; nPos++)
286 if (pOldList[nPos] == nOpCode) // is the function already in the list?
288 if ( nPos == 0 )
289 return false; // already at the top -> no change
291 // count doesn't change, so the original array is modified
293 for (sal_uInt16 nCopy=nPos; nCopy>0; nCopy--)
294 pOldList[nCopy] = pOldList[nCopy-1];
295 pOldList[0] = nOpCode;
297 return true; // list has changed
300 if ( !lcl_FunctionKnown( nOpCode ) )
301 return false; // not in function list -> no change
303 sal_uInt16 nNewCount = std::min( (sal_uInt16)(nOldCount + 1), (sal_uInt16)LRU_MAX );
304 sal_uInt16 nNewList[LRU_MAX];
305 nNewList[0] = nOpCode;
306 for (nPos=1; nPos<nNewCount; nPos++)
307 nNewList[nPos] = pOldList[nPos-1];
308 rAppOpt.SetLRUFuncList( nNewList, nNewCount );
310 return true; // list has changed
313 namespace HelperNotifyChanges
315 void NotifyIfChangesListeners(ScDocShell &rDocShell, ScMarkData& rMark, SCCOL nCol, SCROW nRow)
317 if (ScModelObj *pModelObj = getMustPropagateChangesModel(rDocShell))
319 ScRangeList aChangeRanges;
320 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
321 for (; itr != itrEnd; ++itr)
322 aChangeRanges.Append( ScRange( nCol, nRow, *itr ) );
324 HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, "cell-change");
329 // actual functions
331 // input - undo OK
332 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
333 const OUString& rString,
334 const EditTextObject* pData )
336 ScDocument* pDoc = GetViewData().GetDocument();
337 ScMarkData rMark(GetViewData().GetMarkData());
338 bool bRecord = pDoc->IsUndoEnabled();
339 SCTAB i;
341 ScDocShell* pDocSh = GetViewData().GetDocShell();
342 ScDocFunc &rFunc = GetViewData().GetDocFunc();
343 ScDocShellModificator aModificator( *pDocSh );
345 ScEditableTester aTester( pDoc, nCol,nRow, nCol,nRow, rMark );
346 if (!aTester.IsEditable())
348 ErrorMessage(aTester.GetMessageId());
349 PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there
350 return;
353 if ( bRecord )
354 rFunc.EnterListAction( STR_UNDO_ENTERDATA );
356 bool bFormula = false;
358 // a single '=' character is handled as string (needed for special filters)
359 if ( rString.getLength() > 1 )
361 if ( rString[0] == '=' )
363 // handle as formula
364 bFormula = true;
366 else if ( rString[0] == '+' || rString[0] == '-' )
368 // if there is more than one leading '+' or '-' character, remove the additional ones
369 sal_Int32 nIndex = 1;
370 sal_Int32 nLen = rString.getLength();
371 while ( nIndex < nLen && ( rString[ nIndex ] == '+' || rString[ nIndex ] == '-' ) )
373 ++nIndex;
375 OUString aString = rString.replaceAt( 1, nIndex - 1, "" );
377 // if the remaining part without the leading '+' or '-' character
378 // is non-empty and not a number, handle as formula
379 if ( aString.getLength() > 1 )
381 sal_uInt32 nFormat = 0;
382 pDoc->GetNumberFormat( nCol, nRow, nTab, nFormat );
383 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
384 double fNumber = 0;
385 if ( !pFormatter->IsNumberFormat( aString, nFormat, fNumber ) )
387 bFormula = true;
393 bool bNumFmtChanged = false;
394 if ( bFormula )
395 { // formula, compile with autoCorrection
396 i = rMark.GetFirstSelected();
397 ScAddress aPos( nCol, nRow, i );
398 ScCompiler aComp( pDoc, aPos);
399 aComp.SetGrammar(pDoc->GetGrammar());
400 //2do: enable/disable autoCorrection via calcoptions
401 aComp.SetAutoCorrection( true );
402 if ( rString[0] == '+' || rString[0] == '-' )
404 aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK );
406 OUString aFormula( rString );
407 ScTokenArray* pArr;
408 bool bAgain;
411 bAgain = false;
412 bool bAddEqual = false;
413 ScTokenArray* pArrFirst = pArr = aComp.CompileString( aFormula );
414 bool bCorrected = aComp.IsCorrected();
415 if ( bCorrected )
416 { // try to parse with first parser-correction
417 pArr = aComp.CompileString( aComp.GetCorrectedFormula() );
419 if ( !pArr->GetCodeError() )
421 bAddEqual = true;
422 aComp.CompileTokenArray();
423 bCorrected |= aComp.IsCorrected();
425 if ( bCorrected )
427 OUString aCorrectedFormula;
428 if ( bAddEqual )
430 aCorrectedFormula = "=" + aComp.GetCorrectedFormula();
432 else
433 aCorrectedFormula = aComp.GetCorrectedFormula();
434 short nResult;
435 if ( aCorrectedFormula.getLength() == 1 )
436 nResult = RET_NO; // empty formula, just '='
437 else
439 OUString aMessage( ScResId( SCSTR_FORMULA_AUTOCORRECTION ) );
440 aMessage += aCorrectedFormula;
441 nResult = ScopedVclPtrInstance<QueryBox>( GetViewData().GetDialogParent(),
442 WinBits(WB_YES_NO | WB_DEF_YES),
443 aMessage )->Execute();
445 if ( nResult == RET_YES )
447 aFormula = aCorrectedFormula;
448 if ( pArr != pArrFirst )
449 delete pArrFirst;
450 bAgain = true;
452 else
454 if ( pArr != pArrFirst )
456 delete pArr;
457 pArr = pArrFirst;
461 } while ( bAgain );
462 // to be used in multiple tabs, the formula must be compiled anew
463 // via ScFormulaCell copy-ctor because of RangeNames,
464 // the same code-array for all cells is not possible.
465 // If the array has an error, (it) must be RPN-erased in the newly generated
466 // cells and the error be set explicitly, so that
467 // via FormulaCell copy-ctor and Interpreter it will be, when possible,
468 // ironed out again, too intelligent.. e.g.: =1))
469 sal_uInt16 nError = pArr->GetCodeError();
470 if ( !nError )
472 // update list of recent functions with all functions that
473 // are not within parentheses
475 ScModule* pScMod = SC_MOD();
476 ScAppOptions aAppOpt = pScMod->GetAppOptions();
477 bool bOptChanged = false;
479 formula::FormulaToken** ppToken = pArr->GetArray();
480 sal_uInt16 nTokens = pArr->GetLen();
481 sal_uInt16 nLevel = 0;
482 for (sal_uInt16 nTP=0; nTP<nTokens; nTP++)
484 formula::FormulaToken* pTok = ppToken[nTP];
485 OpCode eOp = pTok->GetOpCode();
486 if ( eOp == ocOpen )
487 ++nLevel;
488 else if ( eOp == ocClose && nLevel )
489 --nLevel;
490 if ( nLevel == 0 && pTok->IsFunction() &&
491 lcl_AddFunction( aAppOpt, sal::static_int_cast<sal_uInt16>( eOp ) ) )
492 bOptChanged = true;
495 if ( bOptChanged )
497 pScMod->SetAppOptions(aAppOpt);
501 ScFormulaCell aCell(pDoc, aPos, *pArr, formula::FormulaGrammar::GRAM_DEFAULT, MM_NONE);
502 delete pArr;
504 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
505 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
506 for (; itr != itrEnd; ++itr)
508 i = *itr;
509 aPos.SetTab( i );
510 sal_uLong nIndex = (sal_uLong) static_cast<const SfxUInt32Item*>( pDoc->GetAttr(
511 nCol, nRow, i, ATTR_VALUE_FORMAT ))->GetValue();
512 if ( pFormatter->GetType( nIndex ) == css::util::NumberFormat::TEXT ||
513 ( ( rString[0] == '+' || rString[0] == '-' ) && nError && rString == aFormula ) )
515 if ( pData )
517 // A clone of pData will be stored in the cell.
518 rFunc.SetEditCell(aPos, *pData, true);
520 else
521 rFunc.SetStringCell(aPos, aFormula, true);
523 else
525 ScFormulaCell* pCell = new ScFormulaCell( aCell, *pDoc, aPos );
526 if ( nError )
528 pCell->GetCode()->DelRPN();
529 pCell->SetErrCode( nError );
530 if(pCell->GetCode()->IsHyperLink())
531 pCell->GetCode()->SetHyperLink(false);
533 rFunc.SetFormulaCell(aPos, pCell, true);
537 else
539 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
540 for ( ; itr != itrEnd; ++itr )
542 bool bNumFmtSet = false;
543 rFunc.SetNormalString( bNumFmtSet, ScAddress( nCol, nRow, *itr ), rString, false );
544 if (bNumFmtSet)
546 /* FIXME: if set on any sheet results in changed only on
547 * sheet nTab for TestFormatArea() and DoAutoAttributes() */
548 bNumFmtChanged = true;
553 bool bAutoFormat = TestFormatArea(nCol, nRow, nTab, bNumFmtChanged);
555 if (bAutoFormat)
556 DoAutoAttributes(nCol, nRow, nTab, bNumFmtChanged);
558 pDocSh->UpdateOle(&GetViewData());
560 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow);
562 if ( bRecord )
563 rFunc.EndListAction();
565 aModificator.SetDocumentModified();
566 lcl_PostRepaintCondFormat( pDoc->GetCondFormat( nCol, nRow, nTab ), pDocSh );
569 // enter value in single cell (on nTab only)
571 void ScViewFunc::EnterValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rValue )
573 ScDocument* pDoc = GetViewData().GetDocument();
574 ScDocShell* pDocSh = GetViewData().GetDocShell();
576 if ( pDoc && pDocSh )
578 bool bUndo(pDoc->IsUndoEnabled());
579 ScDocShellModificator aModificator( *pDocSh );
581 ScEditableTester aTester( pDoc, nTab, nCol,nRow, nCol,nRow );
582 if (aTester.IsEditable())
584 ScAddress aPos( nCol, nRow, nTab );
585 ScCellValue aUndoCell;
586 if (bUndo)
587 aUndoCell.assign(*pDoc, aPos);
589 pDoc->SetValue( nCol, nRow, nTab, rValue );
591 // because of ChangeTrack after change in document
592 if (bUndo)
594 pDocSh->GetUndoManager()->AddUndoAction(
595 new ScUndoEnterValue(pDocSh, aPos, aUndoCell, rValue));
598 pDocSh->PostPaintCell( aPos );
599 pDocSh->UpdateOle(&GetViewData());
600 aModificator.SetDocumentModified();
602 else
603 ErrorMessage(aTester.GetMessageId());
607 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
608 const EditTextObject& rData, bool bTestSimple )
610 ScDocShell* pDocSh = GetViewData().GetDocShell();
611 ScMarkData& rMark = GetViewData().GetMarkData();
612 ScDocument& rDoc = pDocSh->GetDocument();
613 bool bRecord = rDoc.IsUndoEnabled();
615 ScDocShellModificator aModificator( *pDocSh );
617 ScEditableTester aTester( &rDoc, nTab, nCol,nRow, nCol,nRow );
618 if (aTester.IsEditable())
621 // test for attribute
623 bool bSimple = false;
624 bool bCommon = false;
625 std::unique_ptr<ScPatternAttr> pCellAttrs;
626 OUString aString;
628 const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
629 ScTabEditEngine aEngine( *pOldPattern, rDoc.GetEnginePool() );
630 aEngine.SetText(rData);
632 if (bTestSimple) // test, if simple string without attribute
634 ScEditAttrTester aAttrTester( &aEngine );
635 bSimple = !aAttrTester.NeedsObject();
636 bCommon = aAttrTester.NeedsCellAttr();
638 // formulas have to be recognized even if they're formatted
639 // (but common attributes are still collected)
641 if ( !bSimple && aEngine.GetParagraphCount() == 1 )
643 OUString aParStr(aEngine.GetText( 0 ));
644 if ( aParStr[0] == '=' )
645 bSimple = true;
648 if (bCommon) // attribute for tab
650 pCellAttrs.reset(new ScPatternAttr( *pOldPattern ));
651 pCellAttrs->GetFromEditItemSet( &aAttrTester.GetAttribs() );
652 //! remove common attributes from EditEngine?
656 // #i97726# always get text for "repeat" of undo action
657 aString = ScEditUtil::GetSpaceDelimitedString(aEngine);
659 // undo
661 EditTextObject* pUndoData = nullptr;
662 ScUndoEnterData::ValuesType aOldValues;
664 if (bRecord && !bSimple)
666 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
667 for (; itr != itrEnd; ++itr)
669 ScUndoEnterData::Value aOldValue;
670 aOldValue.mnTab = *itr;
671 aOldValue.maCell.assign(rDoc, ScAddress(nCol, nRow, *itr));
672 aOldValues.push_back(aOldValue);
675 pUndoData = rData.Clone();
678 // enter data
680 if (bCommon)
681 rDoc.ApplyPattern(nCol,nRow,nTab,*pCellAttrs); //! undo
683 if (bSimple)
685 if (bCommon)
686 AdjustRowHeight(nRow,nRow);
688 EnterData(nCol,nRow,nTab,aString);
690 else
692 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
693 for (; itr != itrEnd; ++itr)
695 ScAddress aPos(nCol, nRow, *itr);
696 rDoc.SetEditText(aPos, rData, rDoc.GetEditPool());
699 if ( bRecord )
700 { // because of ChangeTrack current first
701 pDocSh->GetUndoManager()->AddUndoAction(
702 new ScUndoEnterData(pDocSh, ScAddress(nCol,nRow,nTab), aOldValues, aString, pUndoData));
705 HideAllCursors();
707 AdjustRowHeight(nRow,nRow);
709 itr = rMark.begin();
710 for (; itr != itrEnd; ++itr)
711 pDocSh->PostPaintCell( nCol, nRow, *itr );
713 ShowAllCursors();
715 pDocSh->UpdateOle(&GetViewData());
717 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow);
719 aModificator.SetDocumentModified();
721 lcl_PostRepaintCondFormat( rDoc.GetCondFormat( nCol, nRow, nTab ), pDocSh );
723 else
725 ErrorMessage(aTester.GetMessageId());
726 PaintArea( nCol, nRow, nCol, nRow ); // possibly the edit-engine is still painted there
730 void ScViewFunc::EnterDataAtCursor( const OUString& rString )
732 SCCOL nPosX = GetViewData().GetCurX();
733 SCROW nPosY = GetViewData().GetCurY();
734 SCTAB nTab = GetViewData().GetTabNo();
736 EnterData( nPosX, nPosY, nTab, rString );
739 void ScViewFunc::EnterMatrix( const OUString& rString, ::formula::FormulaGrammar::Grammar eGram )
741 ScViewData& rData = GetViewData();
742 const SCCOL nCol = rData.GetCurX();
743 const SCROW nRow = rData.GetCurY();
744 const ScMarkData& rMark = rData.GetMarkData();
745 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
747 // nothing marked -> temporarily calculate block
748 // with size of result formula to get the size
750 ScDocument* pDoc = rData.GetDocument();
751 SCTAB nTab = rData.GetTabNo();
752 ScFormulaCell aFormCell( pDoc, ScAddress(nCol,nRow,nTab), rString, eGram, MM_FORMULA );
754 SCSIZE nSizeX;
755 SCSIZE nSizeY;
756 aFormCell.GetResultDimensions( nSizeX, nSizeY );
757 if ( nSizeX != 0 && nSizeY != 0 &&
758 nCol+nSizeX-1 <= sal::static_int_cast<SCSIZE>(MAXCOL) &&
759 nRow+nSizeY-1 <= sal::static_int_cast<SCSIZE>(MAXROW) )
761 ScRange aResult( nCol, nRow, nTab,
762 sal::static_int_cast<SCCOL>(nCol+nSizeX-1),
763 sal::static_int_cast<SCROW>(nRow+nSizeY-1), nTab );
764 MarkRange( aResult, false );
768 ScRange aRange;
769 if (rData.GetSimpleArea(aRange) == SC_MARK_SIMPLE)
771 ScDocShell* pDocSh = rData.GetDocShell();
772 bool bSuccess = pDocSh->GetDocFunc().EnterMatrix(
773 aRange, &rMark, nullptr, rString, false, false, EMPTY_OUSTRING, eGram );
774 if (bSuccess)
775 pDocSh->UpdateOle(&GetViewData());
776 else
777 PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there
779 else
780 ErrorMessage(STR_NOMULTISELECT);
783 SvtScriptType ScViewFunc::GetSelectionScriptType()
785 SvtScriptType nScript = SvtScriptType::NONE;
787 ScDocument* pDoc = GetViewData().GetDocument();
788 const ScMarkData& rMark = GetViewData().GetMarkData();
789 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
791 // no selection -> cursor
793 nScript = pDoc->GetScriptType( GetViewData().GetCurX(),
794 GetViewData().GetCurY(), GetViewData().GetTabNo());
796 else
798 ScRangeList aRanges;
799 rMark.FillRangeListWithMarks( &aRanges, false );
800 nScript = pDoc->GetRangeScriptType(aRanges);
803 if (nScript == SvtScriptType::NONE)
804 nScript = ScGlobal::GetDefaultScriptType();
806 return nScript;
809 const ScPatternAttr* ScViewFunc::GetSelectionPattern()
811 // Don't use UnmarkFiltered in slot state functions, for performance reasons.
812 // The displayed state is always that of the whole selection including filtered rows.
814 const ScMarkData& rMark = GetViewData().GetMarkData();
815 ScDocument* pDoc = GetViewData().GetDocument();
816 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
818 // MarkToMulti is no longer necessary for pDoc->GetSelectionPattern
819 const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( rMark );
820 return pAttr;
822 else
824 SCCOL nCol = GetViewData().GetCurX();
825 SCROW nRow = GetViewData().GetCurY();
826 SCTAB nTab = GetViewData().GetTabNo();
828 ScMarkData aTempMark( rMark ); // copy sheet selection
829 aTempMark.SetMarkArea( ScRange( nCol, nRow, nTab ) );
830 const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( aTempMark );
831 return pAttr;
835 void ScViewFunc::GetSelectionFrame( SvxBoxItem& rLineOuter,
836 SvxBoxInfoItem& rLineInner )
838 ScDocument* pDoc = GetViewData().GetDocument();
839 const ScMarkData& rMark = GetViewData().GetMarkData();
841 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
842 pDoc->GetSelectionFrame( rMark, rLineOuter, rLineInner );
843 else
845 const ScPatternAttr* pAttrs =
846 pDoc->GetPattern( GetViewData().GetCurX(),
847 GetViewData().GetCurY(),
848 GetViewData().GetTabNo() );
850 rLineOuter = static_cast<const SvxBoxItem&> (pAttrs->GetItem( ATTR_BORDER ));
851 rLineInner = static_cast<const SvxBoxInfoItem&>(pAttrs->GetItem( ATTR_BORDER_INNER ));
852 rLineInner.SetTable(false);
853 rLineInner.SetDist(true);
854 rLineInner.SetMinDist(false);
858 // apply attribute - undo OK
860 // complete set ( ATTR_STARTINDEX, ATTR_ENDINDEX )
862 void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
863 const SfxItemSet* pOldSet )
865 // not editable because of matrix only? attribute OK nonetheless
866 bool bOnlyNotBecauseOfMatrix;
867 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
869 ErrorMessage(STR_PROTECTIONERR);
870 return;
873 ScPatternAttr aOldAttrs( new SfxItemSet(*pOldSet) );
874 ScPatternAttr aNewAttrs( new SfxItemSet(*pDialogSet) );
875 aNewAttrs.DeleteUnchanged( &aOldAttrs );
877 if ( pDialogSet->GetItemState( ATTR_VALUE_FORMAT ) == SfxItemState::SET )
878 { // don't reset to default SYSTEM GENERAL if not intended
879 sal_uInt32 nOldFormat =
880 static_cast<const SfxUInt32Item&>(pOldSet->Get( ATTR_VALUE_FORMAT )).GetValue();
881 sal_uInt32 nNewFormat =
882 static_cast<const SfxUInt32Item&>(pDialogSet->Get( ATTR_VALUE_FORMAT )).GetValue();
883 if ( nNewFormat != nOldFormat )
885 SvNumberFormatter* pFormatter =
886 GetViewData().GetDocument()->GetFormatTable();
887 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
888 LanguageType eOldLang =
889 pOldEntry ? pOldEntry->GetLanguage() : LANGUAGE_DONTKNOW;
890 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
891 LanguageType eNewLang =
892 pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
893 if ( eNewLang != eOldLang )
895 aNewAttrs.GetItemSet().Put(
896 SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
898 // only the language has changed -> do not touch numberformat-attribute
899 sal_uInt32 nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
900 if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
901 nNewMod <= SV_MAX_ANZ_STANDARD_FORMATE )
902 aNewAttrs.GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
907 const SvxBoxItem* pOldOuter = static_cast<const SvxBoxItem*> (&pOldSet->Get( ATTR_BORDER ));
908 const SvxBoxItem* pNewOuter = static_cast<const SvxBoxItem*> (&pDialogSet->Get( ATTR_BORDER ));
909 const SvxBoxInfoItem* pOldInner = static_cast<const SvxBoxInfoItem*> (&pOldSet->Get( ATTR_BORDER_INNER ));
910 const SvxBoxInfoItem* pNewInner = static_cast<const SvxBoxInfoItem*> (&pDialogSet->Get( ATTR_BORDER_INNER ));
911 SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
912 SfxItemPool* pNewPool = rNewSet.GetPool();
914 pNewPool->Put( *pNewOuter ); // don't delete yet
915 pNewPool->Put( *pNewInner );
916 rNewSet.ClearItem( ATTR_BORDER );
917 rNewSet.ClearItem( ATTR_BORDER_INNER );
920 * establish whether border attribute is to be set:
921 * 1. new != old
922 * 2. is one of the borders not-DontCare (since 238.f: IsxxValid())
926 bool bFrame = (pDialogSet->GetItemState( ATTR_BORDER ) != SfxItemState::DEFAULT)
927 || (pDialogSet->GetItemState( ATTR_BORDER_INNER ) != SfxItemState::DEFAULT);
929 if ( pNewOuter==pOldOuter && pNewInner==pOldInner )
930 bFrame = false;
932 // this should be intercepted by the pool: ?!??!??
934 if ( bFrame && pNewOuter && pNewInner )
935 if ( *pNewOuter == *pOldOuter && *pNewInner == *pOldInner )
936 bFrame = false;
938 if ( pNewInner )
940 bFrame = bFrame
941 && ( pNewInner->IsValid(SvxBoxInfoItemValidFlags::LEFT)
942 || pNewInner->IsValid(SvxBoxInfoItemValidFlags::RIGHT)
943 || pNewInner->IsValid(SvxBoxInfoItemValidFlags::TOP)
944 || pNewInner->IsValid(SvxBoxInfoItemValidFlags::BOTTOM)
945 || pNewInner->IsValid(SvxBoxInfoItemValidFlags::HORI)
946 || pNewInner->IsValid(SvxBoxInfoItemValidFlags::VERT) );
948 else
949 bFrame = false;
951 if (!bFrame)
952 ApplySelectionPattern( aNewAttrs ); // standard only
953 else
955 // if new items are default-items, overwrite the old items:
957 bool bDefNewOuter = ( SFX_ITEMS_STATICDEFAULT == pNewOuter->GetKind() );
958 bool bDefNewInner = ( SFX_ITEMS_STATICDEFAULT == pNewInner->GetKind() );
960 ApplyPatternLines( aNewAttrs,
961 bDefNewOuter ? pOldOuter : pNewOuter,
962 bDefNewInner ? pOldInner : pNewInner );
965 pNewPool->Remove( *pNewOuter ); // release
966 pNewPool->Remove( *pNewInner );
968 // adjust height
969 AdjustBlockHeight();
971 // CellContentChanged is called in ApplySelectionPattern / ApplyPatternLines
974 void ScViewFunc::ApplyAttr( const SfxPoolItem& rAttrItem )
976 // not editable because of matrix only? attribute OK nonetheless
977 bool bOnlyNotBecauseOfMatrix;
978 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
980 ErrorMessage(STR_PROTECTIONERR);
981 return;
984 ScPatternAttr aNewAttrs( new SfxItemSet( *GetViewData().GetDocument()->GetPool(),
985 ATTR_PATTERN_START, ATTR_PATTERN_END ) );
987 aNewAttrs.GetItemSet().Put( rAttrItem );
988 // if justify is set (with Buttons), always indentation 0
989 if ( rAttrItem.Which() == ATTR_HOR_JUSTIFY )
990 aNewAttrs.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, 0 ) );
991 ApplySelectionPattern( aNewAttrs );
993 AdjustBlockHeight();
995 // CellContentChanged is called in ApplySelectionPattern
998 // patterns and borders
1000 void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem* pNewOuter,
1001 const SvxBoxInfoItem* pNewInner )
1003 ScDocument* pDoc = GetViewData().GetDocument();
1004 ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
1005 ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1006 bool bRecord = true;
1007 if (!pDoc->IsUndoEnabled())
1008 bRecord = false;
1010 bool bRemoveAdjCellBorder = false;
1011 if( pNewOuter )
1012 bRemoveAdjCellBorder = pNewOuter->IsRemoveAdjacentCellBorder();
1013 ScRange aMarkRange, aMarkRangeWithEnvelope;
1014 aFuncMark.MarkToSimple();
1015 bool bMulti = aFuncMark.IsMultiMarked();
1016 if (bMulti)
1017 aFuncMark.GetMultiMarkArea( aMarkRange );
1018 else if (aFuncMark.IsMarked())
1019 aFuncMark.GetMarkArea( aMarkRange );
1020 else
1022 aMarkRange = ScRange( GetViewData().GetCurX(),
1023 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1024 DoneBlockMode();
1025 InitOwnBlockMode();
1026 aFuncMark.SetMarkArea(aMarkRange);
1027 MarkDataChanged();
1029 if( bRemoveAdjCellBorder )
1030 aFuncMark.GetSelectionCover( aMarkRangeWithEnvelope );
1031 else
1032 aMarkRangeWithEnvelope = aMarkRange;
1034 ScDocShell* pDocSh = GetViewData().GetDocShell();
1036 ScDocShellModificator aModificator( *pDocSh );
1038 if (bRecord)
1040 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1041 SCTAB nStartTab = aMarkRange.aStart.Tab();
1042 SCTAB nTabCount = pDoc->GetTableCount();
1043 bool bCopyOnlyMarked = false;
1044 if( !bRemoveAdjCellBorder )
1045 bCopyOnlyMarked = bMulti;
1046 pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
1047 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1048 for (; itr != itrEnd; ++itr)
1049 if (*itr != nStartTab)
1050 pUndoDoc->AddUndoTab( *itr, *itr );
1052 ScRange aCopyRange = aMarkRangeWithEnvelope;
1053 aCopyRange.aStart.SetTab(0);
1054 aCopyRange.aEnd.SetTab(nTabCount-1);
1055 pDoc->CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bCopyOnlyMarked, pUndoDoc, &aFuncMark );
1057 pDocSh->GetUndoManager()->AddUndoAction(
1058 new ScUndoSelectionAttr(
1059 pDocSh, aFuncMark,
1060 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), aMarkRange.aStart.Tab(),
1061 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), aMarkRange.aEnd.Tab(),
1062 pUndoDoc, bCopyOnlyMarked, &rAttr, pNewOuter, pNewInner, &aMarkRangeWithEnvelope ) );
1065 sal_uInt16 nExt = SC_PF_TESTMERGE;
1066 pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content before the change
1068 pDoc->ApplySelectionFrame( aFuncMark, pNewOuter, pNewInner );
1070 pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content after the change
1072 aFuncMark.MarkToMulti();
1073 pDoc->ApplySelectionPattern( rAttr, aFuncMark );
1075 pDocSh->PostPaint( aMarkRange, PAINT_GRID, nExt );
1076 pDocSh->UpdateOle(&GetViewData());
1077 aModificator.SetDocumentModified();
1078 CellContentChanged();
1080 StartFormatArea();
1083 // pattern only
1085 void ScViewFunc::ApplySelectionPattern( const ScPatternAttr& rAttr, bool bCursorOnly )
1087 ScViewData& rViewData = GetViewData();
1088 ScDocShell* pDocSh = rViewData.GetDocShell();
1089 ScDocument& rDoc = pDocSh->GetDocument();
1090 ScMarkData aFuncMark( rViewData.GetMarkData() ); // local copy for UnmarkFiltered
1091 ScViewUtil::UnmarkFiltered( aFuncMark, &rDoc );
1093 bool bRecord = true;
1094 if (!rDoc.IsUndoEnabled())
1095 bRecord = false;
1097 // State from old ItemSet doesn't matter for paint flags, as any change will be
1098 // from SfxItemState::SET in the new ItemSet (default is ignored in ApplyPattern).
1099 // New alignment is checked (check in PostPaint isn't enough) in case a right
1100 // alignment is changed to left.
1101 const SfxItemSet& rNewSet = rAttr.GetItemSet();
1102 bool bSetLines = rNewSet.GetItemState( ATTR_BORDER ) == SfxItemState::SET ||
1103 rNewSet.GetItemState( ATTR_SHADOW ) == SfxItemState::SET;
1104 bool bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY ) == SfxItemState::SET;
1106 sal_uInt16 nExtFlags = 0;
1107 if ( bSetLines )
1108 nExtFlags |= SC_PF_LINES;
1109 if ( bSetAlign )
1110 nExtFlags |= SC_PF_WHOLEROWS;
1112 ScDocShellModificator aModificator( *pDocSh );
1114 bool bMulti = aFuncMark.IsMultiMarked();
1115 aFuncMark.MarkToMulti();
1116 bool bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && aFuncMark.GetSelectCount() > 1);
1117 if (bOnlyTab)
1119 SCCOL nCol = rViewData.GetCurX();
1120 SCROW nRow = rViewData.GetCurY();
1121 SCTAB nTab = rViewData.GetTabNo();
1122 aFuncMark.SetMarkArea(ScRange(nCol,nRow,nTab));
1123 aFuncMark.MarkToMulti();
1126 ScRangeList aChangeRanges;
1128 if (aFuncMark.IsMultiMarked() && !bCursorOnly)
1130 ScRange aMarkRange;
1131 aFuncMark.GetMultiMarkArea( aMarkRange );
1132 SCTAB nTabCount = rDoc.GetTableCount();
1133 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1134 for (; itr != itrEnd; ++itr)
1136 ScRange aChangeRange( aMarkRange );
1137 aChangeRange.aStart.SetTab( *itr );
1138 aChangeRange.aEnd.SetTab( *itr );
1139 aChangeRanges.Append( aChangeRange );
1142 SCCOL nStartCol = aMarkRange.aStart.Col();
1143 SCROW nStartRow = aMarkRange.aStart.Row();
1144 SCTAB nStartTab = aMarkRange.aStart.Tab();
1145 SCCOL nEndCol = aMarkRange.aEnd.Col();
1146 SCROW nEndRow = aMarkRange.aEnd.Row();
1147 SCTAB nEndTab = aMarkRange.aEnd.Tab();
1149 ScUndoSelectionAttr* pUndoAttr = nullptr;
1150 ScEditDataArray* pEditDataArray = nullptr;
1151 if (bRecord)
1153 ScRange aCopyRange = aMarkRange;
1154 aCopyRange.aStart.SetTab(0);
1155 aCopyRange.aEnd.SetTab(nTabCount-1);
1157 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1158 pUndoDoc->InitUndo( &rDoc, nStartTab, nStartTab );
1159 itr = aFuncMark.begin();
1160 for (; itr != itrEnd; ++itr)
1161 if (*itr != nStartTab)
1162 pUndoDoc->AddUndoTab( *itr, *itr );
1163 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, pUndoDoc, &aFuncMark );
1165 aFuncMark.MarkToMulti();
1167 pUndoAttr = new ScUndoSelectionAttr(
1168 pDocSh, aFuncMark, nStartCol, nStartRow, nStartTab,
1169 nEndCol, nEndRow, nEndTab, pUndoDoc, bMulti, &rAttr );
1170 pDocSh->GetUndoManager()->AddUndoAction(pUndoAttr);
1171 pEditDataArray = pUndoAttr->GetDataArray();
1174 rDoc.ApplySelectionPattern( rAttr, aFuncMark, pEditDataArray );
1176 pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
1177 nEndCol, nEndRow, nEndTab,
1178 PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
1179 pDocSh->UpdateOle(&GetViewData());
1180 aModificator.SetDocumentModified();
1181 CellContentChanged();
1183 else // single cell - simpler undo
1185 SCCOL nCol = rViewData.GetCurX();
1186 SCROW nRow = rViewData.GetCurY();
1187 SCTAB nTab = rViewData.GetTabNo();
1189 EditTextObject* pOldEditData = nullptr;
1190 EditTextObject* pNewEditData = nullptr;
1191 ScAddress aPos(nCol, nRow, nTab);
1192 ScRefCellValue aCell(rDoc, aPos);
1193 if (aCell.meType == CELLTYPE_EDIT)
1195 const EditTextObject* pEditObj = aCell.mpEditText;
1196 pOldEditData = pEditObj->Clone();
1197 rDoc.RemoveEditTextCharAttribs(aPos, rAttr);
1198 pEditObj = rDoc.GetEditText(aPos);
1199 pNewEditData = pEditObj->Clone();
1202 aChangeRanges.Append(aPos);
1203 std::unique_ptr<ScPatternAttr> pOldPat(new ScPatternAttr(*rDoc.GetPattern( nCol, nRow, nTab )));
1205 rDoc.ApplyPattern( nCol, nRow, nTab, rAttr );
1207 const ScPatternAttr* pNewPat = rDoc.GetPattern( nCol, nRow, nTab );
1209 if (bRecord)
1211 ScUndoCursorAttr* pUndo = new ScUndoCursorAttr(
1212 pDocSh, nCol, nRow, nTab, pOldPat.get(), pNewPat, &rAttr );
1213 pUndo->SetEditData(pOldEditData, pNewEditData);
1214 pDocSh->GetUndoManager()->AddUndoAction(pUndo);
1216 pOldPat.reset(); // is copied in undo (Pool)
1218 pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
1219 pDocSh->UpdateOle(&GetViewData());
1220 aModificator.SetDocumentModified();
1221 CellContentChanged();
1224 ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh);
1225 if (pModelObj)
1227 css::uno::Sequence< css::beans::PropertyValue > aProperties;
1228 sal_Int32 nCount = 0;
1229 const SfxItemPropertyMap& rMap = ScCellObj::GetCellPropertyMap();
1230 PropertyEntryVector_t aPropVector = rMap.getPropertyEntries();
1231 for ( sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; ++nWhich )
1233 const SfxPoolItem* pItem = nullptr;
1234 if ( rNewSet.GetItemState( nWhich, true, &pItem ) == SfxItemState::SET && pItem )
1236 PropertyEntryVector_t::const_iterator aIt = aPropVector.begin();
1237 while ( aIt != aPropVector.end())
1239 if ( aIt->nWID == nWhich )
1241 css::uno::Any aVal;
1242 pItem->QueryValue( aVal, aIt->nMemberId );
1243 aProperties.realloc( nCount + 1 );
1244 aProperties[ nCount ].Name = aIt->sName;
1245 aProperties[ nCount ].Value <<= aVal;
1246 ++nCount;
1248 ++aIt;
1252 HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, "attribute", aProperties);
1255 StartFormatArea();
1258 void ScViewFunc::ApplyUserItemSet( const SfxItemSet& rItemSet )
1260 // ItemSet from UI, may have different pool
1262 bool bOnlyNotBecauseOfMatrix;
1263 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1265 ErrorMessage(STR_PROTECTIONERR);
1266 return;
1269 ScPatternAttr aNewAttrs( GetViewData().GetDocument()->GetPool() );
1270 SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
1271 rNewSet.Put( rItemSet, false );
1272 ApplySelectionPattern( aNewAttrs );
1274 AdjustBlockHeight();
1277 const SfxStyleSheet* ScViewFunc::GetStyleSheetFromMarked()
1279 // Don't use UnmarkFiltered in slot state functions, for performance reasons.
1280 // The displayed state is always that of the whole selection including filtered rows.
1282 const ScStyleSheet* pSheet = nullptr;
1283 ScViewData& rViewData = GetViewData();
1284 ScDocument* pDoc = rViewData.GetDocument();
1285 ScMarkData& rMark = rViewData.GetMarkData();
1287 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1288 pSheet = pDoc->GetSelectionStyle( rMark ); // MarkToMulti isn't necessary
1289 else
1290 pSheet = pDoc->GetStyle( rViewData.GetCurX(),
1291 rViewData.GetCurY(),
1292 rViewData.GetTabNo() );
1294 return pSheet;
1297 void ScViewFunc::SetStyleSheetToMarked( SfxStyleSheet* pStyleSheet )
1299 // not editable because of matrix only? attribute OK nonetheless
1300 bool bOnlyNotBecauseOfMatrix;
1301 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1303 ErrorMessage(STR_PROTECTIONERR);
1304 return;
1307 if ( !pStyleSheet) return;
1309 ScViewData& rViewData = GetViewData();
1310 ScDocShell* pDocSh = rViewData.GetDocShell();
1311 ScDocument& rDoc = pDocSh->GetDocument();
1312 ScMarkData aFuncMark( rViewData.GetMarkData() ); // local copy for UnmarkFiltered
1313 ScViewUtil::UnmarkFiltered( aFuncMark, &rDoc );
1314 SCTAB nTabCount = rDoc.GetTableCount();
1315 bool bRecord = true;
1316 if (!rDoc.IsUndoEnabled())
1317 bRecord = false;
1319 ScDocShellModificator aModificator( *pDocSh );
1321 if ( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() )
1323 ScRange aMarkRange;
1324 aFuncMark.MarkToMulti();
1325 aFuncMark.GetMultiMarkArea( aMarkRange );
1327 if ( bRecord )
1329 SCTAB nTab = rViewData.GetTabNo();
1330 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1331 pUndoDoc->InitUndo( &rDoc, nTab, nTab );
1332 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1333 for (; itr != itrEnd; ++itr)
1334 if (*itr != nTab)
1335 pUndoDoc->AddUndoTab( *itr, *itr );
1337 ScRange aCopyRange = aMarkRange;
1338 aCopyRange.aStart.SetTab(0);
1339 aCopyRange.aEnd.SetTab(nTabCount-1);
1340 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, true, pUndoDoc, &aFuncMark );
1341 aFuncMark.MarkToMulti();
1343 OUString aName = pStyleSheet->GetName();
1344 pDocSh->GetUndoManager()->AddUndoAction(
1345 new ScUndoSelectionStyle( pDocSh, aFuncMark, aMarkRange, aName, pUndoDoc ) );
1348 rDoc.ApplySelectionStyle( static_cast<ScStyleSheet&>(*pStyleSheet), aFuncMark );
1350 if (!AdjustBlockHeight())
1351 rViewData.GetDocShell()->PostPaint( aMarkRange, PAINT_GRID );
1353 aFuncMark.MarkToSimple();
1355 else
1357 SCCOL nCol = rViewData.GetCurX();
1358 SCROW nRow = rViewData.GetCurY();
1359 SCTAB nTab = rViewData.GetTabNo();
1361 if ( bRecord )
1363 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1364 pUndoDoc->InitUndo( &rDoc, nTab, nTab );
1365 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1366 for (; itr != itrEnd; ++itr)
1367 if (*itr != nTab)
1368 pUndoDoc->AddUndoTab( *itr, *itr );
1370 ScRange aCopyRange( nCol, nRow, 0, nCol, nRow, nTabCount-1 );
1371 rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, false, pUndoDoc );
1373 ScRange aMarkRange ( nCol, nRow, nTab );
1374 ScMarkData aUndoMark = aFuncMark;
1375 aUndoMark.SetMultiMarkArea( aMarkRange );
1377 OUString aName = pStyleSheet->GetName();
1378 pDocSh->GetUndoManager()->AddUndoAction(
1379 new ScUndoSelectionStyle( pDocSh, aUndoMark, aMarkRange, aName, pUndoDoc ) );
1382 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1383 for (; itr != itrEnd; ++itr)
1384 rDoc.ApplyStyle( nCol, nRow, *itr, static_cast<ScStyleSheet&>(*pStyleSheet) );
1386 if (!AdjustBlockHeight())
1387 rViewData.GetDocShell()->PostPaintCell( nCol, nRow, nTab );
1391 aModificator.SetDocumentModified();
1393 StartFormatArea();
1396 void ScViewFunc::RemoveStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1398 if ( !pStyleSheet) return;
1400 ScViewData& rViewData = GetViewData();
1401 ScDocument* pDoc = rViewData.GetDocument();
1402 ScDocShell* pDocSh = rViewData.GetDocShell();
1404 ScDocShellModificator aModificator( *pDocSh );
1406 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1407 pVirtDev->SetMapMode(MAP_PIXEL);
1408 pDoc->StyleSheetChanged( pStyleSheet, true, pVirtDev,
1409 rViewData.GetPPTX(),
1410 rViewData.GetPPTY(),
1411 rViewData.GetZoomX(),
1412 rViewData.GetZoomY() );
1414 pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
1415 aModificator.SetDocumentModified();
1417 ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1418 if (pHdl)
1419 pHdl->ForgetLastPattern();
1422 void ScViewFunc::UpdateStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1424 if ( !pStyleSheet) return;
1426 ScViewData& rViewData = GetViewData();
1427 ScDocument* pDoc = rViewData.GetDocument();
1428 ScDocShell* pDocSh = rViewData.GetDocShell();
1430 ScDocShellModificator aModificator( *pDocSh );
1432 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1433 pVirtDev->SetMapMode(MAP_PIXEL);
1434 pDoc->StyleSheetChanged( pStyleSheet, false, pVirtDev,
1435 rViewData.GetPPTX(),
1436 rViewData.GetPPTY(),
1437 rViewData.GetZoomX(),
1438 rViewData.GetZoomY() );
1440 pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
1441 aModificator.SetDocumentModified();
1443 ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1444 if (pHdl)
1445 pHdl->ForgetLastPattern();
1448 // insert cells - undo OK
1450 bool ScViewFunc::InsertCells( InsCellCmd eCmd, bool bRecord, bool bPartOfPaste )
1452 ScRange aRange;
1453 if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
1455 ScDocShell* pDocSh = GetViewData().GetDocShell();
1456 const ScMarkData& rMark = GetViewData().GetMarkData();
1457 bool bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, &rMark, eCmd, bRecord, false, bPartOfPaste );
1458 if (bSuccess)
1460 pDocSh->UpdateOle(&GetViewData());
1461 CellContentChanged();
1462 ResetAutoSpell();
1464 if ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_INSCOLS_AFTER )
1466 OUString aOperation = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER ) ?
1467 OUString("insert-rows"):
1468 OUString("insert-columns");
1469 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange, aOperation);
1472 return bSuccess;
1474 else
1476 ErrorMessage(STR_NOMULTISELECT);
1477 return false;
1481 // delete cells - undo OK
1483 void ScViewFunc::DeleteCells( DelCellCmd eCmd )
1485 ScRange aRange;
1486 if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
1488 ScDocShell* pDocSh = GetViewData().GetDocShell();
1489 const ScMarkData& rMark = GetViewData().GetMarkData();
1491 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1492 // #i94841# [Collaboration] if deleting rows is rejected, the content is sometimes wrong
1493 if ( pDocSh->IsDocShared() && ( eCmd == DEL_DELROWS || eCmd == DEL_DELCOLS ) )
1495 ScRange aDelRange( aRange.aStart );
1496 SCCOLROW nCount = 0;
1497 if ( eCmd == DEL_DELROWS )
1499 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
1501 else
1503 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Col() - aRange.aStart.Col() + 1 );
1505 while ( nCount > 0 )
1507 pDocSh->GetDocFunc().DeleteCells( aDelRange, &rMark, eCmd, false );
1508 --nCount;
1511 else
1512 #endif
1514 pDocSh->GetDocFunc().DeleteCells( aRange, &rMark, eCmd, false );
1517 pDocSh->UpdateOle(&GetViewData());
1518 CellContentChanged();
1519 ResetAutoSpell();
1521 if ( eCmd == DEL_DELROWS || eCmd == DEL_DELCOLS )
1523 OUString aOperation = ( eCmd == DEL_DELROWS) ?
1524 OUString("delete-rows"):
1525 OUString("delete-columns");
1526 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange, aOperation);
1529 // put cursor directly behind deleted range
1530 SCCOL nCurX = GetViewData().GetCurX();
1531 SCROW nCurY = GetViewData().GetCurY();
1532 if ( eCmd==DEL_CELLSLEFT || eCmd==DEL_DELCOLS )
1533 nCurX = aRange.aStart.Col();
1534 else
1535 nCurY = aRange.aStart.Row();
1536 SetCursor( nCurX, nCurY );
1538 else
1540 if (eCmd == DEL_DELCOLS)
1541 DeleteMulti( false );
1542 else if (eCmd == DEL_DELROWS)
1543 DeleteMulti( true );
1544 else
1545 ErrorMessage(STR_NOMULTISELECT);
1548 Unmark();
1551 void ScViewFunc::DeleteMulti( bool bRows )
1553 ScDocShell* pDocSh = GetViewData().GetDocShell();
1554 ScDocShellModificator aModificator( *pDocSh );
1555 SCTAB nTab = GetViewData().GetTabNo();
1556 ScDocument& rDoc = pDocSh->GetDocument();
1557 ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
1558 ScViewUtil::UnmarkFiltered( aFuncMark, &rDoc );
1560 bool bRecord = true;
1561 if (!rDoc.IsUndoEnabled())
1562 bRecord = false;
1564 std::vector<sc::ColRowSpan> aSpans;
1565 if (bRows)
1566 aSpans = aFuncMark.GetMarkedRowSpans();
1567 else
1568 aSpans = aFuncMark.GetMarkedColSpans();
1570 if (aSpans.empty())
1572 SCCOLROW nCurPos = bRows ? GetViewData().GetCurY() : GetViewData().GetCurX();
1573 aSpans.push_back(sc::ColRowSpan(nCurPos, nCurPos));
1576 // test if allowed
1578 sal_uInt16 nErrorId = 0;
1579 bool bNeedRefresh = false;
1580 for (size_t i = 0, n = aSpans.size(); i < n && !nErrorId; ++i)
1582 SCCOLROW nStart = aSpans[i].mnStart;
1583 SCCOLROW nEnd = aSpans[i].mnEnd;
1585 SCCOL nStartCol, nEndCol;
1586 SCROW nStartRow, nEndRow;
1587 if ( bRows )
1589 nStartCol = 0;
1590 nEndCol = MAXCOL;
1591 nStartRow = static_cast<SCROW>(nStart);
1592 nEndRow = static_cast<SCROW>(nEnd);
1594 else
1596 nStartCol = static_cast<SCCOL>(nStart);
1597 nEndCol = static_cast<SCCOL>(nEnd);
1598 nStartRow = 0;
1599 nEndRow = MAXROW;
1602 // cell protection (only needed for first range, as all following cells are moved)
1603 if (i == 0)
1605 // test to the end of the sheet
1606 ScEditableTester aTester( &rDoc, nTab, nStartCol, nStartRow, MAXCOL, MAXROW );
1607 if (!aTester.IsEditable())
1608 nErrorId = aTester.GetMessageId();
1611 // merged cells
1612 SCCOL nMergeStartX = nStartCol;
1613 SCROW nMergeStartY = nStartRow;
1614 SCCOL nMergeEndX = nEndCol;
1615 SCROW nMergeEndY = nEndRow;
1616 rDoc.ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1617 rDoc.ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1619 if ( nMergeStartX != nStartCol || nMergeStartY != nStartRow )
1621 // Disallow deleting parts of a merged cell.
1622 // Deleting the start is allowed (merge is removed), so the end doesn't have to be checked.
1624 nErrorId = STR_MSSG_DELETECELLS_0;
1626 if ( nMergeEndX != nEndCol || nMergeEndY != nEndRow )
1628 // detect if the start of a merged cell is deleted, so the merge flags can be refreshed
1630 bNeedRefresh = true;
1634 if ( nErrorId )
1636 ErrorMessage( nErrorId );
1637 return;
1640 // proceed
1642 WaitObject aWait( GetFrameWin() ); // important for TrackFormulas in UpdateReference
1644 ScDocument* pUndoDoc = nullptr;
1645 ScRefUndoData* pUndoData = nullptr;
1646 if (bRecord)
1648 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1649 pUndoDoc->InitUndo( &rDoc, nTab, nTab, !bRows, bRows ); // row height
1651 for (sc::ColRowSpan & rSpan : aSpans)
1653 SCCOLROW nStart = rSpan.mnStart;
1654 SCCOLROW nEnd = rSpan.mnEnd;
1655 if (bRows)
1656 rDoc.CopyToDocument( 0,nStart,nTab, MAXCOL,nEnd,nTab, InsertDeleteFlags::ALL,false,pUndoDoc );
1657 else
1658 rDoc.CopyToDocument( static_cast<SCCOL>(nStart),0,nTab,
1659 static_cast<SCCOL>(nEnd),MAXROW,nTab,
1660 InsertDeleteFlags::ALL,false,pUndoDoc );
1663 // all Formulas because of references
1664 SCTAB nTabCount = rDoc.GetTableCount();
1665 pUndoDoc->AddUndoTab( 0, nTabCount-1 );
1666 rDoc.CopyToDocument( 0,0,0, MAXCOL,MAXROW,MAXTAB, InsertDeleteFlags::FORMULA,false,pUndoDoc );
1668 pUndoData = new ScRefUndoData( &rDoc );
1670 rDoc.BeginDrawUndo();
1673 std::vector<sc::ColRowSpan>::const_reverse_iterator ri = aSpans.rbegin(), riEnd = aSpans.rend();
1674 for (; ri != riEnd; ++ri)
1676 SCCOLROW nEnd = ri->mnEnd;
1677 SCCOLROW nStart = ri->mnStart;
1679 if (bRows)
1680 rDoc.DeleteRow( 0,nTab, MAXCOL,nTab, nStart, static_cast<SCSIZE>(nEnd-nStart+1) );
1681 else
1682 rDoc.DeleteCol( 0,nTab, MAXROW,nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
1685 if (bNeedRefresh)
1687 SCCOLROW nFirstStart = aSpans[0].mnStart;
1688 SCCOL nStartCol = bRows ? 0 : static_cast<SCCOL>(nFirstStart);
1689 SCROW nStartRow = bRows ? static_cast<SCROW>(nFirstStart) : 0;
1690 SCCOL nEndCol = MAXCOL;
1691 SCROW nEndRow = MAXROW;
1693 rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
1694 rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
1697 if (bRecord)
1699 pDocSh->GetUndoManager()->AddUndoAction(
1700 new ScUndoDeleteMulti(
1701 pDocSh, bRows, bNeedRefresh, nTab, aSpans, pUndoDoc, pUndoData));
1704 if (!AdjustRowHeight(0, MAXROW))
1706 if (bRows)
1708 pDocSh->PostPaint(
1709 0, aSpans[0].mnStart, nTab,
1710 MAXCOL, MAXROW, nTab, (PAINT_GRID | PAINT_LEFT));
1712 else
1714 pDocSh->PostPaint(
1715 static_cast<SCCOL>(aSpans[0].mnStart), 0, nTab,
1716 MAXCOL, MAXROW, nTab, (PAINT_GRID | PAINT_TOP));
1720 ResetAutoSpell();
1721 aModificator.SetDocumentModified();
1723 CellContentChanged();
1725 // put cursor directly behind the first deleted range
1726 SCCOL nCurX = GetViewData().GetCurX();
1727 SCROW nCurY = GetViewData().GetCurY();
1728 if ( bRows )
1729 nCurY = aSpans[0].mnStart;
1730 else
1731 nCurX = static_cast<SCCOL>(aSpans[0].mnStart);
1732 SetCursor( nCurX, nCurY );
1734 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
1737 // delete contents
1739 void ScViewFunc::DeleteContents( InsertDeleteFlags nFlags )
1741 ScViewData& rViewData = GetViewData();
1742 rViewData.SetPasteMode( SC_PASTE_NONE );
1743 rViewData.GetViewShell()->UpdateCopySourceOverlay();
1745 // not editable because of matrix only? attribute OK nonetheless
1746 bool bOnlyNotBecauseOfMatrix;
1747 bool bEditable = SelectionEditable( &bOnlyNotBecauseOfMatrix );
1748 if ( !bEditable )
1750 if ( !(bOnlyNotBecauseOfMatrix &&
1751 ((nFlags & (InsertDeleteFlags::ATTRIB | InsertDeleteFlags::EDITATTR)) == nFlags)) )
1753 ErrorMessage(bOnlyNotBecauseOfMatrix ? STR_MATRIXFRAGMENTERR : STR_PROTECTIONERR);
1754 return;
1758 ScRange aMarkRange;
1759 bool bSimple = false;
1761 ScDocument* pDoc = GetViewData().GetDocument();
1762 ScDocShell* pDocSh = GetViewData().GetDocShell();
1763 ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
1764 ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1766 bool bRecord =true;
1767 if (!pDoc->IsUndoEnabled())
1768 bRecord = false;
1770 if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
1772 aMarkRange.aStart.SetCol(GetViewData().GetCurX());
1773 aMarkRange.aStart.SetRow(GetViewData().GetCurY());
1774 aMarkRange.aStart.SetTab(GetViewData().GetTabNo());
1775 aMarkRange.aEnd = aMarkRange.aStart;
1776 if ( pDoc->HasAttrib( aMarkRange, HASATTR_MERGED ) )
1778 aFuncMark.SetMarkArea( aMarkRange );
1780 else
1781 bSimple = true;
1784 HideAllCursors(); // for if summary is cancelled
1786 ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
1787 if (bSimple)
1788 rDocFunc.DeleteCell(aMarkRange.aStart, aFuncMark, nFlags, bRecord);
1789 else
1790 rDocFunc.DeleteContents(aFuncMark, nFlags, bRecord, false);
1792 pDocSh->UpdateOle(&GetViewData());
1794 if (ScModelObj *pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh))
1796 ScRangeList aChangeRanges;
1797 if ( bSimple )
1799 aChangeRanges.Append( aMarkRange );
1801 else
1803 aFuncMark.FillRangeListWithMarks( &aChangeRanges, false );
1805 HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
1808 CellContentChanged();
1809 ShowAllCursors();
1811 if ( nFlags & InsertDeleteFlags::ATTRIB )
1813 if ( nFlags & InsertDeleteFlags::CONTENTS )
1814 ForgetFormatArea();
1815 else
1816 StartFormatArea(); // delete attribute is also attribute-change
1820 // column width/row height (via header) - undo OK
1822 void ScViewFunc::SetWidthOrHeight(
1823 bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, ScSizeMode eMode,
1824 sal_uInt16 nSizeTwips, bool bRecord, ScMarkData* pMarkData )
1826 if (rRanges.empty())
1827 return;
1829 // Use view's mark if none specified, but do not modify the original data,
1830 // i.e. no MarkToMulti() on that.
1831 ScMarkData aMarkData( pMarkData ? *pMarkData : GetViewData().GetMarkData());
1833 ScDocShell* pDocSh = GetViewData().GetDocShell();
1834 ScDocument& rDoc = pDocSh->GetDocument();
1835 SCTAB nFirstTab = aMarkData.GetFirstSelected();
1836 SCTAB nCurTab = GetViewData().GetTabNo();
1837 SCTAB nTab;
1838 if (bRecord && !rDoc.IsUndoEnabled())
1839 bRecord = false;
1841 ScDocShellModificator aModificator( *pDocSh );
1843 bool bAllowed = true;
1844 ScMarkData::iterator itr = aMarkData.begin(), itrEnd = aMarkData.end();
1845 for (; itr != itrEnd && bAllowed; ++itr)
1847 for (size_t i = 0, n = rRanges.size(); i < n && bAllowed; ++i)
1849 bool bOnlyMatrix;
1850 if (bWidth)
1852 bAllowed = rDoc.IsBlockEditable(
1853 *itr, rRanges[i].mnStart, 0, rRanges[i].mnEnd, MAXROW,
1854 &bOnlyMatrix ) || bOnlyMatrix;
1856 else
1858 bAllowed = rDoc.IsBlockEditable(
1859 *itr, 0, rRanges[i].mnStart, MAXCOL,rRanges[i].mnEnd, &bOnlyMatrix) || bOnlyMatrix;
1864 // Allow users to resize cols/rows in readonly docs despite the r/o state.
1865 // It is frustrating to be unable to see content in mis-sized cells.
1866 if( !bAllowed && !pDocSh->IsReadOnly() )
1868 ErrorMessage(STR_PROTECTIONERR);
1869 return;
1872 SCCOLROW nStart = rRanges.front().mnStart;
1873 SCCOLROW nEnd = rRanges.back().mnEnd;
1875 bool bFormula = false;
1876 if ( eMode == SC_SIZE_OPTIMAL )
1878 const ScViewOptions& rOpts = GetViewData().GetOptions();
1879 bFormula = rOpts.GetOption( VOPT_FORMULAS );
1882 ScDocument* pUndoDoc = nullptr;
1883 ScOutlineTable* pUndoTab = nullptr;
1884 std::vector<sc::ColRowSpan> aUndoRanges;
1886 if ( bRecord )
1888 rDoc.BeginDrawUndo(); // Drawing Updates
1890 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1891 itr = aMarkData.begin();
1892 for (; itr != itrEnd; ++itr)
1894 if (bWidth)
1896 if ( *itr == nFirstTab )
1897 pUndoDoc->InitUndo( &rDoc, *itr, *itr, true );
1898 else
1899 pUndoDoc->AddUndoTab( *itr, *itr, true );
1900 rDoc.CopyToDocument( static_cast<SCCOL>(nStart), 0, *itr,
1901 static_cast<SCCOL>(nEnd), MAXROW, *itr, InsertDeleteFlags::NONE,
1902 false, pUndoDoc );
1904 else
1906 if ( *itr == nFirstTab )
1907 pUndoDoc->InitUndo( &rDoc, *itr, *itr, false, true );
1908 else
1909 pUndoDoc->AddUndoTab( *itr, *itr, false, true );
1910 rDoc.CopyToDocument( 0, nStart, *itr, MAXCOL, nEnd, *itr, InsertDeleteFlags::NONE, false, pUndoDoc );
1914 aUndoRanges = rRanges;
1916 //! outlines from all tab?
1917 ScOutlineTable* pTable = rDoc.GetOutlineTable( nCurTab );
1918 if (pTable)
1919 pUndoTab = new ScOutlineTable( *pTable );
1922 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
1923 aMarkData.MarkToMulti();
1925 bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
1926 bool bOutline = false;
1928 itr = aMarkData.begin();
1929 for (; itr != itrEnd; ++itr)
1931 nTab = *itr;
1933 for (const sc::ColRowSpan & rRange : rRanges)
1935 SCCOLROW nStartNo = rRange.mnStart;
1936 SCCOLROW nEndNo = rRange.mnEnd;
1938 if ( !bWidth ) // height always blockwise
1940 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
1942 bool bAll = ( eMode==SC_SIZE_OPTIMAL );
1943 if (!bAll)
1945 // delete CR_MANUALSIZE for all in range,
1946 // then SetOptimalHeight with bShrink = FALSE
1947 for (SCROW nRow = nStartNo; nRow <= nEndNo; ++nRow)
1949 SCROW nLastRow = nRow;
1950 if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
1952 nRow = nLastRow;
1953 continue;
1956 sal_uInt8 nOld = rDoc.GetRowFlags(nRow, nTab);
1957 if (nOld & CR_MANUALSIZE)
1958 rDoc.SetRowFlags(nRow, nTab, nOld & ~CR_MANUALSIZE);
1962 double nPPTX = GetViewData().GetPPTX();
1963 double nPPTY = GetViewData().GetPPTY();
1964 Fraction aZoomX = GetViewData().GetZoomX();
1965 Fraction aZoomY = GetViewData().GetZoomY();
1967 ScSizeDeviceProvider aProv(pDocSh);
1968 if (aProv.IsPrinter())
1970 nPPTX = aProv.GetPPTX();
1971 nPPTY = aProv.GetPPTY();
1972 aZoomX = aZoomY = Fraction( 1, 1 );
1975 sc::RowHeightContext aCxt(nPPTX, nPPTY, aZoomX, aZoomY, aProv.GetDevice());
1976 aCxt.setForceAutoSize(bAll);
1977 aCxt.setExtraHeight(nSizeTwips);
1978 rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab);
1979 if (bAll)
1980 rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
1982 // Manual-Flag already (re)set in SetOptimalHeight in case of bAll=sal_True
1983 // (set for Extra-Height, else reset).
1985 else if ( eMode==SC_SIZE_DIRECT )
1987 if (nSizeTwips)
1989 rDoc.SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
1990 rDoc.SetManualHeight( nStartNo, nEndNo, nTab, true ); // height was set manually
1992 rDoc.ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
1994 else if ( eMode==SC_SIZE_SHOW )
1996 rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
1999 else // column width
2001 for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
2003 if ( eMode != SC_SIZE_VISOPT || !rDoc.ColHidden(nCol, nTab) )
2005 sal_uInt16 nThisSize = nSizeTwips;
2007 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2008 nThisSize = nSizeTwips + GetOptimalColWidth( nCol, nTab, bFormula );
2009 if ( nThisSize )
2010 rDoc.SetColWidth( nCol, nTab, nThisSize );
2012 rDoc.ShowCol( nCol, nTab, bShow );
2017 // adjust outline
2019 if (bWidth)
2021 if ( rDoc.UpdateOutlineCol( static_cast<SCCOL>(nStartNo),
2022 static_cast<SCCOL>(nEndNo), nTab, bShow ) )
2023 bOutline = true;
2025 else
2027 if ( rDoc.UpdateOutlineRow( nStartNo, nEndNo, nTab, bShow ) )
2028 bOutline = true;
2031 rDoc.SetDrawPageSize(nTab);
2034 if (!bOutline)
2035 DELETEZ(pUndoTab);
2037 if (bRecord)
2039 pDocSh->GetUndoManager()->AddUndoAction(
2040 new ScUndoWidthOrHeight(
2041 pDocSh, aMarkData, nStart, nCurTab, nEnd, nCurTab,
2042 pUndoDoc, aUndoRanges, pUndoTab, eMode, nSizeTwips, bWidth));
2045 // fdo#36247 Ensure that the drawing layer's map mode scaling factors match
2046 // the new heights and widths.
2047 GetViewData().GetView()->RefreshZoom();
2049 itr = aMarkData.begin();
2050 for (; itr != itrEnd; ++itr)
2051 rDoc.UpdatePageBreaks( *itr );
2053 GetViewData().GetView()->UpdateScrollBars();
2056 itr = aMarkData.begin();
2057 for (; itr != itrEnd; ++itr)
2059 nTab = *itr;
2060 if (bWidth)
2062 if (rDoc.HasAttrib( static_cast<SCCOL>(nStart),0,nTab,
2063 static_cast<SCCOL>(nEnd),MAXROW,nTab,
2064 HASATTR_MERGED | HASATTR_OVERLAPPED ))
2065 nStart = 0;
2066 if (nStart > 0) // go upwards because of Lines and cursor
2067 --nStart;
2068 pDocSh->PostPaint( static_cast<SCCOL>(nStart), 0, nTab,
2069 MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_TOP );
2071 else
2073 if (rDoc.HasAttrib( 0,nStart,nTab, MAXCOL,nEnd,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
2074 nStart = 0;
2075 if (nStart != 0)
2076 --nStart;
2077 pDocSh->PostPaint( 0, nStart, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_LEFT );
2081 pDocSh->UpdateOle(&GetViewData());
2082 if( !pDocSh->IsReadOnly() )
2083 aModificator.SetDocumentModified();
2086 if ( bWidth )
2088 if (ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh))
2090 ScRangeList aChangeRanges;
2091 itr = aMarkData.begin();
2092 for (; itr != itrEnd; ++itr)
2094 nTab = *itr;
2095 for (const sc::ColRowSpan & rRange : rRanges)
2097 SCCOL nStartCol = rRange.mnStart;
2098 SCCOL nEndCol = rRange.mnEnd;
2099 for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
2101 aChangeRanges.Append( ScRange( nCol, 0, nTab ) );
2105 HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, "column-resize");
2110 // column width/row height (via marked range)
2112 void ScViewFunc::SetMarkedWidthOrHeight( bool bWidth, ScSizeMode eMode, sal_uInt16 nSizeTwips )
2114 ScMarkData& rMark = GetViewData().GetMarkData();
2116 rMark.MarkToMulti();
2117 if (!rMark.IsMultiMarked())
2119 SCCOL nCol = GetViewData().GetCurX();
2120 SCROW nRow = GetViewData().GetCurY();
2121 SCTAB nTab = GetViewData().GetTabNo();
2122 DoneBlockMode();
2123 InitOwnBlockMode();
2124 rMark.SetMultiMarkArea( ScRange( nCol,nRow,nTab ) );
2125 MarkDataChanged();
2128 std::vector<sc::ColRowSpan> aRanges =
2129 bWidth ? rMark.GetMarkedColSpans() : rMark.GetMarkedRowSpans();
2131 SetWidthOrHeight(bWidth, aRanges, eMode, nSizeTwips);
2133 rMark.MarkToSimple();
2136 void ScViewFunc::ModifyCellSize( ScDirection eDir, bool bOptimal )
2138 //! step size adjustable
2139 // step size is also minimum
2140 sal_uInt16 nStepX = STD_COL_WIDTH / 5;
2141 sal_uInt16 nStepY = ScGlobal::nStdRowHeight;
2143 ScModule* pScMod = SC_MOD();
2144 bool bAnyEdit = pScMod->IsInputMode();
2145 SCCOL nCol = GetViewData().GetCurX();
2146 SCROW nRow = GetViewData().GetCurY();
2147 SCTAB nTab = GetViewData().GetTabNo();
2148 ScDocShell* pDocSh = GetViewData().GetDocShell();
2149 ScDocument& rDoc = pDocSh->GetDocument();
2151 bool bAllowed, bOnlyMatrix;
2152 if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2153 bAllowed = rDoc.IsBlockEditable( nTab, nCol,0, nCol,MAXROW, &bOnlyMatrix );
2154 else
2155 bAllowed = rDoc.IsBlockEditable( nTab, 0,nRow, MAXCOL,nRow, &bOnlyMatrix );
2156 if ( !bAllowed && !bOnlyMatrix )
2158 ErrorMessage(STR_PROTECTIONERR);
2159 return;
2162 HideAllCursors();
2164 sal_uInt16 nWidth = rDoc.GetColWidth( nCol, nTab );
2165 sal_uInt16 nHeight = rDoc.GetRowHeight( nRow, nTab );
2166 std::vector<sc::ColRowSpan> aRange(1, sc::ColRowSpan(0,0));
2167 if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2169 if (bOptimal) // width of this single cell
2171 if ( bAnyEdit )
2173 // when editing the actual entered width
2174 ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData().GetViewShell() );
2175 if (pHdl)
2177 long nEdit = pHdl->GetTextSize().Width(); // in 0.01 mm
2179 const ScPatternAttr* pPattern = rDoc.GetPattern( nCol, nRow, nTab );
2180 const SvxMarginItem& rMItem =
2181 static_cast<const SvxMarginItem&>(pPattern->GetItem(ATTR_MARGIN));
2182 sal_uInt16 nMargin = rMItem.GetLeftMargin() + rMItem.GetRightMargin();
2183 if ( static_cast<const SvxHorJustifyItem&>( pPattern->
2184 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_LEFT )
2185 nMargin = sal::static_int_cast<sal_uInt16>(
2186 nMargin + static_cast<const SfxUInt16Item&>(pPattern->GetItem(ATTR_INDENT)).GetValue() );
2188 nWidth = (sal_uInt16)(nEdit * pDocSh->GetOutputFactor() / HMM_PER_TWIPS)
2189 + nMargin + STD_EXTRA_WIDTH;
2192 else
2194 double nPPTX = GetViewData().GetPPTX();
2195 double nPPTY = GetViewData().GetPPTY();
2196 Fraction aZoomX = GetViewData().GetZoomX();
2197 Fraction aZoomY = GetViewData().GetZoomY();
2199 ScSizeDeviceProvider aProv(pDocSh);
2200 if (aProv.IsPrinter())
2202 nPPTX = aProv.GetPPTX();
2203 nPPTY = aProv.GetPPTY();
2204 aZoomX = aZoomY = Fraction( 1, 1 );
2207 long nPixel = rDoc.GetNeededSize( nCol, nRow, nTab, aProv.GetDevice(),
2208 nPPTX, nPPTY, aZoomX, aZoomY, true );
2209 sal_uInt16 nTwips = (sal_uInt16)( nPixel / nPPTX );
2210 if (nTwips != 0)
2211 nWidth = nTwips + STD_EXTRA_WIDTH;
2212 else
2213 nWidth = STD_COL_WIDTH;
2216 else // increment / decrement
2218 if ( eDir == DIR_RIGHT )
2219 nWidth = sal::static_int_cast<sal_uInt16>( nWidth + nStepX );
2220 else if ( nWidth > nStepX )
2221 nWidth = sal::static_int_cast<sal_uInt16>( nWidth - nStepX );
2222 if ( nWidth < nStepX ) nWidth = nStepX;
2223 if ( nWidth > MAX_COL_WIDTH ) nWidth = MAX_COL_WIDTH;
2225 aRange[0].mnStart = nCol;
2226 aRange[0].mnEnd = nCol;
2227 SetWidthOrHeight(true, aRange, SC_SIZE_DIRECT, nWidth);
2229 // adjust height of this row if width demands/allows this
2231 if (!bAnyEdit)
2233 const ScPatternAttr* pPattern = rDoc.GetPattern( nCol, nRow, nTab );
2234 bool bNeedHeight =
2235 static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_LINEBREAK )).GetValue() ||
2236 static_cast<const SvxHorJustifyItem&>(pPattern->
2237 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK;
2238 if (bNeedHeight)
2239 AdjustRowHeight( nRow, nRow );
2242 else
2244 ScSizeMode eMode;
2245 if (bOptimal)
2247 eMode = SC_SIZE_OPTIMAL;
2248 nHeight = 0;
2250 else
2252 eMode = SC_SIZE_DIRECT;
2253 if ( eDir == DIR_BOTTOM )
2254 nHeight = sal::static_int_cast<sal_uInt16>( nHeight + nStepY );
2255 else if ( nHeight > nStepY )
2256 nHeight = sal::static_int_cast<sal_uInt16>( nHeight - nStepY );
2257 if ( nHeight < nStepY ) nHeight = nStepY;
2258 if ( nHeight > MAX_ROW_HEIGHT ) nHeight = MAX_ROW_HEIGHT;
2260 aRange[0].mnStart = nRow;
2261 aRange[0].mnEnd = nRow;
2262 SetWidthOrHeight(false, aRange, eMode, nHeight);
2265 if ( bAnyEdit )
2267 UpdateEditView();
2268 if ( rDoc.HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_NEEDHEIGHT ) )
2270 ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData().GetViewShell() );
2271 if (pHdl)
2272 pHdl->SetModified(); // so that the height is adjusted with Enter
2276 ShowAllCursors();
2279 void ScViewFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
2281 if (nTab == TABLEID_DOC)
2282 return;
2284 ScMarkData& rMark = GetViewData().GetMarkData();
2285 ScDocShell* pDocSh = GetViewData().GetDocShell();
2286 ScDocument& rDoc = pDocSh->GetDocument();
2287 ScDocFunc &rFunc = pDocSh->GetDocFunc();
2288 bool bUndo(rDoc.IsUndoEnabled());
2290 // modifying several tabs is handled here
2292 if (bUndo)
2294 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
2295 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2298 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
2299 for (; itr != itrEnd; ++itr)
2300 rFunc.ProtectSheet(*itr, rProtect);
2302 if (bUndo)
2303 pDocSh->GetUndoManager()->LeaveListAction();
2305 UpdateLayerLocks(); //! broadcast to all views
2308 void ScViewFunc::Protect( SCTAB nTab, const OUString& rPassword )
2310 ScMarkData& rMark = GetViewData().GetMarkData();
2311 ScDocShell* pDocSh = GetViewData().GetDocShell();
2312 ScDocument& rDoc = pDocSh->GetDocument();
2313 ScDocFunc &rFunc = pDocSh->GetDocFunc();
2314 bool bUndo(rDoc.IsUndoEnabled());
2316 if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
2317 rFunc.Protect( nTab, rPassword, false );
2318 else
2320 // modifying several tabs is handled here
2322 if (bUndo)
2324 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
2325 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2328 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
2329 for (; itr != itrEnd; ++itr)
2330 rFunc.Protect( *itr, rPassword, false );
2332 if (bUndo)
2333 pDocSh->GetUndoManager()->LeaveListAction();
2336 UpdateLayerLocks(); //! broadcast to all views
2339 bool ScViewFunc::Unprotect( SCTAB nTab, const OUString& rPassword )
2341 ScMarkData& rMark = GetViewData().GetMarkData();
2342 ScDocShell* pDocSh = GetViewData().GetDocShell();
2343 ScDocument& rDoc = pDocSh->GetDocument();
2344 ScDocFunc &rFunc = pDocSh->GetDocFunc();
2345 bool bChanged = false;
2346 bool bUndo (rDoc.IsUndoEnabled());
2348 if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
2349 bChanged = rFunc.Unprotect( nTab, rPassword, false );
2350 else
2352 // modifying several tabs is handled here
2354 if (bUndo)
2356 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_UNPROTECT_TAB );
2357 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2360 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
2361 for (; itr != itrEnd; ++itr)
2362 if ( rFunc.Unprotect( *itr, rPassword, false ) )
2363 bChanged = true;
2365 if (bUndo)
2366 pDocSh->GetUndoManager()->LeaveListAction();
2369 if (bChanged)
2370 UpdateLayerLocks(); //! broadcast to all views
2372 return bChanged;
2375 void ScViewFunc::SetNoteText( const ScAddress& rPos, const OUString& rNoteText )
2377 GetViewData().GetDocShell()->GetDocFunc().SetNoteText( rPos, rNoteText, false );
2380 void ScViewFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate )
2382 GetViewData().GetDocShell()->GetDocFunc().ReplaceNote( rPos, rNoteText, pAuthor, pDate, false );
2385 void ScViewFunc::SetNumberFormat( short nFormatType, sal_uLong nAdd )
2387 // not editable because of matrix only? attribute OK nonetheless
2388 bool bOnlyNotBecauseOfMatrix;
2389 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2391 ErrorMessage(STR_PROTECTIONERR);
2392 return;
2395 sal_uInt32 nNumberFormat = 0;
2396 ScViewData& rViewData = GetViewData();
2397 ScDocument* pDoc = rViewData.GetDocument();
2398 SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
2399 LanguageType eLanguage = ScGlobal::eLnge;
2400 ScPatternAttr aNewAttrs( pDoc->GetPool() );
2402 // always take language from cursor position, even if there is a selection
2404 sal_uInt32 nCurrentNumberFormat;
2405 pDoc->GetNumberFormat( rViewData.GetCurX(),
2406 rViewData.GetCurY(),
2407 rViewData.GetTabNo(),
2408 nCurrentNumberFormat );
2409 const SvNumberformat* pEntry = pNumberFormatter->GetEntry( nCurrentNumberFormat );
2410 if (pEntry)
2411 eLanguage = pEntry->GetLanguage(); // else keep ScGlobal::eLnge
2413 nNumberFormat = pNumberFormatter->GetStandardFormat( nFormatType, eLanguage ) + nAdd;
2415 SfxItemSet& rSet = aNewAttrs.GetItemSet();
2416 rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2417 // ATTR_LANGUAGE_FORMAT not
2418 ApplySelectionPattern( aNewAttrs );
2421 void ScViewFunc::SetNumFmtByStr( const OUString& rCode )
2423 // not editable because of matrix only? attribute OK nonetheless
2424 bool bOnlyNotBecauseOfMatrix;
2425 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2427 ErrorMessage(STR_PROTECTIONERR);
2428 return;
2431 ScViewData& rViewData = GetViewData();
2432 ScDocument* pDoc = rViewData.GetDocument();
2433 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
2435 // language always from cursor position
2437 sal_uInt32 nCurrentNumberFormat;
2438 pDoc->GetNumberFormat( rViewData.GetCurX(), rViewData.GetCurY(),
2439 rViewData.GetTabNo(), nCurrentNumberFormat );
2440 const SvNumberformat* pEntry = pFormatter->GetEntry( nCurrentNumberFormat );
2441 LanguageType eLanguage = pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge;
2443 // determine index for String
2445 bool bOk = true;
2446 sal_uInt32 nNumberFormat = pFormatter->GetEntryKey( rCode, eLanguage );
2447 if ( nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
2449 // enter new
2451 OUString aFormat = rCode; // will be changed
2452 sal_Int32 nErrPos = 0;
2453 short nType = 0; //! ???
2454 bOk = pFormatter->PutEntry( aFormat, nErrPos, nType, nNumberFormat, eLanguage );
2457 if ( bOk ) // valid format?
2459 ScPatternAttr aNewAttrs( pDoc->GetPool() );
2460 SfxItemSet& rSet = aNewAttrs.GetItemSet();
2461 rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2462 rSet.Put( SvxLanguageItem( eLanguage, ATTR_LANGUAGE_FORMAT ) );
2463 ApplySelectionPattern( aNewAttrs );
2466 //! else return error / issue warning ???
2469 void ScViewFunc::ChangeNumFmtDecimals( bool bIncrement )
2471 // not editable because of matrix only? attribute OK nonetheless
2472 bool bOnlyNotBecauseOfMatrix;
2473 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2475 ErrorMessage(STR_PROTECTIONERR);
2476 return;
2479 ScDocument* pDoc = GetViewData().GetDocument();
2480 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
2482 SCCOL nCol = GetViewData().GetCurX();
2483 SCROW nRow = GetViewData().GetCurY();
2484 SCTAB nTab = GetViewData().GetTabNo();
2486 sal_uInt32 nOldFormat;
2487 pDoc->GetNumberFormat( nCol, nRow, nTab, nOldFormat );
2488 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
2489 if (!pOldEntry)
2491 OSL_FAIL("numberformat not found !!!");
2492 return;
2495 // what have we got here?
2497 sal_uInt32 nNewFormat = nOldFormat;
2498 bool bError = false;
2500 LanguageType eLanguage = pOldEntry->GetLanguage();
2501 bool bThousand, bNegRed;
2502 sal_uInt16 nPrecision, nLeading;
2503 pOldEntry->GetFormatSpecialInfo( bThousand, bNegRed, nPrecision, nLeading );
2505 short nOldType = pOldEntry->GetType();
2506 if ( 0 == ( nOldType & (
2507 css::util::NumberFormat::NUMBER | css::util::NumberFormat::CURRENCY | css::util::NumberFormat::PERCENT | css::util::NumberFormat::SCIENTIFIC ) ) )
2509 // date, time, fraction, logical, text can not be changed
2510 bError = true;
2513 //! SvNumberformat has a Member bStandard, but doesn't disclose it
2514 bool bWasStandard = ( nOldFormat == pFormatter->GetStandardIndex( eLanguage ) );
2515 OUString sExponentialStandardFormat = "";
2516 if (bWasStandard)
2518 // with "Standard" the decimal places depend on cell content
2519 // 0 if empty or text -> no decimal places
2520 double nVal = pDoc->GetValue( ScAddress( nCol, nRow, nTab ) );
2522 // the ways of the Numberformatters are unfathomable, so try:
2523 OUString aOut;
2524 Color* pCol;
2525 const_cast<SvNumberformat*>(pOldEntry)->GetOutputString( nVal, aOut, &pCol );
2527 nPrecision = 0;
2528 // 'E' for exponential is fixed in Numberformatter
2529 sal_Int32 nIndexE = aOut.indexOf((sal_Unicode)'E');
2530 if ( nIndexE >= 0 )
2532 sExponentialStandardFormat = aOut.copy( nIndexE ).replace( '-', '+' );
2533 for ( sal_Int32 i=1 ; i<sExponentialStandardFormat.getLength() ; i++ )
2535 if ( sExponentialStandardFormat[i] >= '1' && sExponentialStandardFormat[i] <= '9' )
2536 sExponentialStandardFormat = sExponentialStandardFormat.replaceAt( i, 1, "0" );
2538 aOut = aOut.copy( 0, nIndexE ); // remove exponential part
2540 OUString aDecSep( pFormatter->GetFormatDecimalSep( nOldFormat ) );
2541 sal_Int32 nPos = aOut.indexOf( aDecSep );
2542 if ( nPos >= 0 )
2543 nPrecision = aOut.getLength() - nPos - aDecSep.getLength();
2544 // else keep 0
2546 else
2548 if ( (nOldType & css::util::NumberFormat::SCIENTIFIC) && !bThousand &&
2549 (pOldEntry->GetFormatIntegerDigits()%3 == 0) && pOldEntry->GetFormatIntegerDigits() > 0 )
2550 bThousand = true;
2553 if (!bError)
2555 if (bIncrement)
2557 if (nPrecision<20)
2558 ++nPrecision; // increment
2559 else
2560 bError = true; // 20 is maximum
2562 else
2564 if (nPrecision)
2565 --nPrecision; // decrement
2566 else
2567 bError = true; // 0 is minimum
2571 if (!bError)
2573 OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLanguage,
2574 bThousand, bNegRed,
2575 nPrecision, nLeading)
2576 + sExponentialStandardFormat;
2578 nNewFormat = pFormatter->GetEntryKey( aNewPicture, eLanguage );
2579 if ( nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
2581 sal_Int32 nErrPos = 0;
2582 short nNewType = 0;
2583 bool bOk = pFormatter->PutEntry( aNewPicture, nErrPos,
2584 nNewType, nNewFormat, eLanguage );
2585 OSL_ENSURE( bOk, "incorrect numberformat generated" );
2586 if (!bOk)
2587 bError = true;
2591 if (!bError)
2593 ScPatternAttr aNewAttrs( pDoc->GetPool() );
2594 SfxItemSet& rSet = aNewAttrs.GetItemSet();
2595 rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
2596 // ATTR_LANGUAGE_FORMAT not
2597 ApplySelectionPattern( aNewAttrs );
2601 void ScViewFunc::ChangeIndent( bool bIncrement )
2603 ScViewData& rViewData = GetViewData();
2604 ScDocShell* pDocSh = rViewData.GetDocShell();
2605 ScMarkData& rMark = rViewData.GetMarkData();
2607 ScMarkData aWorkMark = rMark;
2608 ScViewUtil::UnmarkFiltered( aWorkMark, &pDocSh->GetDocument() );
2609 aWorkMark.MarkToMulti();
2610 if (!aWorkMark.IsMultiMarked())
2612 SCCOL nCol = rViewData.GetCurX();
2613 SCROW nRow = rViewData.GetCurY();
2614 SCTAB nTab = rViewData.GetTabNo();
2615 aWorkMark.SetMultiMarkArea( ScRange(nCol,nRow,nTab) );
2618 bool bSuccess = pDocSh->GetDocFunc().ChangeIndent( aWorkMark, bIncrement, false );
2619 if (bSuccess)
2621 pDocSh->UpdateOle(&rViewData);
2622 StartFormatArea();
2624 // stuff for sidebar panels
2625 SfxBindings& rBindings = GetViewData().GetBindings();
2626 rBindings.Invalidate( SID_H_ALIGNCELL );
2627 rBindings.Invalidate( SID_ATTR_ALIGN_INDENT );
2631 bool ScViewFunc::InsertName( const OUString& rName, const OUString& rSymbol,
2632 const OUString& rType )
2634 // Type = P,R,C,F (and combinations)
2635 //! undo...
2637 bool bOk = false;
2638 ScDocShell* pDocSh = GetViewData().GetDocShell();
2639 ScDocument& rDoc = pDocSh->GetDocument();
2640 SCTAB nTab = GetViewData().GetTabNo();
2641 ScRangeName* pList = rDoc.GetRangeName();
2643 ScRangeData::Type nType = ScRangeData::Type::Name;
2644 ScRangeData* pNewEntry = new ScRangeData( &rDoc, rName, rSymbol,
2645 ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(),
2646 nTab), nType );
2647 OUString aUpType = rType.toAsciiUpperCase();
2648 if ( aUpType.indexOf( 'P' ) != -1 )
2649 nType |= ScRangeData::Type::PrintArea;
2650 if ( aUpType.indexOf( 'R' ) != -1 )
2651 nType |= ScRangeData::Type::RowHeader;
2652 if ( aUpType.indexOf( 'C' ) != -1 )
2653 nType |= ScRangeData::Type::ColHeader;
2654 if ( aUpType.indexOf( 'F' ) != -1 )
2655 nType |= ScRangeData::Type::Criteria;
2656 pNewEntry->AddType(nType);
2658 if ( !pNewEntry->GetErrCode() ) // text valid?
2660 ScDocShellModificator aModificator( *pDocSh );
2662 rDoc.PreprocessRangeNameUpdate();
2664 // input available yet? Then remove beforehand (=change)
2665 ScRangeData* pData = pList->findByUpperName(ScGlobal::pCharClass->uppercase(rName));
2666 if (pData)
2667 { // take old Index
2668 pNewEntry->SetIndex(pData->GetIndex());
2669 pList->erase(*pData);
2672 if ( pList->insert( pNewEntry ) )
2673 bOk = true;
2674 pNewEntry = nullptr; // never delete, insert took ownership
2676 rDoc.CompileHybridFormula();
2678 aModificator.SetDocumentModified();
2679 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
2682 delete pNewEntry; // if it wasn't inserted
2683 return bOk;
2686 void ScViewFunc::CreateNames( sal_uInt16 nFlags )
2688 bool bDone = false;
2689 ScRange aRange;
2690 if ( GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE )
2691 bDone = GetViewData().GetDocShell()->GetDocFunc().CreateNames( aRange, nFlags, false );
2693 if (!bDone)
2694 ErrorMessage(STR_CREATENAME_MARKERR);
2697 sal_uInt16 ScViewFunc::GetCreateNameFlags()
2699 sal_uInt16 nFlags = 0;
2701 SCCOL nStartCol, nEndCol;
2702 SCROW nStartRow, nEndRow;
2703 SCTAB nDummy;
2704 if (GetViewData().GetSimpleArea(nStartCol,nStartRow,nDummy,nEndCol,nEndRow,nDummy) == SC_MARK_SIMPLE)
2706 ScDocument* pDoc = GetViewData().GetDocument();
2707 SCTAB nTab = GetViewData().GetTabNo();
2708 bool bOk;
2709 SCCOL i;
2710 SCROW j;
2712 bOk = true;
2713 SCCOL nFirstCol = nStartCol;
2714 SCCOL nLastCol = nEndCol;
2715 if (nStartCol+1 < nEndCol) { ++nFirstCol; --nLastCol; }
2716 for (i=nFirstCol; i<=nLastCol && bOk; i++)
2717 if (!pDoc->HasStringData( i,nStartRow,nTab ))
2718 bOk = false;
2719 if (bOk)
2720 nFlags |= NAME_TOP;
2721 else // Bottom only if not Top
2723 bOk = true;
2724 for (i=nFirstCol; i<=nLastCol && bOk; i++)
2725 if (!pDoc->HasStringData( i,nEndRow,nTab ))
2726 bOk = false;
2727 if (bOk)
2728 nFlags |= NAME_BOTTOM;
2731 bOk = true;
2732 SCROW nFirstRow = nStartRow;
2733 SCROW nLastRow = nEndRow;
2734 if (nStartRow+1 < nEndRow) { ++nFirstRow; --nLastRow; }
2735 for (j=nFirstRow; j<=nLastRow && bOk; j++)
2736 if (!pDoc->HasStringData( nStartCol,j,nTab ))
2737 bOk = false;
2738 if (bOk)
2739 nFlags |= NAME_LEFT;
2740 else // Right only if not Left
2742 bOk = true;
2743 for (j=nFirstRow; j<=nLastRow && bOk; j++)
2744 if (!pDoc->HasStringData( nEndCol,j,nTab ))
2745 bOk = false;
2746 if (bOk)
2747 nFlags |= NAME_RIGHT;
2751 if (nStartCol == nEndCol)
2752 nFlags &= ~( NAME_LEFT | NAME_RIGHT );
2753 if (nStartRow == nEndRow)
2754 nFlags &= ~( NAME_TOP | NAME_BOTTOM );
2756 return nFlags;
2759 void ScViewFunc::InsertNameList()
2761 ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
2762 ScDocShell* pDocSh = GetViewData().GetDocShell();
2763 if ( pDocSh->GetDocFunc().InsertNameList( aPos, false ) )
2764 pDocSh->UpdateOle(&GetViewData());
2767 void ScViewFunc::UpdateSelectionArea( const ScMarkData& rSel, ScPatternAttr* pAttr )
2769 ScDocShell* pDocShell = GetViewData().GetDocShell();
2770 ScRange aMarkRange;
2771 if (rSel.IsMultiMarked() )
2772 rSel.GetMultiMarkArea( aMarkRange );
2773 else
2774 rSel.GetMarkArea( aMarkRange );
2776 bool bSetLines = false;
2777 bool bSetAlign = false;
2778 if ( pAttr )
2780 const SfxItemSet& rNewSet = pAttr->GetItemSet();
2781 bSetLines = rNewSet.GetItemState( ATTR_BORDER ) == SfxItemState::SET ||
2782 rNewSet.GetItemState( ATTR_SHADOW ) == SfxItemState::SET;
2783 bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY ) == SfxItemState::SET;
2786 sal_uInt16 nExtFlags = 0;
2787 if ( bSetLines )
2788 nExtFlags |= SC_PF_LINES;
2789 if ( bSetAlign )
2790 nExtFlags |= SC_PF_WHOLEROWS;
2792 SCCOL nStartCol = aMarkRange.aStart.Col();
2793 SCROW nStartRow = aMarkRange.aStart.Row();
2794 SCTAB nStartTab = aMarkRange.aStart.Tab();
2795 SCCOL nEndCol = aMarkRange.aEnd.Col();
2796 SCROW nEndRow = aMarkRange.aEnd.Row();
2797 SCTAB nEndTab = aMarkRange.aEnd.Tab();
2798 pDocShell->PostPaint( nStartCol, nStartRow, nStartTab,
2799 nEndCol, nEndRow, nEndTab,
2800 PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
2801 ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
2802 pTabViewShell->AdjustBlockHeight(false, const_cast<ScMarkData*>(&rSel));
2805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */