diff options
Diffstat (limited to 'sc/source/ui/view/gridwin2.cxx')
-rw-r--r-- | sc/source/ui/view/gridwin2.cxx | 320 |
1 files changed, 311 insertions, 9 deletions
diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx index 643928a7c8aa1..e0dd63ff090e3 100644 --- a/sc/source/ui/view/gridwin2.cxx +++ b/sc/source/ui/view/gridwin2.cxx @@ -55,48 +55,124 @@ #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 -using namespace com::sun::star; +#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 ----------------------------------------------------------- // ----------------------------------------------------------------------- -BOOL ScGridWindow::HasPageFieldData( SCCOL nCol, SCROW nRow ) const +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 && nCol > 0 ) + if (!pDPObj) + return DataPilotFieldOrientation_HIDDEN; + + USHORT nOrient = DataPilotFieldOrientation_HIDDEN; + + // Check for page field first. + if (nCol > 0) { // look for the dimension header left of the drop-down arrow - USHORT nOrient = sheet::DataPilotFieldOrientation_HIDDEN; long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient ); - if ( nField >= 0 && nOrient == sheet::DataPilotFieldOrientation_PAGE ) + if ( nField >= 0 && nOrient == DataPilotFieldOrientation_PAGE ) { BOOL bIsDataLayout = FALSE; String aFieldName = pDPObj->GetDimName( nField, bIsDataLayout ); if ( aFieldName.Len() && !bIsDataLayout ) - return TRUE; + return DataPilotFieldOrientation_PAGE; } } - return FALSE; + + 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) ) + { + BOOL bIsDataLayout = 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 BOOL ScGridWindow::DoPageFieldSelection( SCCOL nCol, SCROW nRow ) { - if ( HasPageFieldData( nCol, nRow ) ) + if (GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE) { - DoPageFieldMenue( nCol, nRow ); + LaunchPageFieldMenu( nCol, nRow ); return TRUE; } return 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; + BOOL bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + if ( bLayoutRTL ) + aDiffPix.X() = -aDiffPix.X(); + + long nSizeX, nSizeY; + pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); + 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())); + mpFilterButton->setBoundingBox(aScrPos, aScrSize); + 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(); @@ -114,6 +190,15 @@ void ScGridWindow::DoPushButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt bDPMouse = 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, TRUE ); StartTracking(); } @@ -282,6 +367,223 @@ void ScGridWindow::DPTestMouse( const MouseEvent& rMEvt, BOOL bMove ) pViewData->GetView()->ResetTimer(); } +bool ScGridWindow::DPTestFieldPopupArrow(const MouseEvent& rMEvt, const ScAddress& rPos, ScDPObject* pDPObj) +{ + // 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); + 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; +}; + +} + +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; + + USHORT nOrient; + pDPData->mnDim = pDPObj->GetHeaderDim(rPos, nOrient); + + if (pDPData->maDPParam.maLabelArray.size() <= static_cast<size_t>(pDPData->mnDim)) + // out-of-bound dimension ID. This should never happen! + return; + + const ScDPLabelData& rLabelData = *pDPData->maDPParam.maLabelArray[pDPData->mnDim]; + + mpDPFieldPopup.reset(new ScDPFieldPopupWindow(this, pViewData->GetDocument())); + mpDPFieldPopup->setName(OUString::createFromAscii("DataPilot 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)); + } + } + + Rectangle aCellRect(rScrPos, rScrSize); + const Size& rPopupSize = mpDPFieldPopup->getWindowSize(); + 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(); + + BOOL bIsDataLayout; + String aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout); + ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aDimName); + if (!pDim) + return; + + // Build a map of layout names to original names. + const ScDPLabelData& rLabelData = *pDPData->maDPParam.maLabelArray[pDPData->mnDim]; + 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, TRUE ); |