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