update dev300-m58
[ooovba.git] / sc / source / ui / view / gridwin2.cxx
blob8e522b6687c027488ae0971898028d651cdb508a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gridwin2.cxx,v $
10 * $Revision: 1.16.32.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include "scitems.hxx"
39 #include <vcl/msgbox.hxx>
40 #include <vcl/sound.hxx>
42 #include "gridwin.hxx"
43 #include "tabvwsh.hxx"
44 #include "docsh.hxx"
45 #include "viewdata.hxx"
46 #include "pivot.hxx"
47 //CHINA001 #include "pfiltdlg.hxx"
48 #include "uiitems.hxx"
49 #include "scresid.hxx"
50 #include "sc.hrc"
51 #include "globstr.hrc"
52 #include "pagedata.hxx"
53 #include "dpobject.hxx"
54 #include "dpsave.hxx"
55 #include "dpoutput.hxx" // ScDPPositionData
56 #include "dpshttab.hxx"
57 #include "dbdocfun.hxx"
58 #include "dpcontrol.hxx"
59 #include "dpcontrol.hrc"
60 #include "strload.hxx"
61 #include "userlist.hxx"
63 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
64 #include "scabstdlg.hxx" //CHINA001
66 #include <vector>
67 #include <hash_map>
69 using namespace com::sun::star;
70 using ::com::sun::star::sheet::DataPilotFieldOrientation;
71 using ::std::vector;
72 using ::std::auto_ptr;
73 using ::std::hash_map;
74 using ::rtl::OUString;
75 using ::rtl::OUStringHash;
77 // STATIC DATA -----------------------------------------------------------
79 // -----------------------------------------------------------------------
81 DataPilotFieldOrientation ScGridWindow::GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const
83 using namespace ::com::sun::star::sheet;
85 ScDocument* pDoc = pViewData->GetDocument();
86 SCTAB nTab = pViewData->GetTabNo();
87 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
88 if (!pDPObj)
89 return DataPilotFieldOrientation_HIDDEN;
91 USHORT nOrient = DataPilotFieldOrientation_HIDDEN;
93 // Check for page field first.
94 if (nCol > 0)
96 // look for the dimension header left of the drop-down arrow
97 long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient );
98 if ( nField >= 0 && nOrient == DataPilotFieldOrientation_PAGE )
100 BOOL bIsDataLayout = FALSE;
101 String aFieldName = pDPObj->GetDimName( nField, bIsDataLayout );
102 if ( aFieldName.Len() && !bIsDataLayout )
103 return DataPilotFieldOrientation_PAGE;
107 nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
109 // Now, check for row/column field.
110 long nField = pDPObj->GetHeaderDim(ScAddress(nCol, nRow, nTab), nOrient);
111 if (nField >= 0 && (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) )
113 BOOL bIsDataLayout = FALSE;
114 String aFieldName = pDPObj->GetDimName(nField, bIsDataLayout);
115 if (aFieldName.Len() && !bIsDataLayout)
116 return static_cast<DataPilotFieldOrientation>(nOrient);
119 return DataPilotFieldOrientation_HIDDEN;
122 // private method for mouse button handling
123 BOOL ScGridWindow::DoPageFieldSelection( SCCOL nCol, SCROW nRow )
125 if (GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE)
127 LaunchPageFieldMenu( nCol, nRow );
128 return TRUE;
130 return FALSE;
133 bool ScGridWindow::DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt )
135 ScDocument* pDoc = pViewData->GetDocument();
136 SCTAB nTab = pViewData->GetTabNo();
137 Point aScrPos = pViewData->GetScrPos(nCol, nRow, eWhich);
138 Point aDiffPix = rMEvt.GetPosPixel();
140 aDiffPix -= aScrPos;
141 BOOL bLayoutRTL = pDoc->IsLayoutRTL( nTab );
142 if ( bLayoutRTL )
143 aDiffPix.X() = -aDiffPix.X();
145 long nSizeX, nSizeY;
146 pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
147 Size aScrSize(nSizeX-1, nSizeY-1);
149 // Check if the mouse cursor is clicking on the popup arrow box.
150 mpFilterButton.reset(new ScDPFieldButton(this, &GetSettings().GetStyleSettings(), &pViewData->GetZoomX(), &pViewData->GetZoomY()));
151 mpFilterButton->setBoundingBox(aScrPos, aScrSize);
152 Point aPopupPos;
153 Size aPopupSize;
154 mpFilterButton->getPopupBoundingBox(aPopupPos, aPopupSize);
155 Rectangle aRec(aPopupPos, aPopupSize);
156 if (aRec.IsInside(rMEvt.GetPosPixel()))
158 if ( DoPageFieldSelection( nCol, nRow ) )
159 return true;
161 bool bFilterActive = IsAutoFilterActive(nCol, nRow, nTab);
162 mpFilterButton->setHasHiddenMember(bFilterActive);
163 mpFilterButton->setDrawBaseButton(false);
164 mpFilterButton->setDrawPopupButton(true);
165 mpFilterButton->setPopupPressed(true);
166 HideCursor();
167 mpFilterButton->draw();
168 ShowCursor();
169 DoAutoFilterMenue(nCol, nRow, false);
170 return true;
173 return false;
176 void ScGridWindow::DoPushButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt )
178 ScDocument* pDoc = pViewData->GetDocument();
179 SCTAB nTab = pViewData->GetTabNo();
181 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
183 if (pDPObj)
185 USHORT nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
186 ScAddress aPos( nCol, nRow, nTab );
187 long nField = pDPObj->GetHeaderDim( aPos, nOrient );
188 if ( nField >= 0 )
190 bDPMouse = TRUE;
191 nDPField = nField;
192 pDragDPObj = pDPObj;
194 if (DPTestFieldPopupArrow(rMEvt, aPos, pDPObj))
196 // field name pop up menu has been launched. Don't activate
197 // field move.
198 bDPMouse = false;
199 return;
202 DPTestMouse( rMEvt, TRUE );
203 StartTracking();
205 else if ( pDPObj->IsFilterButton(aPos) )
207 ReleaseMouse(); // may have been captured in ButtonDown
209 ScQueryParam aQueryParam;
210 SCTAB nSrcTab = 0;
211 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
212 DBG_ASSERT(pDesc, "no sheet source for filter button");
213 if (pDesc)
215 aQueryParam = pDesc->aQueryParam;
216 nSrcTab = pDesc->aSourceRange.aStart.Tab();
219 SfxItemSet aArgSet( pViewData->GetViewShell()->GetPool(),
220 SCITEM_QUERYDATA, SCITEM_QUERYDATA );
221 aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA, pViewData, &aQueryParam ) );
223 //CHINA001 ScPivotFilterDlg* pDlg = new ScPivotFilterDlg(
224 //CHINA001 pViewData->GetViewShell()->GetDialogParent(),
225 //CHINA001 aArgSet, nSrcTab );
226 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
227 DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001
229 AbstractScPivotFilterDlg* pDlg = pFact->CreateScPivotFilterDlg( pViewData->GetViewShell()->GetDialogParent(),
230 aArgSet, nSrcTab,
231 RID_SCDLG_PIVOTFILTER);
232 DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001
233 if ( pDlg->Execute() == RET_OK )
235 ScSheetSourceDesc aNewDesc;
236 if (pDesc)
237 aNewDesc = *pDesc;
239 const ScQueryItem& rQueryItem = pDlg->GetOutputItem();
240 aNewDesc.aQueryParam = rQueryItem.GetQueryData();
242 ScDPObject aNewObj( *pDPObj );
243 aNewObj.SetSheetDesc( aNewDesc );
244 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
245 aFunc.DataPilotUpdate( pDPObj, &aNewObj, TRUE, FALSE );
246 pViewData->GetView()->CursorPosChanged(); // shells may be switched
248 delete pDlg;
250 else
251 Sound::Beep();
253 else
255 DBG_ERROR("Da is ja garnix");
259 // -----------------------------------------------------------------------
261 // Data Pilot interaction
264 void ScGridWindow::DPTestMouse( const MouseEvent& rMEvt, BOOL bMove )
266 DBG_ASSERT(pDragDPObj, "pDragDPObj missing");
268 // scroll window if at edges
269 //! move this to separate method
271 BOOL bTimer = FALSE;
272 Point aPixel = rMEvt.GetPosPixel();
274 SCsCOL nDx = 0;
275 SCsROW nDy = 0;
276 if ( aPixel.X() < 0 )
277 nDx = -1;
278 if ( aPixel.Y() < 0 )
279 nDy = -1;
280 Size aSize = GetOutputSizePixel();
281 if ( aPixel.X() >= aSize.Width() )
282 nDx = 1;
283 if ( aPixel.Y() >= aSize.Height() )
284 nDy = 1;
285 if ( nDx != 0 || nDy != 0 )
287 UpdateDragRect( FALSE, Rectangle() );
289 if ( nDx != 0)
290 pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
291 if ( nDy != 0 )
292 pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
294 bTimer = TRUE;
297 // ---
299 SCsCOL nPosX;
300 SCsROW nPosY;
301 pViewData->GetPosFromPixel( aPixel.X(), aPixel.Y(), eWhich, nPosX, nPosY );
302 BOOL bMouseLeft;
303 BOOL bMouseTop;
304 pViewData->GetMouseQuadrant( aPixel, eWhich, nPosX, nPosY, bMouseLeft, bMouseTop );
306 ScAddress aPos( nPosX, nPosY, pViewData->GetTabNo() );
308 Rectangle aPosRect;
309 USHORT nOrient;
310 long nDimPos;
311 BOOL bHasRange = pDragDPObj->GetHeaderDrag( aPos, bMouseLeft, bMouseTop, nDPField,
312 aPosRect, nOrient, nDimPos );
313 UpdateDragRect( bHasRange && bMove, aPosRect );
315 if (bMove) // set mouse pointer
317 PointerStyle ePointer = POINTER_PIVOT_DELETE;
318 if ( bHasRange )
319 switch (nOrient)
321 case sheet::DataPilotFieldOrientation_COLUMN: ePointer = POINTER_PIVOT_COL; break;
322 case sheet::DataPilotFieldOrientation_ROW: ePointer = POINTER_PIVOT_ROW; break;
323 case sheet::DataPilotFieldOrientation_PAGE:
324 case sheet::DataPilotFieldOrientation_DATA: ePointer = POINTER_PIVOT_FIELD; break;
326 SetPointer( ePointer );
328 else // execute change
330 if (!bHasRange)
331 nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
333 BOOL bIsDataLayout;
334 String aDimName = pDragDPObj->GetDimName( nDPField, bIsDataLayout );
335 if ( bIsDataLayout && ( nOrient != sheet::DataPilotFieldOrientation_COLUMN &&
336 nOrient != sheet::DataPilotFieldOrientation_ROW ) )
338 // removing data layout is not allowed
339 pViewData->GetView()->ErrorMessage(STR_PIVOT_MOVENOTALLOWED);
341 else
343 ScDPSaveData aSaveData( *pDragDPObj->GetSaveData() );
345 ScDPSaveDimension* pDim;
346 if ( bIsDataLayout )
347 pDim = aSaveData.GetDataLayoutDimension();
348 else
349 pDim = aSaveData.GetDimensionByName(aDimName);
350 pDim->SetOrientation( nOrient );
351 aSaveData.SetPosition( pDim, nDimPos );
353 //! docfunc method with ScDPSaveData as argument?
355 ScDPObject aNewObj( *pDragDPObj );
356 aNewObj.SetSaveData( aSaveData );
357 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
358 // when dragging fields, allow re-positioning (bAllowMove)
359 aFunc.DataPilotUpdate( pDragDPObj, &aNewObj, TRUE, FALSE, TRUE );
360 pViewData->GetView()->CursorPosChanged(); // shells may be switched
364 if (bTimer && bMove)
365 pViewData->GetView()->SetTimer( this, rMEvt ); // repeat event
366 else
367 pViewData->GetView()->ResetTimer();
370 bool ScGridWindow::DPTestFieldPopupArrow(const MouseEvent& rMEvt, const ScAddress& rPos, ScDPObject* pDPObj)
372 // Get the geometry of the cell.
373 Point aScrPos = pViewData->GetScrPos(rPos.Col(), rPos.Row(), eWhich);
374 long nSizeX, nSizeY;
375 pViewData->GetMergeSizePixel(rPos.Col(), rPos.Row(), nSizeX, nSizeY);
376 Size aScrSize(nSizeX-1, nSizeY-1);
378 // Check if the mouse cursor is clicking on the popup arrow box.
379 ScDPFieldButton aBtn(this, &GetSettings().GetStyleSettings());
380 aBtn.setBoundingBox(aScrPos, aScrSize);
381 Point aPopupPos;
382 Size aPopupSize;
383 aBtn.getPopupBoundingBox(aPopupPos, aPopupSize);
384 Rectangle aRec(aPopupPos, aPopupSize);
385 if (aRec.IsInside(rMEvt.GetPosPixel()))
387 // Mouse cursor inside the popup arrow box. Launch the field menu.
388 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, rPos, pDPObj);
389 return true;
392 return false;
395 namespace {
397 struct DPFieldPopupData : public ScDPFieldPopupWindow::ExtendedData
399 ScPivotParam maDPParam;
400 ScDPObject* mpDPObj;
401 long mnDim;
404 class DPFieldPopupOKAction : public ScMenuFloatingWindow::Action
406 public:
407 explicit DPFieldPopupOKAction(ScGridWindow* p) :
408 mpGridWindow(p) {}
410 virtual void execute()
412 mpGridWindow->UpdateDPFromFieldPopupMenu();
414 private:
415 ScGridWindow* mpGridWindow;
418 class PopupSortAction : public ScMenuFloatingWindow::Action
420 public:
421 enum SortType { ASCENDING, DESCENDING, CUSTOM };
423 explicit PopupSortAction(const ScAddress& rPos, SortType eType, sal_uInt16 nUserListIndex, ScTabViewShell* pViewShell) :
424 maPos(rPos), meType(eType), mnUserListIndex(nUserListIndex), mpViewShell(pViewShell) {}
426 virtual void execute()
428 switch (meType)
430 case ASCENDING:
431 mpViewShell->DataPilotSort(maPos, true);
432 break;
433 case DESCENDING:
434 mpViewShell->DataPilotSort(maPos, false);
435 break;
436 case CUSTOM:
437 mpViewShell->DataPilotSort(maPos, true, &mnUserListIndex);
438 break;
439 default:
444 private:
445 ScAddress maPos;
446 SortType meType;
447 sal_uInt16 mnUserListIndex;
448 ScTabViewShell* mpViewShell;
453 void ScGridWindow::DPLaunchFieldPopupMenu(
454 const Point& rScrPos, const Size& rScrSize, const ScAddress& rPos, ScDPObject* pDPObj)
456 // We need to get the list of field members.
457 auto_ptr<DPFieldPopupData> pDPData(new DPFieldPopupData);
458 pDPObj->FillLabelData(pDPData->maDPParam);
459 pDPData->mpDPObj = pDPObj;
461 USHORT nOrient;
462 pDPData->mnDim = pDPObj->GetHeaderDim(rPos, nOrient);
464 if (pDPData->maDPParam.maLabelArray.size() <= static_cast<size_t>(pDPData->mnDim))
465 // out-of-bound dimension ID. This should never happen!
466 return;
468 const ScDPLabelData& rLabelData = *pDPData->maDPParam.maLabelArray[pDPData->mnDim];
470 mpDPFieldPopup.reset(new ScDPFieldPopupWindow(this, pViewData->GetDocument()));
471 mpDPFieldPopup->setName(OUString::createFromAscii("DataPilot field member popup"));
472 mpDPFieldPopup->setExtendedData(pDPData.release());
473 mpDPFieldPopup->setOKAction(new DPFieldPopupOKAction(this));
475 // Populate field members.
476 size_t n = rLabelData.maMembers.size();
477 mpDPFieldPopup->setMemberSize(n);
478 for (size_t i = 0; i < n; ++i)
480 const ScDPLabelData::Member& rMem = rLabelData.maMembers[i];
481 mpDPFieldPopup->addMember(rMem.getDisplayName(), rMem.mbVisible);
483 mpDPFieldPopup->initMembers();
486 vector<OUString> aUserSortNames;
487 ScUserList* pUserList = ScGlobal::GetUserList();
488 if (pUserList)
490 sal_uInt16 n = pUserList->GetCount();
491 aUserSortNames.reserve(n);
492 for (sal_uInt16 i = 0; i < n; ++i)
494 ScUserListData* pData = static_cast<ScUserListData*>((*pUserList)[i]);
495 aUserSortNames.push_back(pData->GetString());
499 // Populate the menus.
500 ScTabViewShell* pViewShell = pViewData->GetViewShell();
501 mpDPFieldPopup->addMenuItem(
502 ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_ASC).GetString(), true,
503 new PopupSortAction(rPos, PopupSortAction::ASCENDING, 0, pViewShell));
504 mpDPFieldPopup->addMenuItem(
505 ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_DESC).GetString(), true,
506 new PopupSortAction(rPos, PopupSortAction::DESCENDING, 0, pViewShell));
507 ScMenuFloatingWindow* pSubMenu = mpDPFieldPopup->addSubMenuItem(
508 ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_CUSTOM).GetString(), !aUserSortNames.empty());
510 if (pSubMenu && !aUserSortNames.empty())
512 size_t n = aUserSortNames.size();
513 for (size_t i = 0; i < n; ++i)
515 pSubMenu->addMenuItem(
516 aUserSortNames[i], true,
517 new PopupSortAction(rPos, PopupSortAction::CUSTOM, i, pViewShell));
521 Rectangle aCellRect(rScrPos, rScrSize);
522 const Size& rPopupSize = mpDPFieldPopup->getWindowSize();
523 if (rScrSize.getWidth() > rPopupSize.getWidth())
525 // If the cell width is larger than the popup window width, launch it
526 // right-aligned with the cell.
527 long nXOffset = rScrSize.getWidth() - rPopupSize.getWidth();
528 aCellRect.SetPos(Point(rScrPos.X() + nXOffset, rScrPos.Y()));
530 mpDPFieldPopup->SetPopupModeEndHdl( LINK(this, ScGridWindow, PopupModeEndHdl) );
531 mpDPFieldPopup->StartPopupMode(aCellRect, (FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_GRABFOCUS));
534 void ScGridWindow::UpdateDPFromFieldPopupMenu()
536 typedef hash_map<OUString, OUString, OUStringHash> MemNameMapType;
537 typedef hash_map<OUString, bool, OUStringHash> MemVisibilityType;
539 if (!mpDPFieldPopup.get())
540 return;
542 DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(mpDPFieldPopup->getExtendedData());
543 if (!pDPData)
544 return;
546 ScDPObject* pDPObj = pDPData->mpDPObj;
547 ScDPObject aNewDPObj(*pDPObj);
548 aNewDPObj.BuildAllDimensionMembers();
549 ScDPSaveData* pSaveData = aNewDPObj.GetSaveData();
551 BOOL bIsDataLayout;
552 String aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
553 ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aDimName);
554 if (!pDim)
555 return;
557 // Build a map of layout names to original names.
558 const ScDPLabelData& rLabelData = *pDPData->maDPParam.maLabelArray[pDPData->mnDim];
559 MemNameMapType aMemNameMap;
560 for (vector<ScDPLabelData::Member>::const_iterator itr = rLabelData.maMembers.begin(), itrEnd = rLabelData.maMembers.end();
561 itr != itrEnd; ++itr)
562 aMemNameMap.insert(MemNameMapType::value_type(itr->maLayoutName, itr->maName));
564 // The raw result may contain a mixture of layout names and original names.
565 MemVisibilityType aRawResult;
566 mpDPFieldPopup->getResult(aRawResult);
568 MemVisibilityType aResult;
569 for (MemVisibilityType::const_iterator itr = aRawResult.begin(), itrEnd = aRawResult.end(); itr != itrEnd; ++itr)
571 MemNameMapType::const_iterator itrNameMap = aMemNameMap.find(itr->first);
572 if (itrNameMap == aMemNameMap.end())
573 // This is an original member name. Use it as-is.
574 aResult.insert(MemVisibilityType::value_type(itr->first, itr->second));
575 else
577 // This is a layout name. Get the original member name and use it.
578 aResult.insert(MemVisibilityType::value_type(itrNameMap->second, itr->second));
581 pDim->UpdateMemberVisibility(aResult);
583 ScDBDocFunc aFunc(*pViewData->GetDocShell());
584 aFunc.DataPilotUpdate(pDPObj, &aNewDPObj, true, false);
587 void ScGridWindow::DPMouseMove( const MouseEvent& rMEvt )
589 DPTestMouse( rMEvt, TRUE );
592 void ScGridWindow::DPMouseButtonUp( const MouseEvent& rMEvt )
594 bDPMouse = FALSE;
595 ReleaseMouse();
597 DPTestMouse( rMEvt, FALSE );
598 SetPointer( Pointer( POINTER_ARROW ) );
601 // -----------------------------------------------------------------------
603 void ScGridWindow::UpdateDragRect( BOOL bShowRange, const Rectangle& rPosRect )
605 SCCOL nStartX = ( rPosRect.Left() >= 0 ) ? static_cast<SCCOL>(rPosRect.Left()) : SCCOL_MAX;
606 SCROW nStartY = ( rPosRect.Top() >= 0 ) ? static_cast<SCROW>(rPosRect.Top()) : SCROW_MAX;
607 SCCOL nEndX = ( rPosRect.Right() >= 0 ) ? static_cast<SCCOL>(rPosRect.Right()) : SCCOL_MAX;
608 SCROW nEndY = ( rPosRect.Bottom() >= 0 ) ? static_cast<SCROW>(rPosRect.Bottom()) : SCROW_MAX;
610 if ( bShowRange == bDragRect && nDragStartX == nStartX && nDragEndX == nEndX &&
611 nDragStartY == nStartY && nDragEndY == nEndY )
613 return; // everything unchanged
616 // if ( bDragRect )
617 // DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, FALSE );
618 if ( bShowRange )
620 nDragStartX = nStartX;
621 nDragStartY = nStartY;
622 nDragEndX = nEndX;
623 nDragEndY = nEndY;
624 bDragRect = TRUE;
625 // DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, FALSE );
627 else
628 bDragRect = FALSE;
630 UpdateDragRectOverlay();
633 // -----------------------------------------------------------------------
635 // Page-Break-Modus
637 USHORT ScGridWindow::HitPageBreak( const Point& rMouse, ScRange* pSource,
638 SCCOLROW* pBreak, SCCOLROW* pPrev )
640 USHORT nFound = SC_PD_NONE; // 0
641 ScRange aSource;
642 SCCOLROW nBreak = 0;
643 SCCOLROW nPrev = 0;
645 ScPageBreakData* pPageData = pViewData->GetView()->GetPageBreakData();
646 if ( pPageData )
648 BOOL bHori = FALSE;
649 BOOL bVert = FALSE;
650 SCCOL nHitX = 0;
651 SCROW nHitY = 0;
653 long nMouseX = rMouse.X();
654 long nMouseY = rMouse.Y();
655 SCsCOL nPosX;
656 SCsROW nPosY;
657 pViewData->GetPosFromPixel( nMouseX, nMouseY, eWhich, nPosX, nPosY );
658 Point aTL = pViewData->GetScrPos( nPosX, nPosY, eWhich );
659 Point aBR = pViewData->GetScrPos( nPosX+1, nPosY+1, eWhich );
661 // Horizontal mehr Toleranz als vertikal, weil mehr Platz ist
662 if ( nMouseX <= aTL.X() + 4 )
664 bHori = TRUE;
665 nHitX = nPosX;
667 else if ( nMouseX >= aBR.X() - 6 )
669 bHori = TRUE;
670 nHitX = nPosX+1; // linker Rand der naechsten Zelle
672 if ( nMouseY <= aTL.Y() + 2 )
674 bVert = TRUE;
675 nHitY = nPosY;
677 else if ( nMouseY >= aBR.Y() - 4 )
679 bVert = TRUE;
680 nHitY = nPosY+1; // oberer Rand der naechsten Zelle
683 if ( bHori || bVert )
685 USHORT nCount = sal::static_int_cast<USHORT>( pPageData->GetCount() );
686 for (USHORT nPos=0; nPos<nCount && !nFound; nPos++)
688 ScPrintRangeData& rData = pPageData->GetData(nPos);
689 ScRange aRange = rData.GetPrintRange();
690 BOOL bLHit = ( bHori && nHitX == aRange.aStart.Col() );
691 BOOL bRHit = ( bHori && nHitX == aRange.aEnd.Col() + 1 );
692 BOOL bTHit = ( bVert && nHitY == aRange.aStart.Row() );
693 BOOL bBHit = ( bVert && nHitY == aRange.aEnd.Row() + 1 );
694 BOOL bInsideH = ( nPosX >= aRange.aStart.Col() && nPosX <= aRange.aEnd.Col() );
695 BOOL bInsideV = ( nPosY >= aRange.aStart.Row() && nPosY <= aRange.aEnd.Row() );
697 if ( bLHit )
699 if ( bTHit )
700 nFound = SC_PD_RANGE_TL;
701 else if ( bBHit )
702 nFound = SC_PD_RANGE_BL;
703 else if ( bInsideV )
704 nFound = SC_PD_RANGE_L;
706 else if ( bRHit )
708 if ( bTHit )
709 nFound = SC_PD_RANGE_TR;
710 else if ( bBHit )
711 nFound = SC_PD_RANGE_BR;
712 else if ( bInsideV )
713 nFound = SC_PD_RANGE_R;
715 else if ( bTHit && bInsideH )
716 nFound = SC_PD_RANGE_T;
717 else if ( bBHit && bInsideH )
718 nFound = SC_PD_RANGE_B;
719 if (nFound)
720 aSource = aRange;
722 // Umbrueche
724 if ( bVert && bInsideH && !nFound )
726 size_t nRowCount = rData.GetPagesY();
727 const SCROW* pRowEnd = rData.GetPageEndY();
728 for (size_t nRowPos=0; nRowPos+1<nRowCount; nRowPos++)
729 if ( pRowEnd[nRowPos]+1 == nHitY )
731 nFound = SC_PD_BREAK_V;
732 aSource = aRange;
733 nBreak = nHitY;
734 if ( nRowPos )
735 nPrev = pRowEnd[nRowPos-1]+1;
736 else
737 nPrev = aRange.aStart.Row();
740 if ( bHori && bInsideV && !nFound )
742 size_t nColCount = rData.GetPagesX();
743 const SCCOL* pColEnd = rData.GetPageEndX();
744 for (size_t nColPos=0; nColPos+1<nColCount; nColPos++)
745 if ( pColEnd[nColPos]+1 == nHitX )
747 nFound = SC_PD_BREAK_H;
748 aSource = aRange;
749 nBreak = nHitX;
750 if ( nColPos )
751 nPrev = pColEnd[nColPos-1]+1;
752 else
753 nPrev = aRange.aStart.Col();
760 if (pSource)
761 *pSource = aSource; // Druckbereich
762 if (pBreak)
763 *pBreak = nBreak; // X/Y Position des verchobenen Seitenumbruchs
764 if (pPrev)
765 *pPrev = nPrev; // X/Y Anfang der Seite, die am Umbruch zuende ist
766 return nFound;
769 void ScGridWindow::PagebreakMove( const MouseEvent& rMEvt, BOOL bUp )
771 //! Scrolling und Umschalten mit RFMouseMove zusammenfassen !
772 //! (Weginvertieren vor dem Scrolling ist anders)
774 // Scrolling
776 BOOL bTimer = FALSE;
777 Point aPos = rMEvt.GetPosPixel();
778 SCsCOL nDx = 0;
779 SCsROW nDy = 0;
780 if ( aPos.X() < 0 ) nDx = -1;
781 if ( aPos.Y() < 0 ) nDy = -1;
782 Size aSize = GetOutputSizePixel();
783 if ( aPos.X() >= aSize.Width() )
784 nDx = 1;
785 if ( aPos.Y() >= aSize.Height() )
786 nDy = 1;
787 if ( nDx != 0 || nDy != 0 )
789 if ( bPagebreakDrawn ) // weginvertieren
791 // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(),
792 // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), FALSE );
793 bPagebreakDrawn = FALSE;
794 UpdateDragRectOverlay();
797 if ( nDx != 0 ) pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
798 if ( nDy != 0 ) pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
799 bTimer = TRUE;
802 // Umschalten bei Fixierung (damit Scrolling funktioniert)
804 if ( eWhich == pViewData->GetActivePart() ) //??
806 if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
807 if ( nDx > 0 )
809 if ( eWhich == SC_SPLIT_TOPLEFT )
810 pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
811 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
812 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
815 if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
816 if ( nDy > 0 )
818 if ( eWhich == SC_SPLIT_TOPLEFT )
819 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
820 else if ( eWhich == SC_SPLIT_TOPRIGHT )
821 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
825 // ab hier neu
827 // gesucht wird eine Position zwischen den Zellen (vor nPosX / nPosY)
828 SCsCOL nPosX;
829 SCsROW nPosY;
830 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
831 BOOL bLeft, bTop;
832 pViewData->GetMouseQuadrant( aPos, eWhich, nPosX, nPosY, bLeft, bTop );
833 if ( !bLeft ) ++nPosX;
834 if ( !bTop ) ++nPosY;
836 BOOL bBreak = ( nPagebreakMouse == SC_PD_BREAK_H || nPagebreakMouse == SC_PD_BREAK_V );
837 BOOL bHide = FALSE;
838 BOOL bToEnd = FALSE;
839 ScRange aDrawRange = aPagebreakSource;
840 if ( bBreak )
842 if ( nPagebreakMouse == SC_PD_BREAK_H )
844 if ( nPosX > aPagebreakSource.aStart.Col() &&
845 nPosX <= aPagebreakSource.aEnd.Col() + 1 ) // ans Ende ist auch erlaubt
847 bToEnd = ( nPosX == aPagebreakSource.aEnd.Col() + 1 );
848 aDrawRange.aStart.SetCol( nPosX );
849 aDrawRange.aEnd.SetCol( nPosX - 1 );
851 else
852 bHide = TRUE;
854 else
856 if ( nPosY > aPagebreakSource.aStart.Row() &&
857 nPosY <= aPagebreakSource.aEnd.Row() + 1 ) // ans Ende ist auch erlaubt
859 bToEnd = ( nPosY == aPagebreakSource.aEnd.Row() + 1 );
860 aDrawRange.aStart.SetRow( nPosY );
861 aDrawRange.aEnd.SetRow( nPosY - 1 );
863 else
864 bHide = TRUE;
867 else
869 if ( nPagebreakMouse & SC_PD_RANGE_L )
870 aDrawRange.aStart.SetCol( nPosX );
871 if ( nPagebreakMouse & SC_PD_RANGE_T )
872 aDrawRange.aStart.SetRow( nPosY );
873 if ( nPagebreakMouse & SC_PD_RANGE_R )
875 if ( nPosX > 0 )
876 aDrawRange.aEnd.SetCol( nPosX-1 );
877 else
878 bHide = TRUE;
880 if ( nPagebreakMouse & SC_PD_RANGE_B )
882 if ( nPosY > 0 )
883 aDrawRange.aEnd.SetRow( nPosY-1 );
884 else
885 bHide = TRUE;
887 if ( aDrawRange.aStart.Col() > aDrawRange.aEnd.Col() ||
888 aDrawRange.aStart.Row() > aDrawRange.aEnd.Row() )
889 bHide = TRUE;
892 if ( !bPagebreakDrawn || bUp || aDrawRange != aPagebreakDrag )
894 // zeichnen...
896 if ( bPagebreakDrawn )
898 // weginvertieren
899 // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(),
900 // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), FALSE );
901 bPagebreakDrawn = FALSE;
903 aPagebreakDrag = aDrawRange;
904 if ( !bUp && !bHide )
906 // hininvertieren
907 // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(),
908 // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), FALSE );
909 bPagebreakDrawn = TRUE;
911 UpdateDragRectOverlay();
914 // bei ButtonUp die Aenderung ausfuehren
916 if ( bUp )
918 ScViewFunc* pViewFunc = pViewData->GetView();
919 ScDocShell* pDocSh = pViewData->GetDocShell();
920 ScDocument* pDoc = pDocSh->GetDocument();
921 SCTAB nTab = pViewData->GetTabNo();
922 BOOL bUndo (pDoc->IsUndoEnabled());
924 if ( bBreak )
926 BOOL bColumn = ( nPagebreakMouse == SC_PD_BREAK_H );
927 SCCOLROW nNew = bColumn ? static_cast<SCCOLROW>(nPosX) : static_cast<SCCOLROW>(nPosY);
928 if ( nNew != nPagebreakBreak )
930 if (bUndo)
932 String aUndo = ScGlobal::GetRscString( STR_UNDO_DRAG_BREAK );
933 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
936 BOOL bGrow = !bHide && nNew > nPagebreakBreak;
937 if ( bColumn )
939 if (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakBreak), nTab) & BREAK_MANUAL)
941 ScAddress aOldAddr( static_cast<SCCOL>(nPagebreakBreak), nPosY, nTab );
942 pViewFunc->DeletePageBreak( TRUE, TRUE, &aOldAddr, FALSE );
944 if ( !bHide && !bToEnd ) // am Ende nicht
946 ScAddress aNewAddr( static_cast<SCCOL>(nNew), nPosY, nTab );
947 pViewFunc->InsertPageBreak( TRUE, TRUE, &aNewAddr, FALSE );
949 if ( bGrow )
951 // vorigen Break auf hart, und Skalierung aendern
952 bool bManualBreak = (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakPrev), nTab) & BREAK_MANUAL);
953 if ( static_cast<SCCOL>(nPagebreakPrev) > aPagebreakSource.aStart.Col() && !bManualBreak )
955 ScAddress aPrev( static_cast<SCCOL>(nPagebreakPrev), nPosY, nTab );
956 pViewFunc->InsertPageBreak( TRUE, TRUE, &aPrev, FALSE );
959 if (!pDocSh->AdjustPrintZoom( ScRange(
960 static_cast<SCCOL>(nPagebreakPrev),0,nTab, static_cast<SCCOL>(nNew-1),0,nTab ) ))
961 bGrow = FALSE;
964 else
966 if (pDoc->HasRowBreak(nPagebreakBreak, nTab) & BREAK_MANUAL)
968 ScAddress aOldAddr( nPosX, nPagebreakBreak, nTab );
969 pViewFunc->DeletePageBreak( FALSE, TRUE, &aOldAddr, FALSE );
971 if ( !bHide && !bToEnd ) // am Ende nicht
973 ScAddress aNewAddr( nPosX, nNew, nTab );
974 pViewFunc->InsertPageBreak( FALSE, TRUE, &aNewAddr, FALSE );
976 if ( bGrow )
978 // vorigen Break auf hart, und Skalierung aendern
979 bool bManualBreak = (pDoc->HasRowBreak(nPagebreakPrev, nTab) & BREAK_MANUAL);
980 if ( nPagebreakPrev > aPagebreakSource.aStart.Row() && !bManualBreak )
982 ScAddress aPrev( nPosX, nPagebreakPrev, nTab );
983 pViewFunc->InsertPageBreak( FALSE, TRUE, &aPrev, FALSE );
986 if (!pDocSh->AdjustPrintZoom( ScRange(
987 0,nPagebreakPrev,nTab, 0,nNew-1,nTab ) ))
988 bGrow = FALSE;
992 if (bUndo)
994 pDocSh->GetUndoManager()->LeaveListAction();
997 if (!bGrow) // sonst in AdjustPrintZoom schon passiert
999 pViewFunc->UpdatePageBreakData( TRUE );
1000 pDocSh->SetDocumentModified();
1004 else if ( bHide || aPagebreakDrag != aPagebreakSource )
1006 // Druckbereich setzen
1008 String aNewRanges;
1009 USHORT nOldCount = pDoc->GetPrintRangeCount( nTab );
1010 if ( nOldCount )
1012 for (USHORT nPos=0; nPos<nOldCount; nPos++)
1014 const ScRange* pOld = pDoc->GetPrintRange( nTab, nPos );
1015 if ( pOld )
1017 String aTemp;
1018 if ( *pOld != aPagebreakSource )
1019 pOld->Format( aTemp, SCA_VALID );
1020 else if ( !bHide )
1021 aPagebreakDrag.Format( aTemp, SCA_VALID );
1022 if (aTemp.Len())
1024 if ( aNewRanges.Len() )
1025 aNewRanges += ';';
1026 aNewRanges += aTemp;
1031 else if (!bHide)
1032 aPagebreakDrag.Format( aNewRanges, SCA_VALID );
1034 pViewFunc->SetPrintRanges( pDoc->IsPrintEntireSheet( nTab ), &aNewRanges, NULL, NULL, FALSE );
1038 // Timer fuer Scrolling
1040 if (bTimer && !bUp)
1041 pViewData->GetView()->SetTimer( this, rMEvt ); // Event wiederholen
1042 else
1043 pViewData->GetView()->ResetTimer();