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 <sal/config.h>
21 :
22 : #include <o3tl/ptr_container.hxx>
23 : #include <unotools/transliterationwrapper.hxx>
24 :
25 : #include "dbdata.hxx"
26 : #include "globalnames.hxx"
27 : #include "refupdat.hxx"
28 : #include "rechead.hxx"
29 : #include "document.hxx"
30 : #include "queryparam.hxx"
31 : #include "queryentry.hxx"
32 : #include "globstr.hrc"
33 : #include "subtotalparam.hxx"
34 : #include "sortparam.hxx"
35 :
36 : #include <memory>
37 : #include <utility>
38 :
39 : using ::std::unique_ptr;
40 : using ::std::unary_function;
41 : using ::std::for_each;
42 : using ::std::find_if;
43 : using ::std::remove_if;
44 : using ::std::pair;
45 :
46 87 : bool ScDBData::less::operator() (const ScDBData& left, const ScDBData& right) const
47 : {
48 87 : return ScGlobal::GetpTransliteration()->compareString(left.GetUpperName(), right.GetUpperName()) < 0;
49 : }
50 :
51 67 : ScDBData::ScDBData( const OUString& rName,
52 : SCTAB nTab,
53 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
54 : bool bByR, bool bHasH, bool bTotals) :
55 67 : mpSortParam(new ScSortParam),
56 67 : mpQueryParam(new ScQueryParam),
57 67 : mpSubTotal(new ScSubTotalParam),
58 67 : mpImportParam(new ScImportParam),
59 : aName (rName),
60 : aUpper (rName),
61 : nTable (nTab),
62 : nStartCol (nCol1),
63 : nStartRow (nRow1),
64 : nEndCol (nCol2),
65 : nEndRow (nRow2),
66 : bByRow (bByR),
67 : bHasHeader (bHasH),
68 : bHasTotals (bTotals),
69 : bDoSize (false),
70 : bKeepFmt (false),
71 : bStripData (false),
72 : bIsAdvanced (false),
73 : bDBSelection(false),
74 : nIndex (0),
75 : bAutoFilter (false),
76 335 : bModified (false)
77 : {
78 67 : aUpper = ScGlobal::pCharClass->uppercase(aUpper);
79 67 : }
80 :
81 419 : ScDBData::ScDBData( const ScDBData& rData ) :
82 : ScRefreshTimer ( rData ),
83 838 : mpSortParam(new ScSortParam(*rData.mpSortParam)),
84 838 : mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
85 838 : mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
86 838 : mpImportParam(new ScImportParam(*rData.mpImportParam)),
87 : aName (rData.aName),
88 : aUpper (rData.aUpper),
89 : nTable (rData.nTable),
90 : nStartCol (rData.nStartCol),
91 : nStartRow (rData.nStartRow),
92 : nEndCol (rData.nEndCol),
93 : nEndRow (rData.nEndRow),
94 : bByRow (rData.bByRow),
95 : bHasHeader (rData.bHasHeader),
96 : bHasTotals (rData.bHasTotals),
97 : bDoSize (rData.bDoSize),
98 : bKeepFmt (rData.bKeepFmt),
99 : bStripData (rData.bStripData),
100 : bIsAdvanced (rData.bIsAdvanced),
101 : aAdvSource (rData.aAdvSource),
102 : bDBSelection (rData.bDBSelection),
103 : nIndex (rData.nIndex),
104 : bAutoFilter (rData.bAutoFilter),
105 3771 : bModified (rData.bModified)
106 : {
107 419 : }
108 :
109 2 : ScDBData::ScDBData( const OUString& rName, const ScDBData& rData ) :
110 : ScRefreshTimer ( rData ),
111 4 : mpSortParam(new ScSortParam(*rData.mpSortParam)),
112 4 : mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
113 4 : mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
114 4 : mpImportParam(new ScImportParam(*rData.mpImportParam)),
115 : aName (rName),
116 : aUpper (rName),
117 : nTable (rData.nTable),
118 : nStartCol (rData.nStartCol),
119 : nStartRow (rData.nStartRow),
120 : nEndCol (rData.nEndCol),
121 : nEndRow (rData.nEndRow),
122 : bByRow (rData.bByRow),
123 : bHasHeader (rData.bHasHeader),
124 : bHasTotals (rData.bHasTotals),
125 : bDoSize (rData.bDoSize),
126 : bKeepFmt (rData.bKeepFmt),
127 : bStripData (rData.bStripData),
128 : bIsAdvanced (rData.bIsAdvanced),
129 : aAdvSource (rData.aAdvSource),
130 : bDBSelection (rData.bDBSelection),
131 : nIndex (rData.nIndex),
132 : bAutoFilter (rData.bAutoFilter),
133 18 : bModified (rData.bModified)
134 : {
135 2 : aUpper = ScGlobal::pCharClass->uppercase(aUpper);
136 2 : }
137 :
138 51 : ScDBData& ScDBData::operator= (const ScDBData& rData)
139 : {
140 : // Don't modify the name. The name is not mutable as it is used as a key
141 : // in the container to keep the db ranges sorted by the name.
142 51 : ScRefreshTimer::operator=( rData );
143 51 : mpSortParam.reset(new ScSortParam(*rData.mpSortParam));
144 51 : mpQueryParam.reset(new ScQueryParam(*rData.mpQueryParam));
145 51 : mpSubTotal.reset(new ScSubTotalParam(*rData.mpSubTotal));
146 51 : mpImportParam.reset(new ScImportParam(*rData.mpImportParam));
147 51 : nTable = rData.nTable;
148 51 : nStartCol = rData.nStartCol;
149 51 : nStartRow = rData.nStartRow;
150 51 : nEndCol = rData.nEndCol;
151 51 : nEndRow = rData.nEndRow;
152 51 : bByRow = rData.bByRow;
153 51 : bHasHeader = rData.bHasHeader;
154 51 : bHasTotals = rData.bHasTotals;
155 51 : bDoSize = rData.bDoSize;
156 51 : bKeepFmt = rData.bKeepFmt;
157 51 : bStripData = rData.bStripData;
158 51 : bIsAdvanced = rData.bIsAdvanced;
159 51 : aAdvSource = rData.aAdvSource;
160 51 : bDBSelection = rData.bDBSelection;
161 51 : nIndex = rData.nIndex;
162 51 : bAutoFilter = rData.bAutoFilter;
163 :
164 51 : return *this;
165 : }
166 :
167 0 : bool ScDBData::operator== (const ScDBData& rData) const
168 : {
169 : // Daten, die nicht in den Params sind
170 :
171 0 : if ( nTable != rData.nTable ||
172 0 : bDoSize != rData.bDoSize ||
173 0 : bKeepFmt != rData.bKeepFmt ||
174 0 : bIsAdvanced!= rData.bIsAdvanced||
175 0 : bStripData != rData.bStripData ||
176 : // SAB: I think this should be here, but I don't want to break something
177 : // bAutoFilter!= rData.bAutoFilter||
178 0 : ScRefreshTimer::operator!=( rData )
179 : )
180 0 : return false;
181 :
182 0 : if ( bIsAdvanced && aAdvSource != rData.aAdvSource )
183 0 : return false;
184 :
185 0 : ScSortParam aSort1, aSort2;
186 0 : GetSortParam(aSort1);
187 0 : rData.GetSortParam(aSort2);
188 0 : if (!(aSort1 == aSort2))
189 0 : return false;
190 :
191 0 : ScQueryParam aQuery1, aQuery2;
192 0 : GetQueryParam(aQuery1);
193 0 : rData.GetQueryParam(aQuery2);
194 0 : if (!(aQuery1 == aQuery2))
195 0 : return false;
196 :
197 0 : ScSubTotalParam aSubTotal1, aSubTotal2;
198 0 : GetSubTotalParam(aSubTotal1);
199 0 : rData.GetSubTotalParam(aSubTotal2);
200 0 : if (!(aSubTotal1 == aSubTotal2))
201 0 : return false;
202 :
203 0 : ScImportParam aImport1, aImport2;
204 0 : GetImportParam(aImport1);
205 0 : rData.GetImportParam(aImport2);
206 0 : if (!(aImport1 == aImport2))
207 0 : return false;
208 :
209 0 : return true;
210 : }
211 :
212 1404 : ScDBData::~ScDBData()
213 : {
214 485 : StopRefreshTimer();
215 919 : }
216 :
217 0 : OUString ScDBData::GetSourceString() const
218 : {
219 0 : OUStringBuffer aBuf;
220 0 : if (mpImportParam->bImport)
221 : {
222 0 : aBuf.append(mpImportParam->aDBName);
223 0 : aBuf.append('/');
224 0 : aBuf.append(mpImportParam->aStatement);
225 : }
226 0 : return aBuf.makeStringAndClear();
227 : }
228 :
229 0 : OUString ScDBData::GetOperations() const
230 : {
231 0 : OUStringBuffer aBuf;
232 0 : if (mpQueryParam->GetEntryCount())
233 : {
234 0 : const ScQueryEntry& rEntry = mpQueryParam->GetEntry(0);
235 0 : if (rEntry.bDoQuery)
236 0 : aBuf.append(ScGlobal::GetRscString(STR_OPERATION_FILTER));
237 : }
238 :
239 0 : if (mpSortParam->maKeyState[0].bDoSort)
240 : {
241 0 : if (!aBuf.isEmpty())
242 0 : aBuf.append(", ");
243 0 : aBuf.append(ScGlobal::GetRscString(STR_OPERATION_SORT));
244 : }
245 :
246 0 : if (mpSubTotal->bGroupActive[0] && !mpSubTotal->bRemoveOnly)
247 : {
248 0 : if (!aBuf.isEmpty())
249 0 : aBuf.append(", ");
250 0 : aBuf.append(ScGlobal::GetRscString(STR_OPERATION_SUBTOTAL));
251 : }
252 :
253 0 : if (aBuf.isEmpty())
254 0 : aBuf.append(ScGlobal::GetRscString(STR_OPERATION_NONE));
255 :
256 0 : return aBuf.makeStringAndClear();
257 : }
258 :
259 343 : void ScDBData::GetArea(SCTAB& rTab, SCCOL& rCol1, SCROW& rRow1, SCCOL& rCol2, SCROW& rRow2) const
260 : {
261 343 : rTab = nTable;
262 343 : rCol1 = nStartCol;
263 343 : rRow1 = nStartRow;
264 343 : rCol2 = nEndCol;
265 343 : rRow2 = nEndRow;
266 343 : }
267 :
268 216 : void ScDBData::GetArea(ScRange& rRange) const
269 : {
270 216 : SCROW nNewEndRow = nEndRow;
271 216 : rRange = ScRange( nStartCol, nStartRow, nTable, nEndCol, nNewEndRow, nTable );
272 216 : }
273 :
274 290 : void ScDBData::SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
275 : {
276 290 : nTable = nTab;
277 290 : nStartCol = nCol1;
278 290 : nStartRow = nRow1;
279 290 : nEndCol = nCol2;
280 290 : nEndRow = nRow2;
281 290 : }
282 :
283 280 : void ScDBData::MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
284 : {
285 : sal_uInt16 i;
286 280 : long nDifX = ((long) nCol1) - ((long) nStartCol);
287 280 : long nDifY = ((long) nRow1) - ((long) nStartRow);
288 :
289 280 : long nSortDif = bByRow ? nDifX : nDifY;
290 280 : long nSortEnd = bByRow ? static_cast<long>(nCol2) : static_cast<long>(nRow2);
291 :
292 1116 : for (i=0; i<mpSortParam->GetSortKeyCount(); i++)
293 : {
294 836 : mpSortParam->maKeyState[i].nField += nSortDif;
295 836 : if (mpSortParam->maKeyState[i].nField > nSortEnd)
296 : {
297 0 : mpSortParam->maKeyState[i].nField = 0;
298 0 : mpSortParam->maKeyState[i].bDoSort = false;
299 : }
300 : }
301 :
302 280 : SCSIZE nCount = mpQueryParam->GetEntryCount();
303 2520 : for (i = 0; i < nCount; ++i)
304 : {
305 2240 : ScQueryEntry& rEntry = mpQueryParam->GetEntry(i);
306 2240 : rEntry.nField += nDifX;
307 2240 : if (rEntry.nField > nCol2)
308 : {
309 0 : rEntry.nField = 0;
310 0 : rEntry.bDoQuery = false;
311 : }
312 : }
313 1120 : for (i=0; i<MAXSUBTOTAL; i++)
314 : {
315 840 : mpSubTotal->nField[i] = sal::static_int_cast<SCCOL>( mpSubTotal->nField[i] + nDifX );
316 840 : if (mpSubTotal->nField[i] > nCol2)
317 : {
318 0 : mpSubTotal->nField[i] = 0;
319 0 : mpSubTotal->bGroupActive[i] = false;
320 : }
321 : }
322 :
323 280 : SetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
324 280 : }
325 :
326 16 : void ScDBData::GetSortParam( ScSortParam& rSortParam ) const
327 : {
328 16 : rSortParam = *mpSortParam;
329 16 : rSortParam.nCol1 = nStartCol;
330 16 : rSortParam.nRow1 = nStartRow;
331 16 : rSortParam.nCol2 = nEndCol;
332 16 : rSortParam.nRow2 = nEndRow;
333 16 : rSortParam.bByRow = bByRow;
334 16 : rSortParam.bHasHeader = bHasHeader;
335 : /* TODO: add Totals to ScSortParam? */
336 16 : }
337 :
338 32 : void ScDBData::SetSortParam( const ScSortParam& rSortParam )
339 : {
340 32 : mpSortParam.reset(new ScSortParam(rSortParam));
341 32 : bByRow = rSortParam.bByRow;
342 32 : }
343 :
344 89 : void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const
345 : {
346 89 : rQueryParam = *mpQueryParam;
347 89 : rQueryParam.nCol1 = nStartCol;
348 89 : rQueryParam.nRow1 = nStartRow;
349 89 : rQueryParam.nCol2 = nEndCol;
350 89 : rQueryParam.nRow2 = nEndRow;
351 89 : rQueryParam.nTab = nTable;
352 89 : rQueryParam.bByRow = bByRow;
353 89 : rQueryParam.bHasHeader = bHasHeader;
354 : /* TODO: add Totals to ScQueryParam? */
355 89 : }
356 :
357 67 : void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam)
358 : {
359 67 : mpQueryParam.reset(new ScQueryParam(rQueryParam));
360 :
361 : // set bIsAdvanced to false for everything that is not from the
362 : // advanced filter dialog
363 67 : bIsAdvanced = false;
364 67 : }
365 :
366 25 : void ScDBData::SetAdvancedQuerySource(const ScRange* pSource)
367 : {
368 25 : if (pSource)
369 : {
370 2 : aAdvSource = *pSource;
371 2 : bIsAdvanced = true;
372 : }
373 : else
374 23 : bIsAdvanced = false;
375 25 : }
376 :
377 40 : bool ScDBData::GetAdvancedQuerySource(ScRange& rSource) const
378 : {
379 40 : rSource = aAdvSource;
380 40 : return bIsAdvanced;
381 : }
382 :
383 21 : void ScDBData::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
384 : {
385 21 : rSubTotalParam = *mpSubTotal;
386 :
387 : // Share the data range with the parent db data. The range in the subtotal
388 : // param struct is not used.
389 21 : rSubTotalParam.nCol1 = nStartCol;
390 21 : rSubTotalParam.nRow1 = nStartRow;
391 21 : rSubTotalParam.nCol2 = nEndCol;
392 21 : rSubTotalParam.nRow2 = nEndRow;
393 21 : }
394 :
395 4 : void ScDBData::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam)
396 : {
397 4 : mpSubTotal.reset(new ScSubTotalParam(rSubTotalParam));
398 4 : }
399 :
400 11 : void ScDBData::GetImportParam(ScImportParam& rImportParam) const
401 : {
402 11 : rImportParam = *mpImportParam;
403 : // set the range.
404 11 : rImportParam.nCol1 = nStartCol;
405 11 : rImportParam.nRow1 = nStartRow;
406 11 : rImportParam.nCol2 = nEndCol;
407 11 : rImportParam.nRow2 = nEndRow;
408 11 : }
409 :
410 23 : void ScDBData::SetImportParam(const ScImportParam& rImportParam)
411 : {
412 : // the range is ignored.
413 23 : mpImportParam.reset(new ScImportParam(rImportParam));
414 23 : }
415 :
416 12 : bool ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) const
417 : {
418 12 : if (nTab == nTable)
419 : {
420 12 : if ( bStartOnly )
421 0 : return ( nCol == nStartCol && nRow == nStartRow );
422 : else
423 36 : return ( nCol >= nStartCol && nCol <= nEndCol &&
424 36 : nRow >= nStartRow && nRow <= nEndRow );
425 : }
426 :
427 0 : return false;
428 : }
429 :
430 63 : bool ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
431 : {
432 63 : return (bool)((nTab == nTable)
433 63 : && (nCol1 == nStartCol) && (nRow1 == nStartRow)
434 122 : && (nCol2 == nEndCol) && (nRow2 == nEndRow));
435 : }
436 :
437 44 : bool ScDBData::HasImportParam() const
438 : {
439 44 : return mpImportParam && mpImportParam->bImport;
440 : }
441 :
442 0 : bool ScDBData::HasQueryParam() const
443 : {
444 0 : if (!mpQueryParam)
445 0 : return false;
446 :
447 0 : if (!mpQueryParam->GetEntryCount())
448 0 : return false;
449 :
450 0 : return mpQueryParam->GetEntry(0).bDoQuery;
451 : }
452 :
453 0 : bool ScDBData::HasSortParam() const
454 : {
455 0 : return mpSortParam &&
456 0 : !mpSortParam->maKeyState.empty() &&
457 0 : mpSortParam->maKeyState[0].bDoSort;
458 : }
459 :
460 0 : bool ScDBData::HasSubTotalParam() const
461 : {
462 0 : return mpSubTotal && mpSubTotal->bGroupActive[0];
463 : }
464 :
465 0 : void ScDBData::UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
466 : {
467 0 : ScRange aRange;
468 0 : GetArea( aRange );
469 0 : SCTAB nTab = aRange.aStart.Tab(); // hat nur eine Tabelle
470 :
471 : // anpassen wie die aktuelle Tabelle bei ScTablesHint (tabvwsh5.cxx)
472 :
473 0 : if ( nTab == nOldPos ) // verschobene Tabelle
474 0 : nTab = nNewPos;
475 0 : else if ( nOldPos < nNewPos ) // nach hinten verschoben
476 : {
477 0 : if ( nTab > nOldPos && nTab <= nNewPos ) // nachrueckender Bereich
478 0 : --nTab;
479 : }
480 : else // nach vorne verschoben
481 : {
482 0 : if ( nTab >= nNewPos && nTab < nOldPos ) // nachrueckender Bereich
483 0 : ++nTab;
484 : }
485 :
486 0 : bool bChanged = ( nTab != aRange.aStart.Tab() );
487 0 : if (bChanged)
488 0 : SetArea( nTab, aRange.aStart.Col(), aRange.aStart.Row(),
489 0 : aRange.aEnd.Col(),aRange.aEnd .Row() );
490 :
491 : // MoveTo ist nicht noetig, wenn nur die Tabelle geaendert ist
492 :
493 0 : SetModified(bChanged);
494 :
495 0 : }
496 :
497 10 : void ScDBData::UpdateReference(ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
498 : SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
499 : SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
500 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz)
501 : {
502 : SCCOL theCol1;
503 : SCROW theRow1;
504 : SCTAB theTab1;
505 : SCCOL theCol2;
506 : SCROW theRow2;
507 : SCTAB theTab2;
508 10 : GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
509 10 : theTab2 = theTab1;
510 :
511 : bool bDoUpdate = ScRefUpdate::Update( pDoc, eUpdateRefMode,
512 : nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
513 10 : theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) != UR_NOTHING;
514 10 : if (bDoUpdate)
515 7 : MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
516 :
517 10 : ScRange aRangeAdvSource;
518 10 : if ( GetAdvancedQuerySource(aRangeAdvSource) )
519 : {
520 0 : aRangeAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
521 0 : if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
522 : nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
523 0 : theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
524 : {
525 0 : aRangeAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
526 0 : aRangeAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
527 0 : SetAdvancedQuerySource( &aRangeAdvSource );
528 :
529 0 : bDoUpdate = true; // DBData is modified
530 : }
531 : }
532 :
533 10 : SetModified(bDoUpdate);
534 :
535 : //TODO: check if something was deleted/inserted with-in the range !!!
536 10 : }
537 :
538 0 : void ScDBData::ExtendDataArea(ScDocument* pDoc)
539 : {
540 : // Extend the DB area to include data rows immediately below.
541 : // or shrink it if all cells are empty
542 0 : pDoc->GetDataArea(nTable, nStartCol, nStartRow, nEndCol, nEndRow, false, true);
543 0 : }
544 :
545 : namespace {
546 :
547 : class FindByTable : public unary_function<ScDBData, bool>
548 : {
549 : SCTAB mnTab;
550 : public:
551 206 : FindByTable(SCTAB nTab) : mnTab(nTab) {}
552 :
553 8 : bool operator() (const ScDBData& r) const
554 : {
555 8 : ScRange aRange;
556 8 : r.GetArea(aRange);
557 8 : return aRange.aStart.Tab() == mnTab;
558 : }
559 : };
560 :
561 : class UpdateRefFunc : public unary_function<ScDBData, void>
562 : {
563 : ScDocument* mpDoc;
564 : UpdateRefMode meMode;
565 : SCCOL mnCol1;
566 : SCROW mnRow1;
567 : SCTAB mnTab1;
568 : SCCOL mnCol2;
569 : SCROW mnRow2;
570 : SCTAB mnTab2;
571 : SCsCOL mnDx;
572 : SCsROW mnDy;
573 : SCsTAB mnDz;
574 :
575 : public:
576 348 : UpdateRefFunc(ScDocument* pDoc, UpdateRefMode eMode,
577 : SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
578 : SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
579 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz) :
580 : mpDoc(pDoc), meMode(eMode),
581 : mnCol1(nCol1), mnRow1(nRow1), mnTab1(nTab1),
582 : mnCol2(nCol2), mnRow2(nRow2), mnTab2(nTab2),
583 348 : mnDx(nDx), mnDy(nDy), mnDz(nDz) {}
584 :
585 6 : void operator() (ScDBData& r)
586 : {
587 6 : r.UpdateReference(mpDoc, meMode, mnCol1, mnRow1, mnTab1, mnCol2, mnRow2, mnTab2, mnDx, mnDy, mnDz);
588 6 : }
589 : };
590 :
591 : class UpdateMoveTabFunc : public unary_function<ScDBData, void>
592 : {
593 : SCTAB mnOldTab;
594 : SCTAB mnNewTab;
595 : public:
596 14 : UpdateMoveTabFunc(SCTAB nOld, SCTAB nNew) : mnOldTab(nOld), mnNewTab(nNew) {}
597 0 : void operator() (ScDBData& r)
598 : {
599 0 : r.UpdateMoveTab(mnOldTab, mnNewTab);
600 0 : }
601 : };
602 :
603 : class FindByCursor : public unary_function<ScDBData, bool>
604 : {
605 : SCCOL mnCol;
606 : SCROW mnRow;
607 : SCTAB mnTab;
608 : bool mbStartOnly;
609 : public:
610 506 : FindByCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) :
611 506 : mnCol(nCol), mnRow(nRow), mnTab(nTab), mbStartOnly(bStartOnly) {}
612 :
613 4 : bool operator() (const ScDBData& r)
614 : {
615 4 : return r.IsDBAtCursor(mnCol, mnRow, mnTab, mbStartOnly);
616 : }
617 : };
618 :
619 : class FindByRange : public unary_function<ScDBData, bool>
620 : {
621 : const ScRange& mrRange;
622 : public:
623 82 : FindByRange(const ScRange& rRange) : mrRange(rRange) {}
624 :
625 5 : bool operator() (const ScDBData& r)
626 : {
627 : return r.IsDBAtArea(
628 5 : mrRange.aStart.Tab(), mrRange.aStart.Col(), mrRange.aStart.Row(), mrRange.aEnd.Col(), mrRange.aEnd.Row());
629 : }
630 : };
631 :
632 : class FindByIndex : public unary_function<ScDBData, bool>
633 : {
634 : sal_uInt16 mnIndex;
635 : public:
636 19 : FindByIndex(sal_uInt16 nIndex) : mnIndex(nIndex) {}
637 23 : bool operator() (const ScDBData& r) const
638 : {
639 23 : return r.GetIndex() == mnIndex;
640 : }
641 : };
642 :
643 : class FindByUpperName : public unary_function<ScDBData, bool>
644 : {
645 : const OUString& mrName;
646 : public:
647 210 : FindByUpperName(const OUString& rName) : mrName(rName) {}
648 230 : bool operator() (const ScDBData& r) const
649 : {
650 230 : return r.GetUpperName() == mrName;
651 : }
652 : };
653 :
654 : }
655 :
656 2321 : ScDBCollection::NamedDBs::NamedDBs(ScDBCollection& rParent, ScDocument& rDoc) :
657 2321 : mrParent(rParent), mrDoc(rDoc) {}
658 :
659 104 : ScDBCollection::NamedDBs::NamedDBs(const NamedDBs& r) :
660 104 : maDBs(r.maDBs), mrParent(r.mrParent), mrDoc(r.mrDoc) {}
661 :
662 1043 : ScDBCollection::NamedDBs::iterator ScDBCollection::NamedDBs::begin()
663 : {
664 1043 : return maDBs.begin();
665 : }
666 :
667 1371 : ScDBCollection::NamedDBs::iterator ScDBCollection::NamedDBs::end()
668 : {
669 1371 : return maDBs.end();
670 : }
671 :
672 418 : ScDBCollection::NamedDBs::const_iterator ScDBCollection::NamedDBs::begin() const
673 : {
674 418 : return maDBs.begin();
675 : }
676 :
677 417 : ScDBCollection::NamedDBs::const_iterator ScDBCollection::NamedDBs::end() const
678 : {
679 417 : return maDBs.end();
680 : }
681 :
682 19 : ScDBData* ScDBCollection::NamedDBs::findByIndex(sal_uInt16 nIndex)
683 : {
684 : DBsType::iterator itr = find_if(
685 19 : maDBs.begin(), maDBs.end(), FindByIndex(nIndex));
686 19 : return itr == maDBs.end() ? NULL : &(*itr);
687 : }
688 :
689 210 : ScDBData* ScDBCollection::NamedDBs::findByUpperName(const OUString& rName)
690 : {
691 : DBsType::iterator itr = find_if(
692 210 : maDBs.begin(), maDBs.end(), FindByUpperName(rName));
693 210 : return itr == maDBs.end() ? NULL : &(*itr);
694 : }
695 :
696 25 : bool ScDBCollection::NamedDBs::insert(ScDBData* p)
697 : {
698 25 : unique_ptr<ScDBData> pData(p);
699 25 : if (!pData->GetIndex())
700 23 : pData->SetIndex(mrParent.nEntryIndex++);
701 :
702 25 : pair<DBsType::iterator, bool> r = o3tl::ptr_container::insert(maDBs, std::move(pData));
703 :
704 25 : if (r.second && p->HasImportParam() && !p->HasImportSelection())
705 : {
706 1 : p->SetRefreshHandler(mrParent.GetRefreshHandler());
707 1 : p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
708 : }
709 25 : return r.second;
710 : }
711 :
712 2 : void ScDBCollection::NamedDBs::erase(iterator itr)
713 : {
714 2 : maDBs.erase(itr);
715 2 : }
716 :
717 2 : void ScDBCollection::NamedDBs::erase(const ScDBData& r)
718 : {
719 2 : maDBs.erase(r);
720 2 : }
721 :
722 113 : bool ScDBCollection::NamedDBs::empty() const
723 : {
724 113 : return maDBs.empty();
725 : }
726 :
727 42 : size_t ScDBCollection::NamedDBs::size() const
728 : {
729 42 : return maDBs.size();
730 : }
731 :
732 0 : bool ScDBCollection::NamedDBs::operator== (const NamedDBs& r) const
733 : {
734 0 : return maDBs == r.maDBs;
735 : }
736 :
737 362 : ScDBCollection::AnonDBs::iterator ScDBCollection::AnonDBs::begin()
738 : {
739 362 : return maDBs.begin();
740 : }
741 :
742 362 : ScDBCollection::AnonDBs::iterator ScDBCollection::AnonDBs::end()
743 : {
744 362 : return maDBs.end();
745 : }
746 :
747 0 : ScDBCollection::AnonDBs::const_iterator ScDBCollection::AnonDBs::begin() const
748 : {
749 0 : return maDBs.begin();
750 : }
751 :
752 0 : ScDBCollection::AnonDBs::const_iterator ScDBCollection::AnonDBs::end() const
753 : {
754 0 : return maDBs.end();
755 : }
756 :
757 247 : const ScDBData* ScDBCollection::AnonDBs::findAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) const
758 : {
759 : DBsType::const_iterator itr = find_if(
760 247 : maDBs.begin(), maDBs.end(), FindByCursor(nCol, nRow, nTab, bStartOnly));
761 247 : return itr == maDBs.end() ? NULL : &(*itr);
762 : }
763 :
764 13 : const ScDBData* ScDBCollection::AnonDBs::findByRange(const ScRange& rRange) const
765 : {
766 : DBsType::const_iterator itr = find_if(
767 13 : maDBs.begin(), maDBs.end(), FindByRange(rRange));
768 13 : return itr == maDBs.end() ? NULL : &(*itr);
769 : }
770 :
771 103 : void ScDBCollection::AnonDBs::deleteOnTab(SCTAB nTab)
772 : {
773 103 : FindByTable func(nTab);
774 103 : maDBs.erase_if(func);
775 103 : }
776 :
777 0 : ScDBData* ScDBCollection::AnonDBs::getByRange(const ScRange& rRange)
778 : {
779 0 : const ScDBData* pData = findByRange(rRange);
780 0 : if (!pData)
781 : {
782 : // Insert a new db data. They all have identical names.
783 0 : OUString aName(STR_DB_GLOBAL_NONAME);
784 : ::std::unique_ptr<ScDBData> pNew(new ScDBData(
785 0 : aName, rRange.aStart.Tab(), rRange.aStart.Col(), rRange.aStart.Row(),
786 0 : rRange.aEnd.Col(), rRange.aEnd.Row(), true, false, false));
787 0 : pData = pNew.get();
788 0 : o3tl::ptr_container::push_back(maDBs, std::move(pNew));
789 : }
790 0 : return const_cast<ScDBData*>(pData);
791 : }
792 :
793 0 : void ScDBCollection::AnonDBs::insert(ScDBData* p)
794 : {
795 0 : ::std::unique_ptr<ScDBData> pNew(p);
796 0 : o3tl::ptr_container::push_back(maDBs, std::move(pNew));
797 0 : }
798 :
799 110 : bool ScDBCollection::AnonDBs::empty() const
800 : {
801 110 : return maDBs.empty();
802 : }
803 :
804 0 : bool ScDBCollection::AnonDBs::operator== (const AnonDBs& r) const
805 : {
806 0 : return maDBs == r.maDBs;
807 : }
808 :
809 2321 : ScDBCollection::ScDBCollection(ScDocument* pDocument) :
810 2321 : pDoc(pDocument), nEntryIndex(1), maNamedDBs(*this, *pDocument) {}
811 :
812 104 : ScDBCollection::ScDBCollection(const ScDBCollection& r) :
813 104 : pDoc(r.pDoc), nEntryIndex(r.nEntryIndex), maNamedDBs(r.maNamedDBs), maAnonDBs(r.maAnonDBs) {}
814 :
815 0 : const ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) const
816 : {
817 : // First, search the global named db ranges.
818 : NamedDBs::DBsType::const_iterator itr = find_if(
819 0 : maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, bStartOnly));
820 0 : if (itr != maNamedDBs.end())
821 0 : return &(*itr);
822 :
823 : // Check for the sheet-local anonymous db range.
824 0 : const ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
825 0 : if (pNoNameData)
826 0 : if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,bStartOnly))
827 0 : return pNoNameData;
828 :
829 : // Check the global anonymous db ranges.
830 0 : const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, bStartOnly);
831 0 : if (pData)
832 0 : return pData;
833 :
834 0 : return NULL;
835 : }
836 :
837 259 : ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly)
838 : {
839 : // First, search the global named db ranges.
840 : NamedDBs::DBsType::iterator itr = find_if(
841 259 : maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, bStartOnly));
842 259 : if (itr != maNamedDBs.end())
843 4 : return &(*itr);
844 :
845 : // Check for the sheet-local anonymous db range.
846 255 : ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
847 255 : if (pNoNameData)
848 8 : if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,bStartOnly))
849 8 : return pNoNameData;
850 :
851 : // Check the global anonymous db ranges.
852 247 : const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, bStartOnly);
853 247 : if (pData)
854 0 : return const_cast<ScDBData*>(pData);
855 :
856 247 : return NULL;
857 : }
858 :
859 0 : const ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
860 : {
861 : // First, search the global named db ranges.
862 0 : ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
863 : NamedDBs::DBsType::const_iterator itr = find_if(
864 0 : maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
865 0 : if (itr != maNamedDBs.end())
866 0 : return &(*itr);
867 :
868 : // Check for the sheet-local anonymous db range.
869 0 : ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
870 0 : if (pNoNameData)
871 0 : if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
872 0 : return pNoNameData;
873 :
874 : // Lastly, check the global anonymous db ranges.
875 0 : return maAnonDBs.findByRange(aRange);
876 : }
877 :
878 69 : ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
879 : {
880 : // First, search the global named db ranges.
881 69 : ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
882 : NamedDBs::DBsType::iterator itr = find_if(
883 69 : maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
884 69 : if (itr != maNamedDBs.end())
885 1 : return &(*itr);
886 :
887 : // Check for the sheet-local anonymous db range.
888 68 : ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
889 68 : if (pNoNameData)
890 58 : if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
891 55 : return pNoNameData;
892 :
893 : // Lastly, check the global anonymous db ranges.
894 13 : const ScDBData* pData = getAnonDBs().findByRange(aRange);
895 13 : if (pData)
896 0 : return const_cast<ScDBData*>(pData);
897 :
898 13 : return NULL;
899 : }
900 :
901 103 : void ScDBCollection::DeleteOnTab( SCTAB nTab )
902 : {
903 103 : FindByTable func(nTab);
904 : // First, collect the positions of all items that need to be deleted.
905 103 : ::std::vector<NamedDBs::DBsType::iterator> v;
906 : {
907 103 : NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
908 111 : for (; itr != itrEnd; ++itr)
909 : {
910 8 : if (func(*itr))
911 2 : v.push_back(itr);
912 : }
913 : }
914 :
915 : // Delete them all.
916 103 : ::std::vector<NamedDBs::DBsType::iterator>::iterator itr = v.begin(), itrEnd = v.end();
917 105 : for (; itr != itrEnd; ++itr)
918 2 : maNamedDBs.erase(*itr);
919 :
920 103 : maAnonDBs.deleteOnTab(nTab);
921 103 : }
922 :
923 348 : void ScDBCollection::UpdateReference(UpdateRefMode eUpdateRefMode,
924 : SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
925 : SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
926 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
927 : {
928 348 : ScDBData* pData = pDoc->GetAnonymousDBData(nTab1);
929 348 : if (pData)
930 : {
931 4 : if (nTab1 == nTab2 && nDz == 0)
932 : {
933 : pData->UpdateReference(
934 : pDoc, eUpdateRefMode,
935 4 : nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
936 : }
937 : else
938 : {
939 : //this will perhabs break undo
940 : }
941 : }
942 :
943 348 : UpdateRefFunc func(pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
944 348 : for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
945 348 : for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
946 348 : }
947 :
948 14 : void ScDBCollection::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
949 : {
950 14 : UpdateMoveTabFunc func(nOldPos, nNewPos);
951 14 : for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
952 14 : for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
953 14 : }
954 :
955 13 : ScDBData* ScDBCollection::GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab )
956 : {
957 13 : ScDBData* pNearData = NULL;
958 13 : NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
959 13 : for (; itr != itrEnd; ++itr)
960 : {
961 : SCTAB nAreaTab;
962 : SCCOL nStartCol, nEndCol;
963 : SCROW nStartRow, nEndRow;
964 0 : itr->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
965 0 : if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 &&
966 0 : nRow+1 >= nStartRow && nRow <= nEndRow+1 )
967 : {
968 0 : if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow )
969 : {
970 0 : if (!pNearData)
971 0 : pNearData = &(*itr); // ersten angrenzenden Bereich merken
972 : }
973 : else
974 0 : return &(*itr); // nicht "unbenannt" und Cursor steht wirklich drin
975 : }
976 : }
977 13 : if (pNearData)
978 0 : return pNearData; // angrenzender, wenn nichts direkt getroffen
979 13 : return pDoc->GetAnonymousDBData(nTab); // "unbenannt" nur zurueck, wenn sonst nichts gefunden
980 : }
981 :
982 82 : bool ScDBCollection::empty() const
983 : {
984 82 : return maNamedDBs.empty() && maAnonDBs.empty();
985 : }
986 :
987 0 : bool ScDBCollection::operator== (const ScDBCollection& r) const
988 : {
989 0 : return maNamedDBs == r.maNamedDBs && maAnonDBs == r.maAnonDBs &&
990 0 : nEntryIndex == r.nEntryIndex && pDoc == r.pDoc && aRefreshHandler == r.aRefreshHandler;
991 156 : }
992 :
993 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|