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