xref: /aoo41x/main/sc/source/ui/view/viewfunc.cxx (revision cdf0e10c)
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