xref: /aoo41x/main/sc/source/core/data/documen4.cxx (revision 557cb412)
1b3f79822SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3b3f79822SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4b3f79822SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5b3f79822SAndrew Rist  * distributed with this work for additional information
6b3f79822SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7b3f79822SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8b3f79822SAndrew Rist  * "License"); you may not use this file except in compliance
9b3f79822SAndrew Rist  * with the License.  You may obtain a copy of the License at
10b3f79822SAndrew Rist  *
11b3f79822SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12b3f79822SAndrew Rist  *
13b3f79822SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14b3f79822SAndrew Rist  * software distributed under the License is distributed on an
15b3f79822SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16b3f79822SAndrew Rist  * KIND, either express or implied.  See the License for the
17b3f79822SAndrew Rist  * specific language governing permissions and limitations
18b3f79822SAndrew Rist  * under the License.
19b3f79822SAndrew Rist  *
20b3f79822SAndrew Rist  *************************************************************/
21b3f79822SAndrew Rist 
22b3f79822SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sc.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir 
28cdf0e10cSrcweir 
29cdf0e10cSrcweir // INCLUDE ---------------------------------------------------------------
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include <svl/intitem.hxx>
32cdf0e10cSrcweir #include <svl/zforlist.hxx>
33cdf0e10cSrcweir #include <vcl/sound.hxx>
34cdf0e10cSrcweir #include <formula/token.hxx>
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include "document.hxx"
37cdf0e10cSrcweir #include "table.hxx"
38cdf0e10cSrcweir #include "globstr.hrc"
39cdf0e10cSrcweir #include "subtotal.hxx"
40cdf0e10cSrcweir #include "docoptio.hxx"
41cdf0e10cSrcweir #include "interpre.hxx"
42cdf0e10cSrcweir #include "markdata.hxx"
43cdf0e10cSrcweir #include "validat.hxx"
44cdf0e10cSrcweir #include "scitems.hxx"
45cdf0e10cSrcweir #include "stlpool.hxx"
46cdf0e10cSrcweir #include "poolhelp.hxx"
47cdf0e10cSrcweir #include "detdata.hxx"
48cdf0e10cSrcweir #include "patattr.hxx"
49cdf0e10cSrcweir #include "chgtrack.hxx"
50cdf0e10cSrcweir #include "progress.hxx"
51cdf0e10cSrcweir #include "paramisc.hxx"
52cdf0e10cSrcweir #include "compiler.hxx"
53cdf0e10cSrcweir #include "externalrefmgr.hxx"
54cdf0e10cSrcweir 
55cdf0e10cSrcweir using namespace formula;
56cdf0e10cSrcweir 
57cdf0e10cSrcweir // -----------------------------------------------------------------------
58cdf0e10cSrcweir 
59cdf0e10cSrcweir // Nach der Regula Falsi Methode
Solver(SCCOL nFCol,SCROW nFRow,SCTAB nFTab,SCCOL nVCol,SCROW nVRow,SCTAB nVTab,const String & sValStr,double & nX)60cdf0e10cSrcweir sal_Bool ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
61cdf0e10cSrcweir 						SCCOL nVCol, SCROW nVRow, SCTAB nVTab,
62cdf0e10cSrcweir 						const String& sValStr, double& nX)
63cdf0e10cSrcweir {
64cdf0e10cSrcweir 	sal_Bool bRet = sal_False;
65cdf0e10cSrcweir 	nX = 0.0;
66cdf0e10cSrcweir 	if (ValidColRow(nFCol, nFRow) && ValidColRow(nVCol, nVRow) &&
67cdf0e10cSrcweir 		VALIDTAB(nFTab) && VALIDTAB(nVTab) && pTab[nFTab] && pTab[nVTab])
68cdf0e10cSrcweir 	{
69cdf0e10cSrcweir 		CellType eFType, eVType;
70cdf0e10cSrcweir 		GetCellType(nFCol, nFRow, nFTab, eFType);
71cdf0e10cSrcweir 		GetCellType(nVCol, nVRow, nVTab, eVType);
72cdf0e10cSrcweir         // CELLTYPE_NOTE: no value, but referenced by formula
73cdf0e10cSrcweir         // #i108005# convert target value to number using default format,
74cdf0e10cSrcweir         // as previously done in ScInterpreter::GetDouble
75cdf0e10cSrcweir         double nTargetVal = 0.0;
76cdf0e10cSrcweir         sal_uInt32 nFIndex = 0;
77cdf0e10cSrcweir         if (eFType == CELLTYPE_FORMULA && (eVType == CELLTYPE_VALUE || eVType == CELLTYPE_NOTE) &&
78cdf0e10cSrcweir             GetFormatTable()->IsNumberFormat(sValStr, nFIndex, nTargetVal))
79cdf0e10cSrcweir 		{
80cdf0e10cSrcweir 			ScSingleRefData aRefData;
81cdf0e10cSrcweir 			aRefData.InitFlags();
82cdf0e10cSrcweir 			aRefData.nCol = nVCol;
83cdf0e10cSrcweir 			aRefData.nRow = nVRow;
84cdf0e10cSrcweir 			aRefData.nTab = nVTab;
85cdf0e10cSrcweir 
86cdf0e10cSrcweir 			ScTokenArray aArr;
87cdf0e10cSrcweir 			aArr.AddOpCode( ocBackSolver );
88cdf0e10cSrcweir 			aArr.AddOpCode( ocOpen );
89cdf0e10cSrcweir 			aArr.AddSingleReference( aRefData );
90cdf0e10cSrcweir 			aArr.AddOpCode( ocSep );
91cdf0e10cSrcweir 
92cdf0e10cSrcweir 			aRefData.nCol = nFCol;
93cdf0e10cSrcweir 			aRefData.nRow = nFRow;
94cdf0e10cSrcweir 			aRefData.nTab = nFTab;
95cdf0e10cSrcweir 
96cdf0e10cSrcweir 			aArr.AddSingleReference( aRefData );
97cdf0e10cSrcweir 			aArr.AddOpCode( ocSep );
98cdf0e10cSrcweir             aArr.AddDouble( nTargetVal );
99cdf0e10cSrcweir 			aArr.AddOpCode( ocClose );
100cdf0e10cSrcweir 			aArr.AddOpCode( ocStop );
101cdf0e10cSrcweir 
102cdf0e10cSrcweir 			ScFormulaCell* pCell = new ScFormulaCell( this, ScAddress(), &aArr );
103cdf0e10cSrcweir 
104cdf0e10cSrcweir 			if (pCell)
105cdf0e10cSrcweir 			{
106cdf0e10cSrcweir                 // FIXME FIXME FIXME this might need to be reworked now that we have formula::FormulaErrorToken and ScFormulaResult, double check !!!
107cdf0e10cSrcweir                 DBG_ERRORFILE("ScDocument::Solver: -> ScFormulaCell::GetValueAlways might need reimplementation");
108cdf0e10cSrcweir 				pCell->Interpret();
109cdf0e10cSrcweir 				sal_uInt16 nErrCode = pCell->GetErrCode();
110cdf0e10cSrcweir 				nX = pCell->GetValueAlways();
111cdf0e10cSrcweir 				if (nErrCode == 0)					// kein fehler beim Rechnen
112cdf0e10cSrcweir 					bRet = sal_True;
113cdf0e10cSrcweir 				delete pCell;
114cdf0e10cSrcweir 			}
115cdf0e10cSrcweir 		}
116cdf0e10cSrcweir 	}
117cdf0e10cSrcweir 	return bRet;
118cdf0e10cSrcweir }
119cdf0e10cSrcweir 
InsertMatrixFormula(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2,const ScMarkData & rMark,const String & rFormula,const ScTokenArray * pArr,const formula::FormulaGrammar::Grammar eGram)120cdf0e10cSrcweir void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
121cdf0e10cSrcweir 									 SCCOL nCol2, SCROW nRow2,
122cdf0e10cSrcweir 									 const ScMarkData& rMark,
123cdf0e10cSrcweir 									 const String& rFormula,
124cdf0e10cSrcweir 									 const ScTokenArray* pArr,
125cdf0e10cSrcweir                                      const formula::FormulaGrammar::Grammar eGram )
126cdf0e10cSrcweir {
127cdf0e10cSrcweir 	PutInOrder(nCol1, nCol2);
128cdf0e10cSrcweir 	PutInOrder(nRow1, nRow2);
129cdf0e10cSrcweir 	SCTAB i, nTab1;
130cdf0e10cSrcweir     SCCOL j;
131cdf0e10cSrcweir     SCROW k;
132cdf0e10cSrcweir 	i = 0;
133cdf0e10cSrcweir 	sal_Bool bStop = sal_False;
134cdf0e10cSrcweir 	while (i <= MAXTAB && !bStop)				// erste markierte Tabelle finden
135cdf0e10cSrcweir 	{
136cdf0e10cSrcweir 		if (pTab[i] && rMark.GetTableSelect(i))
137cdf0e10cSrcweir 			bStop = sal_True;
138cdf0e10cSrcweir 		else
139cdf0e10cSrcweir 			i++;
140cdf0e10cSrcweir 	}
141cdf0e10cSrcweir 	nTab1 = i;
142cdf0e10cSrcweir 	if (i == MAXTAB + 1)
143cdf0e10cSrcweir 	{
144cdf0e10cSrcweir 		Sound::Beep();
145cdf0e10cSrcweir 		DBG_ERROR("ScDocument::InsertMatrixFormula Keine Tabelle markiert");
146cdf0e10cSrcweir 		return;
147cdf0e10cSrcweir 	}
148cdf0e10cSrcweir 
149cdf0e10cSrcweir 	ScFormulaCell* pCell;
150cdf0e10cSrcweir 	ScAddress aPos( nCol1, nRow1, nTab1 );
151cdf0e10cSrcweir 	if (pArr)
152cdf0e10cSrcweir 		pCell = new ScFormulaCell( this, aPos, pArr, eGram, MM_FORMULA );
153cdf0e10cSrcweir 	else
154cdf0e10cSrcweir         pCell = new ScFormulaCell( this, aPos, rFormula, eGram, MM_FORMULA );
155cdf0e10cSrcweir 	pCell->SetMatColsRows( nCol2 - nCol1 + 1, nRow2 - nRow1 + 1 );
156cdf0e10cSrcweir 	for (i = 0; i <= MAXTAB; i++)
157cdf0e10cSrcweir 	{
158cdf0e10cSrcweir 		if (pTab[i] && rMark.GetTableSelect(i))
159cdf0e10cSrcweir 		{
160cdf0e10cSrcweir 			if (i == nTab1)
161cdf0e10cSrcweir 				pTab[i]->PutCell(nCol1, nRow1, pCell);
162cdf0e10cSrcweir 			else
163cdf0e10cSrcweir                 pTab[i]->PutCell(nCol1, nRow1, pCell->CloneWithoutNote(*this, ScAddress( nCol1, nRow1, i), SC_CLONECELL_STARTLISTENING));
164cdf0e10cSrcweir 		}
165cdf0e10cSrcweir 	}
166cdf0e10cSrcweir 
167cdf0e10cSrcweir 	ScSingleRefData aRefData;
168cdf0e10cSrcweir 	aRefData.InitFlags();
169cdf0e10cSrcweir 	aRefData.nCol = nCol1;
170cdf0e10cSrcweir 	aRefData.nRow = nRow1;
171cdf0e10cSrcweir 	aRefData.nTab = nTab1;
172cdf0e10cSrcweir 	aRefData.SetColRel( sal_True );
173cdf0e10cSrcweir 	aRefData.SetRowRel( sal_True );
174cdf0e10cSrcweir 	aRefData.SetTabRel( sal_True );
175cdf0e10cSrcweir 	aRefData.CalcRelFromAbs( ScAddress( nCol1, nRow1, nTab1 ) );
176cdf0e10cSrcweir 
177cdf0e10cSrcweir 	ScTokenArray aArr;
178cdf0e10cSrcweir 	ScToken* t = static_cast<ScToken*>(aArr.AddMatrixSingleReference( aRefData));
179cdf0e10cSrcweir 
180cdf0e10cSrcweir 	for (i = 0; i <= MAXTAB; i++)
181cdf0e10cSrcweir 	{
182cdf0e10cSrcweir 		if (pTab[i] && rMark.GetTableSelect(i))
183cdf0e10cSrcweir 		{
184cdf0e10cSrcweir 			pTab[i]->DoColResize( nCol1, nCol2, static_cast<SCSIZE>(nRow2 - nRow1 + 1) );
185cdf0e10cSrcweir 			if (i != nTab1)
186cdf0e10cSrcweir 			{
187cdf0e10cSrcweir 				aRefData.nTab = i;
188cdf0e10cSrcweir 				aRefData.nRelTab = i - nTab1;
189cdf0e10cSrcweir 				t->GetSingleRef() = aRefData;
190cdf0e10cSrcweir 			}
191cdf0e10cSrcweir 			for (j = nCol1; j <= nCol2; j++)
192cdf0e10cSrcweir 			{
193cdf0e10cSrcweir 				for (k = nRow1; k <= nRow2; k++)
194cdf0e10cSrcweir 				{
195cdf0e10cSrcweir 					if (j != nCol1 || k != nRow1)		// nicht in der ersten Zelle
196cdf0e10cSrcweir 					{
197cdf0e10cSrcweir 						// Array muss geklont werden, damit jede
198cdf0e10cSrcweir 						// Zelle ein eigenes Array erhaelt!
199cdf0e10cSrcweir 						aPos = ScAddress( j, k, i );
200cdf0e10cSrcweir 						t->CalcRelFromAbs( aPos );
201cdf0e10cSrcweir 						pCell = new ScFormulaCell( this, aPos, aArr.Clone(), eGram, MM_REFERENCE );
202cdf0e10cSrcweir 						pTab[i]->PutCell(j, k, (ScBaseCell*) pCell);
203cdf0e10cSrcweir 					}
204cdf0e10cSrcweir 				}
205cdf0e10cSrcweir 			}
206cdf0e10cSrcweir 		}
207cdf0e10cSrcweir 	}
208cdf0e10cSrcweir }
209cdf0e10cSrcweir 
InsertTableOp(const ScTabOpParam & rParam,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2,const ScMarkData & rMark)210cdf0e10cSrcweir void ScDocument::InsertTableOp(const ScTabOpParam& rParam,      // Mehrfachoperation
211cdf0e10cSrcweir 							   SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
212cdf0e10cSrcweir 							   const ScMarkData& rMark)
213cdf0e10cSrcweir {
214cdf0e10cSrcweir 	PutInOrder(nCol1, nCol2);
215cdf0e10cSrcweir 	PutInOrder(nRow1, nRow2);
216cdf0e10cSrcweir 	SCTAB i, nTab1;
217cdf0e10cSrcweir     SCCOL j;
218cdf0e10cSrcweir     SCROW k;
219cdf0e10cSrcweir 	i = 0;
220cdf0e10cSrcweir 	sal_Bool bStop = sal_False;
221cdf0e10cSrcweir 	while (i <= MAXTAB && !bStop)				// erste markierte Tabelle finden
222cdf0e10cSrcweir 	{
223cdf0e10cSrcweir 		if (pTab[i] && rMark.GetTableSelect(i))
224cdf0e10cSrcweir 			bStop = sal_True;
225cdf0e10cSrcweir 		else
226cdf0e10cSrcweir 			i++;
227cdf0e10cSrcweir 	}
228cdf0e10cSrcweir 	nTab1 = i;
229cdf0e10cSrcweir 	if (i == MAXTAB + 1)
230cdf0e10cSrcweir 	{
231cdf0e10cSrcweir 		Sound::Beep();
232cdf0e10cSrcweir 		DBG_ERROR("ScDocument::InsertTableOp: Keine Tabelle markiert");
233cdf0e10cSrcweir 		return;
234cdf0e10cSrcweir 	}
235cdf0e10cSrcweir 
236cdf0e10cSrcweir     ScRefAddress aRef;
237cdf0e10cSrcweir 	String aForString = '=';
238cdf0e10cSrcweir     aForString += ScCompiler::GetNativeSymbol(ocTableOp);
239cdf0e10cSrcweir 	aForString += ScCompiler::GetNativeSymbol( ocOpen);
240cdf0e10cSrcweir 
241cdf0e10cSrcweir     const String& sSep = ScCompiler::GetNativeSymbol( ocSep);
242cdf0e10cSrcweir 	if (rParam.nMode == 0)							// nur Spalte
243cdf0e10cSrcweir 	{
244cdf0e10cSrcweir         aRef.Set( rParam.aRefFormulaCell.GetAddress(), sal_True, sal_False, sal_False );
245cdf0e10cSrcweir         aForString += aRef.GetRefString(this, nTab1);
246cdf0e10cSrcweir         aForString += sSep;
247cdf0e10cSrcweir         aForString += rParam.aRefColCell.GetRefString(this, nTab1);
248cdf0e10cSrcweir         aForString += sSep;
249cdf0e10cSrcweir         aRef.Set( nCol1, nRow1, nTab1, sal_False, sal_True, sal_True );
250cdf0e10cSrcweir         aForString += aRef.GetRefString(this, nTab1);
251cdf0e10cSrcweir         nCol1++;
252cdf0e10cSrcweir         nCol2 = Min( nCol2, (SCCOL)(rParam.aRefFormulaEnd.Col() -
253cdf0e10cSrcweir                     rParam.aRefFormulaCell.Col() + nCol1 + 1));
254cdf0e10cSrcweir     }
255cdf0e10cSrcweir 	else if (rParam.nMode == 1)					// nur zeilenweise
256cdf0e10cSrcweir 	{
257cdf0e10cSrcweir         aRef.Set( rParam.aRefFormulaCell.GetAddress(), sal_False, sal_True, sal_False );
258cdf0e10cSrcweir         aForString += aRef.GetRefString(this, nTab1);
259cdf0e10cSrcweir         aForString += sSep;
260cdf0e10cSrcweir         aForString += rParam.aRefRowCell.GetRefString(this, nTab1);
261cdf0e10cSrcweir         aForString += sSep;
262cdf0e10cSrcweir         aRef.Set( nCol1, nRow1, nTab1, sal_True, sal_False, sal_True );
263cdf0e10cSrcweir         aForString += aRef.GetRefString(this, nTab1);
264cdf0e10cSrcweir         nRow1++;
265cdf0e10cSrcweir         nRow2 = Min( nRow2, (SCROW)(rParam.aRefFormulaEnd.Row() -
266cdf0e10cSrcweir                     rParam.aRefFormulaCell.Row() + nRow1 + 1));
267cdf0e10cSrcweir 	}
268cdf0e10cSrcweir 	else					// beides
269cdf0e10cSrcweir 	{
270cdf0e10cSrcweir         aForString += rParam.aRefFormulaCell.GetRefString(this, nTab1);
271cdf0e10cSrcweir         aForString += sSep;
272cdf0e10cSrcweir         aForString += rParam.aRefColCell.GetRefString(this, nTab1);
273cdf0e10cSrcweir         aForString += sSep;
274cdf0e10cSrcweir         aRef.Set( nCol1, nRow1 + 1, nTab1, sal_False, sal_True, sal_True );
275cdf0e10cSrcweir         aForString += aRef.GetRefString(this, nTab1);
276cdf0e10cSrcweir         aForString += sSep;
277cdf0e10cSrcweir         aForString += rParam.aRefRowCell.GetRefString(this, nTab1);
278cdf0e10cSrcweir         aForString += sSep;
279cdf0e10cSrcweir         aRef.Set( nCol1 + 1, nRow1, nTab1, sal_True, sal_False, sal_True );
280cdf0e10cSrcweir         aForString += aRef.GetRefString(this, nTab1);
281cdf0e10cSrcweir         nCol1++; nRow1++;
282cdf0e10cSrcweir 	}
283cdf0e10cSrcweir 	aForString += ScCompiler::GetNativeSymbol( ocClose);
284cdf0e10cSrcweir 
285cdf0e10cSrcweir     ScFormulaCell aRefCell( this, ScAddress( nCol1, nRow1, nTab1 ), aForString,
286cdf0e10cSrcweir            formula::FormulaGrammar::GRAM_NATIVE, MM_NONE );
287cdf0e10cSrcweir     for( j = nCol1; j <= nCol2; j++ )
288cdf0e10cSrcweir         for( k = nRow1; k <= nRow2; k++ )
289cdf0e10cSrcweir             for (i = 0; i <= MAXTAB; i++)
290cdf0e10cSrcweir                 if( pTab[i] && rMark.GetTableSelect(i) )
291cdf0e10cSrcweir                     pTab[i]->PutCell( j, k, aRefCell.CloneWithoutNote( *this, ScAddress( j, k, i ), SC_CLONECELL_STARTLISTENING ) );
292cdf0e10cSrcweir }
293cdf0e10cSrcweir 
MarkUsedExternalReferences(ScTokenArray & rArr)294cdf0e10cSrcweir bool ScDocument::MarkUsedExternalReferences( ScTokenArray & rArr )
295cdf0e10cSrcweir {
296cdf0e10cSrcweir     bool bAllMarked = false;
297cdf0e10cSrcweir     if (rArr.GetLen())
298cdf0e10cSrcweir     {
299cdf0e10cSrcweir         ScExternalRefManager* pRefMgr = NULL;
300cdf0e10cSrcweir         rArr.Reset();
301cdf0e10cSrcweir         ScToken* t;
302cdf0e10cSrcweir         while (!bAllMarked && (t = static_cast<ScToken*>(rArr.GetNextReferenceOrName())) != NULL)
303cdf0e10cSrcweir         {
304cdf0e10cSrcweir             if (t->GetOpCode() == ocExternalRef)
305cdf0e10cSrcweir             {
306cdf0e10cSrcweir                 if (!pRefMgr)
307cdf0e10cSrcweir                     pRefMgr = GetExternalRefManager();
308cdf0e10cSrcweir                 switch (t->GetType())
309cdf0e10cSrcweir                 {
310cdf0e10cSrcweir                     case svExternalSingleRef:
311cdf0e10cSrcweir                         bAllMarked = pRefMgr->setCacheTableReferenced(
312cdf0e10cSrcweir                                 t->GetIndex(), t->GetString(), 1);
313cdf0e10cSrcweir                         break;
314cdf0e10cSrcweir                     case svExternalDoubleRef:
315cdf0e10cSrcweir                         {
316cdf0e10cSrcweir                             const ScComplexRefData& rRef = t->GetDoubleRef();
317cdf0e10cSrcweir                             size_t nSheets = rRef.Ref2.nTab - rRef.Ref1.nTab + 1;
318cdf0e10cSrcweir                             bAllMarked = pRefMgr->setCacheTableReferenced(
319cdf0e10cSrcweir                                     t->GetIndex(), t->GetString(), nSheets);
320cdf0e10cSrcweir                         }
321cdf0e10cSrcweir                         break;
322cdf0e10cSrcweir                     case svExternalName:
323cdf0e10cSrcweir                         /* TODO: external names aren't supported yet, but would
324cdf0e10cSrcweir                          * have to be marked as well, if so. Mechanism would be
325cdf0e10cSrcweir                          * different. */
326cdf0e10cSrcweir                         DBG_ERRORFILE("ScDocument::MarkUsedExternalReferences: implement the svExternalName case!");
327cdf0e10cSrcweir                         break;
328cdf0e10cSrcweir                     default: break;
329cdf0e10cSrcweir                 }
330cdf0e10cSrcweir             }
331cdf0e10cSrcweir         }
332cdf0e10cSrcweir     }
333cdf0e10cSrcweir     return bAllMarked;
334cdf0e10cSrcweir }
335cdf0e10cSrcweir 
GetNextSpellingCell(SCCOL & nCol,SCROW & nRow,SCTAB nTab,sal_Bool bInSel,const ScMarkData & rMark) const336cdf0e10cSrcweir sal_Bool ScDocument::GetNextSpellingCell(SCCOL& nCol, SCROW& nRow, SCTAB nTab,
337cdf0e10cSrcweir 						sal_Bool bInSel, const ScMarkData& rMark) const
338cdf0e10cSrcweir {
339cdf0e10cSrcweir 	if (ValidTab(nTab) && pTab[nTab])
340cdf0e10cSrcweir 		return pTab[nTab]->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
341cdf0e10cSrcweir 	else
342cdf0e10cSrcweir 		return sal_False;
343cdf0e10cSrcweir }
344cdf0e10cSrcweir 
GetNextMarkedCell(SCCOL & rCol,SCROW & rRow,SCTAB nTab,const ScMarkData & rMark)345cdf0e10cSrcweir sal_Bool ScDocument::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, SCTAB nTab,
346cdf0e10cSrcweir 										const ScMarkData& rMark )
347cdf0e10cSrcweir {
348cdf0e10cSrcweir 	if (ValidTab(nTab) && pTab[nTab])
349cdf0e10cSrcweir 		return pTab[nTab]->GetNextMarkedCell( rCol, rRow, rMark );
350cdf0e10cSrcweir 	else
351cdf0e10cSrcweir 		return sal_False;
352cdf0e10cSrcweir }
353cdf0e10cSrcweir 
ReplaceStyle(const SvxSearchItem & rSearchItem,SCCOL nCol,SCROW nRow,SCTAB nTab,ScMarkData & rMark,sal_Bool bIsUndoP)354cdf0e10cSrcweir sal_Bool ScDocument::ReplaceStyle(const SvxSearchItem& rSearchItem,
355cdf0e10cSrcweir 							  SCCOL nCol, SCROW nRow, SCTAB nTab,
356cdf0e10cSrcweir 							  ScMarkData& rMark,
357cdf0e10cSrcweir                               sal_Bool bIsUndoP)
358cdf0e10cSrcweir {
359cdf0e10cSrcweir 	if (pTab[nTab])
360cdf0e10cSrcweir         return pTab[nTab]->ReplaceStyle(rSearchItem, nCol, nRow, rMark, bIsUndoP);
361cdf0e10cSrcweir 	else
362cdf0e10cSrcweir 		return sal_False;
363cdf0e10cSrcweir }
364cdf0e10cSrcweir 
CompileDBFormula()365cdf0e10cSrcweir void ScDocument::CompileDBFormula()
366cdf0e10cSrcweir {
367cdf0e10cSrcweir 	for (SCTAB i=0; i<=MAXTAB; i++)
368cdf0e10cSrcweir 	{
369cdf0e10cSrcweir 		if (pTab[i]) pTab[i]->CompileDBFormula();
370cdf0e10cSrcweir 	}
371cdf0e10cSrcweir }
372cdf0e10cSrcweir 
CompileDBFormula(sal_Bool bCreateFormulaString)373cdf0e10cSrcweir void ScDocument::CompileDBFormula( sal_Bool bCreateFormulaString )
374cdf0e10cSrcweir {
375cdf0e10cSrcweir 	for (SCTAB i=0; i<=MAXTAB; i++)
376cdf0e10cSrcweir 	{
377cdf0e10cSrcweir 		if (pTab[i]) pTab[i]->CompileDBFormula( bCreateFormulaString );
378cdf0e10cSrcweir 	}
379cdf0e10cSrcweir }
380cdf0e10cSrcweir 
CompileNameFormula(sal_Bool bCreateFormulaString)381cdf0e10cSrcweir void ScDocument::CompileNameFormula( sal_Bool bCreateFormulaString )
382cdf0e10cSrcweir {
383cdf0e10cSrcweir 	if ( pCondFormList )
384cdf0e10cSrcweir 		pCondFormList->CompileAll();	// nach ScNameDlg noetig
385cdf0e10cSrcweir 
386cdf0e10cSrcweir 	for (SCTAB i=0; i<=MAXTAB; i++)
387cdf0e10cSrcweir 	{
388cdf0e10cSrcweir 		if (pTab[i]) pTab[i]->CompileNameFormula( bCreateFormulaString );
389cdf0e10cSrcweir 	}
390cdf0e10cSrcweir }
391cdf0e10cSrcweir 
CompileColRowNameFormula()392cdf0e10cSrcweir void ScDocument::CompileColRowNameFormula()
393cdf0e10cSrcweir {
394cdf0e10cSrcweir 	for (SCTAB i=0; i<=MAXTAB; i++)
395cdf0e10cSrcweir 	{
396cdf0e10cSrcweir 		if (pTab[i]) pTab[i]->CompileColRowNameFormula();
397cdf0e10cSrcweir 	}
398cdf0e10cSrcweir }
399cdf0e10cSrcweir 
DoColResize(SCTAB nTab,SCCOL nCol1,SCCOL nCol2,SCSIZE nAdd)400cdf0e10cSrcweir void ScDocument::DoColResize( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd )
401cdf0e10cSrcweir {
402cdf0e10cSrcweir 	if (ValidTab(nTab) && pTab[nTab])
403cdf0e10cSrcweir 		pTab[nTab]->DoColResize( nCol1, nCol2, nAdd );
404cdf0e10cSrcweir 	else
405cdf0e10cSrcweir 	{
406cdf0e10cSrcweir 		DBG_ERROR("DoColResize: falsche Tabelle");
407cdf0e10cSrcweir 	}
408cdf0e10cSrcweir }
409cdf0e10cSrcweir 
InvalidateTableArea()410cdf0e10cSrcweir void ScDocument::InvalidateTableArea()
411cdf0e10cSrcweir {
412cdf0e10cSrcweir 	for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
413cdf0e10cSrcweir 	{
414cdf0e10cSrcweir 		pTab[nTab]->InvalidateTableArea();
415cdf0e10cSrcweir 		if ( pTab[nTab]->IsScenario() )
416cdf0e10cSrcweir 			pTab[nTab]->InvalidateScenarioRanges();
417cdf0e10cSrcweir 	}
418cdf0e10cSrcweir }
419cdf0e10cSrcweir 
GetLastAttrCell(SCTAB nTab,SCCOL & rEndCol,SCROW & rEndRow) const420*557cb412SWang Lei void ScDocument::GetLastAttrCell( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
421*557cb412SWang Lei {
422*557cb412SWang Lei 	if ( ValidTab( nTab ) && pTab[nTab] )
423*557cb412SWang Lei 	{
424*557cb412SWang Lei 		pTab[nTab]->GetLastAttrCell( rEndCol, rEndRow );
425*557cb412SWang Lei 	}
426*557cb412SWang Lei }
427*557cb412SWang Lei 
GetMaxStringLen(SCTAB nTab,SCCOL nCol,SCROW nRowStart,SCROW nRowEnd,CharSet eCharSet) const428cdf0e10cSrcweir sal_Int32 ScDocument::GetMaxStringLen( SCTAB nTab, SCCOL nCol,
429cdf0e10cSrcweir         SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
430cdf0e10cSrcweir {
431cdf0e10cSrcweir 	if (ValidTab(nTab) && pTab[nTab])
432cdf0e10cSrcweir 		return pTab[nTab]->GetMaxStringLen( nCol, nRowStart, nRowEnd, eCharSet );
433cdf0e10cSrcweir 	else
434cdf0e10cSrcweir         return 0;
435cdf0e10cSrcweir }
436cdf0e10cSrcweir 
GetMaxNumberStringLen(sal_uInt16 & nPrecision,SCTAB nTab,SCCOL nCol,SCROW nRowStart,SCROW nRowEnd) const437cdf0e10cSrcweir xub_StrLen ScDocument::GetMaxNumberStringLen( sal_uInt16& nPrecision, SCTAB nTab,
438cdf0e10cSrcweir                                     SCCOL nCol,
439cdf0e10cSrcweir                                     SCROW nRowStart, SCROW nRowEnd ) const
440cdf0e10cSrcweir {
441cdf0e10cSrcweir     if (ValidTab(nTab) && pTab[nTab])
442cdf0e10cSrcweir         return pTab[nTab]->GetMaxNumberStringLen( nPrecision, nCol,
443cdf0e10cSrcweir             nRowStart, nRowEnd );
444cdf0e10cSrcweir     else
445cdf0e10cSrcweir         return 0;
446cdf0e10cSrcweir }
447cdf0e10cSrcweir 
GetSelectionFunction(ScSubTotalFunc eFunc,const ScAddress & rCursor,const ScMarkData & rMark,double & rResult)448cdf0e10cSrcweir sal_Bool ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
449cdf0e10cSrcweir 										const ScAddress& rCursor, const ScMarkData& rMark,
450cdf0e10cSrcweir 										double& rResult )
451cdf0e10cSrcweir {
452cdf0e10cSrcweir 	ScFunctionData aData(eFunc);
453cdf0e10cSrcweir 
454cdf0e10cSrcweir 	ScRange aSingle( rCursor );
455cdf0e10cSrcweir 	if ( rMark.IsMarked() )
456cdf0e10cSrcweir 		rMark.GetMarkArea(aSingle);
457cdf0e10cSrcweir 
458cdf0e10cSrcweir 	SCCOL nStartCol = aSingle.aStart.Col();
459cdf0e10cSrcweir 	SCROW nStartRow = aSingle.aStart.Row();
460cdf0e10cSrcweir 	SCCOL nEndCol = aSingle.aEnd.Col();
461cdf0e10cSrcweir 	SCROW nEndRow = aSingle.aEnd.Row();
462cdf0e10cSrcweir 
463cdf0e10cSrcweir 	for (SCTAB nTab=0; nTab<=MAXTAB && !aData.bError; nTab++)
464cdf0e10cSrcweir 		if (pTab[nTab] && rMark.GetTableSelect(nTab))
465cdf0e10cSrcweir 			pTab[nTab]->UpdateSelectionFunction( aData,
466cdf0e10cSrcweir 							nStartCol, nStartRow, nEndCol, nEndRow, rMark );
467cdf0e10cSrcweir 
468cdf0e10cSrcweir 			//!	rMark an UpdateSelectionFunction uebergeben !!!!!
469cdf0e10cSrcweir 
470cdf0e10cSrcweir 	if (!aData.bError)
471cdf0e10cSrcweir 		switch (eFunc)
472cdf0e10cSrcweir 		{
473cdf0e10cSrcweir 			case SUBTOTAL_FUNC_SUM:
474cdf0e10cSrcweir 				rResult = aData.nVal;
475cdf0e10cSrcweir 				break;
476cdf0e10cSrcweir 			case SUBTOTAL_FUNC_CNT:
477cdf0e10cSrcweir 			case SUBTOTAL_FUNC_CNT2:
478cdf0e10cSrcweir 				rResult = aData.nCount;
479cdf0e10cSrcweir 				break;
480cdf0e10cSrcweir 			case SUBTOTAL_FUNC_AVE:
481cdf0e10cSrcweir 				if (aData.nCount)
482cdf0e10cSrcweir 					rResult = aData.nVal / (double) aData.nCount;
483cdf0e10cSrcweir 				else
484cdf0e10cSrcweir 					aData.bError = sal_True;
485cdf0e10cSrcweir 				break;
486cdf0e10cSrcweir 			case SUBTOTAL_FUNC_MAX:
487cdf0e10cSrcweir 			case SUBTOTAL_FUNC_MIN:
488cdf0e10cSrcweir 				if (aData.nCount)
489cdf0e10cSrcweir 					rResult = aData.nVal;
490cdf0e10cSrcweir 				else
491cdf0e10cSrcweir 					aData.bError = sal_True;
492cdf0e10cSrcweir 				break;
493cdf0e10cSrcweir             default:
494cdf0e10cSrcweir             {
495cdf0e10cSrcweir                 // added to avoid warnings
496cdf0e10cSrcweir             }
497cdf0e10cSrcweir 		}
498cdf0e10cSrcweir 
499cdf0e10cSrcweir 	if (aData.bError)
500cdf0e10cSrcweir 		rResult = 0.0;
501cdf0e10cSrcweir 
502cdf0e10cSrcweir 	return !aData.bError;
503cdf0e10cSrcweir }
504cdf0e10cSrcweir 
RoundValueAsShown(double fVal,sal_uLong nFormat)505cdf0e10cSrcweir double ScDocument::RoundValueAsShown( double fVal, sal_uLong nFormat )
506cdf0e10cSrcweir {
507cdf0e10cSrcweir 	short nType;
508cdf0e10cSrcweir 	if ( (nType = GetFormatTable()->GetType( nFormat )) != NUMBERFORMAT_DATE
509cdf0e10cSrcweir 	  && nType != NUMBERFORMAT_TIME && nType != NUMBERFORMAT_DATETIME )
510cdf0e10cSrcweir 	{
511cdf0e10cSrcweir 		short nPrecision;
512cdf0e10cSrcweir         if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
513cdf0e10cSrcweir 		{
514cdf0e10cSrcweir 			nPrecision = (short)GetFormatTable()->GetFormatPrecision( nFormat );
515cdf0e10cSrcweir 			switch ( nType )
516cdf0e10cSrcweir 			{
517cdf0e10cSrcweir 				case NUMBERFORMAT_PERCENT:		// 0,41% == 0,0041
518cdf0e10cSrcweir 					nPrecision += 2;
519cdf0e10cSrcweir 					break;
520cdf0e10cSrcweir 				case NUMBERFORMAT_SCIENTIFIC:	// 1,23e-3 == 0,00123
521cdf0e10cSrcweir 				{
522cdf0e10cSrcweir 					if ( fVal > 0.0 )
523cdf0e10cSrcweir                         nPrecision = sal::static_int_cast<short>( nPrecision - (short)floor( log10( fVal ) ) );
524cdf0e10cSrcweir 					else if ( fVal < 0.0 )
525cdf0e10cSrcweir                         nPrecision = sal::static_int_cast<short>( nPrecision - (short)floor( log10( -fVal ) ) );
526cdf0e10cSrcweir 					break;
527cdf0e10cSrcweir 				}
528cdf0e10cSrcweir 			}
529cdf0e10cSrcweir 		}
530cdf0e10cSrcweir 		else
531cdf0e10cSrcweir         {
532cdf0e10cSrcweir 			nPrecision = (short)GetDocOptions().GetStdPrecision();
533cdf0e10cSrcweir             // #i115512# no rounding for automatic decimals
534cdf0e10cSrcweir             if (nPrecision == static_cast<short>(SvNumberFormatter::UNLIMITED_PRECISION))
535cdf0e10cSrcweir                 return fVal;
536cdf0e10cSrcweir         }
537cdf0e10cSrcweir 		double fRound = ::rtl::math::round( fVal, nPrecision );
538cdf0e10cSrcweir 		if ( ::rtl::math::approxEqual( fVal, fRound ) )
539cdf0e10cSrcweir 			return fVal;		// durch Rundung hoechstens Fehler
540cdf0e10cSrcweir 		else
541cdf0e10cSrcweir 			return fRound;
542cdf0e10cSrcweir 	}
543cdf0e10cSrcweir 	else
544cdf0e10cSrcweir 		return fVal;
545cdf0e10cSrcweir }
546cdf0e10cSrcweir 
547cdf0e10cSrcweir //
548cdf0e10cSrcweir //			bedingte Formate und Gueltigkeitsbereiche
549cdf0e10cSrcweir //
550cdf0e10cSrcweir 
AddCondFormat(const ScConditionalFormat & rNew)551cdf0e10cSrcweir sal_uLong ScDocument::AddCondFormat( const ScConditionalFormat& rNew )
552cdf0e10cSrcweir {
553cdf0e10cSrcweir 	if (rNew.IsEmpty())
554cdf0e10cSrcweir 		return 0;					// leer ist immer 0
555cdf0e10cSrcweir 
556cdf0e10cSrcweir 	if (!pCondFormList)
557cdf0e10cSrcweir 		pCondFormList = new ScConditionalFormatList;
558cdf0e10cSrcweir 
559cdf0e10cSrcweir 	sal_uLong nMax = 0;
560cdf0e10cSrcweir 	sal_uInt16 nCount = pCondFormList->Count();
561cdf0e10cSrcweir 	for (sal_uInt16 i=0; i<nCount; i++)
562cdf0e10cSrcweir 	{
563cdf0e10cSrcweir 		const ScConditionalFormat* pForm = (*pCondFormList)[i];
564cdf0e10cSrcweir 		sal_uLong nKey = pForm->GetKey();
565cdf0e10cSrcweir 		if ( pForm->EqualEntries( rNew ) )
566cdf0e10cSrcweir 			return nKey;
567cdf0e10cSrcweir 		if ( nKey > nMax )
568cdf0e10cSrcweir 			nMax = nKey;
569cdf0e10cSrcweir 	}
570cdf0e10cSrcweir 
571cdf0e10cSrcweir 	// Der Aufruf kann aus ScPatternAttr::PutInPool kommen, darum Clone (echte Kopie)
572cdf0e10cSrcweir 
573cdf0e10cSrcweir 	sal_uLong nNewKey = nMax + 1;
574cdf0e10cSrcweir 	ScConditionalFormat* pInsert = rNew.Clone(this);
575cdf0e10cSrcweir 	pInsert->SetKey( nNewKey );
576cdf0e10cSrcweir 	pCondFormList->InsertNew( pInsert );
577cdf0e10cSrcweir 	return nNewKey;
578cdf0e10cSrcweir }
579cdf0e10cSrcweir 
AddValidationEntry(const ScValidationData & rNew)580cdf0e10cSrcweir sal_uLong ScDocument::AddValidationEntry( const ScValidationData& rNew )
581cdf0e10cSrcweir {
582cdf0e10cSrcweir 	if (rNew.IsEmpty())
583cdf0e10cSrcweir 		return 0;					// leer ist immer 0
584cdf0e10cSrcweir 
585cdf0e10cSrcweir 	if (!pValidationList)
586cdf0e10cSrcweir 		pValidationList = new ScValidationDataList;
587cdf0e10cSrcweir 
588cdf0e10cSrcweir 	sal_uLong nMax = 0;
589cdf0e10cSrcweir 	sal_uInt16 nCount = pValidationList->Count();
590cdf0e10cSrcweir 	for (sal_uInt16 i=0; i<nCount; i++)
591cdf0e10cSrcweir 	{
592cdf0e10cSrcweir 		const ScValidationData* pData = (*pValidationList)[i];
593cdf0e10cSrcweir 		sal_uLong nKey = pData->GetKey();
594cdf0e10cSrcweir 		if ( pData->EqualEntries( rNew ) )
595cdf0e10cSrcweir 			return nKey;
596cdf0e10cSrcweir 		if ( nKey > nMax )
597cdf0e10cSrcweir 			nMax = nKey;
598cdf0e10cSrcweir 	}
599cdf0e10cSrcweir 
600cdf0e10cSrcweir 	// Der Aufruf kann aus ScPatternAttr::PutInPool kommen, darum Clone (echte Kopie)
601cdf0e10cSrcweir 
602cdf0e10cSrcweir 	sal_uLong nNewKey = nMax + 1;
603cdf0e10cSrcweir 	ScValidationData* pInsert = rNew.Clone(this);
604cdf0e10cSrcweir 	pInsert->SetKey( nNewKey );
605cdf0e10cSrcweir 	pValidationList->InsertNew( pInsert );
606cdf0e10cSrcweir 	return nNewKey;
607cdf0e10cSrcweir }
608cdf0e10cSrcweir 
GetEffItem(SCCOL nCol,SCROW nRow,SCTAB nTab,sal_uInt16 nWhich) const609cdf0e10cSrcweir const SfxPoolItem* ScDocument::GetEffItem(
610cdf0e10cSrcweir 						SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
611cdf0e10cSrcweir {
612cdf0e10cSrcweir 	const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
613cdf0e10cSrcweir 	if ( pPattern )
614cdf0e10cSrcweir 	{
615cdf0e10cSrcweir 		const SfxItemSet& rSet = pPattern->GetItemSet();
616cdf0e10cSrcweir 		const SfxPoolItem* pItem;
617cdf0e10cSrcweir 		if ( rSet.GetItemState( ATTR_CONDITIONAL, sal_True, &pItem ) == SFX_ITEM_SET )
618cdf0e10cSrcweir 		{
619cdf0e10cSrcweir 			sal_uLong nIndex = ((const SfxUInt32Item*)pItem)->GetValue();
620cdf0e10cSrcweir 			if (nIndex && pCondFormList)
621cdf0e10cSrcweir 			{
622cdf0e10cSrcweir 				const ScConditionalFormat* pForm = pCondFormList->GetFormat( nIndex );
623cdf0e10cSrcweir 				if ( pForm )
624cdf0e10cSrcweir 				{
625cdf0e10cSrcweir 					ScBaseCell* pCell = ((ScDocument*)this)->GetCell(ScAddress(nCol,nRow,nTab));
626cdf0e10cSrcweir 					String aStyle = pForm->GetCellStyle( pCell, ScAddress(nCol, nRow, nTab) );
627cdf0e10cSrcweir 					if (aStyle.Len())
628cdf0e10cSrcweir 					{
629cdf0e10cSrcweir 						SfxStyleSheetBase* pStyleSheet = xPoolHelper->GetStylePool()->Find(
630cdf0e10cSrcweir 																aStyle, SFX_STYLE_FAMILY_PARA );
631cdf0e10cSrcweir 						if ( pStyleSheet && pStyleSheet->GetItemSet().GetItemState(
632cdf0e10cSrcweir 												nWhich, sal_True, &pItem ) == SFX_ITEM_SET )
633cdf0e10cSrcweir 							return pItem;
634cdf0e10cSrcweir 					}
635cdf0e10cSrcweir 				}
636cdf0e10cSrcweir 			}
637cdf0e10cSrcweir 		}
638cdf0e10cSrcweir 		return &rSet.Get( nWhich );
639cdf0e10cSrcweir 	}
640cdf0e10cSrcweir 	DBG_ERROR("kein Pattern");
641cdf0e10cSrcweir 	return NULL;
642cdf0e10cSrcweir }
643cdf0e10cSrcweir 
GetCondResult(SCCOL nCol,SCROW nRow,SCTAB nTab) const644cdf0e10cSrcweir const SfxItemSet* ScDocument::GetCondResult( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
645cdf0e10cSrcweir {
646cdf0e10cSrcweir 	const ScConditionalFormat* pForm = GetCondFormat( nCol, nRow, nTab );
647cdf0e10cSrcweir 	if ( pForm )
648cdf0e10cSrcweir 	{
649cdf0e10cSrcweir 		ScBaseCell* pCell = ((ScDocument*)this)->GetCell(ScAddress(nCol,nRow,nTab));
650cdf0e10cSrcweir 		String aStyle = pForm->GetCellStyle( pCell, ScAddress(nCol, nRow, nTab) );
651cdf0e10cSrcweir 		if (aStyle.Len())
652cdf0e10cSrcweir 		{
653cdf0e10cSrcweir 			SfxStyleSheetBase* pStyleSheet = xPoolHelper->GetStylePool()->Find( aStyle, SFX_STYLE_FAMILY_PARA );
654cdf0e10cSrcweir 			if ( pStyleSheet )
655cdf0e10cSrcweir 				return &pStyleSheet->GetItemSet();
656cdf0e10cSrcweir 			// if style is not there, treat like no condition
657cdf0e10cSrcweir 		}
658cdf0e10cSrcweir 	}
659cdf0e10cSrcweir 	return NULL;
660cdf0e10cSrcweir }
661cdf0e10cSrcweir 
GetCondFormat(SCCOL nCol,SCROW nRow,SCTAB nTab) const662cdf0e10cSrcweir const ScConditionalFormat* ScDocument::GetCondFormat(
663cdf0e10cSrcweir 							SCCOL nCol, SCROW nRow, SCTAB nTab ) const
664cdf0e10cSrcweir {
665cdf0e10cSrcweir 	sal_uLong nIndex = ((const SfxUInt32Item*)GetAttr(nCol,nRow,nTab,ATTR_CONDITIONAL))->GetValue();
666cdf0e10cSrcweir 	if (nIndex)
667cdf0e10cSrcweir 	{
668cdf0e10cSrcweir 		if (pCondFormList)
669cdf0e10cSrcweir 			return pCondFormList->GetFormat( nIndex );
670cdf0e10cSrcweir 		else
671cdf0e10cSrcweir 		{
672cdf0e10cSrcweir 			DBG_ERROR("pCondFormList ist 0");
673cdf0e10cSrcweir 		}
674cdf0e10cSrcweir 	}
675cdf0e10cSrcweir 
676cdf0e10cSrcweir 	return NULL;
677cdf0e10cSrcweir }
678cdf0e10cSrcweir 
GetValidationEntry(sal_uLong nIndex) const679cdf0e10cSrcweir const ScValidationData*	ScDocument::GetValidationEntry( sal_uLong nIndex ) const
680cdf0e10cSrcweir {
681cdf0e10cSrcweir 	if ( pValidationList )
682cdf0e10cSrcweir 		return pValidationList->GetData( nIndex );
683cdf0e10cSrcweir 	else
684cdf0e10cSrcweir 		return NULL;
685cdf0e10cSrcweir }
686cdf0e10cSrcweir 
FindConditionalFormat(sal_uLong nKey,ScRangeList & rRanges)687cdf0e10cSrcweir void ScDocument::FindConditionalFormat( sal_uLong nKey, ScRangeList& rRanges )
688cdf0e10cSrcweir {
689cdf0e10cSrcweir 	for (SCTAB i=0; i<=MAXTAB && pTab[i]; i++)
690cdf0e10cSrcweir 		pTab[i]->FindConditionalFormat( nKey, rRanges );
691cdf0e10cSrcweir }
692cdf0e10cSrcweir 
FindConditionalFormat(sal_uLong nKey,ScRangeList & rRanges,SCTAB nTab)693cdf0e10cSrcweir void ScDocument::FindConditionalFormat( sal_uLong nKey, ScRangeList& rRanges, SCTAB nTab )
694cdf0e10cSrcweir {
695cdf0e10cSrcweir     if(VALIDTAB(nTab) && pTab[nTab])
696cdf0e10cSrcweir         pTab[nTab]->FindConditionalFormat( nKey, rRanges );
697cdf0e10cSrcweir }
698cdf0e10cSrcweir 
ConditionalChanged(sal_uLong nKey)699cdf0e10cSrcweir void ScDocument::ConditionalChanged( sal_uLong nKey )
700cdf0e10cSrcweir {
701cdf0e10cSrcweir 	if ( nKey && pCondFormList && !bIsClip && !bIsUndo )		// nKey==0 -> noop
702cdf0e10cSrcweir 	{
703cdf0e10cSrcweir 		ScConditionalFormat* pForm = pCondFormList->GetFormat( nKey );
704cdf0e10cSrcweir 		if (pForm)
705cdf0e10cSrcweir 			pForm->InvalidateArea();
706cdf0e10cSrcweir 	}
707cdf0e10cSrcweir }
708cdf0e10cSrcweir 
SetCondFormList(ScConditionalFormatList * pNew)709cdf0e10cSrcweir void ScDocument::SetCondFormList(ScConditionalFormatList* pNew)
710cdf0e10cSrcweir {
711cdf0e10cSrcweir 	if (pCondFormList)
712cdf0e10cSrcweir 	{
713cdf0e10cSrcweir 		pCondFormList->DeleteAndDestroy( 0, pCondFormList->Count() );
714cdf0e10cSrcweir 		delete pCondFormList;
715cdf0e10cSrcweir 	}
716cdf0e10cSrcweir 
717cdf0e10cSrcweir 	pCondFormList = pNew;
718cdf0e10cSrcweir }
719cdf0e10cSrcweir 
720cdf0e10cSrcweir //------------------------------------------------------------------------
721cdf0e10cSrcweir 
HasDetectiveOperations() const722cdf0e10cSrcweir sal_Bool ScDocument::HasDetectiveOperations() const
723cdf0e10cSrcweir {
724cdf0e10cSrcweir 	return pDetOpList && pDetOpList->Count();
725cdf0e10cSrcweir }
726cdf0e10cSrcweir 
AddDetectiveOperation(const ScDetOpData & rData)727cdf0e10cSrcweir void ScDocument::AddDetectiveOperation( const ScDetOpData& rData )
728cdf0e10cSrcweir {
729cdf0e10cSrcweir 	if (!pDetOpList)
730cdf0e10cSrcweir 		pDetOpList = new ScDetOpList;
731cdf0e10cSrcweir 
732cdf0e10cSrcweir 	pDetOpList->Append( new ScDetOpData( rData ) );
733cdf0e10cSrcweir }
734cdf0e10cSrcweir 
ClearDetectiveOperations()735cdf0e10cSrcweir void ScDocument::ClearDetectiveOperations()
736cdf0e10cSrcweir {
737cdf0e10cSrcweir 	delete pDetOpList;		// loescht auch die Eintraege
738cdf0e10cSrcweir 	pDetOpList = NULL;
739cdf0e10cSrcweir }
740cdf0e10cSrcweir 
SetDetOpList(ScDetOpList * pNew)741cdf0e10cSrcweir void ScDocument::SetDetOpList(ScDetOpList* pNew)
742cdf0e10cSrcweir {
743cdf0e10cSrcweir 	delete pDetOpList;		// loescht auch die Eintraege
744cdf0e10cSrcweir 	pDetOpList = pNew;
745cdf0e10cSrcweir }
746cdf0e10cSrcweir 
747cdf0e10cSrcweir //------------------------------------------------------------------------
748cdf0e10cSrcweir //
749cdf0e10cSrcweir //		Vergleich von Dokumenten
750cdf0e10cSrcweir //
751cdf0e10cSrcweir //------------------------------------------------------------------------
752cdf0e10cSrcweir 
753cdf0e10cSrcweir //	Pfriemel-Faktoren
754cdf0e10cSrcweir #define SC_DOCCOMP_MAXDIFF	256
755cdf0e10cSrcweir #define SC_DOCCOMP_MINGOOD	128
756cdf0e10cSrcweir #define SC_DOCCOMP_COLUMNS	10
757cdf0e10cSrcweir #define SC_DOCCOMP_ROWS		100
758cdf0e10cSrcweir 
759cdf0e10cSrcweir 
RowDifferences(SCROW nThisRow,SCTAB nThisTab,ScDocument & rOtherDoc,SCROW nOtherRow,SCTAB nOtherTab,SCCOL nMaxCol,SCCOLROW * pOtherCols)760cdf0e10cSrcweir sal_uInt16 ScDocument::RowDifferences( SCROW nThisRow, SCTAB nThisTab,
761cdf0e10cSrcweir 									ScDocument& rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab,
762cdf0e10cSrcweir 									SCCOL nMaxCol, SCCOLROW* pOtherCols )
763cdf0e10cSrcweir {
764cdf0e10cSrcweir 	sal_uLong nDif = 0;
765cdf0e10cSrcweir 	sal_uLong nUsed = 0;
766cdf0e10cSrcweir 	for (SCCOL nThisCol=0; nThisCol<=nMaxCol; nThisCol++)
767cdf0e10cSrcweir 	{
768cdf0e10cSrcweir 		SCCOL nOtherCol;
769cdf0e10cSrcweir 		if ( pOtherCols )
770cdf0e10cSrcweir 			nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
771cdf0e10cSrcweir 		else
772cdf0e10cSrcweir 			nOtherCol = nThisCol;
773cdf0e10cSrcweir 
774cdf0e10cSrcweir 		if (ValidCol(nOtherCol))	// nur Spalten vergleichen, die in beiden Dateien sind
775cdf0e10cSrcweir 		{
776cdf0e10cSrcweir 			const ScBaseCell* pThisCell = GetCell( ScAddress( nThisCol, nThisRow, nThisTab ) );
777cdf0e10cSrcweir 			const ScBaseCell* pOtherCell = rOtherDoc.GetCell( ScAddress( nOtherCol, nOtherRow, nOtherTab ) );
778cdf0e10cSrcweir 			if (!ScBaseCell::CellEqual( pThisCell, pOtherCell ))
779cdf0e10cSrcweir 			{
780cdf0e10cSrcweir 				if ( pThisCell && pOtherCell )
781cdf0e10cSrcweir 					nDif += 3;
782cdf0e10cSrcweir 				else
783cdf0e10cSrcweir 					nDif += 4;		// Inhalt <-> leer zaehlt mehr
784cdf0e10cSrcweir 			}
785cdf0e10cSrcweir 
786cdf0e10cSrcweir 			if ( ( pThisCell  && pThisCell->GetCellType()!=CELLTYPE_NOTE ) ||
787cdf0e10cSrcweir 				 ( pOtherCell && pOtherCell->GetCellType()!=CELLTYPE_NOTE ) )
788cdf0e10cSrcweir 				++nUsed;
789cdf0e10cSrcweir 		}
790cdf0e10cSrcweir 	}
791cdf0e10cSrcweir 
792cdf0e10cSrcweir 	if (nUsed > 0)
793cdf0e10cSrcweir 		return static_cast<sal_uInt16>((nDif*64)/nUsed);			// max.256 (SC_DOCCOMP_MAXDIFF)
794cdf0e10cSrcweir 
795cdf0e10cSrcweir 	DBG_ASSERT(!nDif,"Diff ohne Used");
796cdf0e10cSrcweir 	return 0;
797cdf0e10cSrcweir }
798cdf0e10cSrcweir 
ColDifferences(SCCOL nThisCol,SCTAB nThisTab,ScDocument & rOtherDoc,SCCOL nOtherCol,SCTAB nOtherTab,SCROW nMaxRow,SCCOLROW * pOtherRows)799cdf0e10cSrcweir sal_uInt16 ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
800cdf0e10cSrcweir 									ScDocument& rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab,
801cdf0e10cSrcweir 									SCROW nMaxRow, SCCOLROW* pOtherRows )
802cdf0e10cSrcweir {
803cdf0e10cSrcweir 	//!	optimieren mit Iterator oder so
804cdf0e10cSrcweir 
805cdf0e10cSrcweir 	sal_uLong nDif = 0;
806cdf0e10cSrcweir 	sal_uLong nUsed = 0;
807cdf0e10cSrcweir 	for (SCROW nThisRow=0; nThisRow<=nMaxRow; nThisRow++)
808cdf0e10cSrcweir 	{
809cdf0e10cSrcweir 		SCROW nOtherRow;
810cdf0e10cSrcweir 		if ( pOtherRows )
811cdf0e10cSrcweir 			nOtherRow = pOtherRows[nThisRow];
812cdf0e10cSrcweir 		else
813cdf0e10cSrcweir 			nOtherRow = nThisRow;
814cdf0e10cSrcweir 
815cdf0e10cSrcweir 		if (ValidRow(nOtherRow))	// nur Zeilen vergleichen, die in beiden Dateien sind
816cdf0e10cSrcweir 		{
817cdf0e10cSrcweir 			const ScBaseCell* pThisCell = GetCell( ScAddress( nThisCol, nThisRow, nThisTab ) );
818cdf0e10cSrcweir 			const ScBaseCell* pOtherCell = rOtherDoc.GetCell( ScAddress( nOtherCol, nOtherRow, nOtherTab ) );
819cdf0e10cSrcweir 			if (!ScBaseCell::CellEqual( pThisCell, pOtherCell ))
820cdf0e10cSrcweir 			{
821cdf0e10cSrcweir 				if ( pThisCell && pOtherCell )
822cdf0e10cSrcweir 					nDif += 3;
823cdf0e10cSrcweir 				else
824cdf0e10cSrcweir 					nDif += 4;		// Inhalt <-> leer zaehlt mehr
825cdf0e10cSrcweir 			}
826cdf0e10cSrcweir 
827cdf0e10cSrcweir 			if ( ( pThisCell  && pThisCell->GetCellType()!=CELLTYPE_NOTE ) ||
828cdf0e10cSrcweir 				 ( pOtherCell && pOtherCell->GetCellType()!=CELLTYPE_NOTE ) )
829cdf0e10cSrcweir 				++nUsed;
830cdf0e10cSrcweir 		}
831cdf0e10cSrcweir 	}
832cdf0e10cSrcweir 
833cdf0e10cSrcweir 	if (nUsed > 0)
834cdf0e10cSrcweir 		return static_cast<sal_uInt16>((nDif*64)/nUsed);	// max.256
835cdf0e10cSrcweir 
836cdf0e10cSrcweir 	DBG_ASSERT(!nDif,"Diff ohne Used");
837cdf0e10cSrcweir 	return 0;
838cdf0e10cSrcweir }
839cdf0e10cSrcweir 
FindOrder(SCCOLROW * pOtherRows,SCCOLROW nThisEndRow,SCCOLROW nOtherEndRow,sal_Bool bColumns,ScDocument & rOtherDoc,SCTAB nThisTab,SCTAB nOtherTab,SCCOLROW nEndCol,SCCOLROW * pTranslate,ScProgress * pProgress,sal_uLong nProAdd)840cdf0e10cSrcweir void ScDocument::FindOrder( SCCOLROW* pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow,
841cdf0e10cSrcweir 							sal_Bool bColumns, ScDocument& rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab,
842cdf0e10cSrcweir 							SCCOLROW nEndCol, SCCOLROW* pTranslate, ScProgress* pProgress, sal_uLong nProAdd )
843cdf0e10cSrcweir {
844cdf0e10cSrcweir 	//	bColumns=sal_True: Zeilen sind Spalten und umgekehrt
845cdf0e10cSrcweir 
846cdf0e10cSrcweir 	SCCOLROW nMaxCont;						// wieviel weiter
847cdf0e10cSrcweir 	SCCOLROW nMinGood;						// was ist ein Treffer (incl.)
848cdf0e10cSrcweir 	if ( bColumns )
849cdf0e10cSrcweir 	{
850cdf0e10cSrcweir 		nMaxCont = SC_DOCCOMP_COLUMNS;		// 10 Spalten
851cdf0e10cSrcweir 		nMinGood = SC_DOCCOMP_MINGOOD;
852cdf0e10cSrcweir 		//!	Extra Durchgang mit nMinGood = 0 ????
853cdf0e10cSrcweir 	}
854cdf0e10cSrcweir 	else
855cdf0e10cSrcweir 	{
856cdf0e10cSrcweir 		nMaxCont = SC_DOCCOMP_ROWS;			// 100 Zeilen
857cdf0e10cSrcweir 		nMinGood = SC_DOCCOMP_MINGOOD;
858cdf0e10cSrcweir 	}
859cdf0e10cSrcweir 	sal_Bool bUseTotal = bColumns && !pTranslate;		// nur beim ersten Durchgang
860cdf0e10cSrcweir 
861cdf0e10cSrcweir 
862cdf0e10cSrcweir 	SCCOLROW nOtherRow = 0;
863cdf0e10cSrcweir 	sal_uInt16 nComp;
864cdf0e10cSrcweir 	SCCOLROW nThisRow;
865cdf0e10cSrcweir 	sal_Bool bTotal = sal_False;		// ueber verschiedene nThisRow beibehalten
866cdf0e10cSrcweir 	SCCOLROW nUnknown = 0;
867cdf0e10cSrcweir 	for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
868cdf0e10cSrcweir 	{
869cdf0e10cSrcweir 		SCCOLROW nTempOther = nOtherRow;
870cdf0e10cSrcweir 		sal_Bool bFound = sal_False;
871cdf0e10cSrcweir 		sal_uInt16 nBest = SC_DOCCOMP_MAXDIFF;
872cdf0e10cSrcweir 		SCCOLROW nMax = Min( nOtherEndRow, static_cast<SCCOLROW>(( nTempOther + nMaxCont + nUnknown )) );
873cdf0e10cSrcweir 		for (SCCOLROW i=nTempOther; i<=nMax && nBest>0; i++)	// bei 0 abbrechen
874cdf0e10cSrcweir 		{
875cdf0e10cSrcweir 			if (bColumns)
876cdf0e10cSrcweir 				nComp = ColDifferences( static_cast<SCCOL>(nThisRow), nThisTab, rOtherDoc, static_cast<SCCOL>(i), nOtherTab, nEndCol, pTranslate );
877cdf0e10cSrcweir 			else
878cdf0e10cSrcweir 				nComp = RowDifferences( nThisRow, nThisTab, rOtherDoc, i, nOtherTab, static_cast<SCCOL>(nEndCol), pTranslate );
879cdf0e10cSrcweir 			if ( nComp < nBest && ( nComp <= nMinGood || bTotal ) )
880cdf0e10cSrcweir 			{
881cdf0e10cSrcweir 				nTempOther = i;
882cdf0e10cSrcweir 				nBest = nComp;
883cdf0e10cSrcweir 				bFound = sal_True;
884cdf0e10cSrcweir 			}
885cdf0e10cSrcweir 			if ( nComp < SC_DOCCOMP_MAXDIFF || bFound )
886cdf0e10cSrcweir 				bTotal = sal_False;
887cdf0e10cSrcweir 			else if ( i == nTempOther && bUseTotal )
888cdf0e10cSrcweir 				bTotal = sal_True;							// nur ganz oben
889cdf0e10cSrcweir 		}
890cdf0e10cSrcweir 		if ( bFound )
891cdf0e10cSrcweir 		{
892cdf0e10cSrcweir 			pOtherRows[nThisRow] = nTempOther;
893cdf0e10cSrcweir 			nOtherRow = nTempOther + 1;
894cdf0e10cSrcweir 			nUnknown = 0;
895cdf0e10cSrcweir 		}
896cdf0e10cSrcweir 		else
897cdf0e10cSrcweir 		{
898cdf0e10cSrcweir 			pOtherRows[nThisRow] = SCROW_MAX;
899cdf0e10cSrcweir 			++nUnknown;
900cdf0e10cSrcweir 		}
901cdf0e10cSrcweir 
902cdf0e10cSrcweir 		if (pProgress)
903cdf0e10cSrcweir 			pProgress->SetStateOnPercent(nProAdd+static_cast<sal_uLong>(nThisRow));
904cdf0e10cSrcweir 	}
905cdf0e10cSrcweir 
906cdf0e10cSrcweir 	//	Bloecke ohne Uebereinstimmung ausfuellen
907cdf0e10cSrcweir 
908cdf0e10cSrcweir 	SCROW nFillStart = 0;
909cdf0e10cSrcweir 	SCROW nFillPos = 0;
910cdf0e10cSrcweir 	sal_Bool bInFill = sal_False;
911cdf0e10cSrcweir 	for (nThisRow = 0; nThisRow <= nThisEndRow+1; nThisRow++)
912cdf0e10cSrcweir 	{
913cdf0e10cSrcweir 		SCROW nThisOther = ( nThisRow <= nThisEndRow ) ? pOtherRows[nThisRow] : (nOtherEndRow+1);
914cdf0e10cSrcweir 		if ( ValidRow(nThisOther) )
915cdf0e10cSrcweir 		{
916cdf0e10cSrcweir 			if ( bInFill )
917cdf0e10cSrcweir 			{
918cdf0e10cSrcweir 				if ( nThisOther > nFillStart )		// ist was zu verteilen da?
919cdf0e10cSrcweir 				{
920cdf0e10cSrcweir 					SCROW nDiff1 = nThisOther - nFillStart;
921cdf0e10cSrcweir 					SCROW nDiff2 = nThisRow   - nFillPos;
922cdf0e10cSrcweir 					SCROW nMinDiff = Min(nDiff1, nDiff2);
923cdf0e10cSrcweir 					for (SCROW i=0; i<nMinDiff; i++)
924cdf0e10cSrcweir 						pOtherRows[nFillPos+i] = nFillStart+i;
925cdf0e10cSrcweir 				}
926cdf0e10cSrcweir 
927cdf0e10cSrcweir 				bInFill = sal_False;
928cdf0e10cSrcweir 			}
929cdf0e10cSrcweir 			nFillStart = nThisOther + 1;
930cdf0e10cSrcweir 			nFillPos = nThisRow + 1;
931cdf0e10cSrcweir 		}
932cdf0e10cSrcweir 		else
933cdf0e10cSrcweir 			bInFill = sal_True;
934cdf0e10cSrcweir 	}
935cdf0e10cSrcweir }
936cdf0e10cSrcweir 
CompareDocument(ScDocument & rOtherDoc)937cdf0e10cSrcweir void ScDocument::CompareDocument( ScDocument& rOtherDoc )
938cdf0e10cSrcweir {
939cdf0e10cSrcweir 	if (!pChangeTrack)
940cdf0e10cSrcweir 		return;
941cdf0e10cSrcweir 
942cdf0e10cSrcweir 	SCTAB nThisCount = GetTableCount();
943cdf0e10cSrcweir 	SCTAB nOtherCount = rOtherDoc.GetTableCount();
944cdf0e10cSrcweir 	SCTAB* pOtherTabs = new SCTAB[nThisCount];
945cdf0e10cSrcweir 	SCTAB nThisTab;
946cdf0e10cSrcweir 
947cdf0e10cSrcweir 	//	Tabellen mit gleichen Namen vergleichen
948cdf0e10cSrcweir 	String aThisName;
949cdf0e10cSrcweir 	String aOtherName;
950cdf0e10cSrcweir 	for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
951cdf0e10cSrcweir 	{
952cdf0e10cSrcweir 		SCTAB nOtherTab = SCTAB_MAX;
953cdf0e10cSrcweir 		if (!IsScenario(nThisTab))	// Szenarien weglassen
954cdf0e10cSrcweir 		{
955cdf0e10cSrcweir 			GetName( nThisTab, aThisName );
956cdf0e10cSrcweir 			for (SCTAB nTemp=0; nTemp<nOtherCount && nOtherTab>MAXTAB; nTemp++)
957cdf0e10cSrcweir 				if (!rOtherDoc.IsScenario(nTemp))
958cdf0e10cSrcweir 				{
959cdf0e10cSrcweir 					rOtherDoc.GetName( nTemp, aOtherName );
960cdf0e10cSrcweir 					if ( aThisName == aOtherName )
961cdf0e10cSrcweir 						nOtherTab = nTemp;
962cdf0e10cSrcweir 				}
963cdf0e10cSrcweir 		}
964cdf0e10cSrcweir 		pOtherTabs[nThisTab] = nOtherTab;
965cdf0e10cSrcweir 	}
966cdf0e10cSrcweir 	//	auffuellen, damit einzeln umbenannte Tabellen nicht wegfallen
967cdf0e10cSrcweir 	SCTAB nFillStart = 0;
968cdf0e10cSrcweir 	SCTAB nFillPos = 0;
969cdf0e10cSrcweir 	sal_Bool bInFill = sal_False;
970cdf0e10cSrcweir 	for (nThisTab = 0; nThisTab <= nThisCount; nThisTab++)
971cdf0e10cSrcweir 	{
972cdf0e10cSrcweir 		SCTAB nThisOther = ( nThisTab < nThisCount ) ? pOtherTabs[nThisTab] : nOtherCount;
973cdf0e10cSrcweir 		if ( ValidTab(nThisOther) )
974cdf0e10cSrcweir 		{
975cdf0e10cSrcweir 			if ( bInFill )
976cdf0e10cSrcweir 			{
977cdf0e10cSrcweir 				if ( nThisOther > nFillStart )		// ist was zu verteilen da?
978cdf0e10cSrcweir 				{
979cdf0e10cSrcweir 					SCTAB nDiff1 = nThisOther - nFillStart;
980cdf0e10cSrcweir 					SCTAB nDiff2 = nThisTab   - nFillPos;
981cdf0e10cSrcweir 					SCTAB nMinDiff = Min(nDiff1, nDiff2);
982cdf0e10cSrcweir 					for (SCTAB i=0; i<nMinDiff; i++)
983cdf0e10cSrcweir 						if ( !IsScenario(nFillPos+i) && !rOtherDoc.IsScenario(nFillStart+i) )
984cdf0e10cSrcweir 							pOtherTabs[nFillPos+i] = nFillStart+i;
985cdf0e10cSrcweir 				}
986cdf0e10cSrcweir 
987cdf0e10cSrcweir 				bInFill = sal_False;
988cdf0e10cSrcweir 			}
989cdf0e10cSrcweir 			nFillStart = nThisOther + 1;
990cdf0e10cSrcweir 			nFillPos = nThisTab + 1;
991cdf0e10cSrcweir 		}
992cdf0e10cSrcweir 		else
993cdf0e10cSrcweir 			bInFill = sal_True;
994cdf0e10cSrcweir 	}
995cdf0e10cSrcweir 
996cdf0e10cSrcweir 	//
997cdf0e10cSrcweir 	//	Tabellen in der gefundenen Reihenfolge vergleichen
998cdf0e10cSrcweir 	//
999cdf0e10cSrcweir 
1000cdf0e10cSrcweir 	for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
1001cdf0e10cSrcweir 	{
1002cdf0e10cSrcweir 		SCTAB nOtherTab = pOtherTabs[nThisTab];
1003cdf0e10cSrcweir 		if ( ValidTab(nOtherTab) )
1004cdf0e10cSrcweir 		{
1005cdf0e10cSrcweir 			SCCOL nThisEndCol = 0;
1006cdf0e10cSrcweir 			SCROW nThisEndRow = 0;
1007cdf0e10cSrcweir 			SCCOL nOtherEndCol = 0;
1008cdf0e10cSrcweir 			SCROW nOtherEndRow = 0;
1009cdf0e10cSrcweir 			GetCellArea( nThisTab, nThisEndCol, nThisEndRow );
1010cdf0e10cSrcweir 			rOtherDoc.GetCellArea( nOtherTab, nOtherEndCol, nOtherEndRow );
1011cdf0e10cSrcweir 			SCCOL nEndCol = Max(nThisEndCol, nOtherEndCol);
1012cdf0e10cSrcweir 			SCROW nEndRow = Max(nThisEndRow, nOtherEndRow);
1013cdf0e10cSrcweir 			SCCOL nThisCol;
1014cdf0e10cSrcweir 			SCROW nThisRow;
1015cdf0e10cSrcweir 			sal_uLong n1,n2;	// fuer AppendDeleteRange
1016cdf0e10cSrcweir 
1017cdf0e10cSrcweir 			//!	ein Progress ueber alle Tabellen ???
1018cdf0e10cSrcweir 			String aTabName;
1019cdf0e10cSrcweir 			GetName( nThisTab, aTabName );
1020cdf0e10cSrcweir 			String aTemplate = ScGlobal::GetRscString(STR_PROGRESS_COMPARING);
1021cdf0e10cSrcweir 			String aProText = aTemplate.GetToken( 0, '#' );
1022cdf0e10cSrcweir 			aProText += aTabName;
1023cdf0e10cSrcweir 			aProText += aTemplate.GetToken( 1, '#' );
1024cdf0e10cSrcweir 			ScProgress aProgress( GetDocumentShell(),
1025cdf0e10cSrcweir 										aProText, 3*nThisEndRow );	// 2x FindOrder, 1x hier
1026cdf0e10cSrcweir 			long nProgressStart = 2*nThisEndRow;					// start fuer hier
1027cdf0e10cSrcweir 
1028cdf0e10cSrcweir 			SCCOLROW* pTempRows = new SCCOLROW[nThisEndRow+1];
1029cdf0e10cSrcweir 			SCCOLROW* pOtherRows = new SCCOLROW[nThisEndRow+1];
1030cdf0e10cSrcweir 			SCCOLROW* pOtherCols = new SCCOLROW[nThisEndCol+1];
1031cdf0e10cSrcweir 
1032cdf0e10cSrcweir 			//	eingefuegte/geloeschte Spalten/Zeilen finden:
1033cdf0e10cSrcweir 			//	Zwei Versuche:
1034cdf0e10cSrcweir 			//	1) Original Zeilen vergleichen							(pTempRows)
1035cdf0e10cSrcweir 			//	2) Original Spalten vergleichen							(pOtherCols)
1036cdf0e10cSrcweir 			//	   mit dieser Spaltenreihenfolge Zeilen vergleichen		(pOtherRows)
1037cdf0e10cSrcweir 
1038cdf0e10cSrcweir 			//!	Spalten vergleichen zweimal mit unterschiedlichem nMinGood ???
1039cdf0e10cSrcweir 
1040cdf0e10cSrcweir 			// 1
1041cdf0e10cSrcweir 			FindOrder( pTempRows, nThisEndRow, nOtherEndRow, sal_False,
1042cdf0e10cSrcweir 						rOtherDoc, nThisTab, nOtherTab, nEndCol, NULL, &aProgress, 0 );
1043cdf0e10cSrcweir 			// 2
1044cdf0e10cSrcweir 			FindOrder( pOtherCols, nThisEndCol, nOtherEndCol, sal_True,
1045cdf0e10cSrcweir 						rOtherDoc, nThisTab, nOtherTab, nEndRow, NULL, NULL, 0 );
1046cdf0e10cSrcweir 			FindOrder( pOtherRows, nThisEndRow, nOtherEndRow, sal_False,
1047cdf0e10cSrcweir 						rOtherDoc, nThisTab, nOtherTab, nThisEndCol,
1048cdf0e10cSrcweir 						pOtherCols, &aProgress, nThisEndRow );
1049cdf0e10cSrcweir 
1050cdf0e10cSrcweir 			sal_uLong nMatch1 = 0;	// pTempRows, keine Spalten
1051cdf0e10cSrcweir 			for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
1052cdf0e10cSrcweir 				if (ValidRow(pTempRows[nThisRow]))
1053cdf0e10cSrcweir 					nMatch1 += SC_DOCCOMP_MAXDIFF -
1054cdf0e10cSrcweir 							   RowDifferences( nThisRow, nThisTab, rOtherDoc, pTempRows[nThisRow],
1055cdf0e10cSrcweir 												nOtherTab, nEndCol, NULL );
1056cdf0e10cSrcweir 
1057cdf0e10cSrcweir 			sal_uLong nMatch2 = 0;	// pOtherRows, pOtherCols
1058cdf0e10cSrcweir 			for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
1059cdf0e10cSrcweir 				if (ValidRow(pOtherRows[nThisRow]))
1060cdf0e10cSrcweir 					nMatch2 += SC_DOCCOMP_MAXDIFF -
1061cdf0e10cSrcweir 							   RowDifferences( nThisRow, nThisTab, rOtherDoc, pOtherRows[nThisRow],
1062cdf0e10cSrcweir 												nOtherTab, nThisEndCol, pOtherCols );
1063cdf0e10cSrcweir 
1064cdf0e10cSrcweir 			if ( nMatch1 >= nMatch2 )			// ohne Spalten ?
1065cdf0e10cSrcweir 			{
1066cdf0e10cSrcweir 				//	Spalten zuruecksetzen
1067cdf0e10cSrcweir 				for (nThisCol = 0; nThisCol<=nThisEndCol; nThisCol++)
1068cdf0e10cSrcweir 					pOtherCols[nThisCol] = nThisCol;
1069cdf0e10cSrcweir 
1070cdf0e10cSrcweir 				//	Zeilenarrays vertauschen (geloescht werden sowieso beide)
1071cdf0e10cSrcweir 				SCCOLROW* pSwap = pTempRows;
1072cdf0e10cSrcweir 				pTempRows = pOtherRows;
1073cdf0e10cSrcweir 				pOtherRows = pSwap;
1074cdf0e10cSrcweir 			}
1075cdf0e10cSrcweir 			else
1076cdf0e10cSrcweir 			{
1077cdf0e10cSrcweir 				//	bleibt bei pOtherCols, pOtherRows
1078cdf0e10cSrcweir 			}
1079cdf0e10cSrcweir 
1080cdf0e10cSrcweir 
1081cdf0e10cSrcweir 			//	Change-Actions erzeugen
1082cdf0e10cSrcweir 			//	1) Spalten von rechts
1083cdf0e10cSrcweir 			//	2) Zeilen von unten
1084cdf0e10cSrcweir 			//	3) einzelne Zellen in normaler Reihenfolge
1085cdf0e10cSrcweir 
1086cdf0e10cSrcweir 			//	Actions fuer eingefuegte/geloeschte Spalten
1087cdf0e10cSrcweir 
1088cdf0e10cSrcweir 			SCCOL nLastOtherCol = static_cast<SCCOL>(nOtherEndCol + 1);
1089cdf0e10cSrcweir 			//	nThisEndCol ... 0
1090cdf0e10cSrcweir 			for ( nThisCol = nThisEndCol+1; nThisCol > 0; )
1091cdf0e10cSrcweir 			{
1092cdf0e10cSrcweir 				--nThisCol;
1093cdf0e10cSrcweir 				SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
1094cdf0e10cSrcweir 				if ( ValidCol(nOtherCol) && nOtherCol+1 < nLastOtherCol )
1095cdf0e10cSrcweir 				{
1096cdf0e10cSrcweir 					// Luecke -> geloescht
1097cdf0e10cSrcweir 					ScRange aDelRange( nOtherCol+1, 0, nOtherTab,
1098cdf0e10cSrcweir 										nLastOtherCol-1, MAXROW, nOtherTab );
1099cdf0e10cSrcweir 					pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1100cdf0e10cSrcweir 				}
1101cdf0e10cSrcweir 				if ( nOtherCol > MAXCOL )						// eingefuegt
1102cdf0e10cSrcweir 				{
1103cdf0e10cSrcweir 					//	zusammenfassen
1104cdf0e10cSrcweir 					if ( nThisCol == nThisEndCol || ValidCol(static_cast<SCCOL>(pOtherCols[nThisCol+1])) )
1105cdf0e10cSrcweir 					{
1106cdf0e10cSrcweir 						SCCOL nFirstNew = static_cast<SCCOL>(nThisCol);
1107cdf0e10cSrcweir 						while ( nFirstNew > 0 && pOtherCols[nFirstNew-1] > MAXCOL )
1108cdf0e10cSrcweir 							--nFirstNew;
1109cdf0e10cSrcweir 						SCCOL nDiff = nThisCol - nFirstNew;
1110cdf0e10cSrcweir 						ScRange aRange( nLastOtherCol, 0, nOtherTab,
1111cdf0e10cSrcweir 										nLastOtherCol+nDiff, MAXROW, nOtherTab );
1112cdf0e10cSrcweir 						pChangeTrack->AppendInsert( aRange );
1113cdf0e10cSrcweir 					}
1114cdf0e10cSrcweir 				}
1115cdf0e10cSrcweir 				else
1116cdf0e10cSrcweir 					nLastOtherCol = nOtherCol;
1117cdf0e10cSrcweir 			}
1118cdf0e10cSrcweir 			if ( nLastOtherCol > 0 )							// ganz oben geloescht
1119cdf0e10cSrcweir 			{
1120cdf0e10cSrcweir 				ScRange aDelRange( 0, 0, nOtherTab,
1121cdf0e10cSrcweir 									nLastOtherCol-1, MAXROW, nOtherTab );
1122cdf0e10cSrcweir 				pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1123cdf0e10cSrcweir 			}
1124cdf0e10cSrcweir 
1125cdf0e10cSrcweir 			//	Actions fuer eingefuegte/geloeschte Zeilen
1126cdf0e10cSrcweir 
1127cdf0e10cSrcweir 			SCROW nLastOtherRow = nOtherEndRow + 1;
1128cdf0e10cSrcweir 			//	nThisEndRow ... 0
1129cdf0e10cSrcweir 			for ( nThisRow = nThisEndRow+1; nThisRow > 0; )
1130cdf0e10cSrcweir 			{
1131cdf0e10cSrcweir 				--nThisRow;
1132cdf0e10cSrcweir 				SCROW nOtherRow = pOtherRows[nThisRow];
1133cdf0e10cSrcweir 				if ( ValidRow(nOtherRow) && nOtherRow+1 < nLastOtherRow )
1134cdf0e10cSrcweir 				{
1135cdf0e10cSrcweir 					// Luecke -> geloescht
1136cdf0e10cSrcweir 					ScRange aDelRange( 0, nOtherRow+1, nOtherTab,
1137cdf0e10cSrcweir 										MAXCOL, nLastOtherRow-1, nOtherTab );
1138cdf0e10cSrcweir 					pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1139cdf0e10cSrcweir 				}
1140cdf0e10cSrcweir 				if ( nOtherRow > MAXROW )						// eingefuegt
1141cdf0e10cSrcweir 				{
1142cdf0e10cSrcweir 					//	zusammenfassen
1143cdf0e10cSrcweir 					if ( nThisRow == nThisEndRow || ValidRow(pOtherRows[nThisRow+1]) )
1144cdf0e10cSrcweir 					{
1145cdf0e10cSrcweir 						SCROW nFirstNew = nThisRow;
1146cdf0e10cSrcweir 						while ( nFirstNew > 0 && pOtherRows[nFirstNew-1] > MAXROW )
1147cdf0e10cSrcweir 							--nFirstNew;
1148cdf0e10cSrcweir 						SCROW nDiff = nThisRow - nFirstNew;
1149cdf0e10cSrcweir 						ScRange aRange( 0, nLastOtherRow, nOtherTab,
1150cdf0e10cSrcweir 										MAXCOL, nLastOtherRow+nDiff, nOtherTab );
1151cdf0e10cSrcweir 						pChangeTrack->AppendInsert( aRange );
1152cdf0e10cSrcweir 					}
1153cdf0e10cSrcweir 				}
1154cdf0e10cSrcweir 				else
1155cdf0e10cSrcweir 					nLastOtherRow = nOtherRow;
1156cdf0e10cSrcweir 			}
1157cdf0e10cSrcweir 			if ( nLastOtherRow > 0 )							// ganz oben geloescht
1158cdf0e10cSrcweir 			{
1159cdf0e10cSrcweir 				ScRange aDelRange( 0, 0, nOtherTab,
1160cdf0e10cSrcweir 									MAXCOL, nLastOtherRow-1, nOtherTab );
1161cdf0e10cSrcweir 				pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
1162cdf0e10cSrcweir 			}
1163cdf0e10cSrcweir 
1164cdf0e10cSrcweir 			//	Zeilen durchgehen um einzelne Zellen zu finden
1165cdf0e10cSrcweir 
1166cdf0e10cSrcweir 			for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
1167cdf0e10cSrcweir 			{
1168cdf0e10cSrcweir 				SCROW nOtherRow = pOtherRows[nThisRow];
1169cdf0e10cSrcweir                 for (nThisCol = 0; nThisCol <= nThisEndCol; nThisCol++)
1170cdf0e10cSrcweir 				{
1171cdf0e10cSrcweir 					SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
1172cdf0e10cSrcweir 					ScAddress aThisPos( nThisCol, nThisRow, nThisTab );
1173cdf0e10cSrcweir 					const ScBaseCell* pThisCell = GetCell( aThisPos );
1174cdf0e10cSrcweir 					const ScBaseCell* pOtherCell = NULL;
1175cdf0e10cSrcweir 					if ( ValidCol(nOtherCol) && ValidRow(nOtherRow) )
1176cdf0e10cSrcweir 					{
1177cdf0e10cSrcweir 						ScAddress aOtherPos( nOtherCol, nOtherRow, nOtherTab );
1178cdf0e10cSrcweir 						pOtherCell = rOtherDoc.GetCell( aOtherPos );
1179cdf0e10cSrcweir 					}
1180cdf0e10cSrcweir 					if ( !ScBaseCell::CellEqual( pThisCell, pOtherCell ) )
1181cdf0e10cSrcweir 					{
1182cdf0e10cSrcweir 						ScRange aRange( aThisPos );
1183cdf0e10cSrcweir 						ScChangeActionContent* pAction = new ScChangeActionContent( aRange );
1184cdf0e10cSrcweir 						pAction->SetOldValue( pOtherCell, &rOtherDoc, this );
1185cdf0e10cSrcweir 						pAction->SetNewValue( pThisCell, this );
1186cdf0e10cSrcweir 						pChangeTrack->Append( pAction );
1187cdf0e10cSrcweir 					}
1188cdf0e10cSrcweir 				}
1189cdf0e10cSrcweir 				aProgress.SetStateOnPercent(nProgressStart+nThisRow);
1190cdf0e10cSrcweir 			}
1191cdf0e10cSrcweir 
1192cdf0e10cSrcweir 			delete[] pOtherCols;
1193cdf0e10cSrcweir 			delete[] pOtherRows;
1194cdf0e10cSrcweir 			delete[] pTempRows;
1195cdf0e10cSrcweir 		}
1196cdf0e10cSrcweir 	}
1197cdf0e10cSrcweir 
1198cdf0e10cSrcweir 	//!	Inhalt von eingefuegten / geloeschten Tabellen ???
1199cdf0e10cSrcweir 	//!	Aktionen fuer eingefuegte / geloeschte Tabellen ???
1200cdf0e10cSrcweir 
1201cdf0e10cSrcweir 	delete[] pOtherTabs;
1202cdf0e10cSrcweir }
1203cdf0e10cSrcweir 
1204cdf0e10cSrcweir 
1205cdf0e10cSrcweir 
1206cdf0e10cSrcweir 
1207cdf0e10cSrcweir 
1208