fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / view / gridwin2.cxx
blobcd7d66d8883050bbedc1b6f313bffd367cb2faad
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 <unordered_map>
50 #include <vector>
52 using namespace css;
53 using namespace css::sheet;
54 using css::sheet::DataPilotFieldOrientation;
55 using std::vector;
56 using std::unique_ptr;
58 // STATIC DATA -----------------------------------------------------------
60 DataPilotFieldOrientation ScGridWindow::GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const
62 ScDocument* pDoc = pViewData->GetDocument();
63 SCTAB nTab = pViewData->GetTabNo();
64 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
65 if (!pDPObj)
66 return DataPilotFieldOrientation_HIDDEN;
68 sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN;
70 // Check for page field first.
71 if (nCol > 0)
73 // look for the dimension header left of the drop-down arrow
74 long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient );
75 if ( nField >= 0 && nOrient == DataPilotFieldOrientation_PAGE )
77 bool bIsDataLayout = false;
78 OUString aFieldName = pDPObj->GetDimName( nField, bIsDataLayout );
79 if ( !aFieldName.isEmpty() && !bIsDataLayout )
80 return DataPilotFieldOrientation_PAGE;
84 nOrient = DataPilotFieldOrientation_HIDDEN;
86 // Now, check for row/column field.
87 long nField = pDPObj->GetHeaderDim(ScAddress(nCol, nRow, nTab), nOrient);
88 if (nField >= 0 && (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) )
90 bool bIsDataLayout = false;
91 OUString aFieldName = pDPObj->GetDimName(nField, bIsDataLayout);
92 if (!aFieldName.isEmpty() && !bIsDataLayout)
93 return static_cast<DataPilotFieldOrientation>(nOrient);
96 return DataPilotFieldOrientation_HIDDEN;
99 // private method for mouse button handling
100 bool ScGridWindow::DoPageFieldSelection( SCCOL nCol, SCROW nRow )
102 if (GetDPFieldOrientation( nCol, nRow ) == DataPilotFieldOrientation_PAGE)
104 LaunchPageFieldMenu( nCol, nRow );
105 return true;
107 return false;
110 bool ScGridWindow::DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt )
112 ScDocument* pDoc = pViewData->GetDocument();
113 SCTAB nTab = pViewData->GetTabNo();
114 Point aScrPos = pViewData->GetScrPos(nCol, nRow, eWhich);
115 Point aDiffPix = rMEvt.GetPosPixel();
117 aDiffPix -= aScrPos;
118 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
119 if ( bLayoutRTL )
120 aDiffPix.X() = -aDiffPix.X();
122 long nSizeX, nSizeY;
123 pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
124 // The button height should not use the merged cell height, should still use single row height
125 nSizeY = ScViewData::ToPixel(pDoc->GetRowHeight(nRow, nTab), pViewData->GetPPTY());
126 Size aScrSize(nSizeX-1, nSizeY-1);
128 // Check if the mouse cursor is clicking on the popup arrow box.
129 mpFilterButton.reset(new ScDPFieldButton(this, &GetSettings().GetStyleSettings(), &pViewData->GetZoomX(), &pViewData->GetZoomY(), pDoc));
130 mpFilterButton->setBoundingBox(aScrPos, aScrSize, bLayoutRTL);
131 mpFilterButton->setPopupLeft(bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL
132 Point aPopupPos;
133 Size aPopupSize;
134 mpFilterButton->getPopupBoundingBox(aPopupPos, aPopupSize);
135 Rectangle aRect(aPopupPos, aPopupSize);
136 if (aRect.IsInside(rMEvt.GetPosPixel()))
138 if ( DoPageFieldSelection( nCol, nRow ) )
139 return true;
141 bool bFilterActive = IsAutoFilterActive(nCol, nRow, nTab);
142 mpFilterButton->setHasHiddenMember(bFilterActive);
143 mpFilterButton->setDrawBaseButton(false);
144 mpFilterButton->setDrawPopupButton(true);
145 mpFilterButton->setPopupPressed(true);
146 mpFilterButton->draw();
147 LaunchAutoFilterMenu(nCol, nRow);
148 return true;
151 return false;
154 void ScGridWindow::DoPushPivotButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt, bool bButton, bool bPopup )
156 ScDocument* pDoc = pViewData->GetDocument();
157 SCTAB nTab = pViewData->GetTabNo();
159 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
161 if (pDPObj)
163 sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN;
164 ScAddress aPos( nCol, nRow, nTab );
165 ScAddress aDimPos = aPos;
166 if (!bButton && bPopup && aDimPos.Col() > 0)
167 // For page field selection cell, the real field position is to the left.
168 aDimPos.IncCol(-1);
170 long nField = pDPObj->GetHeaderDim(aDimPos, nOrient);
171 if ( nField >= 0 )
173 bDPMouse = false;
174 nDPField = nField;
175 pDragDPObj = pDPObj;
176 if (bPopup && DPTestFieldPopupArrow(rMEvt, aPos, aDimPos, pDPObj))
178 // field name pop up menu has been launched. Don't activate
179 // field move.
180 return;
183 if (bButton)
185 bDPMouse = true;
186 DPTestMouse( rMEvt, true );
187 StartTracking();
190 else if ( pDPObj->IsFilterButton(aPos) )
192 ReleaseMouse(); // may have been captured in ButtonDown
194 ScQueryParam aQueryParam;
195 SCTAB nSrcTab = 0;
196 const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
197 OSL_ENSURE(pDesc, "no sheet source for filter button");
198 if (pDesc)
200 aQueryParam = pDesc->GetQueryParam();
201 nSrcTab = pDesc->GetSourceRange().aStart.Tab();
204 SfxItemSet aArgSet( pViewData->GetViewShell()->GetPool(),
205 SCITEM_QUERYDATA, SCITEM_QUERYDATA );
206 aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA, pViewData, &aQueryParam ) );
208 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
209 OSL_ENSURE(pFact, "ScAbstractFactory create fail!");
211 const std::unique_ptr<AbstractScPivotFilterDlg> pDlg(
212 pFact->CreateScPivotFilterDlg(
213 pViewData->GetViewShell()->GetDialogParent(), aArgSet, nSrcTab));
214 OSL_ENSURE(pDlg, "Dialog create fail!");
215 if ( pDlg->Execute() == RET_OK )
217 ScSheetSourceDesc aNewDesc(pDoc);
218 if (pDesc)
219 aNewDesc = *pDesc;
221 const ScQueryItem& rQueryItem = pDlg->GetOutputItem();
222 aNewDesc.SetQueryParam(rQueryItem.GetQueryData());
224 ScDPObject aNewObj( *pDPObj );
225 aNewObj.SetSheetDesc( aNewDesc );
226 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
227 aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
228 pViewData->GetView()->CursorPosChanged(); // shells may be switched
232 else
234 OSL_FAIL("Da is ja garnix");
238 // Data Pilot interaction
240 void ScGridWindow::DPTestMouse( const MouseEvent& rMEvt, bool bMove )
242 OSL_ENSURE(pDragDPObj, "pDragDPObj missing");
244 // scroll window if at edges
245 //! move this to separate method
247 bool bTimer = false;
248 Point aPixel = rMEvt.GetPosPixel();
250 SCsCOL nDx = 0;
251 SCsROW nDy = 0;
252 if ( aPixel.X() < 0 )
253 nDx = -1;
254 if ( aPixel.Y() < 0 )
255 nDy = -1;
256 Size aSize = GetOutputSizePixel();
257 if ( aPixel.X() >= aSize.Width() )
258 nDx = 1;
259 if ( aPixel.Y() >= aSize.Height() )
260 nDy = 1;
261 if ( nDx != 0 || nDy != 0 )
263 UpdateDragRect( false, Rectangle() );
265 if ( nDx != 0)
266 pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
267 if ( nDy != 0 )
268 pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
270 bTimer = true;
273 SCsCOL nPosX;
274 SCsROW nPosY;
275 pViewData->GetPosFromPixel( aPixel.X(), aPixel.Y(), eWhich, nPosX, nPosY );
276 bool bMouseLeft;
277 bool bMouseTop;
278 pViewData->GetMouseQuadrant( aPixel, eWhich, nPosX, nPosY, bMouseLeft, bMouseTop );
280 ScAddress aPos( nPosX, nPosY, pViewData->GetTabNo() );
282 Rectangle aPosRect;
283 sal_uInt16 nOrient;
284 long nDimPos;
285 bool bHasRange = pDragDPObj->GetHeaderDrag( aPos, bMouseLeft, bMouseTop, nDPField,
286 aPosRect, nOrient, nDimPos );
287 UpdateDragRect( bHasRange && bMove, aPosRect );
289 bool bIsDataLayout;
290 sal_Int32 nDimFlags = 0;
291 OUString aDimName = pDragDPObj->GetDimName( nDPField, bIsDataLayout, &nDimFlags );
292 bool bAllowed = !bHasRange || ScDPObject::IsOrientationAllowed( nOrient, nDimFlags );
294 if (bMove) // set mouse pointer
296 PointerStyle ePointer = PointerStyle::PivotDelete;
297 if ( !bAllowed )
298 ePointer = PointerStyle::NotAllowed;
299 else if ( bHasRange )
300 switch (nOrient)
302 case DataPilotFieldOrientation_COLUMN: ePointer = PointerStyle::PivotCol; break;
303 case DataPilotFieldOrientation_ROW: ePointer = PointerStyle::PivotRow; break;
304 case DataPilotFieldOrientation_PAGE:
305 case DataPilotFieldOrientation_DATA: ePointer = PointerStyle::PivotField; break;
307 SetPointer( ePointer );
309 else // execute change
311 if (!bHasRange)
312 nOrient = DataPilotFieldOrientation_HIDDEN;
314 if ( bIsDataLayout && ( nOrient != DataPilotFieldOrientation_COLUMN &&
315 nOrient != DataPilotFieldOrientation_ROW ) )
317 // removing data layout is not allowed
318 pViewData->GetView()->ErrorMessage(STR_PIVOT_MOVENOTALLOWED);
320 else if ( bAllowed )
322 ScDPSaveData aSaveData( *pDragDPObj->GetSaveData() );
324 ScDPSaveDimension* pDim;
325 if ( bIsDataLayout )
326 pDim = aSaveData.GetDataLayoutDimension();
327 else
328 pDim = aSaveData.GetDimensionByName(aDimName);
329 pDim->SetOrientation( nOrient );
330 aSaveData.SetPosition( pDim, nDimPos );
332 //! docfunc method with ScDPSaveData as argument?
334 ScDPObject aNewObj( *pDragDPObj );
335 aNewObj.SetSaveData( aSaveData );
336 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
337 // when dragging fields, allow re-positioning (bAllowMove)
338 aFunc.DataPilotUpdate( pDragDPObj, &aNewObj, true, false, true );
339 pViewData->GetView()->CursorPosChanged(); // shells may be switched
343 if (bTimer && bMove)
344 pViewData->GetView()->SetTimer( this, rMEvt ); // repeat event
345 else
346 pViewData->GetView()->ResetTimer();
349 bool ScGridWindow::DPTestFieldPopupArrow(
350 const MouseEvent& rMEvt, const ScAddress& rPos, const ScAddress& rDimPos, ScDPObject* pDPObj)
352 bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
354 // Get the geometry of the cell.
355 Point aScrPos = pViewData->GetScrPos(rPos.Col(), rPos.Row(), eWhich);
356 long nSizeX, nSizeY;
357 pViewData->GetMergeSizePixel(rPos.Col(), rPos.Row(), nSizeX, nSizeY);
358 Size aScrSize(nSizeX-1, nSizeY-1);
360 // Check if the mouse cursor is clicking on the popup arrow box.
361 ScDPFieldButton aBtn(this, &GetSettings().GetStyleSettings());
362 aBtn.setBoundingBox(aScrPos, aScrSize, bLayoutRTL);
363 aBtn.setPopupLeft(false); // DataPilot popup is always right-aligned for now
364 Point aPopupPos;
365 Size aPopupSize;
366 aBtn.getPopupBoundingBox(aPopupPos, aPopupSize);
367 Rectangle aRect(aPopupPos, aPopupSize);
368 if (aRect.IsInside(rMEvt.GetPosPixel()))
370 // Mouse cursor inside the popup arrow box. Launch the field menu.
371 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, rDimPos, pDPObj);
372 return true;
375 return false;
378 namespace {
380 struct DPFieldPopupData : public ScCheckListMenuWindow::ExtendedData
382 ScDPLabelData maLabels;
383 ScDPObject* mpDPObj;
384 long mnDim;
387 class DPFieldPopupOKAction : public ScMenuFloatingWindow::Action
389 public:
390 explicit DPFieldPopupOKAction(ScGridWindow* p) :
391 mpGridWindow(p) {}
393 virtual void execute() SAL_OVERRIDE
395 mpGridWindow->UpdateDPFromFieldPopupMenu();
397 private:
398 VclPtr<ScGridWindow> mpGridWindow;
401 class PopupSortAction : public ScMenuFloatingWindow::Action
403 public:
404 enum SortType { ASCENDING, DESCENDING, CUSTOM };
406 explicit PopupSortAction(const ScAddress& rPos, SortType eType, sal_uInt16 nUserListIndex, ScTabViewShell* pViewShell) :
407 maPos(rPos), meType(eType), mnUserListIndex(nUserListIndex), mpViewShell(pViewShell) {}
409 virtual void execute() SAL_OVERRIDE
411 switch (meType)
413 case ASCENDING:
414 mpViewShell->DataPilotSort(maPos, true);
415 break;
416 case DESCENDING:
417 mpViewShell->DataPilotSort(maPos, false);
418 break;
419 case CUSTOM:
420 mpViewShell->DataPilotSort(maPos, true, &mnUserListIndex);
421 break;
422 default:
427 private:
428 ScAddress maPos;
429 SortType meType;
430 sal_uInt16 mnUserListIndex;
431 ScTabViewShell* mpViewShell;
436 void ScGridWindow::DPLaunchFieldPopupMenu(
437 const Point& rScrPos, const Size& rScrSize, const ScAddress& rPos, ScDPObject* pDPObj)
439 unique_ptr<DPFieldPopupData> pDPData(new DPFieldPopupData);
440 sal_uInt16 nOrient;
441 pDPData->mnDim = pDPObj->GetHeaderDim(rPos, nOrient);
443 bool bIsDataLayout;
444 OUString aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
445 pDPObj->BuildAllDimensionMembers();
446 const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
447 const ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName(aDimName);
448 if (!pDim)
449 // This should never happen.
450 return;
452 // We need to get the list of field members.
453 pDPObj->FillLabelData(pDPData->mnDim, pDPData->maLabels);
454 pDPData->mpDPObj = pDPObj;
456 const ScDPLabelData& rLabelData = pDPData->maLabels;
458 mpDPFieldPopup.disposeAndClear();
459 mpDPFieldPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pViewData->GetDocument()));
460 mpDPFieldPopup->setName("DataPilot field member popup");
461 mpDPFieldPopup->setExtendedData(pDPData.release());
462 mpDPFieldPopup->setOKAction(new DPFieldPopupOKAction(this));
464 // Populate field members.
465 size_t n = rLabelData.maMembers.size();
466 mpDPFieldPopup->setMemberSize(n);
467 for (size_t i = 0; i < n; ++i)
469 const ScDPLabelData::Member& rMem = rLabelData.maMembers[i];
470 OUString aName = rMem.getDisplayName();
471 if (aName.isEmpty())
472 // Use special string for an empty name.
473 mpDPFieldPopup->addMember(ScGlobal::GetRscString(STR_EMPTYDATA), rMem.mbVisible);
474 else
475 mpDPFieldPopup->addMember(rMem.getDisplayName(), rMem.mbVisible);
477 mpDPFieldPopup->initMembers();
480 if (pDim->GetOrientation() != DataPilotFieldOrientation_PAGE)
482 vector<OUString> aUserSortNames;
483 ScUserList* pUserList = ScGlobal::GetUserList();
484 if (pUserList)
486 size_t n = pUserList->size();
487 aUserSortNames.reserve(n);
488 for (size_t i = 0; i < n; ++i)
490 const ScUserListData* pData = (*pUserList)[i];
491 aUserSortNames.push_back(pData->GetString());
495 // Populate the menus.
496 ScTabViewShell* pViewShell = pViewData->GetViewShell();
497 mpDPFieldPopup->addMenuItem(
498 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_ASC), true,
499 new PopupSortAction(rPos, PopupSortAction::ASCENDING, 0, pViewShell));
500 mpDPFieldPopup->addMenuItem(
501 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_DESC), true,
502 new PopupSortAction(rPos, PopupSortAction::DESCENDING, 0, pViewShell));
503 ScMenuFloatingWindow* pSubMenu = mpDPFieldPopup->addSubMenuItem(
504 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_CUSTOM), !aUserSortNames.empty());
506 if (pSubMenu && !aUserSortNames.empty())
508 size_t n = aUserSortNames.size();
509 for (size_t i = 0; i < n; ++i)
511 pSubMenu->addMenuItem(
512 aUserSortNames[i], true,
513 new PopupSortAction(rPos, PopupSortAction::CUSTOM, static_cast<sal_uInt16>(i), pViewShell));
518 Rectangle aCellRect(rScrPos, rScrSize);
520 mpDPFieldPopup->SetPopupModeEndHdl( LINK(this, ScGridWindow, PopupModeEndHdl) );
521 ScCheckListMenuWindow::Config aConfig;
522 aConfig.mbAllowEmptySet = false;
523 aConfig.mbRTL = pViewData->GetDocument()->IsLayoutRTL(pViewData->GetTabNo());
524 mpDPFieldPopup->setConfig(aConfig);
525 mpDPFieldPopup->launch(aCellRect);
528 void ScGridWindow::UpdateDPFromFieldPopupMenu()
530 typedef std::unordered_map<OUString, OUString, OUStringHash> MemNameMapType;
532 if (!mpDPFieldPopup)
533 return;
535 DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(mpDPFieldPopup->getExtendedData());
536 if (!pDPData)
537 return;
539 ScDPObject* pDPObj = pDPData->mpDPObj;
540 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
542 bool bIsDataLayout;
543 OUString aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
544 ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aDimName);
545 if (!pDim)
546 return;
548 // Build a map of layout names to original names.
549 const ScDPLabelData& rLabelData = pDPData->maLabels;
550 MemNameMapType aMemNameMap;
551 for (vector<ScDPLabelData::Member>::const_iterator itr = rLabelData.maMembers.begin(), itrEnd = rLabelData.maMembers.end();
552 itr != itrEnd; ++itr)
553 aMemNameMap.insert(MemNameMapType::value_type(itr->maLayoutName, itr->maName));
555 // The raw result may contain a mixture of layout names and original names.
556 ScCheckListMenuWindow::ResultType aRawResult;
557 mpDPFieldPopup->getResult(aRawResult);
559 ScCheckListMenuWindow::ResultType aResult;
560 ScCheckListMenuWindow::ResultType::const_iterator itr = aRawResult.begin(), itrEnd = aRawResult.end();
561 for (; itr != itrEnd; ++itr)
563 MemNameMapType::const_iterator itrNameMap = aMemNameMap.find(itr->first);
564 if (itrNameMap == aMemNameMap.end())
566 // This is an original member name. Use it as-is.
567 OUString aName = itr->first;
568 if (aName.equals(ScGlobal::GetRscString(STR_EMPTYDATA)))
569 // Translate the special empty name into an empty string.
570 aName.clear();
572 aResult.insert(
573 ScCheckListMenuWindow::ResultType::value_type(
574 aName, itr->second));
576 else
578 // This is a layout name. Get the original member name and use it.
579 aResult.insert(
580 ScCheckListMenuWindow::ResultType::value_type(
581 itrNameMap->second, itr->second));
584 pDim->UpdateMemberVisibility(aResult);
586 ScDBDocFunc aFunc(*pViewData->GetDocShell());
587 aFunc.UpdatePivotTable(*pDPObj, true, false);
590 bool ScGridWindow::UpdateVisibleRange()
592 ScDocument& rDoc = pViewData->GetDocShell()->GetDocument();
594 SCCOL nPosX = 0;
595 SCROW nPosY = 0;
596 SCCOL nXRight = MAXCOL;
597 SCROW nYBottom = MAXROW;
599 if (rDoc.GetDrawLayer()->isTiledRendering())
601 // entire table in the tiled rendering case
602 SCTAB nTab = pViewData->GetTabNo();
603 SCCOL nEndCol = 0;
604 SCROW nEndRow = 0;
606 if (rDoc.GetPrintArea(nTab, nEndCol, nEndRow, false))
608 nXRight = nEndCol;
609 nYBottom = nEndRow;
612 else
614 nPosX = pViewData->GetPosX(eHWhich);
615 nPosY = pViewData->GetPosY(eVWhich);
616 nXRight = nPosX + pViewData->VisibleCellsX(eHWhich);
617 if (nXRight > MAXCOL)
618 nXRight = MAXCOL;
619 nYBottom = nPosY + pViewData->VisibleCellsY(eVWhich);
620 if (nYBottom > MAXROW)
621 nYBottom = MAXROW;
624 // Store the current visible range.
625 bool bChanged = maVisibleRange.set(nPosX, nPosY, nXRight, nYBottom);
626 if (bChanged)
627 ResetAutoSpell();
629 return bChanged;
632 void ScGridWindow::DPMouseMove( const MouseEvent& rMEvt )
634 DPTestMouse( rMEvt, true );
637 void ScGridWindow::DPMouseButtonUp( const MouseEvent& rMEvt )
639 bDPMouse = false;
640 ReleaseMouse();
642 DPTestMouse( rMEvt, false );
643 SetPointer( Pointer( PointerStyle::Arrow ) );
646 void ScGridWindow::UpdateDragRect( bool bShowRange, const Rectangle& rPosRect )
648 SCCOL nStartX = ( rPosRect.Left() >= 0 ) ? static_cast<SCCOL>(rPosRect.Left()) : SCCOL_MAX;
649 SCROW nStartY = ( rPosRect.Top() >= 0 ) ? static_cast<SCROW>(rPosRect.Top()) : SCROW_MAX;
650 SCCOL nEndX = ( rPosRect.Right() >= 0 ) ? static_cast<SCCOL>(rPosRect.Right()) : SCCOL_MAX;
651 SCROW nEndY = ( rPosRect.Bottom() >= 0 ) ? static_cast<SCROW>(rPosRect.Bottom()) : SCROW_MAX;
653 if ( bShowRange == bDragRect && nDragStartX == nStartX && nDragEndX == nEndX &&
654 nDragStartY == nStartY && nDragEndY == nEndY )
656 return; // everything unchanged
659 if ( bShowRange )
661 nDragStartX = nStartX;
662 nDragStartY = nStartY;
663 nDragEndX = nEndX;
664 nDragEndY = nEndY;
665 bDragRect = true;
667 else
668 bDragRect = false;
670 UpdateDragRectOverlay();
673 // Page-Break-Modus
675 sal_uInt16 ScGridWindow::HitPageBreak( const Point& rMouse, ScRange* pSource,
676 SCCOLROW* pBreak, SCCOLROW* pPrev )
678 sal_uInt16 nFound = SC_PD_NONE; // 0
679 ScRange aSource;
680 SCCOLROW nBreak = 0;
681 SCCOLROW nPrev = 0;
683 ScPageBreakData* pPageData = pViewData->GetView()->GetPageBreakData();
684 if ( pPageData )
686 bool bHori = false;
687 bool bVert = false;
688 SCCOL nHitX = 0;
689 SCROW nHitY = 0;
691 long nMouseX = rMouse.X();
692 long nMouseY = rMouse.Y();
693 SCsCOL nPosX;
694 SCsROW nPosY;
695 pViewData->GetPosFromPixel( nMouseX, nMouseY, eWhich, nPosX, nPosY );
696 Point aTL = pViewData->GetScrPos( nPosX, nPosY, eWhich );
697 Point aBR = pViewData->GetScrPos( nPosX+1, nPosY+1, eWhich );
699 // Horizontal mehr Toleranz als vertikal, weil mehr Platz ist
700 if ( nMouseX <= aTL.X() + 4 )
702 bHori = true;
703 nHitX = nPosX;
705 else if ( nMouseX >= aBR.X() - 6 )
707 bHori = true;
708 nHitX = nPosX+1; // linker Rand der naechsten Zelle
710 if ( nMouseY <= aTL.Y() + 2 )
712 bVert = true;
713 nHitY = nPosY;
715 else if ( nMouseY >= aBR.Y() - 4 )
717 bVert = true;
718 nHitY = nPosY+1; // oberer Rand der naechsten Zelle
721 if ( bHori || bVert )
723 sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
724 for (sal_uInt16 nPos=0; nPos<nCount && !nFound; nPos++)
726 ScPrintRangeData& rData = pPageData->GetData(nPos);
727 ScRange aRange = rData.GetPrintRange();
728 bool bLHit = ( bHori && nHitX == aRange.aStart.Col() );
729 bool bRHit = ( bHori && nHitX == aRange.aEnd.Col() + 1 );
730 bool bTHit = ( bVert && nHitY == aRange.aStart.Row() );
731 bool bBHit = ( bVert && nHitY == aRange.aEnd.Row() + 1 );
732 bool bInsideH = ( nPosX >= aRange.aStart.Col() && nPosX <= aRange.aEnd.Col() );
733 bool bInsideV = ( nPosY >= aRange.aStart.Row() && nPosY <= aRange.aEnd.Row() );
735 if ( bLHit )
737 if ( bTHit )
738 nFound = SC_PD_RANGE_TL;
739 else if ( bBHit )
740 nFound = SC_PD_RANGE_BL;
741 else if ( bInsideV )
742 nFound = SC_PD_RANGE_L;
744 else if ( bRHit )
746 if ( bTHit )
747 nFound = SC_PD_RANGE_TR;
748 else if ( bBHit )
749 nFound = SC_PD_RANGE_BR;
750 else if ( bInsideV )
751 nFound = SC_PD_RANGE_R;
753 else if ( bTHit && bInsideH )
754 nFound = SC_PD_RANGE_T;
755 else if ( bBHit && bInsideH )
756 nFound = SC_PD_RANGE_B;
757 if (nFound)
758 aSource = aRange;
760 // Umbrueche
762 if ( bVert && bInsideH && !nFound )
764 size_t nRowCount = rData.GetPagesY();
765 const SCROW* pRowEnd = rData.GetPageEndY();
766 for (size_t nRowPos=0; nRowPos+1<nRowCount; nRowPos++)
767 if ( pRowEnd[nRowPos]+1 == nHitY )
769 nFound = SC_PD_BREAK_V;
770 aSource = aRange;
771 nBreak = nHitY;
772 if ( nRowPos )
773 nPrev = pRowEnd[nRowPos-1]+1;
774 else
775 nPrev = aRange.aStart.Row();
778 if ( bHori && bInsideV && !nFound )
780 size_t nColCount = rData.GetPagesX();
781 const SCCOL* pColEnd = rData.GetPageEndX();
782 for (size_t nColPos=0; nColPos+1<nColCount; nColPos++)
783 if ( pColEnd[nColPos]+1 == nHitX )
785 nFound = SC_PD_BREAK_H;
786 aSource = aRange;
787 nBreak = nHitX;
788 if ( nColPos )
789 nPrev = pColEnd[nColPos-1]+1;
790 else
791 nPrev = aRange.aStart.Col();
798 if (pSource)
799 *pSource = aSource; // Druckbereich
800 if (pBreak)
801 *pBreak = nBreak; // X/Y Position des verchobenen Seitenumbruchs
802 if (pPrev)
803 *pPrev = nPrev; // X/Y Anfang der Seite, die am Umbruch zuende ist
804 return nFound;
807 void ScGridWindow::PagebreakMove( const MouseEvent& rMEvt, bool bUp )
809 //! Scrolling und Umschalten mit RFMouseMove zusammenfassen !
810 //! (Weginvertieren vor dem Scrolling ist anders)
812 // Scrolling
814 bool bTimer = false;
815 Point aPos = rMEvt.GetPosPixel();
816 SCsCOL nDx = 0;
817 SCsROW nDy = 0;
818 if ( aPos.X() < 0 ) nDx = -1;
819 if ( aPos.Y() < 0 ) nDy = -1;
820 Size aSize = GetOutputSizePixel();
821 if ( aPos.X() >= aSize.Width() )
822 nDx = 1;
823 if ( aPos.Y() >= aSize.Height() )
824 nDy = 1;
825 if ( nDx != 0 || nDy != 0 )
827 if ( bPagebreakDrawn ) // weginvertieren
829 bPagebreakDrawn = false;
830 UpdateDragRectOverlay();
833 if ( nDx != 0 ) pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
834 if ( nDy != 0 ) pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
835 bTimer = true;
838 // Umschalten bei Fixierung (damit Scrolling funktioniert)
840 if ( eWhich == pViewData->GetActivePart() ) //??
842 if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
843 if ( nDx > 0 )
845 if ( eWhich == SC_SPLIT_TOPLEFT )
846 pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
847 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
848 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
851 if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
852 if ( nDy > 0 )
854 if ( eWhich == SC_SPLIT_TOPLEFT )
855 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
856 else if ( eWhich == SC_SPLIT_TOPRIGHT )
857 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
861 // ab hier neu
863 // gesucht wird eine Position zwischen den Zellen (vor nPosX / nPosY)
864 SCsCOL nPosX;
865 SCsROW nPosY;
866 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
867 bool bLeft, bTop;
868 pViewData->GetMouseQuadrant( aPos, eWhich, nPosX, nPosY, bLeft, bTop );
869 if ( !bLeft ) ++nPosX;
870 if ( !bTop ) ++nPosY;
872 bool bBreak = ( nPagebreakMouse == SC_PD_BREAK_H || nPagebreakMouse == SC_PD_BREAK_V );
873 bool bHide = false;
874 bool bToEnd = false;
875 ScRange aDrawRange = aPagebreakSource;
876 if ( bBreak )
878 if ( nPagebreakMouse == SC_PD_BREAK_H )
880 if ( nPosX > aPagebreakSource.aStart.Col() &&
881 nPosX <= aPagebreakSource.aEnd.Col() + 1 ) // ans Ende ist auch erlaubt
883 bToEnd = ( nPosX == aPagebreakSource.aEnd.Col() + 1 );
884 aDrawRange.aStart.SetCol( nPosX );
885 aDrawRange.aEnd.SetCol( nPosX - 1 );
887 else
888 bHide = true;
890 else
892 if ( nPosY > aPagebreakSource.aStart.Row() &&
893 nPosY <= aPagebreakSource.aEnd.Row() + 1 ) // ans Ende ist auch erlaubt
895 bToEnd = ( nPosY == aPagebreakSource.aEnd.Row() + 1 );
896 aDrawRange.aStart.SetRow( nPosY );
897 aDrawRange.aEnd.SetRow( nPosY - 1 );
899 else
900 bHide = true;
903 else
905 if ( nPagebreakMouse & SC_PD_RANGE_L )
906 aDrawRange.aStart.SetCol( nPosX );
907 if ( nPagebreakMouse & SC_PD_RANGE_T )
908 aDrawRange.aStart.SetRow( nPosY );
909 if ( nPagebreakMouse & SC_PD_RANGE_R )
911 if ( nPosX > 0 )
912 aDrawRange.aEnd.SetCol( nPosX-1 );
913 else
914 bHide = true;
916 if ( nPagebreakMouse & SC_PD_RANGE_B )
918 if ( nPosY > 0 )
919 aDrawRange.aEnd.SetRow( nPosY-1 );
920 else
921 bHide = true;
923 if ( aDrawRange.aStart.Col() > aDrawRange.aEnd.Col() ||
924 aDrawRange.aStart.Row() > aDrawRange.aEnd.Row() )
925 bHide = true;
928 if ( !bPagebreakDrawn || bUp || aDrawRange != aPagebreakDrag )
930 // zeichnen...
932 if ( bPagebreakDrawn )
934 // weginvertieren
935 bPagebreakDrawn = false;
937 aPagebreakDrag = aDrawRange;
938 if ( !bUp && !bHide )
940 // hininvertieren
941 bPagebreakDrawn = true;
943 UpdateDragRectOverlay();
946 // bei ButtonUp die Aenderung ausfuehren
948 if ( bUp )
950 ScViewFunc* pViewFunc = pViewData->GetView();
951 ScDocShell* pDocSh = pViewData->GetDocShell();
952 ScDocument& rDoc = pDocSh->GetDocument();
953 SCTAB nTab = pViewData->GetTabNo();
954 bool bUndo (rDoc.IsUndoEnabled());
956 if ( bBreak )
958 bool bColumn = ( nPagebreakMouse == SC_PD_BREAK_H );
959 SCCOLROW nNew = bColumn ? static_cast<SCCOLROW>(nPosX) : static_cast<SCCOLROW>(nPosY);
960 if ( nNew != nPagebreakBreak )
962 if (bUndo)
964 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_DRAG_BREAK );
965 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
968 bool bGrow = !bHide && nNew > nPagebreakBreak;
969 if ( bColumn )
971 if (rDoc.HasColBreak(static_cast<SCCOL>(nPagebreakBreak), nTab) & BREAK_MANUAL)
973 ScAddress aOldAddr( static_cast<SCCOL>(nPagebreakBreak), nPosY, nTab );
974 pViewFunc->DeletePageBreak( true, true, &aOldAddr, false );
976 if ( !bHide && !bToEnd ) // am Ende nicht
978 ScAddress aNewAddr( static_cast<SCCOL>(nNew), nPosY, nTab );
979 pViewFunc->InsertPageBreak( true, true, &aNewAddr, false );
981 if ( bGrow )
983 // vorigen Break auf hart, und Skalierung aendern
984 bool bManualBreak = (rDoc.HasColBreak(static_cast<SCCOL>(nPagebreakPrev), nTab) & BREAK_MANUAL);
985 if ( static_cast<SCCOL>(nPagebreakPrev) > aPagebreakSource.aStart.Col() && !bManualBreak )
987 ScAddress aPrev( static_cast<SCCOL>(nPagebreakPrev), nPosY, nTab );
988 pViewFunc->InsertPageBreak( true, true, &aPrev, false );
991 if (!pDocSh->AdjustPrintZoom( ScRange(
992 static_cast<SCCOL>(nPagebreakPrev),0,nTab, static_cast<SCCOL>(nNew-1),0,nTab ) ))
993 bGrow = false;
996 else
998 if (rDoc.HasRowBreak(nPagebreakBreak, nTab) & BREAK_MANUAL)
1000 ScAddress aOldAddr( nPosX, nPagebreakBreak, nTab );
1001 pViewFunc->DeletePageBreak( false, true, &aOldAddr, false );
1003 if ( !bHide && !bToEnd ) // am Ende nicht
1005 ScAddress aNewAddr( nPosX, nNew, nTab );
1006 pViewFunc->InsertPageBreak( false, true, &aNewAddr, false );
1008 if ( bGrow )
1010 // vorigen Break auf hart, und Skalierung aendern
1011 bool bManualBreak = (rDoc.HasRowBreak(nPagebreakPrev, nTab) & BREAK_MANUAL);
1012 if ( nPagebreakPrev > aPagebreakSource.aStart.Row() && !bManualBreak )
1014 ScAddress aPrev( nPosX, nPagebreakPrev, nTab );
1015 pViewFunc->InsertPageBreak( false, true, &aPrev, false );
1018 if (!pDocSh->AdjustPrintZoom( ScRange(
1019 0,nPagebreakPrev,nTab, 0,nNew-1,nTab ) ))
1020 bGrow = false;
1024 if (bUndo)
1026 pDocSh->GetUndoManager()->LeaveListAction();
1029 if (!bGrow) // sonst in AdjustPrintZoom schon passiert
1031 pViewFunc->UpdatePageBreakData( true );
1032 pDocSh->SetDocumentModified();
1036 else if ( bHide || aPagebreakDrag != aPagebreakSource )
1038 // Druckbereich setzen
1040 OUString aNewRanges;
1041 sal_uInt16 nOldCount = rDoc.GetPrintRangeCount( nTab );
1042 if ( nOldCount )
1044 for (sal_uInt16 nPos=0; nPos<nOldCount; nPos++)
1046 const ScRange* pOld = rDoc.GetPrintRange( nTab, nPos );
1047 if ( pOld )
1049 OUString aTemp;
1050 if ( *pOld != aPagebreakSource )
1051 aTemp = pOld->Format(SCA_VALID);
1052 else if ( !bHide )
1053 aTemp = aPagebreakDrag.Format(SCA_VALID);
1054 if (!aTemp.isEmpty())
1056 if ( !aNewRanges.isEmpty() )
1057 aNewRanges += ";";
1058 aNewRanges += aTemp;
1063 else if (!bHide)
1064 aNewRanges = aPagebreakDrag.Format(SCA_VALID);
1066 pViewFunc->SetPrintRanges( rDoc.IsPrintEntireSheet( nTab ), &aNewRanges, NULL, NULL, false );
1070 // Timer fuer Scrolling
1072 if (bTimer && !bUp)
1073 pViewData->GetView()->SetTimer( this, rMEvt ); // Event wiederholen
1074 else
1075 pViewData->GetView()->ResetTimer();
1078 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */