xref: /AOO41X/main/sc/source/ui/view/gridwin2.cxx (revision 51b45b885d34684241bbd5d7074220a670520cb5)
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