Bump version to 4.3-4
[LibreOffice.git] / sc / source / ui / view / gridwin2.cxx
blob357b4191b7a36d59f5599156ca28c7e7a4cf0445
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
21 #include <vcl/msgbox.hxx>
22 #include <vcl/settings.hxx>
24 #include "gridwin.hxx"
25 #include "tabvwsh.hxx"
26 #include "docsh.hxx"
27 #include "viewdata.hxx"
28 #include "pivot.hxx"
29 #include "uiitems.hxx"
30 #include "scresid.hxx"
31 #include "sc.hrc"
32 #include "globstr.hrc"
33 #include "pagedata.hxx"
34 #include "dpobject.hxx"
35 #include "dpsave.hxx"
36 #include "dpoutput.hxx"
37 #include "dpshttab.hxx"
38 #include "dbdocfun.hxx"
39 #include "checklistmenu.hxx"
40 #include "dpcontrol.hxx"
41 #include "checklistmenu.hrc"
42 #include "strload.hxx"
43 #include "userlist.hxx"
44 #include "scabstdlg.hxx"
45 #include "spellcheckcontext.hxx"
47 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
49 #include <vector>
50 #include <boost/scoped_ptr.hpp>
51 #include <boost/unordered_map.hpp>
53 using namespace com::sun::star;
54 using ::com::sun::star::sheet::DataPilotFieldOrientation;
55 using ::std::vector;
56 using ::std::auto_ptr;
57 using ::boost::unordered_map;
59 // STATIC DATA -----------------------------------------------------------
61 DataPilotFieldOrientation ScGridWindow::GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const
63 using namespace ::com::sun::star::sheet;
65 ScDocument* pDoc = pViewData->GetDocument();
66 SCTAB nTab = pViewData->GetTabNo();
67 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
68 if (!pDPObj)
69 return DataPilotFieldOrientation_HIDDEN;
71 sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN;
73 // Check for page field first.
74 if (nCol > 0)
76 // look for the dimension header left of the drop-down arrow
77 long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient );
78 if ( nField >= 0 && nOrient == DataPilotFieldOrientation_PAGE )
80 bool bIsDataLayout = false;
81 OUString aFieldName = pDPObj->GetDimName( nField, bIsDataLayout );
82 if ( !aFieldName.isEmpty() && !bIsDataLayout )
83 return DataPilotFieldOrientation_PAGE;
87 nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
89 // Now, check for row/column field.
90 long nField = pDPObj->GetHeaderDim(ScAddress(nCol, nRow, nTab), nOrient);
91 if (nField >= 0 && (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) )
93 bool bIsDataLayout = false;
94 OUString aFieldName = pDPObj->GetDimName(nField, bIsDataLayout);
95 if (!aFieldName.isEmpty() && !bIsDataLayout)
96 return static_cast<DataPilotFieldOrientation>(nOrient);
99 return DataPilotFieldOrientation_HIDDEN;
102 // private method for mouse button handling
103 bool ScGridWindow::DoPageFieldSelection( SCCOL nCol, SCROW nRow )
105 if (GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE)
107 LaunchPageFieldMenu( nCol, nRow );
108 return true;
110 return false;
113 bool ScGridWindow::DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt )
115 ScDocument* pDoc = pViewData->GetDocument();
116 SCTAB nTab = pViewData->GetTabNo();
117 Point aScrPos = pViewData->GetScrPos(nCol, nRow, eWhich);
118 Point aDiffPix = rMEvt.GetPosPixel();
120 aDiffPix -= aScrPos;
121 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
122 if ( bLayoutRTL )
123 aDiffPix.X() = -aDiffPix.X();
125 long nSizeX, nSizeY;
126 pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
127 // The button height should not use the merged cell height, should still use single row height
128 nSizeY = pViewData->ToPixel(pDoc->GetRowHeight(nRow, nTab), pViewData->GetPPTY());
129 Size aScrSize(nSizeX-1, nSizeY-1);
131 // Check if the mouse cursor is clicking on the popup arrow box.
132 mpFilterButton.reset(new ScDPFieldButton(this, &GetSettings().GetStyleSettings(), &pViewData->GetZoomX(), &pViewData->GetZoomY(), pDoc));
133 mpFilterButton->setBoundingBox(aScrPos, aScrSize, bLayoutRTL);
134 mpFilterButton->setPopupLeft(bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL
135 Point aPopupPos;
136 Size aPopupSize;
137 mpFilterButton->getPopupBoundingBox(aPopupPos, aPopupSize);
138 Rectangle aRect(aPopupPos, aPopupSize);
139 if (aRect.IsInside(rMEvt.GetPosPixel()))
141 if ( DoPageFieldSelection( nCol, nRow ) )
142 return true;
144 bool bFilterActive = IsAutoFilterActive(nCol, nRow, nTab);
145 mpFilterButton->setHasHiddenMember(bFilterActive);
146 mpFilterButton->setDrawBaseButton(false);
147 mpFilterButton->setDrawPopupButton(true);
148 mpFilterButton->setPopupPressed(true);
149 mpFilterButton->draw();
150 LaunchAutoFilterMenu(nCol, nRow);
151 return true;
154 return false;
157 void ScGridWindow::DoPushPivotButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt, bool bButton, bool bPopup )
159 ScDocument* pDoc = pViewData->GetDocument();
160 SCTAB nTab = pViewData->GetTabNo();
162 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
164 if (pDPObj)
166 sal_uInt16 nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
167 ScAddress aPos( nCol, nRow, nTab );
168 ScAddress aDimPos = aPos;
169 if (!bButton && bPopup && aDimPos.Col() > 0)
170 // For page field selection cell, the real field position is to the left.
171 aDimPos.IncCol(-1);
173 long nField = pDPObj->GetHeaderDim(aDimPos, nOrient);
174 if ( nField >= 0 )
176 bDPMouse = false;
177 nDPField = nField;
178 pDragDPObj = pDPObj;
179 if (bPopup && DPTestFieldPopupArrow(rMEvt, aPos, aDimPos, pDPObj))
181 // field name pop up menu has been launched. Don't activate
182 // field move.
183 return;
186 if (bButton)
188 bDPMouse = true;
189 DPTestMouse( rMEvt, true );
190 StartTracking();
193 else if ( pDPObj->IsFilterButton(aPos) )
195 ReleaseMouse(); // may have been captured in ButtonDown
197 ScQueryParam aQueryParam;
198 SCTAB nSrcTab = 0;
199 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
200 OSL_ENSURE(pDesc, "no sheet source for filter button");
201 if (pDesc)
203 aQueryParam = pDesc->GetQueryParam();
204 nSrcTab = pDesc->GetSourceRange().aStart.Tab();
207 SfxItemSet aArgSet( pViewData->GetViewShell()->GetPool(),
208 SCITEM_QUERYDATA, SCITEM_QUERYDATA );
209 aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA, pViewData, &aQueryParam ) );
211 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
212 OSL_ENSURE(pFact, "ScAbstractFactory create fail!");
214 boost::scoped_ptr<AbstractScPivotFilterDlg> pDlg(pFact->CreateScPivotFilterDlg(
215 pViewData->GetViewShell()->GetDialogParent(), aArgSet, nSrcTab));
216 OSL_ENSURE(pDlg, "Dialog create fail!");
217 if ( pDlg->Execute() == RET_OK )
219 ScSheetSourceDesc aNewDesc(pDoc);
220 if (pDesc)
221 aNewDesc = *pDesc;
223 const ScQueryItem& rQueryItem = pDlg->GetOutputItem();
224 aNewDesc.SetQueryParam(rQueryItem.GetQueryData());
226 ScDPObject aNewObj( *pDPObj );
227 aNewObj.SetSheetDesc( aNewDesc );
228 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
229 aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
230 pViewData->GetView()->CursorPosChanged(); // shells may be switched
234 else
236 OSL_FAIL("Da is ja garnix");
240 // Data Pilot interaction
243 void ScGridWindow::DPTestMouse( const MouseEvent& rMEvt, bool bMove )
245 OSL_ENSURE(pDragDPObj, "pDragDPObj missing");
247 // scroll window if at edges
248 //! move this to separate method
250 bool bTimer = false;
251 Point aPixel = rMEvt.GetPosPixel();
253 SCsCOL nDx = 0;
254 SCsROW nDy = 0;
255 if ( aPixel.X() < 0 )
256 nDx = -1;
257 if ( aPixel.Y() < 0 )
258 nDy = -1;
259 Size aSize = GetOutputSizePixel();
260 if ( aPixel.X() >= aSize.Width() )
261 nDx = 1;
262 if ( aPixel.Y() >= aSize.Height() )
263 nDy = 1;
264 if ( nDx != 0 || nDy != 0 )
266 UpdateDragRect( false, Rectangle() );
268 if ( nDx != 0)
269 pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
270 if ( nDy != 0 )
271 pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
273 bTimer = true;
276 SCsCOL nPosX;
277 SCsROW nPosY;
278 pViewData->GetPosFromPixel( aPixel.X(), aPixel.Y(), eWhich, nPosX, nPosY );
279 bool bMouseLeft;
280 bool bMouseTop;
281 pViewData->GetMouseQuadrant( aPixel, eWhich, nPosX, nPosY, bMouseLeft, bMouseTop );
283 ScAddress aPos( nPosX, nPosY, pViewData->GetTabNo() );
285 Rectangle aPosRect;
286 sal_uInt16 nOrient;
287 long nDimPos;
288 bool bHasRange = pDragDPObj->GetHeaderDrag( aPos, bMouseLeft, bMouseTop, nDPField,
289 aPosRect, nOrient, nDimPos );
290 UpdateDragRect( bHasRange && bMove, aPosRect );
292 bool bIsDataLayout;
293 sal_Int32 nDimFlags = 0;
294 OUString aDimName = pDragDPObj->GetDimName( nDPField, bIsDataLayout, &nDimFlags );
295 bool bAllowed = !bHasRange || ScDPObject::IsOrientationAllowed( nOrient, nDimFlags );
297 if (bMove) // set mouse pointer
299 PointerStyle ePointer = POINTER_PIVOT_DELETE;
300 if ( !bAllowed )
301 ePointer = POINTER_NOTALLOWED;
302 else if ( bHasRange )
303 switch (nOrient)
305 case sheet::DataPilotFieldOrientation_COLUMN: ePointer = POINTER_PIVOT_COL; break;
306 case sheet::DataPilotFieldOrientation_ROW: ePointer = POINTER_PIVOT_ROW; break;
307 case sheet::DataPilotFieldOrientation_PAGE:
308 case sheet::DataPilotFieldOrientation_DATA: ePointer = POINTER_PIVOT_FIELD; break;
310 SetPointer( ePointer );
312 else // execute change
314 if (!bHasRange)
315 nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
317 if ( bIsDataLayout && ( nOrient != sheet::DataPilotFieldOrientation_COLUMN &&
318 nOrient != sheet::DataPilotFieldOrientation_ROW ) )
320 // removing data layout is not allowed
321 pViewData->GetView()->ErrorMessage(STR_PIVOT_MOVENOTALLOWED);
323 else if ( bAllowed )
325 ScDPSaveData aSaveData( *pDragDPObj->GetSaveData() );
327 ScDPSaveDimension* pDim;
328 if ( bIsDataLayout )
329 pDim = aSaveData.GetDataLayoutDimension();
330 else
331 pDim = aSaveData.GetDimensionByName(aDimName);
332 pDim->SetOrientation( nOrient );
333 aSaveData.SetPosition( pDim, nDimPos );
335 //! docfunc method with ScDPSaveData as argument?
337 ScDPObject aNewObj( *pDragDPObj );
338 aNewObj.SetSaveData( aSaveData );
339 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
340 // when dragging fields, allow re-positioning (bAllowMove)
341 aFunc.DataPilotUpdate( pDragDPObj, &aNewObj, true, false, true );
342 pViewData->GetView()->CursorPosChanged(); // shells may be switched
346 if (bTimer && bMove)
347 pViewData->GetView()->SetTimer( this, rMEvt ); // repeat event
348 else
349 pViewData->GetView()->ResetTimer();
352 bool ScGridWindow::DPTestFieldPopupArrow(
353 const MouseEvent& rMEvt, const ScAddress& rPos, const ScAddress& rDimPos, ScDPObject* pDPObj)
355 bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
357 // Get the geometry of the cell.
358 Point aScrPos = pViewData->GetScrPos(rPos.Col(), rPos.Row(), eWhich);
359 long nSizeX, nSizeY;
360 pViewData->GetMergeSizePixel(rPos.Col(), rPos.Row(), nSizeX, nSizeY);
361 Size aScrSize(nSizeX-1, nSizeY-1);
363 // Check if the mouse cursor is clicking on the popup arrow box.
364 ScDPFieldButton aBtn(this, &GetSettings().GetStyleSettings());
365 aBtn.setBoundingBox(aScrPos, aScrSize, bLayoutRTL);
366 aBtn.setPopupLeft(false); // DataPilot popup is always right-aligned for now
367 Point aPopupPos;
368 Size aPopupSize;
369 aBtn.getPopupBoundingBox(aPopupPos, aPopupSize);
370 Rectangle aRect(aPopupPos, aPopupSize);
371 if (aRect.IsInside(rMEvt.GetPosPixel()))
373 // Mouse cursor inside the popup arrow box. Launch the field menu.
374 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, rDimPos, pDPObj);
375 return true;
378 return false;
381 namespace {
383 struct DPFieldPopupData : public ScCheckListMenuWindow::ExtendedData
385 ScDPLabelData maLabels;
386 ScDPObject* mpDPObj;
387 long mnDim;
390 class DPFieldPopupOKAction : public ScMenuFloatingWindow::Action
392 public:
393 explicit DPFieldPopupOKAction(ScGridWindow* p) :
394 mpGridWindow(p) {}
396 virtual void execute() SAL_OVERRIDE
398 mpGridWindow->UpdateDPFromFieldPopupMenu();
400 private:
401 ScGridWindow* mpGridWindow;
404 class PopupSortAction : public ScMenuFloatingWindow::Action
406 public:
407 enum SortType { ASCENDING, DESCENDING, CUSTOM };
409 explicit PopupSortAction(const ScAddress& rPos, SortType eType, sal_uInt16 nUserListIndex, ScTabViewShell* pViewShell) :
410 maPos(rPos), meType(eType), mnUserListIndex(nUserListIndex), mpViewShell(pViewShell) {}
412 virtual void execute() SAL_OVERRIDE
414 switch (meType)
416 case ASCENDING:
417 mpViewShell->DataPilotSort(maPos, true);
418 break;
419 case DESCENDING:
420 mpViewShell->DataPilotSort(maPos, false);
421 break;
422 case CUSTOM:
423 mpViewShell->DataPilotSort(maPos, true, &mnUserListIndex);
424 break;
425 default:
430 private:
431 ScAddress maPos;
432 SortType meType;
433 sal_uInt16 mnUserListIndex;
434 ScTabViewShell* mpViewShell;
439 void ScGridWindow::DPLaunchFieldPopupMenu(
440 const Point& rScrPos, const Size& rScrSize, const ScAddress& rPos, ScDPObject* pDPObj)
442 auto_ptr<DPFieldPopupData> pDPData(new DPFieldPopupData);
443 sal_uInt16 nOrient;
444 pDPData->mnDim = pDPObj->GetHeaderDim(rPos, nOrient);
446 bool bIsDataLayout;
447 OUString aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
448 pDPObj->BuildAllDimensionMembers();
449 const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
450 const ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName(aDimName);
451 if (!pDim)
452 // This should never happen.
453 return;
455 // We need to get the list of field members.
456 pDPObj->FillLabelData(pDPData->mnDim, pDPData->maLabels);
457 pDPData->mpDPObj = pDPObj;
459 const ScDPLabelData& rLabelData = pDPData->maLabels;
461 mpDPFieldPopup.reset(new ScCheckListMenuWindow(this, pViewData->GetDocument()));
462 mpDPFieldPopup->setName("DataPilot field member popup");
463 mpDPFieldPopup->setExtendedData(pDPData.release());
464 mpDPFieldPopup->setOKAction(new DPFieldPopupOKAction(this));
466 // Populate field members.
467 size_t n = rLabelData.maMembers.size();
468 mpDPFieldPopup->setMemberSize(n);
469 for (size_t i = 0; i < n; ++i)
471 const ScDPLabelData::Member& rMem = rLabelData.maMembers[i];
472 OUString aName = rMem.getDisplayName();
473 if (aName.isEmpty())
474 // Use special string for an empty name.
475 mpDPFieldPopup->addMember(ScGlobal::GetRscString(STR_EMPTYDATA), rMem.mbVisible);
476 else
477 mpDPFieldPopup->addMember(rMem.getDisplayName(), rMem.mbVisible);
479 mpDPFieldPopup->initMembers();
482 if (pDim->GetOrientation() != sheet::DataPilotFieldOrientation_PAGE)
484 vector<OUString> aUserSortNames;
485 ScUserList* pUserList = ScGlobal::GetUserList();
486 if (pUserList)
488 size_t n = pUserList->size();
489 aUserSortNames.reserve(n);
490 for (size_t i = 0; i < n; ++i)
492 const ScUserListData* pData = (*pUserList)[i];
493 aUserSortNames.push_back(pData->GetString());
497 // Populate the menus.
498 ScTabViewShell* pViewShell = pViewData->GetViewShell();
499 mpDPFieldPopup->addMenuItem(
500 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_ASC), true,
501 new PopupSortAction(rPos, PopupSortAction::ASCENDING, 0, pViewShell));
502 mpDPFieldPopup->addMenuItem(
503 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_DESC), true,
504 new PopupSortAction(rPos, PopupSortAction::DESCENDING, 0, pViewShell));
505 ScMenuFloatingWindow* pSubMenu = mpDPFieldPopup->addSubMenuItem(
506 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_CUSTOM), !aUserSortNames.empty());
508 if (pSubMenu && !aUserSortNames.empty())
510 size_t n = aUserSortNames.size();
511 for (size_t i = 0; i < n; ++i)
513 pSubMenu->addMenuItem(
514 aUserSortNames[i], true,
515 new PopupSortAction(rPos, PopupSortAction::CUSTOM, static_cast<sal_uInt16>(i), pViewShell));
520 Rectangle aCellRect(rScrPos, rScrSize);
522 mpDPFieldPopup->SetPopupModeEndHdl( LINK(this, ScGridWindow, PopupModeEndHdl) );
523 ScCheckListMenuWindow::Config aConfig;
524 aConfig.mbAllowEmptySet = false;
525 aConfig.mbRTL = pViewData->GetDocument()->IsLayoutRTL(pViewData->GetTabNo());
526 mpDPFieldPopup->setConfig(aConfig);
527 mpDPFieldPopup->launch(aCellRect);
530 void ScGridWindow::UpdateDPFromFieldPopupMenu()
532 typedef boost::unordered_map<OUString, OUString, OUStringHash> MemNameMapType;
534 if (!mpDPFieldPopup)
535 return;
537 DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(mpDPFieldPopup->getExtendedData());
538 if (!pDPData)
539 return;
541 ScDPObject* pDPObj = pDPData->mpDPObj;
542 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
544 bool bIsDataLayout;
545 OUString aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
546 ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aDimName);
547 if (!pDim)
548 return;
550 // Build a map of layout names to original names.
551 const ScDPLabelData& rLabelData = pDPData->maLabels;
552 MemNameMapType aMemNameMap;
553 for (vector<ScDPLabelData::Member>::const_iterator itr = rLabelData.maMembers.begin(), itrEnd = rLabelData.maMembers.end();
554 itr != itrEnd; ++itr)
555 aMemNameMap.insert(MemNameMapType::value_type(itr->maLayoutName, itr->maName));
557 // The raw result may contain a mixture of layout names and original names.
558 ScCheckListMenuWindow::ResultType aRawResult;
559 mpDPFieldPopup->getResult(aRawResult);
561 ScCheckListMenuWindow::ResultType aResult;
562 ScCheckListMenuWindow::ResultType::const_iterator itr = aRawResult.begin(), itrEnd = aRawResult.end();
563 for (; itr != itrEnd; ++itr)
565 MemNameMapType::const_iterator itrNameMap = aMemNameMap.find(itr->first);
566 if (itrNameMap == aMemNameMap.end())
568 // This is an original member name. Use it as-is.
569 OUString aName = itr->first;
570 if (aName.equals(ScGlobal::GetRscString(STR_EMPTYDATA)))
571 // Translate the special empty name into an empty string.
572 aName = OUString();
574 aResult.insert(
575 ScCheckListMenuWindow::ResultType::value_type(
576 aName, itr->second));
578 else
580 // This is a layout name. Get the original member name and use it.
581 aResult.insert(
582 ScCheckListMenuWindow::ResultType::value_type(
583 itrNameMap->second, itr->second));
586 pDim->UpdateMemberVisibility(aResult);
588 ScDBDocFunc aFunc(*pViewData->GetDocShell());
589 aFunc.UpdatePivotTable(*pDPObj, true, false);
592 bool ScGridWindow::UpdateVisibleRange()
594 SCCOL nPosX = pViewData->GetPosX(eHWhich);
595 SCROW nPosY = pViewData->GetPosY(eVWhich);
596 SCCOL nXRight = nPosX + pViewData->VisibleCellsX(eHWhich);
597 if (nXRight > MAXCOL) nXRight = MAXCOL;
598 SCROW nYBottom = nPosY + pViewData->VisibleCellsY(eVWhich);
599 if (nYBottom > MAXROW) nYBottom = MAXROW;
601 // Store the current visible range.
602 bool bChanged = maVisibleRange.set(nPosX, nPosY, nXRight, nYBottom);
603 if (bChanged)
604 ResetAutoSpell();
606 return bChanged;
609 void ScGridWindow::DPMouseMove( const MouseEvent& rMEvt )
611 DPTestMouse( rMEvt, true );
614 void ScGridWindow::DPMouseButtonUp( const MouseEvent& rMEvt )
616 bDPMouse = false;
617 ReleaseMouse();
619 DPTestMouse( rMEvt, false );
620 SetPointer( Pointer( POINTER_ARROW ) );
623 void ScGridWindow::UpdateDragRect( bool bShowRange, const Rectangle& rPosRect )
625 SCCOL nStartX = ( rPosRect.Left() >= 0 ) ? static_cast<SCCOL>(rPosRect.Left()) : SCCOL_MAX;
626 SCROW nStartY = ( rPosRect.Top() >= 0 ) ? static_cast<SCROW>(rPosRect.Top()) : SCROW_MAX;
627 SCCOL nEndX = ( rPosRect.Right() >= 0 ) ? static_cast<SCCOL>(rPosRect.Right()) : SCCOL_MAX;
628 SCROW nEndY = ( rPosRect.Bottom() >= 0 ) ? static_cast<SCROW>(rPosRect.Bottom()) : SCROW_MAX;
630 if ( bShowRange == bDragRect && nDragStartX == nStartX && nDragEndX == nEndX &&
631 nDragStartY == nStartY && nDragEndY == nEndY )
633 return; // everything unchanged
636 if ( bShowRange )
638 nDragStartX = nStartX;
639 nDragStartY = nStartY;
640 nDragEndX = nEndX;
641 nDragEndY = nEndY;
642 bDragRect = true;
644 else
645 bDragRect = false;
647 UpdateDragRectOverlay();
650 // Page-Break-Modus
652 sal_uInt16 ScGridWindow::HitPageBreak( const Point& rMouse, ScRange* pSource,
653 SCCOLROW* pBreak, SCCOLROW* pPrev )
655 sal_uInt16 nFound = SC_PD_NONE; // 0
656 ScRange aSource;
657 SCCOLROW nBreak = 0;
658 SCCOLROW nPrev = 0;
660 ScPageBreakData* pPageData = pViewData->GetView()->GetPageBreakData();
661 if ( pPageData )
663 bool bHori = false;
664 bool bVert = false;
665 SCCOL nHitX = 0;
666 SCROW nHitY = 0;
668 long nMouseX = rMouse.X();
669 long nMouseY = rMouse.Y();
670 SCsCOL nPosX;
671 SCsROW nPosY;
672 pViewData->GetPosFromPixel( nMouseX, nMouseY, eWhich, nPosX, nPosY );
673 Point aTL = pViewData->GetScrPos( nPosX, nPosY, eWhich );
674 Point aBR = pViewData->GetScrPos( nPosX+1, nPosY+1, eWhich );
676 // Horizontal mehr Toleranz als vertikal, weil mehr Platz ist
677 if ( nMouseX <= aTL.X() + 4 )
679 bHori = true;
680 nHitX = nPosX;
682 else if ( nMouseX >= aBR.X() - 6 )
684 bHori = true;
685 nHitX = nPosX+1; // linker Rand der naechsten Zelle
687 if ( nMouseY <= aTL.Y() + 2 )
689 bVert = true;
690 nHitY = nPosY;
692 else if ( nMouseY >= aBR.Y() - 4 )
694 bVert = true;
695 nHitY = nPosY+1; // oberer Rand der naechsten Zelle
698 if ( bHori || bVert )
700 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
701 for (sal_uInt16 nPos=0; nPos<nCount && !nFound; nPos++)
703 ScPrintRangeData& rData = pPageData->GetData(nPos);
704 ScRange aRange = rData.GetPrintRange();
705 bool bLHit = ( bHori && nHitX == aRange.aStart.Col() );
706 bool bRHit = ( bHori && nHitX == aRange.aEnd.Col() + 1 );
707 bool bTHit = ( bVert && nHitY == aRange.aStart.Row() );
708 bool bBHit = ( bVert && nHitY == aRange.aEnd.Row() + 1 );
709 bool bInsideH = ( nPosX >= aRange.aStart.Col() && nPosX <= aRange.aEnd.Col() );
710 bool bInsideV = ( nPosY >= aRange.aStart.Row() && nPosY <= aRange.aEnd.Row() );
712 if ( bLHit )
714 if ( bTHit )
715 nFound = SC_PD_RANGE_TL;
716 else if ( bBHit )
717 nFound = SC_PD_RANGE_BL;
718 else if ( bInsideV )
719 nFound = SC_PD_RANGE_L;
721 else if ( bRHit )
723 if ( bTHit )
724 nFound = SC_PD_RANGE_TR;
725 else if ( bBHit )
726 nFound = SC_PD_RANGE_BR;
727 else if ( bInsideV )
728 nFound = SC_PD_RANGE_R;
730 else if ( bTHit && bInsideH )
731 nFound = SC_PD_RANGE_T;
732 else if ( bBHit && bInsideH )
733 nFound = SC_PD_RANGE_B;
734 if (nFound)
735 aSource = aRange;
737 // Umbrueche
739 if ( bVert && bInsideH && !nFound )
741 size_t nRowCount = rData.GetPagesY();
742 const SCROW* pRowEnd = rData.GetPageEndY();
743 for (size_t nRowPos=0; nRowPos+1<nRowCount; nRowPos++)
744 if ( pRowEnd[nRowPos]+1 == nHitY )
746 nFound = SC_PD_BREAK_V;
747 aSource = aRange;
748 nBreak = nHitY;
749 if ( nRowPos )
750 nPrev = pRowEnd[nRowPos-1]+1;
751 else
752 nPrev = aRange.aStart.Row();
755 if ( bHori && bInsideV && !nFound )
757 size_t nColCount = rData.GetPagesX();
758 const SCCOL* pColEnd = rData.GetPageEndX();
759 for (size_t nColPos=0; nColPos+1<nColCount; nColPos++)
760 if ( pColEnd[nColPos]+1 == nHitX )
762 nFound = SC_PD_BREAK_H;
763 aSource = aRange;
764 nBreak = nHitX;
765 if ( nColPos )
766 nPrev = pColEnd[nColPos-1]+1;
767 else
768 nPrev = aRange.aStart.Col();
775 if (pSource)
776 *pSource = aSource; // Druckbereich
777 if (pBreak)
778 *pBreak = nBreak; // X/Y Position des verchobenen Seitenumbruchs
779 if (pPrev)
780 *pPrev = nPrev; // X/Y Anfang der Seite, die am Umbruch zuende ist
781 return nFound;
784 void ScGridWindow::PagebreakMove( const MouseEvent& rMEvt, bool bUp )
786 //! Scrolling und Umschalten mit RFMouseMove zusammenfassen !
787 //! (Weginvertieren vor dem Scrolling ist anders)
789 // Scrolling
791 bool bTimer = false;
792 Point aPos = rMEvt.GetPosPixel();
793 SCsCOL nDx = 0;
794 SCsROW nDy = 0;
795 if ( aPos.X() < 0 ) nDx = -1;
796 if ( aPos.Y() < 0 ) nDy = -1;
797 Size aSize = GetOutputSizePixel();
798 if ( aPos.X() >= aSize.Width() )
799 nDx = 1;
800 if ( aPos.Y() >= aSize.Height() )
801 nDy = 1;
802 if ( nDx != 0 || nDy != 0 )
804 if ( bPagebreakDrawn ) // weginvertieren
806 bPagebreakDrawn = false;
807 UpdateDragRectOverlay();
810 if ( nDx != 0 ) pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
811 if ( nDy != 0 ) pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
812 bTimer = true;
815 // Umschalten bei Fixierung (damit Scrolling funktioniert)
817 if ( eWhich == pViewData->GetActivePart() ) //??
819 if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
820 if ( nDx > 0 )
822 if ( eWhich == SC_SPLIT_TOPLEFT )
823 pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
824 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
825 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
828 if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
829 if ( nDy > 0 )
831 if ( eWhich == SC_SPLIT_TOPLEFT )
832 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
833 else if ( eWhich == SC_SPLIT_TOPRIGHT )
834 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
838 // ab hier neu
840 // gesucht wird eine Position zwischen den Zellen (vor nPosX / nPosY)
841 SCsCOL nPosX;
842 SCsROW nPosY;
843 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
844 bool bLeft, bTop;
845 pViewData->GetMouseQuadrant( aPos, eWhich, nPosX, nPosY, bLeft, bTop );
846 if ( !bLeft ) ++nPosX;
847 if ( !bTop ) ++nPosY;
849 bool bBreak = ( nPagebreakMouse == SC_PD_BREAK_H || nPagebreakMouse == SC_PD_BREAK_V );
850 bool bHide = false;
851 bool bToEnd = false;
852 ScRange aDrawRange = aPagebreakSource;
853 if ( bBreak )
855 if ( nPagebreakMouse == SC_PD_BREAK_H )
857 if ( nPosX > aPagebreakSource.aStart.Col() &&
858 nPosX <= aPagebreakSource.aEnd.Col() + 1 ) // ans Ende ist auch erlaubt
860 bToEnd = ( nPosX == aPagebreakSource.aEnd.Col() + 1 );
861 aDrawRange.aStart.SetCol( nPosX );
862 aDrawRange.aEnd.SetCol( nPosX - 1 );
864 else
865 bHide = true;
867 else
869 if ( nPosY > aPagebreakSource.aStart.Row() &&
870 nPosY <= aPagebreakSource.aEnd.Row() + 1 ) // ans Ende ist auch erlaubt
872 bToEnd = ( nPosY == aPagebreakSource.aEnd.Row() + 1 );
873 aDrawRange.aStart.SetRow( nPosY );
874 aDrawRange.aEnd.SetRow( nPosY - 1 );
876 else
877 bHide = true;
880 else
882 if ( nPagebreakMouse & SC_PD_RANGE_L )
883 aDrawRange.aStart.SetCol( nPosX );
884 if ( nPagebreakMouse & SC_PD_RANGE_T )
885 aDrawRange.aStart.SetRow( nPosY );
886 if ( nPagebreakMouse & SC_PD_RANGE_R )
888 if ( nPosX > 0 )
889 aDrawRange.aEnd.SetCol( nPosX-1 );
890 else
891 bHide = true;
893 if ( nPagebreakMouse & SC_PD_RANGE_B )
895 if ( nPosY > 0 )
896 aDrawRange.aEnd.SetRow( nPosY-1 );
897 else
898 bHide = true;
900 if ( aDrawRange.aStart.Col() > aDrawRange.aEnd.Col() ||
901 aDrawRange.aStart.Row() > aDrawRange.aEnd.Row() )
902 bHide = true;
905 if ( !bPagebreakDrawn || bUp || aDrawRange != aPagebreakDrag )
907 // zeichnen...
909 if ( bPagebreakDrawn )
911 // weginvertieren
912 bPagebreakDrawn = false;
914 aPagebreakDrag = aDrawRange;
915 if ( !bUp && !bHide )
917 // hininvertieren
918 bPagebreakDrawn = true;
920 UpdateDragRectOverlay();
923 // bei ButtonUp die Aenderung ausfuehren
925 if ( bUp )
927 ScViewFunc* pViewFunc = pViewData->GetView();
928 ScDocShell* pDocSh = pViewData->GetDocShell();
929 ScDocument* pDoc = pDocSh->GetDocument();
930 SCTAB nTab = pViewData->GetTabNo();
931 bool bUndo (pDoc->IsUndoEnabled());
933 if ( bBreak )
935 bool bColumn = ( nPagebreakMouse == SC_PD_BREAK_H );
936 SCCOLROW nNew = bColumn ? static_cast<SCCOLROW>(nPosX) : static_cast<SCCOLROW>(nPosY);
937 if ( nNew != nPagebreakBreak )
939 if (bUndo)
941 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_DRAG_BREAK );
942 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
945 bool bGrow = !bHide && nNew > nPagebreakBreak;
946 if ( bColumn )
948 if (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakBreak), nTab) & BREAK_MANUAL)
950 ScAddress aOldAddr( static_cast<SCCOL>(nPagebreakBreak), nPosY, nTab );
951 pViewFunc->DeletePageBreak( true, true, &aOldAddr, false );
953 if ( !bHide && !bToEnd ) // am Ende nicht
955 ScAddress aNewAddr( static_cast<SCCOL>(nNew), nPosY, nTab );
956 pViewFunc->InsertPageBreak( true, true, &aNewAddr, false );
958 if ( bGrow )
960 // vorigen Break auf hart, und Skalierung aendern
961 bool bManualBreak = (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakPrev), nTab) & BREAK_MANUAL);
962 if ( static_cast<SCCOL>(nPagebreakPrev) > aPagebreakSource.aStart.Col() && !bManualBreak )
964 ScAddress aPrev( static_cast<SCCOL>(nPagebreakPrev), nPosY, nTab );
965 pViewFunc->InsertPageBreak( true, true, &aPrev, false );
968 if (!pDocSh->AdjustPrintZoom( ScRange(
969 static_cast<SCCOL>(nPagebreakPrev),0,nTab, static_cast<SCCOL>(nNew-1),0,nTab ) ))
970 bGrow = false;
973 else
975 if (pDoc->HasRowBreak(nPagebreakBreak, nTab) & BREAK_MANUAL)
977 ScAddress aOldAddr( nPosX, nPagebreakBreak, nTab );
978 pViewFunc->DeletePageBreak( false, true, &aOldAddr, false );
980 if ( !bHide && !bToEnd ) // am Ende nicht
982 ScAddress aNewAddr( nPosX, nNew, nTab );
983 pViewFunc->InsertPageBreak( false, true, &aNewAddr, false );
985 if ( bGrow )
987 // vorigen Break auf hart, und Skalierung aendern
988 bool bManualBreak = (pDoc->HasRowBreak(nPagebreakPrev, nTab) & BREAK_MANUAL);
989 if ( nPagebreakPrev > aPagebreakSource.aStart.Row() && !bManualBreak )
991 ScAddress aPrev( nPosX, nPagebreakPrev, nTab );
992 pViewFunc->InsertPageBreak( false, true, &aPrev, false );
995 if (!pDocSh->AdjustPrintZoom( ScRange(
996 0,nPagebreakPrev,nTab, 0,nNew-1,nTab ) ))
997 bGrow = false;
1001 if (bUndo)
1003 pDocSh->GetUndoManager()->LeaveListAction();
1006 if (!bGrow) // sonst in AdjustPrintZoom schon passiert
1008 pViewFunc->UpdatePageBreakData( true );
1009 pDocSh->SetDocumentModified();
1013 else if ( bHide || aPagebreakDrag != aPagebreakSource )
1015 // Druckbereich setzen
1017 OUString aNewRanges;
1018 sal_uInt16 nOldCount = pDoc->GetPrintRangeCount( nTab );
1019 if ( nOldCount )
1021 for (sal_uInt16 nPos=0; nPos<nOldCount; nPos++)
1023 const ScRange* pOld = pDoc->GetPrintRange( nTab, nPos );
1024 if ( pOld )
1026 OUString aTemp;
1027 if ( *pOld != aPagebreakSource )
1028 aTemp = pOld->Format(SCA_VALID);
1029 else if ( !bHide )
1030 aTemp = aPagebreakDrag.Format(SCA_VALID);
1031 if (!aTemp.isEmpty())
1033 if ( !aNewRanges.isEmpty() )
1034 aNewRanges += ";";
1035 aNewRanges += aTemp;
1040 else if (!bHide)
1041 aNewRanges = aPagebreakDrag.Format(SCA_VALID);
1043 pViewFunc->SetPrintRanges( pDoc->IsPrintEntireSheet( nTab ), &aNewRanges, NULL, NULL, false );
1047 // Timer fuer Scrolling
1049 if (bTimer && !bUp)
1050 pViewData->GetView()->SetTimer( this, rMEvt ); // Event wiederholen
1051 else
1052 pViewData->GetView()->ResetTimer();
1056 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */