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