blob: b13f444050bb72ab9d40e7fde57021f7ad8fa4f8 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
// INCLUDE ---------------------------------------------------------------
#include "scitems.hxx"
#include <vcl/msgbox.hxx>
#include <vcl/sound.hxx>
#include "gridwin.hxx"
#include "tabvwsh.hxx"
#include "docsh.hxx"
#include "viewdata.hxx"
#include "pivot.hxx"
//CHINA001 #include "pfiltdlg.hxx"
#include "uiitems.hxx"
#include "scresid.hxx"
#include "sc.hrc"
#include "globstr.hrc"
#include "pagedata.hxx"
#include "dpobject.hxx"
#include "dpsave.hxx"
#include "dpoutput.hxx" // ScDPPositionData
#include "dpshttab.hxx"
#include "dbdocfun.hxx"
#include "dpcontrol.hxx"
#include "dpcontrol.hrc"
#include "strload.hxx"
#include "userlist.hxx"
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
#include "scabstdlg.hxx" //CHINA001
#include <vector>
#include <hash_map>
using namespace com::sun::star;
using ::com::sun::star::sheet::DataPilotFieldOrientation;
using ::std::vector;
using ::std::auto_ptr;
using ::std::hash_map;
using ::rtl::OUString;
using ::rtl::OUStringHash;
// STATIC DATA -----------------------------------------------------------
// -----------------------------------------------------------------------
DataPilotFieldOrientation ScGridWindow::GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const
{
using namespace ::com::sun::star::sheet;
ScDocument* pDoc = pViewData->GetDocument();
SCTAB nTab = pViewData->GetTabNo();
ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
if (!pDPObj)
return DataPilotFieldOrientation_HIDDEN;
sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN;
// Check for page field first.
if (nCol > 0)
{
// look for the dimension header left of the drop-down arrow
long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient );
if ( nField >= 0 && nOrient == DataPilotFieldOrientation_PAGE )
{
sal_Bool bIsDataLayout = sal_False;
String aFieldName = pDPObj->GetDimName( nField, bIsDataLayout );
if ( aFieldName.Len() && !bIsDataLayout )
return DataPilotFieldOrientation_PAGE;
}
}
nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
// Now, check for row/column field.
long nField = pDPObj->GetHeaderDim(ScAddress(nCol, nRow, nTab), nOrient);
if (nField >= 0 && (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) )
{
sal_Bool bIsDataLayout = sal_False;
String aFieldName = pDPObj->GetDimName(nField, bIsDataLayout);
if (aFieldName.Len() && !bIsDataLayout)
return static_cast<DataPilotFieldOrientation>(nOrient);
}
return DataPilotFieldOrientation_HIDDEN;
}
// private method for mouse button handling
sal_Bool ScGridWindow::DoPageFieldSelection( SCCOL nCol, SCROW nRow )
{
if (GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE)
{
LaunchPageFieldMenu( nCol, nRow );
return sal_True;
}
return sal_False;
}
bool ScGridWindow::DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt )
{
ScDocument* pDoc = pViewData->GetDocument();
SCTAB nTab = pViewData->GetTabNo();
Point aScrPos = pViewData->GetScrPos(nCol, nRow, eWhich);
Point aDiffPix = rMEvt.GetPosPixel();
aDiffPix -= aScrPos;
sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
if ( bLayoutRTL )
aDiffPix.X() = -aDiffPix.X();
long nSizeX, nSizeY;
pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
// The button height should not use the merged cell height, should still use single row height
nSizeY = pViewData->ToPixel(pDoc->GetRowHeight(nRow, nTab), pViewData->GetPPTY());
Size aScrSize(nSizeX-1, nSizeY-1);
// Check if the mouse cursor is clicking on the popup arrow box.
mpFilterButton.reset(new ScDPFieldButton(this, &GetSettings().GetStyleSettings(), &pViewData->GetZoomX(), &pViewData->GetZoomY(), pDoc));
mpFilterButton->setBoundingBox(aScrPos, aScrSize, bLayoutRTL);
mpFilterButton->setPopupLeft(bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL
Point aPopupPos;
Size aPopupSize;
mpFilterButton->getPopupBoundingBox(aPopupPos, aPopupSize);
Rectangle aRec(aPopupPos, aPopupSize);
if (aRec.IsInside(rMEvt.GetPosPixel()))
{
if ( DoPageFieldSelection( nCol, nRow ) )
return true;
bool bFilterActive = IsAutoFilterActive(nCol, nRow, nTab);
mpFilterButton->setHasHiddenMember(bFilterActive);
mpFilterButton->setDrawBaseButton(false);
mpFilterButton->setDrawPopupButton(true);
mpFilterButton->setPopupPressed(true);
HideCursor();
mpFilterButton->draw();
ShowCursor();
DoAutoFilterMenue(nCol, nRow, false);
return true;
}
return false;
}
void ScGridWindow::DoPushButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt )
{
ScDocument* pDoc = pViewData->GetDocument();
SCTAB nTab = pViewData->GetTabNo();
ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
if (pDPObj)
{
sal_uInt16 nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
ScAddress aPos( nCol, nRow, nTab );
long nField = pDPObj->GetHeaderDim( aPos, nOrient );
if ( nField >= 0 )
{
bDPMouse = sal_True;
nDPField = nField;
pDragDPObj = pDPObj;
if (DPTestFieldPopupArrow(rMEvt, aPos, pDPObj))
{
// field name pop up menu has been launched. Don't activate
// field move.
bDPMouse = false;
return;
}
DPTestMouse( rMEvt, sal_True );
StartTracking();
}
else if ( pDPObj->IsFilterButton(aPos) )
{
ReleaseMouse(); // may have been captured in ButtonDown
ScQueryParam aQueryParam;
SCTAB nSrcTab = 0;
const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
DBG_ASSERT(pDesc, "no sheet source for filter button");
if (pDesc)
{
aQueryParam = pDesc->aQueryParam;
nSrcTab = pDesc->aSourceRange.aStart.Tab();
}
SfxItemSet aArgSet( pViewData->GetViewShell()->GetPool(),
SCITEM_QUERYDATA, SCITEM_QUERYDATA );
aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA, pViewData, &aQueryParam ) );
//CHINA001 ScPivotFilterDlg* pDlg = new ScPivotFilterDlg(
//CHINA001 pViewData->GetViewShell()->GetDialogParent(),
//CHINA001 aArgSet, nSrcTab );
ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001
AbstractScPivotFilterDlg* pDlg = pFact->CreateScPivotFilterDlg( pViewData->GetViewShell()->GetDialogParent(),
aArgSet, nSrcTab,
RID_SCDLG_PIVOTFILTER);
DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001
if ( pDlg->Execute() == RET_OK )
{
ScSheetSourceDesc aNewDesc;
if (pDesc)
aNewDesc = *pDesc;
const ScQueryItem& rQueryItem = pDlg->GetOutputItem();
aNewDesc.aQueryParam = rQueryItem.GetQueryData();
ScDPObject aNewObj( *pDPObj );
aNewObj.SetSheetDesc( aNewDesc );
ScDBDocFunc aFunc( *pViewData->GetDocShell() );
aFunc.DataPilotUpdate( pDPObj, &aNewObj, sal_True, sal_False );
pViewData->GetView()->CursorPosChanged(); // shells may be switched
}
delete pDlg;
}
else
Sound::Beep();
}
else
{
DBG_ERROR("Da is ja garnix");
}
}
// -----------------------------------------------------------------------
//
// Data Pilot interaction
//
void ScGridWindow::DPTestMouse( const MouseEvent& rMEvt, sal_Bool bMove )
{
DBG_ASSERT(pDragDPObj, "pDragDPObj missing");
// scroll window if at edges
//! move this to separate method
sal_Bool bTimer = sal_False;
Point aPixel = rMEvt.GetPosPixel();
SCsCOL nDx = 0;
SCsROW nDy = 0;
if ( aPixel.X() < 0 )
nDx = -1;
if ( aPixel.Y() < 0 )
nDy = -1;
Size aSize = GetOutputSizePixel();
if ( aPixel.X() >= aSize.Width() )
nDx = 1;
if ( aPixel.Y() >= aSize.Height() )
nDy = 1;
if ( nDx != 0 || nDy != 0 )
{
UpdateDragRect( sal_False, Rectangle() );
if ( nDx != 0)
pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
if ( nDy != 0 )
pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
bTimer = sal_True;
}
// ---
SCsCOL nPosX;
SCsROW nPosY;
pViewData->GetPosFromPixel( aPixel.X(), aPixel.Y(), eWhich, nPosX, nPosY );
sal_Bool bMouseLeft;
sal_Bool bMouseTop;
pViewData->GetMouseQuadrant( aPixel, eWhich, nPosX, nPosY, bMouseLeft, bMouseTop );
ScAddress aPos( nPosX, nPosY, pViewData->GetTabNo() );
Rectangle aPosRect;
sal_uInt16 nOrient;
long nDimPos;
sal_Bool bHasRange = pDragDPObj->GetHeaderDrag( aPos, bMouseLeft, bMouseTop, nDPField,
aPosRect, nOrient, nDimPos );
UpdateDragRect( bHasRange && bMove, aPosRect );
sal_Bool bIsDataLayout;
sal_Int32 nDimFlags = 0;
String aDimName = pDragDPObj->GetDimName( nDPField, bIsDataLayout, &nDimFlags );
bool bAllowed = !bHasRange || ScDPObject::IsOrientationAllowed( nOrient, nDimFlags );
if (bMove) // set mouse pointer
{
PointerStyle ePointer = POINTER_PIVOT_DELETE;
if ( !bAllowed )
ePointer = POINTER_NOTALLOWED;
else if ( bHasRange )
switch (nOrient)
{
case sheet::DataPilotFieldOrientation_COLUMN: ePointer = POINTER_PIVOT_COL; break;
case sheet::DataPilotFieldOrientation_ROW: ePointer = POINTER_PIVOT_ROW; break;
case sheet::DataPilotFieldOrientation_PAGE:
case sheet::DataPilotFieldOrientation_DATA: ePointer = POINTER_PIVOT_FIELD; break;
}
SetPointer( ePointer );
}
else // execute change
{
if (!bHasRange)
nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
if ( bIsDataLayout && ( nOrient != sheet::DataPilotFieldOrientation_COLUMN &&
nOrient != sheet::DataPilotFieldOrientation_ROW ) )
{
// removing data layout is not allowed
pViewData->GetView()->ErrorMessage(STR_PIVOT_MOVENOTALLOWED);
}
else if ( bAllowed )
{
ScDPSaveData aSaveData( *pDragDPObj->GetSaveData() );
ScDPSaveDimension* pDim;
if ( bIsDataLayout )
pDim = aSaveData.GetDataLayoutDimension();
else
pDim = aSaveData.GetDimensionByName(aDimName);
pDim->SetOrientation( nOrient );
aSaveData.SetPosition( pDim, nDimPos );
//! docfunc method with ScDPSaveData as argument?
ScDPObject aNewObj( *pDragDPObj );
aNewObj.SetSaveData( aSaveData );
ScDBDocFunc aFunc( *pViewData->GetDocShell() );
// when dragging fields, allow re-positioning (bAllowMove)
aFunc.DataPilotUpdate( pDragDPObj, &aNewObj, sal_True, sal_False, sal_True );
pViewData->GetView()->CursorPosChanged(); // shells may be switched
}
}
if (bTimer && bMove)
pViewData->GetView()->SetTimer( this, rMEvt ); // repeat event
else
pViewData->GetView()->ResetTimer();
}
bool ScGridWindow::DPTestFieldPopupArrow(const MouseEvent& rMEvt, const ScAddress& rPos, ScDPObject* pDPObj)
{
sal_Bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
// Get the geometry of the cell.
Point aScrPos = pViewData->GetScrPos(rPos.Col(), rPos.Row(), eWhich);
long nSizeX, nSizeY;
pViewData->GetMergeSizePixel(rPos.Col(), rPos.Row(), nSizeX, nSizeY);
Size aScrSize(nSizeX-1, nSizeY-1);
// Check if the mouse cursor is clicking on the popup arrow box.
ScDPFieldButton aBtn(this, &GetSettings().GetStyleSettings());
aBtn.setBoundingBox(aScrPos, aScrSize, bLayoutRTL);
aBtn.setPopupLeft(false); // DataPilot popup is always right-aligned for now
Point aPopupPos;
Size aPopupSize;
aBtn.getPopupBoundingBox(aPopupPos, aPopupSize);
Rectangle aRec(aPopupPos, aPopupSize);
if (aRec.IsInside(rMEvt.GetPosPixel()))
{
// Mouse cursor inside the popup arrow box. Launch the field menu.
DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, rPos, pDPObj);
return true;
}
return false;
}
namespace {
struct DPFieldPopupData : public ScDPFieldPopupWindow::ExtendedData
{
ScPivotParam maDPParam;
ScDPObject* mpDPObj;
long mnDim;
};
class DPFieldPopupOKAction : public ScMenuFloatingWindow::Action
{
public:
explicit DPFieldPopupOKAction(ScGridWindow* p) :
mpGridWindow(p) {}
virtual void execute()
{
mpGridWindow->UpdateDPFromFieldPopupMenu();
}
private:
ScGridWindow* mpGridWindow;
};
class PopupSortAction : public ScMenuFloatingWindow::Action
{
public:
enum SortType { ASCENDING, DESCENDING, CUSTOM };
explicit PopupSortAction(const ScAddress& rPos, SortType eType, sal_uInt16 nUserListIndex, ScTabViewShell* pViewShell) :
maPos(rPos), meType(eType), mnUserListIndex(nUserListIndex), mpViewShell(pViewShell) {}
virtual void execute()
{
switch (meType)
{
case ASCENDING:
mpViewShell->DataPilotSort(maPos, true);
break;
case DESCENDING:
mpViewShell->DataPilotSort(maPos, false);
break;
case CUSTOM:
mpViewShell->DataPilotSort(maPos, true, &mnUserListIndex);
break;
default:
;
}
}
private:
ScAddress maPos;
SortType meType;
sal_uInt16 mnUserListIndex;
ScTabViewShell* mpViewShell;
};
}
bool lcl_GetLabelIndex( size_t& rLabelIndex, long nDimension, const ScDPLabelDataVector& rLabelArray )
{
size_t n = rLabelArray.size();
for (size_t i = 0; i < n; ++i)
if (static_cast<long>(rLabelArray[i].mnCol) == nDimension)
{
rLabelIndex = i;
return true;
}
return false;
}
void ScGridWindow::DPLaunchFieldPopupMenu(
const Point& rScrPos, const Size& rScrSize, const ScAddress& rPos, ScDPObject* pDPObj)
{
// We need to get the list of field members.
auto_ptr<DPFieldPopupData> pDPData(new DPFieldPopupData);
pDPObj->FillLabelData(pDPData->maDPParam);
pDPData->mpDPObj = pDPObj;
sal_uInt16 nOrient;
pDPData->mnDim = pDPObj->GetHeaderDim(rPos, nOrient);
// #i116457# FillLabelData skips empty column names, so mnDim can't be used directly as index into maLabelArray.
size_t nLabelIndex = 0;
if (!lcl_GetLabelIndex( nLabelIndex, pDPData->mnDim, pDPData->maDPParam.maLabelArray ))
return;
const ScDPLabelData& rLabelData = pDPData->maDPParam.maLabelArray[nLabelIndex];
mpDPFieldPopup.reset(new ScDPFieldPopupWindow(this, pViewData->GetDocument()));
mpDPFieldPopup->setName(OUString::createFromAscii("Pivot table field member popup"));
mpDPFieldPopup->setExtendedData(pDPData.release());
mpDPFieldPopup->setOKAction(new DPFieldPopupOKAction(this));
{
// Populate field members.
size_t n = rLabelData.maMembers.size();
mpDPFieldPopup->setMemberSize(n);
for (size_t i = 0; i < n; ++i)
{
const ScDPLabelData::Member& rMem = rLabelData.maMembers[i];
mpDPFieldPopup->addMember(rMem.getDisplayName(), rMem.mbVisible);
}
mpDPFieldPopup->initMembers();
}
vector<OUString> aUserSortNames;
ScUserList* pUserList = ScGlobal::GetUserList();
if (pUserList)
{
sal_uInt16 n = pUserList->GetCount();
aUserSortNames.reserve(n);
for (sal_uInt16 i = 0; i < n; ++i)
{
ScUserListData* pData = static_cast<ScUserListData*>((*pUserList)[i]);
aUserSortNames.push_back(pData->GetString());
}
}
// Populate the menus.
ScTabViewShell* pViewShell = pViewData->GetViewShell();
mpDPFieldPopup->addMenuItem(
ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_ASC).GetString(), true,
new PopupSortAction(rPos, PopupSortAction::ASCENDING, 0, pViewShell));
mpDPFieldPopup->addMenuItem(
ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_DESC).GetString(), true,
new PopupSortAction(rPos, PopupSortAction::DESCENDING, 0, pViewShell));
ScMenuFloatingWindow* pSubMenu = mpDPFieldPopup->addSubMenuItem(
ScRscStrLoader(RID_POPUP_FILTER, STR_MENU_SORT_CUSTOM).GetString(), !aUserSortNames.empty());
if (pSubMenu && !aUserSortNames.empty())
{
size_t n = aUserSortNames.size();
for (size_t i = 0; i < n; ++i)
{
pSubMenu->addMenuItem(
aUserSortNames[i], true,
new PopupSortAction(rPos, PopupSortAction::CUSTOM, static_cast<sal_uInt16>(i), pViewShell));
}
}
sal_Bool bLayoutRTL = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
Rectangle aCellRect(rScrPos, rScrSize);
const Size& rPopupSize = mpDPFieldPopup->getWindowSize();
if (bLayoutRTL)
{
// RTL: rScrPos is logical-left (visual right) position, always right-align with that
aCellRect.SetPos(Point(rScrPos.X() - rPopupSize.Width() + 1, rScrPos.Y()));
}
else if (rScrSize.getWidth() > rPopupSize.getWidth())
{
// If the cell width is larger than the popup window width, launch it
// right-aligned with the cell.
long nXOffset = rScrSize.getWidth() - rPopupSize.getWidth();
aCellRect.SetPos(Point(rScrPos.X() + nXOffset, rScrPos.Y()));
}
mpDPFieldPopup->SetPopupModeEndHdl( LINK(this, ScGridWindow, PopupModeEndHdl) );
mpDPFieldPopup->StartPopupMode(aCellRect, (FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_GRABFOCUS));
}
void ScGridWindow::UpdateDPFromFieldPopupMenu()
{
typedef hash_map<OUString, OUString, OUStringHash> MemNameMapType;
typedef hash_map<OUString, bool, OUStringHash> MemVisibilityType;
if (!mpDPFieldPopup.get())
return;
DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(mpDPFieldPopup->getExtendedData());
if (!pDPData)
return;
ScDPObject* pDPObj = pDPData->mpDPObj;
ScDPObject aNewDPObj(*pDPObj);
aNewDPObj.BuildAllDimensionMembers();
ScDPSaveData* pSaveData = aNewDPObj.GetSaveData();
sal_Bool bIsDataLayout;
String aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aDimName);
if (!pDim)
return;
size_t nLabelIndex = 0;
lcl_GetLabelIndex( nLabelIndex, pDPData->mnDim, pDPData->maDPParam.maLabelArray );
// Build a map of layout names to original names.
const ScDPLabelData& rLabelData = pDPData->maDPParam.maLabelArray[nLabelIndex];
MemNameMapType aMemNameMap;
for (vector<ScDPLabelData::Member>::const_iterator itr = rLabelData.maMembers.begin(), itrEnd = rLabelData.maMembers.end();
itr != itrEnd; ++itr)
aMemNameMap.insert(MemNameMapType::value_type(itr->maLayoutName, itr->maName));
// The raw result may contain a mixture of layout names and original names.
MemVisibilityType aRawResult;
mpDPFieldPopup->getResult(aRawResult);
MemVisibilityType aResult;
for (MemVisibilityType::const_iterator itr = aRawResult.begin(), itrEnd = aRawResult.end(); itr != itrEnd; ++itr)
{
MemNameMapType::const_iterator itrNameMap = aMemNameMap.find(itr->first);
if (itrNameMap == aMemNameMap.end())
// This is an original member name. Use it as-is.
aResult.insert(MemVisibilityType::value_type(itr->first, itr->second));
else
{
// This is a layout name. Get the original member name and use it.
aResult.insert(MemVisibilityType::value_type(itrNameMap->second, itr->second));
}
}
pDim->UpdateMemberVisibility(aResult);
ScDBDocFunc aFunc(*pViewData->GetDocShell());
aFunc.DataPilotUpdate(pDPObj, &aNewDPObj, true, false);
}
void ScGridWindow::DPMouseMove( const MouseEvent& rMEvt )
{
DPTestMouse( rMEvt, sal_True );
}
void ScGridWindow::DPMouseButtonUp( const MouseEvent& rMEvt )
{
bDPMouse = sal_False;
ReleaseMouse();
DPTestMouse( rMEvt, sal_False );
SetPointer( Pointer( POINTER_ARROW ) );
}
// -----------------------------------------------------------------------
void ScGridWindow::UpdateDragRect( sal_Bool bShowRange, const Rectangle& rPosRect )
{
SCCOL nStartX = ( rPosRect.Left() >= 0 ) ? static_cast<SCCOL>(rPosRect.Left()) : SCCOL_MAX;
SCROW nStartY = ( rPosRect.Top() >= 0 ) ? static_cast<SCROW>(rPosRect.Top()) : SCROW_MAX;
SCCOL nEndX = ( rPosRect.Right() >= 0 ) ? static_cast<SCCOL>(rPosRect.Right()) : SCCOL_MAX;
SCROW nEndY = ( rPosRect.Bottom() >= 0 ) ? static_cast<SCROW>(rPosRect.Bottom()) : SCROW_MAX;
if ( bShowRange == bDragRect && nDragStartX == nStartX && nDragEndX == nEndX &&
nDragStartY == nStartY && nDragEndY == nEndY )
{
return; // everything unchanged
}
// if ( bDragRect )
// DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, sal_False );
if ( bShowRange )
{
nDragStartX = nStartX;
nDragStartY = nStartY;
nDragEndX = nEndX;
nDragEndY = nEndY;
bDragRect = sal_True;
// DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, sal_False );
}
else
bDragRect = sal_False;
UpdateDragRectOverlay();
}
// -----------------------------------------------------------------------
// Page-Break-Modus
sal_uInt16 ScGridWindow::HitPageBreak( const Point& rMouse, ScRange* pSource,
SCCOLROW* pBreak, SCCOLROW* pPrev )
{
sal_uInt16 nFound = SC_PD_NONE; // 0
ScRange aSource;
SCCOLROW nBreak = 0;
SCCOLROW nPrev = 0;
ScPageBreakData* pPageData = pViewData->GetView()->GetPageBreakData();
if ( pPageData )
{
sal_Bool bHori = sal_False;
sal_Bool bVert = sal_False;
SCCOL nHitX = 0;
SCROW nHitY = 0;
long nMouseX = rMouse.X();
long nMouseY = rMouse.Y();
SCsCOL nPosX;
SCsROW nPosY;
pViewData->GetPosFromPixel( nMouseX, nMouseY, eWhich, nPosX, nPosY );
Point aTL = pViewData->GetScrPos( nPosX, nPosY, eWhich );
Point aBR = pViewData->GetScrPos( nPosX+1, nPosY+1, eWhich );
// Horizontal mehr Toleranz als vertikal, weil mehr Platz ist
if ( nMouseX <= aTL.X() + 4 )
{
bHori = sal_True;
nHitX = nPosX;
}
else if ( nMouseX >= aBR.X() - 6 )
{
bHori = sal_True;
nHitX = nPosX+1; // linker Rand der naechsten Zelle
}
if ( nMouseY <= aTL.Y() + 2 )
{
bVert = sal_True;
nHitY = nPosY;
}
else if ( nMouseY >= aBR.Y() - 4 )
{
bVert = sal_True;
nHitY = nPosY+1; // oberer Rand der naechsten Zelle
}
if ( bHori || bVert )
{
sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
for (sal_uInt16 nPos=0; nPos<nCount && !nFound; nPos++)
{
ScPrintRangeData& rData = pPageData->GetData(nPos);
ScRange aRange = rData.GetPrintRange();
sal_Bool bLHit = ( bHori && nHitX == aRange.aStart.Col() );
sal_Bool bRHit = ( bHori && nHitX == aRange.aEnd.Col() + 1 );
sal_Bool bTHit = ( bVert && nHitY == aRange.aStart.Row() );
sal_Bool bBHit = ( bVert && nHitY == aRange.aEnd.Row() + 1 );
sal_Bool bInsideH = ( nPosX >= aRange.aStart.Col() && nPosX <= aRange.aEnd.Col() );
sal_Bool bInsideV = ( nPosY >= aRange.aStart.Row() && nPosY <= aRange.aEnd.Row() );
if ( bLHit )
{
if ( bTHit )
nFound = SC_PD_RANGE_TL;
else if ( bBHit )
nFound = SC_PD_RANGE_BL;
else if ( bInsideV )
nFound = SC_PD_RANGE_L;
}
else if ( bRHit )
{
if ( bTHit )
nFound = SC_PD_RANGE_TR;
else if ( bBHit )
nFound = SC_PD_RANGE_BR;
else if ( bInsideV )
nFound = SC_PD_RANGE_R;
}
else if ( bTHit && bInsideH )
nFound = SC_PD_RANGE_T;
else if ( bBHit && bInsideH )
nFound = SC_PD_RANGE_B;
if (nFound)
aSource = aRange;
// Umbrueche
if ( bVert && bInsideH && !nFound )
{
size_t nRowCount = rData.GetPagesY();
const SCROW* pRowEnd = rData.GetPageEndY();
for (size_t nRowPos=0; nRowPos+1<nRowCount; nRowPos++)
if ( pRowEnd[nRowPos]+1 == nHitY )
{
nFound = SC_PD_BREAK_V;
aSource = aRange;
nBreak = nHitY;
if ( nRowPos )
nPrev = pRowEnd[nRowPos-1]+1;
else
nPrev = aRange.aStart.Row();
}
}
if ( bHori && bInsideV && !nFound )
{
size_t nColCount = rData.GetPagesX();
const SCCOL* pColEnd = rData.GetPageEndX();
for (size_t nColPos=0; nColPos+1<nColCount; nColPos++)
if ( pColEnd[nColPos]+1 == nHitX )
{
nFound = SC_PD_BREAK_H;
aSource = aRange;
nBreak = nHitX;
if ( nColPos )
nPrev = pColEnd[nColPos-1]+1;
else
nPrev = aRange.aStart.Col();
}
}
}
}
}
if (pSource)
*pSource = aSource; // Druckbereich
if (pBreak)
*pBreak = nBreak; // X/Y Position des verchobenen Seitenumbruchs
if (pPrev)
*pPrev = nPrev; // X/Y Anfang der Seite, die am Umbruch zuende ist
return nFound;
}
void ScGridWindow::PagebreakMove( const MouseEvent& rMEvt, sal_Bool bUp )
{
//! Scrolling und Umschalten mit RFMouseMove zusammenfassen !
//! (Weginvertieren vor dem Scrolling ist anders)
// Scrolling
sal_Bool bTimer = sal_False;
Point aPos = rMEvt.GetPosPixel();
SCsCOL nDx = 0;
SCsROW nDy = 0;
if ( aPos.X() < 0 ) nDx = -1;
if ( aPos.Y() < 0 ) nDy = -1;
Size aSize = GetOutputSizePixel();
if ( aPos.X() >= aSize.Width() )
nDx = 1;
if ( aPos.Y() >= aSize.Height() )
nDy = 1;
if ( nDx != 0 || nDy != 0 )
{
if ( bPagebreakDrawn ) // weginvertieren
{
// DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(),
// aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False );
bPagebreakDrawn = sal_False;
UpdateDragRectOverlay();
}
if ( nDx != 0 ) pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
if ( nDy != 0 ) pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
bTimer = sal_True;
}
// Umschalten bei Fixierung (damit Scrolling funktioniert)
if ( eWhich == pViewData->GetActivePart() ) //??
{
if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
if ( nDx > 0 )
{
if ( eWhich == SC_SPLIT_TOPLEFT )
pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
}
if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
if ( nDy > 0 )
{
if ( eWhich == SC_SPLIT_TOPLEFT )
pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
else if ( eWhich == SC_SPLIT_TOPRIGHT )
pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
}
}
// ab hier neu
// gesucht wird eine Position zwischen den Zellen (vor nPosX / nPosY)
SCsCOL nPosX;
SCsROW nPosY;
pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
sal_Bool bLeft, bTop;
pViewData->GetMouseQuadrant( aPos, eWhich, nPosX, nPosY, bLeft, bTop );
if ( !bLeft ) ++nPosX;
if ( !bTop ) ++nPosY;
sal_Bool bBreak = ( nPagebreakMouse == SC_PD_BREAK_H || nPagebreakMouse == SC_PD_BREAK_V );
sal_Bool bHide = sal_False;
sal_Bool bToEnd = sal_False;
ScRange aDrawRange = aPagebreakSource;
if ( bBreak )
{
if ( nPagebreakMouse == SC_PD_BREAK_H )
{
if ( nPosX > aPagebreakSource.aStart.Col() &&
nPosX <= aPagebreakSource.aEnd.Col() + 1 ) // ans Ende ist auch erlaubt
{
bToEnd = ( nPosX == aPagebreakSource.aEnd.Col() + 1 );
aDrawRange.aStart.SetCol( nPosX );
aDrawRange.aEnd.SetCol( nPosX - 1 );
}
else
bHide = sal_True;
}
else
{
if ( nPosY > aPagebreakSource.aStart.Row() &&
nPosY <= aPagebreakSource.aEnd.Row() + 1 ) // ans Ende ist auch erlaubt
{
bToEnd = ( nPosY == aPagebreakSource.aEnd.Row() + 1 );
aDrawRange.aStart.SetRow( nPosY );
aDrawRange.aEnd.SetRow( nPosY - 1 );
}
else
bHide = sal_True;
}
}
else
{
if ( nPagebreakMouse & SC_PD_RANGE_L )
aDrawRange.aStart.SetCol( nPosX );
if ( nPagebreakMouse & SC_PD_RANGE_T )
aDrawRange.aStart.SetRow( nPosY );
if ( nPagebreakMouse & SC_PD_RANGE_R )
{
if ( nPosX > 0 )
aDrawRange.aEnd.SetCol( nPosX-1 );
else
bHide = sal_True;
}
if ( nPagebreakMouse & SC_PD_RANGE_B )
{
if ( nPosY > 0 )
aDrawRange.aEnd.SetRow( nPosY-1 );
else
bHide = sal_True;
}
if ( aDrawRange.aStart.Col() > aDrawRange.aEnd.Col() ||
aDrawRange.aStart.Row() > aDrawRange.aEnd.Row() )
bHide = sal_True;
}
if ( !bPagebreakDrawn || bUp || aDrawRange != aPagebreakDrag )
{
// zeichnen...
if ( bPagebreakDrawn )
{
// weginvertieren
// DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(),
// aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False );
bPagebreakDrawn = sal_False;
}
aPagebreakDrag = aDrawRange;
if ( !bUp && !bHide )
{
// hininvertieren
// DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(),
// aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False );
bPagebreakDrawn = sal_True;
}
UpdateDragRectOverlay();
}
// bei ButtonUp die Aenderung ausfuehren
if ( bUp )
{
ScViewFunc* pViewFunc = pViewData->GetView();
ScDocShell* pDocSh = pViewData->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
SCTAB nTab = pViewData->GetTabNo();
sal_Bool bUndo (pDoc->IsUndoEnabled());
if ( bBreak )
{
sal_Bool bColumn = ( nPagebreakMouse == SC_PD_BREAK_H );
SCCOLROW nNew = bColumn ? static_cast<SCCOLROW>(nPosX) : static_cast<SCCOLROW>(nPosY);
if ( nNew != nPagebreakBreak )
{
if (bUndo)
{
String aUndo = ScGlobal::GetRscString( STR_UNDO_DRAG_BREAK );
pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
}
sal_Bool bGrow = !bHide && nNew > nPagebreakBreak;
if ( bColumn )
{
if (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakBreak), nTab) & BREAK_MANUAL)
{
ScAddress aOldAddr( static_cast<SCCOL>(nPagebreakBreak), nPosY, nTab );
pViewFunc->DeletePageBreak( sal_True, sal_True, &aOldAddr, sal_False );
}
if ( !bHide && !bToEnd ) // am Ende nicht
{
ScAddress aNewAddr( static_cast<SCCOL>(nNew), nPosY, nTab );
pViewFunc->InsertPageBreak( sal_True, sal_True, &aNewAddr, sal_False );
}
if ( bGrow )
{
// vorigen Break auf hart, und Skalierung aendern
bool bManualBreak = (pDoc->HasColBreak(static_cast<SCCOL>(nPagebreakPrev), nTab) & BREAK_MANUAL);
if ( static_cast<SCCOL>(nPagebreakPrev) > aPagebreakSource.aStart.Col() && !bManualBreak )
{
ScAddress aPrev( static_cast<SCCOL>(nPagebreakPrev), nPosY, nTab );
pViewFunc->InsertPageBreak( sal_True, sal_True, &aPrev, sal_False );
}
if (!pDocSh->AdjustPrintZoom( ScRange(
static_cast<SCCOL>(nPagebreakPrev),0,nTab, static_cast<SCCOL>(nNew-1),0,nTab ) ))
bGrow = sal_False;
}
}
else
{
if (pDoc->HasRowBreak(nPagebreakBreak, nTab) & BREAK_MANUAL)
{
ScAddress aOldAddr( nPosX, nPagebreakBreak, nTab );
pViewFunc->DeletePageBreak( sal_False, sal_True, &aOldAddr, sal_False );
}
if ( !bHide && !bToEnd ) // am Ende nicht
{
ScAddress aNewAddr( nPosX, nNew, nTab );
pViewFunc->InsertPageBreak( sal_False, sal_True, &aNewAddr, sal_False );
}
if ( bGrow )
{
// vorigen Break auf hart, und Skalierung aendern
bool bManualBreak = (pDoc->HasRowBreak(nPagebreakPrev, nTab) & BREAK_MANUAL);
if ( nPagebreakPrev > aPagebreakSource.aStart.Row() && !bManualBreak )
{
ScAddress aPrev( nPosX, nPagebreakPrev, nTab );
pViewFunc->InsertPageBreak( sal_False, sal_True, &aPrev, sal_False );
}
if (!pDocSh->AdjustPrintZoom( ScRange(
0,nPagebreakPrev,nTab, 0,nNew-1,nTab ) ))
bGrow = sal_False;
}
}
if (bUndo)
{
pDocSh->GetUndoManager()->LeaveListAction();
}
if (!bGrow) // sonst in AdjustPrintZoom schon passiert
{
pViewFunc->UpdatePageBreakData( sal_True );
pDocSh->SetDocumentModified();
}
}
}
else if ( bHide || aPagebreakDrag != aPagebreakSource )
{
// Druckbereich setzen
String aNewRanges;
sal_uInt16 nOldCount = pDoc->GetPrintRangeCount( nTab );
if ( nOldCount )
{
for (sal_uInt16 nPos=0; nPos<nOldCount; nPos++)
{
const ScRange* pOld = pDoc->GetPrintRange( nTab, nPos );
if ( pOld )
{
String aTemp;
if ( *pOld != aPagebreakSource )
pOld->Format( aTemp, SCA_VALID );
else if ( !bHide )
aPagebreakDrag.Format( aTemp, SCA_VALID );
if (aTemp.Len())
{
if ( aNewRanges.Len() )
aNewRanges += ';';
aNewRanges += aTemp;
}
}
}
}
else if (!bHide)
aPagebreakDrag.Format( aNewRanges, SCA_VALID );
pViewFunc->SetPrintRanges( pDoc->IsPrintEntireSheet( nTab ), &aNewRanges, NULL, NULL, sal_False );
}
}
// Timer fuer Scrolling
if (bTimer && !bUp)
pViewData->GetView()->SetTimer( this, rMEvt ); // Event wiederholen
else
pViewData->GetView()->ResetTimer();
}