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