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