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 "scitems.hxx" 36 #include <vcl/msgbox.hxx> 37 #include <vcl/sound.hxx> 38 39 #include "gridwin.hxx" 40 #include "tabvwsh.hxx" 41 #include "docsh.hxx" 42 #include "viewdata.hxx" 43 #include "pivot.hxx" 44 //CHINA001 #include "pfiltdlg.hxx" 45 #include "uiitems.hxx" 46 #include "scresid.hxx" 47 #include "sc.hrc" 48 #include "globstr.hrc" 49 #include "pagedata.hxx" 50 #include "dpobject.hxx" 51 #include "dpsave.hxx" 52 #include "dpoutput.hxx" // ScDPPositionData 53 #include "dpshttab.hxx" 54 #include "dbdocfun.hxx" 55 #include "dpcontrol.hxx" 56 #include "dpcontrol.hrc" 57 #include "strload.hxx" 58 #include "userlist.hxx" 59 60 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> 61 #include "scabstdlg.hxx" //CHINA001 62 63 #include <vector> 64 #include <hash_map> 65 66 using namespace com::sun::star; 67 using ::com::sun::star::sheet::DataPilotFieldOrientation; 68 using ::std::vector; 69 using ::std::auto_ptr; 70 using ::std::hash_map; 71 using ::rtl::OUString; 72 using ::rtl::OUStringHash; 73 74 // STATIC DATA ----------------------------------------------------------- 75 76 // ----------------------------------------------------------------------- 77 78 DataPilotFieldOrientation ScGridWindow::GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const 79 { 80 using namespace ::com::sun::star::sheet; 81 82 ScDocument* pDoc = pViewData->GetDocument(); 83 SCTAB nTab = pViewData->GetTabNo(); 84 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab); 85 if (!pDPObj) 86 return DataPilotFieldOrientation_HIDDEN; 87 88 sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN; 89 90 // Check for page field first. 91 if (nCol > 0) 92 { 93 // look for the dimension header left of the drop-down arrow 94 long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient ); 95 if ( nField >= 0 && nOrient == DataPilotFieldOrientation_PAGE ) 96 { 97 sal_Bool bIsDataLayout = sal_False; 98 String aFieldName = pDPObj->GetDimName( nField, bIsDataLayout ); 99 if ( aFieldName.Len() && !bIsDataLayout ) 100 return DataPilotFieldOrientation_PAGE; 101 } 102 } 103 104 nOrient = sheet::DataPilotFieldOrientation_HIDDEN; 105 106 // Now, check for row/column field. 107 long nField = pDPObj->GetHeaderDim(ScAddress(nCol, nRow, nTab), nOrient); 108 if (nField >= 0 && (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) ) 109 { 110 sal_Bool bIsDataLayout = sal_False; 111 String aFieldName = pDPObj->GetDimName(nField, bIsDataLayout); 112 if (aFieldName.Len() && !bIsDataLayout) 113 return static_cast<DataPilotFieldOrientation>(nOrient); 114 } 115 116 return DataPilotFieldOrientation_HIDDEN; 117 } 118 119 // private method for mouse button handling 120 sal_Bool ScGridWindow::DoPageFieldSelection( SCCOL nCol, SCROW nRow ) 121 { 122 if (GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE) 123 { 124 LaunchPageFieldMenu( nCol, nRow ); 125 return sal_True; 126 } 127 return sal_False; 128 } 129 130 bool ScGridWindow::DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt ) 131 { 132 ScDocument* pDoc = pViewData->GetDocument(); 133 SCTAB nTab = pViewData->GetTabNo(); 134 Point aScrPos = pViewData->GetScrPos(nCol, nRow, eWhich); 135 Point aDiffPix = rMEvt.GetPosPixel(); 136 137 aDiffPix -= aScrPos; 138 sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); 139 if ( bLayoutRTL ) 140 aDiffPix.X() = -aDiffPix.X(); 141 142 long nSizeX, nSizeY; 143 pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); 144 Size aScrSize(nSizeX-1, nSizeY-1); 145 146 // Check if the mouse cursor is clicking on the popup arrow box. 147 mpFilterButton.reset(new ScDPFieldButton(this, &GetSettings().GetStyleSettings(), &pViewData->GetZoomX(), &pViewData->GetZoomY(), pDoc)); 148 mpFilterButton->setBoundingBox(aScrPos, aScrSize, bLayoutRTL); 149 mpFilterButton->setPopupLeft(bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL 150 Point aPopupPos; 151 Size aPopupSize; 152 mpFilterButton->getPopupBoundingBox(aPopupPos, aPopupSize); 153 Rectangle aRec(aPopupPos, aPopupSize); 154 if (aRec.IsInside(rMEvt.GetPosPixel())) 155 { 156 if ( DoPageFieldSelection( nCol, nRow ) ) 157 return true; 158 159 bool bFilterActive = IsAutoFilterActive(nCol, nRow, nTab); 160 mpFilterButton->setHasHiddenMember(bFilterActive); 161 mpFilterButton->setDrawBaseButton(false); 162 mpFilterButton->setDrawPopupButton(true); 163 mpFilterButton->setPopupPressed(true); 164 HideCursor(); 165 mpFilterButton->draw(); 166 ShowCursor(); 167 DoAutoFilterMenue(nCol, nRow, false); 168 return true; 169 } 170 171 return false; 172 } 173 174 void ScGridWindow::DoPushButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt ) 175 { 176 ScDocument* pDoc = pViewData->GetDocument(); 177 SCTAB nTab = pViewData->GetTabNo(); 178 179 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab); 180 181 if (pDPObj) 182 { 183 sal_uInt16 nOrient = sheet::DataPilotFieldOrientation_HIDDEN; 184 ScAddress aPos( nCol, nRow, nTab ); 185 long nField = pDPObj->GetHeaderDim( aPos, nOrient ); 186 if ( nField >= 0 ) 187 { 188 bDPMouse = sal_True; 189 nDPField = nField; 190 pDragDPObj = pDPObj; 191 192 if (DPTestFieldPopupArrow(rMEvt, aPos, pDPObj)) 193 { 194 // field name pop up menu has been launched. Don't activate 195 // field move. 196 bDPMouse = false; 197 return; 198 } 199 200 DPTestMouse( rMEvt, sal_True ); 201 StartTracking(); 202 } 203 else if ( pDPObj->IsFilterButton(aPos) ) 204 { 205 ReleaseMouse(); // may have been captured in ButtonDown 206 207 ScQueryParam aQueryParam; 208 SCTAB nSrcTab = 0; 209 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc(); 210 DBG_ASSERT(pDesc, "no sheet source for filter button"); 211 if (pDesc) 212 { 213 aQueryParam = pDesc->aQueryParam; 214 nSrcTab = pDesc->aSourceRange.aStart.Tab(); 215 } 216 217 SfxItemSet aArgSet( pViewData->GetViewShell()->GetPool(), 218 SCITEM_QUERYDATA, SCITEM_QUERYDATA ); 219 aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA, pViewData, &aQueryParam ) ); 220 221 //CHINA001 ScPivotFilterDlg* pDlg = new ScPivotFilterDlg( 222 //CHINA001 pViewData->GetViewShell()->GetDialogParent(), 223 //CHINA001 aArgSet, nSrcTab ); 224 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); 225 DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 226 227 AbstractScPivotFilterDlg* pDlg = pFact->CreateScPivotFilterDlg( pViewData->GetViewShell()->GetDialogParent(), 228 aArgSet, nSrcTab, 229 RID_SCDLG_PIVOTFILTER); 230 DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001 231 if ( pDlg->Execute() == RET_OK ) 232 { 233 ScSheetSourceDesc aNewDesc; 234 if (pDesc) 235 aNewDesc = *pDesc; 236 237 const ScQueryItem& rQueryItem = pDlg->GetOutputItem(); 238 aNewDesc.aQueryParam = rQueryItem.GetQueryData(); 239 240 ScDPObject aNewObj( *pDPObj ); 241 aNewObj.SetSheetDesc( aNewDesc ); 242 ScDBDocFunc aFunc( *pViewData->GetDocShell() ); 243 aFunc.DataPilotUpdate( pDPObj, &aNewObj, sal_True, sal_False ); 244 pViewData->GetView()->CursorPosChanged(); // shells may be switched 245 } 246 delete pDlg; 247 } 248 else 249 Sound::Beep(); 250 } 251 else 252 { 253 DBG_ERROR("Da is ja garnix"); 254 } 255 } 256 257 // ----------------------------------------------------------------------- 258 // 259 // Data Pilot interaction 260 // 261 262 void ScGridWindow::DPTestMouse( const MouseEvent& rMEvt, sal_Bool bMove ) 263 { 264 DBG_ASSERT(pDragDPObj, "pDragDPObj missing"); 265 266 // scroll window if at edges 267 //! move this to separate method 268 269 sal_Bool bTimer = sal_False; 270 Point aPixel = rMEvt.GetPosPixel(); 271 272 SCsCOL nDx = 0; 273 SCsROW nDy = 0; 274 if ( aPixel.X() < 0 ) 275 nDx = -1; 276 if ( aPixel.Y() < 0 ) 277 nDy = -1; 278 Size aSize = GetOutputSizePixel(); 279 if ( aPixel.X() >= aSize.Width() ) 280 nDx = 1; 281 if ( aPixel.Y() >= aSize.Height() ) 282 nDy = 1; 283 if ( nDx != 0 || nDy != 0 ) 284 { 285 UpdateDragRect( sal_False, Rectangle() ); 286 287 if ( nDx != 0) 288 pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) ); 289 if ( nDy != 0 ) 290 pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) ); 291 292 bTimer = sal_True; 293 } 294 295 // --- 296 297 SCsCOL nPosX; 298 SCsROW nPosY; 299 pViewData->GetPosFromPixel( aPixel.X(), aPixel.Y(), eWhich, nPosX, nPosY ); 300 sal_Bool bMouseLeft; 301 sal_Bool bMouseTop; 302 pViewData->GetMouseQuadrant( aPixel, eWhich, nPosX, nPosY, bMouseLeft, bMouseTop ); 303 304 ScAddress aPos( nPosX, nPosY, pViewData->GetTabNo() ); 305 306 Rectangle aPosRect; 307 sal_uInt16 nOrient; 308 long nDimPos; 309 sal_Bool bHasRange = pDragDPObj->GetHeaderDrag( aPos, bMouseLeft, bMouseTop, nDPField, 310 aPosRect, nOrient, nDimPos ); 311 UpdateDragRect( bHasRange && bMove, aPosRect ); 312 313 sal_Bool bIsDataLayout; 314 sal_Int32 nDimFlags = 0; 315 String aDimName = pDragDPObj->GetDimName( nDPField, bIsDataLayout, &nDimFlags ); 316 bool bAllowed = !bHasRange || ScDPObject::IsOrientationAllowed( nOrient, nDimFlags ); 317 318 if (bMove) // set mouse pointer 319 { 320 PointerStyle ePointer = POINTER_PIVOT_DELETE; 321 if ( !bAllowed ) 322 ePointer = POINTER_NOTALLOWED; 323 else if ( bHasRange ) 324 switch (nOrient) 325 { 326 case sheet::DataPilotFieldOrientation_COLUMN: ePointer = POINTER_PIVOT_COL; break; 327 case sheet::DataPilotFieldOrientation_ROW: ePointer = POINTER_PIVOT_ROW; break; 328 case sheet::DataPilotFieldOrientation_PAGE: 329 case sheet::DataPilotFieldOrientation_DATA: ePointer = POINTER_PIVOT_FIELD; break; 330 } 331 SetPointer( ePointer ); 332 } 333 else // execute change 334 { 335 if (!bHasRange) 336 nOrient = sheet::DataPilotFieldOrientation_HIDDEN; 337 338 if ( bIsDataLayout && ( nOrient != sheet::DataPilotFieldOrientation_COLUMN && 339 nOrient != sheet::DataPilotFieldOrientation_ROW ) ) 340 { 341 // removing data layout is not allowed 342 pViewData->GetView()->ErrorMessage(STR_PIVOT_MOVENOTALLOWED); 343 } 344 else if ( bAllowed ) 345 { 346 ScDPSaveData aSaveData( *pDragDPObj->GetSaveData() ); 347 348 ScDPSaveDimension* pDim; 349 if ( bIsDataLayout ) 350 pDim = aSaveData.GetDataLayoutDimension(); 351 else 352 pDim = aSaveData.GetDimensionByName(aDimName); 353 pDim->SetOrientation( nOrient ); 354 aSaveData.SetPosition( pDim, nDimPos ); 355 356 //! docfunc method with ScDPSaveData as argument? 357 358 ScDPObject aNewObj( *pDragDPObj ); 359 aNewObj.SetSaveData( aSaveData ); 360 ScDBDocFunc aFunc( *pViewData->GetDocShell() ); 361 // when dragging fields, allow re-positioning (bAllowMove) 362 aFunc.DataPilotUpdate( pDragDPObj, &aNewObj, sal_True, sal_False, sal_True ); 363 pViewData->GetView()->CursorPosChanged(); // shells may be switched 364 } 365 } 366 367 if (bTimer && bMove) 368 pViewData->GetView()->SetTimer( this, rMEvt ); // repeat event 369 else 370 pViewData->GetView()->ResetTimer(); 371 } 372 373 bool ScGridWindow::DPTestFieldPopupArrow(const MouseEvent& rMEvt, const ScAddress& rPos, ScDPObject* pDPObj) 374 { 375 sal_Bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() ); 376 377 // Get the geometry of the cell. 378 Point aScrPos = pViewData->GetScrPos(rPos.Col(), rPos.Row(), eWhich); 379 long nSizeX, nSizeY; 380 pViewData->GetMergeSizePixel(rPos.Col(), rPos.Row(), nSizeX, nSizeY); 381 Size aScrSize(nSizeX-1, nSizeY-1); 382 383 // Check if the mouse cursor is clicking on the popup arrow box. 384 ScDPFieldButton aBtn(this, &GetSettings().GetStyleSettings()); 385 aBtn.setBoundingBox(aScrPos, aScrSize, bLayoutRTL); 386 aBtn.setPopupLeft(false); // DataPilot popup is always right-aligned for now 387 Point aPopupPos; 388 Size aPopupSize; 389 aBtn.getPopupBoundingBox(aPopupPos, aPopupSize); 390 Rectangle aRec(aPopupPos, aPopupSize); 391 if (aRec.IsInside(rMEvt.GetPosPixel())) 392 { 393 // Mouse cursor inside the popup arrow box. Launch the field menu. 394 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, rPos, pDPObj); 395 return true; 396 } 397 398 return false; 399 } 400 401 namespace { 402 403 struct DPFieldPopupData : public ScDPFieldPopupWindow::ExtendedData 404 { 405 ScPivotParam maDPParam; 406 ScDPObject* mpDPObj; 407 long mnDim; 408 }; 409 410 class DPFieldPopupOKAction : public ScMenuFloatingWindow::Action 411 { 412 public: 413 explicit DPFieldPopupOKAction(ScGridWindow* p) : 414 mpGridWindow(p) {} 415 416 virtual void execute() 417 { 418 mpGridWindow->UpdateDPFromFieldPopupMenu(); 419 } 420 private: 421 ScGridWindow* mpGridWindow; 422 }; 423 424 class PopupSortAction : public ScMenuFloatingWindow::Action 425 { 426 public: 427 enum SortType { ASCENDING, DESCENDING, CUSTOM }; 428 429 explicit PopupSortAction(const ScAddress& rPos, SortType eType, sal_uInt16 nUserListIndex, ScTabViewShell* pViewShell) : 430 maPos(rPos), meType(eType), mnUserListIndex(nUserListIndex), mpViewShell(pViewShell) {} 431 432 virtual void execute() 433 { 434 switch (meType) 435 { 436 case ASCENDING: 437 mpViewShell->DataPilotSort(maPos, true); 438 break; 439 case DESCENDING: 440 mpViewShell->DataPilotSort(maPos, false); 441 break; 442 case CUSTOM: 443 mpViewShell->DataPilotSort(maPos, true, &mnUserListIndex); 444 break; 445 default: 446 ; 447 } 448 } 449 450 private: 451 ScAddress maPos; 452 SortType meType; 453 sal_uInt16 mnUserListIndex; 454 ScTabViewShell* mpViewShell; 455 }; 456 457 } 458 459 bool lcl_GetLabelIndex( size_t& rLabelIndex, long nDimension, const ScDPLabelDataVector& rLabelArray ) 460 { 461 size_t n = rLabelArray.size(); 462 for (size_t i = 0; i < n; ++i) 463 if (static_cast<long>(rLabelArray[i].mnCol) == nDimension) 464 { 465 rLabelIndex = i; 466 return true; 467 } 468 return false; 469 } 470 471 void ScGridWindow::DPLaunchFieldPopupMenu( 472 const Point& rScrPos, const Size& rScrSize, const ScAddress& rPos, ScDPObject* pDPObj) 473 { 474 // We need to get the list of field members. 475 auto_ptr<DPFieldPopupData> pDPData(new DPFieldPopupData); 476 pDPObj->FillLabelData(pDPData->maDPParam); 477 pDPData->mpDPObj = pDPObj; 478 479 sal_uInt16 nOrient; 480 pDPData->mnDim = pDPObj->GetHeaderDim(rPos, nOrient); 481 482 // #i116457# FillLabelData skips empty column names, so mnDim can't be used directly as index into maLabelArray. 483 size_t nLabelIndex = 0; 484 if (!lcl_GetLabelIndex( nLabelIndex, pDPData->mnDim, pDPData->maDPParam.maLabelArray )) 485 return; 486 487 const ScDPLabelData& rLabelData = pDPData->maDPParam.maLabelArray[nLabelIndex]; 488 489 mpDPFieldPopup.reset(new ScDPFieldPopupWindow(this, pViewData->GetDocument())); 490 mpDPFieldPopup->setName(OUString::createFromAscii("Pivot table field member popup")); 491 mpDPFieldPopup->setExtendedData(pDPData.release()); 492 mpDPFieldPopup->setOKAction(new DPFieldPopupOKAction(this)); 493 { 494 // Populate field members. 495 size_t n = rLabelData.maMembers.size(); 496 mpDPFieldPopup->setMemberSize(n); 497 for (size_t i = 0; i < n; ++i) 498 { 499 const ScDPLabelData::Member& rMem = rLabelData.maMembers[i]; 500 mpDPFieldPopup->addMember(rMem.getDisplayName(), rMem.mbVisible); 501 } 502 mpDPFieldPopup->initMembers(); 503 } 504 505 vector<OUString> aUserSortNames; 506 ScUserList* pUserList = ScGlobal::GetUserList(); 507 if (pUserList) 508 { 509 sal_uInt16 n = pUserList->GetCount(); 510 aUserSortNames.reserve(n); 511 for (sal_uInt16 i = 0; i < n; ++i) 512 { 513 ScUserListData* pData = static_cast<ScUserListData*>((*pUserList)[i]); 514 aUserSortNames.push_back(pData->GetString()); 515 } 516 } 517 518 // Populate the menus. 519 ScTabViewShell* pViewShell = pViewData->GetViewShell(); 520 mpDPFieldPopup->addMenuItem( 521 ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_ASC).GetString(), true, 522 new PopupSortAction(rPos, PopupSortAction::ASCENDING, 0, pViewShell)); 523 mpDPFieldPopup->addMenuItem( 524 ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_DESC).GetString(), true, 525 new PopupSortAction(rPos, PopupSortAction::DESCENDING, 0, pViewShell)); 526 ScMenuFloatingWindow* pSubMenu = mpDPFieldPopup->addSubMenuItem( 527 ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_CUSTOM).GetString(), !aUserSortNames.empty()); 528 529 if (pSubMenu && !aUserSortNames.empty()) 530 { 531 size_t n = aUserSortNames.size(); 532 for (size_t i = 0; i < n; ++i) 533 { 534 pSubMenu->addMenuItem( 535 aUserSortNames[i], true, 536 new PopupSortAction(rPos, PopupSortAction::CUSTOM, static_cast<sal_uInt16>(i), pViewShell)); 537 } 538 } 539 540 sal_Bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() ); 541 542 Rectangle aCellRect(rScrPos, rScrSize); 543 const Size& rPopupSize = mpDPFieldPopup->getWindowSize(); 544 if (bLayoutRTL) 545 { 546 // RTL: rScrPos is logical-left (visual right) position, always right-align with that 547 aCellRect.SetPos(Point(rScrPos.X() - rPopupSize.Width() + 1, rScrPos.Y())); 548 } 549 else if (rScrSize.getWidth() > rPopupSize.getWidth()) 550 { 551 // If the cell width is larger than the popup window width, launch it 552 // right-aligned with the cell. 553 long nXOffset = rScrSize.getWidth() - rPopupSize.getWidth(); 554 aCellRect.SetPos(Point(rScrPos.X() + nXOffset, rScrPos.Y())); 555 } 556 mpDPFieldPopup->SetPopupModeEndHdl( LINK(this, ScGridWindow, PopupModeEndHdl) ); 557 mpDPFieldPopup->StartPopupMode(aCellRect, (FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_GRABFOCUS)); 558 } 559 560 void ScGridWindow::UpdateDPFromFieldPopupMenu() 561 { 562 typedef hash_map<OUString, OUString, OUStringHash> MemNameMapType; 563 typedef hash_map<OUString, bool, OUStringHash> MemVisibilityType; 564 565 if (!mpDPFieldPopup.get()) 566 return; 567 568 DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(mpDPFieldPopup->getExtendedData()); 569 if (!pDPData) 570 return; 571 572 ScDPObject* pDPObj = pDPData->mpDPObj; 573 ScDPObject aNewDPObj(*pDPObj); 574 aNewDPObj.BuildAllDimensionMembers(); 575 ScDPSaveData* pSaveData = aNewDPObj.GetSaveData(); 576 577 sal_Bool bIsDataLayout; 578 String aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout); 579 ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aDimName); 580 if (!pDim) 581 return; 582 583 size_t nLabelIndex = 0; 584 lcl_GetLabelIndex( nLabelIndex, pDPData->mnDim, pDPData->maDPParam.maLabelArray ); 585 586 // Build a map of layout names to original names. 587 const ScDPLabelData& rLabelData = pDPData->maDPParam.maLabelArray[nLabelIndex]; 588 MemNameMapType aMemNameMap; 589 for (vector<ScDPLabelData::Member>::const_iterator itr = rLabelData.maMembers.begin(), itrEnd = rLabelData.maMembers.end(); 590 itr != itrEnd; ++itr) 591 aMemNameMap.insert(MemNameMapType::value_type(itr->maLayoutName, itr->maName)); 592 593 // The raw result may contain a mixture of layout names and original names. 594 MemVisibilityType aRawResult; 595 mpDPFieldPopup->getResult(aRawResult); 596 597 MemVisibilityType aResult; 598 for (MemVisibilityType::const_iterator itr = aRawResult.begin(), itrEnd = aRawResult.end(); itr != itrEnd; ++itr) 599 { 600 MemNameMapType::const_iterator itrNameMap = aMemNameMap.find(itr->first); 601 if (itrNameMap == aMemNameMap.end()) 602 // This is an original member name. Use it as-is. 603 aResult.insert(MemVisibilityType::value_type(itr->first, itr->second)); 604 else 605 { 606 // This is a layout name. Get the original member name and use it. 607 aResult.insert(MemVisibilityType::value_type(itrNameMap->second, itr->second)); 608 } 609 } 610 pDim->UpdateMemberVisibility(aResult); 611 612 ScDBDocFunc aFunc(*pViewData->GetDocShell()); 613 aFunc.DataPilotUpdate(pDPObj, &aNewDPObj, true, false); 614 } 615 616 void ScGridWindow::DPMouseMove( const MouseEvent& rMEvt ) 617 { 618 DPTestMouse( rMEvt, sal_True ); 619 } 620 621 void ScGridWindow::DPMouseButtonUp( const MouseEvent& rMEvt ) 622 { 623 bDPMouse = sal_False; 624 ReleaseMouse(); 625 626 DPTestMouse( rMEvt, sal_False ); 627 SetPointer( Pointer( POINTER_ARROW ) ); 628 } 629 630 // ----------------------------------------------------------------------- 631 632 void ScGridWindow::UpdateDragRect( sal_Bool bShowRange, const Rectangle& rPosRect ) 633 { 634 SCCOL nStartX = ( rPosRect.Left() >= 0 ) ? static_cast<SCCOL>(rPosRect.Left()) : SCCOL_MAX; 635 SCROW nStartY = ( rPosRect.Top() >= 0 ) ? static_cast<SCROW>(rPosRect.Top()) : SCROW_MAX; 636 SCCOL nEndX = ( rPosRect.Right() >= 0 ) ? static_cast<SCCOL>(rPosRect.Right()) : SCCOL_MAX; 637 SCROW nEndY = ( rPosRect.Bottom() >= 0 ) ? static_cast<SCROW>(rPosRect.Bottom()) : SCROW_MAX; 638 639 if ( bShowRange == bDragRect && nDragStartX == nStartX && nDragEndX == nEndX && 640 nDragStartY == nStartY && nDragEndY == nEndY ) 641 { 642 return; // everything unchanged 643 } 644 645 // if ( bDragRect ) 646 // DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, sal_False ); 647 if ( bShowRange ) 648 { 649 nDragStartX = nStartX; 650 nDragStartY = nStartY; 651 nDragEndX = nEndX; 652 nDragEndY = nEndY; 653 bDragRect = sal_True; 654 // DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, sal_False ); 655 } 656 else 657 bDragRect = sal_False; 658 659 UpdateDragRectOverlay(); 660 } 661 662 // ----------------------------------------------------------------------- 663 664 // Page-Break-Modus 665 666 sal_uInt16 ScGridWindow::HitPageBreak( const Point& rMouse, ScRange* pSource, 667 SCCOLROW* pBreak, SCCOLROW* pPrev ) 668 { 669 sal_uInt16 nFound = SC_PD_NONE; // 0 670 ScRange aSource; 671 SCCOLROW nBreak = 0; 672 SCCOLROW nPrev = 0; 673 674 ScPageBreakData* pPageData = pViewData->GetView()->GetPageBreakData(); 675 if ( pPageData ) 676 { 677 sal_Bool bHori = sal_False; 678 sal_Bool bVert = sal_False; 679 SCCOL nHitX = 0; 680 SCROW nHitY = 0; 681 682 long nMouseX = rMouse.X(); 683 long nMouseY = rMouse.Y(); 684 SCsCOL nPosX; 685 SCsROW nPosY; 686 pViewData->GetPosFromPixel( nMouseX, nMouseY, eWhich, nPosX, nPosY ); 687 Point aTL = pViewData->GetScrPos( nPosX, nPosY, eWhich ); 688 Point aBR = pViewData->GetScrPos( nPosX+1, nPosY+1, eWhich ); 689 690 // Horizontal mehr Toleranz als vertikal, weil mehr Platz ist 691 if ( nMouseX <= aTL.X() + 4 ) 692 { 693 bHori = sal_True; 694 nHitX = nPosX; 695 } 696 else if ( nMouseX >= aBR.X() - 6 ) 697 { 698 bHori = sal_True; 699 nHitX = nPosX+1; // linker Rand der naechsten Zelle 700 } 701 if ( nMouseY <= aTL.Y() + 2 ) 702 { 703 bVert = sal_True; 704 nHitY = nPosY; 705 } 706 else if ( nMouseY >= aBR.Y() - 4 ) 707 { 708 bVert = sal_True; 709 nHitY = nPosY+1; // oberer Rand der naechsten Zelle 710 } 711 712 if ( bHori || bVert ) 713 { 714 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() ); 715 for (sal_uInt16 nPos=0; nPos<nCount && !nFound; nPos++) 716 { 717 ScPrintRangeData& rData = pPageData->GetData(nPos); 718 ScRange aRange = rData.GetPrintRange(); 719 sal_Bool bLHit = ( bHori && nHitX == aRange.aStart.Col() ); 720 sal_Bool bRHit = ( bHori && nHitX == aRange.aEnd.Col() + 1 ); 721 sal_Bool bTHit = ( bVert && nHitY == aRange.aStart.Row() ); 722 sal_Bool bBHit = ( bVert && nHitY == aRange.aEnd.Row() + 1 ); 723 sal_Bool bInsideH = ( nPosX >= aRange.aStart.Col() && nPosX <= aRange.aEnd.Col() ); 724 sal_Bool bInsideV = ( nPosY >= aRange.aStart.Row() && nPosY <= aRange.aEnd.Row() ); 725 726 if ( bLHit ) 727 { 728 if ( bTHit ) 729 nFound = SC_PD_RANGE_TL; 730 else if ( bBHit ) 731 nFound = SC_PD_RANGE_BL; 732 else if ( bInsideV ) 733 nFound = SC_PD_RANGE_L; 734 } 735 else if ( bRHit ) 736 { 737 if ( bTHit ) 738 nFound = SC_PD_RANGE_TR; 739 else if ( bBHit ) 740 nFound = SC_PD_RANGE_BR; 741 else if ( bInsideV ) 742 nFound = SC_PD_RANGE_R; 743 } 744 else if ( bTHit && bInsideH ) 745 nFound = SC_PD_RANGE_T; 746 else if ( bBHit && bInsideH ) 747 nFound = SC_PD_RANGE_B; 748 if (nFound) 749 aSource = aRange; 750 751 // Umbrueche 752 753 if ( bVert && bInsideH && !nFound ) 754 { 755 size_t nRowCount = rData.GetPagesY(); 756 const SCROW* pRowEnd = rData.GetPageEndY(); 757 for (size_t nRowPos=0; nRowPos+1<nRowCount; nRowPos++) 758 if ( pRowEnd[nRowPos]+1 == nHitY ) 759 { 760 nFound = SC_PD_BREAK_V; 761 aSource = aRange; 762 nBreak = nHitY; 763 if ( nRowPos ) 764 nPrev = pRowEnd[nRowPos-1]+1; 765 else 766 nPrev = aRange.aStart.Row(); 767 } 768 } 769 if ( bHori && bInsideV && !nFound ) 770 { 771 size_t nColCount = rData.GetPagesX(); 772 const SCCOL* pColEnd = rData.GetPageEndX(); 773 for (size_t nColPos=0; nColPos+1<nColCount; nColPos++) 774 if ( pColEnd[nColPos]+1 == nHitX ) 775 { 776 nFound = SC_PD_BREAK_H; 777 aSource = aRange; 778 nBreak = nHitX; 779 if ( nColPos ) 780 nPrev = pColEnd[nColPos-1]+1; 781 else 782 nPrev = aRange.aStart.Col(); 783 } 784 } 785 } 786 } 787 } 788 789 if (pSource) 790 *pSource = aSource; // Druckbereich 791 if (pBreak) 792 *pBreak = nBreak; // X/Y Position des verchobenen Seitenumbruchs 793 if (pPrev) 794 *pPrev = nPrev; // X/Y Anfang der Seite, die am Umbruch zuende ist 795 return nFound; 796 } 797 798 void ScGridWindow::PagebreakMove( const MouseEvent& rMEvt, sal_Bool bUp ) 799 { 800 //! Scrolling und Umschalten mit RFMouseMove zusammenfassen ! 801 //! (Weginvertieren vor dem Scrolling ist anders) 802 803 // Scrolling 804 805 sal_Bool bTimer = sal_False; 806 Point aPos = rMEvt.GetPosPixel(); 807 SCsCOL nDx = 0; 808 SCsROW nDy = 0; 809 if ( aPos.X() < 0 ) nDx = -1; 810 if ( aPos.Y() < 0 ) nDy = -1; 811 Size aSize = GetOutputSizePixel(); 812 if ( aPos.X() >= aSize.Width() ) 813 nDx = 1; 814 if ( aPos.Y() >= aSize.Height() ) 815 nDy = 1; 816 if ( nDx != 0 || nDy != 0 ) 817 { 818 if ( bPagebreakDrawn ) // weginvertieren 819 { 820 // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(), 821 // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False ); 822 bPagebreakDrawn = sal_False; 823 UpdateDragRectOverlay(); 824 } 825 826 if ( nDx != 0 ) pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) ); 827 if ( nDy != 0 ) pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) ); 828 bTimer = sal_True; 829 } 830 831 // Umschalten bei Fixierung (damit Scrolling funktioniert) 832 833 if ( eWhich == pViewData->GetActivePart() ) //?? 834 { 835 if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX ) 836 if ( nDx > 0 ) 837 { 838 if ( eWhich == SC_SPLIT_TOPLEFT ) 839 pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT ); 840 else if ( eWhich == SC_SPLIT_BOTTOMLEFT ) 841 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ); 842 } 843 844 if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX ) 845 if ( nDy > 0 ) 846 { 847 if ( eWhich == SC_SPLIT_TOPLEFT ) 848 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT ); 849 else if ( eWhich == SC_SPLIT_TOPRIGHT ) 850 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ); 851 } 852 } 853 854 // ab hier neu 855 856 // gesucht wird eine Position zwischen den Zellen (vor nPosX / nPosY) 857 SCsCOL nPosX; 858 SCsROW nPosY; 859 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); 860 sal_Bool bLeft, bTop; 861 pViewData->GetMouseQuadrant( aPos, eWhich, nPosX, nPosY, bLeft, bTop ); 862 if ( !bLeft ) ++nPosX; 863 if ( !bTop ) ++nPosY; 864 865 sal_Bool bBreak = ( nPagebreakMouse == SC_PD_BREAK_H || nPagebreakMouse == SC_PD_BREAK_V ); 866 sal_Bool bHide = sal_False; 867 sal_Bool bToEnd = sal_False; 868 ScRange aDrawRange = aPagebreakSource; 869 if ( bBreak ) 870 { 871 if ( nPagebreakMouse == SC_PD_BREAK_H ) 872 { 873 if ( nPosX > aPagebreakSource.aStart.Col() && 874 nPosX <= aPagebreakSource.aEnd.Col() + 1 ) // ans Ende ist auch erlaubt 875 { 876 bToEnd = ( nPosX == aPagebreakSource.aEnd.Col() + 1 ); 877 aDrawRange.aStart.SetCol( nPosX ); 878 aDrawRange.aEnd.SetCol( nPosX - 1 ); 879 } 880 else 881 bHide = sal_True; 882 } 883 else 884 { 885 if ( nPosY > aPagebreakSource.aStart.Row() && 886 nPosY <= aPagebreakSource.aEnd.Row() + 1 ) // ans Ende ist auch erlaubt 887 { 888 bToEnd = ( nPosY == aPagebreakSource.aEnd.Row() + 1 ); 889 aDrawRange.aStart.SetRow( nPosY ); 890 aDrawRange.aEnd.SetRow( nPosY - 1 ); 891 } 892 else 893 bHide = sal_True; 894 } 895 } 896 else 897 { 898 if ( nPagebreakMouse & SC_PD_RANGE_L ) 899 aDrawRange.aStart.SetCol( nPosX ); 900 if ( nPagebreakMouse & SC_PD_RANGE_T ) 901 aDrawRange.aStart.SetRow( nPosY ); 902 if ( nPagebreakMouse & SC_PD_RANGE_R ) 903 { 904 if ( nPosX > 0 ) 905 aDrawRange.aEnd.SetCol( nPosX-1 ); 906 else 907 bHide = sal_True; 908 } 909 if ( nPagebreakMouse & SC_PD_RANGE_B ) 910 { 911 if ( nPosY > 0 ) 912 aDrawRange.aEnd.SetRow( nPosY-1 ); 913 else 914 bHide = sal_True; 915 } 916 if ( aDrawRange.aStart.Col() > aDrawRange.aEnd.Col() || 917 aDrawRange.aStart.Row() > aDrawRange.aEnd.Row() ) 918 bHide = sal_True; 919 } 920 921 if ( !bPagebreakDrawn || bUp || aDrawRange != aPagebreakDrag ) 922 { 923 // zeichnen... 924 925 if ( bPagebreakDrawn ) 926 { 927 // weginvertieren 928 // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(), 929 // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False ); 930 bPagebreakDrawn = sal_False; 931 } 932 aPagebreakDrag = aDrawRange; 933 if ( !bUp && !bHide ) 934 { 935 // hininvertieren 936 // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(), 937 // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False ); 938 bPagebreakDrawn = sal_True; 939 } 940 UpdateDragRectOverlay(); 941 } 942 943 // bei ButtonUp die Aenderung ausfuehren 944 945 if ( bUp ) 946 { 947 ScViewFunc* pViewFunc = pViewData->GetView(); 948 ScDocShell* pDocSh = pViewData->GetDocShell(); 949 ScDocument* pDoc = pDocSh->GetDocument(); 950 SCTAB nTab = pViewData->GetTabNo(); 951 sal_Bool bUndo (pDoc->IsUndoEnabled()); 952 953 if ( bBreak ) 954 { 955 sal_Bool bColumn = ( nPagebreakMouse == SC_PD_BREAK_H ); 956 SCCOLROW nNew = bColumn ? static_cast<SCCOLROW>(nPosX) : static_cast<SCCOLROW>(nPosY); 957 if ( nNew != nPagebreakBreak ) 958 { 959 if (bUndo) 960 { 961 String aUndo = ScGlobal::GetRscString( STR_UNDO_DRAG_BREAK ); 962 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo ); 963 } 964 965 sal_Bool bGrow = !bHide && nNew > nPagebreakBreak; 966 if ( bColumn ) 967 { 968 if (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakBreak), nTab) & BREAK_MANUAL) 969 { 970 ScAddress aOldAddr( static_cast<SCCOL>(nPagebreakBreak), nPosY, nTab ); 971 pViewFunc->DeletePageBreak( sal_True, sal_True, &aOldAddr, sal_False ); 972 } 973 if ( !bHide && !bToEnd ) // am Ende nicht 974 { 975 ScAddress aNewAddr( static_cast<SCCOL>(nNew), nPosY, nTab ); 976 pViewFunc->InsertPageBreak( sal_True, sal_True, &aNewAddr, sal_False ); 977 } 978 if ( bGrow ) 979 { 980 // vorigen Break auf hart, und Skalierung aendern 981 bool bManualBreak = (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakPrev), nTab) & BREAK_MANUAL); 982 if ( static_cast<SCCOL>(nPagebreakPrev) > aPagebreakSource.aStart.Col() && !bManualBreak ) 983 { 984 ScAddress aPrev( static_cast<SCCOL>(nPagebreakPrev), nPosY, nTab ); 985 pViewFunc->InsertPageBreak( sal_True, sal_True, &aPrev, sal_False ); 986 } 987 988 if (!pDocSh->AdjustPrintZoom( ScRange( 989 static_cast<SCCOL>(nPagebreakPrev),0,nTab, static_cast<SCCOL>(nNew-1),0,nTab ) )) 990 bGrow = sal_False; 991 } 992 } 993 else 994 { 995 if (pDoc->HasRowBreak(nPagebreakBreak, nTab) & BREAK_MANUAL) 996 { 997 ScAddress aOldAddr( nPosX, nPagebreakBreak, nTab ); 998 pViewFunc->DeletePageBreak( sal_False, sal_True, &aOldAddr, sal_False ); 999 } 1000 if ( !bHide && !bToEnd ) // am Ende nicht 1001 { 1002 ScAddress aNewAddr( nPosX, nNew, nTab ); 1003 pViewFunc->InsertPageBreak( sal_False, sal_True, &aNewAddr, sal_False ); 1004 } 1005 if ( bGrow ) 1006 { 1007 // vorigen Break auf hart, und Skalierung aendern 1008 bool bManualBreak = (pDoc->HasRowBreak(nPagebreakPrev, nTab) & BREAK_MANUAL); 1009 if ( nPagebreakPrev > aPagebreakSource.aStart.Row() && !bManualBreak ) 1010 { 1011 ScAddress aPrev( nPosX, nPagebreakPrev, nTab ); 1012 pViewFunc->InsertPageBreak( sal_False, sal_True, &aPrev, sal_False ); 1013 } 1014 1015 if (!pDocSh->AdjustPrintZoom( ScRange( 1016 0,nPagebreakPrev,nTab, 0,nNew-1,nTab ) )) 1017 bGrow = sal_False; 1018 } 1019 } 1020 1021 if (bUndo) 1022 { 1023 pDocSh->GetUndoManager()->LeaveListAction(); 1024 } 1025 1026 if (!bGrow) // sonst in AdjustPrintZoom schon passiert 1027 { 1028 pViewFunc->UpdatePageBreakData( sal_True ); 1029 pDocSh->SetDocumentModified(); 1030 } 1031 } 1032 } 1033 else if ( bHide || aPagebreakDrag != aPagebreakSource ) 1034 { 1035 // Druckbereich setzen 1036 1037 String aNewRanges; 1038 sal_uInt16 nOldCount = pDoc->GetPrintRangeCount( nTab ); 1039 if ( nOldCount ) 1040 { 1041 for (sal_uInt16 nPos=0; nPos<nOldCount; nPos++) 1042 { 1043 const ScRange* pOld = pDoc->GetPrintRange( nTab, nPos ); 1044 if ( pOld ) 1045 { 1046 String aTemp; 1047 if ( *pOld != aPagebreakSource ) 1048 pOld->Format( aTemp, SCA_VALID ); 1049 else if ( !bHide ) 1050 aPagebreakDrag.Format( aTemp, SCA_VALID ); 1051 if (aTemp.Len()) 1052 { 1053 if ( aNewRanges.Len() ) 1054 aNewRanges += ';'; 1055 aNewRanges += aTemp; 1056 } 1057 } 1058 } 1059 } 1060 else if (!bHide) 1061 aPagebreakDrag.Format( aNewRanges, SCA_VALID ); 1062 1063 pViewFunc->SetPrintRanges( pDoc->IsPrintEntireSheet( nTab ), &aNewRanges, NULL, NULL, sal_False ); 1064 } 1065 } 1066 1067 // Timer fuer Scrolling 1068 1069 if (bTimer && !bUp) 1070 pViewData->GetView()->SetTimer( this, rMEvt ); // Event wiederholen 1071 else 1072 pViewData->GetView()->ResetTimer(); 1073 } 1074 1075 1076 1077 1078