xref: /trunk/main/sc/source/ui/view/viewfunc.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 //------------------------------------------------------------------
34 
35 // INCLUDE ---------------------------------------------------------------
36 
37 #include "scitems.hxx"
38 #include <editeng/eeitem.hxx>
39 
40 #include <sfx2/app.hxx>
41 #include <svx/algitem.hxx>
42 #include <editeng/boxitem.hxx>
43 #include <editeng/editobj.hxx>
44 #include <editeng/editview.hxx>
45 #include <editeng/langitem.hxx>
46 #include <editeng/scripttypeitem.hxx>
47 #include <sfx2/bindings.hxx>
48 #include <svl/zforlist.hxx>
49 #include <svl/zformat.hxx>
50 #include <vcl/msgbox.hxx>
51 #include <vcl/sound.hxx>
52 #include <vcl/virdev.hxx>
53 #include <vcl/waitobj.hxx>
54 #include <vcl/wrkwin.hxx>
55 #include <stdlib.h>             // qsort
56 
57 #include "viewfunc.hxx"
58 #include "tabvwsh.hxx"
59 #include "docsh.hxx"
60 #include "attrib.hxx"
61 #include "patattr.hxx"
62 #include "docpool.hxx"
63 #include "uiitems.hxx"
64 #include "sc.hrc"
65 #include "undocell.hxx"
66 #include "undoblk.hxx"
67 #include "undotab.hxx"
68 #include "refundo.hxx"
69 #include "dbcolect.hxx"
70 #include "olinetab.hxx"
71 #include "rangeutl.hxx"
72 #include "rangenam.hxx"
73 #include "globstr.hrc"
74 #include "global.hxx"
75 #include "stlsheet.hxx"
76 #include "editutil.hxx"
77 //CHINA001 #include "namecrea.hxx"          // wegen Flags
78 #include "cell.hxx"
79 #include "scresid.hxx"
80 #include "inputhdl.hxx"
81 #include "scmod.hxx"
82 #include "inputopt.hxx"
83 #include "compiler.hxx"
84 #include "docfunc.hxx"
85 #include "appoptio.hxx"
86 #include "dociter.hxx"
87 #include "sizedev.hxx"
88 #include "editable.hxx"
89 #include "scui_def.hxx" //CHINA001
90 #include "funcdesc.hxx"
91 #include "docuno.hxx"
92 #include "cellsuno.hxx"
93 //==================================================================
94 
95 ScViewFunc::ScViewFunc( Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
96     ScTabView( pParent, rDocSh, pViewShell ),
97     bFormatValid( sal_False )
98 {
99 }
100 
101 //UNUSED2008-05  ScViewFunc::ScViewFunc( Window* pParent, const ScViewFunc& rViewFunc, ScTabViewShell* pViewShell ) :
102 //UNUSED2008-05      ScTabView( pParent, rViewFunc, pViewShell ),
103 //UNUSED2008-05      bFormatValid( sal_False )
104 //UNUSED2008-05  {
105 //UNUSED2008-05  }
106 
107 ScViewFunc::~ScViewFunc()
108 {
109 }
110 
111 //------------------------------------------------------------------------------------
112 
113 void ScViewFunc::StartFormatArea()
114 {
115     //  ueberhaupt aktiviert?
116     if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
117         return;
118 
119     //  start only with single cell (marked or cursor position)
120     ScRange aMarkRange;
121     sal_Bool bOk = (GetViewData()->GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE);
122     if ( bOk && aMarkRange.aStart != aMarkRange.aEnd )
123         bOk = sal_False;
124 
125     if (bOk)
126     {
127         bFormatValid = sal_True;
128         aFormatSource = aMarkRange.aStart;
129         aFormatArea = ScRange( aFormatSource );
130     }
131     else
132         bFormatValid = sal_False;       // keinen alten Bereich behalten
133 }
134 
135 sal_Bool ScViewFunc::TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_Bool bAttrChanged )
136 {
137     //  ueberhaupt aktiviert?
138     if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
139         return sal_False;
140 
141     //  Test: Eingabe mit Zahlformat (bAttrChanged) immer als neue Attributierung behandeln
142     //  (alte Area verwerfen). Wenn das nicht gewollt ist, den if-Teil weglassen:
143     if ( bAttrChanged )
144     {
145         StartFormatArea();
146         return sal_False;
147     }
148 
149     //! Abfrage, ob Zelle leer war ???
150 
151     sal_Bool bFound = sal_False;
152     ScRange aNewRange = aFormatArea;
153     if ( bFormatValid && nTab == aFormatSource.Tab() )
154     {
155         if ( nRow >= aFormatArea.aStart.Row() && nRow <= aFormatArea.aEnd.Row() )
156         {
157             //  innerhalb ?
158             if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
159             {
160                 bFound = sal_True;          // Bereich nicht aendern
161             }
162             //  links ?
163             if ( nCol+1 == aFormatArea.aStart.Col() )
164             {
165                 bFound = sal_True;
166                 aNewRange.aStart.SetCol( nCol );
167             }
168             //  rechts ?
169             if ( nCol == aFormatArea.aEnd.Col()+1 )
170             {
171                 bFound = sal_True;
172                 aNewRange.aEnd.SetCol( nCol );
173             }
174         }
175         if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
176         {
177             //  oben ?
178             if ( nRow+1 == aFormatArea.aStart.Row() )
179             {
180                 bFound = sal_True;
181                 aNewRange.aStart.SetRow( nRow );
182             }
183             //  unten ?
184             if ( nRow == aFormatArea.aEnd.Row()+1 )
185             {
186                 bFound = sal_True;
187                 aNewRange.aEnd.SetRow( nRow );
188             }
189         }
190     }
191 
192     if (bFound)
193         aFormatArea = aNewRange;    // erweitern
194     else
195     {
196         bFormatValid = sal_False;       // ausserhalb -> abbrechen
197         if ( bAttrChanged )         // Wert mit Zahlformat eingegeben?
198             StartFormatArea();      // dann ggf. neu starten
199     }
200 
201     return bFound;
202 }
203 
204 void ScViewFunc::DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
205                                     sal_Bool bAttrChanged, sal_Bool bAddUndo )
206 {
207     ScDocShell* pDocSh = GetViewData()->GetDocShell();
208     ScDocument* pDoc = pDocSh->GetDocument();
209     if (bAddUndo && !pDoc->IsUndoEnabled())
210         bAddUndo = sal_False;
211 
212     const ScPatternAttr* pSource = pDoc->GetPattern(
213                             aFormatSource.Col(), aFormatSource.Row(), nTab );
214     if ( !((const ScMergeAttr&)pSource->GetItem(ATTR_MERGE)).IsMerged() )
215     {
216         const ScPatternAttr* pDocOld = pDoc->GetPattern( nCol, nRow, nTab );
217         //  pDocOld ist nur bis zum Apply... gueltig!
218 
219         ScPatternAttr* pOldPattern = NULL;
220         if ( bAddUndo )
221             pOldPattern = new ScPatternAttr( *pDocOld );
222 
223         const ScStyleSheet* pSrcStyle = pSource->GetStyleSheet();
224         if ( pSrcStyle && pSrcStyle != pDocOld->GetStyleSheet() )
225             pDoc->ApplyStyle( nCol, nRow, nTab, *pSrcStyle );
226         pDoc->ApplyPattern( nCol, nRow, nTab, *pSource );
227         AdjustRowHeight( nRow, nRow, sal_True );                //! nicht doppelt ?
228 
229         if ( bAddUndo )
230         {
231             const ScPatternAttr* pNewPattern = pDoc->GetPattern( nCol, nRow, nTab );
232 
233             pDocSh->GetUndoManager()->AddUndoAction(
234                         new ScUndoCursorAttr( pDocSh, nCol, nRow, nTab,
235                                               pOldPattern, pNewPattern, pSource,
236                                               sal_True ) );
237 
238             delete pOldPattern;     // wird im Undo kopiert (Pool)
239         }
240     }
241 
242     if ( bAttrChanged )                             // Wert mit Zahlformat eingegeben?
243         aFormatSource.Set( nCol, nRow, nTab );      // dann als neue Quelle
244 }
245 
246 //------------------------------------------------------------------------------------
247 
248 //      Hilfsroutinen
249 
250 sal_uInt16 ScViewFunc::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, sal_Bool bFormula )
251 {
252     ScDocShell* pDocSh = GetViewData()->GetDocShell();
253     ScDocument* pDoc = pDocSh->GetDocument();
254     ScMarkData& rMark = GetViewData()->GetMarkData();
255 
256     double nPPTX = GetViewData()->GetPPTX();
257     double nPPTY = GetViewData()->GetPPTY();
258     Fraction aZoomX = GetViewData()->GetZoomX();
259     Fraction aZoomY = GetViewData()->GetZoomY();
260 
261     ScSizeDeviceProvider aProv(pDocSh);
262     if (aProv.IsPrinter())
263     {
264         nPPTX = aProv.GetPPTX();
265         nPPTY = aProv.GetPPTY();
266         aZoomX = aZoomY = Fraction( 1, 1 );
267     }
268 
269     sal_uInt16 nTwips = pDoc->GetOptimalColWidth( nCol, nTab, aProv.GetDevice(),
270                                 nPPTX, nPPTY, aZoomX, aZoomY, bFormula, &rMark );
271     return nTwips;
272 }
273 
274 sal_Bool ScViewFunc::SelectionEditable( sal_Bool* pOnlyNotBecauseOfMatrix /* = NULL */ )
275 {
276     sal_Bool bRet;
277     ScDocument* pDoc = GetViewData()->GetDocument();
278     ScMarkData& rMark = GetViewData()->GetMarkData();
279     if (rMark.IsMarked() || rMark.IsMultiMarked())
280         bRet = pDoc->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix );
281     else
282     {
283         SCCOL nCol = GetViewData()->GetCurX();
284         SCROW nRow = GetViewData()->GetCurY();
285         SCTAB nTab = GetViewData()->GetTabNo();
286         bRet = pDoc->IsBlockEditable( nTab, nCol, nRow, nCol, nRow,
287             pOnlyNotBecauseOfMatrix );
288     }
289     return bRet;
290 }
291 
292 #ifndef LRU_MAX
293 #define LRU_MAX 10
294 #endif
295 
296 sal_Bool lcl_FunctionKnown( sal_uInt16 nOpCode )
297 {
298     const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
299     if ( pFuncList )
300     {
301         sal_uLong nCount = pFuncList->GetCount();
302         for (sal_uLong i=0; i<nCount; i++)
303             if ( pFuncList->GetFunction(i)->nFIndex == nOpCode )
304                 return sal_True;
305     }
306     return sal_False;
307 }
308 
309 sal_Bool lcl_AddFunction( ScAppOptions& rAppOpt, sal_uInt16 nOpCode )
310 {
311     sal_uInt16 nOldCount = rAppOpt.GetLRUFuncListCount();
312     sal_uInt16* pOldList = rAppOpt.GetLRUFuncList();
313     sal_uInt16 nPos;
314     for (nPos=0; nPos<nOldCount; nPos++)
315         if (pOldList[nPos] == nOpCode)          // is the function already in the list?
316         {
317             if ( nPos == 0 )
318                 return sal_False;                   // already at the top -> no change
319 
320             //  count doesn't change, so the original array is modified
321 
322             for (sal_uInt16 nCopy=nPos; nCopy>0; nCopy--)
323                 pOldList[nCopy] = pOldList[nCopy-1];
324             pOldList[0] = nOpCode;
325 
326             return sal_True;                        // list has changed
327         }
328 
329     if ( !lcl_FunctionKnown( nOpCode ) )
330         return sal_False;                           // not in function list -> no change
331 
332     sal_uInt16 nNewCount = Min( (sal_uInt16)(nOldCount + 1), (sal_uInt16)LRU_MAX );
333     sal_uInt16 nNewList[LRU_MAX];
334     nNewList[0] = nOpCode;
335     for (nPos=1; nPos<nNewCount; nPos++)
336         nNewList[nPos] = pOldList[nPos-1];
337     rAppOpt.SetLRUFuncList( nNewList, nNewCount );
338 
339     return sal_True;                                // list has changed
340 }
341 
342 //      eigentliche Funktionen
343 
344 //  Eingabe - Undo OK
345 
346 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
347                             sal_Bool bRecord, const EditTextObject* pData )
348 {
349     ScDocument* pDoc = GetViewData()->GetDocument();
350     ScMarkData& rMark = GetViewData()->GetMarkData();
351     SCTAB nTabCount = pDoc->GetTableCount();
352     SCTAB nSelCount = rMark.GetSelectCount();
353     SCTAB i;
354     if (bRecord && !pDoc->IsUndoEnabled())
355         bRecord = sal_False;
356 
357     ScDocShell* pDocSh = GetViewData()->GetDocShell();
358     ScDocShellModificator aModificator( *pDocSh );
359 
360     ScEditableTester aTester( pDoc, nCol,nRow, nCol,nRow, rMark );
361     if (aTester.IsEditable())
362     {
363         sal_Bool bEditDeleted = sal_False;
364         sal_uInt8 nOldScript = 0;
365 
366         ScBaseCell** ppOldCells = NULL;
367         sal_Bool* pHasFormat        = NULL;
368         sal_uLong* pOldFormats      = NULL;
369         SCTAB* pTabs            = NULL;
370         SCTAB nUndoPos = 0;
371         EditTextObject* pUndoData = NULL;
372         if ( bRecord )
373         {
374             ppOldCells      = new ScBaseCell*[nSelCount];
375             pHasFormat      = new sal_Bool[nSelCount];
376             pOldFormats     = new sal_uLong[nSelCount];
377             pTabs           = new SCTAB[nSelCount];
378             nUndoPos = 0;
379 
380             for (i=0; i<nTabCount; i++)
381                 if (rMark.GetTableSelect(i))
382                 {
383                     pTabs[nUndoPos] = i;
384                     ScBaseCell* pDocCell;
385                     pDoc->GetCell( nCol, nRow, i, pDocCell );
386                     if ( pDocCell )
387                     {
388                         ppOldCells[nUndoPos] = pDocCell->CloneWithoutNote( *pDoc );
389                         if ( pDocCell->GetCellType() == CELLTYPE_EDIT )
390                             bEditDeleted = sal_True;
391 
392                         sal_uInt8 nDocScript = pDoc->GetScriptType( nCol, nRow, i, pDocCell );
393                         if ( nOldScript == 0 )
394                             nOldScript = nDocScript;
395                         else if ( nDocScript != nOldScript )
396                             bEditDeleted = sal_True;
397                     }
398                     else
399                     {
400                         ppOldCells[nUndoPos] = NULL;
401                     }
402 
403                     const SfxPoolItem* pItem;
404                     const ScPatternAttr* pPattern = pDoc->GetPattern(nCol, nRow, i);
405                     if ( SFX_ITEM_SET == pPattern->GetItemSet().GetItemState(
406                                             ATTR_VALUE_FORMAT,sal_False,&pItem) )
407                     {
408                         pHasFormat[nUndoPos] = sal_True;
409                         pOldFormats[nUndoPos] = ((const SfxUInt32Item*)pItem)->GetValue();
410                     }
411                     else
412                         pHasFormat[nUndoPos] = sal_False;
413 
414                     ++nUndoPos;
415                 }
416 
417             DBG_ASSERT( nUndoPos==nSelCount, "nUndoPos!=nSelCount" );
418 
419             pUndoData = ( pData ? pData->Clone() : NULL );
420         }
421 
422         bool bFormula = false;
423 
424         // a single '=' character is handled as string (needed for special filters)
425         if ( rString.Len() > 1 )
426         {
427             if ( rString.GetChar(0) == '=' )
428             {
429                 // handle as formula
430                 bFormula = true;
431             }
432             else if ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' )
433             {
434                 // if there is more than one leading '+' or '-' character, remove the additional ones
435                 String aString( rString );
436                 xub_StrLen nIndex = 1;
437                 xub_StrLen nLen = aString.Len();
438                 while ( nIndex < nLen && ( aString.GetChar( nIndex ) == '+' || aString.GetChar( nIndex ) == '-' ) )
439                 {
440                     ++nIndex;
441                 }
442                 aString.Erase( 1, nIndex - 1 );
443 
444                 // if the remaining part without the leading '+' or '-' character
445                 // is non-empty and not a number, handle as formula
446                 if ( aString.Len() > 1 )
447                 {
448                     sal_uInt32 nFormat = 0;
449                     pDoc->GetNumberFormat( nCol, nRow, nTab, nFormat );
450                     SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
451                     double fNumber = 0;
452                     if ( !pFormatter->IsNumberFormat( aString, nFormat, fNumber ) )
453                     {
454                         bFormula = true;
455                     }
456                 }
457             }
458         }
459 
460         sal_Bool bNumFmtChanged = sal_False;
461         if ( bFormula )
462         {   // Formel, compile mit AutoCorrection
463             for (i=0; i<nTabCount; i++)
464                 if (rMark.GetTableSelect(i))
465                     break;
466             ScAddress aPos( nCol, nRow, i );
467             ScCompiler aComp( pDoc, aPos);
468             aComp.SetGrammar(pDoc->GetGrammar());
469 //2do: AutoCorrection via CalcOptions abschaltbar machen
470             aComp.SetAutoCorrection( sal_True );
471             if ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' )
472             {
473                 aComp.SetExtendedErrorDetection( true );
474             }
475             String aFormula( rString );
476             ScTokenArray* pArr;
477             sal_Bool bAgain;
478             do
479             {
480                 bAgain = sal_False;
481                 sal_Bool bAddEqual = sal_False;
482                 ScTokenArray* pArrFirst = pArr = aComp.CompileString( aFormula );
483                 sal_Bool bCorrected = aComp.IsCorrected();
484                 if ( bCorrected )
485                 {   // probieren, mit erster Parser-Korrektur neu zu parsen
486                     pArr = aComp.CompileString( aComp.GetCorrectedFormula() );
487                 }
488                 if ( !pArr->GetCodeError() )
489                 {
490                     bAddEqual = sal_True;
491                     aComp.CompileTokenArray();
492                     bCorrected |= aComp.IsCorrected();
493                 }
494                 if ( bCorrected )
495                 {
496                     String aCorrectedFormula;
497                     if ( bAddEqual )
498                     {
499                         aCorrectedFormula = '=';
500                         aCorrectedFormula += aComp.GetCorrectedFormula();
501                     }
502                     else
503                         aCorrectedFormula = aComp.GetCorrectedFormula();
504                     short nResult;
505                     if ( aCorrectedFormula.Len() == 1 )
506                         nResult = RET_NO;   // leere Formel, nur '='
507                     else
508                     {
509                         String aMessage( ScResId( SCSTR_FORMULA_AUTOCORRECTION ) );
510                         aMessage += aCorrectedFormula;
511                         nResult = QueryBox( GetViewData()->GetDialogParent(),
512                                                 WinBits(WB_YES_NO | WB_DEF_YES),
513                                                 aMessage ).Execute();
514                     }
515                     if ( nResult == RET_YES )
516                     {
517                         aFormula = aCorrectedFormula;
518                         if ( pArr != pArrFirst )
519                             delete pArrFirst;
520                         bAgain = sal_True;
521                     }
522                     else
523                     {
524                         if ( pArr != pArrFirst )
525                         {
526                             delete pArr;
527                             pArr = pArrFirst;
528                         }
529                     }
530                 }
531             } while ( bAgain );
532             // um in mehreren Tabellen eingesetzt zu werden, muss die Formel
533             // via ScFormulaCell copy-ctor evtl. wegen RangeNames neu kompiliert
534             // werden, gleiches Code-Array fuer alle Zellen geht nicht.
535             // Wenn das Array einen Fehler enthaelt, muss in den neu erzeugten
536             // Zellen RPN geloescht und der Fehler explizit gesetzt werden, da
537             // via FormulaCell copy-ctor und Interpreter das, wenn moeglich,
538             // wieder glattgebuegelt wird, zu intelligent.. z.B.: =1))
539             sal_uInt16 nError = pArr->GetCodeError();
540             if ( !nError )
541             {
542                 //  #68693# update list of recent functions with all functions that
543                 //  are not within parentheses
544 
545                 ScModule* pScMod = SC_MOD();
546                 ScAppOptions aAppOpt = pScMod->GetAppOptions();
547                 sal_Bool bOptChanged = sal_False;
548 
549                 formula::FormulaToken** ppToken = pArr->GetArray();
550                 sal_uInt16 nTokens = pArr->GetLen();
551                 sal_uInt16 nLevel = 0;
552                 for (sal_uInt16 nTP=0; nTP<nTokens; nTP++)
553                 {
554                     formula::FormulaToken* pTok = ppToken[nTP];
555                     OpCode eOp = pTok->GetOpCode();
556                     if ( eOp == ocOpen )
557                         ++nLevel;
558                     else if ( eOp == ocClose && nLevel )
559                         --nLevel;
560                     if ( nLevel == 0 && pTok->IsFunction() &&
561                             lcl_AddFunction( aAppOpt, sal::static_int_cast<sal_uInt16>( eOp ) ) )
562                         bOptChanged = sal_True;
563                 }
564 
565                 if ( bOptChanged )
566                 {
567                     pScMod->SetAppOptions(aAppOpt);
568                     pScMod->RecentFunctionsChanged();
569                 }
570             }
571 
572             ScFormulaCell aCell( pDoc, aPos, pArr,formula::FormulaGrammar::GRAM_DEFAULT, MM_NONE );
573             delete pArr;
574             sal_Bool bAutoCalc = pDoc->GetAutoCalc();
575             SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
576             for ( ; i<nTabCount; i++)
577             {
578                 if (rMark.GetTableSelect(i))
579                 {
580                     aPos.SetTab( i );
581                     sal_uLong nIndex = (sal_uLong) ((SfxUInt32Item*) pDoc->GetAttr(
582                         nCol, nRow, i, ATTR_VALUE_FORMAT ))->GetValue();
583                     if ( pFormatter->GetType( nIndex ) == NUMBERFORMAT_TEXT ||
584                          ( ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' ) && nError && rString.Equals( aFormula ) ) )
585                     {
586                         if ( pData )
587                         {
588                             ScEditCell* pCell = new ScEditCell( pData, pDoc, NULL );
589                             pDoc->PutCell( aPos, pCell );
590                         }
591                         else
592                         {
593                             ScStringCell* pCell = new ScStringCell( aFormula );
594                             pDoc->PutCell( aPos, pCell );
595                         }
596                     }
597                     else
598                     {
599                         DELETEZ(pUndoData);
600                         ScFormulaCell* pCell = new ScFormulaCell( aCell, *pDoc, aPos );
601                         if ( nError )
602                         {
603                             pCell->GetCode()->DelRPN();
604                             pCell->SetErrCode( nError );
605                             if(pCell->GetCode()->IsHyperLink())
606                                 pCell->GetCode()->SetHyperLink(sal_False);
607                         }
608                         pDoc->PutCell( aPos, pCell );
609                         if ( !bAutoCalc )
610                         {   // einmal nur die Zelle berechnen und wieder dirty setzen
611                             pCell->Interpret();
612                             pCell->SetDirtyVar();
613                             pDoc->PutInFormulaTree( pCell );
614                         }
615                     }
616 
617                 }
618             }
619         }
620         else
621         {
622             for (i=0; i<nTabCount; i++)
623                 if (rMark.GetTableSelect(i))
624                     if (pDoc->SetString( nCol, nRow, i, rString ))
625                         bNumFmtChanged = sal_True;
626         }
627 
628         //  row height must be changed if new text has a different script type
629         for (i=0; i<nTabCount && !bEditDeleted; i++)
630             if (rMark.GetTableSelect(i))
631                 if ( pDoc->GetScriptType( nCol, nRow, i ) != nOldScript )
632                     bEditDeleted = sal_True;
633 
634         HideAllCursors();
635 
636         if (bEditDeleted || pDoc->HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_NEEDHEIGHT ))
637             AdjustRowHeight(nRow,nRow);
638 
639         sal_Bool bAutoFormat = TestFormatArea(nCol, nRow, nTab, bNumFmtChanged);
640         if (bAutoFormat)
641             DoAutoAttributes(nCol, nRow, nTab, bNumFmtChanged, bRecord);
642 
643         if ( bRecord )
644         {   // wg. ChangeTrack erst jetzt
645             pDocSh->GetUndoManager()->AddUndoAction(
646                 new ScUndoEnterData( pDocSh, nCol, nRow, nTab, nUndoPos, pTabs,
647                                      ppOldCells, pHasFormat, pOldFormats,
648                                      rString, pUndoData ) );
649         }
650 
651         for (i=0; i<nTabCount; i++)
652             if (rMark.GetTableSelect(i))
653                 pDocSh->PostPaintCell( nCol, nRow, i );
654 
655         ShowAllCursors();
656 
657         pDocSh->UpdateOle(GetViewData());
658 
659         // #i97876# Spreadsheet data changes are not notified
660         ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
661         if ( pModelObj && pModelObj->HasChangesListeners() )
662         {
663             ScRangeList aChangeRanges;
664             for ( i = 0; i < nTabCount; ++i )
665             {
666                 if ( rMark.GetTableSelect( i ) )
667                 {
668                     aChangeRanges.Append( ScRange( nCol, nRow, i ) );
669                 }
670             }
671             pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
672         }
673 
674         aModificator.SetDocumentModified();
675     }
676     else
677     {
678         ErrorMessage(aTester.GetMessageId());
679         PaintArea( nCol, nRow, nCol, nRow );        // da steht evtl. noch die Edit-Engine
680     }
681 }
682 
683 //  Wert in einzele Zelle eintragen (nur auf nTab)
684 
685 void ScViewFunc::EnterValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rValue )
686 {
687     ScDocument* pDoc = GetViewData()->GetDocument();
688     ScDocShell* pDocSh = GetViewData()->GetDocShell();
689     sal_Bool bUndo (pDoc->IsUndoEnabled());
690 
691     if ( pDoc && pDocSh )
692     {
693         ScDocShellModificator aModificator( *pDocSh );
694 
695         ScEditableTester aTester( pDoc, nTab, nCol,nRow, nCol,nRow );
696         if (aTester.IsEditable())
697         {
698             ScAddress aPos( nCol, nRow, nTab );
699             ScBaseCell* pOldCell = pDoc->GetCell( aPos );
700             sal_Bool bNeedHeight = ( pOldCell && pOldCell->GetCellType() == CELLTYPE_EDIT )
701                                 || pDoc->HasAttrib(
702                                     nCol,nRow,nTab, nCol,nRow,nTab, HASATTR_NEEDHEIGHT );
703 
704             //  Undo
705             ScBaseCell* pUndoCell = (bUndo && pOldCell) ? pOldCell->CloneWithoutNote( *pDoc ) : 0;
706 
707             pDoc->SetValue( nCol, nRow, nTab, rValue );
708 
709             // wg. ChangeTrack nach Aenderung im Dokument
710             if (bUndo)
711             {
712                 pDocSh->GetUndoManager()->AddUndoAction(
713                     new ScUndoEnterValue( pDocSh, aPos, pUndoCell, rValue, bNeedHeight ) );
714             }
715 
716 /*!             Zeilenhoehe anpassen? Dann auch bei Undo...
717             if (bNeedHeight)
718                 AdjustRowHeight(nRow,nRow);
719 */
720 
721             pDocSh->PostPaintCell( aPos );
722             pDocSh->UpdateOle(GetViewData());
723             aModificator.SetDocumentModified();
724         }
725         else
726             ErrorMessage(aTester.GetMessageId());
727     }
728 }
729 
730 void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const EditTextObject* pData,
731                             sal_Bool bRecord, sal_Bool bTestSimple )
732 {
733     ScDocShell* pDocSh = GetViewData()->GetDocShell();
734     ScMarkData& rMark = GetViewData()->GetMarkData();
735     ScDocument* pDoc = pDocSh->GetDocument();
736     if (bRecord && !pDoc->IsUndoEnabled())
737         bRecord = sal_False;
738 
739     ScDocShellModificator aModificator( *pDocSh );
740 
741     ScEditableTester aTester( pDoc, nTab, nCol,nRow, nCol,nRow );
742     if (aTester.IsEditable())
743     {
744         //
745         //      Test auf Attribute
746         //
747         sal_Bool bSimple = sal_False;
748         sal_Bool bCommon = sal_False;
749         ScPatternAttr* pCellAttrs = NULL;
750         EditTextObject* pNewData = NULL;
751         String aString;
752 
753         const ScPatternAttr* pOldPattern = pDoc->GetPattern( nCol, nRow, nTab );
754         ScTabEditEngine aEngine( *pOldPattern, pDoc->GetEnginePool() );
755         aEngine.SetText(*pData);
756 
757         if (bTestSimple)                    // Testen, ob einfacher String ohne Attribute
758         {
759             ScEditAttrTester aAttrTester( &aEngine );
760             bSimple = !aAttrTester.NeedsObject();
761             bCommon = aAttrTester.NeedsCellAttr();
762 
763             // formulas have to be recognized even if they're formatted
764             // (but commmon attributes are still collected)
765 
766             if ( !bSimple && aEngine.GetParagraphCount() == 1 )
767             {
768                 String aParStr = aEngine.GetText( (sal_uInt16) 0 );
769                 if ( aParStr.GetChar(0) == '=' )
770                     bSimple = sal_True;
771             }
772 
773             if (bCommon)                // Attribute fuer Tabelle
774             {
775                 pCellAttrs = new ScPatternAttr( *pOldPattern );
776                 pCellAttrs->GetFromEditItemSet( &aAttrTester.GetAttribs() );
777                 //! remove common attributes from EditEngine?
778             }
779         }
780 
781         // #i97726# always get text for "repeat" of undo action
782         aString = ScEditUtil::GetSpaceDelimitedString(aEngine);
783 
784         //
785         //      Undo
786         //
787 
788         SCTAB nTabCount = pDoc->GetTableCount();
789         SCTAB nSelCount = rMark.GetSelectCount();
790         SCTAB i;
791         ScBaseCell** ppOldCells = NULL;
792         SCTAB* pTabs            = NULL;
793         SCTAB nPos = 0;
794         EditTextObject* pUndoData = NULL;
795         if (bRecord && !bSimple)
796         {
797             ppOldCells  = new ScBaseCell*[nSelCount];
798             pTabs       = new SCTAB[nSelCount];
799             nPos = 0;
800 
801             for (i=0; i<nTabCount; i++)
802                 if (rMark.GetTableSelect(i))
803                 {
804                     pTabs[nPos] = i;
805                     ScBaseCell* pDocCell;
806                     pDoc->GetCell( nCol, nRow, i, pDocCell );
807                     ppOldCells[nPos] = pDocCell ? pDocCell->CloneWithoutNote( *pDoc ) : 0;
808                     ++nPos;
809                 }
810 
811             DBG_ASSERT( nPos==nSelCount, "nPos!=nSelCount" );
812 
813             pUndoData = pData->Clone();
814         }
815 
816         //
817         //      Daten eintragen
818         //
819 
820         if (bCommon)
821             pDoc->ApplyPattern(nCol,nRow,nTab,*pCellAttrs);         //! Undo
822 
823         if (bSimple)
824         {
825             if (bCommon)
826                 AdjustRowHeight(nRow,nRow);
827 
828             EnterData(nCol,nRow,nTab,aString,bRecord);
829         }
830         else
831         {
832             for (i=0; i<nTabCount; i++)
833                 if (rMark.GetTableSelect(i))
834                     pDoc->PutCell( nCol, nRow, i, new ScEditCell( pData, pDoc, NULL ) );
835 
836             if ( bRecord )
837             {   // wg. ChangeTrack erst jetzt
838                 pDocSh->GetUndoManager()->AddUndoAction(
839                     new ScUndoEnterData( pDocSh, nCol, nRow, nTab, nPos, pTabs,
840                                         ppOldCells, NULL, NULL, aString,
841                                         pUndoData ) );
842             }
843 
844             HideAllCursors();
845 
846             AdjustRowHeight(nRow,nRow);
847 
848             for (i=0; i<nTabCount; i++)
849                 if (rMark.GetTableSelect(i))
850                     pDocSh->PostPaintCell( nCol, nRow, i );
851 
852             ShowAllCursors();
853 
854             pDocSh->UpdateOle(GetViewData());
855 
856             // #i97876# Spreadsheet data changes are not notified
857             ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
858             if ( pModelObj && pModelObj->HasChangesListeners() )
859             {
860                 ScRangeList aChangeRanges;
861                 for ( i = 0; i < nTabCount; ++i )
862                 {
863                     if ( rMark.GetTableSelect( i ) )
864                     {
865                         aChangeRanges.Append( ScRange( nCol, nRow, i ) );
866                     }
867                 }
868                 pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
869             }
870 
871             aModificator.SetDocumentModified();
872         }
873 
874         delete pCellAttrs;
875         delete pNewData;
876     }
877     else
878     {
879         ErrorMessage(aTester.GetMessageId());
880         PaintArea( nCol, nRow, nCol, nRow );        // da steht evtl. noch die Edit-Engine
881     }
882 }
883 
884 void ScViewFunc::EnterDataAtCursor( const String& rString )
885 {
886     SCCOL nPosX = GetViewData()->GetCurX();
887     SCROW nPosY = GetViewData()->GetCurY();
888     SCTAB nTab = GetViewData()->GetTabNo();
889 
890     EnterData( nPosX, nPosY, nTab, rString );
891 }
892 
893 void ScViewFunc::EnterMatrix( const String& rString )
894 {
895     ScViewData* pData = GetViewData();
896     const ScMarkData& rMark = pData->GetMarkData();
897     if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
898     {
899         //  nichts markiert -> automatisch Block mit Groesse des Ergebnisses
900         //  Formel temporaer berechnen, um an die Groesse heranzukommen
901 
902         ScDocument* pDoc = pData->GetDocument();
903         SCCOL nCol = pData->GetCurX();
904         SCROW nRow = pData->GetCurY();
905         SCTAB nTab = pData->GetTabNo();
906         ScFormulaCell aFormCell( pDoc, ScAddress(nCol,nRow,nTab), rString,formula::FormulaGrammar::GRAM_DEFAULT, MM_FORMULA );
907 
908         SCSIZE nSizeX;
909         SCSIZE nSizeY;
910         aFormCell.GetResultDimensions( nSizeX, nSizeY );
911         if ( nSizeX != 0 && nSizeY != 0 &&
912              nCol+nSizeX-1 <= sal::static_int_cast<SCSIZE>(MAXCOL) &&
913              nRow+nSizeY-1 <= sal::static_int_cast<SCSIZE>(MAXROW) )
914         {
915             ScRange aResult( nCol, nRow, nTab,
916                              sal::static_int_cast<SCCOL>(nCol+nSizeX-1),
917                              sal::static_int_cast<SCROW>(nRow+nSizeY-1), nTab );
918             MarkRange( aResult, sal_False );
919         }
920     }
921 
922     ScRange aRange;
923     if (pData->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
924     {
925         ScDocShell* pDocSh = pData->GetDocShell();
926         sal_Bool bSuccess = pDocSh->GetDocFunc().EnterMatrix( aRange, &rMark, NULL, rString, sal_False, sal_False, EMPTY_STRING, formula::FormulaGrammar::GRAM_DEFAULT );
927         if (bSuccess)
928             pDocSh->UpdateOle(GetViewData());
929     }
930     else
931         ErrorMessage(STR_NOMULTISELECT);
932 }
933 
934 sal_uInt8 ScViewFunc::GetSelectionScriptType()
935 {
936     sal_uInt8 nScript = 0;
937 
938     ScDocument* pDoc = GetViewData()->GetDocument();
939     const ScMarkData& rMark = GetViewData()->GetMarkData();
940     if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
941     {
942         // no selection -> cursor
943 
944         nScript = pDoc->GetScriptType( GetViewData()->GetCurX(),
945                             GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
946     }
947     else
948     {
949         ScRangeList aRanges;
950         rMark.FillRangeListWithMarks( &aRanges, sal_False );
951         sal_uLong nCount = aRanges.Count();
952         for (sal_uLong i=0; i<nCount; i++)
953         {
954             ScRange aRange = *aRanges.GetObject(i);
955             ScCellIterator aIter( pDoc, aRange );
956             ScBaseCell* pCell = aIter.GetFirst();
957             while ( pCell )
958             {
959                 nScript |= pDoc->GetScriptType( aIter.GetCol(), aIter.GetRow(), aIter.GetTab(), pCell );
960                 pCell = aIter.GetNext();
961             }
962         }
963     }
964 
965     if (nScript == 0)
966         nScript = ScGlobal::GetDefaultScriptType();
967 
968     return nScript;
969 }
970 
971 const ScPatternAttr* ScViewFunc::GetSelectionPattern()
972 {
973     // Don't use UnmarkFiltered in slot state functions, for performance reasons.
974     // The displayed state is always that of the whole selection including filtered rows.
975 
976     const ScMarkData& rMark = GetViewData()->GetMarkData();
977     ScDocument* pDoc = GetViewData()->GetDocument();
978     if ( rMark.IsMarked() || rMark.IsMultiMarked() )
979     {
980         //  MarkToMulti is no longer necessary for pDoc->GetSelectionPattern
981         const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( rMark );
982         return pAttr;
983     }
984     else
985     {
986         SCCOL  nCol = GetViewData()->GetCurX();
987         SCROW  nRow = GetViewData()->GetCurY();
988         SCTAB  nTab = GetViewData()->GetTabNo();
989 
990         ScMarkData aTempMark( rMark );      // copy sheet selection
991         aTempMark.SetMarkArea( ScRange( nCol, nRow, nTab ) );
992         const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( aTempMark );
993         return pAttr;
994     }
995 }
996 
997 void ScViewFunc::GetSelectionFrame( SvxBoxItem&     rLineOuter,
998                                     SvxBoxInfoItem& rLineInner )
999 {
1000     ScDocument* pDoc = GetViewData()->GetDocument();
1001     const ScMarkData& rMark = GetViewData()->GetMarkData();
1002 
1003     if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1004     {
1005         if ( rMark.IsMultiMarked() )
1006         {
1007             ScMarkData aNewMark( rMark );   // use local copy for MarkToSimple
1008             aNewMark.MarkToSimple();        // simple block is needed for GetSelectionFrame
1009             pDoc->GetSelectionFrame( aNewMark, rLineOuter, rLineInner );
1010         }
1011         else
1012             pDoc->GetSelectionFrame( rMark, rLineOuter, rLineInner );
1013     }
1014     else
1015     {
1016         const ScPatternAttr* pAttrs =
1017                     pDoc->GetPattern( GetViewData()->GetCurX(),
1018                                       GetViewData()->GetCurY(),
1019                                       GetViewData()->GetTabNo() );
1020 
1021         rLineOuter = (const SvxBoxItem&)    (pAttrs->GetItem( ATTR_BORDER ));
1022         rLineInner = (const SvxBoxInfoItem&)(pAttrs->GetItem( ATTR_BORDER_INNER ));
1023         rLineInner.SetTable(sal_False);
1024         rLineInner.SetDist(sal_True);
1025         rLineInner.SetMinDist(sal_False);
1026     }
1027 }
1028 
1029 //
1030 //  Attribute anwenden - Undo OK
1031 //
1032 //  kompletter Set ( ATTR_STARTINDEX, ATTR_ENDINDEX )
1033 //
1034 
1035 void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
1036                                   const SfxItemSet* pOldSet,
1037                                   sal_Bool              bRecord )
1038 {
1039     // nur wegen Matrix nicht editierbar? Attribute trotzdem ok
1040     sal_Bool bOnlyNotBecauseOfMatrix;
1041     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1042     {
1043         ErrorMessage(STR_PROTECTIONERR);
1044         return;
1045     }
1046 
1047     ScPatternAttr aOldAttrs( new SfxItemSet(*pOldSet) );
1048     ScPatternAttr aNewAttrs( new SfxItemSet(*pDialogSet) );
1049     aNewAttrs.DeleteUnchanged( &aOldAttrs );
1050 
1051     if ( pDialogSet->GetItemState( ATTR_VALUE_FORMAT ) == SFX_ITEM_SET )
1052     {   // #82521# don't reset to default SYSTEM GENERAL if not intended
1053         sal_uInt32 nOldFormat =
1054             ((const SfxUInt32Item&)pOldSet->Get( ATTR_VALUE_FORMAT )).GetValue();
1055         sal_uInt32 nNewFormat =
1056             ((const SfxUInt32Item&)pDialogSet->Get( ATTR_VALUE_FORMAT )).GetValue();
1057         if ( nNewFormat != nOldFormat )
1058         {
1059             SvNumberFormatter* pFormatter =
1060                 GetViewData()->GetDocument()->GetFormatTable();
1061             const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
1062             LanguageType eOldLang =
1063                 pOldEntry ? pOldEntry->GetLanguage() : LANGUAGE_DONTKNOW;
1064             const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
1065             LanguageType eNewLang =
1066                 pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
1067             if ( eNewLang != eOldLang )
1068             {
1069                 aNewAttrs.GetItemSet().Put(
1070                     SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
1071 
1072                 //  #40606# nur die Sprache geaendert -> Zahlformat-Attribut nicht anfassen
1073                 sal_uInt32 nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
1074                 if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
1075                     nNewMod <= SV_MAX_ANZ_STANDARD_FORMATE )
1076                     aNewAttrs.GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
1077             }
1078         }
1079     }
1080 
1081     const SvxBoxItem*     pOldOuter = (const SvxBoxItem*)     &pOldSet->Get( ATTR_BORDER );
1082     const SvxBoxItem*     pNewOuter = (const SvxBoxItem*)     &pDialogSet->Get( ATTR_BORDER );
1083     const SvxBoxInfoItem* pOldInner = (const SvxBoxInfoItem*) &pOldSet->Get( ATTR_BORDER_INNER );
1084     const SvxBoxInfoItem* pNewInner = (const SvxBoxInfoItem*) &pDialogSet->Get( ATTR_BORDER_INNER );
1085     SfxItemSet&           rNewSet   = aNewAttrs.GetItemSet();
1086     SfxItemPool*          pNewPool  = rNewSet.GetPool();
1087 
1088     pNewPool->Put( *pNewOuter );        // noch nicht loeschen
1089     pNewPool->Put( *pNewInner );
1090     rNewSet.ClearItem( ATTR_BORDER );
1091     rNewSet.ClearItem( ATTR_BORDER_INNER );
1092 
1093     /*
1094      * Feststellen, ob Rahmenattribute zu setzen sind:
1095      * 1. Neu != Alt
1096      * 2. Ist eine der Linien nicht-DontCare (seit 238.f: IsxxValid())
1097      *
1098      */
1099 
1100     sal_Bool bFrame =    (pDialogSet->GetItemState( ATTR_BORDER ) != SFX_ITEM_DEFAULT)
1101                   || (pDialogSet->GetItemState( ATTR_BORDER_INNER ) != SFX_ITEM_DEFAULT);
1102 
1103     if ( pNewOuter==pOldOuter && pNewInner==pOldInner )
1104         bFrame = sal_False;
1105 
1106     //  das sollte doch der Pool abfangen: ?!??!??
1107 
1108     if ( bFrame && pNewOuter && pNewInner )
1109         if ( *pNewOuter == *pOldOuter && *pNewInner == *pOldInner )
1110             bFrame = sal_False;
1111 
1112     if ( pNewInner )
1113     {
1114         bFrame =   bFrame
1115                 && (   pNewInner->IsValid(VALID_LEFT)
1116                     || pNewInner->IsValid(VALID_RIGHT)
1117                     || pNewInner->IsValid(VALID_TOP)
1118                     || pNewInner->IsValid(VALID_BOTTOM)
1119                     || pNewInner->IsValid(VALID_HORI)
1120                     || pNewInner->IsValid(VALID_VERT) );
1121     }
1122     else
1123         bFrame = sal_False;
1124 
1125     if (!bFrame)
1126         ApplySelectionPattern( aNewAttrs, bRecord );                // nur normale
1127     else
1128     {
1129         // wenn neue Items Default-Items sind, so muessen die
1130         // alten Items geputtet werden:
1131 
1132         sal_Bool bDefNewOuter = ( SFX_ITEMS_STATICDEFAULT == pNewOuter->GetKind() );
1133         sal_Bool bDefNewInner = ( SFX_ITEMS_STATICDEFAULT == pNewInner->GetKind() );
1134 
1135         ApplyPatternLines( aNewAttrs,
1136                            bDefNewOuter ? pOldOuter : pNewOuter,
1137                            bDefNewInner ? pOldInner : pNewInner,
1138                            bRecord );
1139     }
1140 
1141     pNewPool->Remove( *pNewOuter );         // freigeben
1142     pNewPool->Remove( *pNewInner );
1143 
1144     //  Hoehen anpassen
1145     AdjustBlockHeight();
1146 
1147     // CellContentChanged wird von ApplySelectionPattern / ApplyPatternLines gerufen
1148 }
1149 
1150 void ScViewFunc::ApplyAttr( const SfxPoolItem& rAttrItem )
1151 {
1152     // nur wegen Matrix nicht editierbar? Attribute trotzdem ok
1153     sal_Bool bOnlyNotBecauseOfMatrix;
1154     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1155     {
1156         ErrorMessage(STR_PROTECTIONERR);
1157         return;
1158     }
1159 
1160     ScPatternAttr aNewAttrs( new SfxItemSet( *GetViewData()->GetDocument()->GetPool(),
1161                                             ATTR_PATTERN_START, ATTR_PATTERN_END ) );
1162 
1163     aNewAttrs.GetItemSet().Put( rAttrItem );
1164     //  Wenn Ausrichtung eingestellt wird (ueber Buttons), immer Einzug 0
1165     if ( rAttrItem.Which() == ATTR_HOR_JUSTIFY )
1166         aNewAttrs.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, 0 ) );
1167     ApplySelectionPattern( aNewAttrs );
1168 
1169     AdjustBlockHeight();
1170 
1171     // CellContentChanged wird von ApplySelectionPattern gerufen
1172 }
1173 
1174 
1175 //  Pattern und Rahmen
1176 
1177 void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem* pNewOuter,
1178                                     const SvxBoxInfoItem* pNewInner, sal_Bool bRecord )
1179 {
1180     ScDocument* pDoc = GetViewData()->GetDocument();
1181     ScMarkData aFuncMark( GetViewData()->GetMarkData() );       // local copy for UnmarkFiltered
1182     ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1183     if (bRecord && !pDoc->IsUndoEnabled())
1184         bRecord = sal_False;
1185 
1186     ScRange aMarkRange;
1187     aFuncMark.MarkToSimple();
1188     sal_Bool bMulti = aFuncMark.IsMultiMarked();
1189     if (bMulti)
1190         aFuncMark.GetMultiMarkArea( aMarkRange );
1191     else if (aFuncMark.IsMarked())
1192         aFuncMark.GetMarkArea( aMarkRange );
1193     else
1194     {
1195         aMarkRange = ScRange( GetViewData()->GetCurX(),
1196                             GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1197         DoneBlockMode();
1198         InitOwnBlockMode();
1199         aFuncMark.SetMarkArea(aMarkRange);
1200         MarkDataChanged();
1201     }
1202 
1203     ScDocShell* pDocSh = GetViewData()->GetDocShell();
1204 
1205     ScDocShellModificator aModificator( *pDocSh );
1206 
1207     if (bRecord)
1208     {
1209         ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1210         SCTAB nStartTab = aMarkRange.aStart.Tab();
1211         SCTAB nTabCount = pDoc->GetTableCount();
1212         pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
1213         for (SCTAB i=0; i<nTabCount; i++)
1214             if (i != nStartTab && aFuncMark.GetTableSelect(i))
1215                 pUndoDoc->AddUndoTab( i, i );
1216 
1217         ScRange aCopyRange = aMarkRange;
1218         aCopyRange.aStart.SetTab(0);
1219         aCopyRange.aEnd.SetTab(nTabCount-1);
1220         pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &aFuncMark );
1221 
1222         pDocSh->GetUndoManager()->AddUndoAction(
1223             new ScUndoSelectionAttr(
1224             pDocSh, aFuncMark,
1225             aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), aMarkRange.aStart.Tab(),
1226             aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), aMarkRange.aEnd.Tab(),
1227             pUndoDoc, bMulti, &rAttr, pNewOuter, pNewInner ) );
1228     }
1229 
1230     sal_uInt16 nExt = SC_PF_TESTMERGE;
1231     pDocSh->UpdatePaintExt( nExt, aMarkRange ); // content before the change
1232 
1233     pDoc->ApplySelectionFrame( aFuncMark, pNewOuter, pNewInner );
1234 
1235     pDocSh->UpdatePaintExt( nExt, aMarkRange ); // content after the change
1236 
1237     aFuncMark.MarkToMulti();
1238     pDoc->ApplySelectionPattern( rAttr, aFuncMark );
1239 
1240     pDocSh->PostPaint( aMarkRange, PAINT_GRID, nExt );
1241     pDocSh->UpdateOle(GetViewData());
1242     aModificator.SetDocumentModified();
1243     CellContentChanged();
1244 
1245     StartFormatArea();
1246 }
1247 
1248 //  nur Pattern
1249 
1250 void ScViewFunc::ApplySelectionPattern( const ScPatternAttr& rAttr,
1251                                             sal_Bool bRecord, sal_Bool bCursorOnly )
1252 {
1253     ScViewData* pViewData   = GetViewData();
1254     ScDocShell* pDocSh      = pViewData->GetDocShell();
1255     ScDocument* pDoc        = pDocSh->GetDocument();
1256     ScMarkData aFuncMark( pViewData->GetMarkData() );       // local copy for UnmarkFiltered
1257     ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1258 
1259     if (bRecord && !pDoc->IsUndoEnabled())
1260         bRecord = sal_False;
1261 
1262     //  State from old ItemSet doesn't matter for paint flags, as any change will be
1263     //  from SFX_ITEM_SET in the new ItemSet (default is ignored in ApplyPattern).
1264     //  New alignment is checked (check in PostPaint isn't enough) in case a right
1265     //  alignment is changed to left.
1266     const SfxItemSet& rNewSet = rAttr.GetItemSet();
1267     sal_Bool bSetLines = rNewSet.GetItemState( ATTR_BORDER, sal_True ) == SFX_ITEM_SET ||
1268                      rNewSet.GetItemState( ATTR_SHADOW, sal_True ) == SFX_ITEM_SET;
1269     sal_Bool bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY, sal_True ) == SFX_ITEM_SET;
1270 
1271     sal_uInt16 nExtFlags = 0;
1272     if ( bSetLines )
1273         nExtFlags |= SC_PF_LINES;
1274     if ( bSetAlign )
1275         nExtFlags |= SC_PF_WHOLEROWS;
1276 
1277     ScDocShellModificator aModificator( *pDocSh );
1278 
1279     sal_Bool bMulti = aFuncMark.IsMultiMarked();
1280     aFuncMark.MarkToMulti();
1281     sal_Bool bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && aFuncMark.GetSelectCount() > 1);
1282     if (bOnlyTab)
1283     {
1284         SCCOL nCol = pViewData->GetCurX();
1285         SCROW nRow = pViewData->GetCurY();
1286         SCTAB nTab = pViewData->GetTabNo();
1287         aFuncMark.SetMarkArea(ScRange(nCol,nRow,nTab));
1288         aFuncMark.MarkToMulti();
1289     }
1290 
1291     ScRangeList aChangeRanges;
1292 
1293     if (aFuncMark.IsMultiMarked() && !bCursorOnly)
1294     {
1295         ScRange aMarkRange;
1296         aFuncMark.GetMultiMarkArea( aMarkRange );
1297         SCTAB nTabCount = pDoc->GetTableCount();
1298         for ( SCTAB i = 0; i < nTabCount; ++i )
1299         {
1300             if ( aFuncMark.GetTableSelect( i ) )
1301             {
1302                 ScRange aChangeRange( aMarkRange );
1303                 aChangeRange.aStart.SetTab( i );
1304                 aChangeRange.aEnd.SetTab( i );
1305                 aChangeRanges.Append( aChangeRange );
1306             }
1307         }
1308 
1309         SCCOL nStartCol = aMarkRange.aStart.Col();
1310         SCROW nStartRow = aMarkRange.aStart.Row();
1311         SCTAB nStartTab = aMarkRange.aStart.Tab();
1312         SCCOL nEndCol = aMarkRange.aEnd.Col();
1313         SCROW nEndRow = aMarkRange.aEnd.Row();
1314         SCTAB nEndTab = aMarkRange.aEnd.Tab();
1315 
1316         if (bRecord)
1317         {
1318             ScRange aCopyRange = aMarkRange;
1319             aCopyRange.aStart.SetTab(0);
1320             aCopyRange.aEnd.SetTab(nTabCount-1);
1321 
1322             ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1323             pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
1324             for (SCTAB i=0; i<nTabCount; i++)
1325                 if (i != nStartTab && aFuncMark.GetTableSelect(i))
1326                     pUndoDoc->AddUndoTab( i, i );
1327             pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &aFuncMark );
1328 
1329             aFuncMark.MarkToMulti();
1330 
1331             pDocSh->GetUndoManager()->AddUndoAction(
1332                 new ScUndoSelectionAttr(
1333                             pDocSh, aFuncMark,
1334                             nStartCol, nStartRow, nStartTab,
1335                             nEndCol, nEndRow, nEndTab,
1336                             pUndoDoc, bMulti, &rAttr ) );
1337         }
1338 
1339         pDoc->ApplySelectionPattern( rAttr, aFuncMark );
1340 
1341         pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
1342                            nEndCol,   nEndRow,   nEndTab,
1343                            PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
1344         pDocSh->UpdateOle(GetViewData());
1345         aModificator.SetDocumentModified();
1346         CellContentChanged();
1347     }
1348     else                            // einzelne Zelle - Undo einfacher
1349     {
1350         SCCOL nCol = pViewData->GetCurX();
1351         SCROW nRow = pViewData->GetCurY();
1352         SCTAB nTab = pViewData->GetTabNo();
1353         aChangeRanges.Append( ScRange( nCol, nRow, nTab ) );
1354         ScPatternAttr* pOldPat = new ScPatternAttr(*pDoc->GetPattern( nCol, nRow, nTab ));
1355 
1356         pDoc->ApplyPattern( nCol, nRow, nTab, rAttr );
1357 
1358         const ScPatternAttr* pNewPat = pDoc->GetPattern( nCol, nRow, nTab );
1359 
1360         if (bRecord)
1361         {
1362             pDocSh->GetUndoManager()->AddUndoAction(
1363                         new ScUndoCursorAttr( pDocSh,
1364                                               nCol, nRow, nTab,
1365                                               pOldPat, pNewPat, &rAttr,
1366                                               sal_False ) );    // sal_False = nicht automatisch
1367         }
1368         delete pOldPat;     // wird im Undo kopiert (Pool)
1369 
1370         pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
1371         pDocSh->UpdateOle(GetViewData());
1372         aModificator.SetDocumentModified();
1373         CellContentChanged();
1374     }
1375 
1376     // #i97876# Spreadsheet data changes are not notified
1377     ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
1378     if ( pModelObj && pModelObj->HasChangesListeners() )
1379     {
1380         ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aProperties;
1381         sal_Int32 nCount = 0;
1382         const SfxItemPropertyMap* pMap = ScCellObj::GetCellPropertyMap();
1383         PropertyEntryVector_t aPropVector = pMap->getPropertyEntries();
1384         for ( sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; ++nWhich )
1385         {
1386             const SfxPoolItem* pItem = 0;
1387             if ( rNewSet.GetItemState( nWhich, sal_True, &pItem ) == SFX_ITEM_SET && pItem )
1388             {
1389                 PropertyEntryVector_t::const_iterator aIt = aPropVector.begin();
1390                 while ( aIt != aPropVector.end())
1391                 {
1392                     if ( aIt->nWID == nWhich )
1393                     {
1394                         ::com::sun::star::uno::Any aVal;
1395                         pItem->QueryValue( aVal, aIt->nMemberId );
1396                         aProperties.realloc( nCount + 1 );
1397                         aProperties[ nCount ].Name = aIt->sName;
1398                         aProperties[ nCount ].Value <<= aVal;
1399                         ++nCount;
1400                     }
1401                     ++aIt;
1402                 }
1403             }
1404         }
1405         pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "attribute" ) ), aChangeRanges, aProperties );
1406     }
1407 
1408     StartFormatArea();
1409 }
1410 
1411 void ScViewFunc::ApplyUserItemSet( const SfxItemSet& rItemSet )
1412 {
1413     //  ItemSet from UI, may have different pool
1414 
1415     sal_Bool bOnlyNotBecauseOfMatrix;
1416     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1417     {
1418         ErrorMessage(STR_PROTECTIONERR);
1419         return;
1420     }
1421 
1422     ScPatternAttr aNewAttrs( GetViewData()->GetDocument()->GetPool() );
1423     SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
1424     rNewSet.Put( rItemSet, sal_False );
1425     ApplySelectionPattern( aNewAttrs );
1426 
1427     AdjustBlockHeight();
1428 }
1429 
1430 const SfxStyleSheet* ScViewFunc::GetStyleSheetFromMarked()
1431 {
1432     // Don't use UnmarkFiltered in slot state functions, for performance reasons.
1433     // The displayed state is always that of the whole selection including filtered rows.
1434 
1435     const ScStyleSheet* pSheet      = NULL;
1436     ScViewData*         pViewData   = GetViewData();
1437     ScDocument*         pDoc        = pViewData->GetDocument();
1438     ScMarkData&         rMark       = pViewData->GetMarkData();
1439 
1440     if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1441         pSheet = pDoc->GetSelectionStyle( rMark );                  // MarkToMulti isn't necessary
1442     else
1443         pSheet = pDoc->GetStyle( pViewData->GetCurX(),
1444                                  pViewData->GetCurY(),
1445                                  pViewData->GetTabNo() );
1446 
1447     return pSheet;
1448 }
1449 
1450 void ScViewFunc::SetStyleSheetToMarked( SfxStyleSheet* pStyleSheet, sal_Bool bRecord )
1451 {
1452     // nur wegen Matrix nicht editierbar? Attribute trotzdem ok
1453     sal_Bool bOnlyNotBecauseOfMatrix;
1454     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
1455     {
1456         ErrorMessage(STR_PROTECTIONERR);
1457         return;
1458     }
1459 
1460     if ( !pStyleSheet) return;
1461     // -------------------------------------------------------------------
1462 
1463     ScViewData* pViewData   = GetViewData();
1464     ScDocShell* pDocSh      = pViewData->GetDocShell();
1465     ScDocument* pDoc        = pDocSh->GetDocument();
1466     ScMarkData aFuncMark( pViewData->GetMarkData() );       // local copy for UnmarkFiltered
1467     ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1468     SCTAB nTabCount     = pDoc->GetTableCount();
1469     if (bRecord && !pDoc->IsUndoEnabled())
1470         bRecord = sal_False;
1471 
1472     ScDocShellModificator aModificator( *pDocSh );
1473 
1474     if ( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() )
1475     {
1476         ScRange aMarkRange;
1477         aFuncMark.MarkToMulti();
1478         aFuncMark.GetMultiMarkArea( aMarkRange );
1479 
1480         if ( bRecord )
1481         {
1482             SCTAB nTab = pViewData->GetTabNo();
1483             ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1484             pUndoDoc->InitUndo( pDoc, nTab, nTab );
1485             for (SCTAB i=0; i<nTabCount; i++)
1486                 if (i != nTab && aFuncMark.GetTableSelect(i))
1487                     pUndoDoc->AddUndoTab( i, i );
1488 
1489             ScRange aCopyRange = aMarkRange;
1490             aCopyRange.aStart.SetTab(0);
1491             aCopyRange.aEnd.SetTab(nTabCount-1);
1492             pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, sal_True, pUndoDoc, &aFuncMark );
1493             aFuncMark.MarkToMulti();
1494 
1495             String aName = pStyleSheet->GetName();
1496             pDocSh->GetUndoManager()->AddUndoAction(
1497                 new ScUndoSelectionStyle( pDocSh, aFuncMark, aMarkRange, aName, pUndoDoc ) );
1498         }
1499 
1500         pDoc->ApplySelectionStyle( (ScStyleSheet&)*pStyleSheet, aFuncMark );
1501 
1502         if (!AdjustBlockHeight())
1503             pViewData->GetDocShell()->PostPaint( aMarkRange, PAINT_GRID );
1504 
1505         aFuncMark.MarkToSimple();
1506     }
1507     else
1508     {
1509         SCCOL nCol = pViewData->GetCurX();
1510         SCROW nRow = pViewData->GetCurY();
1511         SCTAB nTab = pViewData->GetTabNo();
1512 
1513         if ( bRecord )
1514         {
1515             ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1516             pUndoDoc->InitUndo( pDoc, nTab, nTab );
1517             for (SCTAB i=0; i<nTabCount; i++)
1518                 if (i != nTab && aFuncMark.GetTableSelect(i))
1519                     pUndoDoc->AddUndoTab( i, i );
1520 
1521             ScRange aCopyRange( nCol, nRow, 0, nCol, nRow, nTabCount-1 );
1522             pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, sal_False, pUndoDoc );
1523 
1524             ScRange aMarkRange ( nCol, nRow, nTab );
1525             ScMarkData aUndoMark = aFuncMark;
1526             aUndoMark.SetMultiMarkArea( aMarkRange );
1527 
1528             String aName = pStyleSheet->GetName();
1529             pDocSh->GetUndoManager()->AddUndoAction(
1530                 new ScUndoSelectionStyle( pDocSh, aUndoMark, aMarkRange, aName, pUndoDoc ) );
1531         }
1532 
1533         for (SCTAB i=0; i<nTabCount; i++)
1534             if (aFuncMark.GetTableSelect(i))
1535                 pDoc->ApplyStyle( nCol, nRow, i, (ScStyleSheet&)*pStyleSheet );
1536 
1537         if (!AdjustBlockHeight())
1538             pViewData->GetDocShell()->PostPaintCell( nCol, nRow, nTab );
1539 
1540     }
1541 
1542     aModificator.SetDocumentModified();
1543 
1544     StartFormatArea();
1545 }
1546 
1547 
1548 void ScViewFunc::RemoveStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1549 {
1550     if ( !pStyleSheet) return;
1551     // -------------------------------------------------------------------
1552 
1553     ScViewData* pViewData   = GetViewData();
1554     ScDocument* pDoc        = pViewData->GetDocument();
1555     ScDocShell* pDocSh      = pViewData->GetDocShell();
1556 
1557     ScDocShellModificator aModificator( *pDocSh );
1558 
1559     VirtualDevice aVirtDev;
1560     aVirtDev.SetMapMode(MAP_PIXEL);
1561     pDoc->StyleSheetChanged( pStyleSheet, sal_True, &aVirtDev,
1562                                 pViewData->GetPPTX(),
1563                                 pViewData->GetPPTY(),
1564                                 pViewData->GetZoomX(),
1565                                 pViewData->GetZoomY() );
1566 
1567     pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
1568     aModificator.SetDocumentModified();
1569 
1570     ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1571     if (pHdl)
1572         pHdl->ForgetLastPattern();
1573 }
1574 
1575 void ScViewFunc::UpdateStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
1576 {
1577     if ( !pStyleSheet) return;
1578     // -------------------------------------------------------------------
1579 
1580     ScViewData* pViewData   = GetViewData();
1581     ScDocument* pDoc        = pViewData->GetDocument();
1582     ScDocShell* pDocSh      = pViewData->GetDocShell();
1583 
1584     ScDocShellModificator aModificator( *pDocSh );
1585 
1586     VirtualDevice aVirtDev;
1587     aVirtDev.SetMapMode(MAP_PIXEL);
1588     pDoc->StyleSheetChanged( pStyleSheet, sal_False, &aVirtDev,
1589                                 pViewData->GetPPTX(),
1590                                 pViewData->GetPPTY(),
1591                                 pViewData->GetZoomX(),
1592                                 pViewData->GetZoomY() );
1593 
1594     pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
1595     aModificator.SetDocumentModified();
1596 
1597     ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1598     if (pHdl)
1599         pHdl->ForgetLastPattern();
1600 }
1601 
1602 //  Zellen einfuegen - Undo OK
1603 
1604 sal_Bool ScViewFunc::InsertCells( InsCellCmd eCmd, sal_Bool bRecord, sal_Bool bPartOfPaste )
1605 {
1606     ScRange aRange;
1607     if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
1608     {
1609         ScDocShell* pDocSh = GetViewData()->GetDocShell();
1610         const ScMarkData& rMark = GetViewData()->GetMarkData();
1611         sal_Bool bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, &rMark, eCmd, bRecord, sal_False, bPartOfPaste );
1612         if (bSuccess)
1613         {
1614             pDocSh->UpdateOle(GetViewData());
1615             CellContentChanged();
1616 
1617             // #i97876# Spreadsheet data changes are not notified
1618             ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
1619             if ( pModelObj && pModelObj->HasChangesListeners() )
1620             {
1621                 if ( eCmd == INS_INSROWS || eCmd == INS_INSCOLS )
1622                 {
1623                     ScRangeList aChangeRanges;
1624                     aChangeRanges.Append( aRange );
1625                     ::rtl::OUString aOperation = ( eCmd == INS_INSROWS ?
1626                         ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert-rows" ) ) :
1627                         ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert-columns" ) ) );
1628                     pModelObj->NotifyChanges( aOperation, aChangeRanges );
1629                 }
1630             }
1631         }
1632         return bSuccess;
1633     }
1634     else
1635     {
1636         ErrorMessage(STR_NOMULTISELECT);
1637         return sal_False;
1638     }
1639 }
1640 
1641 //  Zellen loeschen - Undo OK
1642 
1643 void ScViewFunc::DeleteCells( DelCellCmd eCmd, sal_Bool bRecord )
1644 {
1645     ScRange aRange;
1646     if ( GetViewData()->GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
1647     {
1648         ScDocShell* pDocSh = GetViewData()->GetDocShell();
1649         const ScMarkData& rMark = GetViewData()->GetMarkData();
1650 
1651         // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
1652         if ( pDocSh->IsDocShared() && ( eCmd == DEL_DELROWS || eCmd == DEL_DELCOLS ) )
1653         {
1654             ScRange aDelRange( aRange.aStart );
1655             SCCOLROW nCount = 0;
1656             if ( eCmd == DEL_DELROWS )
1657             {
1658                 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
1659             }
1660             else
1661             {
1662                 nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Col() - aRange.aStart.Col() + 1 );
1663             }
1664             while ( nCount > 0 )
1665             {
1666                 pDocSh->GetDocFunc().DeleteCells( aDelRange, &rMark, eCmd, bRecord, sal_False );
1667                 --nCount;
1668             }
1669         }
1670         else
1671         {
1672             pDocSh->GetDocFunc().DeleteCells( aRange, &rMark, eCmd, bRecord, sal_False );
1673         }
1674 
1675         pDocSh->UpdateOle(GetViewData());
1676         CellContentChanged();
1677 
1678         // #i97876# Spreadsheet data changes are not notified
1679         ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
1680         if ( pModelObj && pModelObj->HasChangesListeners() )
1681         {
1682             if ( eCmd == DEL_DELROWS || eCmd == DEL_DELCOLS )
1683             {
1684                 ScRangeList aChangeRanges;
1685                 aChangeRanges.Append( aRange );
1686                 ::rtl::OUString aOperation = ( eCmd == DEL_DELROWS ?
1687                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete-rows" ) ) :
1688                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete-columns" ) ) );
1689                 pModelObj->NotifyChanges( aOperation, aChangeRanges );
1690             }
1691         }
1692 
1693         //  #58106# Cursor direkt hinter den geloeschten Bereich setzen
1694         SCCOL nCurX = GetViewData()->GetCurX();
1695         SCROW nCurY = GetViewData()->GetCurY();
1696         if ( eCmd==DEL_CELLSLEFT || eCmd==DEL_DELCOLS )
1697             nCurX = aRange.aStart.Col();
1698         else
1699             nCurY = aRange.aStart.Row();
1700         SetCursor( nCurX, nCurY );
1701     }
1702     else
1703     {
1704         if (eCmd == DEL_DELCOLS)
1705             DeleteMulti( sal_False, bRecord );
1706         else if (eCmd == DEL_DELROWS)
1707             DeleteMulti( sal_True, bRecord );
1708         else
1709             ErrorMessage(STR_NOMULTISELECT);
1710     }
1711 
1712     Unmark();
1713 }
1714 
1715 void ScViewFunc::DeleteMulti( sal_Bool bRows, sal_Bool bRecord )
1716 {
1717     ScDocShell* pDocSh = GetViewData()->GetDocShell();
1718     ScDocShellModificator aModificator( *pDocSh );
1719     SCTAB nTab = GetViewData()->GetTabNo();
1720     ScDocument* pDoc = pDocSh->GetDocument();
1721     ScMarkData aFuncMark( GetViewData()->GetMarkData() );       // local copy for UnmarkFiltered
1722     ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1723 
1724     if (bRecord && !pDoc->IsUndoEnabled())
1725         bRecord = sal_False;
1726     SCCOLROW* pRanges = new SCCOLROW[MAXCOLROWCOUNT];
1727     SCCOLROW nRangeCnt = bRows ? aFuncMark.GetMarkRowRanges( pRanges ) :
1728                                 aFuncMark.GetMarkColumnRanges( pRanges );
1729     if (nRangeCnt == 0)
1730     {
1731         pRanges[0] = pRanges[1] = bRows ? static_cast<SCCOLROW>(GetViewData()->GetCurY()) : static_cast<SCCOLROW>(GetViewData()->GetCurX());
1732         nRangeCnt = 1;
1733     }
1734 
1735     //  Test ob erlaubt
1736 
1737     SCCOLROW* pOneRange = pRanges;
1738     sal_uInt16 nErrorId = 0;
1739     sal_Bool bNeedRefresh = sal_False;
1740     SCCOLROW nRangeNo;
1741     for (nRangeNo=0; nRangeNo<nRangeCnt && !nErrorId; nRangeNo++)
1742     {
1743         SCCOLROW nStart = *(pOneRange++);
1744         SCCOLROW nEnd = *(pOneRange++);
1745 
1746         SCCOL nStartCol, nEndCol;
1747         SCROW nStartRow, nEndRow;
1748         if ( bRows )
1749         {
1750             nStartCol = 0;
1751             nEndCol   = MAXCOL;
1752             nStartRow = static_cast<SCROW>(nStart);
1753             nEndRow   = static_cast<SCROW>(nEnd);
1754         }
1755         else
1756         {
1757             nStartCol = static_cast<SCCOL>(nStart);
1758             nEndCol   = static_cast<SCCOL>(nEnd);
1759             nStartRow = 0;
1760             nEndRow   = MAXROW;
1761         }
1762 
1763         // cell protection (only needed for first range, as all following cells are moved)
1764         if ( nRangeNo == 0 )
1765         {
1766             // test to the end of the sheet
1767             ScEditableTester aTester( pDoc, nTab, nStartCol, nStartRow, MAXCOL, MAXROW );
1768             if (!aTester.IsEditable())
1769                 nErrorId = aTester.GetMessageId();
1770         }
1771 
1772         // merged cells
1773         SCCOL nMergeStartX = nStartCol;
1774         SCROW nMergeStartY = nStartRow;
1775         SCCOL nMergeEndX   = nEndCol;
1776         SCROW nMergeEndY   = nEndRow;
1777         pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1778         pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
1779 
1780         if ( nMergeStartX != nStartCol || nMergeStartY != nStartRow )
1781         {
1782             // Disallow deleting parts of a merged cell.
1783             // Deleting the start is allowed (merge is removed), so the end doesn't have to be checked.
1784 
1785             nErrorId = STR_MSSG_DELETECELLS_0;
1786         }
1787         if ( nMergeEndX != nEndCol || nMergeEndY != nEndRow )
1788         {
1789             // detect if the start of a merged cell is deleted, so the merge flags can be refreshed
1790 
1791             bNeedRefresh = sal_True;
1792         }
1793     }
1794 
1795     if ( nErrorId )
1796     {
1797         ErrorMessage( nErrorId );
1798         delete[] pRanges;
1799         return;
1800     }
1801 
1802     //  ausfuehren
1803 
1804     WaitObject aWait( GetFrameWin() );      // wichtig wegen TrackFormulas bei UpdateReference
1805 
1806     ScDocument* pUndoDoc = NULL;
1807     ScRefUndoData* pUndoData = NULL;
1808     if (bRecord)
1809     {
1810         pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1811         pUndoDoc->InitUndo( pDoc, nTab, nTab, !bRows, bRows );      // Zeilenhoehen
1812 
1813         pOneRange = pRanges;
1814         for (nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
1815         {
1816             SCCOLROW nStart = *(pOneRange++);
1817             SCCOLROW nEnd = *(pOneRange++);
1818             if (bRows)
1819                 pDoc->CopyToDocument( 0,nStart,nTab, MAXCOL,nEnd,nTab, IDF_ALL,sal_False,pUndoDoc );
1820             else
1821                 pDoc->CopyToDocument( static_cast<SCCOL>(nStart),0,nTab,
1822                         static_cast<SCCOL>(nEnd),MAXROW,nTab,
1823                         IDF_ALL,sal_False,pUndoDoc );
1824         }
1825 
1826                 //  alle Formeln wegen Referenzen
1827         SCTAB nTabCount = pDoc->GetTableCount();
1828         pUndoDoc->AddUndoTab( 0, nTabCount-1, sal_False, sal_False );
1829         pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA,sal_False,pUndoDoc );
1830 
1831         pUndoData = new ScRefUndoData( pDoc );
1832 
1833         pDoc->BeginDrawUndo();
1834     }
1835 
1836     pOneRange = &pRanges[2*nRangeCnt];      // rueckwaerts
1837     for (nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
1838     {
1839         SCCOLROW nEnd = *(--pOneRange);
1840         SCCOLROW nStart = *(--pOneRange);
1841 
1842         if (bRows)
1843             pDoc->DeleteRow( 0,nTab, MAXCOL,nTab, nStart, static_cast<SCSIZE>(nEnd-nStart+1) );
1844         else
1845             pDoc->DeleteCol( 0,nTab, MAXROW,nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
1846     }
1847 
1848     if (bNeedRefresh)
1849     {
1850         SCCOLROW nFirstStart = pRanges[0];
1851         SCCOL nStartCol = bRows ? 0 : static_cast<SCCOL>(nFirstStart);
1852         SCROW nStartRow = bRows ? static_cast<SCROW>(nFirstStart) : 0;
1853         SCCOL nEndCol = MAXCOL;
1854         SCROW nEndRow = MAXROW;
1855 
1856         pDoc->RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
1857         pDoc->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, sal_True );
1858     }
1859 
1860     if (bRecord)
1861     {
1862         pDocSh->GetUndoManager()->AddUndoAction(
1863             new ScUndoDeleteMulti( pDocSh, bRows, bNeedRefresh, nTab, pRanges, nRangeCnt,
1864                                     pUndoDoc, pUndoData ) );
1865     }
1866 
1867     if (!AdjustRowHeight(0, MAXROW))
1868     {
1869         if (bRows)
1870             pDocSh->PostPaint( 0,pRanges[0],nTab, MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_LEFT );
1871         else
1872             pDocSh->PostPaint( static_cast<SCCOL>(pRanges[0]),0,nTab,
1873                     MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_TOP );
1874     }
1875     aModificator.SetDocumentModified();
1876 
1877     CellContentChanged();
1878 
1879     //  #58106# Cursor direkt hinter den ersten geloeschten Bereich setzen
1880     SCCOL nCurX = GetViewData()->GetCurX();
1881     SCROW nCurY = GetViewData()->GetCurY();
1882     if ( bRows )
1883         nCurY = pRanges[0];
1884     else
1885         nCurX = static_cast<SCCOL>(pRanges[0]);
1886     SetCursor( nCurX, nCurY );
1887 
1888     delete[] pRanges;
1889 
1890     SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
1891 }
1892 
1893 //  Inhalte loeschen
1894 
1895 void ScViewFunc::DeleteContents( sal_uInt16 nFlags, sal_Bool bRecord )
1896 {
1897     // nur wegen Matrix nicht editierbar? Attribute trotzdem ok
1898     sal_Bool bOnlyNotBecauseOfMatrix;
1899     sal_Bool bEditable = SelectionEditable( &bOnlyNotBecauseOfMatrix );
1900     if ( !bEditable )
1901     {
1902         if ( !(bOnlyNotBecauseOfMatrix &&
1903                 ((nFlags & (IDF_ATTRIB | IDF_EDITATTR)) == nFlags)) )
1904         {
1905             ErrorMessage(bOnlyNotBecauseOfMatrix ? STR_MATRIXFRAGMENTERR : STR_PROTECTIONERR);
1906             return;
1907         }
1908     }
1909 
1910     ScRange aMarkRange;
1911     sal_Bool bSimple = sal_False;
1912 
1913     ScDocument* pDoc = GetViewData()->GetDocument();
1914     ScDocShell* pDocSh = GetViewData()->GetDocShell();
1915     ScMarkData aFuncMark( GetViewData()->GetMarkData() );       // local copy for UnmarkFiltered
1916     ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
1917 
1918     if (bRecord && !pDoc->IsUndoEnabled())
1919         bRecord = sal_False;
1920 
1921     ScDocShellModificator aModificator( *pDocSh );
1922 
1923     if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
1924     {
1925         aMarkRange.aStart.SetCol(GetViewData()->GetCurX());
1926         aMarkRange.aStart.SetRow(GetViewData()->GetCurY());
1927         aMarkRange.aStart.SetTab(GetViewData()->GetTabNo());
1928         aMarkRange.aEnd = aMarkRange.aStart;
1929         if ( pDoc->HasAttrib( aMarkRange, HASATTR_MERGED ) )
1930         {
1931 //          InitOwnBlockMode();
1932             aFuncMark.SetMarkArea( aMarkRange );
1933         }
1934         else
1935             bSimple = sal_True;
1936     }
1937 
1938     aFuncMark.SetMarking(sal_False);        // for MarkToMulti
1939     aFuncMark.MarkToSimple();           // before bMulti test below
1940 
1941     DBG_ASSERT( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() || bSimple, "delete what?" );
1942 
1943     ScDocument* pUndoDoc = NULL;
1944     sal_Bool bMulti = !bSimple && aFuncMark.IsMultiMarked();
1945     if (!bSimple)
1946     {
1947         aFuncMark.MarkToMulti();
1948         aFuncMark.GetMultiMarkArea( aMarkRange );
1949     }
1950     ScRange aExtendedRange(aMarkRange);
1951     if (!bSimple)
1952     {
1953         if ( pDoc->ExtendMerge( aExtendedRange, sal_True ) )
1954             bMulti = sal_False;
1955     }
1956 
1957     // keine Objekte auf geschuetzten Tabellen
1958     sal_Bool bObjects = sal_False;
1959     if ( nFlags & IDF_OBJECTS )
1960     {
1961         bObjects = sal_True;
1962         SCTAB nTabCount = pDoc->GetTableCount();
1963         for (SCTAB nTab=0; nTab<nTabCount; nTab++)
1964             if (aFuncMark.GetTableSelect(nTab) && pDoc->IsTabProtected(nTab))
1965                 bObjects = sal_False;
1966     }
1967 
1968     sal_uInt16 nExtFlags = 0;       // extra flags are needed only if attributes are deleted
1969     if ( nFlags & IDF_ATTRIB )
1970         pDocSh->UpdatePaintExt( nExtFlags, aMarkRange );
1971 
1972     //  Reihenfolge:
1973     //  1) BeginDrawUndo
1974     //  2) Objekte loeschen (DrawUndo wird gefuellt)
1975     //  3) Inhalte fuer Undo kopieren
1976     //  4) Inhalte loeschen
1977     //  5) Undo-Aktion anlegen
1978 
1979     sal_Bool bDrawUndo = bObjects || ( nFlags & IDF_NOTE );     // needed for shown notes
1980     if ( bDrawUndo && bRecord )
1981         pDoc->BeginDrawUndo();
1982 
1983     if (bObjects)
1984     {
1985         if (bMulti)
1986             pDoc->DeleteObjectsInSelection( aFuncMark );
1987         else
1988             pDoc->DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
1989 /*!*/                                  aMarkRange.aEnd.Col(),   aMarkRange.aEnd.Row(),
1990                                        aFuncMark );
1991     }
1992 
1993     if ( bRecord )
1994     {
1995         pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1996         SCTAB nTab = aMarkRange.aStart.Tab();
1997         pUndoDoc->InitUndo( pDoc, nTab, nTab );
1998         SCTAB nTabCount = pDoc->GetTableCount();
1999         for (SCTAB i=0; i<nTabCount; i++)
2000             if (i != nTab && aFuncMark.GetTableSelect(i))
2001                 pUndoDoc->AddUndoTab( i, i );
2002         ScRange aCopyRange = aExtendedRange;
2003         aCopyRange.aStart.SetTab(0);
2004         aCopyRange.aEnd.SetTab(nTabCount-1);
2005 
2006         //  bei "Format/Standard" alle Attribute kopieren, weil CopyToDocument
2007         //  nur mit IDF_HARDATTR zu langsam ist:
2008         sal_uInt16 nUndoDocFlags = nFlags;
2009         if (nFlags & IDF_ATTRIB)
2010             nUndoDocFlags |= IDF_ATTRIB;
2011         if (nFlags & IDF_EDITATTR)          // Edit-Engine-Attribute
2012             nUndoDocFlags |= IDF_STRING;    // -> Zellen werden geaendert
2013         if (nFlags & IDF_NOTE)
2014             nUndoDocFlags |= IDF_CONTENTS;  // #68795# copy all cells with their notes
2015         // do not copy note captions to undo document
2016         nUndoDocFlags |= IDF_NOCAPTIONS;
2017         pDoc->CopyToDocument( aCopyRange, nUndoDocFlags, bMulti, pUndoDoc, &aFuncMark );
2018     }
2019 
2020     HideAllCursors();   // falls Zusammenfassung aufgehoben wird
2021     if (bSimple)
2022         pDoc->DeleteArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
2023                           aMarkRange.aEnd.Col(),   aMarkRange.aEnd.Row(),
2024                           aFuncMark, nFlags );
2025     else
2026     {
2027         pDoc->DeleteSelection( nFlags, aFuncMark );
2028 //       aFuncMark.MarkToSimple();
2029     }
2030 
2031     if ( bRecord )
2032     {
2033         pDocSh->GetUndoManager()->AddUndoAction(
2034             new ScUndoDeleteContents( pDocSh, aFuncMark, aExtendedRange,
2035                                       pUndoDoc, bMulti, nFlags, bDrawUndo ) );
2036     }
2037 
2038     if (!AdjustRowHeight( aExtendedRange.aStart.Row(), aExtendedRange.aEnd.Row() ))
2039         pDocSh->PostPaint( aExtendedRange, PAINT_GRID, nExtFlags );
2040 
2041     pDocSh->UpdateOle(GetViewData());
2042 
2043     // #i97876# Spreadsheet data changes are not notified
2044     ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
2045     if ( pModelObj && pModelObj->HasChangesListeners() )
2046     {
2047         ScRangeList aChangeRanges;
2048         if ( bSimple )
2049         {
2050             aChangeRanges.Append( aMarkRange );
2051         }
2052         else
2053         {
2054             aFuncMark.FillRangeListWithMarks( &aChangeRanges, sal_False );
2055         }
2056         pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "cell-change" ) ), aChangeRanges );
2057     }
2058 
2059     aModificator.SetDocumentModified();
2060     CellContentChanged();
2061     ShowAllCursors();
2062 
2063     if ( nFlags & IDF_ATTRIB )
2064     {
2065         if ( nFlags & IDF_CONTENTS )
2066             ForgetFormatArea();
2067         else
2068             StartFormatArea();              // Attribute loeschen ist auch Attributierung
2069     }
2070 }
2071 
2072 //  Spaltenbreiten/Zeilenhoehen (ueber Header) - Undo OK
2073 
2074 void ScViewFunc::SetWidthOrHeight( sal_Bool bWidth, SCCOLROW nRangeCnt, SCCOLROW* pRanges,
2075                                     ScSizeMode eMode, sal_uInt16 nSizeTwips,
2076                                     sal_Bool bRecord, sal_Bool bPaint, ScMarkData* pMarkData )
2077 {
2078     if (nRangeCnt == 0)
2079         return;
2080 
2081     // use view's mark if none specified
2082     if ( !pMarkData )
2083         pMarkData = &GetViewData()->GetMarkData();
2084 
2085     ScDocShell* pDocSh = GetViewData()->GetDocShell();
2086     ScDocument* pDoc = pDocSh->GetDocument();
2087     SCTAB nTabCount = pDoc->GetTableCount();
2088     SCTAB nFirstTab = pMarkData->GetFirstSelected();
2089     SCTAB nCurTab = GetViewData()->GetTabNo();
2090     SCTAB nTab;
2091     if (bRecord && !pDoc->IsUndoEnabled())
2092         bRecord = sal_False;
2093 
2094     ScDocShellModificator aModificator( *pDocSh );
2095 
2096     sal_Bool bAllowed = sal_True;
2097     for (nTab=0; nTab<nTabCount && bAllowed; nTab++)
2098         if (pMarkData->GetTableSelect(nTab))
2099         {
2100             for ( SCCOLROW i=0; i<nRangeCnt && bAllowed; i++ )
2101             {
2102                 sal_Bool bOnlyMatrix;
2103                 if (bWidth)
2104                     bAllowed = pDoc->IsBlockEditable( nTab,
2105                             static_cast<SCCOL>(pRanges[2*i]),0,
2106                             static_cast<SCCOL>(pRanges[2*i+1]),MAXROW,
2107                             &bOnlyMatrix ) || bOnlyMatrix;
2108                 else
2109                     bAllowed = pDoc->IsBlockEditable( nTab, 0,pRanges[2*i],
2110                             MAXCOL,pRanges[2*i+1], &bOnlyMatrix ) ||
2111                         bOnlyMatrix;
2112             }
2113         }
2114     if ( !bAllowed )
2115     {
2116         ErrorMessage(STR_PROTECTIONERR);
2117         return;
2118     }
2119 
2120     SCCOLROW nStart = pRanges[0];
2121     SCCOLROW nEnd = pRanges[2*nRangeCnt-1];
2122 
2123     sal_Bool bFormula = sal_False;
2124     if ( eMode == SC_SIZE_OPTIMAL )
2125     {
2126         const ScViewOptions& rOpts = GetViewData()->GetOptions();
2127         bFormula = rOpts.GetOption( VOPT_FORMULAS );
2128     }
2129 
2130     ScDocument*     pUndoDoc = NULL;
2131     ScOutlineTable* pUndoTab = NULL;
2132     SCCOLROW*       pUndoRanges = NULL;
2133 
2134     if ( bRecord )
2135     {
2136         pDoc->BeginDrawUndo();                          // Drawing Updates
2137 
2138         pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2139         for (nTab=0; nTab<nTabCount; nTab++)
2140             if (pMarkData->GetTableSelect(nTab))
2141             {
2142                 if (bWidth)
2143                 {
2144                     if ( nTab == nFirstTab )
2145                         pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_False );
2146                     else
2147                         pUndoDoc->AddUndoTab( nTab, nTab, sal_True, sal_False );
2148                     pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab,
2149                             static_cast<SCCOL>(nEnd), MAXROW, nTab, IDF_NONE,
2150                             sal_False, pUndoDoc );
2151                 }
2152                 else
2153                 {
2154                     if ( nTab == nFirstTab )
2155                         pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_False, sal_True );
2156                     else
2157                         pUndoDoc->AddUndoTab( nTab, nTab, sal_False, sal_True );
2158                     pDoc->CopyToDocument( 0, nStart, nTab, MAXCOL, nEnd, nTab, IDF_NONE, sal_False, pUndoDoc );
2159                 }
2160             }
2161 
2162         pUndoRanges = new SCCOLROW[ 2*nRangeCnt ];
2163         memmove( pUndoRanges, pRanges, 2*nRangeCnt*sizeof(SCCOLROW) );
2164 
2165         //! outlines from all tables?
2166         ScOutlineTable* pTable = pDoc->GetOutlineTable( nCurTab );
2167         if (pTable)
2168             pUndoTab = new ScOutlineTable( *pTable );
2169     }
2170 
2171     if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2172         pMarkData->MarkToMulti();
2173 
2174     sal_Bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
2175     sal_Bool bOutline = sal_False;
2176 
2177     for (nTab=0; nTab<nTabCount; nTab++)
2178         if (pMarkData->GetTableSelect(nTab))
2179         {
2180             const SCCOLROW* pTabRanges = pRanges;
2181 
2182             pDoc->IncSizeRecalcLevel( nTab );       // nicht fuer jede Spalte einzeln
2183             pDoc->InitializeNoteCaptions( nTab );
2184             for (SCCOLROW nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
2185             {
2186                 SCCOLROW nStartNo = *(pTabRanges++);
2187                 SCCOLROW nEndNo = *(pTabRanges++);
2188 
2189                 if ( !bWidth )                      // Hoehen immer blockweise
2190                 {
2191                     if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2192                     {
2193                         sal_Bool bAll = ( eMode==SC_SIZE_OPTIMAL );
2194                         if (!bAll)
2195                         {
2196                             //  fuer alle eingeblendeten CR_MANUALSIZE loeschen,
2197                             //  dann SetOptimalHeight mit bShrink = FALSE
2198                             for (SCROW nRow = nStartNo; nRow <= nEndNo; ++nRow)
2199                             {
2200                                 SCROW nLastRow = nRow;
2201                                 if (pDoc->RowHidden(nRow, nTab, NULL, &nLastRow))
2202                                 {
2203                                     nRow = nLastRow;
2204                                     continue;
2205                                 }
2206 
2207                                 sal_uInt8 nOld = pDoc->GetRowFlags(nRow, nTab);
2208                                 if (nOld & CR_MANUALSIZE)
2209                                     pDoc->SetRowFlags(nRow, nTab, nOld & ~CR_MANUALSIZE);
2210                             }
2211                         }
2212 
2213                         double nPPTX = GetViewData()->GetPPTX();
2214                         double nPPTY = GetViewData()->GetPPTY();
2215                         Fraction aZoomX = GetViewData()->GetZoomX();
2216                         Fraction aZoomY = GetViewData()->GetZoomY();
2217 
2218                         ScSizeDeviceProvider aProv(pDocSh);
2219                         if (aProv.IsPrinter())
2220                         {
2221                             nPPTX = aProv.GetPPTX();
2222                             nPPTY = aProv.GetPPTY();
2223                             aZoomX = aZoomY = Fraction( 1, 1 );
2224                         }
2225 
2226                         pDoc->SetOptimalHeight( nStartNo, nEndNo, nTab, nSizeTwips, aProv.GetDevice(),
2227                                                     nPPTX, nPPTY, aZoomX, aZoomY, bAll );
2228                         if (bAll)
2229                             pDoc->ShowRows( nStartNo, nEndNo, nTab, sal_True );
2230 
2231                         //  Manual-Flag wird bei bAll=sal_True schon in SetOptimalHeight gesetzt
2232                         //  (an bei Extra-Height, sonst aus).
2233                     }
2234                     else if ( eMode==SC_SIZE_DIRECT )
2235                     {
2236                         if (nSizeTwips)
2237                         {
2238                             pDoc->SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
2239                             pDoc->SetManualHeight( nStartNo, nEndNo, nTab, sal_True );          // height was set manually
2240                         }
2241                         pDoc->ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
2242                     }
2243                     else if ( eMode==SC_SIZE_SHOW )
2244                     {
2245                         pDoc->ShowRows( nStartNo, nEndNo, nTab, sal_True );
2246                     }
2247                 }
2248                 else                                // Spaltenbreiten
2249                 {
2250                     for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
2251                     {
2252                         if ( eMode != SC_SIZE_VISOPT || !pDoc->ColHidden(nCol, nTab) )
2253                         {
2254                             sal_uInt16 nThisSize = nSizeTwips;
2255 
2256                             if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
2257                                 nThisSize = nSizeTwips + GetOptimalColWidth( nCol, nTab, bFormula );
2258                             if ( nThisSize )
2259                                 pDoc->SetColWidth( nCol, nTab, nThisSize );
2260 
2261                             pDoc->ShowCol( nCol, nTab, bShow );
2262                         }
2263                     }
2264                 }
2265 
2266                                     //  Outline anpassen
2267 
2268                 if (bWidth)
2269                 {
2270                     if ( pDoc->UpdateOutlineCol( static_cast<SCCOL>(nStartNo),
2271                                 static_cast<SCCOL>(nEndNo), nTab, bShow ) )
2272                         bOutline = sal_True;
2273                 }
2274                 else
2275                 {
2276                     if ( pDoc->UpdateOutlineRow( nStartNo, nEndNo, nTab, bShow ) )
2277                         bOutline = sal_True;
2278                 }
2279             }
2280             pDoc->DecSizeRecalcLevel( nTab );       // nicht fuer jede Spalte einzeln
2281         }
2282 
2283 
2284     if (!bOutline)
2285         DELETEZ(pUndoTab);
2286 
2287     if (bRecord)
2288     {
2289         pDocSh->GetUndoManager()->AddUndoAction(
2290             new ScUndoWidthOrHeight( pDocSh, *pMarkData,
2291                                      nStart, nCurTab, nEnd, nCurTab,
2292                                      pUndoDoc, nRangeCnt, pUndoRanges,
2293                                      pUndoTab, eMode, nSizeTwips, bWidth ) );
2294     }
2295 
2296     for (nTab=0; nTab<nTabCount; nTab++)
2297         if (pMarkData->GetTableSelect(nTab))
2298             pDoc->UpdatePageBreaks( nTab );
2299 
2300     GetViewData()->GetView()->UpdateScrollBars();
2301 
2302     if (bPaint)
2303     {
2304         HideCursor();
2305 
2306         for (nTab=0; nTab<nTabCount; nTab++)
2307             if (pMarkData->GetTableSelect(nTab))
2308             {
2309                 if (bWidth)
2310                 {
2311                     if (pDoc->HasAttrib( static_cast<SCCOL>(nStart),0,nTab,
2312                                 static_cast<SCCOL>(nEnd),MAXROW,nTab,
2313                                 HASATTR_MERGED | HASATTR_OVERLAPPED ))
2314                         nStart = 0;
2315                     if (nStart > 0)             // weiter oben anfangen wegen Linien und Cursor
2316                         --nStart;
2317                     pDocSh->PostPaint( static_cast<SCCOL>(nStart), 0, nTab,
2318                             MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_TOP );
2319                 }
2320                 else
2321                 {
2322                     if (pDoc->HasAttrib( 0,nStart,nTab, MAXCOL,nEnd,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
2323                         nStart = 0;
2324                     if (nStart != 0)
2325                         --nStart;
2326                     pDocSh->PostPaint( 0, nStart, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_LEFT );
2327                 }
2328             }
2329 
2330         pDocSh->UpdateOle(GetViewData());
2331         aModificator.SetDocumentModified();
2332 
2333         ShowCursor();
2334     }
2335 
2336     // #i97876# Spreadsheet data changes are not notified
2337     if ( bWidth )
2338     {
2339         ScModelObj* pModelObj = ScModelObj::getImplementation( pDocSh->GetModel() );
2340         if ( pModelObj && pModelObj->HasChangesListeners() )
2341         {
2342             ScRangeList aChangeRanges;
2343             for ( nTab = 0; nTab < nTabCount; ++nTab )
2344             {
2345                 if ( pMarkData->GetTableSelect( nTab ) )
2346                 {
2347                     const SCCOLROW* pTabRanges = pRanges;
2348                     for ( SCCOLROW nRange = 0; nRange < nRangeCnt; ++nRange )
2349                     {
2350                         SCCOL nStartCol = static_cast< SCCOL >( *(pTabRanges++) );
2351                         SCCOL nEndCol = static_cast< SCCOL >( *(pTabRanges++) );
2352                         for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
2353                         {
2354                             aChangeRanges.Append( ScRange( nCol, 0, nTab ) );
2355                         }
2356                     }
2357                 }
2358             }
2359             pModelObj->NotifyChanges( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "column-resize" ) ), aChangeRanges );
2360         }
2361     }
2362 }
2363 
2364 //  Spaltenbreiten/Zeilenhoehen (ueber Blockmarken)
2365 
2366 void ScViewFunc::SetMarkedWidthOrHeight( sal_Bool bWidth, ScSizeMode eMode, sal_uInt16 nSizeTwips,
2367                                         sal_Bool bRecord, sal_Bool bPaint )
2368 {
2369     ScMarkData& rMark = GetViewData()->GetMarkData();
2370 
2371     rMark.MarkToMulti();
2372     if (!rMark.IsMultiMarked())
2373     {
2374         SCCOL nCol = GetViewData()->GetCurX();
2375         SCROW nRow = GetViewData()->GetCurY();
2376         SCTAB nTab = GetViewData()->GetTabNo();
2377         DoneBlockMode();
2378         InitOwnBlockMode();
2379         rMark.SetMultiMarkArea( ScRange( nCol,nRow,nTab ), sal_True );
2380         MarkDataChanged();
2381     }
2382 
2383     SCCOLROW* pRanges = new SCCOLROW[MAXCOLROWCOUNT];
2384     SCCOLROW nRangeCnt = 0;
2385 
2386     if ( bWidth )
2387         nRangeCnt = rMark.GetMarkColumnRanges( pRanges );
2388     else
2389         nRangeCnt = rMark.GetMarkRowRanges( pRanges );
2390 
2391     SetWidthOrHeight( bWidth, nRangeCnt, pRanges, eMode, nSizeTwips, bRecord, bPaint );
2392 
2393     delete[] pRanges;
2394     rMark.MarkToSimple();
2395 }
2396 
2397 void ScViewFunc::ModifyCellSize( ScDirection eDir, sal_Bool bOptimal )
2398 {
2399     //! Schrittweiten einstellbar
2400     //  Schrittweite ist auch Minimum
2401     sal_uInt16 nStepX = STD_COL_WIDTH / 5;
2402     sal_uInt16 nStepY = ScGlobal::nStdRowHeight;
2403 
2404     ScModule* pScMod = SC_MOD();
2405     sal_Bool bAnyEdit = pScMod->IsInputMode();
2406     SCCOL nCol = GetViewData()->GetCurX();
2407     SCROW nRow = GetViewData()->GetCurY();
2408     SCTAB nTab = GetViewData()->GetTabNo();
2409     ScDocShell* pDocSh = GetViewData()->GetDocShell();
2410     ScDocument* pDoc = pDocSh->GetDocument();
2411 
2412     sal_Bool bAllowed, bOnlyMatrix;
2413     if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2414         bAllowed = pDoc->IsBlockEditable( nTab, nCol,0, nCol,MAXROW, &bOnlyMatrix );
2415     else
2416         bAllowed = pDoc->IsBlockEditable( nTab, 0,nRow, MAXCOL,nRow, &bOnlyMatrix );
2417     if ( !bAllowed && !bOnlyMatrix )
2418     {
2419         ErrorMessage(STR_PROTECTIONERR);
2420         return;
2421     }
2422 
2423     HideAllCursors();
2424 
2425     sal_uInt16 nWidth = pDoc->GetColWidth( nCol, nTab );
2426     sal_uInt16 nHeight = pDoc->GetRowHeight( nRow, nTab );
2427     SCCOLROW nRange[2];
2428     if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
2429     {
2430         if (bOptimal)               // Breite dieser einen Zelle
2431         {
2432             if ( bAnyEdit )
2433             {
2434                 //  beim Editieren die aktuelle Breite der Eingabe
2435                 ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData()->GetViewShell() );
2436                 if (pHdl)
2437                 {
2438                     long nEdit = pHdl->GetTextSize().Width();       // in 1/100mm
2439 
2440                     const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
2441                     const SvxMarginItem& rMItem =
2442                             (const SvxMarginItem&)pPattern->GetItem(ATTR_MARGIN);
2443                     sal_uInt16 nMargin = rMItem.GetLeftMargin() + rMItem.GetRightMargin();
2444                     if ( ((const SvxHorJustifyItem&) pPattern->
2445                             GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_LEFT )
2446                         nMargin = sal::static_int_cast<sal_uInt16>(
2447                             nMargin + ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue() );
2448 
2449                     nWidth = (sal_uInt16)(nEdit * pDocSh->GetOutputFactor() / HMM_PER_TWIPS)
2450                                 + nMargin + STD_EXTRA_WIDTH;
2451                 }
2452             }
2453             else
2454             {
2455                 double nPPTX = GetViewData()->GetPPTX();
2456                 double nPPTY = GetViewData()->GetPPTY();
2457                 Fraction aZoomX = GetViewData()->GetZoomX();
2458                 Fraction aZoomY = GetViewData()->GetZoomY();
2459 
2460                 ScSizeDeviceProvider aProv(pDocSh);
2461                 if (aProv.IsPrinter())
2462                 {
2463                     nPPTX = aProv.GetPPTX();
2464                     nPPTY = aProv.GetPPTY();
2465                     aZoomX = aZoomY = Fraction( 1, 1 );
2466                 }
2467 
2468                 long nPixel = pDoc->GetNeededSize( nCol, nRow, nTab, aProv.GetDevice(),
2469                                             nPPTX, nPPTY, aZoomX, aZoomY, sal_True );
2470                 sal_uInt16 nTwips = (sal_uInt16)( nPixel / nPPTX );
2471                 if (nTwips != 0)
2472                     nWidth = nTwips + STD_EXTRA_WIDTH;
2473                 else
2474                     nWidth = STD_COL_WIDTH;
2475             }
2476         }
2477         else                        // vergroessern / verkleinern
2478         {
2479             if ( eDir == DIR_RIGHT )
2480                 nWidth = sal::static_int_cast<sal_uInt16>( nWidth + nStepX );
2481             else if ( nWidth > nStepX )
2482                 nWidth = sal::static_int_cast<sal_uInt16>( nWidth - nStepX );
2483             if ( nWidth < nStepX ) nWidth = nStepX;
2484             if ( nWidth > MAX_COL_WIDTH ) nWidth = MAX_COL_WIDTH;
2485         }
2486         nRange[0] = nRange[1] = nCol;
2487         SetWidthOrHeight( sal_True, 1, nRange, SC_SIZE_DIRECT, nWidth );
2488 
2489         //  hier bei Breite auch Hoehe anpassen (nur die eine Zeile)
2490 
2491         if (!bAnyEdit)
2492         {
2493             const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
2494             sal_Bool bNeedHeight =
2495                     ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue() ||
2496                     ((const SvxHorJustifyItem&)pPattern->
2497                         GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK;
2498             if (bNeedHeight)
2499                 AdjustRowHeight( nRow, nRow );
2500         }
2501     }
2502     else
2503     {
2504         ScSizeMode eMode;
2505         if (bOptimal)
2506         {
2507             eMode = SC_SIZE_OPTIMAL;
2508             nHeight = 0;
2509         }
2510         else
2511         {
2512             eMode = SC_SIZE_DIRECT;
2513             if ( eDir == DIR_BOTTOM )
2514                 nHeight = sal::static_int_cast<sal_uInt16>( nHeight + nStepY );
2515             else if ( nHeight > nStepY )
2516                 nHeight = sal::static_int_cast<sal_uInt16>( nHeight - nStepY );
2517             if ( nHeight < nStepY ) nHeight = nStepY;
2518             if ( nHeight > MAX_COL_HEIGHT ) nHeight = MAX_COL_HEIGHT;
2519             //! MAX_COL_HEIGHT umbenennen in MAX_ROW_HEIGHT in global.hxx !!!!!!
2520         }
2521         nRange[0] = nRange[1] = nRow;
2522         SetWidthOrHeight( sal_False, 1, nRange, eMode, nHeight );
2523     }
2524 
2525     if ( bAnyEdit )
2526     {
2527         UpdateEditView();
2528         if ( pDoc->HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_NEEDHEIGHT ) )
2529         {
2530             ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData()->GetViewShell() );
2531             if (pHdl)
2532                 pHdl->SetModified();    // damit bei Enter die Hoehe angepasst wird
2533         }
2534     }
2535 
2536     ShowAllCursors();
2537 }
2538 
2539 void ScViewFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
2540 {
2541     if (nTab == TABLEID_DOC)
2542         return;
2543 
2544     ScMarkData& rMark = GetViewData()->GetMarkData();
2545     ScDocShell* pDocSh = GetViewData()->GetDocShell();
2546     ScDocument* pDoc = pDocSh->GetDocument();
2547     ScDocFunc aFunc(*pDocSh);
2548     bool bUndo(pDoc->IsUndoEnabled());
2549 
2550     //  modifying several tables is handled here
2551 
2552     if (bUndo)
2553     {
2554         String aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
2555         pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2556     }
2557 
2558     SCTAB nCount = pDocSh->GetDocument()->GetTableCount();
2559     for ( SCTAB i=0; i<nCount; i++ )
2560         if ( rMark.GetTableSelect(i) )
2561             aFunc.ProtectSheet(i, rProtect);
2562 
2563     if (bUndo)
2564         pDocSh->GetUndoManager()->LeaveListAction();
2565 
2566     UpdateLayerLocks();         //! broadcast to all views
2567 }
2568 
2569 void ScViewFunc::Protect( SCTAB nTab, const String& rPassword )
2570 {
2571     ScMarkData& rMark = GetViewData()->GetMarkData();
2572     ScDocShell* pDocSh = GetViewData()->GetDocShell();
2573     ScDocument* pDoc = pDocSh->GetDocument();
2574     ScDocFunc aFunc(*pDocSh);
2575     sal_Bool bUndo(pDoc->IsUndoEnabled());
2576 
2577     if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
2578         aFunc.Protect( nTab, rPassword, sal_False );
2579     else
2580     {
2581         //  modifying several tables is handled here
2582 
2583         if (bUndo)
2584         {
2585             String aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
2586             pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2587         }
2588 
2589         SCTAB nCount = pDocSh->GetDocument()->GetTableCount();
2590         for ( SCTAB i=0; i<nCount; i++ )
2591             if ( rMark.GetTableSelect(i) )
2592                 aFunc.Protect( i, rPassword, sal_False );
2593 
2594         if (bUndo)
2595             pDocSh->GetUndoManager()->LeaveListAction();
2596     }
2597 
2598     UpdateLayerLocks();         //! broadcast to all views
2599 }
2600 
2601 sal_Bool ScViewFunc::Unprotect( SCTAB nTab, const String& rPassword )
2602 {
2603     ScMarkData& rMark = GetViewData()->GetMarkData();
2604     ScDocShell* pDocSh = GetViewData()->GetDocShell();
2605     ScDocument* pDoc = pDocSh->GetDocument();
2606     ScDocFunc aFunc(*pDocSh);
2607     sal_Bool bChanged = sal_False;
2608     sal_Bool bUndo (pDoc->IsUndoEnabled());
2609 
2610     if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
2611         bChanged = aFunc.Unprotect( nTab, rPassword, sal_False );
2612     else
2613     {
2614         //  modifying several tables is handled here
2615 
2616         if (bUndo)
2617         {
2618             String aUndo = ScGlobal::GetRscString( STR_UNDO_UNPROTECT_TAB );
2619             pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
2620         }
2621 
2622         SCTAB nCount = pDocSh->GetDocument()->GetTableCount();
2623         for ( SCTAB i=0; i<nCount; i++ )
2624             if ( rMark.GetTableSelect(i) )
2625                 if ( aFunc.Unprotect( i, rPassword, sal_False ) )
2626                     bChanged = sal_True;
2627 
2628         if (bUndo)
2629             pDocSh->GetUndoManager()->LeaveListAction();
2630     }
2631 
2632     if (bChanged)
2633         UpdateLayerLocks();     //! broadcast to all views
2634 
2635     return bChanged;
2636 }
2637 
2638 void ScViewFunc::SetNoteText( const ScAddress& rPos, const String& rNoteText )
2639 {
2640     GetViewData()->GetDocShell()->GetDocFunc().SetNoteText( rPos, rNoteText, sal_False );
2641 }
2642 
2643 void ScViewFunc::ReplaceNote( const ScAddress& rPos, const String& rNoteText, const String* pAuthor, const String* pDate )
2644 {
2645     GetViewData()->GetDocShell()->GetDocFunc().ReplaceNote( rPos, rNoteText, pAuthor, pDate, sal_False );
2646 }
2647 
2648 void ScViewFunc::SetNumberFormat( short nFormatType, sal_uLong nAdd )
2649 {
2650     // nur wegen Matrix nicht editierbar? Attribute trotzdem ok
2651     sal_Bool bOnlyNotBecauseOfMatrix;
2652     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2653     {
2654         ErrorMessage(STR_PROTECTIONERR);
2655         return;
2656     }
2657 
2658     sal_uInt32          nNumberFormat = 0;
2659     ScViewData*         pViewData = GetViewData();
2660     ScDocument*         pDoc = pViewData->GetDocument();
2661     SvNumberFormatter*  pNumberFormatter = pDoc->GetFormatTable();
2662     LanguageType        eLanguage = ScGlobal::eLnge;
2663     ScPatternAttr       aNewAttrs( pDoc->GetPool() );
2664 
2665     //  #67936# always take language from cursor position, even if there is a selection
2666 
2667     sal_uInt32 nCurrentNumberFormat;
2668     pDoc->GetNumberFormat( pViewData->GetCurX(),
2669                            pViewData->GetCurY(),
2670                            pViewData->GetTabNo(),
2671                            nCurrentNumberFormat );
2672     const SvNumberformat* pEntry = pNumberFormatter->GetEntry( nCurrentNumberFormat );
2673     if (pEntry)
2674         eLanguage = pEntry->GetLanguage();      // sonst ScGlobal::eLnge behalten
2675 
2676     nNumberFormat = pNumberFormatter->GetStandardFormat( nFormatType, eLanguage ) + nAdd;
2677 
2678     SfxItemSet& rSet = aNewAttrs.GetItemSet();
2679     rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2680     //  ATTR_LANGUAGE_FORMAT nicht
2681     ApplySelectionPattern( aNewAttrs, sal_True );
2682 }
2683 
2684 void ScViewFunc::SetNumFmtByStr( const String& rCode )
2685 {
2686     // nur wegen Matrix nicht editierbar? Attribute trotzdem ok
2687     sal_Bool bOnlyNotBecauseOfMatrix;
2688     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2689     {
2690         ErrorMessage(STR_PROTECTIONERR);
2691         return;
2692     }
2693 
2694     ScViewData*         pViewData = GetViewData();
2695     ScDocument*         pDoc = pViewData->GetDocument();
2696     SvNumberFormatter*  pFormatter = pDoc->GetFormatTable();
2697 
2698     //  Sprache immer von Cursorposition
2699 
2700     sal_uInt32 nCurrentNumberFormat;
2701     pDoc->GetNumberFormat( pViewData->GetCurX(), pViewData->GetCurY(),
2702                            pViewData->GetTabNo(), nCurrentNumberFormat );
2703     const SvNumberformat* pEntry = pFormatter->GetEntry( nCurrentNumberFormat );
2704     LanguageType eLanguage = pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge;
2705 
2706     //  Index fuer String bestimmen
2707 
2708     sal_Bool bOk = sal_True;
2709     sal_uInt32 nNumberFormat = pFormatter->GetEntryKey( rCode, eLanguage );
2710     if ( nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
2711     {
2712         //  neu eintragen
2713 
2714         String      aFormat = rCode;    // wird veraendert
2715         xub_StrLen  nErrPos = 0;
2716         short       nType   = 0;        //! ???
2717         bOk = pFormatter->PutEntry( aFormat, nErrPos, nType, nNumberFormat, eLanguage );
2718     }
2719 
2720     if ( bOk )          // gueltiges Format?
2721     {
2722         ScPatternAttr aNewAttrs( pDoc->GetPool() );
2723         SfxItemSet& rSet = aNewAttrs.GetItemSet();
2724         rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
2725         rSet.Put( SvxLanguageItem( eLanguage, ATTR_LANGUAGE_FORMAT ) );
2726         ApplySelectionPattern( aNewAttrs, sal_True );
2727     }
2728 
2729     //! sonst Fehler zuerueckgeben / Meldung ausgeben ???
2730 }
2731 
2732 void ScViewFunc::ChangeNumFmtDecimals( sal_Bool bIncrement )
2733 {
2734     // nur wegen Matrix nicht editierbar? Attribute trotzdem ok
2735     sal_Bool bOnlyNotBecauseOfMatrix;
2736     if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
2737     {
2738         ErrorMessage(STR_PROTECTIONERR);
2739         return;
2740     }
2741 
2742     ScDocument*         pDoc = GetViewData()->GetDocument();
2743     SvNumberFormatter*  pFormatter = pDoc->GetFormatTable();
2744 
2745     SCCOL nCol = GetViewData()->GetCurX();
2746     SCROW nRow = GetViewData()->GetCurY();
2747     SCTAB nTab = GetViewData()->GetTabNo();
2748 
2749     sal_uInt32 nOldFormat;
2750     pDoc->GetNumberFormat( nCol, nRow, nTab, nOldFormat );
2751     const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
2752     if (!pOldEntry)
2753     {
2754         DBG_ERROR("Zahlformat nicht gefunden !!!");
2755         return;
2756     }
2757 
2758     //  was haben wir denn da?
2759 
2760     sal_uInt32 nNewFormat = nOldFormat;
2761     sal_Bool bError = sal_False;
2762 
2763     LanguageType eLanguage = pOldEntry->GetLanguage();
2764     sal_Bool bThousand, bNegRed;
2765     sal_uInt16 nPrecision, nLeading;
2766     pOldEntry->GetFormatSpecialInfo( bThousand, bNegRed, nPrecision, nLeading );
2767 
2768     short nOldType = pOldEntry->GetType();
2769     if ( 0 == ( nOldType & (
2770                 NUMBERFORMAT_NUMBER |  NUMBERFORMAT_CURRENCY | NUMBERFORMAT_PERCENT ) ) )
2771     {
2772         //  Datum, Zeit, Bruch, logisch, Text kann nicht angepasst werden
2773         //! bei Wisssenschaftlich kann es der Numberformatter auch nicht
2774         bError = sal_True;
2775     }
2776 
2777     //! Das SvNumberformat hat einen Member bStandard, verraet ihn aber nicht
2778     sal_Bool bWasStandard = ( nOldFormat == pFormatter->GetStandardIndex( eLanguage ) );
2779     if (bWasStandard)
2780     {
2781         //  bei "Standard" die Nachkommastellen abhaengig vom Zellinhalt
2782         //  0 bei leer oder Text -> keine Nachkommastellen
2783         double nVal = pDoc->GetValue( ScAddress( nCol, nRow, nTab ) );
2784 
2785         //  Die Wege des Numberformatters sind unergruendlich, darum ausprobieren:
2786         String aOut;
2787         Color* pCol;
2788         ((SvNumberformat*)pOldEntry)->GetOutputString( nVal, aOut, &pCol );
2789 
2790         nPrecision = 0;
2791         // 'E' fuer Exponential ist fest im Numberformatter
2792         if ( aOut.Search('E') != STRING_NOTFOUND )
2793             bError = sal_True;                              // Exponential nicht veraendern
2794         else
2795         {
2796             String aDecSep( pFormatter->GetFormatDecimalSep( nOldFormat ) );
2797             xub_StrLen nPos = aOut.Search( aDecSep );
2798             if ( nPos != STRING_NOTFOUND )
2799                 nPrecision = aOut.Len() - nPos - aDecSep.Len();
2800             // sonst 0 behalten
2801         }
2802     }
2803 
2804     if (!bError)
2805     {
2806         if (bIncrement)
2807         {
2808             if (nPrecision<20)
2809                 ++nPrecision;           // erhoehen
2810             else
2811                 bError = sal_True;          // 20 ist Maximum
2812         }
2813         else
2814         {
2815             if (nPrecision)
2816                 --nPrecision;           // vermindern
2817             else
2818                 bError = sal_True;          // weniger als 0 geht nicht
2819         }
2820     }
2821 
2822     if (!bError)
2823     {
2824         String aNewPicture;
2825         pFormatter->GenerateFormat( aNewPicture, nOldFormat, eLanguage,
2826                                     bThousand, bNegRed, nPrecision, nLeading );
2827 
2828         nNewFormat = pFormatter->GetEntryKey( aNewPicture, eLanguage );
2829         if ( nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
2830         {
2831             xub_StrLen nErrPos = 0;
2832             short nNewType = 0;
2833             sal_Bool bOk = pFormatter->PutEntry( aNewPicture, nErrPos,
2834                                                 nNewType, nNewFormat, eLanguage );
2835             DBG_ASSERT( bOk, "falsches Zahlformat generiert" );
2836             if (!bOk)
2837                 bError = sal_True;
2838         }
2839     }
2840 
2841     if (!bError)
2842     {
2843         ScPatternAttr aNewAttrs( pDoc->GetPool() );
2844         SfxItemSet& rSet = aNewAttrs.GetItemSet();
2845         rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
2846         //  ATTR_LANGUAGE_FORMAT nicht
2847         ApplySelectionPattern( aNewAttrs, sal_True );
2848     }
2849     else
2850         Sound::Beep();              // war nix
2851 }
2852 
2853 void ScViewFunc::ChangeIndent( sal_Bool bIncrement )
2854 {
2855     ScViewData* pViewData = GetViewData();
2856     ScDocShell* pDocSh  = pViewData->GetDocShell();
2857     ScMarkData& rMark   = pViewData->GetMarkData();
2858 
2859     ScMarkData aWorkMark = rMark;
2860     ScViewUtil::UnmarkFiltered( aWorkMark, pDocSh->GetDocument() );
2861     aWorkMark.MarkToMulti();
2862     if (!aWorkMark.IsMultiMarked())
2863     {
2864         SCCOL nCol = pViewData->GetCurX();
2865         SCROW nRow = pViewData->GetCurY();
2866         SCTAB nTab = pViewData->GetTabNo();
2867         aWorkMark.SetMultiMarkArea( ScRange(nCol,nRow,nTab) );
2868     }
2869 
2870     sal_Bool bSuccess = pDocSh->GetDocFunc().ChangeIndent( aWorkMark, bIncrement, sal_False );
2871     if (bSuccess)
2872     {
2873         pDocSh->UpdateOle(pViewData);
2874         StartFormatArea();
2875     }
2876 }
2877 
2878 sal_Bool ScViewFunc::InsertName( const String& rName, const String& rSymbol,
2879                                 const String& rType )
2880 {
2881     //  Type = P,R,C,F (und Kombinationen)
2882     //! Undo...
2883 
2884     sal_Bool bOk = sal_False;
2885     ScDocShell* pDocSh = GetViewData()->GetDocShell();
2886     ScDocument* pDoc = pDocSh->GetDocument();
2887     SCTAB nTab = GetViewData()->GetTabNo();
2888     ScRangeName* pList = pDoc->GetRangeName();
2889 
2890     RangeType nType = RT_NAME;
2891     ScRangeData* pNewEntry = new ScRangeData( pDoc, rName, rSymbol,
2892             ScAddress( GetViewData()->GetCurX(), GetViewData()->GetCurY(),
2893                 nTab), nType );
2894     String aUpType = rType;
2895     aUpType.ToUpperAscii();
2896     if ( aUpType.Search( 'P' ) != STRING_NOTFOUND )
2897         nType |= RT_PRINTAREA;
2898     if ( aUpType.Search( 'R' ) != STRING_NOTFOUND )
2899         nType |= RT_ROWHEADER;
2900     if ( aUpType.Search( 'C' ) != STRING_NOTFOUND )
2901         nType |= RT_COLHEADER;
2902     if ( aUpType.Search( 'F' ) != STRING_NOTFOUND )
2903         nType |= RT_CRITERIA;
2904     pNewEntry->AddType(nType);
2905 
2906     if ( !pNewEntry->GetErrCode() )     //  Text gueltig?
2907     {
2908         ScDocShellModificator aModificator( *pDocSh );
2909 
2910         pDoc->CompileNameFormula( sal_True );   // CreateFormulaString
2911 
2912         // Eintrag bereits vorhanden? Dann vorher entfernen (=Aendern)
2913         sal_uInt16 nFoundAt;
2914         if ( pList->SearchName( rName, nFoundAt ) )
2915         {                                   // alten Index uebernehmen
2916             pNewEntry->SetIndex( ((ScRangeData*)pList->At(nFoundAt))->GetIndex() );
2917             pList->AtFree( nFoundAt );
2918         }
2919 
2920         if ( pList->Insert( pNewEntry ) )
2921         {
2922             pNewEntry = NULL;   // nicht loeschen
2923             bOk = sal_True;
2924         }
2925 
2926         pDoc->CompileNameFormula( sal_False );  // CompileFormulaString
2927         aModificator.SetDocumentModified();
2928         SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
2929     }
2930 
2931     delete pNewEntry;       // wenn er nicht eingefuegt wurde
2932     return bOk;
2933 }
2934 
2935 void ScViewFunc::CreateNames( sal_uInt16 nFlags )
2936 {
2937     sal_Bool bDone = sal_False;
2938     ScRange aRange;
2939     if ( GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE )
2940         bDone = GetViewData()->GetDocShell()->GetDocFunc().CreateNames( aRange, nFlags, sal_False );
2941 
2942     if (!bDone)
2943         ErrorMessage(STR_CREATENAME_MARKERR);
2944 }
2945 
2946 sal_uInt16 ScViewFunc::GetCreateNameFlags()
2947 {
2948     sal_uInt16 nFlags = 0;
2949 
2950     SCCOL nStartCol, nEndCol;
2951     SCROW nStartRow, nEndRow;
2952     SCTAB nDummy;
2953     if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nDummy,nEndCol,nEndRow,nDummy) == SC_MARK_SIMPLE)
2954     {
2955         ScDocument* pDoc = GetViewData()->GetDocument();
2956         SCTAB nTab = GetViewData()->GetTabNo();
2957         sal_Bool bOk;
2958         SCCOL i;
2959         SCROW j;
2960 
2961         bOk = sal_True;
2962         SCCOL nFirstCol = nStartCol;
2963         SCCOL nLastCol  = nEndCol;
2964         if (nStartCol+1 < nEndCol) { ++nFirstCol; --nLastCol; }
2965         for (i=nFirstCol; i<=nLastCol && bOk; i++)
2966             if (!pDoc->HasStringData( i,nStartRow,nTab ))
2967                 bOk = sal_False;
2968         if (bOk)
2969             nFlags |= NAME_TOP;
2970         else                            // Bottom nur wenn nicht Top
2971         {
2972             bOk = sal_True;
2973             for (i=nFirstCol; i<=nLastCol && bOk; i++)
2974                 if (!pDoc->HasStringData( i,nEndRow,nTab ))
2975                     bOk = sal_False;
2976             if (bOk)
2977                 nFlags |= NAME_BOTTOM;
2978         }
2979 
2980         bOk = sal_True;
2981         SCROW nFirstRow = nStartRow;
2982         SCROW nLastRow  = nEndRow;
2983         if (nStartRow+1 < nEndRow) { ++nFirstRow; --nLastRow; }
2984         for (j=nFirstRow; j<=nLastRow && bOk; j++)
2985             if (!pDoc->HasStringData( nStartCol,j,nTab ))
2986                 bOk = sal_False;
2987         if (bOk)
2988             nFlags |= NAME_LEFT;
2989         else                            // Right nur wenn nicht Left
2990         {
2991             bOk = sal_True;
2992             for (j=nFirstRow; j<=nLastRow && bOk; j++)
2993                 if (!pDoc->HasStringData( nEndCol,j,nTab ))
2994                     bOk = sal_False;
2995             if (bOk)
2996                 nFlags |= NAME_RIGHT;
2997         }
2998     }
2999 
3000     if (nStartCol == nEndCol)
3001         nFlags &= ~( NAME_LEFT | NAME_RIGHT );
3002     if (nStartRow == nEndRow)
3003         nFlags &= ~( NAME_TOP | NAME_BOTTOM );
3004 
3005     return nFlags;
3006 }
3007 
3008 void ScViewFunc::InsertNameList()
3009 {
3010     ScAddress aPos( GetViewData()->GetCurX(), GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
3011     ScDocShell* pDocSh = GetViewData()->GetDocShell();
3012     if ( pDocSh->GetDocFunc().InsertNameList( aPos, sal_False ) )
3013         pDocSh->UpdateOle(GetViewData());
3014 }
3015 
3016 
3017 
3018 
3019