Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / sc / source / ui / view / viewfunc.cxx
blob2ff86f12178fec35a273af79734f1a5ef1b4ea47
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 "scitems.hxx"
21 #include <editeng/eeitem.hxx>
23 #include <sfx2/app.hxx>
24 #include <svx/algitem.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <editeng/editobj.hxx>
27 #include <editeng/editview.hxx>
28 #include <editeng/langitem.hxx>
29 #include <editeng/scripttypeitem.hxx>
30 #include <editeng/justifyitem.hxx>
31 #include <sfx2/bindings.hxx>
32 #include <svl/zforlist.hxx>
33 #include <svl/zformat.hxx>
34 #include <vcl/msgbox.hxx>
35 #include <vcl/virdev.hxx>
36 #include <vcl/waitobj.hxx>
37 #include <vcl/wrkwin.hxx>
38 #include <stdlib.h> // qsort
40 #include "viewfunc.hxx"
41 #include "tabvwsh.hxx"
42 #include "docsh.hxx"
43 #include "attrib.hxx"
44 #include "patattr.hxx"
45 #include "docpool.hxx"
46 #include "uiitems.hxx"
47 #include "sc.hrc"
48 #include "undocell.hxx"
49 #include "undoblk.hxx"
50 #include "undotab.hxx"
51 #include "refundo.hxx"
52 #include "dbdata.hxx"
53 #include "olinetab.hxx"
54 #include "rangeutl.hxx"
55 #include "rangenam.hxx"
56 #include "globstr.hrc"
57 #include "global.hxx"
58 #include "stlsheet.hxx"
59 #include "editutil.hxx"
60 #include "cell.hxx"
61 #include "scresid.hxx"
62 #include "inputhdl.hxx"
63 #include "scmod.hxx"
64 #include "inputopt.hxx"
65 #include "compiler.hxx"
66 #include "docfunc.hxx"
67 #include "appoptio.hxx"
68 #include "dociter.hxx"
69 #include "sizedev.hxx"
70 #include "editable.hxx"
71 #include "scui_def.hxx"
72 #include "funcdesc.hxx"
73 #include "docuno.hxx"
74 #include "cellsuno.hxx"
75 //==================================================================
77 static void lcl_PostRepaintCondFormat( const ScConditionalFormat *pCondFmt, ScDocShell *pDocSh )
79 if( pCondFmt )
81 const ScRangeList& rRanges = pCondFmt->GetRange();
83 pDocSh->PostPaint( rRanges, PAINT_ALL );
88 //==================================================================
90 ScViewFunc::ScViewFunc( Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
91 ScTabView( pParent, rDocSh, pViewShell ),
92 bFormatValid( false )
96 ScViewFunc::~ScViewFunc()
100 //------------------------------------------------------------------------------------
102 void ScViewFunc::StartFormatArea()
104 // anything to do?
105 if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
106 return;
108 // start only with single cell (marked or cursor position)
109 ScRange aMarkRange;
110 sal_Bool bOk = (GetViewData()->GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE);
111 if ( bOk && aMarkRange.aStart != aMarkRange.aEnd )
112 bOk = false;
114 if (bOk)
116 bFormatValid = sal_True;
117 aFormatSource = aMarkRange.aStart;
118 aFormatArea = ScRange( aFormatSource );
120 else
121 bFormatValid = false; // discard old range
124 sal_Bool ScViewFunc::TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bAttrChanged )
126 // anything to do?
127 if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
128 return false;
130 // Test: treat input with numberformat (bAttrChanged) always as new Attribute
131 // (discard old Area ). If not not wanted, discard if-statement
132 if ( bAttrChanged )
134 StartFormatArea();
135 return false;
138 //! Test if cell empty ???
140 sal_Bool bFound = false;
141 ScRange aNewRange = aFormatArea;
142 if ( bFormatValid && nTab == aFormatSource.Tab() )
144 if ( nRow >= aFormatArea.aStart.Row() && nRow <= aFormatArea.aEnd.Row() )
146 // within range?
147 if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
149 bFound = sal_True; // do not change range
151 // left ?
152 if ( nCol+1 == aFormatArea.aStart.Col() )
154 bFound = sal_True;
155 aNewRange.aStart.SetCol( nCol );
157 // right ?
158 if ( nCol == aFormatArea.aEnd.Col()+1 )
160 bFound = sal_True;
161 aNewRange.aEnd.SetCol( nCol );
164 if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
166 // top ?
167 if ( nRow+1 == aFormatArea.aStart.Row() )
169 bFound = sal_True;
170 aNewRange.aStart.SetRow( nRow );
172 // bottom ?
173 if ( nRow == aFormatArea.aEnd.Row()+1 )
175 bFound = sal_True;
176 aNewRange.aEnd.SetRow( nRow );
181 if (bFound)
182 aFormatArea = aNewRange; // extend
183 else
185 bFormatValid = false; // outdside of range -> break
186 if ( bAttrChanged ) // if value entered with numberformat?
187 StartFormatArea(); // then start again
190 return bFound;
193 void ScViewFunc::DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
194 sal_Bool bAttrChanged, sal_Bool bAddUndo )
196 ScDocShell* pDocSh = GetViewData()->GetDocShell();
197 ScDocument* pDoc = pDocSh->GetDocument();
198 if (bAddUndo && !pDoc->IsUndoEnabled())
199 bAddUndo = false;
201 const ScPatternAttr* pSource = pDoc->GetPattern(
202 aFormatSource.Col(), aFormatSource.Row(), nTab );
203 if ( !((const ScMergeAttr&)pSource->GetItem(ATTR_MERGE)).IsMerged() )
205 ScRange aRange( nCol, nRow, nTab, nCol, nRow, nTab );
206 ScMarkData aMark;
207 aMark.SetMarkArea( aRange );
209 ScDocFunc &rFunc = GetViewData()->GetDocFunc();
211 // pOldPattern is only valid until call to ApplyAttributes!
212 const ScPatternAttr* pOldPattern = pDoc->GetPattern( nCol, nRow, nTab );
213 const ScStyleSheet* pSrcStyle = pSource->GetStyleSheet();
214 if ( pSrcStyle && pSrcStyle != pOldPattern->GetStyleSheet() )
215 rFunc.ApplyStyle( aMark, pSrcStyle->GetName(), sal_True, sal_False );
217 rFunc.ApplyAttributes( aMark, *pSource, sal_True, sal_False );
220 if ( bAttrChanged ) // value entered with number format?
221 aFormatSource.Set( nCol, nRow, nTab ); // then set a new source
224 //------------------------------------------------------------------------------------
226 // additional routines
228 sal_uInt16 ScViewFunc::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, sal_Bool bFormula )
230 ScDocShell* pDocSh = GetViewData()->GetDocShell();
231 ScDocument* pDoc = pDocSh->GetDocument();
232 ScMarkData& rMark = GetViewData()->GetMarkData();
234 double nPPTX = GetViewData()->GetPPTX();
235 double nPPTY = GetViewData()->GetPPTY();
236 Fraction aZoomX = GetViewData()->GetZoomX();
237 Fraction aZoomY = GetViewData()->GetZoomY();
239 ScSizeDeviceProvider aProv(pDocSh);
240 if (aProv.IsPrinter())
242 nPPTX = aProv.GetPPTX();
243 nPPTY = aProv.GetPPTY();
244 aZoomX = aZoomY = Fraction( 1, 1 );
247 sal_uInt16 nTwips = pDoc->GetOptimalColWidth( nCol, nTab, aProv.GetDevice(),
248 nPPTX, nPPTY, aZoomX, aZoomY, bFormula, &rMark );
249 return nTwips;
252 sal_Bool ScViewFunc::SelectionEditable( bool* pOnlyNotBecauseOfMatrix /* = NULL */ )
254 bool bRet;
255 ScDocument* pDoc = GetViewData()->GetDocument();
256 ScMarkData& rMark = GetViewData()->GetMarkData();
257 if (rMark.IsMarked() || rMark.IsMultiMarked())
258 bRet = pDoc->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix );
259 else
261 SCCOL nCol = GetViewData()->GetCurX();
262 SCROW nRow = GetViewData()->GetCurY();
263 SCTAB nTab = GetViewData()->GetTabNo();
264 bRet = pDoc->IsBlockEditable( nTab, nCol, nRow, nCol, nRow,
265 pOnlyNotBecauseOfMatrix );
267 return bRet;
270 #ifndef LRU_MAX
271 #define LRU_MAX 10
272 #endif
274 static sal_Bool lcl_FunctionKnown( sal_uInt16 nOpCode )
276 const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
277 if ( pFuncList )
279 sal_uLong nCount = pFuncList->GetCount();
280 for (sal_uLong i=0; i<nCount; i++)
281 if ( pFuncList->GetFunction(i)->nFIndex == nOpCode )
282 return sal_True;
284 return false;
287 static sal_Bool lcl_AddFunction( ScAppOptions& rAppOpt, sal_uInt16 nOpCode )
289 sal_uInt16 nOldCount = rAppOpt.GetLRUFuncListCount();
290 sal_uInt16* pOldList = rAppOpt.GetLRUFuncList();
291 sal_uInt16 nPos;
292 for (nPos=0; nPos<nOldCount; nPos++)
293 if (pOldList[nPos] == nOpCode) // is the function already in the list?
295 if ( nPos == 0 )
296 return false; // already at the top -> no change
298 // count doesn't change, so the original array is modified
300 for (sal_uInt16 nCopy=nPos; nCopy>0; nCopy--)
301 pOldList[nCopy] = pOldList[nCopy-1];
302 pOldList[0] = nOpCode;
304 return sal_True; // list has changed
307 if ( !lcl_FunctionKnown( nOpCode ) )
308 return false; // not in function list -> no change
310 sal_uInt16 nNewCount = Min( (sal_uInt16)(nOldCount + 1), (sal_uInt16)LRU_MAX );
311 sal_uInt16 nNewList[LRU_MAX];
312 nNewList[0] = nOpCode;
313 for (nPos=1; nPos<nNewCount; nPos++)
314 nNewList[nPos] = pOldList[nPos-1];
315 rAppOpt.SetLRUFuncList( nNewList, nNewCount );
317 return sal_True; // list has changed
320 // actual functions
322 // input - undo OK
324 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
325 const String& rString,
326 const EditTextObject* pData )
328 ScDocument* pDoc = GetViewData()->GetDocument();
329 ScMarkData& rMark = GetViewData()->GetMarkData();
330 bool bRecord = pDoc->IsUndoEnabled();
331 SCTAB i;
333 ScDocShell* pDocSh = GetViewData()->GetDocShell();
334 ScDocFunc &rFunc = GetViewData()->GetDocFunc();
335 ScDocShellModificator aModificator( *pDocSh );
337 ScEditableTester aTester( pDoc, nCol,nRow, nCol,nRow, rMark );
338 if (aTester.IsEditable())
340 if ( bRecord )
341 rFunc.EnterListAction( STR_UNDO_ENTERDATA );
343 bool bFormula = false;
345 // a single '=' character is handled as string (needed for special filters)
346 if ( rString.Len() > 1 )
348 if ( rString.GetChar(0) == '=' )
350 // handle as formula
351 bFormula = true;
353 else if ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' )
355 // if there is more than one leading '+' or '-' character, remove the additional ones
356 String aString( rString );
357 xub_StrLen nIndex = 1;
358 xub_StrLen nLen = aString.Len();
359 while ( nIndex < nLen && ( aString.GetChar( nIndex ) == '+' || aString.GetChar( nIndex ) == '-' ) )
361 ++nIndex;
363 aString.Erase( 1, nIndex - 1 );
365 // if the remaining part without the leading '+' or '-' character
366 // is non-empty and not a number, handle as formula
367 if ( aString.Len() > 1 )
369 sal_uInt32 nFormat = 0;
370 pDoc->GetNumberFormat( nCol, nRow, nTab, nFormat );
371 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
372 double fNumber = 0;
373 if ( !pFormatter->IsNumberFormat( aString, nFormat, fNumber ) )
375 bFormula = true;
381 sal_Bool bNumFmtChanged = false;
382 if ( bFormula )
383 { // formula, compile with autoCorrection
384 i = rMark.GetFirstSelected();
385 ScAddress aPos( nCol, nRow, i );
386 ScCompiler aComp( pDoc, aPos);
387 aComp.SetGrammar(pDoc->GetGrammar());
388 //2do: enable/disable autoCorrection via calcoptions
389 aComp.SetAutoCorrection( sal_True );
390 if ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' )
392 aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK );
394 String aFormula( rString );
395 ScTokenArray* pArr;
396 sal_Bool bAgain;
399 bAgain = false;
400 bool bAddEqual = false;
401 ScTokenArray* pArrFirst = pArr = aComp.CompileString( aFormula );
402 bool bCorrected = aComp.IsCorrected();
403 if ( bCorrected )
404 { // try to parse with first parser-correction
405 pArr = aComp.CompileString( aComp.GetCorrectedFormula() );
407 if ( !pArr->GetCodeError() )
409 bAddEqual = true;
410 aComp.CompileTokenArray();
411 bCorrected |= aComp.IsCorrected();
413 if ( bCorrected )
415 String aCorrectedFormula;
416 if ( bAddEqual )
418 aCorrectedFormula = '=';
419 aCorrectedFormula += aComp.GetCorrectedFormula();
421 else
422 aCorrectedFormula = aComp.GetCorrectedFormula();
423 short nResult;
424 if ( aCorrectedFormula.Len() == 1 )
425 nResult = RET_NO; // empty formula, just '='
426 else
428 String aMessage( ScResId( SCSTR_FORMULA_AUTOCORRECTION ) );
429 aMessage += aCorrectedFormula;
430 nResult = QueryBox( GetViewData()->GetDialogParent(),
431 WinBits(WB_YES_NO | WB_DEF_YES),
432 aMessage ).Execute();
434 if ( nResult == RET_YES )
436 aFormula = aCorrectedFormula;
437 if ( pArr != pArrFirst )
438 delete pArrFirst;
439 bAgain = sal_True;
441 else
443 if ( pArr != pArrFirst )
445 delete pArr;
446 pArr = pArrFirst;
450 } while ( bAgain );
451 // to be used in multiple tabs, the formula must be compiled anew
452 // via ScFormulaCell copy-ctor because of RangeNames,
453 // the same code-array for all cells is not possible.
454 // If the array has an error, (it) must be RPN-erased in the newly generated
455 // cellst and the error be set explicitly, so that
456 // via FormulaCell copy-ctor and Interpreter it will be, when possible,
457 // ironed out again, too intelligent.. e.g.: =1))
458 sal_uInt16 nError = pArr->GetCodeError();
459 if ( !nError )
461 // update list of recent functions with all functions that
462 // are not within parentheses
464 ScModule* pScMod = SC_MOD();
465 ScAppOptions aAppOpt = pScMod->GetAppOptions();
466 sal_Bool bOptChanged = false;
468 formula::FormulaToken** ppToken = pArr->GetArray();
469 sal_uInt16 nTokens = pArr->GetLen();
470 sal_uInt16 nLevel = 0;
471 for (sal_uInt16 nTP=0; nTP<nTokens; nTP++)
473 formula::FormulaToken* pTok = ppToken[nTP];
474 OpCode eOp = pTok->GetOpCode();
475 if ( eOp == ocOpen )
476 ++nLevel;
477 else if ( eOp == ocClose && nLevel )
478 --nLevel;
479 if ( nLevel == 0 && pTok->IsFunction() &&
480 lcl_AddFunction( aAppOpt, sal::static_int_cast<sal_uInt16>( eOp ) ) )
481 bOptChanged = sal_True;
484 if ( bOptChanged )
486 pScMod->SetAppOptions(aAppOpt);
487 pScMod->RecentFunctionsChanged();
491 ScFormulaCell aCell( pDoc, aPos, pArr,formula::FormulaGrammar::GRAM_DEFAULT, MM_NONE );
492 delete pArr;
494 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
495 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
496 for (; itr != itrEnd; ++itr)
498 i = *itr;
499 aPos.SetTab( i );
500 sal_uLong nIndex = (sal_uLong) ((SfxUInt32Item*) pDoc->GetAttr(
501 nCol, nRow, i, ATTR_VALUE_FORMAT ))->GetValue();
502 if ( pFormatter->GetType( nIndex ) == NUMBERFORMAT_TEXT ||
503 ( ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' ) && nError && rString.Equals( aFormula ) ) )
505 ScBaseCell *pCell;
506 if ( pData )
507 pCell = new ScEditCell( pData, pDoc, NULL );
508 else
509 pCell = new ScStringCell( aFormula );
510 rFunc.PutCell( aPos, pCell, sal_False );
512 else
514 ScFormulaCell* pCell = new ScFormulaCell( aCell, *pDoc, aPos );
515 if ( nError )
517 pCell->GetCode()->DelRPN();
518 pCell->SetErrCode( nError );
519 if(pCell->GetCode()->IsHyperLink())
520 pCell->GetCode()->SetHyperLink(false);
522 rFunc.PutCell( aPos, pCell, sal_False );
526 else
528 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
529 for ( ; itr != itrEnd; ++itr )
531 bool bNumFmtSet = false;
532 rFunc.SetNormalString( bNumFmtSet, ScAddress( nCol, nRow, *itr ), rString, sal_False );
533 if (bNumFmtSet)
535 /* FIXME: if set on any sheet results in changed only on
536 * sheet nTab for TestFormatArea() and DoAutoAttributes() */
537 bNumFmtChanged = true;
542 sal_Bool bAutoFormat = TestFormatArea(nCol, nRow, nTab, bNumFmtChanged);
544 if (bAutoFormat)
545 DoAutoAttributes(nCol, nRow, nTab, bNumFmtChanged, bRecord);
547 pDocSh->UpdateOle(GetViewData());
549 // #i97876# Spreadsheet data changes are not notified
550 ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
551 if ( pModelObj && pModelObj->HasChangesListeners() )
553 ScRangeList aChangeRanges;
554 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
555 for (; itr != itrEnd; ++itr)
556 aChangeRanges.Append( ScRange( nCol, nRow, *itr ) );
558 pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
561 if ( bRecord )
562 rFunc.EndListAction();
564 aModificator.SetDocumentModified();
565 lcl_PostRepaintCondFormat( pDoc->GetCondFormat( nCol, nRow, nTab ), pDocSh );
567 else
569 ErrorMessage(aTester.GetMessageId());
570 PaintArea( nCol, nRow, nCol, nRow ); // possibly the edit-engine is still painted there
574 // enter value in single cell (on nTab only)
576 void ScViewFunc::EnterValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rValue )
578 ScDocument* pDoc = GetViewData()->GetDocument();
579 ScDocShell* pDocSh = GetViewData()->GetDocShell();
581 if ( pDoc && pDocSh )
583 sal_Bool bUndo(pDoc->IsUndoEnabled());
584 ScDocShellModificator aModificator( *pDocSh );
586 ScEditableTester aTester( pDoc, nTab, nCol,nRow, nCol,nRow );
587 if (aTester.IsEditable())
589 ScAddress aPos( nCol, nRow, nTab );
590 ScBaseCell* pOldCell = pDoc->GetCell( aPos );
592 // undo
593 ScBaseCell* pUndoCell = (bUndo && pOldCell) ? pOldCell->Clone( *pDoc ) : 0;
595 pDoc->SetValue( nCol, nRow, nTab, rValue );
597 // because of ChangeTrack after change in document
598 if (bUndo)
600 pDocSh->GetUndoManager()->AddUndoAction(
601 new ScUndoEnterValue( pDocSh, aPos, pUndoCell, rValue ) );
604 pDocSh->PostPaintCell( aPos );
605 pDocSh->UpdateOle(GetViewData());
606 aModificator.SetDocumentModified();
608 else
609 ErrorMessage(aTester.GetMessageId());
613 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
614 const EditTextObject* pData, bool bTestSimple )
616 ScDocShell* pDocSh = GetViewData()->GetDocShell();
617 ScMarkData& rMark = GetViewData()->GetMarkData();
618 ScDocument* pDoc = pDocSh->GetDocument();
619 bool bRecord = pDoc->IsUndoEnabled();
621 ScDocShellModificator aModificator( *pDocSh );
623 ScEditableTester aTester( pDoc, nTab, nCol,nRow, nCol,nRow );
624 if (aTester.IsEditable())
627 // test for attribute
629 sal_Bool bSimple = false;
630 sal_Bool bCommon = false;
631 ScPatternAttr* pCellAttrs = NULL;
632 EditTextObject* pNewData = NULL;
633 String aString;
635 const ScPatternAttr* pOldPattern = pDoc->GetPattern( nCol, nRow, nTab );
636 ScTabEditEngine aEngine( *pOldPattern, pDoc->GetEnginePool() );
637 aEngine.SetText(*pData);
639 if (bTestSimple) // test, if simple string without attribute
641 ScEditAttrTester aAttrTester( &aEngine );
642 bSimple = !aAttrTester.NeedsObject();
643 bCommon = aAttrTester.NeedsCellAttr();
645 // formulas have to be recognized even if they're formatted
646 // (but commmon attributes are still collected)
648 if ( !bSimple && aEngine.GetParagraphCount() == 1 )
650 String aParStr = aEngine.GetText( (sal_uInt16) 0 );
651 if ( aParStr.GetChar(0) == '=' )
652 bSimple = sal_True;
655 if (bCommon) // attribute for tab
657 pCellAttrs = new ScPatternAttr( *pOldPattern );
658 pCellAttrs->GetFromEditItemSet( &aAttrTester.GetAttribs() );
659 //! remove common attributes from EditEngine?
663 // #i97726# always get text for "repeat" of undo action
664 aString = ScEditUtil::GetSpaceDelimitedString(aEngine);
667 // undo
670 SCTAB nSelCount = rMark.GetSelectCount();
671 ScBaseCell** ppOldCells = NULL;
672 SCTAB* pTabs = NULL;
673 SCTAB nPos = 0;
674 EditTextObject* pUndoData = NULL;
675 if (bRecord && !bSimple)
677 ppOldCells = new ScBaseCell*[nSelCount];
678 pTabs = new SCTAB[nSelCount];
679 nPos = 0;
681 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
682 for (; itr != itrEnd; ++itr)
684 pTabs[nPos] = *itr;
685 ScBaseCell* pDocCell;
686 pDoc->GetCell( nCol, nRow, *itr, pDocCell );
687 ppOldCells[nPos] = pDocCell ? pDocCell->Clone( *pDoc ) : 0;
688 ++nPos;
691 OSL_ENSURE( nPos==nSelCount, "nPos!=nSelCount" );
693 pUndoData = pData->Clone();
697 // enter data
700 if (bCommon)
701 pDoc->ApplyPattern(nCol,nRow,nTab,*pCellAttrs); //! undo
703 if (bSimple)
705 if (bCommon)
706 AdjustRowHeight(nRow,nRow);
708 EnterData(nCol,nRow,nTab,aString);
710 else
712 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
713 for (; itr != itrEnd; ++itr)
714 pDoc->PutCell( nCol, nRow, *itr, new ScEditCell( pData, pDoc, NULL ) );
716 if ( bRecord )
717 { // because of ChangeTrack current first
718 pDocSh->GetUndoManager()->AddUndoAction(
719 new ScUndoEnterData( pDocSh, nCol, nRow, nTab, nPos, pTabs,
720 ppOldCells, NULL, NULL, aString,
721 pUndoData ) );
724 HideAllCursors();
726 AdjustRowHeight(nRow,nRow);
728 itr = rMark.begin();
729 for (; itr != itrEnd; ++itr)
730 pDocSh->PostPaintCell( nCol, nRow, *itr );
732 ShowAllCursors();
734 pDocSh->UpdateOle(GetViewData());
736 // #i97876# Spreadsheet data changes are not notified
737 ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
738 if ( pModelObj && pModelObj->HasChangesListeners() )
740 ScRangeList aChangeRanges;
741 itr = rMark.begin();
742 for (; itr != itrEnd; ++itr)
744 aChangeRanges.Append( ScRange( nCol, nRow, *itr ) );
746 pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
749 aModificator.SetDocumentModified();
751 lcl_PostRepaintCondFormat( pDoc->GetCondFormat( nCol, nRow, nTab ), pDocSh );
753 delete pCellAttrs;
754 delete pNewData;
756 else
758 ErrorMessage(aTester.GetMessageId());
759 PaintArea( nCol, nRow, nCol, nRow ); // possibly the edit-engine is still painted there
763 void ScViewFunc::EnterDataAtCursor( const String& rString )
765 SCCOL nPosX = GetViewData()->GetCurX();
766 SCROW nPosY = GetViewData()->GetCurY();
767 SCTAB nTab = GetViewData()->GetTabNo();
769 EnterData( nPosX, nPosY, nTab, rString );
772 void ScViewFunc::EnterMatrix( const String& rString, ::formula::FormulaGrammar::Grammar eGram )
774 ScViewData* pData = GetViewData();
775 const ScMarkData& rMark = pData->GetMarkData();
776 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
778 // nothing marked -> temporarily calculate block
779 // with size of result formula to get the size
781 ScDocument* pDoc = pData->GetDocument();
782 SCCOL nCol = pData->GetCurX();
783 SCROW nRow = pData->GetCurY();
784 SCTAB nTab = pData->GetTabNo();
785 ScFormulaCell aFormCell( pDoc, ScAddress(nCol,nRow,nTab), rString, eGram, MM_FORMULA );
787 SCSIZE nSizeX;
788 SCSIZE nSizeY;
789 aFormCell.GetResultDimensions( nSizeX, nSizeY );
790 if ( nSizeX != 0 && nSizeY != 0 &&
791 nCol+nSizeX-1 <= sal::static_int_cast<SCSIZE>(MAXCOL) &&
792 nRow+nSizeY-1 <= sal::static_int_cast<SCSIZE>(MAXROW) )
794 ScRange aResult( nCol, nRow, nTab,
795 sal::static_int_cast<SCCOL>(nCol+nSizeX-1),
796 sal::static_int_cast<SCROW>(nRow+nSizeY-1), nTab );
797 MarkRange( aResult, false );
801 ScRange aRange;
802 if (pData->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
804 ScDocShell* pDocSh = pData->GetDocShell();
805 bool bSuccess = pDocSh->GetDocFunc().EnterMatrix(
806 aRange, &rMark, NULL, rString, false, false, EMPTY_STRING, eGram );
807 if (bSuccess)
808 pDocSh->UpdateOle(GetViewData());
810 else
811 ErrorMessage(STR_NOMULTISELECT);
814 sal_uInt8 ScViewFunc::GetSelectionScriptType()
816 sal_uInt8 nScript = 0;
818 ScDocument* pDoc = GetViewData()->GetDocument();
819 const ScMarkData& rMark = GetViewData()->GetMarkData();
820 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
822 // no selection -> cursor
824 nScript = pDoc->GetScriptType( GetViewData()->GetCurX(),
825 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
827 else
829 ScRangeList aRanges;
830 rMark.FillRangeListWithMarks( &aRanges, false );
831 size_t nCount = aRanges.size();
832 for ( size_t i=0; i < nCount; i++ )
834 ScRange aRange = *aRanges[i];
835 ScCellIterator aIter( pDoc, aRange );
836 ScBaseCell* pCell = aIter.GetFirst();
837 while ( pCell )
839 nScript |= pDoc->GetScriptType( aIter.GetCol(), aIter.GetRow(), aIter.GetTab(), pCell );
840 pCell = aIter.GetNext();
845 if (nScript == 0)
846 nScript = ScGlobal::GetDefaultScriptType();
848 return nScript;
851 const ScPatternAttr* ScViewFunc::GetSelectionPattern()
853 // Don't use UnmarkFiltered in slot state functions, for performance reasons.
854 // The displayed state is always that of the whole selection including filtered rows.
856 const ScMarkData& rMark = GetViewData()->GetMarkData();
857 ScDocument* pDoc = GetViewData()->GetDocument();
858 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
860 // MarkToMulti is no longer necessary for pDoc->GetSelectionPattern
861 const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( rMark );
862 return pAttr;
864 else
866 SCCOL nCol = GetViewData()->GetCurX();
867 SCROW nRow = GetViewData()->GetCurY();
868 SCTAB nTab = GetViewData()->GetTabNo();
870 ScMarkData aTempMark( rMark ); // copy sheet selection
871 aTempMark.SetMarkArea( ScRange( nCol, nRow, nTab ) );
872 const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( aTempMark );
873 return pAttr;
877 void ScViewFunc::GetSelectionFrame( SvxBoxItem& rLineOuter,
878 SvxBoxInfoItem& rLineInner )
880 ScDocument* pDoc = GetViewData()->GetDocument();
881 const ScMarkData& rMark = GetViewData()->GetMarkData();
883 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
885 if ( rMark.IsMultiMarked() )
887 ScMarkData aNewMark( rMark ); // use local copy for MarkToSimple
888 aNewMark.MarkToSimple(); // simple block is needed for GetSelectionFrame
889 pDoc->GetSelectionFrame( aNewMark, rLineOuter, rLineInner );
891 else
892 pDoc->GetSelectionFrame( rMark, rLineOuter, rLineInner );
894 else
896 const ScPatternAttr* pAttrs =
897 pDoc->GetPattern( GetViewData()->GetCurX(),
898 GetViewData()->GetCurY(),
899 GetViewData()->GetTabNo() );
901 rLineOuter = (const SvxBoxItem&) (pAttrs->GetItem( ATTR_BORDER ));
902 rLineInner = (const SvxBoxInfoItem&)(pAttrs->GetItem( ATTR_BORDER_INNER ));
903 rLineInner.SetTable(false);
904 rLineInner.SetDist(sal_True);
905 rLineInner.SetMinDist(false);
910 // apply attribute - undo OK
912 // complete set ( ATTR_STARTINDEX, ATTR_ENDINDEX )
915 void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
916 const SfxItemSet* pOldSet,
917 sal_Bool bRecord )
919 // not editable because of matrix only? attribute OK nonetheless
920 bool bOnlyNotBecauseOfMatrix;
921 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
923 ErrorMessage(STR_PROTECTIONERR);
924 return;
927 ScPatternAttr aOldAttrs( new SfxItemSet(*pOldSet) );
928 ScPatternAttr aNewAttrs( new SfxItemSet(*pDialogSet) );
929 aNewAttrs.DeleteUnchanged( &aOldAttrs );
931 if ( pDialogSet->GetItemState( ATTR_VALUE_FORMAT ) == SFX_ITEM_SET )
932 { // don't reset to default SYSTEM GENERAL if not intended
933 sal_uInt32 nOldFormat =
934 ((const SfxUInt32Item&)pOldSet->Get( ATTR_VALUE_FORMAT )).GetValue();
935 sal_uInt32 nNewFormat =
936 ((const SfxUInt32Item&)pDialogSet->Get( ATTR_VALUE_FORMAT )).GetValue();
937 if ( nNewFormat != nOldFormat )
939 SvNumberFormatter* pFormatter =
940 GetViewData()->GetDocument()->GetFormatTable();
941 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
942 LanguageType eOldLang =
943 pOldEntry ? pOldEntry->GetLanguage() : LANGUAGE_DONTKNOW;
944 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
945 LanguageType eNewLang =
946 pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
947 if ( eNewLang != eOldLang )
949 aNewAttrs.GetItemSet().Put(
950 SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
952 // only the language has changed -> do not touch numberformat-attribute
953 sal_uInt32 nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
954 if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
955 nNewMod <= SV_MAX_ANZ_STANDARD_FORMATE )
956 aNewAttrs.GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
961 const SvxBoxItem* pOldOuter = (const SvxBoxItem*) &pOldSet->Get( ATTR_BORDER );
962 const SvxBoxItem* pNewOuter = (const SvxBoxItem*) &pDialogSet->Get( ATTR_BORDER );
963 const SvxBoxInfoItem* pOldInner = (const SvxBoxInfoItem*) &pOldSet->Get( ATTR_BORDER_INNER );
964 const SvxBoxInfoItem* pNewInner = (const SvxBoxInfoItem*) &pDialogSet->Get( ATTR_BORDER_INNER );
965 SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
966 SfxItemPool* pNewPool = rNewSet.GetPool();
968 pNewPool->Put( *pNewOuter ); // don't delete yet
969 pNewPool->Put( *pNewInner );
970 rNewSet.ClearItem( ATTR_BORDER );
971 rNewSet.ClearItem( ATTR_BORDER_INNER );
974 * establish whether border attribute is to be set:
975 * 1. new != old
976 * 2. is one of the borders not-DontCare (since 238.f: IsxxValid())
980 sal_Bool bFrame = (pDialogSet->GetItemState( ATTR_BORDER ) != SFX_ITEM_DEFAULT)
981 || (pDialogSet->GetItemState( ATTR_BORDER_INNER ) != SFX_ITEM_DEFAULT);
983 if ( pNewOuter==pOldOuter && pNewInner==pOldInner )
984 bFrame = false;
986 // this should be intercepted by the pool: ?!??!??
988 if ( bFrame && pNewOuter && pNewInner )
989 if ( *pNewOuter == *pOldOuter && *pNewInner == *pOldInner )
990 bFrame = false;
992 if ( pNewInner )
994 bFrame = bFrame
995 && ( pNewInner->IsValid(VALID_LEFT)
996 || pNewInner->IsValid(VALID_RIGHT)
997 || pNewInner->IsValid(VALID_TOP)
998 || pNewInner->IsValid(VALID_BOTTOM)
999 || pNewInner->IsValid(VALID_HORI)
1000 || pNewInner->IsValid(VALID_VERT) );
1002 else
1003 bFrame = false;
1005 if (!bFrame)
1006 ApplySelectionPattern( aNewAttrs, bRecord ); // standard only
1007 else
1009 // if new items are default-items, overwrite the old items:
1011 sal_Bool bDefNewOuter = ( SFX_ITEMS_STATICDEFAULT == pNewOuter->GetKind() );
1012 sal_Bool bDefNewInner = ( SFX_ITEMS_STATICDEFAULT == pNewInner->GetKind() );
1014 ApplyPatternLines( aNewAttrs,
1015 bDefNewOuter ? pOldOuter : pNewOuter,
1016 bDefNewInner ? pOldInner : pNewInner,
1017 bRecord );
1020 pNewPool->Remove( *pNewOuter ); // release
1021 pNewPool->Remove( *pNewInner );
1023 // adjust height
1024 AdjustBlockHeight();
1026 // CellContentChanged is called in ApplySelectionPattern / ApplyPatternLines
1029 void ScViewFunc::ApplyAttr( const SfxPoolItem& rAttrItem )
1031 // not editable because of matrix only? attribute OK nonetheless
1032 bool bOnlyNotBecauseOfMatrix;
1033 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1035 ErrorMessage(STR_PROTECTIONERR);
1036 return;
1039 ScPatternAttr aNewAttrs( new SfxItemSet( *GetViewData()->GetDocument()->GetPool(),
1040 ATTR_PATTERN_START, ATTR_PATTERN_END ) );
1042 aNewAttrs.GetItemSet().Put( rAttrItem );
1043 // if justify is set (with Buttons), always indentation 0
1044 if ( rAttrItem.Which() == ATTR_HOR_JUSTIFY )
1045 aNewAttrs.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, 0 ) );
1046 ApplySelectionPattern( aNewAttrs );
1048 AdjustBlockHeight();
1050 // CellContentChanged is called in ApplySelectionPattern
1054 // patterns and borders
1056 void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem* pNewOuter,
1057 const SvxBoxInfoItem* pNewInner, sal_Bool bRecord )
1059 ScDocument* pDoc = GetViewData()->GetDocument();
1060 ScMarkData aFuncMark( GetViewData()->GetMarkData() ); // local copy for UnmarkFiltered
1061 ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1062 if (bRecord && !pDoc->IsUndoEnabled())
1063 bRecord = false;
1065 ScRange aMarkRange;
1066 aFuncMark.MarkToSimple();
1067 sal_Bool bMulti = aFuncMark.IsMultiMarked();
1068 if (bMulti)
1069 aFuncMark.GetMultiMarkArea( aMarkRange );
1070 else if (aFuncMark.IsMarked())
1071 aFuncMark.GetMarkArea( aMarkRange );
1072 else
1074 aMarkRange = ScRange( GetViewData()->GetCurX(),
1075 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1076 DoneBlockMode();
1077 InitOwnBlockMode();
1078 aFuncMark.SetMarkArea(aMarkRange);
1079 MarkDataChanged();
1082 ScDocShell* pDocSh = GetViewData()->GetDocShell();
1084 ScDocShellModificator aModificator( *pDocSh );
1086 if (bRecord)
1088 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1089 SCTAB nStartTab = aMarkRange.aStart.Tab();
1090 SCTAB nTabCount = pDoc->GetTableCount();
1091 pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
1092 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1093 for (; itr != itrEnd; ++itr)
1094 if (*itr != nStartTab)
1095 pUndoDoc->AddUndoTab( *itr, *itr );
1097 ScRange aCopyRange = aMarkRange;
1098 aCopyRange.aStart.SetTab(0);
1099 aCopyRange.aEnd.SetTab(nTabCount-1);
1100 pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &aFuncMark );
1102 pDocSh->GetUndoManager()->AddUndoAction(
1103 new ScUndoSelectionAttr(
1104 pDocSh, aFuncMark,
1105 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), aMarkRange.aStart.Tab(),
1106 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), aMarkRange.aEnd.Tab(),
1107 pUndoDoc, bMulti, &rAttr, pNewOuter, pNewInner ) );
1110 sal_uInt16 nExt = SC_PF_TESTMERGE;
1111 pDocSh->UpdatePaintExt( nExt, aMarkRange ); // content before the change
1113 pDoc->ApplySelectionFrame( aFuncMark, pNewOuter, pNewInner );
1115 pDocSh->UpdatePaintExt( nExt, aMarkRange ); // content after the change
1117 aFuncMark.MarkToMulti();
1118 pDoc->ApplySelectionPattern( rAttr, aFuncMark );
1120 pDocSh->PostPaint( aMarkRange, PAINT_GRID, nExt );
1121 pDocSh->UpdateOle(GetViewData());
1122 aModificator.SetDocumentModified();
1123 CellContentChanged();
1125 StartFormatArea();
1128 // pattern only
1130 void ScViewFunc::ApplySelectionPattern( const ScPatternAttr& rAttr,
1131 sal_Bool bRecord, sal_Bool bCursorOnly )
1133 ScViewData* pViewData = GetViewData();
1134 ScDocShell* pDocSh = pViewData->GetDocShell();
1135 ScDocument* pDoc = pDocSh->GetDocument();
1136 ScMarkData aFuncMark( pViewData->GetMarkData() ); // local copy for UnmarkFiltered
1137 ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1139 if (bRecord && !pDoc->IsUndoEnabled())
1140 bRecord = false;
1142 // State from old ItemSet doesn't matter for paint flags, as any change will be
1143 // from SFX_ITEM_SET in the new ItemSet (default is ignored in ApplyPattern).
1144 // New alignment is checked (check in PostPaint isn't enough) in case a right
1145 // alignment is changed to left.
1146 const SfxItemSet& rNewSet = rAttr.GetItemSet();
1147 sal_Bool bSetLines = rNewSet.GetItemState( ATTR_BORDER, sal_True ) == SFX_ITEM_SET ||
1148 rNewSet.GetItemState( ATTR_SHADOW, sal_True ) == SFX_ITEM_SET;
1149 sal_Bool bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY, sal_True ) == SFX_ITEM_SET;
1151 sal_uInt16 nExtFlags = 0;
1152 if ( bSetLines )
1153 nExtFlags |= SC_PF_LINES;
1154 if ( bSetAlign )
1155 nExtFlags |= SC_PF_WHOLEROWS;
1157 ScDocShellModificator aModificator( *pDocSh );
1159 sal_Bool bMulti = aFuncMark.IsMultiMarked();
1160 aFuncMark.MarkToMulti();
1161 sal_Bool bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && aFuncMark.GetSelectCount() > 1);
1162 if (bOnlyTab)
1164 SCCOL nCol = pViewData->GetCurX();
1165 SCROW nRow = pViewData->GetCurY();
1166 SCTAB nTab = pViewData->GetTabNo();
1167 aFuncMark.SetMarkArea(ScRange(nCol,nRow,nTab));
1168 aFuncMark.MarkToMulti();
1171 ScRangeList aChangeRanges;
1173 if (aFuncMark.IsMultiMarked() && !bCursorOnly)
1175 ScRange aMarkRange;
1176 aFuncMark.GetMultiMarkArea( aMarkRange );
1177 SCTAB nTabCount = pDoc->GetTableCount();
1178 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1179 for (; itr != itrEnd; ++itr)
1181 ScRange aChangeRange( aMarkRange );
1182 aChangeRange.aStart.SetTab( *itr );
1183 aChangeRange.aEnd.SetTab( *itr );
1184 aChangeRanges.Append( aChangeRange );
1187 SCCOL nStartCol = aMarkRange.aStart.Col();
1188 SCROW nStartRow = aMarkRange.aStart.Row();
1189 SCTAB nStartTab = aMarkRange.aStart.Tab();
1190 SCCOL nEndCol = aMarkRange.aEnd.Col();
1191 SCROW nEndRow = aMarkRange.aEnd.Row();
1192 SCTAB nEndTab = aMarkRange.aEnd.Tab();
1194 ScUndoSelectionAttr* pUndoAttr = NULL;
1195 ScEditDataArray* pEditDataArray = NULL;
1196 if (bRecord)
1198 ScRange aCopyRange = aMarkRange;
1199 aCopyRange.aStart.SetTab(0);
1200 aCopyRange.aEnd.SetTab(nTabCount-1);
1202 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1203 pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
1204 itr = aFuncMark.begin();
1205 for (; itr != itrEnd; ++itr)
1206 if (*itr != nStartTab)
1207 pUndoDoc->AddUndoTab( *itr, *itr );
1208 pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &aFuncMark );
1210 aFuncMark.MarkToMulti();
1212 pUndoAttr = new ScUndoSelectionAttr(
1213 pDocSh, aFuncMark, nStartCol, nStartRow, nStartTab,
1214 nEndCol, nEndRow, nEndTab, pUndoDoc, bMulti, &rAttr );
1215 pDocSh->GetUndoManager()->AddUndoAction(pUndoAttr);
1216 pEditDataArray = pUndoAttr->GetDataArray();
1219 pDoc->ApplySelectionPattern( rAttr, aFuncMark, pEditDataArray );
1221 pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
1222 nEndCol, nEndRow, nEndTab,
1223 PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
1224 pDocSh->UpdateOle(GetViewData());
1225 aModificator.SetDocumentModified();
1226 CellContentChanged();
1228 else // single cell - simpler undo
1230 SCCOL nCol = pViewData->GetCurX();
1231 SCROW nRow = pViewData->GetCurY();
1232 SCTAB nTab = pViewData->GetTabNo();
1234 ScBaseCell* pCell;
1235 pDoc->GetCell(nCol, nRow, nTab, pCell);
1236 EditTextObject* pOldEditData = NULL;
1237 EditTextObject* pNewEditData = NULL;
1238 if (pCell && pCell->GetCellType() == CELLTYPE_EDIT)
1240 ScEditCell* pEditCell = static_cast<ScEditCell*>(pCell);
1241 pOldEditData = pEditCell->GetData()->Clone();
1242 pEditCell->RemoveCharAttribs(rAttr);
1243 pNewEditData = pEditCell->GetData()->Clone();
1246 aChangeRanges.Append( ScRange( nCol, nRow, nTab ) );
1247 ScPatternAttr* pOldPat = new ScPatternAttr(*pDoc->GetPattern( nCol, nRow, nTab ));
1249 pDoc->ApplyPattern( nCol, nRow, nTab, rAttr );
1251 const ScPatternAttr* pNewPat = pDoc->GetPattern( nCol, nRow, nTab );
1253 if (bRecord)
1255 ScUndoCursorAttr* pUndo = new ScUndoCursorAttr(
1256 pDocSh, nCol, nRow, nTab, pOldPat, pNewPat, &rAttr, false );
1257 pUndo->SetEditData(pOldEditData, pNewEditData);
1258 pDocSh->GetUndoManager()->AddUndoAction(pUndo);
1260 delete pOldPat; // is copied in undo (Pool)
1262 pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
1263 pDocSh->UpdateOle(GetViewData());
1264 aModificator.SetDocumentModified();
1265 CellContentChanged();
1268 // #i97876# Spreadsheet data changes are not notified
1269 ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
1270 if ( pModelObj && pModelObj->HasChangesListeners() )
1272 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aProperties;
1273 sal_Int32 nCount = 0;
1274 const SfxItemPropertyMap& rMap = ScCellObj::GetCellPropertyMap();
1275 PropertyEntryVector_t aPropVector = rMap.getPropertyEntries();
1276 for ( sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; ++nWhich )
1278 const SfxPoolItem* pItem = 0;
1279 if ( rNewSet.GetItemState( nWhich, sal_True, &pItem ) == SFX_ITEM_SET && pItem )
1281 PropertyEntryVector_t::const_iterator aIt = aPropVector.begin();
1282 while ( aIt != aPropVector.end())
1284 if ( aIt->nWID == nWhich )
1286 ::com::sun::star::uno::Any aVal;
1287 pItem->QueryValue( aVal, aIt->nMemberId );
1288 aProperties.realloc( nCount + 1 );
1289 aProperties[ nCount ].Name = aIt->sName;
1290 aProperties[ nCount ].Value <<= aVal;
1291 ++nCount;
1293 ++aIt;
1297 pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "attribute" ) ), aChangeRanges, aProperties );
1300 StartFormatArea();
1303 void ScViewFunc::ApplyUserItemSet( const SfxItemSet& rItemSet )
1305 // ItemSet from UI, may have different pool
1307 bool bOnlyNotBecauseOfMatrix;
1308 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1310 ErrorMessage(STR_PROTECTIONERR);
1311 return;
1314 ScPatternAttr aNewAttrs( GetViewData()->GetDocument()->GetPool() );
1315 SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
1316 rNewSet.Put( rItemSet, false );
1317 ApplySelectionPattern( aNewAttrs );
1319 AdjustBlockHeight();
1322 const SfxStyleSheet* ScViewFunc::GetStyleSheetFromMarked()
1324 // Don't use UnmarkFiltered in slot state functions, for performance reasons.
1325 // The displayed state is always that of the whole selection including filtered rows.
1327 const ScStyleSheet* pSheet = NULL;
1328 ScViewData* pViewData = GetViewData();
1329 ScDocument* pDoc = pViewData->GetDocument();
1330 ScMarkData& rMark = pViewData->GetMarkData();
1332 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1333 pSheet = pDoc->GetSelectionStyle( rMark ); // MarkToMulti isn't necessary
1334 else
1335 pSheet = pDoc->GetStyle( pViewData->GetCurX(),
1336 pViewData->GetCurY(),
1337 pViewData->GetTabNo() );
1339 return pSheet;
1342 void ScViewFunc::SetStyleSheetToMarked( SfxStyleSheet* pStyleSheet, sal_Bool bRecord )
1344 // not editable because of matrix only? attribute OK nonetheless
1345 bool bOnlyNotBecauseOfMatrix;
1346 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1348 ErrorMessage(STR_PROTECTIONERR);
1349 return;
1352 if ( !pStyleSheet) return;
1353 // -------------------------------------------------------------------
1355 ScViewData* pViewData = GetViewData();
1356 ScDocShell* pDocSh = pViewData->GetDocShell();
1357 ScDocument* pDoc = pDocSh->GetDocument();
1358 ScMarkData aFuncMark( pViewData->GetMarkData() ); // local copy for UnmarkFiltered
1359 ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1360 SCTAB nTabCount = pDoc->GetTableCount();
1361 if (bRecord && !pDoc->IsUndoEnabled())
1362 bRecord = false;
1364 ScDocShellModificator aModificator( *pDocSh );
1366 if ( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() )
1368 ScRange aMarkRange;
1369 aFuncMark.MarkToMulti();
1370 aFuncMark.GetMultiMarkArea( aMarkRange );
1372 if ( bRecord )
1374 SCTAB nTab = pViewData->GetTabNo();
1375 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1376 pUndoDoc->InitUndo( pDoc, nTab, nTab );
1377 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1378 for (; itr != itrEnd; ++itr)
1379 if (*itr != nTab)
1380 pUndoDoc->AddUndoTab( *itr, *itr );
1382 ScRange aCopyRange = aMarkRange;
1383 aCopyRange.aStart.SetTab(0);
1384 aCopyRange.aEnd.SetTab(nTabCount-1);
1385 pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, sal_True, pUndoDoc, &aFuncMark );
1386 aFuncMark.MarkToMulti();
1388 String aName = pStyleSheet->GetName();
1389 pDocSh->GetUndoManager()->AddUndoAction(
1390 new ScUndoSelectionStyle( pDocSh, aFuncMark, aMarkRange, aName, pUndoDoc ) );
1393 pDoc->ApplySelectionStyle( (ScStyleSheet&)*pStyleSheet, aFuncMark );
1395 if (!AdjustBlockHeight())
1396 pViewData->GetDocShell()->PostPaint( aMarkRange, PAINT_GRID );
1398 aFuncMark.MarkToSimple();
1400 else
1402 SCCOL nCol = pViewData->GetCurX();
1403 SCROW nRow = pViewData->GetCurY();
1404 SCTAB nTab = pViewData->GetTabNo();
1406 if ( bRecord )
1408 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1409 pUndoDoc->InitUndo( pDoc, nTab, nTab );
1410 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1411 for (; itr != itrEnd; ++itr)
1412 if (*itr != nTab)
1413 pUndoDoc->AddUndoTab( *itr, *itr );
1415 ScRange aCopyRange( nCol, nRow, 0, nCol, nRow, nTabCount-1 );
1416 pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, false, pUndoDoc );
1418 ScRange aMarkRange ( nCol, nRow, nTab );
1419 ScMarkData aUndoMark = aFuncMark;
1420 aUndoMark.SetMultiMarkArea( aMarkRange );
1422 String aName = pStyleSheet->GetName();
1423 pDocSh->GetUndoManager()->AddUndoAction(
1424 new ScUndoSelectionStyle( pDocSh, aUndoMark, aMarkRange, aName, pUndoDoc ) );
1427 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1428 for (; itr != itrEnd; ++itr)
1429 pDoc->ApplyStyle( nCol, nRow, *itr, (ScStyleSheet&)*pStyleSheet );
1431 if (!AdjustBlockHeight())
1432 pViewData->GetDocShell()->PostPaintCell( nCol, nRow, nTab );
1436 aModificator.SetDocumentModified();
1438 StartFormatArea();
1442 void ScViewFunc::RemoveStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1444 if ( !pStyleSheet) return;
1445 // -------------------------------------------------------------------
1447 ScViewData* pViewData = GetViewData();
1448 ScDocument* pDoc = pViewData->GetDocument();
1449 ScDocShell* pDocSh = pViewData->GetDocShell();
1451 ScDocShellModificator aModificator( *pDocSh );
1453 VirtualDevice aVirtDev;
1454 aVirtDev.SetMapMode(MAP_PIXEL);
1455 pDoc->StyleSheetChanged( pStyleSheet, sal_True, &aVirtDev,
1456 pViewData->GetPPTX(),
1457 pViewData->GetPPTY(),
1458 pViewData->GetZoomX(),
1459 pViewData->GetZoomY() );
1461 pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
1462 aModificator.SetDocumentModified();
1464 ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1465 if (pHdl)
1466 pHdl->ForgetLastPattern();
1469 void ScViewFunc::UpdateStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1471 if ( !pStyleSheet) return;
1472 // -------------------------------------------------------------------
1474 ScViewData* pViewData = GetViewData();
1475 ScDocument* pDoc = pViewData->GetDocument();
1476 ScDocShell* pDocSh = pViewData->GetDocShell();
1478 ScDocShellModificator aModificator( *pDocSh );
1480 VirtualDevice aVirtDev;
1481 aVirtDev.SetMapMode(MAP_PIXEL);
1482 pDoc->StyleSheetChanged( pStyleSheet, false, &aVirtDev,
1483 pViewData->GetPPTX(),
1484 pViewData->GetPPTY(),
1485 pViewData->GetZoomX(),
1486 pViewData->GetZoomY() );
1488 pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
1489 aModificator.SetDocumentModified();
1491 ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1492 if (pHdl)
1493 pHdl->ForgetLastPattern();
1496 // insert cells - undo OK
1498 sal_Bool ScViewFunc::InsertCells( InsCellCmd eCmd, sal_Bool bRecord, sal_Bool bPartOfPaste )
1500 ScRange aRange;
1501 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
1503 ScDocShell* pDocSh = GetViewData()->GetDocShell();
1504 const ScMarkData& rMark = GetViewData()->GetMarkData();
1505 sal_Bool bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, &rMark, eCmd, bRecord, false, bPartOfPaste );
1506 if (bSuccess)
1508 pDocSh->UpdateOle(GetViewData());
1509 CellContentChanged();
1511 // #i97876# Spreadsheet data changes are not notified
1512 ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
1513 if ( pModelObj && pModelObj->HasChangesListeners() )
1515 if ( eCmd == INS_INSROWS || eCmd == INS_INSCOLS )
1517 ScRangeList aChangeRanges;
1518 aChangeRanges.Append( aRange );
1519 ::rtl::OUString aOperation = ( eCmd == INS_INSROWS ?
1520 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert-rows" ) ) :
1521 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert-columns" ) ) );
1522 pModelObj->NotifyChanges( aOperation, aChangeRanges );
1526 return bSuccess;
1528 else
1530 ErrorMessage(STR_NOMULTISELECT);
1531 return false;
1535 // delete cells - undo OK
1537 void ScViewFunc::DeleteCells( DelCellCmd eCmd, sal_Bool bRecord )
1539 ScRange aRange;
1540 if ( GetViewData()->GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
1542 ScDocShell* pDocSh = GetViewData()->GetDocShell();
1543 const ScMarkData& rMark = GetViewData()->GetMarkData();
1545 // #i94841# [Collaboration] if deleting rows is rejected, the content is sometimes wrong
1546 if ( pDocSh->IsDocShared() && ( eCmd == DEL_DELROWS || eCmd == DEL_DELCOLS ) )
1548 ScRange aDelRange( aRange.aStart );
1549 SCCOLROW nCount = 0;
1550 if ( eCmd == DEL_DELROWS )
1552 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
1554 else
1556 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Col() - aRange.aStart.Col() + 1 );
1558 while ( nCount > 0 )
1560 pDocSh->GetDocFunc().DeleteCells( aDelRange, &rMark, eCmd, bRecord, false );
1561 --nCount;
1564 else
1566 pDocSh->GetDocFunc().DeleteCells( aRange, &rMark, eCmd, bRecord, false );
1569 pDocSh->UpdateOle(GetViewData());
1570 CellContentChanged();
1572 // #i97876# Spreadsheet data changes are not notified
1573 ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
1574 if ( pModelObj && pModelObj->HasChangesListeners() )
1576 if ( eCmd == DEL_DELROWS || eCmd == DEL_DELCOLS )
1578 ScRangeList aChangeRanges;
1579 aChangeRanges.Append( aRange );
1580 ::rtl::OUString aOperation = ( eCmd == DEL_DELROWS ?
1581 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete-rows" ) ) :
1582 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete-columns" ) ) );
1583 pModelObj->NotifyChanges( aOperation, aChangeRanges );
1587 // put cursor directly behind deleted range
1588 SCCOL nCurX = GetViewData()->GetCurX();
1589 SCROW nCurY = GetViewData()->GetCurY();
1590 if ( eCmd==DEL_CELLSLEFT || eCmd==DEL_DELCOLS )
1591 nCurX = aRange.aStart.Col();
1592 else
1593 nCurY = aRange.aStart.Row();
1594 SetCursor( nCurX, nCurY );
1596 else
1598 if (eCmd == DEL_DELCOLS)
1599 DeleteMulti( false, bRecord );
1600 else if (eCmd == DEL_DELROWS)
1601 DeleteMulti( sal_True, bRecord );
1602 else
1603 ErrorMessage(STR_NOMULTISELECT);
1606 Unmark();
1609 void ScViewFunc::DeleteMulti( sal_Bool bRows, sal_Bool bRecord )
1611 ScDocShell* pDocSh = GetViewData()->GetDocShell();
1612 ScDocShellModificator aModificator( *pDocSh );
1613 SCTAB nTab = GetViewData()->GetTabNo();
1614 ScDocument* pDoc = pDocSh->GetDocument();
1615 ScMarkData aFuncMark( GetViewData()->GetMarkData() ); // local copy for UnmarkFiltered
1616 ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1618 if (bRecord && !pDoc->IsUndoEnabled())
1619 bRecord = false;
1620 SCCOLROW* pRanges = new SCCOLROW[MAXCOLROWCOUNT];
1621 SCCOLROW nRangeCnt = bRows ? aFuncMark.GetMarkRowRanges( pRanges ) :
1622 aFuncMark.GetMarkColumnRanges( pRanges );
1623 if (nRangeCnt == 0)
1625 pRanges[0] = pRanges[1] = bRows ? static_cast<SCCOLROW>(GetViewData()->GetCurY()) : static_cast<SCCOLROW>(GetViewData()->GetCurX());
1626 nRangeCnt = 1;
1629 // test if allowed
1631 SCCOLROW* pOneRange = pRanges;
1632 sal_uInt16 nErrorId = 0;
1633 sal_Bool bNeedRefresh = false;
1634 SCCOLROW nRangeNo;
1635 for (nRangeNo=0; nRangeNo<nRangeCnt && !nErrorId; nRangeNo++)
1637 SCCOLROW nStart = *(pOneRange++);
1638 SCCOLROW nEnd = *(pOneRange++);
1640 SCCOL nStartCol, nEndCol;
1641 SCROW nStartRow, nEndRow;
1642 if ( bRows )
1644 nStartCol = 0;
1645 nEndCol = MAXCOL;
1646 nStartRow = static_cast<SCROW>(nStart);
1647 nEndRow = static_cast<SCROW>(nEnd);
1649 else
1651 nStartCol = static_cast<SCCOL>(nStart);
1652 nEndCol = static_cast<SCCOL>(nEnd);
1653 nStartRow = 0;
1654 nEndRow = MAXROW;
1657 // cell protection (only needed for first range, as all following cells are moved)
1658 if ( nRangeNo == 0 )
1660 // test to the end of the sheet
1661 ScEditableTester aTester( pDoc, nTab, nStartCol, nStartRow, MAXCOL, MAXROW );
1662 if (!aTester.IsEditable())
1663 nErrorId = aTester.GetMessageId();
1666 // merged cells
1667 SCCOL nMergeStartX = nStartCol;
1668 SCROW nMergeStartY = nStartRow;
1669 SCCOL nMergeEndX = nEndCol;
1670 SCROW nMergeEndY = nEndRow;
1671 pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1672 pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1674 if ( nMergeStartX != nStartCol || nMergeStartY != nStartRow )
1676 // Disallow deleting parts of a merged cell.
1677 // Deleting the start is allowed (merge is removed), so the end doesn't have to be checked.
1679 nErrorId = STR_MSSG_DELETECELLS_0;
1681 if ( nMergeEndX != nEndCol || nMergeEndY != nEndRow )
1683 // detect if the start of a merged cell is deleted, so the merge flags can be refreshed
1685 bNeedRefresh = sal_True;
1689 if ( nErrorId )
1691 ErrorMessage( nErrorId );
1692 delete[] pRanges;
1693 return;
1696 // proceed
1698 WaitObject aWait( GetFrameWin() ); // important for TrackFormulas in UpdateReference
1700 ScDocument* pUndoDoc = NULL;
1701 ScRefUndoData* pUndoData = NULL;
1702 if (bRecord)
1704 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1705 pUndoDoc->InitUndo( pDoc, nTab, nTab, !bRows, bRows ); // row height
1707 pOneRange = pRanges;
1708 for (nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
1710 SCCOLROW nStart = *(pOneRange++);
1711 SCCOLROW nEnd = *(pOneRange++);
1712 if (bRows)
1713 pDoc->CopyToDocument( 0,nStart,nTab, MAXCOL,nEnd,nTab, IDF_ALL,false,pUndoDoc );
1714 else
1715 pDoc->CopyToDocument( static_cast<SCCOL>(nStart),0,nTab,
1716 static_cast<SCCOL>(nEnd),MAXROW,nTab,
1717 IDF_ALL,false,pUndoDoc );
1720 // all Formulas because of references
1721 SCTAB nTabCount = pDoc->GetTableCount();
1722 pUndoDoc->AddUndoTab( 0, nTabCount-1, false, false );
1723 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA,false,pUndoDoc );
1725 pUndoData = new ScRefUndoData( pDoc );
1727 pDoc->BeginDrawUndo();
1730 pOneRange = &pRanges[2*nRangeCnt]; // backwards
1731 for (nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
1733 SCCOLROW nEnd = *(--pOneRange);
1734 SCCOLROW nStart = *(--pOneRange);
1736 if (bRows)
1737 pDoc->DeleteRow( 0,nTab, MAXCOL,nTab, nStart, static_cast<SCSIZE>(nEnd-nStart+1) );
1738 else
1739 pDoc->DeleteCol( 0,nTab, MAXROW,nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
1742 if (bNeedRefresh)
1744 SCCOLROW nFirstStart = pRanges[0];
1745 SCCOL nStartCol = bRows ? 0 : static_cast<SCCOL>(nFirstStart);
1746 SCROW nStartRow = bRows ? static_cast<SCROW>(nFirstStart) : 0;
1747 SCCOL nEndCol = MAXCOL;
1748 SCROW nEndRow = MAXROW;
1750 pDoc->RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
1751 pDoc->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, sal_True );
1754 if (bRecord)
1756 pDocSh->GetUndoManager()->AddUndoAction(
1757 new ScUndoDeleteMulti( pDocSh, bRows, bNeedRefresh, nTab, pRanges, nRangeCnt,
1758 pUndoDoc, pUndoData ) );
1761 if (!AdjustRowHeight(0, MAXROW))
1763 if (bRows)
1764 pDocSh->PostPaint( 0,pRanges[0],nTab, MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_LEFT );
1765 else
1766 pDocSh->PostPaint( static_cast<SCCOL>(pRanges[0]),0,nTab,
1767 MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_TOP );
1769 aModificator.SetDocumentModified();
1771 CellContentChanged();
1773 // put cursor directly behind the first deleted range
1774 SCCOL nCurX = GetViewData()->GetCurX();
1775 SCROW nCurY = GetViewData()->GetCurY();
1776 if ( bRows )
1777 nCurY = pRanges[0];
1778 else
1779 nCurX = static_cast<SCCOL>(pRanges[0]);
1780 SetCursor( nCurX, nCurY );
1782 delete[] pRanges;
1784 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
1787 // delete contents
1789 void ScViewFunc::DeleteContents( sal_uInt16 nFlags, sal_Bool bRecord )
1791 ScViewData* pViewData = GetViewData();
1792 pViewData->SetPasteMode( SC_PASTE_NONE );
1793 pViewData->GetViewShell()->UpdateCopySourceOverlay();
1795 // not editable because of matrix only? attribute OK nonetheless
1796 bool bOnlyNotBecauseOfMatrix;
1797 sal_Bool bEditable = SelectionEditable( &bOnlyNotBecauseOfMatrix );
1798 if ( !bEditable )
1800 if ( !(bOnlyNotBecauseOfMatrix &&
1801 ((nFlags & (IDF_ATTRIB | IDF_EDITATTR)) == nFlags)) )
1803 ErrorMessage(bOnlyNotBecauseOfMatrix ? STR_MATRIXFRAGMENTERR : STR_PROTECTIONERR);
1804 return;
1808 ScRange aMarkRange;
1809 sal_Bool bSimple = false;
1811 ScDocument* pDoc = GetViewData()->GetDocument();
1812 ScDocShell* pDocSh = GetViewData()->GetDocShell();
1813 ScMarkData aFuncMark( GetViewData()->GetMarkData() ); // local copy for UnmarkFiltered
1814 ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1816 if (bRecord && !pDoc->IsUndoEnabled())
1817 bRecord = false;
1819 ScDocShellModificator aModificator( *pDocSh );
1821 if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
1823 aMarkRange.aStart.SetCol(GetViewData()->GetCurX());
1824 aMarkRange.aStart.SetRow(GetViewData()->GetCurY());
1825 aMarkRange.aStart.SetTab(GetViewData()->GetTabNo());
1826 aMarkRange.aEnd = aMarkRange.aStart;
1827 if ( pDoc->HasAttrib( aMarkRange, HASATTR_MERGED ) )
1829 aFuncMark.SetMarkArea( aMarkRange );
1831 else
1832 bSimple = sal_True;
1835 aFuncMark.SetMarking(false); // for MarkToMulti
1836 aFuncMark.MarkToSimple(); // before bMulti test below
1838 OSL_ENSURE( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() || bSimple, "delete what?" );
1840 ScDocument* pUndoDoc = NULL;
1841 sal_Bool bMulti = !bSimple && aFuncMark.IsMultiMarked();
1842 if (!bSimple)
1844 aFuncMark.MarkToMulti();
1845 aFuncMark.GetMultiMarkArea( aMarkRange );
1847 ScRange aExtendedRange(aMarkRange);
1848 if (!bSimple)
1850 if ( pDoc->ExtendMerge( aExtendedRange, sal_True ) )
1851 bMulti = false;
1854 // no objects on protected tabs
1855 sal_Bool bObjects = false;
1856 if ( nFlags & IDF_OBJECTS )
1858 bObjects = sal_True;
1859 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1860 for (; itr != itrEnd; ++itr)
1861 if (pDoc->IsTabProtected(*itr))
1862 bObjects = false;
1865 sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted
1866 if ( nFlags & IDF_ATTRIB )
1867 pDocSh->UpdatePaintExt( nExtFlags, aMarkRange );
1869 // order op opeeration:
1870 // 1) BeginDrawUndo
1871 // 2) delete objects (DrawUndo is filled)
1872 // 3) copy contents for undo
1873 // 4) delete contents
1874 // 5) add undo-action
1876 sal_Bool bDrawUndo = bObjects || ( nFlags & IDF_NOTE ); // needed for shown notes
1877 if ( bDrawUndo && bRecord )
1878 pDoc->BeginDrawUndo();
1880 if (bObjects)
1882 if (bMulti)
1883 pDoc->DeleteObjectsInSelection( aFuncMark );
1884 else
1885 pDoc->DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1886 /*!*/ aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
1887 aFuncMark );
1890 if ( bRecord )
1892 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1893 SCTAB nTab = aMarkRange.aStart.Tab();
1894 pUndoDoc->InitUndo( pDoc, nTab, nTab );
1895 SCTAB nTabCount = pDoc->GetTableCount();
1896 ScMarkData::iterator itr = aFuncMark.begin(), itrEnd = aFuncMark.end();
1897 for (; itr != itrEnd; ++itr)
1898 if (*itr != nTab)
1899 pUndoDoc->AddUndoTab( *itr, *itr );
1900 ScRange aCopyRange = aExtendedRange;
1901 aCopyRange.aStart.SetTab(0);
1902 aCopyRange.aEnd.SetTab(nTabCount-1);
1904 // in case of "Format/Standard" copy all attributes, because CopyToDocument
1905 // with IDF_HARDATTR only is too time-consuming:
1906 sal_uInt16 nUndoDocFlags = nFlags;
1907 if (nFlags & IDF_ATTRIB)
1908 nUndoDocFlags |= IDF_ATTRIB;
1909 if (nFlags & IDF_EDITATTR) // Edit-Engine-Attribute
1910 nUndoDocFlags |= IDF_STRING; // -> cells will be changed
1911 if (nFlags & IDF_NOTE)
1912 nUndoDocFlags |= IDF_CONTENTS; // copy all cells with their notes
1913 // do not copy note captions to undo document
1914 nUndoDocFlags |= IDF_NOCAPTIONS;
1915 pDoc->CopyToDocument( aCopyRange, nUndoDocFlags, bMulti, pUndoDoc, &aFuncMark );
1918 HideAllCursors(); // for if summary is cancelled
1919 if (bSimple)
1920 pDoc->DeleteArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1921 aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
1922 aFuncMark, nFlags );
1923 else
1925 pDoc->DeleteSelection( nFlags, aFuncMark );
1928 if ( bRecord )
1930 pDocSh->GetUndoManager()->AddUndoAction(
1931 new ScUndoDeleteContents( pDocSh, aFuncMark, aExtendedRange,
1932 pUndoDoc, bMulti, nFlags, bDrawUndo ) );
1935 if (!AdjustRowHeight( aExtendedRange.aStart.Row(), aExtendedRange.aEnd.Row() ))
1936 pDocSh->PostPaint( aExtendedRange, PAINT_GRID, nExtFlags );
1938 pDocSh->UpdateOle(GetViewData());
1940 // #i97876# Spreadsheet data changes are not notified
1941 ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
1942 if ( pModelObj && pModelObj->HasChangesListeners() )
1944 ScRangeList aChangeRanges;
1945 if ( bSimple )
1947 aChangeRanges.Append( aMarkRange );
1949 else
1951 aFuncMark.FillRangeListWithMarks( &aChangeRanges, false );
1953 pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
1956 aModificator.SetDocumentModified();
1957 CellContentChanged();
1958 ShowAllCursors();
1960 if ( nFlags & IDF_ATTRIB )
1962 if ( nFlags & IDF_CONTENTS )
1963 ForgetFormatArea();
1964 else
1965 StartFormatArea(); // delete attribute is also attribute-change
1969 // column width/row height (via header) - undo OK
1971 void ScViewFunc::SetWidthOrHeight( sal_Bool bWidth, SCCOLROW nRangeCnt, SCCOLROW* pRanges,
1972 ScSizeMode eMode, sal_uInt16 nSizeTwips,
1973 sal_Bool bRecord, sal_Bool bPaint, ScMarkData* pMarkData )
1975 if (nRangeCnt == 0)
1976 return;
1978 // use view's mark if none specified
1979 if ( !pMarkData )
1980 pMarkData = &GetViewData()->GetMarkData();
1982 ScDocShell* pDocSh = GetViewData()->GetDocShell();
1983 ScDocument* pDoc = pDocSh->GetDocument();
1984 SCTAB nFirstTab = pMarkData->GetFirstSelected();
1985 SCTAB nCurTab = GetViewData()->GetTabNo();
1986 SCTAB nTab;
1987 if (bRecord && !pDoc->IsUndoEnabled())
1988 bRecord = false;
1990 ScDocShellModificator aModificator( *pDocSh );
1992 bool bAllowed = true;
1993 ScMarkData::iterator itr = pMarkData->begin(), itrEnd = pMarkData->end();
1994 for (; itr != itrEnd && bAllowed; ++itr)
1995 for ( SCCOLROW i=0; i<nRangeCnt && bAllowed; i++ )
1997 bool bOnlyMatrix;
1998 if (bWidth)
1999 bAllowed = pDoc->IsBlockEditable( *itr,
2000 static_cast<SCCOL>(pRanges[2*i]),0,
2001 static_cast<SCCOL>(pRanges[2*i+1]),MAXROW,
2002 &bOnlyMatrix ) || bOnlyMatrix;
2003 else
2004 bAllowed = pDoc->IsBlockEditable( *itr, 0,pRanges[2*i],
2005 MAXCOL,pRanges[2*i+1], &bOnlyMatrix ) ||
2006 bOnlyMatrix;
2009 // Allow users to resize cols/rows in readonly docs despite the r/o state.
2010 // It is frustrating to be unable to see content in mis-sized cells.
2011 if( !bAllowed && !pDocSh->IsReadOnly() )
2013 ErrorMessage(STR_PROTECTIONERR);
2014 return;
2017 SCCOLROW nStart = pRanges[0];
2018 SCCOLROW nEnd = pRanges[2*nRangeCnt-1];
2020 sal_Bool bFormula = false;
2021 if ( eMode == SC_SIZE_OPTIMAL )
2023 const ScViewOptions& rOpts = GetViewData()->GetOptions();
2024 bFormula = rOpts.GetOption( VOPT_FORMULAS );
2027 ScDocument* pUndoDoc = NULL;
2028 ScOutlineTable* pUndoTab = NULL;
2029 SCCOLROW* pUndoRanges = NULL;
2031 if ( bRecord )
2033 pDoc->BeginDrawUndo(); // Drawing Updates
2035 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2036 itr = pMarkData->begin();
2037 for (; itr != itrEnd; ++itr)
2039 if (bWidth)
2041 if ( *itr == nFirstTab )
2042 pUndoDoc->InitUndo( pDoc, *itr, *itr, true, false );
2043 else
2044 pUndoDoc->AddUndoTab( *itr, *itr, true, false );
2045 pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, *itr,
2046 static_cast<SCCOL>(nEnd), MAXROW, *itr, IDF_NONE,
2047 false, pUndoDoc );
2049 else
2051 if ( *itr == nFirstTab )
2052 pUndoDoc->InitUndo( pDoc, *itr, *itr, false, true );
2053 else
2054 pUndoDoc->AddUndoTab( *itr, *itr, false, true );
2055 pDoc->CopyToDocument( 0, nStart, *itr, MAXCOL, nEnd, *itr, IDF_NONE, false, pUndoDoc );
2059 pUndoRanges = new SCCOLROW[ 2*nRangeCnt ];
2060 memcpy( pUndoRanges, pRanges, 2*nRangeCnt*sizeof(SCCOLROW) );
2062 //! outlines from all tab?
2063 ScOutlineTable* pTable = pDoc->GetOutlineTable( nCurTab );
2064 if (pTable)
2065 pUndoTab = new ScOutlineTable( *pTable );
2068 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2069 pMarkData->MarkToMulti();
2071 sal_Bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
2072 sal_Bool bOutline = false;
2074 itr = pMarkData->begin();
2075 for (; itr != itrEnd; ++itr)
2077 nTab = *itr;
2078 const SCCOLROW* pTabRanges = pRanges;
2080 pDoc->InitializeNoteCaptions( nTab );
2081 for (SCCOLROW nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
2083 SCCOLROW nStartNo = *(pTabRanges++);
2084 SCCOLROW nEndNo = *(pTabRanges++);
2086 if ( !bWidth ) // height always blockwise
2088 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2090 sal_Bool bAll = ( eMode==SC_SIZE_OPTIMAL );
2091 if (!bAll)
2093 // delete CR_MANUALSIZE for all in range,
2094 // then SetOptimalHeight with bShrink = FALSE
2095 for (SCROW nRow = nStartNo; nRow <= nEndNo; ++nRow)
2097 SCROW nLastRow = nRow;
2098 if (pDoc->RowHidden(nRow, nTab, NULL, &nLastRow))
2100 nRow = nLastRow;
2101 continue;
2104 sal_uInt8 nOld = pDoc->GetRowFlags(nRow, nTab);
2105 if (nOld & CR_MANUALSIZE)
2106 pDoc->SetRowFlags(nRow, nTab, nOld & ~CR_MANUALSIZE);
2110 double nPPTX = GetViewData()->GetPPTX();
2111 double nPPTY = GetViewData()->GetPPTY();
2112 Fraction aZoomX = GetViewData()->GetZoomX();
2113 Fraction aZoomY = GetViewData()->GetZoomY();
2115 ScSizeDeviceProvider aProv(pDocSh);
2116 if (aProv.IsPrinter())
2118 nPPTX = aProv.GetPPTX();
2119 nPPTY = aProv.GetPPTY();
2120 aZoomX = aZoomY = Fraction( 1, 1 );
2123 pDoc->SetOptimalHeight( nStartNo, nEndNo, nTab, nSizeTwips, aProv.GetDevice(),
2124 nPPTX, nPPTY, aZoomX, aZoomY, bAll );
2125 if (bAll)
2126 pDoc->ShowRows( nStartNo, nEndNo, nTab, sal_True );
2128 // Manual-Flag already (re)set in SetOptimalHeight in case of bAll=sal_True
2129 // (set for Extra-Height, else reset).
2131 else if ( eMode==SC_SIZE_DIRECT )
2133 if (nSizeTwips)
2135 pDoc->SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
2136 pDoc->SetManualHeight( nStartNo, nEndNo, nTab, sal_True ); // height was set manually
2138 pDoc->ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
2140 else if ( eMode==SC_SIZE_SHOW )
2142 pDoc->ShowRows( nStartNo, nEndNo, nTab, sal_True );
2145 else // column width
2147 for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
2149 if ( eMode != SC_SIZE_VISOPT || !pDoc->ColHidden(nCol, nTab) )
2151 sal_uInt16 nThisSize = nSizeTwips;
2153 if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2154 nThisSize = nSizeTwips + GetOptimalColWidth( nCol, nTab, bFormula );
2155 if ( nThisSize )
2156 pDoc->SetColWidth( nCol, nTab, nThisSize );
2158 pDoc->ShowCol( nCol, nTab, bShow );
2163 // adjust outline
2165 if (bWidth)
2167 if ( pDoc->UpdateOutlineCol( static_cast<SCCOL>(nStartNo),
2168 static_cast<SCCOL>(nEndNo), nTab, bShow ) )
2169 bOutline = sal_True;
2171 else
2173 if ( pDoc->UpdateOutlineRow( nStartNo, nEndNo, nTab, bShow ) )
2174 bOutline = sal_True;
2177 pDoc->SetDrawPageSize(nTab);
2181 if (!bOutline)
2182 DELETEZ(pUndoTab);
2184 if (bRecord)
2186 pDocSh->GetUndoManager()->AddUndoAction(
2187 new ScUndoWidthOrHeight( pDocSh, *pMarkData,
2188 nStart, nCurTab, nEnd, nCurTab,
2189 pUndoDoc, nRangeCnt, pUndoRanges,
2190 pUndoTab, eMode, nSizeTwips, bWidth ) );
2193 // fdo#36247 Ensure that the drawing layer's map mode scaling factors match
2194 // the new heights and widths.
2195 GetViewData()->GetView()->RefreshZoom();
2197 itr = pMarkData->begin();
2198 for (; itr != itrEnd; ++itr)
2199 pDoc->UpdatePageBreaks( *itr );
2201 GetViewData()->GetView()->UpdateScrollBars();
2203 if (bPaint)
2205 itr = pMarkData->begin();
2206 for (; itr != itrEnd; ++itr)
2208 nTab = *itr;
2209 if (bWidth)
2211 if (pDoc->HasAttrib( static_cast<SCCOL>(nStart),0,nTab,
2212 static_cast<SCCOL>(nEnd),MAXROW,nTab,
2213 HASATTR_MERGED | HASATTR_OVERLAPPED ))
2214 nStart = 0;
2215 if (nStart > 0) // go upwards because of Lines and cursor
2216 --nStart;
2217 pDocSh->PostPaint( static_cast<SCCOL>(nStart), 0, nTab,
2218 MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_TOP );
2220 else
2222 if (pDoc->HasAttrib( 0,nStart,nTab, MAXCOL,nEnd,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
2223 nStart = 0;
2224 if (nStart != 0)
2225 --nStart;
2226 pDocSh->PostPaint( 0, nStart, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_LEFT );
2230 pDocSh->UpdateOle(GetViewData());
2231 if( !pDocSh->IsReadOnly() )
2232 aModificator.SetDocumentModified();
2235 // #i97876# Spreadsheet data changes are not notified
2236 if ( bWidth )
2238 ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
2239 if ( pModelObj && pModelObj->HasChangesListeners() )
2241 ScRangeList aChangeRanges;
2242 itr = pMarkData->begin();
2243 for (; itr != itrEnd; ++itr)
2245 nTab = *itr;
2246 const SCCOLROW* pTabRanges = pRanges;
2247 for ( SCCOLROW nRange = 0; nRange < nRangeCnt; ++nRange )
2249 SCCOL nStartCol = static_cast< SCCOL >( *(pTabRanges++) );
2250 SCCOL nEndCol = static_cast< SCCOL >( *(pTabRanges++) );
2251 for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
2253 aChangeRanges.Append( ScRange( nCol, 0, nTab ) );
2257 pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "column-resize" ) ), aChangeRanges );
2262 // column width/row height (via marked range)
2264 void ScViewFunc::SetMarkedWidthOrHeight( sal_Bool bWidth, ScSizeMode eMode, sal_uInt16 nSizeTwips,
2265 sal_Bool bRecord, sal_Bool bPaint )
2267 ScMarkData& rMark = GetViewData()->GetMarkData();
2269 rMark.MarkToMulti();
2270 if (!rMark.IsMultiMarked())
2272 SCCOL nCol = GetViewData()->GetCurX();
2273 SCROW nRow = GetViewData()->GetCurY();
2274 SCTAB nTab = GetViewData()->GetTabNo();
2275 DoneBlockMode();
2276 InitOwnBlockMode();
2277 rMark.SetMultiMarkArea( ScRange( nCol,nRow,nTab ), sal_True );
2278 MarkDataChanged();
2281 SCCOLROW* pRanges = new SCCOLROW[MAXCOLROWCOUNT];
2282 SCCOLROW nRangeCnt = 0;
2284 if ( bWidth )
2285 nRangeCnt = rMark.GetMarkColumnRanges( pRanges );
2286 else
2287 nRangeCnt = rMark.GetMarkRowRanges( pRanges );
2289 SetWidthOrHeight( bWidth, nRangeCnt, pRanges, eMode, nSizeTwips, bRecord, bPaint );
2291 delete[] pRanges;
2292 rMark.MarkToSimple();
2295 void ScViewFunc::ModifyCellSize( ScDirection eDir, sal_Bool bOptimal )
2297 //! step size adjustable
2298 // step size is also minumum
2299 sal_uInt16 nStepX = STD_COL_WIDTH / 5;
2300 sal_uInt16 nStepY = ScGlobal::nStdRowHeight;
2302 ScModule* pScMod = SC_MOD();
2303 sal_Bool bAnyEdit = pScMod->IsInputMode();
2304 SCCOL nCol = GetViewData()->GetCurX();
2305 SCROW nRow = GetViewData()->GetCurY();
2306 SCTAB nTab = GetViewData()->GetTabNo();
2307 ScDocShell* pDocSh = GetViewData()->GetDocShell();
2308 ScDocument* pDoc = pDocSh->GetDocument();
2310 bool bAllowed, bOnlyMatrix;
2311 if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2312 bAllowed = pDoc->IsBlockEditable( nTab, nCol,0, nCol,MAXROW, &bOnlyMatrix );
2313 else
2314 bAllowed = pDoc->IsBlockEditable( nTab, 0,nRow, MAXCOL,nRow, &bOnlyMatrix );
2315 if ( !bAllowed && !bOnlyMatrix )
2317 ErrorMessage(STR_PROTECTIONERR);
2318 return;
2321 HideAllCursors();
2323 sal_uInt16 nWidth = pDoc->GetColWidth( nCol, nTab );
2324 sal_uInt16 nHeight = pDoc->GetRowHeight( nRow, nTab );
2325 SCCOLROW nRange[2];
2326 if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2328 if (bOptimal) // width of this single cell
2330 if ( bAnyEdit )
2332 // when editing the actual entered width
2333 ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData()->GetViewShell() );
2334 if (pHdl)
2336 long nEdit = pHdl->GetTextSize().Width(); // in 0.01 mm
2338 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
2339 const SvxMarginItem& rMItem =
2340 (const SvxMarginItem&)pPattern->GetItem(ATTR_MARGIN);
2341 sal_uInt16 nMargin = rMItem.GetLeftMargin() + rMItem.GetRightMargin();
2342 if ( ((const SvxHorJustifyItem&) pPattern->
2343 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_LEFT )
2344 nMargin = sal::static_int_cast<sal_uInt16>(
2345 nMargin + ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue() );
2347 nWidth = (sal_uInt16)(nEdit * pDocSh->GetOutputFactor() / HMM_PER_TWIPS)
2348 + nMargin + STD_EXTRA_WIDTH;
2351 else
2353 double nPPTX = GetViewData()->GetPPTX();
2354 double nPPTY = GetViewData()->GetPPTY();
2355 Fraction aZoomX = GetViewData()->GetZoomX();
2356 Fraction aZoomY = GetViewData()->GetZoomY();
2358 ScSizeDeviceProvider aProv(pDocSh);
2359 if (aProv.IsPrinter())
2361 nPPTX = aProv.GetPPTX();
2362 nPPTY = aProv.GetPPTY();
2363 aZoomX = aZoomY = Fraction( 1, 1 );
2366 long nPixel = pDoc->GetNeededSize( nCol, nRow, nTab, aProv.GetDevice(),
2367 nPPTX, nPPTY, aZoomX, aZoomY, sal_True );
2368 sal_uInt16 nTwips = (sal_uInt16)( nPixel / nPPTX );
2369 if (nTwips != 0)
2370 nWidth = nTwips + STD_EXTRA_WIDTH;
2371 else
2372 nWidth = STD_COL_WIDTH;
2375 else // increment / decrement
2377 if ( eDir == DIR_RIGHT )
2378 nWidth = sal::static_int_cast<sal_uInt16>( nWidth + nStepX );
2379 else if ( nWidth > nStepX )
2380 nWidth = sal::static_int_cast<sal_uInt16>( nWidth - nStepX );
2381 if ( nWidth < nStepX ) nWidth = nStepX;
2382 if ( nWidth > MAX_COL_WIDTH ) nWidth = MAX_COL_WIDTH;
2384 nRange[0] = nRange[1] = nCol;
2385 SetWidthOrHeight( sal_True, 1, nRange, SC_SIZE_DIRECT, nWidth );
2387 // adjust height of this row if width demands/allows this
2389 if (!bAnyEdit)
2391 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
2392 sal_Bool bNeedHeight =
2393 ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue() ||
2394 ((const SvxHorJustifyItem&)pPattern->
2395 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK;
2396 if (bNeedHeight)
2397 AdjustRowHeight( nRow, nRow );
2400 else
2402 ScSizeMode eMode;
2403 if (bOptimal)
2405 eMode = SC_SIZE_OPTIMAL;
2406 nHeight = 0;
2408 else
2410 eMode = SC_SIZE_DIRECT;
2411 if ( eDir == DIR_BOTTOM )
2412 nHeight = sal::static_int_cast<sal_uInt16>( nHeight + nStepY );
2413 else if ( nHeight > nStepY )
2414 nHeight = sal::static_int_cast<sal_uInt16>( nHeight - nStepY );
2415 if ( nHeight < nStepY ) nHeight = nStepY;
2416 if ( nHeight > MAX_ROW_HEIGHT ) nHeight = MAX_ROW_HEIGHT;
2418 nRange[0] = nRange[1] = nRow;
2419 SetWidthOrHeight( false, 1, nRange, eMode, nHeight );
2422 if ( bAnyEdit )
2424 UpdateEditView();
2425 if ( pDoc->HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_NEEDHEIGHT ) )
2427 ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData()->GetViewShell() );
2428 if (pHdl)
2429 pHdl->SetModified(); // so that the height is adjusted with Enter
2433 ShowAllCursors();
2436 void ScViewFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
2438 if (nTab == TABLEID_DOC)
2439 return;
2441 ScMarkData& rMark = GetViewData()->GetMarkData();
2442 ScDocShell* pDocSh = GetViewData()->GetDocShell();
2443 ScDocument* pDoc = pDocSh->GetDocument();
2444 ScDocFunc &rFunc = pDocSh->GetDocFunc();
2445 bool bUndo(pDoc->IsUndoEnabled());
2447 // modifying several tabs is handled here
2449 if (bUndo)
2451 String aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
2452 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2455 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
2456 for (; itr != itrEnd; ++itr)
2457 rFunc.ProtectSheet(*itr, rProtect);
2459 if (bUndo)
2460 pDocSh->GetUndoManager()->LeaveListAction();
2462 UpdateLayerLocks(); //! broadcast to all views
2465 void ScViewFunc::Protect( SCTAB nTab, const String& rPassword )
2467 ScMarkData& rMark = GetViewData()->GetMarkData();
2468 ScDocShell* pDocSh = GetViewData()->GetDocShell();
2469 ScDocument* pDoc = pDocSh->GetDocument();
2470 ScDocFunc &rFunc = pDocSh->GetDocFunc();
2471 sal_Bool bUndo(pDoc->IsUndoEnabled());
2473 if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
2474 rFunc.Protect( nTab, rPassword, false );
2475 else
2477 // modifying several tabs is handled here
2479 if (bUndo)
2481 String aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
2482 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2485 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
2486 for (; itr != itrEnd; ++itr)
2487 rFunc.Protect( *itr, rPassword, false );
2489 if (bUndo)
2490 pDocSh->GetUndoManager()->LeaveListAction();
2493 UpdateLayerLocks(); //! broadcast to all views
2496 sal_Bool ScViewFunc::Unprotect( SCTAB nTab, const String& rPassword )
2498 ScMarkData& rMark = GetViewData()->GetMarkData();
2499 ScDocShell* pDocSh = GetViewData()->GetDocShell();
2500 ScDocument* pDoc = pDocSh->GetDocument();
2501 ScDocFunc &rFunc = pDocSh->GetDocFunc();
2502 sal_Bool bChanged = false;
2503 sal_Bool bUndo (pDoc->IsUndoEnabled());
2505 if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
2506 bChanged = rFunc.Unprotect( nTab, rPassword, false );
2507 else
2509 // modifying several tabs is handled here
2511 if (bUndo)
2513 String aUndo = ScGlobal::GetRscString( STR_UNDO_UNPROTECT_TAB );
2514 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2517 ScMarkData::iterator itr = rMark.begin(), itrEnd = rMark.end();
2518 for (; itr != itrEnd; ++itr)
2519 if ( rFunc.Unprotect( *itr, rPassword, false ) )
2520 bChanged = sal_True;
2522 if (bUndo)
2523 pDocSh->GetUndoManager()->LeaveListAction();
2526 if (bChanged)
2527 UpdateLayerLocks(); //! broadcast to all views
2529 return bChanged;
2532 void ScViewFunc::SetNoteText( const ScAddress& rPos, const String& rNoteText )
2534 GetViewData()->GetDocShell()->GetDocFunc().SetNoteText( rPos, rNoteText, false );
2537 void ScViewFunc::ReplaceNote( const ScAddress& rPos, const String& rNoteText, const String* pAuthor, const String* pDate )
2539 GetViewData()->GetDocShell()->GetDocFunc().ReplaceNote( rPos, rNoteText, pAuthor, pDate, false );
2542 void ScViewFunc::SetNumberFormat( short nFormatType, sal_uLong nAdd )
2544 // not editable because of matrix only? attribute OK nonetheless
2545 bool bOnlyNotBecauseOfMatrix;
2546 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2548 ErrorMessage(STR_PROTECTIONERR);
2549 return;
2552 sal_uInt32 nNumberFormat = 0;
2553 ScViewData* pViewData = GetViewData();
2554 ScDocument* pDoc = pViewData->GetDocument();
2555 SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
2556 LanguageType eLanguage = ScGlobal::eLnge;
2557 ScPatternAttr aNewAttrs( pDoc->GetPool() );
2559 // always take language from cursor position, even if there is a selection
2561 sal_uInt32 nCurrentNumberFormat;
2562 pDoc->GetNumberFormat( pViewData->GetCurX(),
2563 pViewData->GetCurY(),
2564 pViewData->GetTabNo(),
2565 nCurrentNumberFormat );
2566 const SvNumberformat* pEntry = pNumberFormatter->GetEntry( nCurrentNumberFormat );
2567 if (pEntry)
2568 eLanguage = pEntry->GetLanguage(); // else keep ScGlobal::eLnge
2570 nNumberFormat = pNumberFormatter->GetStandardFormat( nFormatType, eLanguage ) + nAdd;
2572 SfxItemSet& rSet = aNewAttrs.GetItemSet();
2573 rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2574 // ATTR_LANGUAGE_FORMAT not
2575 ApplySelectionPattern( aNewAttrs, sal_True );
2578 void ScViewFunc::SetNumFmtByStr( const String& rCode )
2580 // not editable because of matrix only? attribute OK nonetheless
2581 bool bOnlyNotBecauseOfMatrix;
2582 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2584 ErrorMessage(STR_PROTECTIONERR);
2585 return;
2588 ScViewData* pViewData = GetViewData();
2589 ScDocument* pDoc = pViewData->GetDocument();
2590 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
2592 // language always from cursor position
2594 sal_uInt32 nCurrentNumberFormat;
2595 pDoc->GetNumberFormat( pViewData->GetCurX(), pViewData->GetCurY(),
2596 pViewData->GetTabNo(), nCurrentNumberFormat );
2597 const SvNumberformat* pEntry = pFormatter->GetEntry( nCurrentNumberFormat );
2598 LanguageType eLanguage = pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge;
2600 // determine index for String
2602 sal_Bool bOk = sal_True;
2603 sal_uInt32 nNumberFormat = pFormatter->GetEntryKey( rCode, eLanguage );
2604 if ( nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
2606 // enter new
2608 OUString aFormat = rCode; // will be changed
2609 sal_Int32 nErrPos = 0;
2610 short nType = 0; //! ???
2611 bOk = pFormatter->PutEntry( aFormat, nErrPos, nType, nNumberFormat, eLanguage );
2614 if ( bOk ) // valid format?
2616 ScPatternAttr aNewAttrs( pDoc->GetPool() );
2617 SfxItemSet& rSet = aNewAttrs.GetItemSet();
2618 rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2619 rSet.Put( SvxLanguageItem( eLanguage, ATTR_LANGUAGE_FORMAT ) );
2620 ApplySelectionPattern( aNewAttrs, sal_True );
2623 //! else return error / issue warning ???
2626 void ScViewFunc::ChangeNumFmtDecimals( sal_Bool bIncrement )
2628 // not editable because of matrix only? attribute OK nonetheless
2629 bool bOnlyNotBecauseOfMatrix;
2630 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2632 ErrorMessage(STR_PROTECTIONERR);
2633 return;
2636 ScDocument* pDoc = GetViewData()->GetDocument();
2637 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
2639 SCCOL nCol = GetViewData()->GetCurX();
2640 SCROW nRow = GetViewData()->GetCurY();
2641 SCTAB nTab = GetViewData()->GetTabNo();
2643 sal_uInt32 nOldFormat;
2644 pDoc->GetNumberFormat( nCol, nRow, nTab, nOldFormat );
2645 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
2646 if (!pOldEntry)
2648 OSL_FAIL("numberformat not found !!!");
2649 return;
2652 // what have we got here?
2654 sal_uInt32 nNewFormat = nOldFormat;
2655 sal_Bool bError = false;
2657 LanguageType eLanguage = pOldEntry->GetLanguage();
2658 bool bThousand, bNegRed;
2659 sal_uInt16 nPrecision, nLeading;
2660 pOldEntry->GetFormatSpecialInfo( bThousand, bNegRed, nPrecision, nLeading );
2662 short nOldType = pOldEntry->GetType();
2663 if ( 0 == ( nOldType & (
2664 NUMBERFORMAT_NUMBER | NUMBERFORMAT_CURRENCY | NUMBERFORMAT_PERCENT ) ) )
2666 // date, time, fraction, logical, text can not be changed
2667 //! in case of scientific the Numberformatter also can't
2668 bError = sal_True;
2671 //! SvNumberformat has a Member bStandard, but doesn't disclose it
2672 sal_Bool bWasStandard = ( nOldFormat == pFormatter->GetStandardIndex( eLanguage ) );
2673 if (bWasStandard)
2675 // with "Standard" the decimal places depend on cell content
2676 // 0 if empty or text -> no decimal places
2677 double nVal = pDoc->GetValue( ScAddress( nCol, nRow, nTab ) );
2679 // the ways of the Numberformatters are unfathomable, so try:
2680 OUString aOut;
2681 Color* pCol;
2682 ((SvNumberformat*)pOldEntry)->GetOutputString( nVal, aOut, &pCol );
2684 nPrecision = 0;
2685 // 'E' for exponential is fixed in Numberformatter
2686 if ( aOut.indexOf((sal_Unicode)'E') >= 0 )
2687 bError = sal_True; // exponential not changed
2688 else
2690 OUString aDecSep( pFormatter->GetFormatDecimalSep( nOldFormat ) );
2691 sal_Int32 nPos = aOut.indexOf( aDecSep );
2692 if ( nPos >= 0 )
2693 nPrecision = aOut.getLength() - nPos - aDecSep.getLength();
2694 // else keep 0
2698 if (!bError)
2700 if (bIncrement)
2702 if (nPrecision<20)
2703 ++nPrecision; // increment
2704 else
2705 bError = sal_True; // 20 is maximum
2707 else
2709 if (nPrecision)
2710 --nPrecision; // decrement
2711 else
2712 bError = sal_True; // 0 is minumum
2716 if (!bError)
2718 OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLanguage,
2719 bThousand, bNegRed,
2720 nPrecision, nLeading);
2722 nNewFormat = pFormatter->GetEntryKey( aNewPicture, eLanguage );
2723 if ( nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
2725 sal_Int32 nErrPos = 0;
2726 short nNewType = 0;
2727 sal_Bool bOk = pFormatter->PutEntry( aNewPicture, nErrPos,
2728 nNewType, nNewFormat, eLanguage );
2729 OSL_ENSURE( bOk, "incorrect numberformat generated" );
2730 if (!bOk)
2731 bError = sal_True;
2735 if (!bError)
2737 ScPatternAttr aNewAttrs( pDoc->GetPool() );
2738 SfxItemSet& rSet = aNewAttrs.GetItemSet();
2739 rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
2740 // ATTR_LANGUAGE_FORMAT not
2741 ApplySelectionPattern( aNewAttrs, sal_True );
2745 void ScViewFunc::ChangeIndent( sal_Bool bIncrement )
2747 ScViewData* pViewData = GetViewData();
2748 ScDocShell* pDocSh = pViewData->GetDocShell();
2749 ScMarkData& rMark = pViewData->GetMarkData();
2751 ScMarkData aWorkMark = rMark;
2752 ScViewUtil::UnmarkFiltered( aWorkMark, pDocSh->GetDocument() );
2753 aWorkMark.MarkToMulti();
2754 if (!aWorkMark.IsMultiMarked())
2756 SCCOL nCol = pViewData->GetCurX();
2757 SCROW nRow = pViewData->GetCurY();
2758 SCTAB nTab = pViewData->GetTabNo();
2759 aWorkMark.SetMultiMarkArea( ScRange(nCol,nRow,nTab) );
2762 sal_Bool bSuccess = pDocSh->GetDocFunc().ChangeIndent( aWorkMark, bIncrement, false );
2763 if (bSuccess)
2765 pDocSh->UpdateOle(pViewData);
2766 StartFormatArea();
2770 sal_Bool ScViewFunc::InsertName( const String& rName, const String& rSymbol,
2771 const String& rType )
2773 // Type = P,R,C,F (and combinations)
2774 //! undo...
2776 sal_Bool bOk = false;
2777 ScDocShell* pDocSh = GetViewData()->GetDocShell();
2778 ScDocument* pDoc = pDocSh->GetDocument();
2779 SCTAB nTab = GetViewData()->GetTabNo();
2780 ScRangeName* pList = pDoc->GetRangeName();
2782 RangeType nType = RT_NAME;
2783 ScRangeData* pNewEntry = new ScRangeData( pDoc, rName, rSymbol,
2784 ScAddress( GetViewData()->GetCurX(), GetViewData()->GetCurY(),
2785 nTab), nType );
2786 String aUpType = rType;
2787 aUpType.ToUpperAscii();
2788 if ( aUpType.Search( 'P' ) != STRING_NOTFOUND )
2789 nType |= RT_PRINTAREA;
2790 if ( aUpType.Search( 'R' ) != STRING_NOTFOUND )
2791 nType |= RT_ROWHEADER;
2792 if ( aUpType.Search( 'C' ) != STRING_NOTFOUND )
2793 nType |= RT_COLHEADER;
2794 if ( aUpType.Search( 'F' ) != STRING_NOTFOUND )
2795 nType |= RT_CRITERIA;
2796 pNewEntry->AddType(nType);
2798 if ( !pNewEntry->GetErrCode() ) // text valid?
2800 ScDocShellModificator aModificator( *pDocSh );
2802 pDoc->CompileNameFormula( sal_True ); // CreateFormulaString
2804 // input available yet? Then remove beforehand (=change)
2805 ScRangeData* pData = pList->findByUpperName(ScGlobal::pCharClass->uppercase(rName));
2806 if (pData)
2807 { // take old Index
2808 pNewEntry->SetIndex(pData->GetIndex());
2809 pList->erase(*pData);
2812 if ( pList->insert( pNewEntry ) )
2813 bOk = sal_True;
2814 pNewEntry = NULL; // never delete, insert took ownership
2816 pDoc->CompileNameFormula( false ); // CompileFormulaString
2817 aModificator.SetDocumentModified();
2818 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
2821 delete pNewEntry; // if it wasn't inserted
2822 return bOk;
2825 void ScViewFunc::CreateNames( sal_uInt16 nFlags )
2827 sal_Bool bDone = false;
2828 ScRange aRange;
2829 if ( GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE )
2830 bDone = GetViewData()->GetDocShell()->GetDocFunc().CreateNames( aRange, nFlags, false );
2832 if (!bDone)
2833 ErrorMessage(STR_CREATENAME_MARKERR);
2836 sal_uInt16 ScViewFunc::GetCreateNameFlags()
2838 sal_uInt16 nFlags = 0;
2840 SCCOL nStartCol, nEndCol;
2841 SCROW nStartRow, nEndRow;
2842 SCTAB nDummy;
2843 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nDummy,nEndCol,nEndRow,nDummy) == SC_MARK_SIMPLE)
2845 ScDocument* pDoc = GetViewData()->GetDocument();
2846 SCTAB nTab = GetViewData()->GetTabNo();
2847 sal_Bool bOk;
2848 SCCOL i;
2849 SCROW j;
2851 bOk = sal_True;
2852 SCCOL nFirstCol = nStartCol;
2853 SCCOL nLastCol = nEndCol;
2854 if (nStartCol+1 < nEndCol) { ++nFirstCol; --nLastCol; }
2855 for (i=nFirstCol; i<=nLastCol && bOk; i++)
2856 if (!pDoc->HasStringData( i,nStartRow,nTab ))
2857 bOk = false;
2858 if (bOk)
2859 nFlags |= NAME_TOP;
2860 else // Bottom only if not Top
2862 bOk = sal_True;
2863 for (i=nFirstCol; i<=nLastCol && bOk; i++)
2864 if (!pDoc->HasStringData( i,nEndRow,nTab ))
2865 bOk = false;
2866 if (bOk)
2867 nFlags |= NAME_BOTTOM;
2870 bOk = sal_True;
2871 SCROW nFirstRow = nStartRow;
2872 SCROW nLastRow = nEndRow;
2873 if (nStartRow+1 < nEndRow) { ++nFirstRow; --nLastRow; }
2874 for (j=nFirstRow; j<=nLastRow && bOk; j++)
2875 if (!pDoc->HasStringData( nStartCol,j,nTab ))
2876 bOk = false;
2877 if (bOk)
2878 nFlags |= NAME_LEFT;
2879 else // Right only if not Left
2881 bOk = sal_True;
2882 for (j=nFirstRow; j<=nLastRow && bOk; j++)
2883 if (!pDoc->HasStringData( nEndCol,j,nTab ))
2884 bOk = false;
2885 if (bOk)
2886 nFlags |= NAME_RIGHT;
2890 if (nStartCol == nEndCol)
2891 nFlags &= ~( NAME_LEFT | NAME_RIGHT );
2892 if (nStartRow == nEndRow)
2893 nFlags &= ~( NAME_TOP | NAME_BOTTOM );
2895 return nFlags;
2898 void ScViewFunc::InsertNameList()
2900 ScAddress aPos( GetViewData()->GetCurX(), GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
2901 ScDocShell* pDocSh = GetViewData()->GetDocShell();
2902 if ( pDocSh->GetDocFunc().InsertNameList( aPos, false ) )
2903 pDocSh->UpdateOle(GetViewData());
2909 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */