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