1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 32 33 // INCLUDE --------------------------------------------------------------- 34 35 #include "dbfunc.hxx" 36 #include "scitems.hxx" 37 #include <sfx2/bindings.hxx> 38 #include <vcl/svapp.hxx> 39 #include <vcl/msgbox.hxx> 40 #include <vcl/sound.hxx> 41 #include <vcl/waitobj.hxx> 42 #include <svl/zforlist.hxx> 43 #include <sfx2/app.hxx> 44 #include <com/sun/star/beans/XPropertySet.hpp> 45 #include <com/sun/star/container/XNameAccess.hpp> 46 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp> 47 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> 48 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> 49 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp> 50 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp> 51 #include <com/sun/star/sheet/GeneralFunction.hpp> 52 #include <com/sun/star/sheet/MemberResultFlags.hpp> 53 #include <com/sun/star/sheet/XDimensionsSupplier.hpp> 54 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp> 55 56 #include "global.hxx" 57 #include "globstr.hrc" 58 #include "sc.hrc" 59 #include "undotab.hxx" 60 #include "undodat.hxx" 61 #include "dbcolect.hxx" 62 #include "rangenam.hxx" 63 #include "rangeutl.hxx" 64 #include "docsh.hxx" 65 #include "olinetab.hxx" 66 #include "consoli.hxx" 67 #include "olinefun.hxx" 68 #include "dpobject.hxx" 69 #include "dpsave.hxx" 70 #include "dpdimsave.hxx" 71 #include "dbdocfun.hxx" 72 #include "dpoutput.hxx" 73 #include "dptabsrc.hxx" 74 #include "editable.hxx" 75 #include "docpool.hxx" 76 #include "patattr.hxx" 77 #include "unonames.hxx" 78 #include "cell.hxx" 79 #include "userlist.hxx" 80 81 #include <hash_set> 82 #include <hash_map> 83 #include <memory> 84 #include <list> 85 #include <vector> 86 87 using namespace com::sun::star; 88 using ::com::sun::star::uno::Any; 89 using ::com::sun::star::uno::Sequence; 90 using ::com::sun::star::uno::Reference; 91 using ::com::sun::star::uno::UNO_QUERY; 92 using ::com::sun::star::beans::XPropertySet; 93 using ::com::sun::star::container::XNameAccess; 94 using ::com::sun::star::sheet::XDimensionsSupplier; 95 using ::rtl::OUString; 96 using ::rtl::OUStringHash; 97 using ::rtl::OUStringBuffer; 98 using ::std::auto_ptr; 99 using ::std::list; 100 using ::std::vector; 101 using ::std::hash_map; 102 using ::std::hash_set; 103 104 // STATIC DATA ----------------------------------------------------------- 105 106 107 //================================================================== 108 109 // 110 // Outliner 111 // 112 113 // Outline-Gruppierung erzeugen 114 115 void ScDBFunc::MakeOutline( sal_Bool bColumns, sal_Bool bRecord ) 116 { 117 ScRange aRange; 118 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE) 119 { 120 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 121 ScOutlineDocFunc aFunc(*pDocSh); 122 aFunc.MakeOutline( aRange, bColumns, bRecord, sal_False ); 123 } 124 else 125 ErrorMessage(STR_NOMULTISELECT); 126 } 127 128 // Outline-Gruppierung loeschen 129 130 void ScDBFunc::RemoveOutline( sal_Bool bColumns, sal_Bool bRecord ) 131 { 132 ScRange aRange; 133 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE) 134 { 135 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 136 ScOutlineDocFunc aFunc(*pDocSh); 137 aFunc.RemoveOutline( aRange, bColumns, bRecord, sal_False ); 138 } 139 else 140 ErrorMessage(STR_NOMULTISELECT); 141 } 142 143 // Menue-Status: Outlines loeschen 144 145 void ScDBFunc::TestRemoveOutline( sal_Bool& rCol, sal_Bool& rRow ) 146 { 147 sal_Bool bColFound = sal_False; 148 sal_Bool bRowFound = sal_False; 149 150 SCCOL nStartCol, nEndCol; 151 SCROW nStartRow, nEndRow; 152 SCTAB nStartTab, nEndTab; 153 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE) 154 { 155 SCTAB nTab = nStartTab; 156 ScDocument* pDoc = GetViewData()->GetDocument(); 157 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); 158 if (pTable) 159 { 160 ScOutlineArray* pArray; 161 ScOutlineEntry* pEntry; 162 SCCOLROW nStart; 163 SCCOLROW nEnd; 164 sal_Bool bColMarked = ( nStartRow == 0 && nEndRow == MAXROW ); 165 sal_Bool bRowMarked = ( nStartCol == 0 && nEndCol == MAXCOL ); 166 167 // Spalten 168 169 if ( !bRowMarked || bColMarked ) // nicht wenn ganze Zeilen markiert 170 { 171 pArray = pTable->GetColArray(); 172 ScSubOutlineIterator aColIter( pArray ); 173 while ((pEntry=aColIter.GetNext()) != NULL && !bColFound) 174 { 175 nStart = pEntry->GetStart(); 176 nEnd = pEntry->GetEnd(); 177 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) ) 178 bColFound = sal_True; 179 } 180 } 181 182 // Zeilen 183 184 if ( !bColMarked || bRowMarked ) // nicht wenn ganze Spalten markiert 185 { 186 pArray = pTable->GetRowArray(); 187 ScSubOutlineIterator aRowIter( pArray ); 188 while ((pEntry=aRowIter.GetNext()) != NULL && !bRowFound) 189 { 190 nStart = pEntry->GetStart(); 191 nEnd = pEntry->GetEnd(); 192 if ( nStartRow<=nEnd && nEndRow>=nStart ) 193 bRowFound = sal_True; 194 } 195 } 196 } 197 } 198 199 rCol = bColFound; 200 rRow = bRowFound; 201 } 202 203 void ScDBFunc::RemoveAllOutlines( sal_Bool bRecord ) 204 { 205 SCTAB nTab = GetViewData()->GetTabNo(); 206 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 207 ScOutlineDocFunc aFunc(*pDocSh); 208 209 HideCursor(); 210 sal_Bool bOk = aFunc.RemoveAllOutlines( nTab, bRecord, sal_False ); 211 ShowCursor(); 212 213 if (bOk) 214 UpdateScrollBars(); 215 } 216 217 // Auto-Outlines 218 219 void ScDBFunc::AutoOutline( sal_Bool bRecord ) 220 { 221 SCTAB nTab = GetViewData()->GetTabNo(); 222 ScRange aRange( 0,0,nTab, MAXCOL,MAXROW,nTab ); // ganze Tabelle, wenn nichts markiert 223 ScMarkData& rMark = GetViewData()->GetMarkData(); 224 if ( rMark.IsMarked() || rMark.IsMultiMarked() ) 225 { 226 rMark.MarkToMulti(); 227 rMark.GetMultiMarkArea( aRange ); 228 } 229 230 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 231 ScOutlineDocFunc aFunc(*pDocSh); 232 aFunc.AutoOutline( aRange, bRecord, sal_False ); 233 } 234 235 // Outline-Ebene auswaehlen 236 237 void ScDBFunc::SelectLevel( sal_Bool bColumns, sal_uInt16 nLevel, sal_Bool bRecord, sal_Bool bPaint ) 238 { 239 SCTAB nTab = GetViewData()->GetTabNo(); 240 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 241 ScOutlineDocFunc aFunc(*pDocSh); 242 243 HideCursor(); 244 sal_Bool bOk = aFunc.SelectLevel( nTab, bColumns, nLevel, bRecord, bPaint, sal_False ); 245 ShowCursor(); 246 247 if (bOk) 248 UpdateScrollBars(); 249 } 250 251 // einzelne Outline-Gruppe einblenden 252 253 void ScDBFunc::ShowOutline( sal_Bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bRecord, sal_Bool bPaint ) 254 { 255 SCTAB nTab = GetViewData()->GetTabNo(); 256 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 257 ScOutlineDocFunc aFunc(*pDocSh); 258 259 HideCursor(); 260 sal_Bool bOk = aFunc.ShowOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, sal_False ); 261 ShowCursor(); 262 263 if ( bOk && bPaint ) 264 UpdateScrollBars(); 265 } 266 267 // einzelne Outline-Gruppe ausblenden 268 269 void ScDBFunc::HideOutline( sal_Bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bRecord, sal_Bool bPaint ) 270 { 271 SCTAB nTab = GetViewData()->GetTabNo(); 272 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 273 ScOutlineDocFunc aFunc(*pDocSh); 274 275 HideCursor(); 276 sal_Bool bOk = aFunc.HideOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, sal_False ); 277 ShowCursor(); 278 279 if ( bOk && bPaint ) 280 UpdateScrollBars(); 281 } 282 283 // Menue-Status: markierten Bereich ein-/ausblenden 284 285 sal_Bool ScDBFunc::OutlinePossible(sal_Bool bHide) 286 { 287 sal_Bool bEnable = sal_False; 288 289 SCCOL nStartCol; 290 SCROW nStartRow; 291 SCTAB nStartTab; 292 SCCOL nEndCol; 293 SCROW nEndRow; 294 SCTAB nEndTab; 295 296 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE) 297 { 298 ScDocument* pDoc = GetViewData()->GetDocument(); 299 SCTAB nTab = GetViewData()->GetTabNo(); 300 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); 301 if (pTable) 302 { 303 ScOutlineArray* pArray; 304 ScOutlineEntry* pEntry; 305 SCCOLROW nStart; 306 SCCOLROW nEnd; 307 308 // Spalten 309 310 pArray = pTable->GetColArray(); 311 ScSubOutlineIterator aColIter( pArray ); 312 while ((pEntry=aColIter.GetNext()) != NULL && !bEnable) 313 { 314 nStart = pEntry->GetStart(); 315 nEnd = pEntry->GetEnd(); 316 if ( bHide ) 317 { 318 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) ) 319 if (!pEntry->IsHidden()) 320 bEnable = sal_True; 321 } 322 else 323 { 324 if ( nStart>=nStartCol && nEnd<=nEndCol ) 325 if (pEntry->IsHidden()) 326 bEnable = sal_True; 327 } 328 } 329 330 // Zeilen 331 332 pArray = pTable->GetRowArray(); 333 ScSubOutlineIterator aRowIter( pArray ); 334 while ((pEntry=aRowIter.GetNext()) != NULL) 335 { 336 nStart = pEntry->GetStart(); 337 nEnd = pEntry->GetEnd(); 338 if ( bHide ) 339 { 340 if ( nStartRow<=nEnd && nEndRow>=nStart ) 341 if (!pEntry->IsHidden()) 342 bEnable = sal_True; 343 } 344 else 345 { 346 if ( nStart>=nStartRow && nEnd<=nEndRow ) 347 if (pEntry->IsHidden()) 348 bEnable = sal_True; 349 } 350 } 351 } 352 } 353 354 return bEnable; 355 } 356 357 // markierten Bereich einblenden 358 359 void ScDBFunc::ShowMarkedOutlines( sal_Bool bRecord ) 360 { 361 ScRange aRange; 362 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE) 363 { 364 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 365 ScOutlineDocFunc aFunc(*pDocSh); 366 HideCursor(); 367 sal_Bool bDone = aFunc.ShowMarkedOutlines( aRange, bRecord, sal_False ); 368 ShowCursor(); 369 if (bDone) 370 UpdateScrollBars(); 371 } 372 else 373 ErrorMessage(STR_NOMULTISELECT); 374 } 375 376 // markierten Bereich ausblenden 377 378 void ScDBFunc::HideMarkedOutlines( sal_Bool bRecord ) 379 { 380 ScRange aRange; 381 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE) 382 { 383 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 384 ScOutlineDocFunc aFunc(*pDocSh); 385 HideCursor(); 386 sal_Bool bDone = aFunc.HideMarkedOutlines( aRange, bRecord, sal_False ); 387 ShowCursor(); 388 if (bDone) 389 UpdateScrollBars(); 390 } 391 else 392 ErrorMessage(STR_NOMULTISELECT); 393 } 394 395 // -------------------------------------------------------------------------- 396 397 // 398 // Teilergebnisse 399 // 400 401 void ScDBFunc::DoSubTotals( const ScSubTotalParam& rParam, sal_Bool bRecord, 402 const ScSortParam* pForceNewSort ) 403 { 404 sal_Bool bDo = !rParam.bRemoveOnly; // sal_False = nur loeschen 405 406 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 407 ScDocument* pDoc = pDocSh->GetDocument(); 408 ScMarkData& rMark = GetViewData()->GetMarkData(); 409 SCTAB nTab = GetViewData()->GetTabNo(); 410 if (bRecord && !pDoc->IsUndoEnabled()) 411 bRecord = sal_False; 412 413 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1, 414 rParam.nCol2, rParam.nRow2 ); 415 if (!pDBData) 416 { 417 DBG_ERROR( "SubTotals: keine DBData" ); 418 return; 419 } 420 421 ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW ); 422 if (!aTester.IsEditable()) 423 { 424 ErrorMessage(aTester.GetMessageId()); 425 return; 426 } 427 428 if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab, 429 rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED )) 430 { 431 ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen 432 return; 433 } 434 435 WaitObject aWait( GetViewData()->GetDialogParent() ); 436 sal_Bool bOk = sal_True; 437 sal_Bool bDelete = sal_False; 438 if (rParam.bReplace) 439 if (pDoc->TestRemoveSubTotals( nTab, rParam )) 440 { 441 bDelete = sal_True; 442 bOk = ( MessBox( GetViewData()->GetDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES), 443 // "StarCalc" "Daten loeschen?" 444 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ), 445 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute() 446 == RET_YES ); 447 } 448 449 if (bOk) 450 { 451 ScDocShellModificator aModificator( *pDocSh ); 452 453 ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert 454 ScDocument* pUndoDoc = NULL; 455 ScOutlineTable* pUndoTab = NULL; 456 ScRangeName* pUndoRange = NULL; 457 ScDBCollection* pUndoDB = NULL; 458 SCTAB nTabCount = 0; // fuer Referenz-Undo 459 460 if (bRecord) // alte Daten sichern 461 { 462 sal_Bool bOldFilter = bDo && rParam.bDoSort; 463 464 nTabCount = pDoc->GetTableCount(); 465 pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); 466 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); 467 if (pTable) 468 { 469 pUndoTab = new ScOutlineTable( *pTable ); 470 471 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus 472 SCCOLROW nOutStartRow; 473 SCCOLROW nOutEndCol; 474 SCCOLROW nOutEndRow; 475 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol ); 476 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow ); 477 478 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True ); 479 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, sal_False, pUndoDoc ); 480 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, sal_False, pUndoDoc ); 481 } 482 else 483 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_False, bOldFilter ); 484 485 // Datenbereich sichern - incl. Filter-Ergebnis 486 pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab, 487 IDF_ALL, sal_False, pUndoDoc ); 488 489 // alle Formeln wegen Referenzen 490 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, 491 IDF_FORMULA, sal_False, pUndoDoc ); 492 493 // DB- und andere Bereiche 494 ScRangeName* pDocRange = pDoc->GetRangeName(); 495 if (pDocRange->GetCount()) 496 pUndoRange = new ScRangeName( *pDocRange ); 497 ScDBCollection* pDocDB = pDoc->GetDBCollection(); 498 if (pDocDB->GetCount()) 499 pUndoDB = new ScDBCollection( *pDocDB ); 500 } 501 502 // pDoc->SetOutlineTable( nTab, NULL ); 503 ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab ); 504 if (pOut) 505 pOut->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen 506 507 if (rParam.bReplace) 508 pDoc->RemoveSubTotals( nTab, aNewParam ); 509 sal_Bool bSuccess = sal_True; 510 if (bDo) 511 { 512 // Sortieren 513 if ( rParam.bDoSort || pForceNewSort ) 514 { 515 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 ); 516 517 // Teilergebnis-Felder vor die Sortierung setzen 518 // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden) 519 520 ScSortParam aOldSort; 521 pDBData->GetSortParam( aOldSort ); 522 ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort ); 523 Sort( aSortParam, sal_False, sal_False ); 524 } 525 526 bSuccess = pDoc->DoSubTotals( nTab, aNewParam ); 527 } 528 ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab, 529 aNewParam.nCol2, aNewParam.nRow2, nTab ); 530 pDoc->SetDirty( aDirtyRange ); 531 532 if (bRecord) 533 { 534 // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL; 535 pDocSh->GetUndoManager()->AddUndoAction( 536 new ScUndoSubTotals( pDocSh, nTab, 537 rParam, aNewParam.nRow2, 538 pUndoDoc, pUndoTab, // pUndoDBData, 539 pUndoRange, pUndoDB ) ); 540 } 541 542 if (!bSuccess) 543 { 544 // "Kann keine Zeilen einfuegen" 545 ErrorMessage(STR_MSSG_DOSUBTOTALS_2); 546 } 547 548 // merken 549 pDBData->SetSubTotalParam( aNewParam ); 550 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 ); 551 pDoc->CompileDBFormula(); 552 553 DoneBlockMode(); 554 InitOwnBlockMode(); 555 rMark.SetMarkArea( ScRange( aNewParam.nCol1,aNewParam.nRow1,nTab, 556 aNewParam.nCol2,aNewParam.nRow2,nTab ) ); 557 MarkDataChanged(); 558 559 pDocSh->PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, 560 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE ); 561 562 aModificator.SetDocumentModified(); 563 564 SelectionChanged(); 565 } 566 } 567 568 // 569 // Consolidate 570 // 571 572 void ScDBFunc::Consolidate( const ScConsolidateParam& rParam, sal_Bool bRecord ) 573 { 574 ScDocShell* pDocShell = GetViewData()->GetDocShell(); 575 pDocShell->DoConsolidate( rParam, bRecord ); 576 SetTabNo( rParam.nTab, sal_True ); 577 } 578 579 // 580 // Pivot 581 // 582 583 String lcl_MakePivotTabName( const String& rPrefix, SCTAB nNumber ) 584 { 585 String aName = rPrefix; 586 aName += String::CreateFromInt32( nNumber ); 587 return aName; 588 } 589 590 bool ScDBFunc::MakePivotTable( const ScDPSaveData& rData, const ScRange& rDest, sal_Bool bNewTable, 591 const ScDPObject& rSource, sal_Bool bApi ) 592 { 593 // #70096# error message if no fields are set 594 // this must be removed when drag&drop of fields from a toolbox is available 595 596 if ( rData.IsEmpty() && !bApi ) 597 { 598 ErrorMessage(STR_PIVOT_NODATA); 599 return false; 600 } 601 602 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 603 ScDocument* pDoc = GetViewData()->GetDocument(); 604 sal_Bool bUndo(pDoc->IsUndoEnabled()); 605 606 ScRange aDestRange = rDest; 607 if ( bNewTable ) 608 { 609 SCTAB nSrcTab = GetViewData()->GetTabNo(); 610 611 String aName( ScGlobal::GetRscString(STR_PIVOT_TABLE) ); 612 String aStr; 613 614 pDoc->GetName( nSrcTab, aStr ); 615 aName += '_'; 616 aName += aStr; 617 aName += '_'; 618 619 SCTAB nNewTab = nSrcTab+1; 620 621 SCTAB i=1; 622 while ( !pDoc->InsertTab( nNewTab, lcl_MakePivotTabName( aName, i ) ) && i <= MAXTAB ) 623 i++; 624 625 sal_Bool bAppend = ( nNewTab+1 == pDoc->GetTableCount() ); 626 if (bUndo) 627 { 628 pDocSh->GetUndoManager()->AddUndoAction( 629 new ScUndoInsertTab( pDocSh, nNewTab, bAppend, lcl_MakePivotTabName( aName, i ) )); 630 } 631 632 GetViewData()->InsertTab( nNewTab ); 633 SetTabNo( nNewTab, sal_True ); 634 635 aDestRange = ScRange( 0, 0, nNewTab ); 636 } 637 638 ScDPObject* pDPObj = pDoc->GetDPAtCursor( 639 aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aStart.Tab() ); 640 641 ScDPObject aObj( rSource ); 642 aObj.SetOutRange( aDestRange ); 643 if ( pDPObj && !rData.GetExistingDimensionData() ) 644 { 645 // copy dimension data from old object - lost in the dialog 646 //! change the dialog to keep the dimension data 647 648 ScDPSaveData aNewData( rData ); 649 const ScDPSaveData* pOldData = pDPObj->GetSaveData(); 650 if ( pOldData ) 651 { 652 const ScDPDimensionSaveData* pDimSave = pOldData->GetExistingDimensionData(); 653 aNewData.SetDimensionData( pDimSave ); 654 } 655 aObj.SetSaveData( aNewData ); 656 } 657 else 658 aObj.SetSaveData( rData ); 659 660 sal_Bool bAllowMove = ( pDPObj != NULL ); // allow re-positioning when editing existing table 661 662 ScDBDocFunc aFunc( *pDocSh ); 663 bool bSuccess = aFunc.DataPilotUpdate( pDPObj, &aObj, sal_True, sal_False, bAllowMove ); 664 665 CursorPosChanged(); // shells may be switched 666 667 if ( bNewTable ) 668 { 669 pDocSh->PostPaintExtras(); 670 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); 671 } 672 673 return bSuccess; 674 } 675 676 void ScDBFunc::DeletePivotTable() 677 { 678 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 679 ScDocument* pDoc = pDocSh->GetDocument(); 680 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(), 681 GetViewData()->GetCurY(), 682 GetViewData()->GetTabNo() ); 683 if ( pDPObj ) 684 { 685 ScDBDocFunc aFunc( *pDocSh ); 686 aFunc.DataPilotUpdate( pDPObj, NULL, sal_True, sal_False ); 687 CursorPosChanged(); // shells may be switched 688 } 689 else 690 ErrorMessage(STR_PIVOT_NOTFOUND); 691 } 692 sal_uLong RefreshDPObject( ScDPObject *pDPObj, ScDocument *pDoc, ScDocShell *pDocSh, sal_Bool bRecord, sal_Bool bApi ) 693 { 694 if( !pDPObj ) 695 return STR_PIVOT_NOTFOUND; 696 697 if ( pDocSh && !pDoc ) 698 pDoc = pDocSh->GetDocument(); 699 700 if( !pDoc ) 701 return static_cast<sal_uLong>(-1); 702 703 if( !pDocSh && ( pDocSh = PTR_CAST( ScDocShell, pDoc->GetDocumentShell() ) ) == NULL ) 704 return static_cast<sal_uLong>(-1); 705 706 if( sal_uLong nErrId = pDPObj->RefreshCache() ) 707 return nErrId; 708 else if ( nErrId == 0 ) 709 { 710 //Refresh all dpobjects 711 ScDPCollection* pDPCollection = pDoc->GetDPCollection(); 712 sal_uInt16 nCount = pDPCollection->GetCount(); 713 for (sal_uInt16 i=0; i<nCount; i++) 714 { 715 if ( (*pDPCollection)[i]->GetCacheId() == pDPObj->GetCacheId() ) 716 { 717 ScDBDocFunc aFunc( * pDocSh ); 718 if ( !aFunc.DataPilotUpdate( (*pDPCollection)[i], (*pDPCollection)[i], bRecord, bApi ) ) 719 break; 720 } 721 } 722 723 return nErrId; 724 } 725 726 return 0U; 727 } 728 729 sal_uLong ScDBFunc::RecalcPivotTable() 730 { 731 ScDocShell* pDocSh = GetViewData()->GetDocShell(); 732 ScDocument* pDoc = GetViewData()->GetDocument(); 733 734 // old pivot not used any more 735 736 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(), 737 GetViewData()->GetCurY(), 738 GetViewData()->GetTabNo() ); 739 if ( pDPObj ) 740 { 741 // Wang Xu Ming -- 2009-6-17 742 // DataPilot Migration 743 //ScDBDocFunc aFunc( *pDocSh ); 744 //aFunc.DataPilotUpdate( pDPObj, pDPObj, sal_True, sal_False ); 745 //CursorPosChanged(); // shells may be switched 746 sal_uLong nErrId = RefreshDPObject( pDPObj, pDoc, pDocSh, sal_True, sal_False );//pDPObj->RefreshCache(); 747 if ( nErrId == 0 ) 748 { 749 // There is no undo for the refresh of the cache table, but the undo history for cell changes 750 // remains valid and should be preserved, so the history isn't cleared here. 751 //GetViewData()->GetDocShell()->GetUndoManager()->Clear(); 752 } 753 else if (nErrId <= USHRT_MAX) 754 ErrorMessage(static_cast<sal_uInt16>(nErrId)); 755 return nErrId; 756 // End Comments 757 } 758 else 759 ErrorMessage(STR_PIVOT_NOTFOUND); 760 return STR_PIVOT_NOTFOUND; 761 } 762 763 void ScDBFunc::GetSelectedMemberList( ScStrCollection& rEntries, long& rDimension ) 764 { 765 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(), 766 GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); 767 if ( !pDPObj ) 768 return; 769 770 long nStartDimension = -1; 771 long nStartHierarchy = -1; 772 long nStartLevel = -1; 773 774 ScRangeListRef xRanges; 775 GetViewData()->GetMultiArea( xRanges ); // incl. cursor if nothing is selected 776 sal_uLong nRangeCount = xRanges->Count(); 777 sal_Bool bContinue = sal_True; 778 779 for (sal_uLong nRangePos=0; nRangePos<nRangeCount && bContinue; nRangePos++) 780 { 781 ScRange aRange = *xRanges->GetObject(nRangePos); 782 SCCOL nStartCol = aRange.aStart.Col(); 783 SCROW nStartRow = aRange.aStart.Row(); 784 SCCOL nEndCol = aRange.aEnd.Col(); 785 SCROW nEndRow = aRange.aEnd.Row(); 786 SCTAB nTab = aRange.aStart.Tab(); 787 788 for (SCROW nRow=nStartRow; nRow<=nEndRow && bContinue; nRow++) 789 for (SCCOL nCol=nStartCol; nCol<=nEndCol && bContinue; nCol++) 790 { 791 sheet::DataPilotTableHeaderData aData; 792 pDPObj->GetHeaderPositionData(ScAddress(nCol, nRow, nTab), aData); 793 if ( aData.Dimension < 0 ) 794 bContinue = sal_False; // not part of any dimension 795 else 796 { 797 if ( nStartDimension < 0 ) // first member? 798 { 799 nStartDimension = aData.Dimension; 800 nStartHierarchy = aData.Hierarchy; 801 nStartLevel = aData.Level; 802 } 803 if ( aData.Dimension != nStartDimension || 804 aData.Hierarchy != nStartHierarchy || 805 aData.Level != nStartLevel ) 806 { 807 bContinue = sal_False; // cannot mix dimensions 808 } 809 } 810 if ( bContinue ) 811 { 812 // accept any part of a member description, also subtotals, 813 // but don't stop if empty parts are contained 814 if ( aData.Flags & sheet::MemberResultFlags::HASMEMBER ) 815 { 816 StrData* pNew = new StrData( aData.MemberName ); 817 if ( !rEntries.Insert( pNew ) ) 818 delete pNew; 819 } 820 } 821 } 822 } 823 824 rDimension = nStartDimension; // dimension from which the found members came 825 if (!bContinue) 826 rEntries.FreeAll(); // remove all if not valid 827 } 828 829 sal_Bool ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo& rOldInfo, sal_Int32& rParts ) 830 { 831 // determine if the date group dialog has to be shown for the current selection 832 833 sal_Bool bFound = sal_False; 834 835 SCCOL nCurX = GetViewData()->GetCurX(); 836 SCROW nCurY = GetViewData()->GetCurY(); 837 SCTAB nTab = GetViewData()->GetTabNo(); 838 ScDocument* pDoc = GetViewData()->GetDocument(); 839 840 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab ); 841 if ( pDPObj ) 842 { 843 ScStrCollection aEntries; 844 long nSelectDimension = -1; 845 GetSelectedMemberList( aEntries, nSelectDimension ); 846 847 if ( aEntries.GetCount() > 0 ) 848 { 849 sal_Bool bIsDataLayout; 850 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 851 String aBaseDimName( aDimName ); 852 853 sal_Bool bInGroupDim = sal_False; 854 sal_Bool bFoundParts = sal_False; 855 856 ScDPDimensionSaveData* pDimData = 857 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() ); 858 if ( pDimData ) 859 { 860 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName ); 861 const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( aDimName ); 862 if ( pNumGroupDim ) 863 { 864 // existing num group dimension 865 866 if ( pNumGroupDim->GetDatePart() != 0 ) 867 { 868 // dimension has date info -> edit settings of this dimension 869 // (parts are collected below) 870 871 rOldInfo = pNumGroupDim->GetDateInfo(); 872 bFound = sal_True; 873 } 874 else if ( pNumGroupDim->GetInfo().DateValues ) 875 { 876 // Numerical grouping with DateValues flag is used for grouping 877 // of days with a "Number of days" value. 878 879 rOldInfo = pNumGroupDim->GetInfo(); 880 rParts = com::sun::star::sheet::DataPilotFieldGroupBy::DAYS; // not found in CollectDateParts 881 bFoundParts = sal_True; 882 bFound = sal_True; 883 } 884 bInGroupDim = sal_True; 885 } 886 else if ( pGroupDim ) 887 { 888 // existing additional group dimension 889 890 if ( pGroupDim->GetDatePart() != 0 ) 891 { 892 // dimension has date info -> edit settings of this dimension 893 // (parts are collected below) 894 895 rOldInfo = pGroupDim->GetDateInfo(); 896 aBaseDimName = pGroupDim->GetSourceDimName(); 897 bFound = sal_True; 898 } 899 bInGroupDim = sal_True; 900 } 901 } 902 if ( bFound && !bFoundParts ) 903 { 904 // collect date parts from all group dimensions 905 rParts = pDimData->CollectDateParts( aBaseDimName ); 906 } 907 if ( !bFound && !bInGroupDim ) 908 { 909 // create new date group dimensions if the selection is a single cell 910 // in a normal dimension with date content 911 912 ScRange aSelRange; 913 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) && 914 aSelRange.aStart == aSelRange.aEnd ) 915 { 916 SCCOL nSelCol = aSelRange.aStart.Col(); 917 SCROW nSelRow = aSelRange.aStart.Row(); 918 SCTAB nSelTab = aSelRange.aStart.Tab(); 919 if ( pDoc->HasValueData( nSelCol, nSelRow, nSelTab ) ) 920 { 921 sal_uLong nIndex = static_cast<const SfxUInt32Item*>(pDoc->GetAttr( 922 nSelCol, nSelRow, nSelTab, ATTR_VALUE_FORMAT))->GetValue(); 923 short nType = pDoc->GetFormatTable()->GetType(nIndex); 924 if ( nType == NUMBERFORMAT_DATE || nType == NUMBERFORMAT_TIME || nType == NUMBERFORMAT_DATETIME ) 925 { 926 bFound = sal_True; 927 // use currently selected value for automatic limits 928 if( rOldInfo.AutoStart ) 929 rOldInfo.Start = pDoc->GetValue( aSelRange.aStart ); 930 if( rOldInfo.AutoEnd ) 931 rOldInfo.End = pDoc->GetValue( aSelRange.aStart ); 932 } 933 } 934 } 935 } 936 } 937 } 938 939 return bFound; 940 } 941 942 sal_Bool ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo& rOldInfo ) 943 { 944 // determine if the numeric group dialog has to be shown for the current selection 945 946 sal_Bool bFound = sal_False; 947 948 SCCOL nCurX = GetViewData()->GetCurX(); 949 SCROW nCurY = GetViewData()->GetCurY(); 950 SCTAB nTab = GetViewData()->GetTabNo(); 951 ScDocument* pDoc = GetViewData()->GetDocument(); 952 953 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab ); 954 if ( pDPObj ) 955 { 956 ScStrCollection aEntries; 957 long nSelectDimension = -1; 958 GetSelectedMemberList( aEntries, nSelectDimension ); 959 960 if ( aEntries.GetCount() > 0 ) 961 { 962 sal_Bool bIsDataLayout; 963 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 964 965 sal_Bool bInGroupDim = sal_False; 966 967 ScDPDimensionSaveData* pDimData = 968 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() ); 969 if ( pDimData ) 970 { 971 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName ); 972 if ( pNumGroupDim ) 973 { 974 // existing num group dimension 975 // -> edit settings of this dimension 976 977 rOldInfo = pNumGroupDim->GetInfo(); 978 bFound = sal_True; 979 } 980 else if ( pDimData->GetNamedGroupDim( aDimName ) ) 981 bInGroupDim = sal_True; // in a group dimension 982 } 983 if ( !bFound && !bInGroupDim ) 984 { 985 // create a new num group dimension if the selection is a single cell 986 // in a normal dimension with numeric content 987 988 ScRange aSelRange; 989 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) && 990 aSelRange.aStart == aSelRange.aEnd ) 991 { 992 if ( pDoc->HasValueData( aSelRange.aStart.Col(), aSelRange.aStart.Row(), 993 aSelRange.aStart.Tab() ) ) 994 { 995 bFound = sal_True; 996 // use currently selected value for automatic limits 997 if( rOldInfo.AutoStart ) 998 rOldInfo.Start = pDoc->GetValue( aSelRange.aStart ); 999 if( rOldInfo.AutoEnd ) 1000 rOldInfo.End = pDoc->GetValue( aSelRange.aStart ); 1001 } 1002 } 1003 } 1004 } 1005 } 1006 1007 return bFound; 1008 } 1009 1010 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nParts ) 1011 { 1012 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(), 1013 GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); 1014 if ( pDPObj ) 1015 { 1016 ScStrCollection aEntries; 1017 long nSelectDimension = -1; 1018 GetSelectedMemberList( aEntries, nSelectDimension ); 1019 1020 if ( aEntries.GetCount() > 0 ) 1021 { 1022 sal_Bool bIsDataLayout; 1023 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 1024 1025 ScDPSaveData aData( *pDPObj->GetSaveData() ); 1026 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there 1027 1028 // find original base 1029 String aBaseDimName = aDimName; 1030 if( const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName ) ) 1031 aBaseDimName = pBaseGroupDim->GetSourceDimName(); 1032 1033 // remove all existing parts (the grouping is built completely new) 1034 1035 /* Remove numeric group dimension (exists once at most). No need 1036 to delete anything in save data (grouping was done inplace in 1037 an existing base dimension). */ 1038 pDimData->RemoveNumGroupDimension( aBaseDimName ); 1039 1040 /* Remove named group dimension(s). Collect deleted dimension 1041 names which may be reused while recreating the groups. 1042 Dimensions have to be removed from dimension save data and from 1043 save data too. */ 1044 std::vector< String > aDeletedNames; 1045 const ScDPSaveGroupDimension* pExistingGroup = pDimData->GetGroupDimForBase( aBaseDimName ); 1046 while ( pExistingGroup ) 1047 { 1048 String aGroupDimName = pExistingGroup->GetGroupDimName(); 1049 pDimData->RemoveGroupDimension( aGroupDimName ); // pExistingGroup is deleted 1050 1051 // also remove SaveData settings for the dimension that no longer exists 1052 aData.RemoveDimensionByName( aGroupDimName ); 1053 1054 /* The name can be used for the new group dimensions, although 1055 it is still in use with the DataPilotSource. */ 1056 aDeletedNames.push_back( aGroupDimName ); 1057 1058 // see if there are more group dimensions 1059 pExistingGroup = pDimData->GetGroupDimForBase( aBaseDimName ); 1060 1061 if ( pExistingGroup && pExistingGroup->GetGroupDimName() == aGroupDimName ) 1062 { 1063 // still get the same group dimension? 1064 DBG_ERROR("couldn't remove group dimension"); 1065 pExistingGroup = NULL; // avoid endless loop 1066 } 1067 } 1068 1069 if ( nParts ) 1070 { 1071 // create date group dimensions 1072 1073 ScDPNumGroupInfo aEmpty; 1074 bool bFirst = true; 1075 sal_Int32 nMask = 1; 1076 for (sal_uInt16 nBit=0; nBit<32; nBit++) 1077 { 1078 if ( nParts & nMask ) 1079 { 1080 if ( bFirst ) 1081 { 1082 // innermost part: create NumGroupDimension (replacing original values) 1083 // Dimension name is left unchanged 1084 1085 if ( (nParts == sheet::DataPilotFieldGroupBy::DAYS) && (rInfo.Step >= 1.0) ) 1086 { 1087 // only days, and a step value specified: use numerical grouping 1088 // with DateValues flag, not date grouping 1089 1090 ScDPNumGroupInfo aNumInfo( rInfo ); 1091 aNumInfo.DateValues = sal_True; 1092 1093 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, aNumInfo ); 1094 pDimData->AddNumGroupDimension( aNumGroupDim ); 1095 } 1096 else 1097 { 1098 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, rInfo, nMask ); 1099 pDimData->AddNumGroupDimension( aNumGroupDim ); 1100 } 1101 1102 bFirst = false; 1103 } 1104 else 1105 { 1106 // additional parts: create GroupDimension (shown as additional dimensions) 1107 String aGroupDimName = pDimData->CreateDateGroupDimName( nMask, *pDPObj, true, &aDeletedNames ); 1108 ScDPSaveGroupDimension aGroupDim( aBaseDimName, aGroupDimName ); 1109 aGroupDim.SetDateInfo( rInfo, nMask ); 1110 pDimData->AddGroupDimension( aGroupDim ); 1111 1112 // set orientation 1113 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName ); 1114 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN ) 1115 { 1116 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aBaseDimName ); 1117 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() ); 1118 long nPosition = 0; //! before (immediate) base 1119 aData.SetPosition( pSaveDimension, nPosition ); 1120 } 1121 } 1122 } 1123 nMask *= 2; 1124 } 1125 } 1126 1127 // apply changes 1128 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); 1129 ScDPObject* pNewObj = new ScDPObject( *pDPObj ); 1130 pNewObj->SetSaveData( aData ); 1131 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); 1132 delete pNewObj; 1133 1134 // unmark cell selection 1135 Unmark(); 1136 } 1137 } 1138 } 1139 1140 void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo& rInfo ) 1141 { 1142 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(), 1143 GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); 1144 if ( pDPObj ) 1145 { 1146 ScStrCollection aEntries; 1147 long nSelectDimension = -1; 1148 GetSelectedMemberList( aEntries, nSelectDimension ); 1149 1150 if ( aEntries.GetCount() > 0 ) 1151 { 1152 sal_Bool bIsDataLayout; 1153 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 1154 1155 ScDPSaveData aData( *pDPObj->GetSaveData() ); 1156 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there 1157 1158 ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( aDimName ); 1159 if ( pExisting ) 1160 { 1161 // modify existing group dimension 1162 pExisting->SetGroupInfo( rInfo ); 1163 } 1164 else 1165 { 1166 // create new group dimension 1167 ScDPSaveNumGroupDimension aNumGroupDim( aDimName, rInfo ); 1168 pDimData->AddNumGroupDimension( aNumGroupDim ); 1169 } 1170 1171 // apply changes 1172 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); 1173 ScDPObject* pNewObj = new ScDPObject( *pDPObj ); 1174 pNewObj->SetSaveData( aData ); 1175 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); 1176 delete pNewObj; 1177 1178 // unmark cell selection 1179 Unmark(); 1180 } 1181 } 1182 } 1183 1184 void ScDBFunc::GroupDataPilot() 1185 { 1186 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(), 1187 GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); 1188 if ( pDPObj ) 1189 { 1190 ScStrCollection aEntries; 1191 long nSelectDimension = -1; 1192 GetSelectedMemberList( aEntries, nSelectDimension ); 1193 1194 if ( aEntries.GetCount() > 0 ) 1195 { 1196 sal_Bool bIsDataLayout; 1197 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 1198 1199 ScDPSaveData aData( *pDPObj->GetSaveData() ); 1200 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there 1201 1202 // find original base 1203 String aBaseDimName( aDimName ); 1204 const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName ); 1205 if ( pBaseGroupDim ) 1206 { 1207 // any entry's SourceDimName is the original base 1208 aBaseDimName = pBaseGroupDim->GetSourceDimName(); 1209 } 1210 1211 // find existing group dimension 1212 // (using the selected dim, can be intermediate group dim) 1213 ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName ); 1214 1215 // remove the selected items from their groups 1216 // (empty groups are removed, too) 1217 sal_uInt16 nEntryCount = aEntries.GetCount(); 1218 sal_uInt16 nEntry; 1219 if ( pGroupDimension ) 1220 { 1221 for (nEntry=0; nEntry<nEntryCount; nEntry++) 1222 { 1223 String aEntryName = aEntries[nEntry]->GetString(); 1224 if ( pBaseGroupDim ) 1225 { 1226 // for each selected (intermediate) group, remove all its items 1227 // (same logic as for adding, below) 1228 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName ); 1229 if ( pBaseGroup ) 1230 pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements 1231 else 1232 pGroupDimension->RemoveFromGroups( aEntryName ); 1233 } 1234 else 1235 pGroupDimension->RemoveFromGroups( aEntryName ); 1236 } 1237 } 1238 1239 ScDPSaveGroupDimension* pNewGroupDim = NULL; 1240 if ( !pGroupDimension ) 1241 { 1242 // create a new group dimension 1243 String aGroupDimName = pDimData->CreateGroupDimName( aBaseDimName, *pDPObj, false, NULL ); 1244 pNewGroupDim = new ScDPSaveGroupDimension( aBaseDimName, aGroupDimName ); 1245 1246 pGroupDimension = pNewGroupDim; // make changes to the new dim if none existed 1247 1248 if ( pBaseGroupDim ) 1249 { 1250 // If it's a higher-order group dimension, pre-allocate groups for all 1251 // non-selected original groups, so the individual base members aren't 1252 // used for automatic groups (this would make the original groups hard 1253 // to find). 1254 //! Also do this when removing groups? 1255 //! Handle this case dynamically with automatic groups? 1256 1257 long nGroupCount = pBaseGroupDim->GetGroupCount(); 1258 for ( long nGroup = 0; nGroup < nGroupCount; nGroup++ ) 1259 { 1260 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup ); 1261 1262 StrData aStrData( pBaseGroup->GetGroupName() ); 1263 sal_uInt16 nCollIndex; 1264 if ( !aEntries.Search( &aStrData, nCollIndex ) ) //! ignore case? 1265 { 1266 // add an additional group for each item that is not in the selection 1267 ScDPSaveGroupItem aGroup( pBaseGroup->GetGroupName() ); 1268 aGroup.AddElementsFromGroup( *pBaseGroup ); 1269 pGroupDimension->AddGroupItem( aGroup ); 1270 } 1271 } 1272 } 1273 } 1274 String aGroupDimName = pGroupDimension->GetGroupDimName(); 1275 1276 //! localized prefix string 1277 String aGroupName = pGroupDimension->CreateGroupName( String::CreateFromAscii("Group") ); 1278 ScDPSaveGroupItem aGroup( aGroupName ); 1279 for (nEntry=0; nEntry<nEntryCount; nEntry++) 1280 { 1281 String aEntryName = aEntries[nEntry]->GetString(); 1282 if ( pBaseGroupDim ) 1283 { 1284 // for each selected (intermediate) group, add all its items 1285 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName ); 1286 if ( pBaseGroup ) 1287 aGroup.AddElementsFromGroup( *pBaseGroup ); 1288 else 1289 aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself 1290 } 1291 else 1292 aGroup.AddElement( aEntryName ); // no group dimension, add all items directly 1293 } 1294 1295 pGroupDimension->AddGroupItem( aGroup ); 1296 1297 if ( pNewGroupDim ) 1298 { 1299 pDimData->AddGroupDimension( *pNewGroupDim ); 1300 delete pNewGroupDim; // AddGroupDimension copies the object 1301 // don't access pGroupDimension after here 1302 } 1303 pGroupDimension = pNewGroupDim = NULL; 1304 1305 // set orientation 1306 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName ); 1307 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN ) 1308 { 1309 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aDimName ); 1310 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() ); 1311 long nPosition = 0; //! before (immediate) base 1312 aData.SetPosition( pSaveDimension, nPosition ); 1313 } 1314 1315 // apply changes 1316 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); 1317 ScDPObject* pNewObj = new ScDPObject( *pDPObj ); 1318 pNewObj->SetSaveData( aData ); 1319 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); 1320 delete pNewObj; 1321 1322 // unmark cell selection 1323 Unmark(); 1324 } 1325 } 1326 } 1327 1328 void ScDBFunc::UngroupDataPilot() 1329 { 1330 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(), 1331 GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); 1332 if ( pDPObj ) 1333 { 1334 ScStrCollection aEntries; 1335 long nSelectDimension = -1; 1336 GetSelectedMemberList( aEntries, nSelectDimension ); 1337 1338 if ( aEntries.GetCount() > 0 ) 1339 { 1340 sal_Bool bIsDataLayout; 1341 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 1342 1343 ScDPSaveData aData( *pDPObj->GetSaveData() ); 1344 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there 1345 //! test first if DimensionData exists? 1346 1347 sal_Bool bApply = sal_False; 1348 1349 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName ); 1350 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName ); 1351 if ( ( pGroupDim && pGroupDim->GetDatePart() != 0 ) || 1352 ( pNumGroupDim && pNumGroupDim->GetDatePart() != 0 ) ) 1353 { 1354 // Date grouping: need to remove all affected group dimensions. 1355 // This is done using DateGroupDataPilot with nParts=0. 1356 1357 DateGroupDataPilot( ScDPNumGroupInfo(), 0 ); 1358 // bApply remains FALSE 1359 // dimension pointers become invalid 1360 } 1361 else if ( pGroupDim ) 1362 { 1363 sal_uInt16 nEntryCount = aEntries.GetCount(); 1364 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++) 1365 { 1366 String aEntryName = aEntries[nEntry]->GetString(); 1367 pGroupDim->RemoveGroup( aEntryName ); 1368 } 1369 // remove group dimension if empty 1370 bool bEmptyDim = pGroupDim->IsEmpty(); 1371 if ( !bEmptyDim ) 1372 { 1373 // If all remaining groups in the dimension aren't shown, remove 1374 // the dimension too, as if it was completely empty. 1375 ScStrCollection aVisibleEntries; 1376 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension ); 1377 bEmptyDim = pGroupDim->HasOnlyHidden( aVisibleEntries ); 1378 } 1379 if ( bEmptyDim ) 1380 { 1381 pDimData->RemoveGroupDimension( aDimName ); // pGroupDim is deleted 1382 1383 // also remove SaveData settings for the dimension that no longer exists 1384 aData.RemoveDimensionByName( aDimName ); 1385 } 1386 bApply = sal_True; 1387 } 1388 else if ( pNumGroupDim ) 1389 { 1390 // remove the numerical grouping 1391 pDimData->RemoveNumGroupDimension( aDimName ); 1392 // SaveData settings can remain unchanged - the same dimension still exists 1393 bApply = sal_True; 1394 } 1395 1396 if ( bApply ) 1397 { 1398 // apply changes 1399 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); 1400 ScDPObject* pNewObj = new ScDPObject( *pDPObj ); 1401 pNewObj->SetSaveData( aData ); 1402 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); 1403 delete pNewObj; 1404 1405 // unmark cell selection 1406 Unmark(); 1407 } 1408 } 1409 } 1410 } 1411 1412 static OUString lcl_replaceMemberNameInSubtotal(const OUString& rSubtotal, const OUString& rMemberName) 1413 { 1414 sal_Int32 n = rSubtotal.getLength(); 1415 const sal_Unicode* p = rSubtotal.getStr(); 1416 OUStringBuffer aBuf, aWordBuf; 1417 for (sal_Int32 i = 0; i < n; ++i) 1418 { 1419 sal_Unicode c = p[i]; 1420 if (c == sal_Unicode(' ')) 1421 { 1422 OUString aWord = aWordBuf.makeStringAndClear(); 1423 if (aWord.equals(rMemberName)) 1424 aBuf.append(sal_Unicode('?')); 1425 else 1426 aBuf.append(aWord); 1427 aBuf.append(c); 1428 } 1429 else if (c == sal_Unicode('\\')) 1430 { 1431 // Escape a backslash character. 1432 aWordBuf.append(c); 1433 aWordBuf.append(c); 1434 } 1435 else if (c == sal_Unicode('?')) 1436 { 1437 // A literal '?' must be escaped with a backslash ('\'); 1438 aWordBuf.append(sal_Unicode('\\')); 1439 aWordBuf.append(c); 1440 } 1441 else 1442 aWordBuf.append(c); 1443 } 1444 1445 if (aWordBuf.getLength() > 0) 1446 { 1447 OUString aWord = aWordBuf.makeStringAndClear(); 1448 if (aWord.equals(rMemberName)) 1449 aBuf.append(sal_Unicode('?')); 1450 else 1451 aBuf.append(aWord); 1452 } 1453 1454 return aBuf.makeStringAndClear(); 1455 } 1456 1457 void ScDBFunc::DataPilotInput( const ScAddress& rPos, const String& rString ) 1458 { 1459 using namespace ::com::sun::star::sheet; 1460 1461 String aNewName( rString ); 1462 1463 ScDocument* pDoc = GetViewData()->GetDocument(); 1464 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rPos.Col(), rPos.Row(), rPos.Tab() ); 1465 if (!pDPObj) 1466 return; 1467 1468 String aOldText; 1469 pDoc->GetString( rPos.Col(), rPos.Row(), rPos.Tab(), aOldText ); 1470 1471 if ( aOldText == rString ) 1472 { 1473 // nothing to do: silently exit 1474 return; 1475 } 1476 1477 sal_uInt16 nErrorId = 0; 1478 1479 pDPObj->BuildAllDimensionMembers(); 1480 ScDPSaveData aData( *pDPObj->GetSaveData() ); 1481 sal_Bool bChange = sal_False; 1482 1483 sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN; 1484 long nField = pDPObj->GetHeaderDim( rPos, nOrient ); 1485 if ( nField >= 0 ) 1486 { 1487 // changing a field title 1488 if ( aData.GetExistingDimensionData() ) 1489 { 1490 // only group dimensions can be renamed 1491 1492 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); 1493 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText ); 1494 if ( pGroupDim ) 1495 { 1496 // valid name: not empty, no existing dimension (group or other) 1497 if ( rString.Len() && !pDPObj->IsDimNameInUse(rString) ) 1498 { 1499 pGroupDim->Rename( aNewName ); 1500 1501 // also rename in SaveData to preserve the field settings 1502 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText ); 1503 pSaveDim->SetName( aNewName ); 1504 1505 bChange = sal_True; 1506 } 1507 else 1508 nErrorId = STR_INVALIDNAME; 1509 } 1510 } 1511 else if (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) 1512 { 1513 sal_Bool bDataLayout = false; 1514 String aDimName = pDPObj->GetDimName(nField, bDataLayout); 1515 ScDPSaveDimension* pDim = bDataLayout ? aData.GetDataLayoutDimension() : aData.GetDimensionByName(aDimName); 1516 if (pDim) 1517 { 1518 if (rString.Len()) 1519 { 1520 if (rString.EqualsIgnoreCaseAscii(aDimName)) 1521 { 1522 pDim->RemoveLayoutName(); 1523 bChange = true; 1524 } 1525 else if (!pDPObj->IsDimNameInUse(rString)) 1526 { 1527 pDim->SetLayoutName(rString); 1528 bChange = true; 1529 } 1530 else 1531 nErrorId = STR_INVALIDNAME; 1532 } 1533 else 1534 nErrorId = STR_INVALIDNAME; 1535 } 1536 } 1537 } 1538 else if (pDPObj->IsDataDescriptionCell(rPos)) 1539 { 1540 // There is only one data dimension. 1541 ScDPSaveDimension* pDim = aData.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA); 1542 if (pDim) 1543 { 1544 if (rString.Len()) 1545 { 1546 if (rString.EqualsIgnoreCaseAscii(pDim->GetName())) 1547 { 1548 pDim->RemoveLayoutName(); 1549 bChange = true; 1550 } 1551 else if (!pDPObj->IsDimNameInUse(rString)) 1552 { 1553 pDim->SetLayoutName(rString); 1554 bChange = true; 1555 } 1556 else 1557 nErrorId = STR_INVALIDNAME; 1558 } 1559 else 1560 nErrorId = STR_INVALIDNAME; 1561 } 1562 } 1563 else 1564 { 1565 // This is not a field header. 1566 sheet::DataPilotTableHeaderData aPosData; 1567 pDPObj->GetHeaderPositionData(rPos, aPosData); 1568 1569 if ( (aPosData.Flags & MemberResultFlags::HASMEMBER) && aOldText.Len() ) 1570 { 1571 if ( aData.GetExistingDimensionData() && !(aPosData.Flags & MemberResultFlags::SUBTOTAL)) 1572 { 1573 sal_Bool bIsDataLayout; 1574 String aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout ); 1575 1576 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); 1577 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName ); 1578 if ( pGroupDim ) 1579 { 1580 // valid name: not empty, no existing group in this dimension 1581 //! ignore case? 1582 if ( aNewName.Len() && !pGroupDim->GetNamedGroup( aNewName ) ) 1583 { 1584 ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText ); 1585 if ( pGroup ) 1586 pGroup->Rename( aNewName ); // rename the existing group 1587 else 1588 { 1589 // create a new group to replace the automatic group 1590 ScDPSaveGroupItem aGroup( aNewName ); 1591 aGroup.AddElement( aOldText ); 1592 pGroupDim->AddGroupItem( aGroup ); 1593 } 1594 1595 // in both cases also adjust savedata, to preserve member settings (show details) 1596 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName ); 1597 ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText ); 1598 if ( pSaveMember ) 1599 pSaveMember->SetName( aNewName ); 1600 1601 bChange = sal_True; 1602 } 1603 else 1604 nErrorId = STR_INVALIDNAME; 1605 } 1606 } 1607 else if ((aPosData.Flags & MemberResultFlags::GRANDTOTAL)) 1608 { 1609 aData.SetGrandTotalName(rString); 1610 bChange = true; 1611 } 1612 else if (aPosData.Dimension >= 0 && aPosData.MemberName.getLength() > 0) 1613 { 1614 sal_Bool bDataLayout = false; 1615 String aDimName = pDPObj->GetDimName(static_cast<long>(aPosData.Dimension), bDataLayout); 1616 if (bDataLayout) 1617 { 1618 // data dimension 1619 do 1620 { 1621 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL)) 1622 break; 1623 1624 ScDPSaveDimension* pDim = aData.GetDimensionByName(aPosData.MemberName); 1625 if (!pDim) 1626 break; 1627 1628 if (!rString.Len()) 1629 { 1630 nErrorId = STR_INVALIDNAME; 1631 break; 1632 } 1633 1634 if (aPosData.MemberName.equalsIgnoreAsciiCase(rString)) 1635 { 1636 pDim->RemoveLayoutName(); 1637 bChange = true; 1638 } 1639 else if (!pDPObj->IsDimNameInUse(rString)) 1640 { 1641 pDim->SetLayoutName(rString); 1642 bChange = true; 1643 } 1644 else 1645 nErrorId = STR_INVALIDNAME; 1646 } 1647 while (false); 1648 } 1649 else 1650 { 1651 // field member 1652 do 1653 { 1654 ScDPSaveDimension* pDim = aData.GetDimensionByName(aDimName); 1655 if (!pDim) 1656 break; 1657 1658 ScDPSaveMember* pMem = pDim->GetExistingMemberByName(aPosData.MemberName); 1659 if (!pMem) 1660 break; 1661 1662 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL)) 1663 { 1664 // Change subtotal only when the table has one data dimension. 1665 if (aData.GetDataDimensionCount() > 1) 1666 break; 1667 1668 // display name for subtotal is allowed only if the subtotal type is 'Automatic'. 1669 if (pDim->GetSubTotalsCount() != 1) 1670 break; 1671 1672 if (pDim->GetSubTotalFunc(0) != sheet::GeneralFunction_AUTO) 1673 break; 1674 1675 const OUString* pLayoutName = pMem->GetLayoutName(); 1676 String aMemberName; 1677 if (pLayoutName) 1678 aMemberName = *pLayoutName; 1679 else 1680 aMemberName = aPosData.MemberName; 1681 1682 String aNew = lcl_replaceMemberNameInSubtotal(rString, aMemberName); 1683 pDim->SetSubtotalName(aNew); 1684 bChange = true; 1685 } 1686 else 1687 { 1688 // Check to make sure the member name isn't 1689 // already used. 1690 if (rString.Len()) 1691 { 1692 if (rString.EqualsIgnoreCaseAscii(pMem->GetName())) 1693 { 1694 pMem->RemoveLayoutName(); 1695 bChange = true; 1696 } 1697 else if (!pDim->IsMemberNameInUse(rString)) 1698 { 1699 pMem->SetLayoutName(rString); 1700 bChange = true; 1701 } 1702 else 1703 nErrorId = STR_INVALIDNAME; 1704 } 1705 else 1706 nErrorId = STR_INVALIDNAME; 1707 } 1708 } 1709 while (false); 1710 } 1711 } 1712 } 1713 } 1714 1715 if ( bChange ) 1716 { 1717 // apply changes 1718 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); 1719 ScDPObject* pNewObj = new ScDPObject( *pDPObj ); 1720 pNewObj->SetSaveData( aData ); 1721 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); 1722 delete pNewObj; 1723 } 1724 else 1725 { 1726 if ( !nErrorId ) 1727 nErrorId = STR_ERR_DATAPILOT_INPUT; 1728 ErrorMessage( nErrorId ); 1729 } 1730 } 1731 1732 void lcl_MoveToEnd( ScDPSaveDimension& rDim, const String& rItemName ) 1733 { 1734 ScDPSaveMember* pNewMember = NULL; 1735 const ScDPSaveMember* pOldMember = rDim.GetExistingMemberByName( rItemName ); 1736 if ( pOldMember ) 1737 pNewMember = new ScDPSaveMember( *pOldMember ); 1738 else 1739 pNewMember = new ScDPSaveMember( rItemName ); 1740 rDim.AddMember( pNewMember ); 1741 // AddMember takes ownership of the new pointer, 1742 // puts it to the end of the list even if it was in the list before. 1743 } 1744 1745 struct ScOUStringCollate 1746 { 1747 CollatorWrapper* mpCollator; 1748 1749 ScOUStringCollate(CollatorWrapper* pColl) : mpCollator(pColl) {} 1750 1751 bool operator()(const rtl::OUString& rStr1, const rtl::OUString& rStr2) const 1752 { 1753 return ( mpCollator->compareString(rStr1, rStr2) < 0 ); 1754 } 1755 }; 1756 1757 bool ScDBFunc::DataPilotSort( const ScAddress& rPos, bool bAscending, sal_uInt16* pUserListId ) 1758 { 1759 ScDocument* pDoc = GetViewData()->GetDocument(); 1760 ScDPObject* pDPObj = pDoc->GetDPAtCursor(rPos.Col(), rPos.Row(), rPos.Tab()); 1761 if (!pDPObj) 1762 return false; 1763 1764 // We need to run this to get all members later. 1765 if ( pUserListId ) 1766 pDPObj->BuildAllDimensionMembers(); 1767 1768 sal_uInt16 nOrientation; 1769 long nDimIndex = pDPObj->GetHeaderDim(rPos, nOrientation); 1770 if (nDimIndex < 0) 1771 // Invalid dimension index. Bail out. 1772 return false; 1773 1774 sal_Bool bDataLayout; 1775 ScDPSaveData* pSaveData = pDPObj->GetSaveData(); 1776 if (!pSaveData) 1777 return false; 1778 1779 ScDPSaveData aNewSaveData(*pSaveData); 1780 String aDimName = pDPObj->GetDimName(nDimIndex, bDataLayout); 1781 ScDPSaveDimension* pSaveDim = aNewSaveData.GetDimensionByName(aDimName); 1782 if (!pSaveDim) 1783 return false; 1784 1785 // manual evaluation of sort order is only needed if a user list id is given 1786 if ( pUserListId ) 1787 { 1788 typedef ScDPSaveDimension::MemberList MemList; 1789 const MemList& rDimMembers = pSaveDim->GetMembers(); 1790 list<OUString> aMembers; 1791 hash_set<OUString, ::rtl::OUStringHash> aMemberSet; 1792 size_t nMemberCount = 0; 1793 for (MemList::const_iterator itr = rDimMembers.begin(), itrEnd = rDimMembers.end(); 1794 itr != itrEnd; ++itr) 1795 { 1796 ScDPSaveMember* pMem = *itr; 1797 aMembers.push_back(pMem->GetName()); 1798 aMemberSet.insert(pMem->GetName()); 1799 ++nMemberCount; 1800 } 1801 1802 // Sort the member list in ascending order. 1803 ScOUStringCollate aCollate( ScGlobal::GetCollator() ); 1804 aMembers.sort(aCollate); 1805 1806 // Collect and rank those custom sort strings that also exist in the member name list. 1807 1808 typedef hash_map<OUString, sal_uInt16, OUStringHash> UserSortMap; 1809 UserSortMap aSubStrs; 1810 sal_uInt16 nSubCount = 0; 1811 if (pUserListId) 1812 { 1813 ScUserList* pUserList = ScGlobal::GetUserList(); 1814 if (!pUserList) 1815 return false; 1816 1817 { 1818 sal_uInt16 n = pUserList->GetCount(); 1819 if (!n || *pUserListId >= n) 1820 return false; 1821 } 1822 1823 ScUserListData* pData = static_cast<ScUserListData*>((*pUserList)[*pUserListId]); 1824 if (pData) 1825 { 1826 sal_uInt16 n = pData->GetSubCount(); 1827 for (sal_uInt16 i = 0; i < n; ++i) 1828 { 1829 OUString aSub = pData->GetSubStr(i); 1830 if (!aMemberSet.count(aSub)) 1831 // This string doesn't exist in the member name set. Don't add this. 1832 continue; 1833 1834 aSubStrs.insert(UserSortMap::value_type(aSub, nSubCount++)); 1835 } 1836 } 1837 } 1838 1839 // Rank all members. 1840 1841 vector<OUString> aRankedNames(nMemberCount); 1842 sal_uInt16 nCurStrId = 0; 1843 for (list<OUString>::const_iterator itr = aMembers.begin(), itrEnd = aMembers.end(); 1844 itr != itrEnd; ++itr) 1845 { 1846 OUString aName = *itr; 1847 sal_uInt16 nRank = 0; 1848 UserSortMap::const_iterator itrSub = aSubStrs.find(aName); 1849 if (itrSub == aSubStrs.end()) 1850 nRank = nSubCount + nCurStrId++; 1851 else 1852 nRank = itrSub->second; 1853 1854 if (!bAscending) 1855 nRank = static_cast< sal_uInt16 >( nMemberCount - nRank - 1 ); 1856 1857 aRankedNames[nRank] = aName; 1858 } 1859 1860 // Re-order ScDPSaveMember instances with the new ranks. 1861 1862 for (vector<OUString>::const_iterator itr = aRankedNames.begin(), itrEnd = aRankedNames.end(); 1863 itr != itrEnd; ++itr) 1864 { 1865 const ScDPSaveMember* pOldMem = pSaveDim->GetExistingMemberByName(*itr); 1866 if (!pOldMem) 1867 // All members are supposed to be present. 1868 continue; 1869 1870 ScDPSaveMember* pNewMem = new ScDPSaveMember(*pOldMem); 1871 pSaveDim->AddMember(pNewMem); 1872 } 1873 1874 // Set the sorting mode to manual for now. We may introduce a new sorting 1875 // mode later on. 1876 1877 sheet::DataPilotFieldSortInfo aSortInfo; 1878 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL; 1879 pSaveDim->SetSortInfo(&aSortInfo); 1880 } 1881 else 1882 { 1883 // without user list id, just apply sorting mode 1884 1885 sheet::DataPilotFieldSortInfo aSortInfo; 1886 aSortInfo.Mode = sheet::DataPilotFieldSortMode::NAME; 1887 aSortInfo.IsAscending = bAscending; 1888 pSaveDim->SetSortInfo(&aSortInfo); 1889 } 1890 1891 // Update the datapilot with the newly sorted field members. 1892 1893 auto_ptr<ScDPObject> pNewObj(new ScDPObject(*pDPObj)); 1894 pNewObj->SetSaveData(aNewSaveData); 1895 ScDBDocFunc aFunc(*GetViewData()->GetDocShell()); 1896 1897 return aFunc.DataPilotUpdate(pDPObj, pNewObj.get(), true, false); 1898 } 1899 1900 sal_Bool ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest ) 1901 { 1902 sal_Bool bRet = sal_False; 1903 ScDocument* pDoc = GetViewData()->GetDocument(); 1904 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rSource.aStart.Col(), rSource.aStart.Row(), rSource.aStart.Tab() ); 1905 if ( pDPObj && pDPObj == pDoc->GetDPAtCursor( rDest.Col(), rDest.Row(), rDest.Tab() ) ) 1906 { 1907 sheet::DataPilotTableHeaderData aDestData; 1908 pDPObj->GetHeaderPositionData( rDest, aDestData ); 1909 bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field 1910 1911 // look through the source range 1912 std::hash_set< rtl::OUString, rtl::OUStringHash, std::equal_to<rtl::OUString> > aMembersSet; // for lookup 1913 std::vector< rtl::OUString > aMembersVector; // members in original order, for inserting 1914 aMembersVector.reserve( std::max( static_cast<SCSIZE>( rSource.aEnd.Col() - rSource.aStart.Col() + 1 ), 1915 static_cast<SCSIZE>( rSource.aEnd.Row() - rSource.aStart.Row() + 1 ) ) ); 1916 for (SCROW nRow = rSource.aStart.Row(); bValid && nRow <= rSource.aEnd.Row(); ++nRow ) 1917 for (SCCOL nCol = rSource.aStart.Col(); bValid && nCol <= rSource.aEnd.Col(); ++nCol ) 1918 { 1919 sheet::DataPilotTableHeaderData aSourceData; 1920 pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, rSource.aStart.Tab() ), aSourceData ); 1921 if ( aSourceData.Dimension == aDestData.Dimension && aSourceData.MemberName.getLength() ) 1922 { 1923 if ( aMembersSet.find( aSourceData.MemberName ) == aMembersSet.end() ) 1924 { 1925 aMembersSet.insert( aSourceData.MemberName ); 1926 aMembersVector.push_back( aSourceData.MemberName ); 1927 } 1928 // duplicates are ignored 1929 } 1930 else 1931 bValid = false; // empty (subtotal) or different field 1932 } 1933 1934 if ( bValid ) 1935 { 1936 sal_Bool bIsDataLayout; 1937 String aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout ); 1938 if ( !bIsDataLayout ) 1939 { 1940 ScDPSaveData aData( *pDPObj->GetSaveData() ); 1941 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName ); 1942 1943 // get all member names in source order 1944 uno::Sequence<rtl::OUString> aMemberNames; 1945 pDPObj->GetMemberNames( aDestData.Dimension, aMemberNames ); 1946 1947 bool bInserted = false; 1948 1949 sal_Int32 nMemberCount = aMemberNames.getLength(); 1950 for (sal_Int32 nMemberPos=0; nMemberPos<nMemberCount; ++nMemberPos) 1951 { 1952 String aMemberStr( aMemberNames[nMemberPos] ); 1953 1954 if ( !bInserted && aMemberNames[nMemberPos] == aDestData.MemberName ) 1955 { 1956 // insert dragged items before this item 1957 for ( std::vector<rtl::OUString>::const_iterator aIter = aMembersVector.begin(); 1958 aIter != aMembersVector.end(); ++aIter ) 1959 lcl_MoveToEnd( *pDim, *aIter ); 1960 bInserted = true; 1961 } 1962 1963 if ( aMembersSet.find( aMemberStr ) == aMembersSet.end() ) // skip dragged items 1964 lcl_MoveToEnd( *pDim, aMemberStr ); 1965 } 1966 // insert dragged item at end if dest wasn't found (for example, empty) 1967 if ( !bInserted ) 1968 for ( std::vector<rtl::OUString>::const_iterator aIter = aMembersVector.begin(); 1969 aIter != aMembersVector.end(); ++aIter ) 1970 lcl_MoveToEnd( *pDim, *aIter ); 1971 1972 // Items that were in SaveData, but not in the source, end up at the start of the list. 1973 1974 // set flag for manual sorting 1975 sheet::DataPilotFieldSortInfo aSortInfo; 1976 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL; 1977 pDim->SetSortInfo( &aSortInfo ); 1978 1979 // apply changes 1980 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); 1981 ScDPObject* pNewObj = new ScDPObject( *pDPObj ); 1982 pNewObj->SetSaveData( aData ); 1983 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); //! bApi for drag&drop? 1984 delete pNewObj; 1985 1986 Unmark(); // entry was moved - no use in leaving the old cell selected 1987 1988 bRet = sal_True; 1989 } 1990 } 1991 } 1992 1993 return bRet; 1994 } 1995 1996 sal_Bool ScDBFunc::HasSelectionForDrillDown( sal_uInt16& rOrientation ) 1997 { 1998 sal_Bool bRet = sal_False; 1999 2000 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(), 2001 GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); 2002 if ( pDPObj ) 2003 { 2004 ScStrCollection aEntries; 2005 long nSelectDimension = -1; 2006 GetSelectedMemberList( aEntries, nSelectDimension ); 2007 2008 if ( aEntries.GetCount() > 0 ) 2009 { 2010 sal_Bool bIsDataLayout; 2011 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 2012 if ( !bIsDataLayout ) 2013 { 2014 ScDPSaveData* pSaveData = pDPObj->GetSaveData(); 2015 ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName( aDimName ); 2016 if ( pDim ) 2017 { 2018 sal_uInt16 nDimOrient = pDim->GetOrientation(); 2019 ScDPSaveDimension* pInner = pSaveData->GetInnermostDimension( nDimOrient ); 2020 if ( pDim == pInner ) 2021 { 2022 rOrientation = nDimOrient; 2023 bRet = sal_True; 2024 } 2025 } 2026 } 2027 } 2028 } 2029 2030 return bRet; 2031 } 2032 2033 void ScDBFunc::SetDataPilotDetails( sal_Bool bShow, const String* pNewDimensionName ) 2034 { 2035 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(), 2036 GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); 2037 if ( pDPObj ) 2038 { 2039 ScStrCollection aEntries; 2040 long nSelectDimension = -1; 2041 GetSelectedMemberList( aEntries, nSelectDimension ); 2042 2043 if ( aEntries.GetCount() > 0 ) 2044 { 2045 sal_Bool bIsDataLayout; 2046 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout ); 2047 if ( !bIsDataLayout ) 2048 { 2049 ScDPSaveData aData( *pDPObj->GetSaveData() ); 2050 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName ); 2051 2052 if ( bShow && pNewDimensionName ) 2053 { 2054 // add the new dimension with the same orientation, at the end 2055 2056 ScDPSaveDimension* pNewDim = aData.GetDimensionByName( *pNewDimensionName ); 2057 ScDPSaveDimension* pDuplicated = NULL; 2058 if ( pNewDim->GetOrientation() == sheet::DataPilotFieldOrientation_DATA ) 2059 { 2060 // Need to duplicate the dimension, create column/row in addition to data: 2061 // The duplicated dimension inherits the existing settings, pNewDim is modified below. 2062 pDuplicated = aData.DuplicateDimension( *pNewDimensionName ); 2063 } 2064 2065 sal_uInt16 nOrientation = pDim->GetOrientation(); 2066 pNewDim->SetOrientation( nOrientation ); 2067 2068 long nPosition = LONG_MAX; 2069 aData.SetPosition( pNewDim, nPosition ); 2070 2071 ScDPSaveDimension* pDataLayout = aData.GetDataLayoutDimension(); 2072 if ( pDataLayout->GetOrientation() == nOrientation && 2073 aData.GetDataDimensionCount() <= 1 ) 2074 { 2075 // If there is only one data dimension, the data layout dimension 2076 // must still be the last one in its orientation. 2077 aData.SetPosition( pDataLayout, nPosition ); 2078 } 2079 2080 if ( pDuplicated ) 2081 { 2082 // The duplicated (data) dimension needs to be behind the original dimension 2083 aData.SetPosition( pDuplicated, nPosition ); 2084 } 2085 2086 // Hide details for all visible members (selected are changed below). 2087 //! Use all members from source level instead (including non-visible)? 2088 2089 ScStrCollection aVisibleEntries; 2090 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension ); 2091 2092 sal_uInt16 nVisCount = aVisibleEntries.GetCount(); 2093 for (sal_uInt16 nVisPos=0; nVisPos<nVisCount; nVisPos++) 2094 { 2095 String aVisName = aVisibleEntries[nVisPos]->GetString(); 2096 ScDPSaveMember* pMember = pDim->GetMemberByName( aVisName ); 2097 pMember->SetShowDetails( sal_False ); 2098 } 2099 } 2100 2101 sal_uInt16 nEntryCount = aEntries.GetCount(); 2102 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++) 2103 { 2104 String aEntryName = aEntries[nEntry]->GetString(); 2105 ScDPSaveMember* pMember = pDim->GetMemberByName( aEntryName ); 2106 pMember->SetShowDetails( bShow ); 2107 } 2108 2109 // apply changes 2110 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); 2111 ScDPObject* pNewObj = new ScDPObject( *pDPObj ); 2112 pNewObj->SetSaveData( aData ); 2113 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); 2114 delete pNewObj; 2115 2116 // unmark cell selection 2117 Unmark(); 2118 } 2119 } 2120 } 2121 } 2122 2123 void ScDBFunc::ShowDataPilotSourceData( ScDPObject& rDPObj, const Sequence<sheet::DataPilotFieldFilter>& rFilters ) 2124 { 2125 ScDocument* pDoc = GetViewData()->GetDocument(); 2126 if (pDoc->GetDocumentShell()->IsReadOnly()) 2127 { 2128 ErrorMessage(STR_READONLYERR); 2129 return; 2130 } 2131 2132 Reference<sheet::XDimensionsSupplier> xDimSupplier = rDPObj.GetSource(); 2133 Reference<container::XNameAccess> xDims = xDimSupplier->getDimensions(); 2134 Reference<sheet::XDrillDownDataSupplier> xDDSupplier(xDimSupplier, UNO_QUERY); 2135 if (!xDDSupplier.is()) 2136 return; 2137 2138 Sequence< Sequence<Any> > aTabData = xDDSupplier->getDrillDownData(rFilters); 2139 sal_Int32 nRowSize = aTabData.getLength(); 2140 if (nRowSize <= 1) 2141 // There is no data to show. Bail out. 2142 return; 2143 2144 sal_Int32 nColSize = aTabData[0].getLength(); 2145 2146 SCTAB nNewTab = GetViewData()->GetTabNo(); 2147 2148 auto_ptr<ScDocument> pInsDoc(new ScDocument(SCDOCMODE_CLIP)); 2149 pInsDoc->ResetClip( pDoc, nNewTab ); 2150 for (SCROW nRow = 0; nRow < nRowSize; ++nRow) 2151 { 2152 for (SCCOL nCol = 0; nCol < nColSize; ++nCol) 2153 { 2154 const Any& rAny = aTabData[nRow][nCol]; 2155 rtl::OUString aStr; 2156 double fVal; 2157 if (rAny >>= aStr) 2158 pInsDoc->PutCell( ScAddress(nCol, nRow, nNewTab), new ScStringCell(String(aStr)) ); 2159 else if (rAny >>= fVal) 2160 pInsDoc->SetValue(nCol, nRow, nNewTab, fVal); 2161 } 2162 } 2163 2164 // set number format (important for dates) 2165 for (SCCOL nCol = 0; nCol < nColSize; ++nCol) 2166 { 2167 rtl::OUString aStr; 2168 if (!(aTabData[0][nCol] >>= aStr)) 2169 continue; 2170 2171 Reference<XPropertySet> xPropSet(xDims->getByName(aStr), UNO_QUERY); 2172 if (!xPropSet.is()) 2173 continue; 2174 2175 Any any = xPropSet->getPropertyValue( rtl::OUString::createFromAscii(SC_UNO_NUMBERFO) ); 2176 sal_Int32 nNumFmt = 0; 2177 if (!(any >>= nNumFmt)) 2178 continue; 2179 2180 ScPatternAttr aPattern( pInsDoc->GetPool() ); 2181 aPattern.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT, static_cast<sal_uInt32>(nNumFmt)) ); 2182 pInsDoc->ApplyPatternAreaTab(nCol, 1, nCol, nRowSize-1, nNewTab, aPattern); 2183 } 2184 2185 SCCOL nEndCol = 0; 2186 SCROW nEndRow = 0; 2187 pInsDoc->GetCellArea( nNewTab, nEndCol, nEndRow ); 2188 pInsDoc->SetClipArea( ScRange( 0, 0, nNewTab, nEndCol, nEndRow, nNewTab ) ); 2189 2190 ::svl::IUndoManager* pMgr = GetViewData()->GetDocShell()->GetUndoManager(); 2191 String aUndo = ScGlobal::GetRscString( STR_UNDO_DOOUTLINE ); 2192 pMgr->EnterListAction( aUndo, aUndo ); 2193 2194 String aNewTabName; 2195 pDoc->CreateValidTabName(aNewTabName); 2196 if ( InsertTable(aNewTabName, nNewTab) ) 2197 PasteFromClip( IDF_ALL, pInsDoc.get() ); 2198 2199 pMgr->LeaveListAction(); 2200 } 2201 2202 // 2203 // DB-Operationen (Sortieren, Filtern, Teilergebnisse) wiederholen 2204 // 2205 2206 void ScDBFunc::RepeatDB( sal_Bool bRecord ) 2207 { 2208 SCCOL nCurX = GetViewData()->GetCurX(); 2209 SCROW nCurY = GetViewData()->GetCurY(); 2210 SCTAB nTab = GetViewData()->GetTabNo(); 2211 ScDocument* pDoc = GetViewData()->GetDocument(); 2212 ScDBData* pDBData = GetDBData(); 2213 if (bRecord && !pDoc->IsUndoEnabled()) 2214 bRecord = sal_False; 2215 2216 ScQueryParam aQueryParam; 2217 pDBData->GetQueryParam( aQueryParam ); 2218 sal_Bool bQuery = aQueryParam.GetEntry(0).bDoQuery; 2219 2220 ScSortParam aSortParam; 2221 pDBData->GetSortParam( aSortParam ); 2222 sal_Bool bSort = aSortParam.bDoSort[0]; 2223 2224 ScSubTotalParam aSubTotalParam; 2225 pDBData->GetSubTotalParam( aSubTotalParam ); 2226 sal_Bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly; 2227 2228 if ( bQuery || bSort || bSubTotal ) 2229 { 2230 sal_Bool bQuerySize = sal_False; 2231 ScRange aOldQuery; 2232 ScRange aNewQuery; 2233 if (bQuery && !aQueryParam.bInplace) 2234 { 2235 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow, 2236 aQueryParam.nDestTab, sal_True ); 2237 if (pDest && pDest->IsDoSize()) 2238 { 2239 pDest->GetArea( aOldQuery ); 2240 bQuerySize = sal_True; 2241 } 2242 } 2243 2244 SCTAB nDummy; 2245 SCCOL nStartCol; 2246 SCROW nStartRow; 2247 SCCOL nEndCol; 2248 SCROW nEndRow; 2249 pDBData->GetArea( nDummy, nStartCol, nStartRow, nEndCol, nEndRow ); 2250 2251 //! Undo nur benoetigte Daten ? 2252 2253 ScDocument* pUndoDoc = NULL; 2254 ScOutlineTable* pUndoTab = NULL; 2255 ScRangeName* pUndoRange = NULL; 2256 ScDBCollection* pUndoDB = NULL; 2257 2258 if (bRecord) 2259 { 2260 SCTAB nTabCount = pDoc->GetTableCount(); 2261 pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); 2262 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); 2263 if (pTable) 2264 { 2265 pUndoTab = new ScOutlineTable( *pTable ); 2266 2267 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus 2268 SCCOLROW nOutStartRow; 2269 SCCOLROW nOutEndCol; 2270 SCCOLROW nOutEndRow; 2271 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol ); 2272 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow ); 2273 2274 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True ); 2275 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, sal_False, pUndoDoc ); 2276 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, sal_False, pUndoDoc ); 2277 } 2278 else 2279 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_False, sal_True ); 2280 2281 // Datenbereich sichern - incl. Filter-Ergebnis 2282 pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, sal_False, pUndoDoc ); 2283 2284 // alle Formeln wegen Referenzen 2285 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, sal_False, pUndoDoc ); 2286 2287 // DB- und andere Bereiche 2288 ScRangeName* pDocRange = pDoc->GetRangeName(); 2289 if (pDocRange->GetCount()) 2290 pUndoRange = new ScRangeName( *pDocRange ); 2291 ScDBCollection* pDocDB = pDoc->GetDBCollection(); 2292 if (pDocDB->GetCount()) 2293 pUndoDB = new ScDBCollection( *pDocDB ); 2294 } 2295 2296 if (bSort && bSubTotal) 2297 { 2298 // Sortieren ohne SubTotals 2299 2300 aSubTotalParam.bRemoveOnly = sal_True; // wird unten wieder zurueckgesetzt 2301 DoSubTotals( aSubTotalParam, sal_False ); 2302 } 2303 2304 if (bSort) 2305 { 2306 pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben 2307 Sort( aSortParam, sal_False, sal_False); 2308 } 2309 if (bQuery) 2310 { 2311 pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben 2312 ScRange aAdvSource; 2313 if (pDBData->GetAdvancedQuerySource(aAdvSource)) 2314 { 2315 pDoc->CreateQueryParam( 2316 aAdvSource.aStart.Col(), aAdvSource.aStart.Row(), 2317 aAdvSource.aEnd.Col(), aAdvSource.aEnd.Row(), 2318 aAdvSource.aStart.Tab(), aQueryParam ); 2319 Query( aQueryParam, &aAdvSource, sal_False ); 2320 } 2321 else 2322 Query( aQueryParam, NULL, sal_False ); 2323 2324 // bei nicht-inplace kann die Tabelle umgestellt worden sein 2325 if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab ) 2326 SetTabNo( nTab ); 2327 } 2328 if (bSubTotal) 2329 { 2330 pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben 2331 aSubTotalParam.bRemoveOnly = sal_False; 2332 DoSubTotals( aSubTotalParam, sal_False ); 2333 } 2334 2335 if (bRecord) 2336 { 2337 SCTAB nDummyTab; 2338 SCCOL nDummyCol; 2339 SCROW nDummyRow, nNewEndRow; 2340 pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow ); 2341 2342 const ScRange* pOld = NULL; 2343 const ScRange* pNew = NULL; 2344 if (bQuerySize) 2345 { 2346 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow, 2347 aQueryParam.nDestTab, sal_True ); 2348 if (pDest) 2349 { 2350 pDest->GetArea( aNewQuery ); 2351 pOld = &aOldQuery; 2352 pNew = &aNewQuery; 2353 } 2354 } 2355 2356 GetViewData()->GetDocShell()->GetUndoManager()->AddUndoAction( 2357 new ScUndoRepeatDB( GetViewData()->GetDocShell(), nTab, 2358 nStartCol, nStartRow, nEndCol, nEndRow, 2359 nNewEndRow, 2360 nCurX, nCurY, 2361 pUndoDoc, pUndoTab, 2362 pUndoRange, pUndoDB, 2363 pOld, pNew ) ); 2364 } 2365 2366 GetViewData()->GetDocShell()->PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, 2367 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE ); 2368 } 2369 else // "Keine Operationen auszufuehren" 2370 ErrorMessage(STR_MSSG_REPEATDB_0); 2371 } 2372 2373 2374 2375 2376