diff options
author | Ivo Hinkelmann <ihi@openoffice.org> | 2010-01-29 14:28:08 +0100 |
---|---|---|
committer | Ivo Hinkelmann <ihi@openoffice.org> | 2010-01-29 14:28:08 +0100 |
commit | 3d41d6b157157dd55e62cf795bfba74990b79b0b (patch) | |
tree | 89e3cbcece6b746a54dd7a34fee1402f2d47681d /sc | |
parent | d10477ee1ad60b8c8a47b89358108e860b58b15e (diff) | |
parent | ddea1bbc63a2a08b8c546f8cb1bf833671342f11 (diff) |
CWS-TOOLING: integrate CWS koheidatapilot03
Diffstat (limited to 'sc')
85 files changed, 6572 insertions, 659 deletions
diff --git a/sc/inc/AccessibleFilterMenu.hxx b/sc/inc/AccessibleFilterMenu.hxx new file mode 100644 index 000000000000..76344a65ceda --- /dev/null +++ b/sc/inc/AccessibleFilterMenu.hxx @@ -0,0 +1,194 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_ACCESSIBLEFILTERMENU_HXX +#define SC_ACCESSIBLEFILTERMENU_HXX + +#include "AccessibleContextBase.hxx" +#include "cppuhelper/implbase1.hxx" + +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/accessibility/XAccessibleText.hpp> +#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp> +#include <com/sun/star/accessibility/TextSegment.hpp> + +#include <vector> + +namespace com { namespace sun { namespace star { + namespace accessibility { + struct AccessibleEventObject; + } +}}} + +class ScDocument; +class ScMenuFloatingWindow; + +typedef ::cppu::ImplHelper1< + ::com::sun::star::accessibility::XAccessibleSelection > ScAccessibleFilterMenu_BASE; + +class ScAccessibleFilterMenu : + public ScAccessibleContextBase, + public ScAccessibleFilterMenu_BASE +{ +public: + explicit ScAccessibleFilterMenu( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, + ScMenuFloatingWindow* pWin, const ::rtl::OUString& rName, size_t nMenuPos, ScDocument* pDoc); + virtual ~ScAccessibleFilterMenu(); + + // XAccessibleComponent + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + SAL_CALL getAccessibleAtPoint( const ::com::sun::star::awt::Point& rPoint ) + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Bool SAL_CALL isVisible() + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL grabFocus() + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getForeground() + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getBackground() + throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleContext + + virtual ::rtl::OUString SAL_CALL getAccessibleName() + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getAccessibleChildCount() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleChild(sal_Int32 nIndex) + throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleStateSet> SAL_CALL + getAccessibleStateSet() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + + using ScAccessibleContextBase::addEventListener; + using ScAccessibleContextBase::removeEventListener; + + virtual void SAL_CALL + addEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener>& xListener) + throw (com::sun::star::uno::RuntimeException); + + // Remove an existing event listener. + virtual void SAL_CALL + removeEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener>& xListener) + throw (com::sun::star::uno::RuntimeException); + + // XAccessibleSelection + + virtual void SAL_CALL selectAccessibleChild(sal_Int32 nChildIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + virtual sal_Bool SAL_CALL isAccessibleChildSelected(sal_Int32 nChildIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL clearAccessibleSelection() + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL selectAllAccessibleChildren() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::sal_Int32 SAL_CALL getSelectedAccessibleChildCount() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL + getSelectedAccessibleChild(sal_Int32 nChildIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL deselectAccessibleChild(sal_Int32 nChildIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + // XInterface + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + ::com::sun::star::uno::Type const & rType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire() throw (); + virtual void SAL_CALL release() throw (); + + // XTypeProvider + + virtual ::com::sun::star::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() + throw (::com::sun::star::uno::RuntimeException); + + // non-UNO methods + + void appendMenuItem(const ::rtl::OUString& rName, bool bEnabled, size_t nMenuPos); + void setMenuPos(size_t nMenuPos); + void setEnabled(bool bEnabled); + +protected: + + sal_Int32 getMenuItemCount() const; + + virtual Rectangle GetBoundingBoxOnScreen() const + throw (::com::sun::star::uno::RuntimeException); + + virtual Rectangle GetBoundingBox() const + throw (::com::sun::star::uno::RuntimeException); + +private: + bool isSelected() const; + bool isFocused() const; + + void updateStates(); + +private: + ::std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > > maMenuItems; + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > mxStateSet; + + size_t mnMenuPos; + ScMenuFloatingWindow* mpWindow; + ScDocument* mpDoc; + + bool mbEnabled:1; +}; + +#endif diff --git a/sc/inc/AccessibleFilterMenuItem.hxx b/sc/inc/AccessibleFilterMenuItem.hxx new file mode 100644 index 000000000000..f5ad0fd5d74b --- /dev/null +++ b/sc/inc/AccessibleFilterMenuItem.hxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_ACCESSIBLEFILTERMENUITEM_HXX +#define SC_ACCESSIBLEFILTERMENUITEM_HXX + +#include "AccessibleContextBase.hxx" +#include "cppuhelper/implbase1.hxx" + +#include <com/sun/star/accessibility/XAccessibleAction.hpp> + +class ScMenuFloatingWindow; + +typedef ::cppu::ImplHelper1< + ::com::sun::star::accessibility::XAccessibleAction > ScAccessibleFilterMenuItem_BASE; + +class ScAccessibleFilterMenuItem : + public ScAccessibleContextBase, + public ScAccessibleFilterMenuItem_BASE +{ +public: + explicit ScAccessibleFilterMenuItem( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const ::rtl::OUString& rName, size_t nMenuPos); + + virtual ~ScAccessibleFilterMenuItem(); + + // XAccessibleContext + + virtual sal_Int32 SAL_CALL getAccessibleChildCount() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > SAL_CALL + getAccessibleChild(sal_Int32 nIndex) + throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleStateSet> SAL_CALL + getAccessibleStateSet() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleAction + + virtual ::sal_Int32 SAL_CALL getAccessibleActionCount() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::sal_Bool SAL_CALL doAccessibleAction(sal_Int32 nIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + virtual ::rtl::OUString SAL_CALL getAccessibleActionDescription(sal_Int32 nIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleKeyBinding > SAL_CALL + getAccessibleActionKeyBinding(sal_Int32 nIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + + // XInterface + + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( + ::com::sun::star::uno::Type const & rType ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL acquire() throw (); + virtual void SAL_CALL release() throw (); + + // Non-UNO Methods + + void setEnabled(bool bEnabled); + +protected: + + virtual Rectangle GetBoundingBoxOnScreen() const + throw (::com::sun::star::uno::RuntimeException); + + virtual Rectangle GetBoundingBox() const + throw (::com::sun::star::uno::RuntimeException); + +private: + bool isSelected() const; + bool isFocused() const; + void updateStateSet(); + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet > mxStateSet; + + ScMenuFloatingWindow* mpWindow; + ::rtl::OUString maName; + size_t mnMenuPos; + bool mbEnabled; +}; + +#endif diff --git a/sc/inc/AccessibleFilterTopWindow.hxx b/sc/inc/AccessibleFilterTopWindow.hxx new file mode 100644 index 000000000000..e901949286a1 --- /dev/null +++ b/sc/inc/AccessibleFilterTopWindow.hxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_ACCESSIBLEFILTERTOPWINDOW_HXX +#define SC_ACCESSIBLEFILTERTOPWINDOW_HXX + +//#include "AccessibleContextBase.hxx" +#include "AccessibleFilterMenu.hxx" +#include "cppuhelper/implbase1.hxx" + +class ScDPFieldPopupWindow; +class ScDocument; + +class ScAccessibleFilterTopWindow : public ScAccessibleFilterMenu +{ +public: + ScAccessibleFilterTopWindow( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, + ScDPFieldPopupWindow* pWin, const ::rtl::OUString& rName, ScDocument* pDoc); + virtual ~ScAccessibleFilterTopWindow(); + + // XAccessibleContext + + virtual sal_Int32 SAL_CALL getAccessibleChildCount() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleChild(sal_Int32 nIndex) + throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException); + + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (::com::sun::star::uno::RuntimeException); + + // Non-UNO Methods + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + getAccessibleChildMenu(); + + enum ChildControlType { + LISTBOX, TOGGLE_ALL, SINGLE_ON_BTN, SINGLE_OFF_BTN, OK_BTN, CANCEL_BTN + }; + void setAccessibleChild( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible >& rAccessible, + ChildControlType eType); + +private: + /** The top menu part */ + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + mxAccMenu; + + /** check list box for field member visibility */ + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + mxAccListBox; + + /** check box for toggling all field member's visibility. */ + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + mxAccToggleAll; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + mxAccSingleOnBtn; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + mxAccSingleOffBtn; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + mxAccOkBtn; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + mxAccCancelBtn; + + ScDPFieldPopupWindow* mpWindow; + ScDocument* mpDoc; +}; + +#endif diff --git a/sc/inc/AccessibleGlobal.hxx b/sc/inc/AccessibleGlobal.hxx new file mode 100644 index 000000000000..9f17c2eaacae --- /dev/null +++ b/sc/inc/AccessibleGlobal.hxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_ACCESSIBLEGLOBAL_HXX +#define SC_ACCESSIBLEGLOBAL_HXX + +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> +#include "cppuhelper/implbase1.hxx" + +#include <set> + +/** + * Generic XAccessibleStateSet implementation. + */ +class ScAccessibleStateSet : public ::cppu::WeakImplHelper1< ::com::sun::star::accessibility::XAccessibleStateSet > +{ +public: + ScAccessibleStateSet(); + virtual ~ScAccessibleStateSet(); + + // XAccessibleStateSet + + virtual ::sal_Bool SAL_CALL isEmpty() + throw (::com::sun::star::uno::RuntimeException); + + virtual ::sal_Bool SAL_CALL contains(sal_Int16 nState) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::sal_Bool SAL_CALL containsAll( + const ::com::sun::star::uno::Sequence<sal_Int16>& aStateSet) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence<sal_Int16> SAL_CALL getStates() + throw (::com::sun::star::uno::RuntimeException); + + // Non-UNO Methods + + void insert(sal_Int16 nState); + void clear(); + +private: + ::std::set<sal_Int16> maStates; +}; + +#endif diff --git a/sc/inc/attrib.hxx b/sc/inc/attrib.hxx index 55bb707f4edb..9db8b4001690 100644 --- a/sc/inc/attrib.hxx +++ b/sc/inc/attrib.hxx @@ -42,13 +42,16 @@ // Flags fuer durch Merge verdeckte Zellen // und Control fuer Auto-Filter -#define SC_MF_HOR 1 -#define SC_MF_VER 2 -#define SC_MF_AUTO 4 -#define SC_MF_BUTTON 8 -#define SC_MF_SCENARIO 16 +#define SC_MF_HOR 0x0001 +#define SC_MF_VER 0x0002 +#define SC_MF_AUTO 0x0004 /// autofilter arrow +#define SC_MF_BUTTON 0x0008 /// field button for datapilot +#define SC_MF_SCENARIO 0x0010 +#define SC_MF_BUTTON_POPUP 0x0020 /// dp button with popup arrow +#define SC_MF_HIDDEN_MEMBER 0x0040 /// dp field button with presence of hidden member +#define SC_MF_DP_TABLE 0x0080 /// dp table output -#define SC_MF_ALL 31 +#define SC_MF_ALL 0x00FF class EditTextObject; @@ -103,6 +106,7 @@ public: BOOL HasAutoFilter() const { return ( GetValue() & SC_MF_AUTO ) != 0; } BOOL HasButton() const { return ( GetValue() & SC_MF_BUTTON ) != 0; } + bool HasDPTable() const { return ( GetValue() & SC_MF_DP_TABLE ) != 0; } BOOL IsScenario() const { return ( GetValue() & SC_MF_SCENARIO ) != 0; } }; diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 3f1fbfc1c88f..b69fcb384e04 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -161,7 +161,7 @@ public: SCSIZE GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const; BOOL HasDataAt(SCROW nRow) const; BOOL HasVisibleDataAt(SCROW nRow) const; -//UNUSED2009-05 SCROW GetFirstDataPos() const; + SCROW GetFirstDataPos() const; SCROW GetLastDataPos() const; SCROW GetLastVisDataPos(BOOL bNotes) const; // ohne Broadcaster SCROW GetFirstVisDataPos(BOOL bNotes) const; diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 116d25ee901e..cc575b529d73 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -866,6 +866,8 @@ public: USHORT GetErrCode( const ScAddress& ) const; + bool ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const; + void GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld ); SC_DLLPUBLIC BOOL GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const; diff --git a/sc/inc/dpgroup.hxx b/sc/inc/dpgroup.hxx index 99dac0e517db..cb933f4d2a98 100644 --- a/sc/inc/dpgroup.hxx +++ b/sc/inc/dpgroup.hxx @@ -33,6 +33,7 @@ #include <vector> #include <hash_set> +#include <boost/shared_ptr.hpp> #include "dptabdat.hxx" #include "scdllapi.h" @@ -182,7 +183,7 @@ class ScDPGroupTableData : public ScDPTableData { typedef ::std::hash_set< ::rtl::OUString, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > StringHashSet; - ScDPTableData* pSourceData; + ::boost::shared_ptr<ScDPTableData> pSourceData; long nSourceCount; ScDPGroupDimensionVec aGroups; ScDPNumGroupDimension* pNumGroups; // array[nSourceCount] @@ -200,7 +201,7 @@ class ScDPGroupTableData : public ScDPTableData public: // takes ownership of pSource - ScDPGroupTableData( ScDPTableData* pSource, ScDocument* pDocument ); + ScDPGroupTableData( const ::boost::shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument ); virtual ~ScDPGroupTableData(); void AddGroupDimension( const ScDPGroupDimension& rGroup ); diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx index 2dc8829485c8..ef7a2c491c50 100644 --- a/sc/inc/dpobject.hxx +++ b/sc/inc/dpobject.hxx @@ -36,8 +36,11 @@ #include "address.hxx" #include "collect.hxx" #include "dpoutput.hxx" +#include "pivot.hxx" #include <com/sun/star/sheet/XDimensionsSupplier.hpp> +#include <boost/shared_ptr.hpp> + //------------------------------------------------------------------ namespace com { namespace sun { namespace star { namespace sheet { @@ -64,6 +67,7 @@ class ScStrCollection; class TypedScStrCollection; struct PivotField; class ScDPCacheTable; +class ScDPTableData; struct ScDPServiceDesc { @@ -99,15 +103,19 @@ private: ScSheetSourceDesc* pSheetDesc; // for sheet data ScImportSourceDesc* pImpDesc; // for database data ScDPServiceDesc* pServDesc; // for external service + ::boost::shared_ptr<ScDPTableData> mpTableData; // cached data com::sun::star::uno::Reference<com::sun::star::sheet::XDimensionsSupplier> xSource; ScDPOutput* pOutput; BOOL bSettingsChanged; BOOL bAlive; // FALSE if only used to hold settings + sal_uInt16 mnAutoFormatIndex; BOOL bAllowMove; long nHeaderRows; // page fields plus filter button + bool mbHeaderLayout; // TRUE : grid, FALSE : standard + SC_DLLPRIVATE ScDPTableData* GetTableData(); SC_DLLPRIVATE void CreateObjects(); SC_DLLPRIVATE void CreateOutput(); @@ -135,6 +143,12 @@ public: void SetOutRange(const ScRange& rRange); const ScRange& GetOutRange() const { return aOutRange; } + void SetAutoFormatIndex (const sal_uInt16 nIndex); + sal_uInt16 GetAutoFormatIndex() const; + + void SetHeaderLayout(bool bUseGrid); + bool GetHeaderLayout() const; + void SetSheetDesc(const ScSheetSourceDesc& rDesc); void SetImportDesc(const ScImportSourceDesc& rDesc); void SetServiceData(const ScDPServiceDesc& rDesc); @@ -157,7 +171,14 @@ public: void SetTag(const String& rNew); const String& GetTag() const { return aTableTag; } - BOOL IsDimNameInUse( const String& rName ) const; + /** + * Data description cell displays the description of a data dimension if + * and only if there is only one data dimension. It's usually located at + * the upper-left corner of the table output. + */ + bool IsDataDescriptionCell(const ScAddress& rPos); + + bool IsDimNameInUse(const ::rtl::OUString& rName) const; String GetDimName( long nDim, BOOL& rIsDataLayout ); BOOL IsDuplicated( long nDim ); long GetDimCount(); @@ -190,16 +211,10 @@ public: sal_Int32 GetUsedHierarchy( sal_Int32 nDim ); BOOL GetMembersNA( sal_Int32 nDim, com::sun::star::uno::Reference< com::sun::star::container::XNameAccess >& xMembers ); - BOOL GetMembers( sal_Int32 nDim, - com::sun::star::uno::Sequence< rtl::OUString >& rMembers, - com::sun::star::uno::Sequence< sal_Bool >* pVisible = 0, - com::sun::star::uno::Sequence< sal_Bool >* pShowDet = 0 ); - BOOL GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, com::sun::star::uno::Reference< com::sun::star::container::XNameAccess >& xMembers ); - BOOL GetMembers( sal_Int32 nDim, sal_Int32 nHier, - com::sun::star::uno::Sequence< rtl::OUString >& rMembers, - com::sun::star::uno::Sequence< sal_Bool >* pVisible = 0, - com::sun::star::uno::Sequence< sal_Bool >* pShowDet = 0 ); + + bool GetMemberNames( sal_Int32 nDim, ::com::sun::star::uno::Sequence< ::rtl::OUString >& rNames ); + bool GetMembers( sal_Int32 nDim, sal_Int32 nHier, ::std::vector<ScDPLabelData::Member>& rMembers ); void UpdateReference( UpdateRefMode eUpdateRefMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ); @@ -221,6 +236,8 @@ public: // (button attribute must be present) void RefreshAfterLoad(); + void BuildAllDimensionMembers(); + static BOOL HasRegisteredSources(); static com::sun::star::uno::Sequence<rtl::OUString> GetRegisteredSources(); static com::sun::star::uno::Reference<com::sun::star::sheet::XDimensionsSupplier> @@ -291,6 +308,11 @@ public: ScSimpleSharedString& GetSharedString(); + void FreeTable(ScDPObject* pDPObj); + SC_DLLPUBLIC bool InsertNewTable(ScDPObject* pDPObj); + + bool HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const; + ScDPCacheCell* getCacheCellFromPool(const ScDPCacheCell& rCell); void clearCacheCellPool(); }; diff --git a/sc/inc/dpoutput.hxx b/sc/inc/dpoutput.hxx index 58001e1183a6..e3ab86423d4b 100644 --- a/sc/inc/dpoutput.hxx +++ b/sc/inc/dpoutput.hxx @@ -94,6 +94,7 @@ private: com::sun::star::uno::Sequence< com::sun::star::sheet::DataResult> > aData; BOOL bResultsError; + bool mbHasDataLayout; String aDataDescription; // Number format related parameters @@ -109,6 +110,7 @@ private: long nColCount; long nRowCount; long nHeaderSize; + bool mbHeaderLayout; // TRUE : grid, FALSE : standard SCCOL nTabStartCol; SCROW nTabStartRow; SCCOL nMemberStartCol; @@ -124,7 +126,7 @@ private: const com::sun::star::sheet::MemberResult& rData, BOOL bColHeader, long nLevel ); void FieldCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rCaption, - BOOL bFrame = TRUE ); + bool bInTable, bool bPopup, bool bHasHiddenMember ); void CalcSizes(); /** Query which sub-area of the table the cell is in. See @@ -162,6 +164,9 @@ public: void GetMemberResultNames( ScStrCollection& rNames, long nDimension ); + void SetHeaderLayout(bool bUseGrid); + bool GetHeaderLayout() const; + static void GetDataDimensionNames( String& rSourceName, String& rGivenName, const com::sun::star::uno::Reference< com::sun::star::uno::XInterface>& xDim ); diff --git a/sc/inc/dpoutputgeometry.hxx b/sc/inc/dpoutputgeometry.hxx new file mode 100644 index 000000000000..b665c9cc88b4 --- /dev/null +++ b/sc/inc/dpoutputgeometry.hxx @@ -0,0 +1,80 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xmldpimp.cxx,v $ + * $Revision: 1.27.134.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_DPOUTPUTGEOMETRY_HXX +#define SC_DPOUTPUTGEOMETRY_HXX + +#include "address.hxx" +#include <vector> + +class ScAddress; + +class SC_DLLPUBLIC ScDPOutputGeometry +{ +public: + enum FieldType { Column, Row, Page, Data, None }; + enum ImportType { ODF, XLS }; + + ScDPOutputGeometry(const ScRange& rOutRange, bool bShowFilter, ImportType eImportType); + ~ScDPOutputGeometry(); + + /** + * @param nCount number of row fields, <b>excluding the data layout + * field if exists</b>. + */ + void setRowFieldCount(sal_uInt32 nCount); + void setColumnFieldCount(sal_uInt32 nCount); + void setPageFieldCount(sal_uInt32 nCount); + void setDataFieldCount(sal_uInt32 nCount); + + void getColumnFieldPositions(::std::vector<ScAddress>& rAddrs) const; + void getRowFieldPositions(::std::vector<ScAddress>& rAddrs) const; + void getPageFieldPositions(::std::vector<ScAddress>& rAddrs) const; + + SCROW getRowFieldHeaderRow() const; + + FieldType getFieldButtonType(const ScAddress& rPos) const; + +private: + ScDPOutputGeometry(); // disabled + +private: + ScRange maOutRange; + sal_uInt32 mnRowFields; /// number of row fields (data layout field NOT included!) + sal_uInt32 mnColumnFields; + sal_uInt32 mnPageFields; + sal_uInt32 mnDataFields; + + ImportType meImportType; + + bool mbShowFilter; +}; + +#endif diff --git a/sc/inc/dpsave.hxx b/sc/inc/dpsave.hxx index d3d8d4354145..86093ac8614b 100644 --- a/sc/inc/dpsave.hxx +++ b/sc/inc/dpsave.hxx @@ -34,9 +34,11 @@ #include <tools/string.hxx> #include <tools/list.hxx> #include <com/sun/star/sheet/XDimensionsSupplier.hpp> +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> #include "scdllapi.h" #include <hash_map> #include <list> +#include <memory> namespace com { namespace sun { namespace star { namespace sheet { struct DataPilotFieldReference; @@ -46,6 +48,7 @@ namespace com { namespace sun { namespace star { namespace sheet { } } } } class ScDPDimensionSaveData; +class ScDPTableData; // -------------------------------------------------------------------- // @@ -57,6 +60,7 @@ class ScDPSaveMember { private: String aName; + ::std::auto_ptr<rtl::OUString> mpLayoutName; // custom name to be displayed in the table. USHORT nVisibleMode; USHORT nShowDetailsMode; @@ -77,18 +81,23 @@ public: void SetName( const String& rNew ); // used if the source member was renamed (groups) + SC_DLLPUBLIC void SetLayoutName( const ::rtl::OUString& rName ); + SC_DLLPUBLIC const ::rtl::OUString* GetLayoutName() const; + void RemoveLayoutName(); + void WriteToSource( const com::sun::star::uno::Reference< com::sun::star::uno::XInterface>& xMember, sal_Int32 nPosition ); }; -class ScDPSaveDimension +class SC_DLLPUBLIC ScDPSaveDimension { private: String aName; - String* pLayoutName; // alternative name for layout, not used (yet) String* pSelectedPage; + ::std::auto_ptr<rtl::OUString> mpLayoutName; + ::std::auto_ptr<rtl::OUString> mpSubtotalName; BOOL bIsDataLayout; BOOL bDupFlag; USHORT nOrientation; @@ -127,43 +136,52 @@ public: void SetName( const String& rNew ); // used if the source dim was renamed (groups) - SC_DLLPUBLIC void SetOrientation(USHORT nNew); - SC_DLLPUBLIC void SetSubTotals(long nCount, const USHORT* pFuncs); + void SetOrientation(USHORT nNew); + void SetSubTotals(long nCount, const USHORT* pFuncs); long GetSubTotalsCount() const { return nSubTotalCount; } USHORT GetSubTotalFunc(long nIndex) const { return pSubTotalFuncs[nIndex]; } - SC_DLLPUBLIC void SetShowEmpty(BOOL bSet); + void SetShowEmpty(BOOL bSet); BOOL GetShowEmpty() const { return BOOL(nShowEmptyMode); } - SC_DLLPUBLIC void SetFunction(USHORT nNew); // enum GeneralFunction + void SetFunction(USHORT nNew); // enum GeneralFunction USHORT GetFunction() const { return nFunction; } void SetUsedHierarchy(long nNew); long GetUsedHierarchy() const { return nUsedHierarchy; } - SC_DLLPUBLIC void SetLayoutName(const String* pName); - SC_DLLPUBLIC const String& GetLayoutName() const; - SC_DLLPUBLIC BOOL HasLayoutName() const; + + void SetLayoutName(const ::rtl::OUString& rName); + const ::rtl::OUString* GetLayoutName() const; + void RemoveLayoutName(); + void SetSubtotalName(const ::rtl::OUString& rName); + const ::rtl::OUString* GetSubtotalName() const; + + bool IsMemberNameInUse(const ::rtl::OUString& rName) const; const ::com::sun::star::sheet::DataPilotFieldReference* GetReferenceValue() const { return pReferenceValue; } - SC_DLLPUBLIC void SetReferenceValue(const ::com::sun::star::sheet::DataPilotFieldReference* pNew); + void SetReferenceValue(const ::com::sun::star::sheet::DataPilotFieldReference* pNew); const ::com::sun::star::sheet::DataPilotFieldSortInfo* GetSortInfo() const { return pSortInfo; } - SC_DLLPUBLIC void SetSortInfo(const ::com::sun::star::sheet::DataPilotFieldSortInfo* pNew); + void SetSortInfo(const ::com::sun::star::sheet::DataPilotFieldSortInfo* pNew); const ::com::sun::star::sheet::DataPilotFieldAutoShowInfo* GetAutoShowInfo() const { return pAutoShowInfo; } - SC_DLLPUBLIC void SetAutoShowInfo(const ::com::sun::star::sheet::DataPilotFieldAutoShowInfo* pNew); + void SetAutoShowInfo(const ::com::sun::star::sheet::DataPilotFieldAutoShowInfo* pNew); const ::com::sun::star::sheet::DataPilotFieldLayoutInfo* GetLayoutInfo() const { return pLayoutInfo; } - SC_DLLPUBLIC void SetLayoutInfo(const ::com::sun::star::sheet::DataPilotFieldLayoutInfo* pNew); + void SetLayoutInfo(const ::com::sun::star::sheet::DataPilotFieldLayoutInfo* pNew); - SC_DLLPUBLIC void SetCurrentPage( const String* pPage ); // NULL = no selection (all) - SC_DLLPUBLIC BOOL HasCurrentPage() const; - SC_DLLPUBLIC const String& GetCurrentPage() const; + void SetCurrentPage( const String* pPage ); // NULL = no selection (all) + BOOL HasCurrentPage() const; + const String& GetCurrentPage() const; USHORT GetOrientation() const { return nOrientation; } ScDPSaveMember* GetExistingMemberByName(const String& rName); - SC_DLLPUBLIC ScDPSaveMember* GetMemberByName(const String& rName); + ScDPSaveMember* GetMemberByName(const String& rName); void SetMemberPosition( const String& rName, sal_Int32 nNewPos ); void WriteToSource( const com::sun::star::uno::Reference< com::sun::star::uno::XInterface>& xDim ); + + void UpdateMemberVisibility(const ::std::hash_map< ::rtl::OUString, bool, ::rtl::OUStringHash>& rData); + + bool HasInvisibleMember() const; }; @@ -179,6 +197,12 @@ private: BOOL bFilterButton; // not passed to DataPilotSource BOOL bDrillDown; // not passed to DataPilotSource + /** if true, all dimensions already have all of their member instances + * created. */ + bool mbDimensionMembersBuilt; + + ::std::auto_ptr<rtl::OUString> mpGrandTotalName; + public: SC_DLLPUBLIC ScDPSaveData(); ScDPSaveData(const ScDPSaveData& r); @@ -188,21 +212,26 @@ public: BOOL operator== ( const ScDPSaveData& r ) const; + SC_DLLPUBLIC void SetGrandTotalName(const ::rtl::OUString& rName); + SC_DLLPUBLIC const ::rtl::OUString* GetGrandTotalName() const; + const List& GetDimensions() const { return aDimList; } void AddDimension(ScDPSaveDimension* pDim) { aDimList.Insert(pDim, LIST_APPEND); } ScDPSaveDimension* GetDimensionByName(const String& rName); SC_DLLPUBLIC ScDPSaveDimension* GetDataLayoutDimension(); + SC_DLLPUBLIC ScDPSaveDimension* GetExistingDataLayoutDimension() const; ScDPSaveDimension* DuplicateDimension(const String& rName); SC_DLLPUBLIC ScDPSaveDimension& DuplicateDimension(const ScDPSaveDimension& rDim); - SC_DLLPUBLIC ScDPSaveDimension* GetExistingDimensionByName(const String& rName); + SC_DLLPUBLIC ScDPSaveDimension* GetExistingDimensionByName(const String& rName) const; SC_DLLPUBLIC ScDPSaveDimension* GetNewDimensionByName(const String& rName); void RemoveDimensionByName(const String& rName); ScDPSaveDimension* GetInnermostDimension(USHORT nOrientation); + ScDPSaveDimension* GetFirstDimension(::com::sun::star::sheet::DataPilotFieldOrientation eOrientation); long GetDataDimensionCount() const; @@ -229,6 +258,14 @@ public: const ScDPDimensionSaveData* GetExistingDimensionData() const { return pDimensionData; } SC_DLLPUBLIC ScDPDimensionSaveData* GetDimensionData(); // create if not there void SetDimensionData( const ScDPDimensionSaveData* pNew ); // copied + void BuildAllDimensionMembers(ScDPTableData* pData); + + /** + * Check whether a dimension has one or more invisible members. + * + * @param rDimName dimension name + */ + SC_DLLPUBLIC bool HasInvisibleMember(const ::rtl::OUString& rDimName) const; }; diff --git a/sc/inc/dptabres.hxx b/sc/inc/dptabres.hxx index b18ea8e56b76..a2574820da4a 100644 --- a/sc/inc/dptabres.hxx +++ b/sc/inc/dptabres.hxx @@ -41,6 +41,7 @@ #include <hash_map> #include <hash_set> #include <vector> +#include <memory> namespace com { namespace sun { namespace star { namespace sheet { struct DataPilotFieldReference; @@ -262,7 +263,7 @@ public: long GetMeasureCount() const { return nMeasCount; } ScSubTotalFunc GetMeasureFunction(long nMeasure) const; - String GetMeasureString(long nMeasure, BOOL bForce, ScSubTotalFunc eForceFunc) const; + String GetMeasureString(long nMeasure, BOOL bForce, ScSubTotalFunc eForceFunc, bool& rbTotalResult) const; String GetMeasureDimensionName(long nMeasure) const; const ::com::sun::star::sheet::DataPilotFieldReference& GetMeasureRefVal(long nMeasure) const; USHORT GetMeasureRefOrient(long nMeasure) const; @@ -284,6 +285,8 @@ public: const ScDPItemData& rBaseData, long nBaseIndex ) const; BOOL HasCommonElement( const ScDPItemData& rFirstData, long nFirstIndex, const ScDPItemData& rSecondData, long nSecondIndex ) const; + + const ScDPSource* GetSource() const; }; diff --git a/sc/inc/dptabsrc.hxx b/sc/inc/dptabsrc.hxx index 3b1d8e0e206e..94229f5b1d35 100644 --- a/sc/inc/dptabsrc.hxx +++ b/sc/inc/dptabsrc.hxx @@ -33,6 +33,7 @@ #include <vector> #include <hash_map> +#include <memory> #include <tools/string.hxx> #include <tools/list.hxx> #include "global.hxx" // enum ScSubTotalFunc @@ -108,7 +109,7 @@ class ScDPSource : public cppu::WeakImplHelper6< com::sun::star::lang::XServiceInfo > { private: - ScDPTableData* pData; // data source + ScDPTableData* pData; // data source (ScDPObject manages its life time) ScDPDimensions* pDimensions; // api objects // settings: long nColDims[SC_DAPI_MAXFIELDS]; @@ -136,6 +137,8 @@ private: List aRowLevelList; BOOL bResultOverflow; + ::std::auto_ptr<rtl::OUString> mpGrandTotalName; + void CreateRes_Impl(); void FillMemberResults(); void FillLevelList( USHORT nOrientation, List& rList ); @@ -162,11 +165,15 @@ public: ScDPTableData* GetData() { return pData; } const ScDPTableData* GetData() const { return pData; } + void SetGrandTotalName(const ::rtl::OUString& rName); + const ::rtl::OUString* GetGrandTotalName() const; + USHORT GetOrientation(long nColumn); void SetOrientation(long nColumn, USHORT nNew); long GetPosition(long nColumn); long GetDataDimensionCount(); + ScDPDimension* GetDataDimension(long nIndex); String GetDataDimName(long nIndex); BOOL IsDataLayoutDimension(long nDim); USHORT GetDataLayoutOrientation(); @@ -333,12 +340,15 @@ private: long nUsedHier; USHORT nFunction; // enum GeneralFunction String aName; // if empty, take from source + ::std::auto_ptr<rtl::OUString> mpLayoutName; + ::std::auto_ptr<rtl::OUString> mpSubtotalName; long nSourceDim; // >=0 if dup'ed ::com::sun::star::sheet::DataPilotFieldReference aReferenceValue; // settings for "show data as" / "displayed value" BOOL bHasSelectedPage; String aSelectedPage; ScDPItemData* pSelectedData; // internal, temporary, created from aSelectedPage + sal_Bool mbHasHiddenMember; public: ScDPDimension( ScDPSource* pSrc, long nD ); @@ -350,6 +360,9 @@ public: ScDPDimension* CreateCloneObject(); ScDPHierarchies* GetHierarchiesObject(); + SC_DLLPUBLIC const ::rtl::OUString* GetLayoutName() const; + const ::rtl::OUString* GetSubtotalName() const; + // XNamed virtual ::rtl::OUString SAL_CALL getName() throw(::com::sun::star::uno::RuntimeException); virtual void SAL_CALL setName( const ::rtl::OUString& aName ) @@ -736,7 +749,7 @@ private: long nLev; ScDPItemData maData; -// String aCaption; // visible name (changeable by user) + ::std::auto_ptr<rtl::OUString> mpLayoutName; sal_Int32 nPosition; // manual sorting BOOL bVisible; @@ -750,6 +763,7 @@ public: BOOL IsNamedItem( const ScDPItemData& r ) const; String GetNameStr() const; void FillItemData( ScDPItemData& rData ) const; + SC_DLLPUBLIC const ::rtl::OUString* GetLayoutName() const; sal_Int32 Compare( const ScDPMember& rOther ) const; // visible order diff --git a/sc/inc/fillinfo.hxx b/sc/inc/fillinfo.hxx index b6d48254d06a..d0be5b0cb897 100644 --- a/sc/inc/fillinfo.hxx +++ b/sc/inc/fillinfo.hxx @@ -99,6 +99,8 @@ struct CellInfo BOOL bVOverlapped : 1; BOOL bAutoFilter : 1; BOOL bPushButton : 1; + bool bPopupButton: 1; + bool bFilterActive:1; BOOL bPrinted : 1; // bei Bedarf (Pagebreak-Modus) diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx index 1f6dc13d04ce..c938968ddfef 100644 --- a/sc/inc/global.hxx +++ b/sc/inc/global.hxx @@ -87,8 +87,6 @@ extern "C" { #endif //------------------------------------------------------------------------ -struct LabelData; -//------------------------------------------------------------------------ // die 1000 Namen des Calc... // Clipboard-Namen sind jetzt in so3/soapp.hxx diff --git a/sc/inc/miscuno.hxx b/sc/inc/miscuno.hxx index 1486d3ce480b..df60b2822cb8 100644 --- a/sc/inc/miscuno.hxx +++ b/sc/inc/miscuno.hxx @@ -285,12 +285,29 @@ public: static sal_Int32 GetEnumProperty( const com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet>& xProp, const ::rtl::OUString& rName, long nDefault ); + static ::rtl::OUString GetStringProperty( + const com::sun::star::uno::Reference<com::sun::star::beans::XPropertySet>& xProp, + const ::rtl::OUString& rName, const ::rtl::OUString& rDefault ); static sal_Bool GetBoolFromAny( const com::sun::star::uno::Any& aAny ); static sal_Int16 GetInt16FromAny( const com::sun::star::uno::Any& aAny ); static sal_Int32 GetInt32FromAny( const com::sun::star::uno::Any& aAny ); static sal_Int32 GetEnumFromAny( const com::sun::star::uno::Any& aAny ); static void SetBoolInAny( com::sun::star::uno::Any& rAny, sal_Bool bValue ); + + static void SetOptionalPropertyValue( + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& rPropSet, + const sal_Char* pPropName, const ::com::sun::star::uno::Any& rVal ); + + template<typename ValueType> + static void SetOptionalPropertyValue( + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& rPropSet, + const sal_Char* pPropName, const ValueType& rVal ) + { + ::com::sun::star::uno::Any any; + any <<= rVal; + SetOptionalPropertyValue(rPropSet, pPropName, any); + } }; diff --git a/sc/inc/pivot.hxx b/sc/inc/pivot.hxx index e77dd60f18bb..100463cb5542 100644 --- a/sc/inc/pivot.hxx +++ b/sc/inc/pivot.hxx @@ -53,6 +53,7 @@ #include "address.hxx" #include <vector> +#include <boost/shared_ptr.hpp> class SubTotal; #include "collect.hxx" @@ -69,7 +70,9 @@ class SvStream; class ScDocument; class ScUserListData; class ScProgress; -struct LabelData; +struct ScDPLabelData; + +typedef ::boost::shared_ptr<ScDPLabelData> ScDPLabelDataRef; // ----------------------------------------------------------------------- @@ -93,8 +96,7 @@ struct ScPivotParam SCCOL nCol; // Cursor Position / SCROW nRow; // bzw. Anfang des Zielbereiches SCTAB nTab; - LabelData** ppLabelArr; - SCSIZE nLabels; + ::std::vector<ScDPLabelDataRef> maLabelArray; PivotField aPageArr[PIVOT_MAXPAGEFIELD]; PivotField aColArr[PIVOT_MAXFIELD]; PivotField aRowArr[PIVOT_MAXFIELD]; @@ -115,10 +117,8 @@ struct ScPivotParam ScPivotParam& operator= ( const ScPivotParam& r ); BOOL operator== ( const ScPivotParam& r ) const; //UNUSED2009-05 void Clear (); - void ClearLabelData (); void ClearPivotArrays(); - void SetLabelData ( LabelData** ppLabArr, - SCSIZE nLab ); + void SetLabelData (const ::std::vector<ScDPLabelDataRef>& r); void SetPivotArrays ( const PivotField* pPageArr, const PivotField* pColArr, const PivotField* pRowArr, @@ -136,24 +136,45 @@ typedef PivotField PivotPageFieldArr[PIVOT_MAXPAGEFIELD]; //------------------------------------------------------------------------ -struct LabelData +struct ScDPLabelData { - String maName; /// Visible name of the dimension. + ::rtl::OUString maName; /// Original name of the dimension. + ::rtl::OUString maLayoutName; /// Layout name (display name) SCsCOL mnCol; USHORT mnFuncMask; /// Page/Column/Row subtotal function. sal_Int32 mnUsedHier; /// Used hierarchy. bool mbShowAll; /// true = Show all (also empty) results. bool mbIsValue; /// true = Sum or count in data field. + struct Member + { + ::rtl::OUString maName; + ::rtl::OUString maLayoutName; + bool mbVisible; + bool mbShowDetails; + + Member(); + + /** + * return the name that should be displayed in the dp dialogs i.e. + * when the layout name is present, use it, or else use the original + * name. + */ + ::rtl::OUString SC_DLLPUBLIC getDisplayName() const; + }; + ::std::vector<Member> maMembers; ::com::sun::star::uno::Sequence< ::rtl::OUString > maHiers; /// Hierarchies. - ::com::sun::star::uno::Sequence< ::rtl::OUString > maMembers; /// Members. - ::com::sun::star::uno::Sequence< sal_Bool > maVisible; /// Visibility of members. - ::com::sun::star::uno::Sequence< sal_Bool > maShowDet; /// Show details of members. ::com::sun::star::sheet::DataPilotFieldSortInfo maSortInfo; /// Sorting info. ::com::sun::star::sheet::DataPilotFieldLayoutInfo maLayoutInfo; /// Layout info. ::com::sun::star::sheet::DataPilotFieldAutoShowInfo maShowInfo; /// AutoShow info. - explicit LabelData( const String& rName, short nCol, bool bIsValue ); + explicit ScDPLabelData( const String& rName, short nCol, bool bIsValue ); + + /** + * return the name that should be displayed in the dp dialogs i.e. when + * the layout name is present, use it, or else use the original name. + */ + ::rtl::OUString SC_DLLPUBLIC getDisplayName() const; }; // ============================================================================ @@ -171,7 +192,6 @@ struct ScDPFuncData // ============================================================================ -typedef LabelData ScDPLabelData; typedef std::vector< ScDPLabelData > ScDPLabelDataVec; typedef std::vector< String > ScDPNameVec; diff --git a/sc/inc/sc.hrc b/sc/inc/sc.hrc index 8d3304867f78..62114c892ec3 100644 --- a/sc/inc/sc.hrc +++ b/sc/inc/sc.hrc @@ -1441,6 +1441,8 @@ #define RID_IMG_H_DROP_URL (BMP_START + 5) #define RID_IMG_H_DROP_LINK (BMP_START + 6) #define RID_IMG_H_DROP_COPY (BMP_START + 7) +#define RID_IMG_SELECT_CURRENT (BMP_START + 8) +#define RID_IMG_UNSELECT_CURRENT (BMP_START + 9) #define RID_SCPTR_PIVOTCOL (BMP_START + 81) #define RID_SCPTR_PIVOTROW (BMP_START + 82) @@ -1632,8 +1634,9 @@ #define RID_SCDLG_DOCPROTECTION (SC_DIALOGS_START + 149) #define RID_SCDLG_RETYPEPASS (SC_DIALOGS_START + 150) #define RID_SCDLG_RETYPEPASS_INPUT (SC_DIALOGS_START + 151) +#define RID_POPUP_FILTER (SC_DIALOGS_START + 152) -#define SC_DIALOGS_END (SC_DIALOGS_START + 152) +#define SC_DIALOGS_END (SC_DIALOGS_START + 153) #ifndef STD_MASKCOLOR #define STD_MASKCOLOR Color { Red = 0xFF00; Green = 0x0000; Blue = 0xFF00; } diff --git a/sc/inc/scabstdlg.hxx b/sc/inc/scabstdlg.hxx index 94084aab4f1b..ba62b9a5de06 100644 --- a/sc/inc/scabstdlg.hxx +++ b/sc/inc/scabstdlg.hxx @@ -238,7 +238,7 @@ class AbstractScDPSubtotalDlg : public VclAbstractDialog //add for ScDPSubtotal { public: virtual USHORT GetFuncMask() const = 0; - virtual void FillLabelData( LabelData& rLabelData ) const = 0; + virtual void FillLabelData( ScDPLabelData& rLabelData ) const = 0; }; class AbstractScDPNumGroupDlg : public VclAbstractDialog diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 9fda5d522fdc..f400054d00b7 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -294,6 +294,7 @@ public: } ScBaseCell* GetCell( SCCOL nCol, SCROW nRow ) const; + void GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const; void GetLastDataPos(SCCOL& rCol, SCROW& rRow) const; /** Returns the pointer to a cell note object at the passed cell address. */ diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx index 010e420feb42..18829290eb93 100644 --- a/sc/inc/unonames.hxx +++ b/sc/inc/unonames.hxx @@ -561,6 +561,10 @@ #define SC_UNO_ROWFIELDCOUNT "RowFieldCount" #define SC_UNO_COLUMNFIELDCOUNT "ColumnFieldCount" #define SC_UNO_DATAFIELDCOUNT "DataFieldCount" +#define SC_UNO_LAYOUTNAME "LayoutName" +#define SC_UNO_FIELD_SUBTOTALNAME "FieldSubtotalName" +#define SC_UNO_GRANDTOTAL_NAME "GrandTotalName" +#define SC_UNO_HAS_HIDDEN_MEMBER "HasHiddenMember" // (preliminary:) #define SC_UNO_REFVALUE "ReferenceValue" diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 4205c0f59dcc..3da3d3810f0b 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -1376,13 +1376,13 @@ SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirecti return nLines; } -//UNUSED2009-05 SCROW ScColumn::GetFirstDataPos() const -//UNUSED2009-05 { -//UNUSED2009-05 if (nCount) -//UNUSED2009-05 return pItems[0].nRow; -//UNUSED2009-05 else -//UNUSED2009-05 return 0; -//UNUSED2009-05 } +SCROW ScColumn::GetFirstDataPos() const +{ + if (nCount) + return pItems[0].nRow; + else + return 0; +} SCROW ScColumn::GetLastDataPos() const { diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx index 2b0b3821dcc2..18370d2f5a0f 100644 --- a/sc/source/core/data/documen8.cxx +++ b/sc/source/core/data/documen8.cxx @@ -96,6 +96,7 @@ #include "globstr.hrc" #include "sc.hrc" #include "charthelper.hxx" +#include "dpobject.hxx" #define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue() @@ -700,8 +701,13 @@ BOOL ScDocument::OnlineSpellInRange( const ScRange& rSpellRange, ScAddress& rSpe // skip everything left of rSpellPos: while ( pCell && nRow == rSpellPos.Row() && nCol < rSpellPos.Col() ) pCell = aIter.GetNext( nCol, nRow ); - while ( pCell ) + + for (; pCell; pCell = aIter.GetNext(nCol, nRow)) { + if (pDPCollection && pDPCollection->HasDPTable(nCol, nRow, nTab)) + // Don't spell check within datapilot table. + continue; + CellType eType = pCell->GetCellType(); if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT ) { @@ -786,8 +792,6 @@ BOOL ScDocument::OnlineSpellInRange( const ScRange& rSpellRange, ScAddress& rSpe if ( ++nCellCount >= SPELL_MAXCELLS ) // seen enough cells? break; - - pCell = aIter.GetNext( nCol, nRow ); } if ( pCell ) diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 4dd3f34e3f0d..f8fa2bc46c9b 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -639,6 +639,32 @@ BOOL ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) cons return FALSE; } +bool ScDocument::ShrinkToDataArea(SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow) const +{ + if (!ValidTab(nTab) || !pTab[nTab]) + return false; + + SCCOL nCol1, nCol2; + SCROW nRow1, nRow2; + pTab[nTab]->GetFirstDataPos(nCol1, nRow1); + pTab[nTab]->GetLastDataPos(nCol2, nRow2); + + if (nCol1 > nCol2 || nRow1 > nRow2) + // invalid range. + return false; + + // Make sure the area only shrinks, and doesn't grow. + if (rStartCol < nCol1) + rStartCol = nCol1; + if (nCol2 < rEndCol) + rEndCol = nCol2; + if (rStartRow < nRow1) + rStartRow = nRow1; + if (nRow2 < rEndRow) + rEndRow = nRow2; + + return true; // success! +} // zusammenhaengender Bereich diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx index 09f32b4ba1b1..29284b20e4bb 100644 --- a/sc/source/core/data/dpgroup.cxx +++ b/sc/source/core/data/dpgroup.cxx @@ -70,6 +70,7 @@ using ::rtl::OUStringHash; using ::std::vector; using ::std::hash_set; using ::std::hash_map; +using ::boost::shared_ptr; #define D_TIMEFACTOR 86400.0 @@ -977,7 +978,7 @@ String lcl_GetNumGroupForValue( double fValue, const ScDPNumGroupInfo& rInfo, bo return lcl_GetNumGroupName( fGroupStart, rInfo, bHasNonInteger, cDecSeparator, pFormatter ); } -ScDPGroupTableData::ScDPGroupTableData( ScDPTableData* pSource, ScDocument* pDocument ) : +ScDPGroupTableData::ScDPGroupTableData( const shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument ) : ScDPTableData(pDocument), pSourceData( pSource ), pDoc( pDocument ) @@ -992,7 +993,6 @@ ScDPGroupTableData::ScDPGroupTableData( ScDPTableData* pSource, ScDocument* pDoc ScDPGroupTableData::~ScDPGroupTableData() { delete[] pNumGroups; - delete pSourceData; } void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup ) diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index ad9795d11c4d..295ed78159b3 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -75,9 +75,11 @@ #include <svl/zforlist.hxx> // IsNumberFormat #include <vector> +#include <stdio.h> using namespace com::sun::star; using ::std::vector; +using ::boost::shared_ptr; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY; @@ -162,11 +164,14 @@ ScDPObject::ScDPObject( ScDocument* pD ) : pSheetDesc( NULL ), pImpDesc( NULL ), pServDesc( NULL ), + mpTableData(static_cast<ScDPTableData*>(NULL)), pOutput( NULL ), bSettingsChanged( FALSE ), bAlive( FALSE ), + mnAutoFormatIndex( 65535 ), bAllowMove( FALSE ), - nHeaderRows( 0 ) + nHeaderRows( 0 ), + mbHeaderLayout(false) { } @@ -180,11 +185,14 @@ ScDPObject::ScDPObject(const ScDPObject& r) : pSheetDesc( NULL ), pImpDesc( NULL ), pServDesc( NULL ), + mpTableData(static_cast<ScDPTableData*>(NULL)), pOutput( NULL ), bSettingsChanged( FALSE ), bAlive( FALSE ), + mnAutoFormatIndex( r.mnAutoFormatIndex ), bAllowMove( FALSE ), - nHeaderRows( r.nHeaderRows ) + nHeaderRows( r.nHeaderRows ), + mbHeaderLayout( r.mbHeaderLayout ) { if (r.pSaveData) pSaveData = new ScDPSaveData(*r.pSaveData); @@ -232,6 +240,26 @@ void ScDPObject::SetSaveData(const ScDPSaveData& rData) InvalidateData(); // re-init source from SaveData } +void ScDPObject::SetAutoFormatIndex(const sal_uInt16 nIndex) +{ + mnAutoFormatIndex = nIndex; +} + +sal_uInt16 ScDPObject::GetAutoFormatIndex() const +{ + return mnAutoFormatIndex; +} + +void ScDPObject::SetHeaderLayout (bool bUseGrid) +{ + mbHeaderLayout = bUseGrid; +} + +bool ScDPObject::GetHeaderLayout() const +{ + return mbHeaderLayout; +} + void ScDPObject::SetOutRange(const ScRange& rRange) { aOutRange = rRange; @@ -325,6 +353,22 @@ void ScDPObject::SetTag(const String& rNew) aTableTag = rNew; } +bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos) +{ + if (!pSaveData) + return false; + + long nDataDimCount = pSaveData->GetDataDimensionCount(); + if (nDataDimCount != 1) + // There has to be exactly one data dimension for the description to + // appear at top-left corner. + return false; + + CreateOutput(); + ScRange aTabRange = pOutput->GetOutputRange(sheet::DataPilotOutputRangeType::TABLE); + return (rPos == aTabRange.aStart); +} + uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource() { CreateObjects(); @@ -338,6 +382,7 @@ void ScDPObject::CreateOutput() { BOOL bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton(); pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton ); + pOutput->SetHeaderLayout ( mbHeaderLayout ); long nOldRows = nHeaderRows; nHeaderRows = pOutput->GetHeaderRows(); @@ -365,11 +410,43 @@ void ScDPObject::CreateOutput() } } +ScDPTableData* ScDPObject::GetTableData() +{ + if (!mpTableData) + { + if ( pImpDesc ) + { + // database data + mpTableData.reset(new ScDatabaseDPData(pDoc, *pImpDesc)); + } + else + { + // cell data + if (!pSheetDesc) + { + DBG_ERROR("no source descriptor"); + pSheetDesc = new ScSheetSourceDesc; // dummy defaults + } + mpTableData.reset(new ScSheetDPData(pDoc, *pSheetDesc)); + } + + // grouping (for cell or database data) + if ( pSaveData && pSaveData->GetExistingDimensionData() ) + { + shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc)); + pSaveData->GetExistingDimensionData()->WriteToData(*pGroupData); + mpTableData = pGroupData; + } + } + + return mpTableData.get(); +} + void ScDPObject::CreateObjects() { // if groups are involved, create a new source with the ScDPGroupTableData if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() ) - xSource = NULL; + InvalidateSource(); if (!xSource.is()) { @@ -387,33 +464,9 @@ void ScDPObject::CreateObjects() if ( !xSource.is() ) // database or sheet data, or error in CreateSource { DBG_ASSERT( !pServDesc, "DPSource could not be created" ); - - ScDPTableData* pData = NULL; - if ( pImpDesc ) - { - // database data - pData = new ScDatabaseDPData( pDoc, *pImpDesc ); - } - else - { - // cell data - if (!pSheetDesc) - { - DBG_ERROR("no source descriptor"); - pSheetDesc = new ScSheetSourceDesc; // dummy defaults - } - pData = new ScSheetDPData( pDoc, *pSheetDesc ); - } - - // grouping (for cell or database data) - if ( pSaveData && pSaveData->GetExistingDimensionData() ) - { - ScDPGroupTableData* pGroupData = new ScDPGroupTableData( pData, pDoc ); - pSaveData->GetExistingDimensionData()->WriteToData( *pGroupData ); - pData = pGroupData; - } - - xSource = new ScDPSource( pData ); + ScDPTableData* pData = GetTableData(); + ScDPSource* pSource = new ScDPSource( pData ); + xSource = pSource; } if (pSaveData) @@ -450,6 +503,7 @@ void ScDPObject::InvalidateData() void ScDPObject::InvalidateSource() { xSource = NULL; + mpTableData.reset(); } ScRange ScDPObject::GetNewOutputRange( BOOL& rOverflow ) @@ -484,6 +538,9 @@ void ScDPObject::Output( const ScAddress& rPos ) // aOutRange is always the range that was last output to the document aOutRange = pOutput->GetOutputRange(); + const ScAddress& s = aOutRange.aStart; + const ScAddress& e = aOutRange.aEnd; + pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE); } const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType ) @@ -533,6 +590,63 @@ void ScDPObject::RefreshAfterLoad() nHeaderRows = 0; // nothing found, no drop-down lists } +void ScDPObject::BuildAllDimensionMembers() +{ + if (!pSaveData) + return; + + pSaveData->BuildAllDimensionMembers(GetTableData()); +} + +bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames ) +{ + vector<ScDPLabelData::Member> aMembers; + if (!GetMembers(nDim, GetUsedHierarchy(nDim), aMembers)) + return false; + + size_t n = aMembers.size(); + rNames.realloc(n); + for (size_t i = 0; i < n; ++i) + rNames[i] = aMembers[i].maName; + + return true; +} + +bool ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, vector<ScDPLabelData::Member>& rMembers ) +{ + Reference< container::XNameAccess > xMembersNA; + if (!GetMembersNA( nDim, nHier, xMembersNA )) + return false; + + Reference<container::XIndexAccess> xMembersIA( new ScNameToIndexAccess(xMembersNA) ); + sal_Int32 nCount = xMembersIA->getCount(); + vector<ScDPLabelData::Member> aMembers; + aMembers.reserve(nCount); + + for (sal_Int32 i = 0; i < nCount; ++i) + { + Reference<container::XNamed> xMember(xMembersIA->getByIndex(i), UNO_QUERY); + ScDPLabelData::Member aMem; + + if (xMember.is()) + aMem.maName = xMember->getName(); + + Reference<beans::XPropertySet> xMemProp(xMember, UNO_QUERY); + if (xMemProp.is()) + { + aMem.mbVisible = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_ISVISIBL)); + aMem.mbShowDetails = ScUnoHelpFunctions::GetBoolProperty(xMemProp, OUString::createFromAscii(SC_UNO_SHOWDETA)); + + aMem.maLayoutName = ScUnoHelpFunctions::GetStringProperty( + xMemProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString()); + } + + aMembers.push_back(aMem); + } + rMembers.swap(aMembers); + return true; +} + void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode, const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) { @@ -655,23 +769,33 @@ void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> rTableData = xDrillDownData->getDrillDownData(filters); } -BOOL ScDPObject::IsDimNameInUse( const String& rName ) const +bool ScDPObject::IsDimNameInUse(const OUString& rName) const { - if ( xSource.is() ) + if (!xSource.is()) + return false; + + Reference<container::XNameAccess> xDims = xSource->getDimensions(); + Sequence<OUString> aDimNames = xDims->getElementNames(); + sal_Int32 n = aDimNames.getLength(); + for (sal_Int32 i = 0; i < n; ++i) { - uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); - if ( xDimsName.is() ) + const OUString& rDimName = aDimNames[i]; + if (rDimName.equalsIgnoreAsciiCase(rName)) + return true; + + Reference<beans::XPropertySet> xPropSet(xDims->getByName(rDimName), UNO_QUERY); + if (!xPropSet.is()) + continue; + + Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_LAYOUTNAME)); + OUString aLayoutName; + if (any >>= aLayoutName) { - rtl::OUString aCompare( rName ); - uno::Sequence<rtl::OUString> aNames = xDimsName->getElementNames(); - long nCount = aNames.getLength(); - const rtl::OUString* pArr = aNames.getConstArray(); - for (long nPos=0; nPos<nCount; nPos++) - if ( pArr[nPos] == aCompare ) //! ignore case - return TRUE; + if (aLayoutName.equalsIgnoreAsciiCase(rName)) + return true; } } - return FALSE; // not found + return false; } String ScDPObject::GetDimName( long nDim, BOOL& rIsDataLayout ) @@ -1732,7 +1856,7 @@ BOOL ScDPObject::FillOldParam(ScPivotParam& rParam, BOOL bForFile) const return TRUE; } -void lcl_FillLabelData( LabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp ) +void lcl_FillLabelData( ScDPLabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp ) { uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY ); if ( xDimProp.is() && xDimSupp.is() ) @@ -1778,6 +1902,8 @@ void lcl_FillLabelData( LabelData& rData, const uno::Reference< beans::XProperty BOOL ScDPObject::FillLabelData(ScPivotParam& rParam) { + rParam.maLabelArray.clear(); + ((ScDPObject*)this)->CreateObjects(); uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); @@ -1788,8 +1914,6 @@ BOOL ScDPObject::FillLabelData(ScPivotParam& rParam) if (!nDimCount) return FALSE; - SCSIZE nOutCount = 0; - LabelData** aLabelArr = new LabelData*[nDimCount]; for (long nDim=0; nDim < nDimCount; nDim++) { String aFieldName; @@ -1819,29 +1943,24 @@ BOOL ScDPObject::FillLabelData(ScPivotParam& rParam) { } + OUString aLayoutName = ScUnoHelpFunctions::GetStringProperty( + xDimProp, OUString::createFromAscii(SC_UNO_LAYOUTNAME), OUString()); + if ( aFieldName.Len() && !bData && !bDuplicated ) { SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ??? bool bIsValue = true; //! check - aLabelArr[nOutCount] = new LabelData( aFieldName, nCol, bIsValue ); - - LabelData& rLabelData = *aLabelArr[nOutCount]; - GetHierarchies( nDim, rLabelData.maHiers ); - GetMembers( nDim, rLabelData.maMembers, &rLabelData.maVisible, &rLabelData.maShowDet ); - lcl_FillLabelData( rLabelData, xDimProp ); - - ++nOutCount; + ScDPLabelDataRef pNewLabel(new ScDPLabelData(aFieldName, nCol, bIsValue)); + pNewLabel->maLayoutName = aLayoutName; + GetHierarchies(nDim, pNewLabel->maHiers); + GetMembers(nDim, GetUsedHierarchy(nDim), pNewLabel->maMembers); + lcl_FillLabelData(*pNewLabel, xDimProp); + rParam.maLabelArray.push_back(pNewLabel); } } } - rParam.SetLabelData( aLabelArr, nOutCount ); - - for (SCSIZE i=0; i<nOutCount; i++) - delete aLabelArr[i]; - delete[] aLabelArr; - return TRUE; } @@ -1890,14 +2009,6 @@ BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameA return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers ); } -BOOL ScDPObject::GetMembers( sal_Int32 nDim, - uno::Sequence< rtl::OUString >& rMembers, - uno::Sequence< sal_Bool >* pVisible, - uno::Sequence< sal_Bool >* pShowDet ) -{ - return GetMembers( nDim, GetUsedHierarchy( nDim ), rMembers, pVisible, pShowDet ); -} - BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers ) { BOOL bRet = FALSE; @@ -1933,55 +2044,6 @@ BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< return bRet; } -BOOL ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier, - uno::Sequence< rtl::OUString >& rMembers, - uno::Sequence< sal_Bool >* pVisible, - uno::Sequence< sal_Bool >* pShowDet ) -{ - BOOL bRet = FALSE; - uno::Reference< container::XNameAccess > xMembersNA; - if( GetMembersNA( nDim, nHier, xMembersNA ) ) - { - uno::Reference< container::XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) ); - sal_Int32 nCount = xMembersIA->getCount(); - rMembers.realloc( nCount ); - if( pVisible ) - pVisible->realloc( nCount ); - if( pShowDet ) - pShowDet->realloc( nCount ); - - rtl::OUString* pAry = rMembers.getArray(); - for( sal_Int32 nItem = 0; nItem < nCount; ++nItem ) - { - uno::Reference< container::XNamed > xMember( xMembersIA->getByIndex( nItem ), uno::UNO_QUERY ); - if( xMember.is() ) - pAry[ nItem ] = xMember->getName(); - if( pVisible || pShowDet ) - { - uno::Reference< beans::XPropertySet > xMemProp( xMember, uno::UNO_QUERY ); - if( pVisible ) - { - sal_Bool bVis = sal_True; - if( xMemProp.is() ) - bVis = ScUnoHelpFunctions::GetBoolProperty( xMemProp, - rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_ISVISIBL ) ) ); - (*pVisible)[ nItem ] = bVis; - } - if( pShowDet ) - { - sal_Bool bShow = sal_True; - if( xMemProp.is() ) - bShow = ScUnoHelpFunctions::GetBoolProperty( xMemProp, - rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SHOWDETA ) ) ); - (*pShowDet)[ nItem ] = bShow; - } - } - } - bRet = TRUE; - } - return bRet; -} - //------------------------------------------------------------------------ // convert old pivot tables into new datapilot tables @@ -2376,7 +2438,7 @@ void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const ScDPObject* pDestObj = new ScDPObject( *pSourceObj ); pDestObj->SetAlive(TRUE); - if ( !r.Insert(pDestObj) ) + if ( !r.InsertNewTable(pDestObj) ) { DBG_ERROR("cannot insert DPObject"); DELETEZ( pDestObj ); @@ -2411,6 +2473,39 @@ ScSimpleSharedString& ScDPCollection::GetSharedString() return maSharedString; } +void ScDPCollection::FreeTable(ScDPObject* pDPObj) +{ + const ScRange& rOutRange = pDPObj->GetOutRange(); + const ScAddress& s = rOutRange.aStart; + const ScAddress& e = rOutRange.aEnd; + pDoc->RemoveFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE); + Free(pDPObj); +} + +bool ScDPCollection::InsertNewTable(ScDPObject* pDPObj) +{ + bool bSuccess = Insert(pDPObj); + if (bSuccess) + { + const ScRange& rOutRange = pDPObj->GetOutRange(); + const ScAddress& s = rOutRange.aStart; + const ScAddress& e = rOutRange.aEnd; + pDoc->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), SC_MF_DP_TABLE); + } + return bSuccess; +} + +bool ScDPCollection::HasDPTable(SCCOL nCol, SCROW nRow, SCTAB nTab) const +{ + const ScMergeFlagAttr* pMergeAttr = static_cast<const ScMergeFlagAttr*>( + pDoc->GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG)); + + if (!pMergeAttr) + return false; + + return pMergeAttr->HasDPTable(); +} + ScDPCacheCell* ScDPCollection::getCacheCellFromPool(const ScDPCacheCell& rCell) { ScDPCacheCell aCell(rCell); diff --git a/sc/source/core/data/dpoutput.cxx b/sc/source/core/data/dpoutput.cxx index d1fad68f16a2..10dcbfa8238e 100644 --- a/sc/source/core/data/dpoutput.cxx +++ b/sc/source/core/data/dpoutput.cxx @@ -81,6 +81,7 @@ using namespace com::sun::star; using ::std::vector; +using ::com::sun::star::beans::XPropertySet; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::Reference; @@ -98,7 +99,6 @@ using ::rtl::OUString; #define DP_PROP_ORIENTATION "Orientation" #define DP_PROP_POSITION "Position" #define DP_PROP_USEDHIERARCHY "UsedHierarchy" -#define DP_PROP_DATADESCR "DataDescription" #define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension" #define DP_PROP_NUMBERFORMAT "NumberFormat" #define DP_PROP_FILTER "Filter" @@ -119,9 +119,15 @@ struct ScDPOutLevelData long nLevel; long nDimPos; uno::Sequence<sheet::MemberResult> aResult; - String aCaption; + String maName; /// Name is the internal field name. + String aCaption; /// Caption is the name visible in the output table. + bool mbHasHiddenMember; - ScDPOutLevelData() { nDim = nHier = nLevel = nDimPos = -1; } + ScDPOutLevelData() + { + nDim = nHier = nLevel = nDimPos = -1; + mbHasHiddenMember = false; + } BOOL operator<(const ScDPOutLevelData& r) const { return nDimPos<r.nDimPos || ( nDimPos==r.nDimPos && nHier<r.nHier ) || @@ -370,13 +376,15 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS aStartPos( rPos ), bDoFilter( bFilter ), bResultsError( FALSE ), + mbHasDataLayout(false), pColNumFmt( NULL ), pRowNumFmt( NULL ), nColFmtCount( 0 ), nRowFmtCount( 0 ), nSingleNumFmt( 0 ), bSizesValid( FALSE ), - bSizeOverflow( FALSE ) + bSizeOverflow( FALSE ), + mbHeaderLayout( false ) { nTabStartCol = nMemberStartCol = nDataStartCol = nTabEndCol = 0; nTabStartRow = nMemberStartRow = nDataStartRow = nTabEndRow = 0; @@ -413,6 +421,8 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS BOOL bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp, rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ); + bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty( + xDimProp, OUString::createFromAscii(SC_UNO_HAS_HIDDEN_MEMBER)); if ( eDimOrient != sheet::DataPilotFieldOrientation_HIDDEN ) { @@ -443,7 +453,17 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS xLevel, uno::UNO_QUERY ); if ( xLevNam.is() && xLevRes.is() ) { - String aCaption = String(xLevNam->getName()); //! Caption... + String aName = xLevNam->getName(); + OUString aCaption = aName; // Caption equals the field name by default. + Reference<XPropertySet> xPropSet(xLevel, UNO_QUERY); + if (xPropSet.is()) + { + Any any = xPropSet->getPropertyValue( + OUString::createFromAscii(SC_UNO_LAYOUTNAME)); + any >>= aCaption; + } + + bool bRowFieldHasMember = false; switch ( eDimOrient ) { case sheet::DataPilotFieldOrientation_COLUMN: @@ -452,7 +472,9 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS pColFields[nColFieldCount].nLevel = nLev; pColFields[nColFieldCount].nDimPos = nDimPos; pColFields[nColFieldCount].aResult = xLevRes->getResults(); + pColFields[nColFieldCount].maName = aName; pColFields[nColFieldCount].aCaption= aCaption; + pColFields[nColFieldCount].mbHasHiddenMember = bHasHiddenMember; if (!lcl_MemberEmpty(pColFields[nColFieldCount].aResult)) ++nColFieldCount; break; @@ -462,9 +484,14 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS pRowFields[nRowFieldCount].nLevel = nLev; pRowFields[nRowFieldCount].nDimPos = nDimPos; pRowFields[nRowFieldCount].aResult = xLevRes->getResults(); + pRowFields[nRowFieldCount].maName = aName; pRowFields[nRowFieldCount].aCaption= aCaption; + pRowFields[nRowFieldCount].mbHasHiddenMember = bHasHiddenMember; if (!lcl_MemberEmpty(pRowFields[nRowFieldCount].aResult)) + { ++nRowFieldCount; + bRowFieldHasMember = true; + } break; case sheet::DataPilotFieldOrientation_PAGE: pPageFields[nPageFieldCount].nDim = nDim; @@ -472,7 +499,9 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS pPageFields[nPageFieldCount].nLevel = nLev; pPageFields[nPageFieldCount].nDimPos = nDimPos; pPageFields[nPageFieldCount].aResult = lcl_GetSelectedPageAsResult(xDimProp); + pPageFields[nPageFieldCount].maName = aName; pPageFields[nPageFieldCount].aCaption= aCaption; + pPageFields[nPageFieldCount].mbHasHiddenMember = bHasHiddenMember; // no check on results for page fields ++nPageFieldCount; break; @@ -485,6 +514,9 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS // get number formats from data dimensions if ( bIsDataLayout ) { + if (bRowFieldHasMember) + mbHasDataLayout = true; + DBG_ASSERT( nLevCount == 1, "data layout: multiple levels?" ); if ( eDimOrient == sheet::DataPilotFieldOrientation_COLUMN ) lcl_FillNumberFormats( pColNumFmt, nColFmtCount, xLevRes, xDims ); @@ -528,7 +560,7 @@ ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsS try { uno::Any aAny = xSrcProp->getPropertyValue( - rtl::OUString::createFromAscii(DP_PROP_DATADESCR) ); + rtl::OUString::createFromAscii(SC_UNO_DATADESC) ); rtl::OUString aUStr; aAny >>= aUStr; aDataDescription = String( aUStr ); @@ -605,9 +637,16 @@ void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::MemberResult& rData, BOOL bColHeader, long nLevel ) { long nFlags = rData.Flags; + + rtl::OUStringBuffer aCaptionBuf; + if (!(nFlags & sheet::MemberResultFlags::NUMERIC)) + // This caption is not a number. Make sure it won't get parsed as one. + aCaptionBuf.append(sal_Unicode('\'')); + aCaptionBuf.append(rData.Caption); + if ( nFlags & sheet::MemberResultFlags::HASMEMBER ) { - pDoc->SetString( nCol, nRow, nTab, rData.Caption ); + pDoc->SetString( nCol, nRow, nTab, aCaptionBuf.makeStringAndClear() ); } else { @@ -638,14 +677,20 @@ void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab, } } -void ScDPOutput::FieldCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rCaption, BOOL bFrame ) +void ScDPOutput::FieldCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rCaption, + bool bInTable, bool bPopup, bool bHasHiddenMember ) { pDoc->SetString( nCol, nRow, nTab, rCaption ); - if (bFrame) + if (bInTable) lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 ); // Button - pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr(SC_MF_BUTTON) ); + sal_uInt16 nMergeFlag = SC_MF_BUTTON; + if (bPopup) + nMergeFlag |= SC_MF_BUTTON_POPUP; + if (bHasHiddenMember) + nMergeFlag |= SC_MF_HIDDEN_MEMBER; + pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag); lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLE_FIELDNAME ); } @@ -653,7 +698,7 @@ void ScDPOutput::FieldCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rC void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab ) { pDoc->SetString( nCol, nRow, nTab, ScGlobal::GetRscString(STR_CELL_FILTER) ); - pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr(SC_MF_BUTTON) ); + pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON); } void ScDPOutput::CalcSizes() @@ -666,7 +711,11 @@ void ScDPOutput::CalcSizes() nRowCount = aData.getLength(); const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray(); nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0; - nHeaderSize = 1; // one row for field names + + nHeaderSize = 1; + if (GetHeaderLayout() && nColFieldCount == 0) + // Insert an extra header row only when there is no column field. + nHeaderSize = 2; // calculate output positions and sizes @@ -775,7 +824,7 @@ void ScDPOutput::Output() SCCOL nHdrCol = aStartPos.Col(); SCROW nHdrRow = aStartPos.Row() + nField + ( bDoFilter ? 1 : 0 ); // draw without frame for consistency with filter button: - FieldCell( nHdrCol, nHdrRow, nTab, pPageFields[nField].aCaption, FALSE ); + FieldCell( nHdrCol, nHdrRow, nTab, pPageFields[nField].aCaption, false, false, pPageFields[nField].mbHasHiddenMember ); SCCOL nFldCol = nHdrCol + 1; String aPageValue; @@ -814,7 +863,7 @@ void ScDPOutput::Output() for (nField=0; nField<nColFieldCount; nField++) { SCCOL nHdrCol = nDataStartCol + (SCCOL)nField; //! check for overflow - FieldCell( nHdrCol, nTabStartRow, nTab, pColFields[nField].aCaption ); + FieldCell( nHdrCol, nTabStartRow, nTab, pColFields[nField].aCaption, true, true, pColFields[nField].mbHasHiddenMember ); SCROW nRowPos = nMemberStartRow + (SCROW)nField; //! check for overflow const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult; @@ -849,9 +898,12 @@ void ScDPOutput::Output() for (nField=0; nField<nRowFieldCount; nField++) { + bool bDataLayout = mbHasDataLayout && (nField == nRowFieldCount-1); + SCCOL nHdrCol = nTabStartCol + (SCCOL)nField; //! check for overflow SCROW nHdrRow = nDataStartRow - 1; - FieldCell( nHdrCol, nHdrRow, nTab, pRowFields[nField].aCaption ); + FieldCell( nHdrCol, nHdrRow, nTab, pRowFields[nField].aCaption, true, !bDataLayout, + pRowFields[nField].mbHasHiddenMember ); SCCOL nColPos = nMemberStartCol + (SCCOL)nField; //! check for overflow const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult; @@ -993,6 +1045,16 @@ void ScDPOutput::GetMemberResultNames( ScStrCollection& rNames, long nDimension } } +void ScDPOutput::SetHeaderLayout(bool bUseGrid) +{ + mbHeaderLayout = bUseGrid; + bSizesValid = false; +} + +bool ScDPOutput::GetHeaderLayout() const +{ + return mbHeaderLayout; +} void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData) { @@ -1146,7 +1208,7 @@ bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& for (SCCOL nColField = 0; nColField < nColFieldCount && bFilterByCol; ++nColField) { sheet::DataPilotFieldFilter filter; - filter.FieldName = pColFields[nColField].aCaption; + filter.FieldName = pColFields[nColField].maName; const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nColField].aResult; const sheet::MemberResult* pArray = rSequence.getConstArray(); @@ -1163,10 +1225,15 @@ bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& } // row fields + bool bDataLayoutExists = (nDataFieldCount > 1); for (SCROW nRowField = 0; nRowField < nRowFieldCount && bFilterByRow; ++nRowField) { + if (bDataLayoutExists && nRowField == nRowFieldCount - 1) + // There is no sense including the data layout field for filtering. + continue; + sheet::DataPilotFieldFilter filter; - filter.FieldName = pRowFields[nRowField].aCaption; + filter.FieldName = pRowFields[nRowField].maName; const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nRowField].aResult; const sheet::MemberResult* pArray = rSequence.getConstArray(); @@ -1198,8 +1265,7 @@ bool lcl_IsNamedDataField( const ScDPGetPivotDataField& rTarget, const String& r bool lcl_IsNamedCategoryField( const ScDPGetPivotDataField& rFilter, const ScDPOutLevelData& rField ) { - //! name from source instead of caption? - return ScGlobal::GetpTransliteration()->isEqual( rFilter.maFieldName, rField.aCaption ); + return ScGlobal::GetpTransliteration()->isEqual( rFilter.maFieldName, rField.maName ); } bool lcl_IsCondition( const sheet::MemberResult& rResultEntry, const ScDPGetPivotDataField& rFilter ) diff --git a/sc/source/core/data/dpoutputgeometry.cxx b/sc/source/core/data/dpoutputgeometry.cxx new file mode 100644 index 000000000000..9eace100c137 --- /dev/null +++ b/sc/source/core/data/dpoutputgeometry.cxx @@ -0,0 +1,217 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xmldpimp.cxx,v $ + * $Revision: 1.27.134.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include "dpoutputgeometry.hxx" +#include "address.hxx" + +#include <vector> + +using ::std::vector; + +ScDPOutputGeometry::ScDPOutputGeometry(const ScRange& rOutRange, bool bShowFilter, ImportType eImportType) : + maOutRange(rOutRange), + mnRowFields(0), + mnColumnFields(0), + mnPageFields(0), + mnDataFields(0), + meImportType(eImportType), + mbShowFilter(bShowFilter) +{ +} + +ScDPOutputGeometry::~ScDPOutputGeometry() +{ +} + +void ScDPOutputGeometry::setRowFieldCount(sal_uInt32 nCount) +{ + mnRowFields = nCount; +} + +void ScDPOutputGeometry::setColumnFieldCount(sal_uInt32 nCount) +{ + mnColumnFields = nCount; +} + +void ScDPOutputGeometry::setPageFieldCount(sal_uInt32 nCount) +{ + mnPageFields = nCount; +} + +void ScDPOutputGeometry::setDataFieldCount(sal_uInt32 nCount) +{ + mnDataFields = nCount; +} + +void ScDPOutputGeometry::getColumnFieldPositions(vector<ScAddress>& rAddrs) const +{ + vector<ScAddress> aAddrs; + if (!mnColumnFields) + { + rAddrs.swap(aAddrs); + return; + } + + bool bDataLayout = mnDataFields > 1; + + SCROW nCurRow = maOutRange.aStart.Row(); + + if (mnPageFields) + { + SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter; + SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1); + nCurRow = nRowEnd + 2; + } + else if (mbShowFilter) + nCurRow += 2; + + SCROW nRow = nCurRow; + SCTAB nTab = maOutRange.aStart.Tab(); + SCCOL nColStart = static_cast<SCCOL>(maOutRange.aStart.Col() + mnRowFields + (bDataLayout ? 1 : 0)); + SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnColumnFields-1); + + for (SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol) + aAddrs.push_back(ScAddress(nCol, nRow, nTab)); + rAddrs.swap(aAddrs); +} + +void ScDPOutputGeometry::getRowFieldPositions(vector<ScAddress>& rAddrs) const +{ + vector<ScAddress> aAddrs; + if (!mnRowFields) + { + rAddrs.swap(aAddrs); + return; + } + + SCROW nRow = getRowFieldHeaderRow(); + SCTAB nTab = maOutRange.aStart.Tab(); + SCCOL nColStart = maOutRange.aStart.Col(); + SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnRowFields-1); + + for (SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol) + aAddrs.push_back(ScAddress(nCol, nRow, nTab)); + rAddrs.swap(aAddrs); +} + +void ScDPOutputGeometry::getPageFieldPositions(vector<ScAddress>& rAddrs) const +{ + vector<ScAddress> aAddrs; + if (!mnPageFields) + { + rAddrs.swap(aAddrs); + return; + } + + SCTAB nTab = maOutRange.aStart.Tab(); + SCCOL nCol = maOutRange.aStart.Col(); + + SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter; + SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1); + + for (SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow) + aAddrs.push_back(ScAddress(nCol, nRow, nTab)); + rAddrs.swap(aAddrs); +} + +SCROW ScDPOutputGeometry::getRowFieldHeaderRow() const +{ + SCROW nCurRow = maOutRange.aStart.Row(); + + if (mnPageFields) + { + SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter; + SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1); + nCurRow = nRowEnd + 2; + } + else if (mbShowFilter) + nCurRow += 2; + + if (mnColumnFields) + nCurRow += static_cast<SCROW>(mnColumnFields); + else if (mnRowFields) + ++nCurRow; + + return nCurRow; +} + +ScDPOutputGeometry::FieldType ScDPOutputGeometry::getFieldButtonType(const ScAddress& rPos) const +{ + // We will ignore the table position for now. + + bool bExtraTitleRow = (mnColumnFields == 0 && meImportType == ScDPOutputGeometry::XLS); + bool bDataLayout = mnDataFields > 1; + + SCROW nCurRow = maOutRange.aStart.Row(); + + if (mnPageFields) + { + SCCOL nCol = maOutRange.aStart.Col(); + SCROW nRowStart = maOutRange.aStart.Row() + mbShowFilter; + SCROW nRowEnd = nRowStart + static_cast<SCCOL>(mnPageFields-1); + if (rPos.Col() == nCol && nRowStart <= rPos.Row() && rPos.Row() <= nRowEnd) + return Page; + + nCurRow = nRowEnd + 2; + } + else if (mbShowFilter) + nCurRow += 2; + + if (mnColumnFields) + { + SCROW nRow = nCurRow; + SCCOL nColStart = static_cast<SCCOL>(maOutRange.aStart.Col() + mnRowFields + (bDataLayout ? 1 : 0)); + SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnColumnFields-1); + if (rPos.Row() == nRow && nColStart <= rPos.Col() && rPos.Col() <= nColEnd) + return Column; + + nCurRow += static_cast<SCROW>(mnColumnFields); + } + + if (bExtraTitleRow) + ++nCurRow; + + if (mnRowFields) + { + SCCOL nColStart = maOutRange.aStart.Col(); + SCCOL nColEnd = nColStart + static_cast<SCCOL>(mnRowFields-1); + if (rPos.Row() == nCurRow && nColStart <= rPos.Col() && rPos.Col() <= nColEnd) + return Row; + } + + return None; +} diff --git a/sc/source/core/data/dpsave.cxx b/sc/source/core/data/dpsave.cxx index 62798076afb9..e66bd8dfe705 100644 --- a/sc/source/core/data/dpsave.cxx +++ b/sc/source/core/data/dpsave.cxx @@ -58,7 +58,15 @@ #include <com/sun/star/container/XNamed.hpp> #include <com/sun/star/util/XCloneable.hpp> +#include <hash_map> + using namespace com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::rtl::OUString; +using ::rtl::OUStringHash; +using ::std::hash_map; +using ::std::auto_ptr; // ----------------------------------------------------------------------- @@ -99,6 +107,7 @@ void lcl_SetBoolProperty( const uno::Reference<beans::XPropertySet>& xProp, ScDPSaveMember::ScDPSaveMember(const String& rName) : aName( rName ), + mpLayoutName(NULL), nVisibleMode( SC_DPSAVEMODE_DONTKNOW ), nShowDetailsMode( SC_DPSAVEMODE_DONTKNOW ) { @@ -106,9 +115,12 @@ ScDPSaveMember::ScDPSaveMember(const String& rName) : ScDPSaveMember::ScDPSaveMember(const ScDPSaveMember& r) : aName( r.aName ), + mpLayoutName(NULL), nVisibleMode( r.nVisibleMode ), nShowDetailsMode( r.nShowDetailsMode ) { + if (r.mpLayoutName.get()) + mpLayoutName.reset(new OUString(*r.mpLayoutName)); } ScDPSaveMember::~ScDPSaveMember() @@ -153,12 +165,23 @@ void ScDPSaveMember::SetName( const String& rNew ) aName = rNew; } -void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMember, sal_Int32 nPosition ) +void ScDPSaveMember::SetLayoutName( const OUString& rName ) { - // nothing to do? - if ( nVisibleMode == SC_DPSAVEMODE_DONTKNOW && nShowDetailsMode == SC_DPSAVEMODE_DONTKNOW && nPosition < 0 ) - return; + mpLayoutName.reset(new OUString(rName)); +} + +const OUString* ScDPSaveMember::GetLayoutName() const +{ + return mpLayoutName.get(); +} + +void ScDPSaveMember::RemoveLayoutName() +{ + mpLayoutName.reset(NULL); +} +void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMember, sal_Int32 nPosition ) +{ uno::Reference<beans::XPropertySet> xMembProp( xMember, uno::UNO_QUERY ); DBG_ASSERT( xMembProp.is(), "no properties at member" ); if ( xMembProp.is() ) @@ -173,17 +196,11 @@ void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMemb lcl_SetBoolProperty( xMembProp, rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS), (BOOL)nShowDetailsMode ); + if (mpLayoutName.get()) + ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp, SC_UNO_LAYOUTNAME, *mpLayoutName); + if ( nPosition >= 0 ) - { - try - { - xMembProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_POSITION), uno::Any(nPosition) ); - } - catch ( uno::Exception& ) - { - // position is optional - exception must be ignored - } - } + ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp, DP_PROP_POSITION, nPosition); } } @@ -191,8 +208,9 @@ void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMemb ScDPSaveDimension::ScDPSaveDimension(const String& rName, BOOL bDataLayout) : aName( rName ), - pLayoutName( NULL ), pSelectedPage( NULL ), + mpLayoutName(NULL), + mpSubtotalName(NULL), bIsDataLayout( bDataLayout ), bDupFlag( FALSE ), nOrientation( sheet::DataPilotFieldOrientation_HIDDEN ), @@ -211,6 +229,8 @@ ScDPSaveDimension::ScDPSaveDimension(const String& rName, BOOL bDataLayout) : ScDPSaveDimension::ScDPSaveDimension(const ScDPSaveDimension& r) : aName( r.aName ), + mpLayoutName(NULL), + mpSubtotalName(NULL), bIsDataLayout( r.bIsDataLayout ), bDupFlag( r.bDupFlag ), nOrientation( r.nOrientation ), @@ -251,14 +271,14 @@ ScDPSaveDimension::ScDPSaveDimension(const ScDPSaveDimension& r) : pLayoutInfo = new sheet::DataPilotFieldLayoutInfo( *(r.pLayoutInfo) ); else pLayoutInfo = NULL; - if (r.pLayoutName) - pLayoutName = new String( *(r.pLayoutName) ); - else - pLayoutName = NULL; if (r.pSelectedPage) pSelectedPage = new String( *(r.pSelectedPage) ); else pSelectedPage = NULL; + if (r.mpLayoutName.get()) + mpLayoutName.reset(new OUString(*r.mpLayoutName)); + if (r.mpSubtotalName.get()) + mpSubtotalName.reset(new OUString(*r.mpSubtotalName)); } ScDPSaveDimension::~ScDPSaveDimension() @@ -269,7 +289,6 @@ ScDPSaveDimension::~ScDPSaveDimension() delete pSortInfo; delete pAutoShowInfo; delete pLayoutInfo; - delete pLayoutName; delete pSelectedPage; delete [] pSubTotalFuncs; } @@ -370,25 +389,45 @@ void ScDPSaveDimension::SetUsedHierarchy(long nNew) nUsedHierarchy = nNew; } -BOOL ScDPSaveDimension::HasLayoutName() const +void ScDPSaveDimension::SetSubtotalName(const OUString& rName) { - return ( pLayoutName != NULL ); + mpSubtotalName.reset(new OUString(rName)); } -void ScDPSaveDimension::SetLayoutName(const String* pName) +const OUString* ScDPSaveDimension::GetSubtotalName() const { - delete pLayoutName; - if (pName) - pLayoutName = new String( *pName ); - else - pLayoutName = NULL; + return mpSubtotalName.get(); +} + +bool ScDPSaveDimension::IsMemberNameInUse(const OUString& rName) const +{ + MemberList::const_iterator itr = maMemberList.begin(), itrEnd = maMemberList.end(); + for (; itr != itrEnd; ++itr) + { + const ScDPSaveMember* pMem = *itr; + if (rName.equalsIgnoreAsciiCase(pMem->GetName())) + return true; + + const OUString* pLayoutName = pMem->GetLayoutName(); + if (pLayoutName && rName.equalsIgnoreAsciiCase(*pLayoutName)) + return true; + } + return false; +} + +void ScDPSaveDimension::SetLayoutName(const OUString& rName) +{ + mpLayoutName.reset(new OUString(rName)); +} + +const OUString* ScDPSaveDimension::GetLayoutName() const +{ + return mpLayoutName.get(); } -const String& ScDPSaveDimension::GetLayoutName() const +void ScDPSaveDimension::RemoveLayoutName() { - if (pLayoutName) - return *pLayoutName; - return aName; + mpLayoutName.reset(NULL); } void ScDPSaveDimension::SetReferenceValue(const sheet::DataPilotFieldReference* pNew) @@ -520,15 +559,15 @@ void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xD aFilter = uno::Sequence<sheet::TableFilterField>( &aField, 1 ); } // else keep empty sequence - try - { - aAny <<= aFilter; - xDimProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_FILTER), aAny ); - } - catch ( beans::UnknownPropertyException& ) - { - // recent addition - allow source to not handle it (no error) - } + + ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, DP_PROP_FILTER, aFilter); + if (mpLayoutName.get()) + ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_LAYOUTNAME, *mpLayoutName); + + const OUString* pSubTotalName = GetSubtotalName(); + if (pSubTotalName) + // Custom subtotal name, with '?' being replaced by the visible field name later. + ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_FIELD_SUBTOTALNAME, *pSubTotalName); } // Level loop outside of maMemberList loop @@ -546,6 +585,8 @@ void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xD nHierCount = xHiers->getCount(); } + sal_Bool bHasHiddenMember = false; + for (long nHier=0; nHier<nHierCount; nHier++) { uno::Reference<uno::XInterface> xHierarchy = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHier) ); @@ -585,41 +626,13 @@ void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xD rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY), (BOOL)nShowEmptyMode ); if ( pSortInfo ) - { - aAny <<= *pSortInfo; - try - { - xLevProp->setPropertyValue( rtl::OUString::createFromAscii(SC_UNO_SORTING), aAny ); - } - catch ( beans::UnknownPropertyException& ) - { - // recent addition - allow source to not handle it (no error) - } - } + ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_SORTING, *pSortInfo); + if ( pAutoShowInfo ) - { - aAny <<= *pAutoShowInfo; - try - { - xLevProp->setPropertyValue( rtl::OUString::createFromAscii(SC_UNO_AUTOSHOW), aAny ); - } - catch ( beans::UnknownPropertyException& ) - { - // recent addition - allow source to not handle it (no error) - } - } + ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_AUTOSHOW, *pAutoShowInfo); + if ( pLayoutInfo ) - { - aAny <<= *pLayoutInfo; - try - { - xLevProp->setPropertyValue( rtl::OUString::createFromAscii(SC_UNO_LAYOUT), aAny ); - } - catch ( beans::UnknownPropertyException& ) - { - // recent addition - allow source to not handle it (no error) - } - } + ScUnoHelpFunctions::SetOptionalPropertyValue(xLevProp, SC_UNO_LAYOUT, *pLayoutInfo); // exceptions are caught at ScDPSaveData::WriteToSource } @@ -638,12 +651,15 @@ void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xD for (MemberList::const_iterator i=maMemberList.begin(); i != maMemberList.end() ; i++) { - rtl::OUString aMemberName = (*i)->GetName(); + ScDPSaveMember* pMember = *i; + if (!pMember->GetIsVisible()) + bHasHiddenMember = true; + rtl::OUString aMemberName = pMember->GetName(); if ( xMembers->hasByName( aMemberName ) ) { uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface( xMembers->getByName( aMemberName ) ); - (*i)->WriteToSource( xMemberInt, nPosition ); + pMember->WriteToSource( xMemberInt, nPosition ); if ( nPosition >= 0 ) ++nPosition; // increase if initialized @@ -655,6 +671,35 @@ void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xD } } } + + if (xDimProp.is()) + ScUnoHelpFunctions::SetOptionalPropertyValue(xDimProp, SC_UNO_HAS_HIDDEN_MEMBER, bHasHiddenMember); +} + +void ScDPSaveDimension::UpdateMemberVisibility(const hash_map<OUString, bool, OUStringHash>& rData) +{ + typedef hash_map<OUString, bool, OUStringHash> DataMap; + MemberList::iterator itrMem = maMemberList.begin(), itrMemEnd = maMemberList.end(); + for (; itrMem != itrMemEnd; ++itrMem) + { + ScDPSaveMember* pMem = *itrMem; + const String& rMemName = pMem->GetName(); + DataMap::const_iterator itr = rData.find(rMemName); + if (itr != rData.end()) + pMem->SetIsVisible(itr->second); + } +} + +bool ScDPSaveDimension::HasInvisibleMember() const +{ + MemberList::const_iterator itrMem = maMemberList.begin(), itrMemEnd = maMemberList.end(); + for (; itrMem != itrMemEnd; ++itrMem) + { + const ScDPSaveMember* pMem = *itrMem; + if (!pMem->GetIsVisible()) + return true; + } + return false; } // ----------------------------------------------------------------------- @@ -666,7 +711,9 @@ ScDPSaveData::ScDPSaveData() : nIgnoreEmptyMode( SC_DPSAVEMODE_DONTKNOW ), nRepeatEmptyMode( SC_DPSAVEMODE_DONTKNOW ), bFilterButton( TRUE ), - bDrillDown( TRUE ) + bDrillDown( TRUE ), + mbDimensionMembersBuilt(false), + mpGrandTotalName(NULL) { } @@ -676,7 +723,9 @@ ScDPSaveData::ScDPSaveData(const ScDPSaveData& r) : nIgnoreEmptyMode( r.nIgnoreEmptyMode ), nRepeatEmptyMode( r.nRepeatEmptyMode ), bFilterButton( r.bFilterButton ), - bDrillDown( r.bDrillDown ) + bDrillDown( r.bDrillDown ), + mbDimensionMembersBuilt(r.mbDimensionMembersBuilt), + mpGrandTotalName(NULL) { if ( r.pDimensionData ) pDimensionData = new ScDPDimensionSaveData( *r.pDimensionData ); @@ -689,6 +738,9 @@ ScDPSaveData::ScDPSaveData(const ScDPSaveData& r) : ScDPSaveDimension* pNew = new ScDPSaveDimension( *(ScDPSaveDimension*)r.aDimList.GetObject(i) ); aDimList.Insert( pNew, LIST_APPEND ); } + + if (r.mpGrandTotalName.get()) + mpGrandTotalName.reset(new OUString(*r.mpGrandTotalName)); } ScDPSaveData& ScDPSaveData::operator= ( const ScDPSaveData& r ) @@ -707,6 +759,7 @@ ScDPSaveData& ScDPSaveData::operator= ( const ScDPSaveData& r ) nRepeatEmptyMode = r.nRepeatEmptyMode; bFilterButton = r.bFilterButton; bDrillDown = r.bDrillDown; + mbDimensionMembersBuilt = r.mbDimensionMembersBuilt; // remove old dimensions @@ -725,6 +778,9 @@ ScDPSaveData& ScDPSaveData::operator= ( const ScDPSaveData& r ) new ScDPSaveDimension( *(ScDPSaveDimension*)r.aDimList.GetObject(i) ); aDimList.Insert( pNew, LIST_APPEND ); } + + if (r.mpGrandTotalName.get()) + mpGrandTotalName.reset(new OUString(*r.mpGrandTotalName)); } return *this; } @@ -736,7 +792,8 @@ BOOL ScDPSaveData::operator== ( const ScDPSaveData& r ) const nIgnoreEmptyMode != r.nIgnoreEmptyMode || nRepeatEmptyMode != r.nRepeatEmptyMode || bFilterButton != r.bFilterButton || - bDrillDown != r.bDrillDown ) + bDrillDown != r.bDrillDown || + mbDimensionMembersBuilt != r.mbDimensionMembersBuilt) return FALSE; if ( pDimensionData || r.pDimensionData ) @@ -752,6 +809,16 @@ BOOL ScDPSaveData::operator== ( const ScDPSaveData& r ) const *(ScDPSaveDimension*)r.aDimList.GetObject(i) ) ) return FALSE; + if (mpGrandTotalName.get()) + { + if (!r.mpGrandTotalName.get()) + return false; + if (!mpGrandTotalName->equals(*r.mpGrandTotalName)) + return false; + } + else if (r.mpGrandTotalName.get()) + return false; + return TRUE; } @@ -765,6 +832,16 @@ ScDPSaveData::~ScDPSaveData() delete pDimensionData; } +void ScDPSaveData::SetGrandTotalName(const OUString& rName) +{ + mpGrandTotalName.reset(new OUString(rName)); +} + +const OUString* ScDPSaveData::GetGrandTotalName() const +{ + return mpGrandTotalName.get(); +} + ScDPSaveDimension* ScDPSaveData::GetDimensionByName(const String& rName) { long nCount = aDimList.Count(); @@ -779,7 +856,7 @@ ScDPSaveDimension* ScDPSaveData::GetDimensionByName(const String& rName) return pNew; } -ScDPSaveDimension* ScDPSaveData::GetExistingDimensionByName(const String& rName) +ScDPSaveDimension* ScDPSaveData::GetExistingDimensionByName(const String& rName) const { long nCount = aDimList.Count(); for (long i=0; i<nCount; i++) @@ -807,16 +884,25 @@ ScDPSaveDimension* ScDPSaveData::GetNewDimensionByName(const String& rName) ScDPSaveDimension* ScDPSaveData::GetDataLayoutDimension() { - ULONG nCount = aDimList.Count(); - for (ULONG i=0; i<nCount; i++) + ScDPSaveDimension* pDim = GetExistingDataLayoutDimension(); + if (pDim) + return pDim; + + ScDPSaveDimension* pNew = new ScDPSaveDimension( String(), TRUE ); + aDimList.Insert( pNew, LIST_APPEND ); + return pNew; +} + +ScDPSaveDimension* ScDPSaveData::GetExistingDataLayoutDimension() const +{ + long nCount = aDimList.Count(); + for (long i=0; i<nCount; i++) { ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i); if ( pDim->IsDataLayout() ) return pDim; } - ScDPSaveDimension* pNew = new ScDPSaveDimension( String(), TRUE ); - aDimList.Insert( pNew, LIST_APPEND ); - return pNew; + return NULL; } ScDPSaveDimension* ScDPSaveData::DuplicateDimension(const String& rName) @@ -870,6 +956,18 @@ ScDPSaveDimension* ScDPSaveData::GetInnermostDimension(USHORT nOrientation) return pInner; // the last matching one } +ScDPSaveDimension* ScDPSaveData::GetFirstDimension(sheet::DataPilotFieldOrientation eOrientation) +{ + long nCount = aDimList.Count(); + for (long i = 0; i < nCount; ++i) + { + ScDPSaveDimension* pDim = static_cast<ScDPSaveDimension*>(aDimList.GetObject(i)); + if (pDim->GetOrientation() == eOrientation && !pDim->IsDataLayout()) + return pDim; + } + return NULL; +} + long ScDPSaveData::GetDataDimensionCount() const { long nDataCount = 0; @@ -982,6 +1080,10 @@ void ScDPSaveData::WriteToSource( const uno::Reference<sheet::XDimensionsSupplie { // no error } + + const OUString* pGrandTotalName = GetGrandTotalName(); + if (pGrandTotalName) + ScUnoHelpFunctions::SetOptionalPropertyValue(xSourceProp, SC_UNO_GRANDTOTAL_NAME, *pGrandTotalName); } // exceptions in the other calls are errors @@ -1100,3 +1202,58 @@ void ScDPSaveData::SetDimensionData( const ScDPDimensionSaveData* pNew ) pDimensionData = NULL; } +void ScDPSaveData::BuildAllDimensionMembers(ScDPTableData* pData) +{ + if (mbDimensionMembersBuilt) + return; + + // First, build a dimension name-to-index map. + typedef hash_map<OUString, long, ::rtl::OUStringHash> NameIndexMap; + NameIndexMap aMap; + long nColCount = pData->GetColumnCount(); + for (long i = 0; i < nColCount; ++i) + aMap.insert( NameIndexMap::value_type(pData->getDimensionName(i), i)); + + NameIndexMap::const_iterator itrEnd = aMap.end(); + + sal_uInt32 n = aDimList.Count(); + for (sal_uInt32 i = 0; i < n; ++i) + { + ScDPSaveDimension* pDim = static_cast<ScDPSaveDimension*>(aDimList.GetObject(i)); + const String& rDimName = pDim->GetName(); + if (!rDimName.Len()) + // empty dimension name. It must be data layout. + continue; + + NameIndexMap::const_iterator itr = aMap.find(rDimName); + if (itr == itrEnd) + // dimension name not in the data. This should never happen! + continue; + + long nDimIndex = itr->second; + const TypedScStrCollection& rMembers = pData->GetColumnEntries(nDimIndex); + sal_uInt16 nMemberCount = rMembers.GetCount(); + for (sal_uInt16 j = 0; j < nMemberCount; ++j) + { + const String& rMemName = rMembers[j]->GetString(); + if (pDim->GetExistingMemberByName(rMemName)) + // this member instance already exists. nothing to do. + continue; + + auto_ptr<ScDPSaveMember> pNewMember(new ScDPSaveMember(rMemName)); + pNewMember->SetIsVisible(true); + pDim->AddMember(pNewMember.release()); + } + } + + mbDimensionMembersBuilt = true; +} + +bool ScDPSaveData::HasInvisibleMember(const OUString& rDimName) const +{ + ScDPSaveDimension* pDim = GetExistingDimensionByName(rDimName); + if (!pDim) + return false; + + return pDim->HasInvisibleMember(); +} diff --git a/sc/source/core/data/dptabres.cxx b/sc/source/core/data/dptabres.cxx index 398d4d1c7e01..e548db56d7ff 100644 --- a/sc/source/core/data/dptabres.cxx +++ b/sc/source/core/data/dptabres.cxx @@ -67,6 +67,7 @@ using ::std::vector; using ::std::pair; using ::std::hash_map; using ::com::sun::star::uno::Sequence; +using ::rtl::OUString; // ----------------------------------------------------------------------- @@ -825,11 +826,11 @@ USHORT ScDPResultData::GetMeasureRefOrient(long nMeasure) const return pMeasRefOrient[nMeasure]; } -String ScDPResultData::GetMeasureString(long nMeasure, BOOL bForce, ScSubTotalFunc eForceFunc) const +String ScDPResultData::GetMeasureString(long nMeasure, BOOL bForce, ScSubTotalFunc eForceFunc, bool& rbTotalResult) const { // with bForce==TRUE, return function instead of "result" for single measure // with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc - + rbTotalResult = false; if ( nMeasure < 0 || ( nMeasCount == 1 && !bForce && eForceFunc == SUBTOTAL_FUNC_NONE ) ) { // for user-specified subtotal function with all measures, @@ -837,12 +838,19 @@ String ScDPResultData::GetMeasureString(long nMeasure, BOOL bForce, ScSubTotalFu if ( eForceFunc != SUBTOTAL_FUNC_NONE ) return ScGlobal::GetRscString(nFuncStrIds[eForceFunc]); + rbTotalResult = true; return ScGlobal::GetRscString(STR_TABLE_ERGEBNIS); } else { DBG_ASSERT( pMeasNames && nMeasure < nMeasCount, "bumm" ); - + ScDPDimension* pDataDim = pSource->GetDataDimension(nMeasure); + if (pDataDim) + { + const OUString* pLayoutName = pDataDim->GetLayoutName(); + if (pLayoutName) + return *pLayoutName; + } String aRet; ScSubTotalFunc eFunc = ( eForceFunc == SUBTOTAL_FUNC_NONE ) ? GetMeasureFunction(nMeasure) : eForceFunc; @@ -896,6 +904,11 @@ BOOL ScDPResultData::HasCommonElement( const ScDPItemData& rFirstData, long nFir return pSource->GetData()->HasCommonElement( rFirstData, nFirstIndex, rSecondData, nSecondIndex ); } +const ScDPSource* ScDPResultData::GetSource() const +{ + return pSource; +} + // ----------------------------------------------------------------------- @@ -1172,6 +1185,33 @@ void ScDPResultMember::ProcessData( const vector<ScDPItemData>& aChildMembers, c } } +/** + * Parse subtotal string and replace all occurrences of '?' with the caption + * string. Do ensure that escaped characters are not translated. + */ +static String lcl_parseSubtotalName(const String& rSubStr, const String& rCaption) +{ + String aNewStr; + xub_StrLen n = rSubStr.Len(); + bool bEscaped = false; + for (xub_StrLen i = 0; i < n; ++i) + { + sal_Unicode c = rSubStr.GetChar(i); + if (!bEscaped && c == sal_Unicode('\\')) + { + bEscaped = true; + continue; + } + + if (!bEscaped && c == sal_Unicode('?')) + aNewStr.Append(rCaption); + else + aNewStr.Append(c); + bEscaped = false; + } + return aNewStr; +} + void ScDPResultMember::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences, long& rPos, long nMeasure, BOOL bRoot, const String* pMemberName, @@ -1204,17 +1244,25 @@ void ScDPResultMember::FillMemberResults( uno::Sequence<sheet::MemberResult>* pS } String aCaption = aName; + if (pMemberDesc) + { + const OUString* pLayoutName = pMemberDesc->GetLayoutName(); + if (pLayoutName) + { + aCaption = *pLayoutName; + bIsNumeric = false; // layout name is always non-numeric. + } + } + if ( pMemberCaption ) // use pMemberCaption if != NULL aCaption = *pMemberCaption; if (!aCaption.Len()) aCaption = ScGlobal::GetRscString(STR_EMPTYDATA); - if ( !bIsNumeric ) - { - // add a "'" character so a string isn't parsed as value in the output cell - //! have a separate bit in Flags (MemberResultFlags) instead? - aCaption.Insert( (sal_Unicode) '\'', 0 ); - } + if (bIsNumeric) + pArray[rPos].Flags |= sheet::MemberResultFlags::NUMERIC; + else + pArray[rPos].Flags &= ~sheet::MemberResultFlags::NUMERIC; if ( nSize && !bRoot ) // root is overwritten by first dimension { @@ -1277,9 +1325,30 @@ void ScDPResultMember::FillMemberResults( uno::Sequence<sheet::MemberResult>* pS if (bHasChild) eForce = lcl_GetForceFunc( pParentLevel, nUserPos ); - String aSubStr = aName; //! caption? + bool bTotalResult = false; + String aSubStr = aCaption; aSubStr += ' '; - aSubStr += pResultData->GetMeasureString(nMemberMeasure, FALSE, eForce); + aSubStr += pResultData->GetMeasureString(nMemberMeasure, FALSE, eForce, bTotalResult); + + if (bTotalResult) + { + if (pMemberDesc) + { + // single data field layout. + const OUString* pSubtotalName = pParentDim->GetSubtotalName(); + if (pSubtotalName) + aSubStr = lcl_parseSubtotalName(*pSubtotalName, aCaption); + pArray[rPos].Flags &= ~sheet::MemberResultFlags::GRANDTOTAL; + } + else + { + // root member - subtotal (grand total?) for multi-data field layout. + const rtl::OUString* pGrandTotalName = pResultData->GetSource()->GetGrandTotalName(); + if (pGrandTotalName) + aSubStr = *pGrandTotalName; + pArray[rPos].Flags |= sheet::MemberResultFlags::GRANDTOTAL; + } + } pArray[rPos].Name = rtl::OUString(aName); pArray[rPos].Caption = rtl::OUString(aSubStr); @@ -2796,8 +2865,9 @@ void ScDPResultDimension::FillMemberResults( uno::Sequence<sheet::MemberResult>* // in data layout dimension, use first member with different measures/names if ( bIsDataLayout ) { + bool bTotalResult = false; String aMbrName = pResultData->GetMeasureDimensionName( nSorted ); - String aMbrCapt = pResultData->GetMeasureString( nSorted, FALSE, SUBTOTAL_FUNC_NONE ); + String aMbrCapt = pResultData->GetMeasureString( nSorted, FALSE, SUBTOTAL_FUNC_NONE, bTotalResult ); maMemberArray[0]->FillMemberResults( pSequences, nPos, nSorted, FALSE, &aMbrName, &aMbrCapt ); } else if ( pMember->IsVisible() ) diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx index e123e74a20e6..2a091c8b45b5 100644 --- a/sc/source/core/data/dptabsrc.cxx +++ b/sc/source/core/data/dptabsrc.cxx @@ -85,6 +85,7 @@ using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Any; using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo; +using ::rtl::OUString; // ----------------------------------------------------------------------- @@ -141,15 +142,14 @@ ScDPSource::ScDPSource( ScDPTableData* pD ) : pRowResRoot( NULL ), pColResults( NULL ), pRowResults( NULL ), - bResultOverflow( FALSE ) + bResultOverflow( FALSE ), + mpGrandTotalName(NULL) { pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty ); } ScDPSource::~ScDPSource() { - delete pData; // ScDPTableData is not ref-counted - if (pDimensions) pDimensions->release(); // ref-counted @@ -163,6 +163,16 @@ ScDPSource::~ScDPSource() delete pResData; } +void ScDPSource::SetGrandTotalName(const ::rtl::OUString& rName) +{ + mpGrandTotalName.reset(new ::rtl::OUString(rName)); +} + +const ::rtl::OUString* ScDPSource::GetGrandTotalName() const +{ + return mpGrandTotalName.get(); +} + USHORT ScDPSource::GetOrientation(long nColumn) { long i; @@ -186,16 +196,21 @@ long ScDPSource::GetDataDimensionCount() return nDataDimCount; } +ScDPDimension* ScDPSource::GetDataDimension(long nIndex) +{ + if (nIndex < 0 || nIndex >= nDataDimCount) + return NULL; + + long nDimIndex = nDataDims[nIndex]; + return GetDimensionsObject()->getByIndex(nDimIndex); +} + String ScDPSource::GetDataDimName( long nIndex ) { String aRet; - if ( nIndex >= 0 && nIndex < nDataDimCount ) - { - long nDimIndex = nDataDims[nIndex]; - ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex); - if (pDim) - aRet = String( pDim->getName() ); - } + ScDPDimension* pDim = GetDataDimension(nIndex); + if (pDim) + aRet = String(pDim->getName()); return aRet; } @@ -488,7 +503,10 @@ String ScDPSource::getDataDescription() String aRet; if ( pResData->GetMeasureCount() == 1 ) - aRet = pResData->GetMeasureString( 0, TRUE, SUBTOTAL_FUNC_NONE ); + { + bool bTotalResult = false; + aRet = pResData->GetMeasureString( 0, TRUE, SUBTOTAL_FUNC_NONE, bTotalResult ); + } // empty for more than one measure @@ -1132,6 +1150,7 @@ uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo( throw(uno::RuntimeException) { ScUnoGuard aGuard; + using beans::PropertyAttribute::READONLY; static SfxItemPropertyMapEntry aDPSourceMap_Impl[] = { @@ -1140,6 +1159,10 @@ uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo( {MAP_CHAR_LEN(SC_UNO_IGNOREEM), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only {MAP_CHAR_LEN(SC_UNO_REPEATIF), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only {MAP_CHAR_LEN(SC_UNO_ROWGRAND), 0, &getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_ROWFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_DATAFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_GRANDTOTAL_NAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 }, {0,0,0,0,0,0} }; static uno::Reference<beans::XPropertySetInfo> aRef = @@ -1161,6 +1184,12 @@ void SAL_CALL ScDPSource::setPropertyValue( const rtl::OUString& aPropertyName, setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) ); else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) ) setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) ); + else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME)) + { + OUString aName; + if (aValue >>= aName) + mpGrandTotalName.reset(new OUString(aName)); + } else { DBG_ERROR("unknown property"); @@ -1190,6 +1219,11 @@ uno::Any SAL_CALL ScDPSource::getPropertyValue( const rtl::OUString& aPropertyNa aRet <<= static_cast<sal_Int32>(nColDimCount); else if ( aNameStr.EqualsAscii( SC_UNO_DATAFIELDCOUNT ) ) // read-only aRet <<= static_cast<sal_Int32>(nDataDimCount); + else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME)) + { + if (mpGrandTotalName.get()) + aRet <<= *mpGrandTotalName; + } else { DBG_ERROR("unknown property"); @@ -1337,9 +1371,12 @@ ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) : pHierarchies( NULL ), nUsedHier( 0 ), nFunction( SUBTOTAL_FUNC_SUM ), // sum is default + mpLayoutName(NULL), + mpSubtotalName(NULL), nSourceDim( -1 ), bHasSelectedPage( FALSE ), - pSelectedData( NULL ) + pSelectedData( NULL ), + mbHasHiddenMember(false) { //! hold pSource } @@ -1364,6 +1401,16 @@ ScDPHierarchies* ScDPDimension::GetHierarchiesObject() return pHierarchies; } +const rtl::OUString* ScDPDimension::GetLayoutName() const +{ + return mpLayoutName.get(); +} + +const rtl::OUString* ScDPDimension::GetSubtotalName() const +{ + return mpSubtotalName.get(); +} + uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies() throw(uno::RuntimeException) { @@ -1523,6 +1570,9 @@ uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetIn {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_REFVALUE), 0, &getCppuType((sheet::DataPilotFieldReference*)0), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_USEDHIER), 0, &getCppuType((sal_Int32*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 0, 0 }, {0,0,0,0,0,0} }; static uno::Reference<beans::XPropertySetInfo> aRef = @@ -1593,6 +1643,20 @@ void SAL_CALL ScDPDimension::setPropertyValue( const rtl::OUString& aPropertyNam } DELETEZ( pSelectedData ); // invalid after changing aSelectedPage } + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + { + OUString aTmpName; + if (aValue >>= aTmpName) + mpLayoutName.reset(new OUString(aTmpName)); + } + else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME)) + { + OUString aTmpName; + if (aValue >>= aTmpName) + mpSubtotalName.reset(new OUString(aTmpName)); + } + else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER)) + aValue >>= mbHasHiddenMember; else { DBG_ERROR("unknown property"); @@ -1652,6 +1716,12 @@ uno::Any SAL_CALL ScDPDimension::getPropertyValue( const rtl::OUString& aPropert else aRet <<= uno::Sequence<sheet::TableFilterField>(0); } + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString::createFromAscii(""); + else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME)) + aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString::createFromAscii(""); + else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER)) + aRet <<= mbHasHiddenMember; else { DBG_ERROR("unknown property"); @@ -2155,7 +2225,11 @@ uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::R return aRet; } - return pSource->GetData()->getDimensionName( nSrcDim ); // (original) dimension name + ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim); + if (!pDim) + return rtl::OUString(); + + return pDim->getName(); } void SAL_CALL ScDPLevel::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException) @@ -2258,6 +2332,20 @@ uno::Any SAL_CALL ScDPLevel::getPropertyValue( const rtl::OUString& aPropertyNam aRet <<= aAutoShowInfo; else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) ) aRet <<= aLayoutInfo; + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + { + // read only property + long nSrcDim = pSource->GetSourceDim(nDim); + ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim); + if (!pDim) + return aRet; + + const OUString* pLayoutName = pDim->GetLayoutName(); + if (!pLayoutName) + return aRet; + + aRet <<= *pLayoutName; + } else { DBG_ERROR("unknown property"); @@ -2550,6 +2638,7 @@ ScDPMember::ScDPMember( ScDPSource* pSrc, long nD, long nH, long nL, nHier( nH ), nLev( nL ), maData( rN, fV, bHV ), + mpLayoutName(NULL), nPosition( -1 ), bVisible( TRUE ), bShowDet( TRUE ) @@ -2610,6 +2699,11 @@ void ScDPMember::FillItemData( ScDPItemData& rData ) const rData = maData; } +const OUString* ScDPMember::GetLayoutName() const +{ + return mpLayoutName.get(); +} + String ScDPMember::GetNameStr() const { return maData.aString; @@ -2669,6 +2763,7 @@ uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo( {MAP_CHAR_LEN(SC_UNO_ISVISIBL), 0, &getBooleanCppuType(), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_SHOWDETA), 0, &getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, {0,0,0,0,0,0} }; static uno::Reference<beans::XPropertySetInfo> aRef = @@ -2692,6 +2787,12 @@ void SAL_CALL ScDPMember::setPropertyValue( const rtl::OUString& aPropertyName, if (aValue >>= nInt) setPosition( nInt ); } + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + { + rtl::OUString aName; + if (aValue >>= aName) + mpLayoutName.reset(new rtl::OUString(aName)); + } else { DBG_ERROR("unknown property"); @@ -2711,6 +2812,8 @@ uno::Any SAL_CALL ScDPMember::getPropertyValue( const rtl::OUString& aPropertyNa lcl_SetBoolInAny( aRet, getShowDetails() ); else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) aRet <<= (sal_Int32) getPosition(); + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + aRet <<= mpLayoutName.get() ? *mpLayoutName : rtl::OUString(); else { DBG_ERROR("unknown property"); diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx index c8eba91d2cc1..ac4cb9908a3f 100644 --- a/sc/source/core/data/fillinfo.cxx +++ b/sc/source/core/data/fillinfo.cxx @@ -332,6 +332,8 @@ void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX pInfo->bVOverlapped = FALSE; pInfo->bAutoFilter = FALSE; pInfo->bPushButton = FALSE; + pInfo->bPopupButton = false; + pInfo->bFilterActive = false; pInfo->nRotateDir = SC_ROTDIR_NONE; pInfo->bPrinted = FALSE; // view-intern @@ -458,6 +460,8 @@ void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX BOOL bAutoFilter = ((nOverlap & SC_MF_AUTO) != 0); BOOL bPushButton = ((nOverlap & SC_MF_BUTTON) != 0); BOOL bScenario = ((nOverlap & SC_MF_SCENARIO) != 0); + bool bPopupButton = ((nOverlap & SC_MF_BUTTON_POPUP) != 0); + bool bFilterActive = ((nOverlap & SC_MF_HIDDEN_MEMBER) != 0); if (bMerged||bHOverlapped||bVOverlapped) bAnyMerged = TRUE; // intern @@ -498,6 +502,8 @@ void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX pInfo->bVOverlapped = bVOverlapped; pInfo->bAutoFilter = bAutoFilter; pInfo->bPushButton = bPushButton; + pInfo->bPopupButton = bPopupButton; + pInfo->bFilterActive = bFilterActive; pInfo->pLinesAttr = pLinesAttr; pInfo->mpTLBRLine = pTLBRLine; pInfo->mpBLTRLine = pBLTRLine; @@ -512,7 +518,7 @@ void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX nCurRow >= aEmbedRange.aStart.Row() && nCurRow <= aEmbedRange.aEnd.Row(); - if (bPushButton || bScenario) + if (bScenario) { pInfo->pBackground = ScGlobal::GetButtonBrushItem(); pThisRowInfo->bEmptyBack = FALSE; diff --git a/sc/source/core/data/global2.cxx b/sc/source/core/data/global2.cxx index e6f8523a3c42..ffeb6cc0684c 100644 --- a/sc/source/core/data/global2.cxx +++ b/sc/source/core/data/global2.cxx @@ -56,6 +56,7 @@ #include "sc.hrc" #include "globstr.hrc" +using ::std::vector; // ----------------------------------------------------------------------- @@ -817,7 +818,6 @@ bool PivotField::operator==( const PivotField& r ) const ScPivotParam::ScPivotParam() : nCol(0), nRow(0), nTab(0), - ppLabelArr( NULL ), nLabels(0), nPageCount(0), nColCount(0), nRowCount(0), nDataCount(0), bIgnoreEmptyRows(FALSE), bDetectCategories(FALSE), bMakeTotalCol(TRUE), bMakeTotalRow(TRUE) @@ -828,23 +828,22 @@ ScPivotParam::ScPivotParam() ScPivotParam::ScPivotParam( const ScPivotParam& r ) : nCol( r.nCol ), nRow( r.nRow ), nTab( r.nTab ), - ppLabelArr( NULL ), nLabels(0), nPageCount(0), nColCount(0), nRowCount(0), nDataCount(0), bIgnoreEmptyRows(r.bIgnoreEmptyRows), bDetectCategories(r.bDetectCategories), bMakeTotalCol(r.bMakeTotalCol), bMakeTotalRow(r.bMakeTotalRow) { - SetLabelData ( r.ppLabelArr, r.nLabels ); SetPivotArrays ( r.aPageArr, r.aColArr, r.aRowArr, r.aDataArr, r.nPageCount, r.nColCount, r.nRowCount, r.nDataCount ); + + SetLabelData(r.maLabelArray); } //------------------------------------------------------------------------ __EXPORT ScPivotParam::~ScPivotParam() { - ClearLabelData(); } //------------------------------------------------------------------------ @@ -860,22 +859,6 @@ __EXPORT ScPivotParam::~ScPivotParam() //UNUSED2009-05 ClearPivotArrays(); //UNUSED2009-05 } -//------------------------------------------------------------------------ - -void __EXPORT ScPivotParam::ClearLabelData() -{ - if ( (nLabels > 0) && ppLabelArr ) - { - for ( SCSIZE i=0; i<nLabels; i++ ) - delete ppLabelArr[i]; - delete [] ppLabelArr; - ppLabelArr = NULL; - nLabels = 0; - } -} - -//------------------------------------------------------------------------ - void __EXPORT ScPivotParam::ClearPivotArrays() { memset( aPageArr, 0, PIVOT_MAXPAGEFIELD * sizeof(PivotField) ); @@ -888,20 +871,17 @@ void __EXPORT ScPivotParam::ClearPivotArrays() nDataCount = 0; } -//------------------------------------------------------------------------ - -void __EXPORT ScPivotParam::SetLabelData( LabelData** pLabArr, - SCSIZE nLab ) +void ScPivotParam::SetLabelData(const vector<ScDPLabelDataRef>& r) { - ClearLabelData(); - - if ( (nLab > 0) && pLabArr ) + vector<ScDPLabelDataRef> aNewArray; + aNewArray.reserve(r.size()); + for (vector<ScDPLabelDataRef>::const_iterator itr = r.begin(), itrEnd = r.end(); + itr != itrEnd; ++itr) { - nLabels = (nLab>MAX_LABELS) ? MAX_LABELS : nLab; - ppLabelArr = new LabelData*[nLabels]; - for ( SCSIZE i=0; i<nLabels; i++ ) - ppLabelArr[i] = new LabelData( *(pLabArr[i]) ); + ScDPLabelDataRef p(new ScDPLabelData(**itr)); + aNewArray.push_back(p); } + maLabelArray.swap(aNewArray); } //------------------------------------------------------------------------ @@ -943,10 +923,9 @@ ScPivotParam& __EXPORT ScPivotParam::operator=( const ScPivotParam& r ) bMakeTotalCol = r.bMakeTotalCol; bMakeTotalRow = r.bMakeTotalRow; - SetLabelData ( r.ppLabelArr, r.nLabels ); SetPivotArrays ( r.aPageArr, r.aColArr, r.aRowArr, r.aDataArr, r.nPageCount, r.nColCount, r.nRowCount, r.nDataCount ); - + SetLabelData(r.maLabelArray); return *this; } @@ -961,7 +940,7 @@ BOOL __EXPORT ScPivotParam::operator==( const ScPivotParam& r ) const && (bDetectCategories == r.bDetectCategories) && (bMakeTotalCol == r.bMakeTotalCol) && (bMakeTotalRow == r.bMakeTotalRow) - && (nLabels == r.nLabels) + && (maLabelArray.size() == r.maLabelArray.size()) && (nPageCount == r.nPageCount) && (nColCount == r.nColCount) && (nRowCount == r.nRowCount) diff --git a/sc/source/core/data/makefile.mk b/sc/source/core/data/makefile.mk index d2c700c5f95d..ecd3aad07c0b 100644 --- a/sc/source/core/data/makefile.mk +++ b/sc/source/core/data/makefile.mk @@ -79,6 +79,7 @@ SLOFILES = \ $(SLO)$/dpgroup.obj \ $(SLO)$/dpobject.obj \ $(SLO)$/dpoutput.obj \ + $(SLO)$/dpoutputgeometry.obj \ $(SLO)$/dpsave.obj \ $(SLO)$/dpsdbtab.obj \ $(SLO)$/dpshttab.obj \ @@ -142,6 +143,7 @@ EXCEPTIONSFILES= \ $(SLO)$/dpsdbtab.obj \ $(SLO)$/dpobject.obj \ $(SLO)$/dpoutput.obj \ + $(SLO)$/dpoutputgeometry.obj \ $(SLO)$/dpsave.obj \ $(SLO)$/dbdocutl.obj \ $(SLO)$/dptabsrc.obj \ diff --git a/sc/source/core/data/pivot2.cxx b/sc/source/core/data/pivot2.cxx index e12df0cda6e5..951a656d841d 100644 --- a/sc/source/core/data/pivot2.cxx +++ b/sc/source/core/data/pivot2.cxx @@ -61,11 +61,26 @@ #include "stlsheet.hxx" using ::com::sun::star::sheet::DataPilotFieldReference; +using ::rtl::OUString; // STATIC DATA ----------------------------------------------------------- // ============================================================================ -LabelData::LabelData( const String& rName, short nCol, bool bIsValue ) : +ScDPLabelData::Member::Member() : + mbVisible(true), + mbShowDetails(true) +{ +} + +OUString ScDPLabelData::Member::getDisplayName() const +{ + if (maLayoutName.getLength()) + return maLayoutName; + + return maName; +} + +ScDPLabelData::ScDPLabelData( const String& rName, short nCol, bool bIsValue ) : maName( rName ), mnCol( nCol ), mnFuncMask( PIVOT_FUNC_NONE ), @@ -75,6 +90,14 @@ LabelData::LabelData( const String& rName, short nCol, bool bIsValue ) : { } +OUString ScDPLabelData::getDisplayName() const +{ + if (maLayoutName.getLength()) + return maLayoutName; + + return maName; +} + // ============================================================================ ScDPFuncData::ScDPFuncData( short nCol, USHORT nFuncMask ) : diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 31f9c18e3d3a..4d0eaf76a976 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -972,6 +972,14 @@ ScBaseCell* ScTable::GetCell( SCCOL nCol, SCROW nRow ) const return NULL; } +void ScTable::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const +{ + rCol = 0; + rRow = 0; + while (aCol[rCol].IsEmptyData() && rCol < MAXCOL) + ++rCol; + rRow = aCol[rCol].GetFirstDataPos(); +} void ScTable::GetLastDataPos(SCCOL& rCol, SCROW& rRow) const { diff --git a/sc/source/filter/excel/read.cxx b/sc/source/filter/excel/read.cxx index afa66422ca44..6f0f214d3938 100644 --- a/sc/source/filter/excel/read.cxx +++ b/sc/source/filter/excel/read.cxx @@ -1192,6 +1192,7 @@ FltError ImportExcel8::Read( void ) case EXC_ID_SXDI: rPTableMgr.ReadSxdi( maStrm ); break; case EXC_ID_SXVDEX: rPTableMgr.ReadSxvdex( maStrm ); break; case EXC_ID_SXEX: rPTableMgr.ReadSxex( maStrm ); break; + case EXC_ID_SXVIEWEX9: rPTableMgr.ReadSxViewEx9( maStrm ); break; } } break; @@ -1226,6 +1227,9 @@ FltError ImportExcel8::Read( void ) eLastErr = SCWARN_IMPORT_ROW_OVERFLOW; else if( rAddrConv.IsColTruncated() ) eLastErr = SCWARN_IMPORT_COLUMN_OVERFLOW; + + if( GetBiff() == EXC_BIFF8 ) + GetPivotTableManager().MaybeRefreshPivotTables(); } return eLastErr; diff --git a/sc/source/filter/excel/xepivot.cxx b/sc/source/filter/excel/xepivot.cxx index bc694d01725e..8680623dc29b 100644 --- a/sc/source/filter/excel/xepivot.cxx +++ b/sc/source/filter/excel/xepivot.cxx @@ -67,6 +67,7 @@ using ::com::sun::star::sheet::DataPilotFieldSortInfo; using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo; using ::com::sun::star::sheet::DataPilotFieldLayoutInfo; using ::com::sun::star::sheet::DataPilotFieldReference; +using ::rtl::OUString; using ::rtl::OString; using ::rtl::OUString; @@ -975,6 +976,11 @@ void XclExpPTItem::SetPropertiesFromMember( const ScDPSaveMember& rSaveMem ) { ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN, !rSaveMem.GetIsVisible() ); ::set_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL, !rSaveMem.GetShowDetails() ); + + // visible name + const OUString* pVisName = rSaveMem.GetLayoutName(); + if (pVisName && !pVisName->equals(GetItemName())) + maItemInfo.SetVisName(*pVisName); } void XclExpPTItem::WriteBody( XclExpStream& rStrm ) @@ -1032,6 +1038,31 @@ sal_uInt16 XclExpPTField::GetItemIndex( const String& rName, sal_uInt16 nDefault // fill data -------------------------------------------------------------- +/** + * Calc's subtotal names are escaped with backslashes ('\'), while Excel's + * are not escaped at all. + */ +static OUString lcl_convertCalcSubtotalName(const OUString& rName) +{ + OUStringBuffer aBuf; + const sal_Unicode* p = rName.getStr(); + sal_Int32 n = rName.getLength(); + bool bEscaped = false; + for (sal_Int32 i = 0; i < n; ++i) + { + const sal_Unicode c = p[i]; + if (!bEscaped && c == sal_Unicode('\\')) + { + bEscaped = true; + continue; + } + + aBuf.append(c); + bEscaped = false; + } + return aBuf.makeStringAndClear(); +} + void XclExpPTField::SetPropertiesFromDim( const ScDPSaveDimension& rSaveDim ) { // orientation @@ -1043,8 +1074,16 @@ void XclExpPTField::SetPropertiesFromDim( const ScDPSaveDimension& rSaveDim ) ::set_flag( maFieldExtInfo.mnFlags, EXC_SXVDEX_SHOWALL, rSaveDim.GetShowEmpty() ); // visible name - if( rSaveDim.HasLayoutName() && (rSaveDim.GetLayoutName() != GetFieldName()) ) - maFieldInfo.SetVisName( rSaveDim.GetLayoutName() ); + const OUString* pLayoutName = rSaveDim.GetLayoutName(); + if (pLayoutName && !pLayoutName->equals(GetFieldName())) + maFieldInfo.SetVisName(*pLayoutName); + + const rtl::OUString* pSubtotalName = rSaveDim.GetSubtotalName(); + if (pSubtotalName) + { + OUString aSubName = lcl_convertCalcSubtotalName(*pSubtotalName); + maFieldExtInfo.mpFieldTotalName.reset(new rtl::OUString(aSubName)); + } // subtotals XclPTSubtotalVec aSubtotals; @@ -1111,7 +1150,11 @@ void XclExpPTField::SetDataPropertiesFromDim( const ScDPSaveDimension& rSaveDim rDataInfo.SetApiAggFunc( eFunc ); // visible name - rDataInfo.SetVisName( lclGetDataFieldCaption( GetFieldName(), eFunc ) ); + const rtl::OUString* pVisName = rSaveDim.GetLayoutName(); + if (pVisName) + rDataInfo.SetVisName(*pVisName); + else + rDataInfo.SetVisName( lclGetDataFieldCaption( GetFieldName(), eFunc ) ); // result field reference if( const DataPilotFieldReference* pFieldRef = rSaveDim.GetReferenceValue() ) @@ -1220,9 +1263,10 @@ XclExpPivotTable::XclExpPivotTable( const XclExpRoot& rRoot, const ScDPObject& r // pivot table properties from DP object mnOutScTab = rOutScRange.aStart.Tab(); maPTInfo.maTableName = rDPObj.GetName(); - maPTInfo.maDataName = ScGlobal::GetRscString( STR_PIVOT_DATA ); maPTInfo.mnCacheIdx = mrPCache.GetCacheIndex(); + maPTViewEx9Info.Init( rDPObj ); + if( const ScDPSaveData* pSaveData = rDPObj.GetSaveData() ) { // additional properties from ScDPSaveData @@ -1302,6 +1346,10 @@ void XclExpPivotTable::Save( XclExpStream& rStrm ) WriteSxli( rStrm, maPTInfo.mnDataCols, maPTInfo.mnColFields ); // SXEX WriteSxex( rStrm ); + // QSISXTAG + WriteQsiSxTag( rStrm ); + // SXVIEWEX9 + WriteSxViewEx9( rStrm ); } } @@ -1335,6 +1383,15 @@ void XclExpPivotTable::SetPropertiesFromDP( const ScDPSaveData& rSaveData ) ::set_flag( maPTInfo.mnFlags, EXC_SXVIEW_COLGRAND, rSaveData.GetColumnGrand() ); ::set_flag( maPTExtInfo.mnFlags, EXC_SXEX_DRILLDOWN, rSaveData.GetDrillDown() ); mbFilterBtn = rSaveData.GetFilterButton(); + const ScDPSaveDimension* pDim = rSaveData.GetExistingDataLayoutDimension(); + if (!pDim) + return; + + const rtl::OUString* pLayoutName = pDim->GetLayoutName(); + if (pLayoutName) + maPTInfo.maDataName = *pLayoutName; + else + maPTInfo.maDataName = ScGlobal::GetRscString(STR_PIVOT_DATA); } void XclExpPivotTable::SetFieldPropertiesFromDim( const ScDPSaveDimension& rSaveDim ) @@ -1442,13 +1499,21 @@ void XclExpPivotTable::Finalize() rnDataXclRow = rnXclRow1 + maPTInfo.mnColFields + 1; if( maDataFields.empty() ) ++rnDataXclRow; + + bool bExtraHeaderRow = (0 == maPTViewEx9Info.mnGridLayout && maPTInfo.mnColFields == 0); + if (bExtraHeaderRow) + // Insert an extra row only when there is no column field. + ++rnDataXclRow; + rnXclCol2 = ::std::max( rnXclCol2, rnDataXclCol ); rnXclRow2 = ::std::max( rnXclRow2, rnDataXclRow ); maPTInfo.mnDataCols = rnXclCol2 - rnDataXclCol + 1; maPTInfo.mnDataRows = rnXclRow2 - rnDataXclRow + 1; // first heading - maPTInfo.mnFirstHeadRow = rnXclRow1 + 1; + maPTInfo.mnFirstHeadRow = rnXclRow1; + if (bExtraHeaderRow) + maPTInfo.mnFirstHeadRow += 2; } // records ---------------------------------------------------------------- @@ -1528,6 +1593,72 @@ void XclExpPivotTable::WriteSxex( XclExpStream& rStrm ) const rStrm.EndRecord(); } +void XclExpPivotTable::WriteQsiSxTag( XclExpStream& rStrm ) const +{ + rStrm.StartRecord( 0x0802, 32 ); + + sal_uInt16 nRecordType = 0x0802; + sal_uInt16 nDummyFlags = 0x0000; + sal_uInt16 nTableType = 1; // 0 = query table : 1 = pivot table + + rStrm << nRecordType << nDummyFlags << nTableType; + + // General flags + bool bEnableRefresh = true; + bool bPCacheInvalid = false; + bool bOlapPTReport = false; + + sal_uInt16 nFlags = 0x0000; + if (bEnableRefresh) nFlags |= 0x0001; + if (bPCacheInvalid) nFlags |= 0x0002; + if (bOlapPTReport) nFlags |= 0x0004; + rStrm << nFlags; + + // Feature-specific options. The value differs depending on the table + // type, but we assume the table type is always pivot table. + sal_uInt32 nOptions = 0x00000000; + bool bNoStencil = false; + bool bHideTotal = false; + bool bEmptyRows = false; + bool bEmptyCols = false; + if (bNoStencil) nOptions |= 0x00000001; + if (bHideTotal) nOptions |= 0x00000002; + if (bEmptyRows) nOptions |= 0x00000008; + if (bEmptyCols) nOptions |= 0x00000010; + rStrm << nOptions; + + enum ExcelVersion + { + Excel2000 = 0, + ExcelXP = 1, + Excel2003 = 2, + Excel2007 = 3 + }; + ExcelVersion eXclVer = Excel2000; + sal_uInt8 nOffsetBytes = 16; + rStrm << static_cast<sal_uInt8>(eXclVer) // version table last refreshed + << static_cast<sal_uInt8>(eXclVer) // minimum version to refresh + << nOffsetBytes + << static_cast<sal_uInt8>(eXclVer); // first version created + + rStrm << XclExpString(maPTInfo.maTableName); + rStrm << static_cast<sal_uInt16>(0x0001); // no idea what this is for. + + rStrm.EndRecord(); +} + +void XclExpPivotTable::WriteSxViewEx9( XclExpStream& rStrm ) const +{ + // Until we sync the autoformat ids only export if using grid header layout + // That could only have been set via xls import so far. + if ( 0 == maPTViewEx9Info.mnGridLayout ) + { + rStrm.StartRecord( EXC_ID_SXVIEWEX9, 17 ); + rStrm << maPTViewEx9Info; + rStrm.EndRecord(); + } +} + // ============================================================================ namespace { diff --git a/sc/source/filter/excel/xestring.cxx b/sc/source/filter/excel/xestring.cxx index 9af8dbfdd851..b657e3b1f1d0 100644 --- a/sc/source/filter/excel/xestring.cxx +++ b/sc/source/filter/excel/xestring.cxx @@ -423,7 +423,8 @@ void XclExpString::WriteFormats( XclExpStream& rStrm, bool bWriteSize ) const void XclExpString::Write( XclExpStream& rStrm ) const { - WriteHeader( rStrm ); + if (!mbSkipHeader) + WriteHeader( rStrm ); WriteBuffer( rStrm ); if( IsWriteFormats() ) // only in BIFF8 included in string WriteFormats( rStrm ); @@ -589,6 +590,7 @@ void XclExpString::Init( sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 nMax mbSmartFlags = bBiff8 && ::get_flag( nFlags, EXC_STR_SMARTFLAGS ); mbSkipFormats = ::get_flag( nFlags, EXC_STR_SEPARATEFORMATS ); mbWrapped = false; + mbSkipHeader = ::get_flag( nFlags, EXC_STR_NOHEADER ); mnMaxLen = nMaxLen; SetStrLen( nCurrLen ); diff --git a/sc/source/filter/excel/xipivot.cxx b/sc/source/filter/excel/xipivot.cxx index 56532f1281cc..687dfb9333fe 100644 --- a/sc/source/filter/excel/xipivot.cxx +++ b/sc/source/filter/excel/xipivot.cxx @@ -48,7 +48,9 @@ #include "dpdimsave.hxx" #include "dpobject.hxx" #include "dpshttab.hxx" +#include "dpoutputgeometry.hxx" #include "scitems.hxx" +#include "attrib.hxx" #include "xltracer.hxx" #include "xistream.hxx" @@ -60,13 +62,17 @@ #include "excform.hxx" #include "xltable.hxx" +#include <vector> + using ::rtl::OUString; +using ::rtl::OUStringBuffer; using ::com::sun::star::sheet::DataPilotFieldOrientation; using ::com::sun::star::sheet::DataPilotFieldOrientation_DATA; using ::com::sun::star::sheet::DataPilotFieldSortInfo; using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo; using ::com::sun::star::sheet::DataPilotFieldLayoutInfo; using ::com::sun::star::sheet::DataPilotFieldReference; +using ::std::vector; // ============================================================================ // Pivot cache @@ -847,6 +853,11 @@ void XclImpPivotCache::ReadPivotCacheStream( XclImpStream& rStrm ) } } +bool XclImpPivotCache::IsRefreshOnLoad() const +{ + return static_cast<bool>(maPCInfo.mnFlags & 0x0004); +} + // ============================================================================ // Pivot table // ============================================================================ @@ -882,6 +893,8 @@ void XclImpPTItem::ConvertItem( ScDPSaveDimension& rSaveDim ) const ScDPSaveMember& rMember = *rSaveDim.GetMemberByName( *pItemName ); rMember.SetIsVisible( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDDEN ) ); rMember.SetShowDetails( !::get_flag( maItemInfo.mnFlags, EXC_SXVI_HIDEDETAIL ) ); + if (maItemInfo.HasVisName()) + rMember.SetLayoutName(*maItemInfo.GetVisName()); } } @@ -1022,6 +1035,28 @@ void XclImpPTField::ConvertDataField( ScDPSaveData& rSaveData ) const // private -------------------------------------------------------------------- +/** + * Convert Excel-encoded subtotal name to a Calc-encoded one. + */ +static OUString lcl_convertExcelSubtotalName(const OUString& rName) +{ + OUStringBuffer aBuf; + const sal_Unicode* p = rName.getStr(); + sal_Int32 n = rName.getLength(); + for (sal_Int32 i = 0; i < n; ++i) + { + const sal_Unicode c = p[i]; + if (c == sal_Unicode('\\')) + { + aBuf.append(c); + aBuf.append(c); + } + else + aBuf.append(c); + } + return aBuf.makeStringAndClear(); +} + ScDPSaveDimension* XclImpPTField::ConvertRCPField( ScDPSaveData& rSaveData ) const { const String& rFieldName = GetFieldName(); @@ -1043,7 +1078,7 @@ ScDPSaveDimension* XclImpPTField::ConvertRCPField( ScDPSaveData& rSaveData ) con // visible name if( const String* pVisName = maFieldInfo.GetVisName() ) if( pVisName->Len() > 0 ) - rSaveDim.SetLayoutName( pVisName ); + rSaveDim.SetLayoutName( *pVisName ); // subtotal function(s) XclPTSubtotalVec aSubtotalVec; @@ -1075,6 +1110,13 @@ ScDPSaveDimension* XclImpPTField::ConvertRCPField( ScDPSaveData& rSaveData ) con // grouping info pCacheField->ConvertGroupField( rSaveData, mrPTable.GetVisFieldNames() ); + // custom subtotal name + if (maFieldExtInfo.mpFieldTotalName.get()) + { + OUString aSubName = lcl_convertExcelSubtotalName(*maFieldExtInfo.mpFieldTotalName); + rSaveDim.SetSubtotalName(aSubName); + } + return &rSaveDim; } @@ -1099,7 +1141,7 @@ void XclImpPTField::ConvertDataFieldInfo( ScDPSaveDimension& rSaveDim, const Xcl // visible name if( const String* pVisName = rDataInfo.GetVisName() ) if( pVisName->Len() > 0 ) - rSaveDim.SetLayoutName( pVisName ); + rSaveDim.SetLayoutName( *pVisName ); // aggregation function rSaveDim.SetFunction( static_cast< USHORT >( rDataInfo.GetApiAggFunc() ) ); @@ -1134,7 +1176,8 @@ void XclImpPTField::ConvertItems( ScDPSaveDimension& rSaveDim ) const XclImpPivotTable::XclImpPivotTable( const XclImpRoot& rRoot ) : XclImpRoot( rRoot ), - maDataOrientField( *this, EXC_SXIVD_DATA ) + maDataOrientField( *this, EXC_SXIVD_DATA ), + mpDPObj(NULL) { } @@ -1296,6 +1339,11 @@ void XclImpPivotTable::ReadSxex( XclImpStream& rStrm ) rStrm >> maPTExtInfo; } +void XclImpPivotTable::ReadSxViewEx9( XclImpStream& rStrm ) +{ + rStrm >> maPTViewEx9Info; +} + // ---------------------------------------------------------------------------- void XclImpPivotTable::Convert() @@ -1331,6 +1379,10 @@ void XclImpPivotTable::Convert() if( const XclImpPTField* pField = GetField( *aIt ) ) pField->ConvertPageField( aSaveData ); + // We need to import hidden fields because hidden fields may contain + // special settings for subtotals (aggregation function, filters, custom + // name etc.) and members (hidden, custom name etc.). + // hidden fields for( sal_uInt16 nField = 0, nCount = GetFieldCount(); nField < nCount; ++nField ) if( const XclImpPTField* pField = GetField( nField ) ) @@ -1359,11 +1411,112 @@ void XclImpPivotTable::Convert() // create the DataPilot ScDPObject* pDPObj = new ScDPObject( GetDocPtr() ); pDPObj->SetName( maPTInfo.maTableName ); + if (maPTInfo.maDataName.Len() > 0) + aSaveData.GetDataLayoutDimension()->SetLayoutName(maPTInfo.maDataName); + + if (maPTViewEx9Info.maGrandTotalName.Len() > 0) + aSaveData.SetGrandTotalName(maPTViewEx9Info.maGrandTotalName); + pDPObj->SetSaveData( aSaveData ); pDPObj->SetSheetDesc( aDesc ); pDPObj->SetOutRange( aOutRange ); pDPObj->SetAlive( TRUE ); - GetDoc().GetDPCollection()->Insert( pDPObj ); + pDPObj->SetHeaderLayout( maPTViewEx9Info.mnGridLayout == 0 ); + + GetDoc().GetDPCollection()->InsertNewTable(pDPObj); + mpDPObj = pDPObj; + + ApplyMergeFlags(aOutRange, aSaveData); +} + +void XclImpPivotTable::MaybeRefresh() +{ + if (mpDPObj && mxPCache->IsRefreshOnLoad()) + { + // 'refresh table on load' flag is set. Refresh the table now. Some + // Excel files contain partial table output when this flag is set. + ScRange aOutRange = mpDPObj->GetOutRange(); + mpDPObj->Output(aOutRange.aStart); + } +} + +void XclImpPivotTable::ApplyMergeFlags(const ScRange& rOutRange, const ScDPSaveData& rSaveData) +{ + // Apply merge flags for varoius datapilot controls. + + ScDPOutputGeometry aGeometry(rOutRange, false, ScDPOutputGeometry::XLS); + aGeometry.setColumnFieldCount(maPTInfo.mnColFields); + aGeometry.setPageFieldCount(maPTInfo.mnPageFields); + aGeometry.setDataFieldCount(maPTInfo.mnDataFields); + + // Excel includes data layout field in the row field count. We need to + // subtract it. + bool bDataLayout = maPTInfo.mnDataFields > 1; + aGeometry.setRowFieldCount(maPTInfo.mnRowFields - static_cast<sal_uInt32>(bDataLayout)); + + ScDocument& rDoc = GetDoc(); + + vector<ScAddress> aPageBtns; + aGeometry.getPageFieldPositions(aPageBtns); + vector<ScAddress>::const_iterator itr = aPageBtns.begin(), itrEnd = aPageBtns.end(); + for (; itr != itrEnd; ++itr) + { + sal_uInt16 nMFlag = SC_MF_BUTTON; + String aName; + rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName); + if (rSaveData.HasInvisibleMember(aName)) + nMFlag |= SC_MF_HIDDEN_MEMBER; + + rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag); + rDoc.ApplyFlagsTab(itr->Col()+1, itr->Row(), itr->Col()+1, itr->Row(), itr->Tab(), SC_MF_AUTO); + } + + vector<ScAddress> aColBtns; + aGeometry.getColumnFieldPositions(aColBtns); + itr = aColBtns.begin(); + itrEnd = aColBtns.end(); + for (; itr != itrEnd; ++itr) + { + sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP; + String aName; + rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName); + if (rSaveData.HasInvisibleMember(aName)) + nMFlag |= SC_MF_HIDDEN_MEMBER; + rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag); + } + + vector<ScAddress> aRowBtns; + aGeometry.getRowFieldPositions(aRowBtns); + if (aRowBtns.empty()) + { + if (bDataLayout) + { + // No row fields, but the data layout button exists. + SCROW nRow = aGeometry.getRowFieldHeaderRow(); + SCCOL nCol = rOutRange.aStart.Col(); + SCTAB nTab = rOutRange.aStart.Tab(); + rDoc.ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON); + } + } + else + { + itr = aRowBtns.begin(); + itrEnd = aRowBtns.end(); + for (; itr != itrEnd; ++itr) + { + sal_Int16 nMFlag = SC_MF_BUTTON | SC_MF_BUTTON_POPUP; + String aName; + rDoc.GetString(itr->Col(), itr->Row(), itr->Tab(), aName); + if (rSaveData.HasInvisibleMember(aName)) + nMFlag |= SC_MF_HIDDEN_MEMBER; + rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), nMFlag); + } + if (bDataLayout) + { + --itr; // move back to the last row field position. + rDoc.ApplyFlagsTab(itr->Col(), itr->Row(), itr->Col(), itr->Row(), itr->Tab(), SC_MF_BUTTON); + } + } } // ============================================================================ @@ -1458,6 +1611,12 @@ void XclImpPivotTableManager::ReadSxex( XclImpStream& rStrm ) maPTables.back()->ReadSxex( rStrm ); } +void XclImpPivotTableManager::ReadSxViewEx9( XclImpStream& rStrm ) +{ + if( !maPTables.empty() ) + maPTables.back()->ReadSxViewEx9( rStrm ); +} + // ---------------------------------------------------------------------------- void XclImpPivotTableManager::ReadPivotCaches( XclImpStream& rStrm ) @@ -1472,5 +1631,11 @@ void XclImpPivotTableManager::ConvertPivotTables() (*aIt)->Convert(); } +void XclImpPivotTableManager::MaybeRefreshPivotTables() +{ + for( XclImpPivotTableVec::iterator aIt = maPTables.begin(), aEnd = maPTables.end(); aIt != aEnd; ++aIt ) + (*aIt)->MaybeRefresh(); +} + // ============================================================================ diff --git a/sc/source/filter/excel/xlpivot.cxx b/sc/source/filter/excel/xlpivot.cxx index d36950b2494d..8f5d026379d9 100644 --- a/sc/source/filter/excel/xlpivot.cxx +++ b/sc/source/filter/excel/xlpivot.cxx @@ -31,6 +31,7 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" #include "dpgroup.hxx" +#include "dpsave.hxx" #include "xestream.hxx" #include "xistream.hxx" #include "xestring.hxx" @@ -581,7 +582,9 @@ XclExpStream& operator<<( XclExpStream& rStrm, const XclPTFieldInfo& rInfo ) XclPTFieldExtInfo::XclPTFieldExtInfo() : mnFlags( EXC_SXVDEX_DEFAULTFLAGS ), mnSortField( EXC_SXVDEX_SORT_OWN ), - mnShowField( EXC_SXVDEX_SHOW_NONE ) + mnShowField( EXC_SXVDEX_SHOW_NONE ), + mnNumFmt(0), + mpFieldTotalName(NULL) { } @@ -639,10 +642,19 @@ void XclPTFieldExtInfo::SetApiLayoutMode( sal_Int32 nLayoutMode ) XclImpStream& operator>>( XclImpStream& rStrm, XclPTFieldExtInfo& rInfo ) { - return rStrm - >> rInfo.mnFlags - >> rInfo.mnSortField - >> rInfo.mnShowField; + sal_uInt8 nNameLen = 0; + rStrm >> rInfo.mnFlags + >> rInfo.mnSortField + >> rInfo.mnShowField + >> rInfo.mnNumFmt + >> nNameLen; + + rStrm.Ignore(10); + if (nNameLen != 0xFF) + // Custom field total name is used. Pick it up. + rInfo.mpFieldTotalName.reset(new rtl::OUString(rStrm.ReadUniString(nNameLen, 0))); + + return rStrm; } XclExpStream& operator<<( XclExpStream& rStrm, const XclPTFieldExtInfo& rInfo ) @@ -650,9 +662,23 @@ XclExpStream& operator<<( XclExpStream& rStrm, const XclPTFieldExtInfo& rInfo ) rStrm << rInfo.mnFlags << rInfo.mnSortField << rInfo.mnShowField - << EXC_SXVDEX_FORMAT_NONE - << sal_uInt16( 0xFFFF ); // unknown - rStrm.WriteZeroBytes( 8 ); // unknown + << EXC_SXVDEX_FORMAT_NONE; + + if (rInfo.mpFieldTotalName.get() && rInfo.mpFieldTotalName->getLength() > 0) + { + rtl::OUString aFinalName = *rInfo.mpFieldTotalName; + if (aFinalName.getLength() >= 254) + aFinalName = aFinalName.copy(0, 254); + sal_uInt8 nNameLen = static_cast<sal_uInt8>(aFinalName.getLength()); + rStrm << nNameLen; + rStrm.WriteZeroBytes(10); + rStrm << XclExpString(aFinalName, EXC_STR_NOHEADER); + } + else + { + rStrm << sal_uInt16(0xFFFF); + rStrm.WriteZeroBytes(8); + } return rStrm; } @@ -923,3 +949,86 @@ XclExpStream& operator<<( XclExpStream& rStrm, const XclPTExtInfo& rInfo ) // ============================================================================ +// Pivot table autoformat settings ============================================ + +/** +classic : 10 08 00 00 00 00 00 00 20 00 00 00 01 00 00 00 00 +default : 10 08 00 00 00 00 00 00 20 00 00 00 01 00 00 00 00 +report01 : 10 08 02 00 00 00 00 00 20 00 00 00 00 10 00 00 00 +report02 : 10 08 02 00 00 00 00 00 20 00 00 00 01 10 00 00 00 +report03 : 10 08 02 00 00 00 00 00 20 00 00 00 02 10 00 00 00 +report04 : 10 08 02 00 00 00 00 00 20 00 00 00 03 10 00 00 00 +report05 : 10 08 02 00 00 00 00 00 20 00 00 00 04 10 00 00 00 +report06 : 10 08 02 00 00 00 00 00 20 00 00 00 05 10 00 00 00 +report07 : 10 08 02 00 00 00 00 00 20 00 00 00 06 10 00 00 00 +report08 : 10 08 02 00 00 00 00 00 20 00 00 00 07 10 00 00 00 +report09 : 10 08 02 00 00 00 00 00 20 00 00 00 08 10 00 00 00 +report10 : 10 08 02 00 00 00 00 00 20 00 00 00 09 10 00 00 00 +table01 : 10 08 00 00 00 00 00 00 20 00 00 00 0a 10 00 00 00 +table02 : 10 08 00 00 00 00 00 00 20 00 00 00 0b 10 00 00 00 +table03 : 10 08 00 00 00 00 00 00 20 00 00 00 0c 10 00 00 00 +table04 : 10 08 00 00 00 00 00 00 20 00 00 00 0d 10 00 00 00 +table05 : 10 08 00 00 00 00 00 00 20 00 00 00 0e 10 00 00 00 +table06 : 10 08 00 00 00 00 00 00 20 00 00 00 0f 10 00 00 00 +table07 : 10 08 00 00 00 00 00 00 20 00 00 00 10 10 00 00 00 +table08 : 10 08 00 00 00 00 00 00 20 00 00 00 11 10 00 00 00 +table09 : 10 08 00 00 00 00 00 00 20 00 00 00 12 10 00 00 00 +table10 : 10 08 00 00 00 00 00 00 20 00 00 00 13 10 00 00 00 +none : 10 08 00 00 00 00 00 00 20 00 00 00 15 10 00 00 00 +**/ + +XclPTViewEx9Info::XclPTViewEx9Info() : + mbReport( 0 ), + mnAutoFormat( 0 ), + mnGridLayout( 0x10 ) +{ +} + +void XclPTViewEx9Info::Init( const ScDPObject& rDPObj ) +{ + if( rDPObj.GetHeaderLayout() ) + { + mbReport = 0; + mnAutoFormat = 1; + mnGridLayout = 0; + } + else + { + // Report1 for now + // TODO : sync with autoformat indicies + mbReport = 2; + mnAutoFormat = 1; + mnGridLayout = 0x10; + } + + const ScDPSaveData* pData = rDPObj.GetSaveData(); + if (pData) + { + const rtl::OUString* pGrandTotal = pData->GetGrandTotalName(); + if (pGrandTotal) + maGrandTotalName = *pGrandTotal; + } +} + +XclImpStream& operator>>( XclImpStream& rStrm, XclPTViewEx9Info& rInfo ) +{ + rStrm.Ignore( 2 ); + rStrm >> rInfo.mbReport; /// 2 for report* fmts ? + rStrm.Ignore( 6 ); + rStrm >> rInfo.mnAutoFormat >> rInfo.mnGridLayout; + rInfo.maGrandTotalName = rStrm.ReadUniString(); + return rStrm; +} + +XclExpStream& operator<<( XclExpStream& rStrm, const XclPTViewEx9Info& rInfo ) +{ + return rStrm + << EXC_PT_AUTOFMT_HEADER + << rInfo.mbReport + << EXC_PT_AUTOFMT_ZERO + << EXC_PT_AUTOFMT_FLAGS + << rInfo.mnAutoFormat + << rInfo.mnGridLayout + << XclExpString(rInfo.maGrandTotalName, EXC_STR_DEFAULT, EXC_PT_MAXSTRLEN); +} + diff --git a/sc/source/filter/inc/xepivot.hxx b/sc/source/filter/inc/xepivot.hxx index 28df1586cdcb..716f0bf7a515 100644 --- a/sc/source/filter/inc/xepivot.hxx +++ b/sc/source/filter/inc/xepivot.hxx @@ -413,6 +413,10 @@ private: /** Writes the SXEX records containing additional pivot table info. */ void WriteSxex( XclExpStream& rStrm ) const; + void WriteQsiSxTag( XclExpStream& rStrm ) const; + /** Writes the SX_AUTOFORMAT records with the autoformat id and header layout */ + void WriteSxViewEx9( XclExpStream& rStrm ) const; + // ------------------------------------------------------------------------ private: typedef XclExpRecordList< XclExpPTField > XclExpPTFieldList; @@ -422,6 +426,7 @@ private: const XclExpPivotCache& mrPCache; /// The pivot cache this pivot table bases on. XclPTInfo maPTInfo; /// Info about the pivot table (SXVIEW record). XclPTExtInfo maPTExtInfo; /// Extended info about the pivot table (SXEX record). + XclPTViewEx9Info maPTViewEx9Info; /// The selected autoformat (SXVIEWEX9) XclExpPTFieldList maFieldList; /// All fields in pivot cache order. ScfUInt16Vec maRowFields; /// Row field indexes. ScfUInt16Vec maColFields; /// Column field indexes. diff --git a/sc/source/filter/inc/xestring.hxx b/sc/source/filter/inc/xestring.hxx index 69a1a7af09fb..5fe5e4fb813f 100644 --- a/sc/source/filter/inc/xestring.hxx +++ b/sc/source/filter/inc/xestring.hxx @@ -323,6 +323,7 @@ private: bool mbSmartFlags; /// true = omit flags on empty string; false = always write flags. bool mbSkipFormats; /// true = skip formats on export; false = write complete formatted string. bool mbWrapped; /// true = text contains several paragraphs. + bool mbSkipHeader; /// ture = skip length and flags when writing string bytes. }; inline bool operator==( const XclExpString& rLeft, const XclExpString& rRight ) diff --git a/sc/source/filter/inc/xipivot.hxx b/sc/source/filter/inc/xipivot.hxx index 52b55509219b..9e0e577b1756 100644 --- a/sc/source/filter/inc/xipivot.hxx +++ b/sc/source/filter/inc/xipivot.hxx @@ -186,6 +186,8 @@ public: /** Reads the entire pivot cache stream. Uses decrypter from passed stream. */ void ReadPivotCacheStream( XclImpStream& rStrm ); + bool IsRefreshOnLoad() const; + private: typedef ::std::vector< XclImpPCFieldRef > XclImpPCFieldVec; @@ -350,12 +352,19 @@ public: void ReadSxdi( XclImpStream& rStrm ); /** Reads an SXEX record containing additional settings for the pivot table. */ void ReadSxex( XclImpStream& rStrm ); + /** Reads an SXVIEWEX9 record that specifies the pivot tables + * autoformat. */ + void ReadSxViewEx9( XclImpStream& rStrm ); // ------------------------------------------------------------------------ /** Inserts the pivot table into the Calc document. */ void Convert(); + void MaybeRefresh(); + + void ApplyMergeFlags(const ScRange& rOutRange, const ScDPSaveData& rSaveData); + // ------------------------------------------------------------------------ private: typedef ::std::vector< XclImpPTFieldRef > XclImpPTFieldVec; @@ -364,6 +373,7 @@ private: XclPTInfo maPTInfo; /// General info about the pivot table (SXVIEW record). XclPTExtInfo maPTExtInfo; /// Extended info about the pivot table (SXEX record). + XclPTViewEx9Info maPTViewEx9Info; /// (SXVIEWEX9 record) XclImpPTFieldVec maFields; /// Vector containing all fields. XclImpPTFieldRef mxCurrField; /// Current field for importing additional info. ScfStringVec maVisFieldNames; /// Vector containing all visible field names. @@ -374,6 +384,7 @@ private: ScfUInt16Vec maFiltDataFields; /// Filtered data field indexes. XclImpPTField maDataOrientField; /// Special data field orientation field. ScRange maOutScRange; /// Output range in the Calc document. + ScDPObject* mpDPObj; }; typedef ScfRef< XclImpPivotTable > XclImpPivotTableRef; @@ -422,6 +433,9 @@ public: void ReadSxvi( XclImpStream& rStrm ); /** Reads an SXEX record containing additional settings for a pivot table. */ void ReadSxex( XclImpStream& rStrm ); + /** Reads an SXVIEWEX9 record that specifies the pivot tables + * autoformat. */ + void ReadSxViewEx9( XclImpStream& rStrm ); // ------------------------------------------------------------------------ @@ -430,6 +444,8 @@ public: /** Inserts all pivot tables into the Calc document. */ void ConvertPivotTables(); + void MaybeRefreshPivotTables(); + private: typedef ::std::vector< XclImpPivotCacheRef > XclImpPivotCacheVec; typedef ::std::vector< XclImpPivotTableRef > XclImpPivotTableVec; diff --git a/sc/source/filter/inc/xlpivot.hxx b/sc/source/filter/inc/xlpivot.hxx index 9604c7b1d17d..3ea464e7b919 100644 --- a/sc/source/filter/inc/xlpivot.hxx +++ b/sc/source/filter/inc/xlpivot.hxx @@ -41,6 +41,9 @@ #include <tools/datetime.hxx> #include "ftools.hxx" #include "xladdress.hxx" +#include "dpobject.hxx" + +#include <memory> class XclImpStream; class XclExpStream; @@ -73,6 +76,10 @@ const sal_uInt16 EXC_PT_MAXDATACOUNT = 256; // pivot table items const sal_uInt16 EXC_PT_MAXITEMCOUNT = 32500; +const sal_uInt16 EXC_PT_AUTOFMT_HEADER = 0x810; +const sal_uInt16 EXC_PT_AUTOFMT_ZERO = 0; +const sal_uInt32 EXC_PT_AUTOFMT_FLAGS = 0x20; + /** Data type of a pivot cache item. */ enum XclPCItemType { @@ -396,6 +403,9 @@ const double EXC_SXDBEX_CREATION_DATE = 51901.029652778; const sal_uInt16 EXC_ID_SXFDBTYPE = 0x01BB; const sal_uInt16 EXC_SXFDBTYPE_DEFAULT = 0x0000; +// (0x0810) SXVIEWEX9 --------------------------------------------------------- +const sal_uInt16 EXC_ID_SXVIEWEX9 = 0x0810; + // ============================================================================ // Pivot cache // ============================================================================ @@ -663,6 +673,8 @@ struct XclPTFieldExtInfo sal_uInt32 mnFlags; /// Several flags and number of items for AutoShow. sal_uInt16 mnSortField; /// Index to data field sorting bases on. sal_uInt16 mnShowField; /// Index to data field AutoShow bases on. + sal_uInt16 mnNumFmt; + ::std::auto_ptr<rtl::OUString> mpFieldTotalName; explicit XclPTFieldExtInfo(); @@ -786,5 +798,23 @@ XclExpStream& operator<<( XclExpStream& rStrm, const XclPTExtInfo& rInfo ); // ============================================================================ +// Pivot table autoformat settings ============================================== + +/** Pivot table autoformat settings (SXVIEWEX9 record). */ +struct XclPTViewEx9Info +{ + sal_uInt32 mbReport; /// 2 for report* fmts ? + sal_uInt8 mnAutoFormat; /// AutoFormat ID + sal_uInt8 mnGridLayout; /// 0 == gridlayout, 0x10 == modern + String maGrandTotalName; + + explicit XclPTViewEx9Info(); + void Init( const ScDPObject& rDPObj ); +}; + +XclImpStream& operator>>( XclImpStream& rStrm, XclPTViewEx9Info& rInfo ); +XclExpStream& operator<<( XclExpStream& rStrm, const XclPTViewEx9Info& rInfo ); + +// ============================================================================ #endif diff --git a/sc/source/filter/inc/xlstring.hxx b/sc/source/filter/inc/xlstring.hxx index 0970fafd1ed6..32ee23f83d85 100644 --- a/sc/source/filter/inc/xlstring.hxx +++ b/sc/source/filter/inc/xlstring.hxx @@ -43,6 +43,7 @@ const XclStrFlags EXC_STR_FORCEUNICODE = 0x0001; /// Always use UCS-2 cha const XclStrFlags EXC_STR_8BITLENGTH = 0x0002; /// 8-bit string length field (default: 16-bit). const XclStrFlags EXC_STR_SMARTFLAGS = 0x0004; /// Omit flags on empty string (default: read/write always). BIFF8 only. const XclStrFlags EXC_STR_SEPARATEFORMATS = 0x0008; /// Import: Keep old formats when reading unformatted string (default: clear formats); Export: Write unformatted string. +const XclStrFlags EXC_STR_NOHEADER = 0x0010; /// Export: Don't write the length and flag fields. // ---------------------------------------------------------------------------- diff --git a/sc/source/filter/xml/XMLExportDataPilot.cxx b/sc/source/filter/xml/XMLExportDataPilot.cxx index 32cf92e08d1a..97926ee7113f 100644 --- a/sc/source/filter/xml/XMLExportDataPilot.cxx +++ b/sc/source/filter/xml/XMLExportDataPilot.cxx @@ -68,6 +68,7 @@ using namespace com::sun::star; using namespace xmloff::token; +using ::rtl::OUString; ScXMLExportDataPilot::ScXMLExportDataPilot(ScXMLExport& rTempExport) : rExport(rTempExport), @@ -448,7 +449,14 @@ void ScXMLExportDataPilot::WriteLayoutInfo(ScDPSaveDimension* pDim) void ScXMLExportDataPilot::WriteSubTotals(ScDPSaveDimension* pDim) { + using sheet::GeneralFunction; + sal_Int32 nSubTotalCount = pDim->GetSubTotalsCount(); + const OUString* pLayoutName = NULL; + if (rExport.getDefaultVersion() == SvtSaveOptions::ODFVER_LATEST) + // Export display names only for 1.2 extended or later. + pLayoutName = pDim->GetSubtotalName(); + if (nSubTotalCount > 0) { SvXMLElementExport aElemSTs(rExport, XML_NAMESPACE_TABLE, XML_DATA_PILOT_SUBTOTALS, sal_True, sal_True); @@ -456,8 +464,11 @@ void ScXMLExportDataPilot::WriteSubTotals(ScDPSaveDimension* pDim) for (sal_Int32 nSubTotal = 0; nSubTotal < nSubTotalCount; nSubTotal++) { rtl::OUString sFunction; - ScXMLConverter::GetStringFromFunction( sFunction, (sheet::GeneralFunction)pDim->GetSubTotalFunc(nSubTotal) ); + GeneralFunction nFunc = static_cast<GeneralFunction>(pDim->GetSubTotalFunc(nSubTotal)); + ScXMLConverter::GetStringFromFunction( sFunction, nFunc); rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_FUNCTION, sFunction); + if (pLayoutName && nFunc == sheet::GeneralFunction_AUTO) + rExport.AddAttribute(XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, *pLayoutName); SvXMLElementExport aElemST(rExport, XML_NAMESPACE_TABLE, XML_DATA_PILOT_SUBTOTAL, sal_True, sal_True); } } @@ -473,6 +484,15 @@ void ScXMLExportDataPilot::WriteMembers(ScDPSaveDimension* pDim) for (ScDPSaveDimension::MemberList::const_iterator i=rMembers.begin(); i != rMembers.end() ; i++) { rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, rtl::OUString((*i)->GetName())); + + if (rExport.getDefaultVersion() == SvtSaveOptions::ODFVER_LATEST) + { + // Export display names only for ODF 1.2 extended or later. + const OUString* pLayoutName = (*i)->GetLayoutName(); + if (pLayoutName) + rExport.AddAttribute(XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, *pLayoutName); + } + rtl::OUStringBuffer sBuffer; SvXMLUnitConverter::convertBool(sBuffer, (*i)->GetIsVisible()); rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, sBuffer.makeStringAndClear()); @@ -670,6 +690,14 @@ void ScXMLExportDataPilot::WriteGroupDimElements(ScDPSaveDimension* pDim, const void ScXMLExportDataPilot::WriteDimension(ScDPSaveDimension* pDim, const ScDPDimensionSaveData* pDimData) { rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_SOURCE_FIELD_NAME, rtl::OUString(pDim->GetName())); + if (rExport.getDefaultVersion() == SvtSaveOptions::ODFVER_LATEST) + { + // Export display names only for ODF 1.2 extended or later. + const OUString* pLayoutName = pDim->GetLayoutName(); + if (pLayoutName) + rExport.AddAttribute(XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, *pLayoutName); + } + if (pDim->IsDataLayout()) rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_IS_DATA_LAYOUT_FIELD, XML_TRUE); rtl::OUString sValueStr; @@ -707,6 +735,16 @@ void ScXMLExportDataPilot::WriteDimensions(ScDPSaveData* pDPSave) } } +void ScXMLExportDataPilot::WriteGrandTotal(::xmloff::token::XMLTokenEnum eOrient, bool bVisible, const OUString* pGrandTotal) +{ + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY, bVisible ? XML_TRUE : XML_FALSE); + rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ORIENTATION, eOrient); + if (pGrandTotal) + rExport.AddAttribute(XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, *pGrandTotal); + + SvXMLElementExport aElemGrandTotal(rExport, XML_NAMESPACE_TABLE, XML_DATA_PILOT_GRAND_TOTAL, sal_True, sal_True); +} + void ScXMLExportDataPilot::WriteDataPilots(const uno::Reference <sheet::XSpreadsheetDocument>& /* xSpreadDoc */) { pDoc = rExport.GetDocument(); @@ -775,6 +813,24 @@ void ScXMLExportDataPilot::WriteDataPilots(const uno::Reference <sheet::XSpreads if (!pDPSave->GetDrillDown()) rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DRILL_DOWN_ON_DOUBLE_CLICK, XML_FALSE); SvXMLElementExport aElemDP(rExport, XML_NAMESPACE_TABLE, XML_DATA_PILOT_TABLE, sal_True, sal_True); + + // grand total elements. + + const OUString* pGrandTotalName = pDPSave->GetGrandTotalName(); + if (pGrandTotalName && rExport.getDefaultVersion() == SvtSaveOptions::ODFVER_LATEST) + { + // Use the new data-pilot-grand-total element. + if (bRowGrand && bColumnGrand) + { + WriteGrandTotal(XML_BOTH, true, pGrandTotalName); + } + else + { + WriteGrandTotal(XML_ROW, bRowGrand, pGrandTotalName); + WriteGrandTotal(XML_COLUMN, bColumnGrand, pGrandTotalName); + } + } + rExport.CheckAttrList(); if ((*pDPs)[i]->IsSheetData()) { diff --git a/sc/source/filter/xml/XMLExportDataPilot.hxx b/sc/source/filter/xml/XMLExportDataPilot.hxx index fb78a59d616b..8bf884ab2fd6 100644 --- a/sc/source/filter/xml/XMLExportDataPilot.hxx +++ b/sc/source/filter/xml/XMLExportDataPilot.hxx @@ -34,6 +34,7 @@ #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> #include <rtl/ustring.hxx> #include "global.hxx" +#include "xmloff/xmltoken.hxx" class ScXMLExport; class ScDocument; @@ -69,6 +70,8 @@ class ScXMLExportDataPilot void WriteDimension(ScDPSaveDimension* pDim, const ScDPDimensionSaveData* pDimData); void WriteDimensions(ScDPSaveData* pDPSave); + void WriteGrandTotal(::xmloff::token::XMLTokenEnum eOrient, bool bVisible, const ::rtl::OUString* pGrandTotal); + public: ScXMLExportDataPilot(ScXMLExport& rExport); ~ScXMLExportDataPilot(); diff --git a/sc/source/filter/xml/xmldpimp.cxx b/sc/source/filter/xml/xmldpimp.cxx index 428e369a94dc..08e8633978b1 100644 --- a/sc/source/filter/xml/xmldpimp.cxx +++ b/sc/source/filter/xml/xmldpimp.cxx @@ -48,6 +48,7 @@ #include "dpgroup.hxx" #include "dpdimsave.hxx" #include "rangeutl.hxx" +#include "dpoutputgeometry.hxx" #include <xmloff/xmltkmap.hxx> #include <xmloff/nmspmap.hxx> @@ -65,6 +66,8 @@ using namespace com::sun::star; using namespace xmloff::token; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; using ::rtl::OUString; //------------------------------------------------------------------ @@ -113,6 +116,9 @@ void ScXMLDataPilotTablesContext::EndElement() { } +ScXMLDataPilotTableContext::GrandTotalItem::GrandTotalItem() : + mbVisible(true) {} + ScXMLDataPilotTableContext::ScXMLDataPilotTableContext( ScXMLImport& rImport, USHORT nPrfx, const ::rtl::OUString& rLName, @@ -126,6 +132,10 @@ ScXMLDataPilotTableContext::ScXMLDataPilotTableContext( ScXMLImport& rImport, sDataPilotTableName(), sApplicationData(), sGrandTotal(GetXMLToken(XML_BOTH)), + mnRowFieldCount(0), + mnColFieldCount(0), + mnPageFieldCount(0), + mnDataFieldCount(0), bIsNative(sal_True), bIgnoreEmptyRows(sal_False), bIdentifyCategories(sal_False), @@ -159,6 +169,26 @@ ScXMLDataPilotTableContext::ScXMLDataPilotTableContext( ScXMLImport& rImport, case XML_TOK_DATA_PILOT_TABLE_ATTR_GRAND_TOTAL : { sGrandTotal = sValue; + if (IsXMLToken(sValue, XML_BOTH)) + { + maRowGrandTotal.mbVisible = true; + maColGrandTotal.mbVisible = true; + } + else if (IsXMLToken(sValue, XML_ROW)) + { + maRowGrandTotal.mbVisible = true; + maColGrandTotal.mbVisible = false; + } + else if (IsXMLToken(sValue, XML_COLUMN)) + { + maRowGrandTotal.mbVisible = false; + maColGrandTotal.mbVisible = true; + } + else + { + maRowGrandTotal.mbVisible = false; + maColGrandTotal.mbVisible = false; + } } break; case XML_TOK_DATA_PILOT_TABLE_ATTR_IGNORE_EMPTY_ROWS : @@ -238,6 +268,11 @@ SvXMLImportContext *ScXMLDataPilotTableContext::CreateChildContext( USHORT nPref nSourceType = SERVICE; } break; + case XML_TOK_DATA_PILOT_TABLE_ELEM_GRAND_TOTAL: + { + pContext = new ScXMLDataPilotGrandTotalContext(GetScImport(), nPrefix, rLName, xAttrList, this); + } + break; case XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_CELL_RANGE : { pContext = new ScXMLSourceCellRangeContext(GetScImport(), nPrefix, rLName, xAttrList, this); @@ -257,6 +292,12 @@ SvXMLImportContext *ScXMLDataPilotTableContext::CreateChildContext( USHORT nPref void ScXMLDataPilotTableContext::SetButtons() { + ScDPOutputGeometry aGeometry(aTargetRangeAddress, bShowFilter, ScDPOutputGeometry::ODF); + aGeometry.setColumnFieldCount(mnColFieldCount); + aGeometry.setRowFieldCount(mnRowFieldCount); + aGeometry.setPageFieldCount(mnPageFieldCount); + aGeometry.setDataFieldCount(mnDataFieldCount); + OUString sAddress; sal_Int32 nOffset = 0; while( nOffset >= 0 ) @@ -268,8 +309,21 @@ void ScXMLDataPilotTableContext::SetButtons() sal_Int32 nAddrOffset(0); if (pDoc && ScRangeStringConverter::GetAddressFromString( aScAddress, sAddress, pDoc, ::formula::FormulaGrammar::CONV_OOO, nAddrOffset )) { - ScMergeFlagAttr aAttr( SC_MF_BUTTON ); - pDoc->ApplyAttr( aScAddress.Col(), aScAddress.Row(), aScAddress.Tab(), aAttr ); + ScDPOutputGeometry::FieldType eType = aGeometry.getFieldButtonType(aScAddress); + + sal_Int16 nMFlag = SC_MF_BUTTON; + if (eType == ScDPOutputGeometry::Column || eType == ScDPOutputGeometry::Row) + nMFlag |= SC_MF_BUTTON_POPUP; + + // Use the cell's string value to see if this field contains a + // hidden member. Isn't there a better way? GetString() is + // quite expensive... + String aCellStr; + pDoc->GetString(aScAddress.Col(), aScAddress.Row(), aScAddress.Tab(), aCellStr); + if (maHiddenMemberFields.count(aCellStr)) + nMFlag |= SC_MF_HIDDEN_MEMBER; + + pDoc->ApplyFlagsTab(aScAddress.Col(), aScAddress.Row(), aScAddress.Col(), aScAddress.Row(), aScAddress.Tab(), nMFlag); } } } @@ -278,7 +332,7 @@ void ScXMLDataPilotTableContext::SetButtons() pDPObject->RefreshAfterLoad(); } -void ScXMLDataPilotTableContext::AddDimension(ScDPSaveDimension* pDim) +void ScXMLDataPilotTableContext::AddDimension(ScDPSaveDimension* pDim, bool bHasHiddenMember) { if (pDPSave) { @@ -288,6 +342,38 @@ void ScXMLDataPilotTableContext::AddDimension(ScDPSaveDimension* pDim) pDPSave->GetExistingDimensionByName(pDim->GetName()) ) pDim->SetDupFlag( TRUE ); + if (!pDim->IsDataLayout()) + { + switch (pDim->GetOrientation()) + { + case sheet::DataPilotFieldOrientation_ROW: + ++mnRowFieldCount; + break; + case sheet::DataPilotFieldOrientation_COLUMN: + ++mnColFieldCount; + break; + case sheet::DataPilotFieldOrientation_PAGE: + ++mnPageFieldCount; + break; + case sheet::DataPilotFieldOrientation_DATA: + ++mnDataFieldCount; + break; + case sheet::DataPilotFieldOrientation_HIDDEN: + default: + ; + } + + if (bHasHiddenMember) + { + // the layout name takes priority over the original name, + // since this data is used against cell values. + const OUString* pLayoutName = pDim->GetLayoutName(); + if (pLayoutName) + maHiddenMemberFields.insert(*pLayoutName); + else + maHiddenMemberFields.insert(pDim->GetName()); + } + } pDPSave->AddDimension(pDim); } } @@ -362,26 +448,15 @@ void ScXMLDataPilotTableContext::EndElement() } break; } - if (IsXMLToken(sGrandTotal, XML_BOTH)) - { - pDPSave->SetRowGrand(sal_True); - pDPSave->SetColumnGrand(sal_True); - } - else if (IsXMLToken(sGrandTotal, XML_ROW)) - { - pDPSave->SetRowGrand(sal_True); - pDPSave->SetColumnGrand(sal_False); - } - else if (IsXMLToken(sGrandTotal, XML_COLUMN)) - { - pDPSave->SetRowGrand(sal_False); - pDPSave->SetColumnGrand(sal_True); - } - else - { - pDPSave->SetRowGrand(sal_False); - pDPSave->SetColumnGrand(sal_False); - } + + pDPSave->SetRowGrand(maRowGrandTotal.mbVisible); + pDPSave->SetColumnGrand(maColGrandTotal.mbVisible); + if (maRowGrandTotal.maDisplayName.getLength()) + // TODO: Right now, we only support one grand total name for both + // column and row totals. Take the value from the row total for + // now. + pDPSave->SetGrandTotalName(maRowGrandTotal.maDisplayName); + pDPSave->SetIgnoreEmptyRows(bIgnoreEmptyRows); pDPSave->SetRepeatIfEmpty(bIdentifyCategories); pDPSave->SetFilterButton(bShowFilter); @@ -393,12 +468,36 @@ void ScXMLDataPilotTableContext::EndElement() { ScDPCollection* pDPCollection = pDoc->GetDPCollection(); pDPObject->SetAlive(sal_True); - pDPCollection->Insert(pDPObject); + pDPCollection->InsertNewTable(pDPObject); } SetButtons(); } } +void ScXMLDataPilotTableContext::SetGrandTotal( + XMLTokenEnum eOrientation, bool bVisible, const OUString& rDisplayName) +{ + switch (eOrientation) + { + case XML_BOTH: + maRowGrandTotal.mbVisible = bVisible; + maRowGrandTotal.maDisplayName = rDisplayName; + maColGrandTotal.mbVisible = bVisible; + maColGrandTotal.maDisplayName = rDisplayName; + break; + case XML_ROW: + maRowGrandTotal.mbVisible = bVisible; + maRowGrandTotal.maDisplayName = rDisplayName; + break; + case XML_COLUMN: + maColGrandTotal.mbVisible = bVisible; + maColGrandTotal.maDisplayName = rDisplayName; + break; + default: + ; + } +} + ScXMLDPSourceSQLContext::ScXMLDPSourceSQLContext( ScXMLImport& rImport, USHORT nPrfx, const ::rtl::OUString& rLName, @@ -643,6 +742,81 @@ void ScXMLSourceServiceContext::EndElement() { } +ScXMLImport& ScXMLDataPilotGrandTotalContext::GetScImport() +{ + return static_cast<ScXMLImport&>(GetImport()); +} + +ScXMLDataPilotGrandTotalContext::ScXMLDataPilotGrandTotalContext( + ScXMLImport& rImport, USHORT nPrefix, const OUString& rLName, const Reference<XAttributeList>& xAttrList, + ScXMLDataPilotTableContext* pTableContext ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mpTableContext(pTableContext), + meOrientation(NONE), + mbVisible(false) +{ + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetDataPilotGrandTotalAttrTokenMap(); + for (sal_Int16 i = 0; i < nAttrCount; ++i) + { + const OUString& rAttrName = xAttrList->getNameByIndex(i); + const OUString& rAttrValue = xAttrList->getValueByIndex(i); + + OUString aLocalName; + USHORT nLocalPrefix = GetScImport().GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName); + switch (rAttrTokenMap.Get(nLocalPrefix, aLocalName)) + { + case XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY: + mbVisible = IsXMLToken(rAttrValue, XML_TRUE); + break; + case XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_ORIENTATION: + if (IsXMLToken(rAttrValue, XML_BOTH)) + meOrientation = BOTH; + else if (IsXMLToken(rAttrValue, XML_ROW)) + meOrientation = ROW; + else if (IsXMLToken(rAttrValue, XML_COLUMN)) + meOrientation = COLUMN; + break; + case XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY_NAME: + case XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY_NAME_EXT: + maDisplayName = rAttrValue; + break; + default: + ; + } + } +} + +ScXMLDataPilotGrandTotalContext::~ScXMLDataPilotGrandTotalContext() +{ +} + +SvXMLImportContext* ScXMLDataPilotGrandTotalContext::CreateChildContext( + USHORT /*nPrefix*/, const ::rtl::OUString& /*rLocalName*/, const Reference<XAttributeList>& /*xAttrList*/ ) +{ + return NULL; +} + +void ScXMLDataPilotGrandTotalContext::EndElement() +{ + XMLTokenEnum eOrient = XML_NONE; + switch (meOrientation) + { + case BOTH: + eOrient = XML_BOTH; + break; + case ROW: + eOrient = XML_ROW; + break; + case COLUMN: + eOrient = XML_COLUMN; + break; + default: + ; + } + mpTableContext->SetGrandTotal(eOrient, mbVisible, maDisplayName); +} + ScXMLSourceCellRangeContext::ScXMLSourceCellRangeContext( ScXMLImport& rImport, USHORT nPrfx, const ::rtl::OUString& rLName, @@ -723,10 +897,12 @@ ScXMLDataPilotFieldContext::ScXMLDataPilotFieldContext( ScXMLImport& rImport, bIsGroupField(sal_False), bDateValue(sal_False), bAutoStart(sal_False), - bAutoEnd(sal_False) + bAutoEnd(sal_False), + mbHasHiddenMember(false) { sal_Bool bHasName(sal_False); sal_Bool bDataLayout(sal_False); + OUString aDisplayName; sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetDataPilotFieldAttrTokenMap(); for( sal_Int16 i=0; i < nAttrCount; ++i ) @@ -745,6 +921,12 @@ ScXMLDataPilotFieldContext::ScXMLDataPilotFieldContext( ScXMLImport& rImport, bHasName = sal_True; } break; + case XML_TOK_DATA_PILOT_FIELD_ATTR_DISPLAY_NAME: + case XML_TOK_DATA_PILOT_FIELD_ATTR_DISPLAY_NAME_EXT: + { + aDisplayName = sValue; + } + break; case XML_TOK_DATA_PILOT_FIELD_ATTR_IS_DATA_LAYOUT_FIELD : { bDataLayout = IsXMLToken(sValue, XML_TRUE); @@ -774,7 +956,11 @@ ScXMLDataPilotFieldContext::ScXMLDataPilotFieldContext( ScXMLImport& rImport, } } if (bHasName) + { pDim = new ScDPSaveDimension(String(sName), bDataLayout); + if (aDisplayName.getLength()) + pDim->SetLayoutName(aDisplayName); + } } ScXMLDataPilotFieldContext::~ScXMLDataPilotFieldContext() @@ -808,6 +994,22 @@ SvXMLImportContext *ScXMLDataPilotFieldContext::CreateChildContext( USHORT nPref return pContext; } +void ScXMLDataPilotFieldContext::AddMember(ScDPSaveMember* pMember) +{ + if (pDim) + pDim->AddMember(pMember); + + if (!pMember->GetIsVisible()) + // This member is hidden. + mbHasHiddenMember = true; +} + +void ScXMLDataPilotFieldContext::SetSubTotalName(const OUString& rName) +{ + if (pDim) + pDim->SetSubtotalName(rName); +} + void ScXMLDataPilotFieldContext::AddGroup(const ::std::vector<rtl::OUString>& rMembers, const rtl::OUString& rName) { ScXMLDataPilotGroup aGroup; @@ -828,7 +1030,7 @@ void ScXMLDataPilotFieldContext::EndElement() String sPage(sSelectedPage); pDim->SetCurrentPage(&sPage); } - pDataPilotTable->AddDimension(pDim); + pDataPilotTable->AddDimension(pDim, mbHasHiddenMember); if (bIsGroupField) { ScDPNumGroupInfo aInfo; @@ -1199,6 +1401,8 @@ SvXMLImportContext *ScXMLDataPilotSubTotalsContext::CreateChildContext( USHORT n void ScXMLDataPilotSubTotalsContext::EndElement() { pDataPilotField->SetSubTotals(pFunctions, nFunctionCount); + if (maDisplayName.getLength()) + pDataPilotField->SetSubTotalName(maDisplayName); } void ScXMLDataPilotSubTotalsContext::AddFunction(sal_Int16 nFunction) @@ -1221,6 +1425,11 @@ void ScXMLDataPilotSubTotalsContext::AddFunction(sal_Int16 nFunction) } } +void ScXMLDataPilotSubTotalsContext::SetDisplayName(const OUString& rName) +{ + maDisplayName = rName; +} + ScXMLDataPilotSubTotalContext::ScXMLDataPilotSubTotalContext( ScXMLImport& rImport, USHORT nPrfx, const ::rtl::OUString& rLName, @@ -1247,6 +1456,9 @@ ScXMLDataPilotSubTotalContext::ScXMLDataPilotSubTotalContext( ScXMLImport& rImpo pDataPilotSubTotals->AddFunction( sal::static_int_cast<sal_Int16>( ScXMLConverter::GetFunctionFromString( sValue ) ) ); } + case XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_DISPLAY_NAME: + case XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_DISPLAY_NAME_EXT: + pDataPilotSubTotals->SetDisplayName(sValue); break; } } @@ -1344,6 +1556,11 @@ ScXMLDataPilotMemberContext::ScXMLDataPilotMemberContext( ScXMLImport& rImport, bHasName = sal_True; } break; + case XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY_NAME: + case XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY_NAME_EXT: + { + maDisplayName = sValue; + } case XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY : { bDisplay = IsXMLToken(sValue, XML_TRUE); @@ -1380,6 +1597,8 @@ void ScXMLDataPilotMemberContext::EndElement() if (bHasName) // #i53407# don't check sName, empty name is allowed { ScDPSaveMember* pMember = new ScDPSaveMember(String(sName)); + if (maDisplayName.getLength()) + pMember->SetLayoutName(maDisplayName); pMember->SetIsVisible(bDisplay); pMember->SetShowDetails(bDisplayDetails); pDataPilotField->AddMember(pMember); diff --git a/sc/source/filter/xml/xmldpimp.hxx b/sc/source/filter/xml/xmldpimp.hxx index 874fe27654ba..50dc7e6d9c0d 100644 --- a/sc/source/filter/xml/xmldpimp.hxx +++ b/sc/source/filter/xml/xmldpimp.hxx @@ -41,6 +41,8 @@ #include "dpobject.hxx" #include "dpsave.hxx" +#include <hash_set> + class ScXMLImport; class ScDPSaveNumGroupDimension; class ScDPSaveGroupDimension; @@ -79,10 +81,21 @@ public: class ScXMLDataPilotTableContext : public SvXMLImportContext { + typedef ::std::hash_set< ::rtl::OUString, ::rtl::OUStringHash > StringSet; + StringSet maHiddenMemberFields; + + struct GrandTotalItem + { + ::rtl::OUString maDisplayName; + bool mbVisible; + GrandTotalItem(); + }; ScDocument* pDoc; ScDPObject* pDPObject; ScDPSaveData* pDPSave; ScDPDimensionSaveData* pDPDimSaveData; + GrandTotalItem maRowGrandTotal; + GrandTotalItem maColGrandTotal; rtl::OUString sDataPilotTableName; rtl::OUString sApplicationData; rtl::OUString sGrandTotal; @@ -100,6 +113,10 @@ class ScXMLDataPilotTableContext : public SvXMLImportContext ScAddress aFilterOutputPosition; ScQueryParam aSourceQueryParam; ScMySourceType nSourceType; + sal_uInt32 mnRowFieldCount; + sal_uInt32 mnColFieldCount; + sal_uInt32 mnPageFieldCount; + sal_uInt32 mnDataFieldCount; sal_Bool bIsNative; sal_Bool bIgnoreEmptyRows; sal_Bool bIdentifyCategories; @@ -131,6 +148,7 @@ public: virtual void EndElement(); + void SetGrandTotal(::xmloff::token::XMLTokenEnum eOrientation, bool bVisible, const ::rtl::OUString& rDisplayName); void SetDatabaseName(const rtl::OUString& sValue) { sDatabaseName = sValue; } void SetSourceObject(const rtl::OUString& sValue) { sSourceObject = sValue; } void SetNative(const sal_Bool bValue) { bIsNative = bValue; } @@ -147,7 +165,7 @@ public: void SetFilterSourceRange(const ScRange& aValue) { aFilterSourceRange = aValue; } // void SetFilterIsCaseSensitive(const sal_Bool bValue) { aSourceQueryParam.bCaseSens = bValue; } // void SetFilterSkipDuplicates(const sal_Bool bValue) { aSourceQueryParam.bDuplicate = !bValue; } - void AddDimension(ScDPSaveDimension* pDim); + void AddDimension(ScDPSaveDimension* pDim, bool bHasHiddenMember); void AddGroupDim(const ScDPSaveNumGroupDimension& aNumGroupDim); void AddGroupDim(const ScDPSaveGroupDimension& aGroupDim); void SetButtons(); @@ -253,6 +271,34 @@ public: virtual void EndElement(); }; +class ScXMLDataPilotGrandTotalContext : public SvXMLImportContext +{ + enum Orientation { COLUMN, ROW, BOTH, NONE }; + + ScXMLImport& GetScImport(); + + ScXMLDataPilotTableContext* mpTableContext; + ::rtl::OUString maDisplayName; + Orientation meOrientation; + bool mbVisible; + +public: + ScXMLDataPilotGrandTotalContext( + ScXMLImport& rImport, USHORT nPrefix, const ::rtl::OUString& rLName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList, + ScXMLDataPilotTableContext* pTableContext ); + + virtual ~ScXMLDataPilotGrandTotalContext(); + + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); + + virtual void EndElement(); +}; + class ScXMLSourceCellRangeContext : public SvXMLImportContext { ScXMLDataPilotTableContext* pDataPilotTable; @@ -300,12 +346,13 @@ class ScXMLDataPilotFieldContext : public SvXMLImportContext sal_Int32 nGroupPart; sal_Int16 nFunction; sal_Int16 nOrientation; - sal_Bool bShowEmpty; - sal_Bool bSelectedPage; - sal_Bool bIsGroupField; - sal_Bool bDateValue; - sal_Bool bAutoStart; - sal_Bool bAutoEnd; + sal_Bool bShowEmpty:1; + sal_Bool bSelectedPage:1; + sal_Bool bIsGroupField:1; + sal_Bool bDateValue:1; + sal_Bool bAutoStart:1; + sal_Bool bAutoEnd:1; + bool mbHasHiddenMember:1; const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); } ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); } @@ -329,7 +376,8 @@ public: void SetShowEmpty(const sal_Bool bValue) { if (pDim) pDim->SetShowEmpty(bValue); } void SetSubTotals(const sal_uInt16* pFunctions, const sal_Int16 nCount) { if(pDim) pDim->SetSubTotals(nCount, pFunctions); } - void AddMember(ScDPSaveMember* pMember) { if (pDim) pDim->AddMember(pMember); } + void AddMember(ScDPSaveMember* pMember); + void SetSubTotalName(const ::rtl::OUString& rName); void SetFieldReference(const com::sun::star::sheet::DataPilotFieldReference& aRef) { if (pDim) pDim->SetReferenceValue(&aRef); } void SetAutoShowInfo(const com::sun::star::sheet::DataPilotFieldAutoShowInfo& aInfo) { if (pDim) pDim->SetAutoShowInfo(&aInfo); } void SetSortInfo(const com::sun::star::sheet::DataPilotFieldSortInfo& aInfo) { if (pDim) pDim->SetSortInfo(&aInfo); } @@ -453,6 +501,7 @@ class ScXMLDataPilotSubTotalsContext : public SvXMLImportContext sal_Int16 nFunctionCount; sal_uInt16* pFunctions; + ::rtl::OUString maDisplayName; const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); } ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); } @@ -476,6 +525,7 @@ public: virtual void EndElement(); void AddFunction(sal_Int16 nFunction); + void SetDisplayName(const ::rtl::OUString& rName); }; class ScXMLDataPilotSubTotalContext : public SvXMLImportContext @@ -533,6 +583,7 @@ class ScXMLDataPilotMemberContext : public SvXMLImportContext ScXMLDataPilotFieldContext* pDataPilotField; rtl::OUString sName; + rtl::OUString maDisplayName; sal_Bool bDisplay; sal_Bool bDisplayDetails; sal_Bool bHasName; diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx index 5d07670f53a2..f2fe367a2c64 100644 --- a/sc/source/filter/xml/xmlimprt.cxx +++ b/sc/source/filter/xml/xmlimprt.cxx @@ -1347,6 +1347,7 @@ const SvXMLTokenMap& ScXMLImport::GetDataPilotTableElemTokenMap() { { XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_SQL, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_SQL }, { XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_TABLE, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_TABLE }, + { XML_NAMESPACE_TABLE, XML_DATA_PILOT_GRAND_TOTAL, XML_TOK_DATA_PILOT_TABLE_ELEM_GRAND_TOTAL }, { XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_QUERY, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_QUERY }, { XML_NAMESPACE_TABLE, XML_SOURCE_SERVICE, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_SERVICE }, { XML_NAMESPACE_TABLE, XML_SOURCE_CELL_RANGE, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_CELL_RANGE }, @@ -1380,6 +1381,25 @@ const SvXMLTokenMap& ScXMLImport::GetDataPilotTableSourceServiceAttrTokenMap() return *pDataPilotTableSourceServiceAttrTokenMap; } +const SvXMLTokenMap& ScXMLImport::GetDataPilotGrandTotalAttrTokenMap() +{ + if (!pDataPilotGrandTotalAttrTokenMap) + { + static __FAR_DATA SvXMLTokenMapEntry aDataPilotGrandTotalAttrTokenMap[] = + { + { XML_NAMESPACE_TABLE, XML_DISPLAY, XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY }, + { XML_NAMESPACE_TABLE, XML_ORIENTATION, XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_ORIENTATION }, + { XML_NAMESPACE_TABLE, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY_NAME }, + { XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY_NAME_EXT }, + XML_TOKEN_MAP_END + }; + + pDataPilotGrandTotalAttrTokenMap = new SvXMLTokenMap( aDataPilotGrandTotalAttrTokenMap ); + } + + return *pDataPilotGrandTotalAttrTokenMap; +} + const SvXMLTokenMap& ScXMLImport::GetDataPilotTableSourceCellRangeAttrTokenMap() { if( !pDataPilotTableSourceCellRangeAttrTokenMap ) @@ -1418,12 +1438,14 @@ const SvXMLTokenMap& ScXMLImport::GetDataPilotFieldAttrTokenMap() { static __FAR_DATA SvXMLTokenMapEntry aDataPilotFieldAttrTokenMap[] = { - { XML_NAMESPACE_TABLE, XML_SOURCE_FIELD_NAME, XML_TOK_DATA_PILOT_FIELD_ATTR_SOURCE_FIELD_NAME }, - { XML_NAMESPACE_TABLE, XML_IS_DATA_LAYOUT_FIELD, XML_TOK_DATA_PILOT_FIELD_ATTR_IS_DATA_LAYOUT_FIELD }, - { XML_NAMESPACE_TABLE, XML_FUNCTION, XML_TOK_DATA_PILOT_FIELD_ATTR_FUNCTION }, - { XML_NAMESPACE_TABLE, XML_ORIENTATION, XML_TOK_DATA_PILOT_FIELD_ATTR_ORIENTATION }, - { XML_NAMESPACE_TABLE, XML_SELECTED_PAGE, XML_TOK_DATA_PILOT_FIELD_ATTR_SELECTED_PAGE }, - { XML_NAMESPACE_TABLE, XML_USED_HIERARCHY, XML_TOK_DATA_PILOT_FIELD_ATTR_USED_HIERARCHY }, + { XML_NAMESPACE_TABLE, XML_SOURCE_FIELD_NAME, XML_TOK_DATA_PILOT_FIELD_ATTR_SOURCE_FIELD_NAME }, + { XML_NAMESPACE_TABLE, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_FIELD_ATTR_DISPLAY_NAME }, + { XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_FIELD_ATTR_DISPLAY_NAME_EXT }, + { XML_NAMESPACE_TABLE, XML_IS_DATA_LAYOUT_FIELD, XML_TOK_DATA_PILOT_FIELD_ATTR_IS_DATA_LAYOUT_FIELD }, + { XML_NAMESPACE_TABLE, XML_FUNCTION, XML_TOK_DATA_PILOT_FIELD_ATTR_FUNCTION }, + { XML_NAMESPACE_TABLE, XML_ORIENTATION, XML_TOK_DATA_PILOT_FIELD_ATTR_ORIENTATION }, + { XML_NAMESPACE_TABLE, XML_SELECTED_PAGE, XML_TOK_DATA_PILOT_FIELD_ATTR_SELECTED_PAGE }, + { XML_NAMESPACE_TABLE, XML_USED_HIERARCHY, XML_TOK_DATA_PILOT_FIELD_ATTR_USED_HIERARCHY }, XML_TOKEN_MAP_END }; @@ -1509,7 +1531,9 @@ const SvXMLTokenMap& ScXMLImport::GetDataPilotSubTotalAttrTokenMap() { static __FAR_DATA SvXMLTokenMapEntry aDataPilotSubTotalAttrTokenMap[] = { - { XML_NAMESPACE_TABLE, XML_FUNCTION, XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_FUNCTION }, + { XML_NAMESPACE_TABLE, XML_FUNCTION, XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_FUNCTION }, + { XML_NAMESPACE_TABLE, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_DISPLAY_NAME }, + { XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_DISPLAY_NAME_EXT }, XML_TOKEN_MAP_END }; @@ -1541,9 +1565,11 @@ const SvXMLTokenMap& ScXMLImport::GetDataPilotMemberAttrTokenMap() { static __FAR_DATA SvXMLTokenMapEntry aDataPilotMemberAttrTokenMap[] = { - { XML_NAMESPACE_TABLE, XML_NAME, XML_TOK_DATA_PILOT_MEMBER_ATTR_NAME }, - { XML_NAMESPACE_TABLE, XML_DISPLAY, XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY }, - { XML_NAMESPACE_TABLE, XML_SHOW_DETAILS, XML_TOK_DATA_PILOT_MEMBER_ATTR_SHOW_DETAILS }, + { XML_NAMESPACE_TABLE, XML_NAME, XML_TOK_DATA_PILOT_MEMBER_ATTR_NAME }, + { XML_NAMESPACE_TABLE, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY_NAME }, + { XML_NAMESPACE_TABLE_EXT, XML_DISPLAY_NAME, XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY_NAME_EXT }, + { XML_NAMESPACE_TABLE, XML_DISPLAY, XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY }, + { XML_NAMESPACE_TABLE, XML_SHOW_DETAILS, XML_TOK_DATA_PILOT_MEMBER_ATTR_SHOW_DETAILS }, XML_TOKEN_MAP_END }; @@ -1677,6 +1703,7 @@ ScXMLImport::ScXMLImport( pDataPilotTableAttrTokenMap( 0 ), pDataPilotTableElemTokenMap( 0 ), pDataPilotTableSourceServiceAttrTokenMap( 0 ), + pDataPilotGrandTotalAttrTokenMap(NULL), pDataPilotTableSourceCellRangeElemTokenMap( 0 ), pDataPilotTableSourceCellRangeAttrTokenMap( 0 ), pDataPilotFieldAttrTokenMap( 0 ), diff --git a/sc/source/filter/xml/xmlimprt.hxx b/sc/source/filter/xml/xmlimprt.hxx index c108642d0b68..c110c70f72e2 100644 --- a/sc/source/filter/xml/xmlimprt.hxx +++ b/sc/source/filter/xml/xmlimprt.hxx @@ -489,6 +489,7 @@ enum ScXMLDataPilotTableElemTokens { XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_SQL, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_TABLE, + XML_TOK_DATA_PILOT_TABLE_ELEM_GRAND_TOTAL, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_QUERY, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_SERVICE, XML_TOK_DATA_PILOT_TABLE_ELEM_SOURCE_CELL_RANGE, @@ -504,6 +505,14 @@ enum ScXMLDataPilotTableSourceServiceAttrTokens XML_TOK_SOURCE_SERVICE_ATTR_PASSWORD }; +enum ScXMLDataPilotGrandTotalAttrTokens +{ + XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY, + XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_ORIENTATION, + XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY_NAME, + XML_TOK_DATA_PILOT_GRAND_TOTAL_ATTR_DISPLAY_NAME_EXT +}; + enum ScXMLDataPilotTableSourceCellRangeElemTokens { XML_TOK_SOURCE_CELL_RANGE_ELEM_FILTER @@ -517,6 +526,8 @@ enum ScXMLDataPilotTableSourceCellRangeAttrTokens enum ScXMLDataPilotFieldAttrTokens { XML_TOK_DATA_PILOT_FIELD_ATTR_SOURCE_FIELD_NAME, + XML_TOK_DATA_PILOT_FIELD_ATTR_DISPLAY_NAME, + XML_TOK_DATA_PILOT_FIELD_ATTR_DISPLAY_NAME_EXT, XML_TOK_DATA_PILOT_FIELD_ATTR_IS_DATA_LAYOUT_FIELD, XML_TOK_DATA_PILOT_FIELD_ATTR_FUNCTION, XML_TOK_DATA_PILOT_FIELD_ATTR_ORIENTATION, @@ -552,7 +563,9 @@ enum ScXMLDataPilotSubTotalsElemTokens enum ScXMLDataPilotSubTotalAttrTokens { - XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_FUNCTION + XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_FUNCTION, + XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_DISPLAY_NAME, + XML_TOK_DATA_PILOT_SUBTOTAL_ATTR_DISPLAY_NAME_EXT }; enum ScXMLDataPilotMembersElemTokens @@ -563,6 +576,8 @@ enum ScXMLDataPilotMembersElemTokens enum ScXMLDataPilotMemberAttrTokens { XML_TOK_DATA_PILOT_MEMBER_ATTR_NAME, + XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY_NAME, + XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY_NAME_EXT, XML_TOK_DATA_PILOT_MEMBER_ATTR_DISPLAY, XML_TOK_DATA_PILOT_MEMBER_ATTR_SHOW_DETAILS }; @@ -723,6 +738,7 @@ class ScXMLImport: public SvXMLImport SvXMLTokenMap *pDataPilotTableAttrTokenMap; SvXMLTokenMap *pDataPilotTableElemTokenMap; SvXMLTokenMap *pDataPilotTableSourceServiceAttrTokenMap; + SvXMLTokenMap *pDataPilotGrandTotalAttrTokenMap; SvXMLTokenMap *pDataPilotTableSourceCellRangeElemTokenMap; SvXMLTokenMap *pDataPilotTableSourceCellRangeAttrTokenMap; SvXMLTokenMap *pDataPilotFieldAttrTokenMap; @@ -886,6 +902,7 @@ public: const SvXMLTokenMap& GetDataPilotTableAttrTokenMap(); const SvXMLTokenMap& GetDataPilotTableElemTokenMap(); const SvXMLTokenMap& GetDataPilotTableSourceServiceAttrTokenMap(); + const SvXMLTokenMap& GetDataPilotGrandTotalAttrTokenMap(); const SvXMLTokenMap& GetDataPilotTableSourceCellRangeElemTokenMap(); const SvXMLTokenMap& GetDataPilotTableSourceCellRangeAttrTokenMap(); const SvXMLTokenMap& GetDataPilotFieldAttrTokenMap(); diff --git a/sc/source/ui/Accessibility/AccessibleContextBase.cxx b/sc/source/ui/Accessibility/AccessibleContextBase.cxx index b611198974de..c6c08e8a9c65 100644 --- a/sc/source/ui/Accessibility/AccessibleContextBase.cxx +++ b/sc/source/ui/Accessibility/AccessibleContextBase.cxx @@ -628,3 +628,8 @@ void ScAccessibleContextBase::IsObjectValid() const if (rBHelper.bDisposed || rBHelper.bInDispose) throw lang::DisposedException(); } + +void ScAccessibleContextBase::SetRole(sal_Int16 nRole) +{ + maRole = nRole; +} diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx new file mode 100644 index 000000000000..14824b920c85 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx @@ -0,0 +1,402 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleGlobal.hxx" +#include "AccessibleFilterMenu.hxx" +#include "AccessibleFilterMenuItem.hxx" +#include "unoguard.hxx" +#include "global.hxx" +#include "document.hxx" +#include "docpool.hxx" + +#include "tools/gen.hxx" +#include "svx/unoedsrc.hxx" +#include "svx/editdata.hxx" +#include "svx/outliner.hxx" +#include "svtools/itemset.hxx" +#include "vcl/unohelp.hxx" +#include "dpcontrol.hxx" + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::accessibility::AccessibleStateType; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::uno::RuntimeException; +using ::rtl::OUString; +using ::std::for_each; +using ::std::vector; + +// ============================================================================ + +namespace { + +class AddRemoveEventListener : public ::std::unary_function<void, Reference<XAccessible> > +{ +public: + explicit AddRemoveEventListener(const Reference<XAccessibleEventListener>& rListener, bool bAdd) : + mxListener(rListener), mbAdd(bAdd) {} + + void operator() (const Reference<XAccessible>& xAccessible) const + { + if (!xAccessible.is()) + return; + + Reference<XAccessibleEventBroadcaster> xBc(xAccessible, UNO_QUERY); + if (xBc.is()) + { + if (mbAdd) + xBc->addEventListener(mxListener); + else + xBc->removeEventListener(mxListener); + } + } +private: + Reference<XAccessibleEventListener> mxListener; + bool mbAdd; +}; + +} + +// ============================================================================ + +ScAccessibleFilterMenu::ScAccessibleFilterMenu(const Reference<XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos, ScDocument* pDoc) : + ScAccessibleContextBase(rxParent, AccessibleRole::MENU), + mnMenuPos(nMenuPos), + mpWindow(pWin), + mpDoc(pDoc), + mbEnabled(true) +{ + SetName(rName); +} + +ScAccessibleFilterMenu::~ScAccessibleFilterMenu() +{ +} + +// XAccessibleComponent + +Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleAtPoint( const ::com::sun::star::awt::Point& /*rPoint*/ ) + throw (RuntimeException) +{ + return this; +} + +sal_Bool ScAccessibleFilterMenu::isVisible() throw (RuntimeException) +{ + return mpWindow->IsVisible(); +} + +void ScAccessibleFilterMenu::grabFocus() + throw (RuntimeException) +{ +} + +sal_Int32 ScAccessibleFilterMenu::getForeground() + throw (RuntimeException) +{ + return 0; +} + +sal_Int32 ScAccessibleFilterMenu::getBackground() + throw (RuntimeException) +{ + return 0; +} + +// XAccessibleContext + +OUString ScAccessibleFilterMenu::getAccessibleName() throw (RuntimeException) +{ + return ScAccessibleContextBase::getAccessibleName(); +} + +sal_Int32 ScAccessibleFilterMenu::getAccessibleChildCount() + throw (RuntimeException) +{ + return getMenuItemCount(); +} + +Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleChild(sal_Int32 nIndex) + throw (RuntimeException, IndexOutOfBoundsException) +{ + if (maMenuItems.size() <= static_cast<size_t>(nIndex)) + throw IndexOutOfBoundsException(); + + return maMenuItems[nIndex]; +} + +Reference<XAccessibleStateSet> ScAccessibleFilterMenu::getAccessibleStateSet() + throw (RuntimeException) +{ + updateStates(); + return mxStateSet; +} + +OUString ScAccessibleFilterMenu::getImplementationName() + throw (RuntimeException) +{ + return OUString::createFromAscii("ScAccessibleFilterMenu"); +} + +// XAccessibleEventBroadcaster + +void ScAccessibleFilterMenu::addEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener>& xListener) + throw (com::sun::star::uno::RuntimeException) +{ + ScAccessibleContextBase::addEventListener(xListener); + for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, true)); +} + +void ScAccessibleFilterMenu::removeEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener>& xListener) + throw (com::sun::star::uno::RuntimeException) +{ + ScAccessibleContextBase::removeEventListener(xListener); + for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, false)); +} + +// XAccessibleSelection + +void ScAccessibleFilterMenu::selectAccessibleChild(sal_Int32 nChildIndex) + throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + mpWindow->setSelectedMenuItem(nChildIndex, false, true); +} + +sal_Bool ScAccessibleFilterMenu::isAccessibleChildSelected(sal_Int32 nChildIndex) + throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + return mpWindow->isMenuItemSelected(static_cast<size_t>(nChildIndex)); +} + +void ScAccessibleFilterMenu::clearAccessibleSelection() throw (RuntimeException) +{ + mpWindow->clearSelectedMenuItem(); +} + +void ScAccessibleFilterMenu::selectAllAccessibleChildren() throw (RuntimeException) +{ + // not suported - this is a menu, you can't select all menu items. +} + +sal_Int32 ScAccessibleFilterMenu::getSelectedAccessibleChildCount() throw (RuntimeException) +{ + // Since this is a menu, either one menu item is selected, or none at all. + return mpWindow->getSelectedMenuItem() == ScMenuFloatingWindow::MENU_NOT_SELECTED ? 0 : 1; +} + +Reference<XAccessible> ScAccessibleFilterMenu::getSelectedAccessibleChild(sal_Int32 nChildIndex) + throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + return maMenuItems[nChildIndex]; +} + +void ScAccessibleFilterMenu::deselectAccessibleChild(sal_Int32 nChildIndex) throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + mpWindow->selectMenuItem(nChildIndex, false, false); +} + +// XInterface + +uno::Any SAL_CALL ScAccessibleFilterMenu::queryInterface( uno::Type const & rType ) + throw (RuntimeException) +{ + Any any = ScAccessibleContextBase::queryInterface(rType); + if (any.hasValue()) + return any; + + return ScAccessibleFilterMenu_BASE::queryInterface(rType); +} + +void SAL_CALL ScAccessibleFilterMenu::acquire() throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessibleFilterMenu::release() throw () +{ + ScAccessibleContextBase::release(); +} + +// XTypeProvider + +Sequence<sal_Int8> ScAccessibleFilterMenu::getImplementationId() + throw (RuntimeException) +{ + Sequence<sal_Int8> aId(16); + return aId; +} + +Rectangle ScAccessibleFilterMenu::GetBoundingBoxOnScreen() const + throw (RuntimeException) +{ + if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED) + return Rectangle(); + + // Menu object's bounding box is the bounding box of the menu item that + // launches the menu, which belongs to the parent window. + ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow(); + if (!pParentWin) + return Rectangle(); + + if (!pParentWin->IsVisible()) + return Rectangle(); + + Point aPos = pParentWin->OutputToAbsoluteScreenPixel(Point(0,0)); + Point aMenuPos; + Size aMenuSize; + pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aPos + aMenuPos, aMenuSize); + return aRect; +} + +Rectangle ScAccessibleFilterMenu::GetBoundingBox() const + throw (RuntimeException) +{ + if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED) + return Rectangle(); + + // Menu object's bounding box is the bounding box of the menu item that + // launches the menu, which belongs to the parent window. + ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow(); + if (!pParentWin) + return Rectangle(); + + if (!pParentWin->IsVisible()) + return Rectangle(); + + Point aMenuPos; + Size aMenuSize; + pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aMenuPos, aMenuSize); + return aRect; +} + +void ScAccessibleFilterMenu::appendMenuItem(const OUString& rName, bool bEnabled, size_t nMenuPos) +{ + // Check weather this menu item is a sub menu or a regular menu item. + ScMenuFloatingWindow* pSubMenu = mpWindow->getSubMenuWindow(nMenuPos); + Reference<XAccessible> xAccessible; + if (pSubMenu) + { + xAccessible = pSubMenu->CreateAccessible(); + ScAccessibleFilterMenu* p = + static_cast<ScAccessibleFilterMenu*>(xAccessible.get()); + p->setEnabled(bEnabled); + p->setMenuPos(nMenuPos); + } + else + { + xAccessible.set(new ScAccessibleFilterMenuItem(this, mpWindow, rName, nMenuPos)); + ScAccessibleFilterMenuItem* p = + static_cast<ScAccessibleFilterMenuItem*>(xAccessible.get()); + p->setEnabled(bEnabled); + } + maMenuItems.push_back(xAccessible); +} + +void ScAccessibleFilterMenu::setMenuPos(size_t nMenuPos) +{ + mnMenuPos = nMenuPos; +} + +void ScAccessibleFilterMenu::setEnabled(bool bEnabled) +{ + mbEnabled = bEnabled; +} + +sal_Int32 ScAccessibleFilterMenu::getMenuItemCount() const +{ + return maMenuItems.size(); +} + +bool ScAccessibleFilterMenu::isSelected() const +{ + // Check to see if any of the child menu items is selected. + return mpWindow->isMenuItemSelected(mnMenuPos); +} + +bool ScAccessibleFilterMenu::isFocused() const +{ + return isSelected(); +} + +void ScAccessibleFilterMenu::updateStates() +{ + if (!mxStateSet.is()) + mxStateSet.set(new ScAccessibleStateSet); + + ScAccessibleStateSet* p = static_cast<ScAccessibleStateSet*>( + mxStateSet.get()); + + p->clear(); + + p->insert(ENABLED); + p->insert(FOCUSABLE); + p->insert(SELECTABLE); + p->insert(SENSITIVE); + p->insert(OPAQUE); + + if (isFocused()) + p->insert(FOCUSED); + + if (isSelected()) + p->insert(SELECTED); +} diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx new file mode 100644 index 000000000000..9f5524dcb8ce --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx @@ -0,0 +1,208 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleGlobal.hxx" +#include "AccessibleFilterMenuItem.hxx" +#include "dpcontrol.hxx" + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleEventObject.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/TextSegment.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::accessibility::AccessibleStateType; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::uno::RuntimeException; +using ::rtl::OUString; + +ScAccessibleFilterMenuItem::ScAccessibleFilterMenuItem( + const Reference<XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos) : + ScAccessibleContextBase(rxParent, AccessibleRole::MENU_ITEM), + mpWindow(pWin), + maName(rName), + mnMenuPos(nMenuPos), + mbEnabled(true) +{ + SetName(rName); +} + +ScAccessibleFilterMenuItem::~ScAccessibleFilterMenuItem() +{ +} + +sal_Int32 ScAccessibleFilterMenuItem::getAccessibleChildCount() + throw (RuntimeException) +{ + return 0; +} + +Reference<XAccessible> ScAccessibleFilterMenuItem::getAccessibleChild(sal_Int32 /*nIndex*/) + throw (RuntimeException, IndexOutOfBoundsException) +{ + throw IndexOutOfBoundsException(); +} + +Reference<XAccessibleStateSet> ScAccessibleFilterMenuItem::getAccessibleStateSet() + throw (RuntimeException) +{ + updateStateSet(); + return mxStateSet; +} + +OUString ScAccessibleFilterMenuItem::getImplementationName() + throw (RuntimeException) +{ + return OUString::createFromAscii("ScAccessibleFilterMenuItem"); +} + +// XAccessibleAction + +sal_Int32 ScAccessibleFilterMenuItem::getAccessibleActionCount() throw (RuntimeException) +{ + return 1; +} + +sal_Bool ScAccessibleFilterMenuItem::doAccessibleAction(sal_Int32 /*nIndex*/) + throw (IndexOutOfBoundsException, RuntimeException) +{ + mpWindow->executeMenuItem(mnMenuPos); + return true; +} + +OUString ScAccessibleFilterMenuItem::getAccessibleActionDescription(sal_Int32 /*nIndex*/) + throw (IndexOutOfBoundsException, RuntimeException) +{ + return OUString::createFromAscii("click"); +} + +Reference<XAccessibleKeyBinding> ScAccessibleFilterMenuItem::getAccessibleActionKeyBinding( + sal_Int32 /*nIndex*/) throw (IndexOutOfBoundsException, RuntimeException) +{ + return Reference<XAccessibleKeyBinding>(); +} + +Any SAL_CALL ScAccessibleFilterMenuItem::queryInterface( uno::Type const & rType ) + throw (RuntimeException) +{ + Any any = ScAccessibleContextBase::queryInterface(rType); + if (any.hasValue()) + return any; + + return ScAccessibleFilterMenuItem_BASE::queryInterface(rType); +} + +void SAL_CALL ScAccessibleFilterMenuItem::acquire() throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessibleFilterMenuItem::release() throw () +{ + ScAccessibleContextBase::release(); +} + +bool ScAccessibleFilterMenuItem::isSelected() const +{ + return mpWindow->isMenuItemSelected(mnMenuPos); +} + +bool ScAccessibleFilterMenuItem::isFocused() const +{ + return isSelected(); +} + +void ScAccessibleFilterMenuItem::setEnabled(bool bEnabled) +{ + mbEnabled = bEnabled; +} + +Rectangle ScAccessibleFilterMenuItem::GetBoundingBoxOnScreen() const + throw (RuntimeException) +{ + if (!mpWindow->IsVisible()) + return Rectangle(); + + Point aPos = mpWindow->OutputToAbsoluteScreenPixel(Point(0,0)); + Point aMenuPos; + Size aMenuSize; + mpWindow->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aPos + aMenuPos, aMenuSize); + return aRect; +} + +Rectangle ScAccessibleFilterMenuItem::GetBoundingBox() const + throw (RuntimeException) +{ + if (!mpWindow->IsVisible()) + return Rectangle(); + + Point aMenuPos; + Size aMenuSize; + mpWindow->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aMenuPos, aMenuSize); + return aRect; +} + +void ScAccessibleFilterMenuItem::updateStateSet() +{ + if (!mxStateSet.is()) + mxStateSet.set(new ScAccessibleStateSet); + + ScAccessibleStateSet* p = static_cast<ScAccessibleStateSet*>( + mxStateSet.get()); + + p->clear(); + + p->insert(ENABLED); + p->insert(FOCUSABLE); + p->insert(SELECTABLE); + p->insert(SENSITIVE); + p->insert(OPAQUE); + + if (isFocused()) + p->insert(FOCUSED); + + if (isSelected()) + p->insert(SELECTED); +} + diff --git a/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx b/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx new file mode 100644 index 000000000000..832cb37dd096 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx @@ -0,0 +1,137 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleFilterTopWindow.hxx" +#include "AccessibleFilterMenu.hxx" +#include "dpcontrol.hxx" + +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::RuntimeException; +using ::rtl::OUString; + +ScAccessibleFilterTopWindow::ScAccessibleFilterTopWindow( + const Reference<XAccessible>& rxParent, ScDPFieldPopupWindow* pWin, const OUString& rName, ScDocument* pDoc) : + ScAccessibleFilterMenu(rxParent, pWin, rName, ScMenuFloatingWindow::MENU_NOT_SELECTED, pDoc), + mpWindow(pWin), + mpDoc(pDoc) +{ + SetName(rName); +} + +ScAccessibleFilterTopWindow::~ScAccessibleFilterTopWindow() +{ +} + +// XAccessibleContext + +sal_Int32 ScAccessibleFilterTopWindow::getAccessibleChildCount() throw (RuntimeException) +{ + sal_Int32 nMenuCount = getMenuItemCount(); + return nMenuCount + 6; +} + +Reference<XAccessible> ScAccessibleFilterTopWindow::getAccessibleChild( + sal_Int32 nIndex) throw (RuntimeException, IndexOutOfBoundsException) +{ + if (nIndex >= getAccessibleChildCount()) + throw IndexOutOfBoundsException(); + + sal_Int32 nMenuCount = getMenuItemCount(); + if (nIndex < nMenuCount) + return ScAccessibleFilterMenu::getAccessibleChild(nIndex); + + nIndex -= nMenuCount; + switch (nIndex) + { + case 0: + return mxAccListBox; + case 1: + return mxAccToggleAll; + case 2: + return mxAccSingleOnBtn; + case 3: + return mxAccSingleOffBtn; + case 4: + return mxAccOkBtn; + case 5: + return mxAccCancelBtn; + default: + ; + } + + return Reference<XAccessible>(); +} + +OUString ScAccessibleFilterTopWindow::getImplementationName() throw (RuntimeException) +{ + return OUString::createFromAscii("ScAccessibleFilterTopWindow"); +} + +Reference<XAccessible> ScAccessibleFilterTopWindow::getAccessibleChildMenu() +{ + if (!mxAccMenu.is()) + mxAccMenu.set(new ScAccessibleFilterMenu(this, mpWindow, getAccessibleName(), ScMenuFloatingWindow::MENU_NOT_SELECTED, mpDoc)); + return mxAccMenu; +} + +void ScAccessibleFilterTopWindow::setAccessibleChild( + const Reference<XAccessible>& rAccessible, ChildControlType eType) +{ + switch (eType) + { + case LISTBOX: + mxAccListBox = rAccessible; + break; + case TOGGLE_ALL: + mxAccToggleAll = rAccessible; + break; + case SINGLE_ON_BTN: + mxAccSingleOnBtn = rAccessible; + break; + case SINGLE_OFF_BTN: + mxAccSingleOffBtn = rAccessible; + break; + case OK_BTN: + mxAccOkBtn = rAccessible; + break; + case CANCEL_BTN: + mxAccCancelBtn = rAccessible; + break; + } +} + diff --git a/sc/source/ui/Accessibility/AccessibleGlobal.cxx b/sc/source/ui/Accessibility/AccessibleGlobal.cxx new file mode 100644 index 000000000000..6ac7190a132b --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleGlobal.cxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleDataPilotControl.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleGlobal.hxx" + +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::std::set; + +ScAccessibleStateSet::ScAccessibleStateSet() +{ +} + +ScAccessibleStateSet::~ScAccessibleStateSet() +{ +} + +// XAccessibleStateSet + +sal_Bool SAL_CALL ScAccessibleStateSet::isEmpty() throw (RuntimeException) +{ + return maStates.empty(); +} + +sal_Bool SAL_CALL ScAccessibleStateSet::contains(sal_Int16 nState) + throw (RuntimeException) +{ + return maStates.count(nState) != 0; +} + +sal_Bool SAL_CALL ScAccessibleStateSet::containsAll( + const Sequence<sal_Int16>& aStateSet) throw (RuntimeException) +{ + sal_Int32 n = aStateSet.getLength(); + for (sal_Int32 i = 0; i < n; ++i) + { + if (!maStates.count(aStateSet[i])) + // This state is not set. + return false; + } + // All specified states are set. + return true; +} + +Sequence<sal_Int16> SAL_CALL ScAccessibleStateSet::getStates() + throw (RuntimeException) +{ + Sequence<sal_Int16> aSeq(0); + set<sal_Int16>::const_iterator itr = maStates.begin(), itrEnd = maStates.end(); + for (size_t i = 0; itr != itrEnd; ++itr, ++i) + { + aSeq.realloc(i+1); + aSeq[i] = *itr; + } + return aSeq; +} + +void ScAccessibleStateSet::insert(sal_Int16 nState) +{ + maStates.insert(nState); +} + +void ScAccessibleStateSet::clear() +{ + maStates.clear(); +} + diff --git a/sc/source/ui/Accessibility/makefile.mk b/sc/source/ui/Accessibility/makefile.mk index dfa5ac94b63f..1ef6db37e0c1 100644 --- a/sc/source/ui/Accessibility/makefile.mk +++ b/sc/source/ui/Accessibility/makefile.mk @@ -47,12 +47,16 @@ SLOFILES = \ $(SLO)$/AccessibleContextBase.obj \ $(SLO)$/AccessibleTableBase.obj \ $(SLO)$/AccessibleDocument.obj \ + $(SLO)$/AccessibleGlobal.obj \ $(SLO)$/AccessibleSpreadsheet.obj \ $(SLO)$/AccessibleCell.obj \ $(SLO)$/AccessibilityHints.obj \ $(SLO)$/AccessibleDocumentBase.obj \ $(SLO)$/AccessibleCellBase.obj \ $(SLO)$/AccessibleDocumentPagePreview.obj \ + $(SLO)$/AccessibleFilterMenu.obj \ + $(SLO)$/AccessibleFilterMenuItem.obj \ + $(SLO)$/AccessibleFilterTopWindow.obj \ $(SLO)$/AccessiblePreviewTable.obj \ $(SLO)$/AccessiblePreviewCell.obj \ $(SLO)$/AccessiblePreviewHeaderCell.obj \ @@ -68,11 +72,15 @@ EXCEPTIONSFILES= \ $(SLO)$/AccessibleContextBase.obj \ $(SLO)$/AccessibleTableBase.obj \ $(SLO)$/AccessibleDocument.obj \ + $(SLO)$/AccessibleGlobal.obj \ $(SLO)$/AccessibleSpreadsheet.obj \ $(SLO)$/AccessibleCell.obj \ $(SLO)$/AccessibleDocumentBase.obj \ $(SLO)$/AccessibleCellBase.obj \ $(SLO)$/AccessibleDocumentPagePreview.obj \ + $(SLO)$/AccessibleFilterMenu.obj \ + $(SLO)$/AccessibleFilterMenuItem.obj \ + $(SLO)$/AccessibleFilterTopWindow.obj \ $(SLO)$/AccessiblePreviewTable.obj \ $(SLO)$/AccessiblePreviewCell.obj \ $(SLO)$/AccessiblePreviewHeaderCell.obj \ diff --git a/sc/source/ui/cctrl/dpcontrol.cxx b/sc/source/ui/cctrl/dpcontrol.cxx new file mode 100644 index 000000000000..a938948e1b26 --- /dev/null +++ b/sc/source/ui/cctrl/dpcontrol.cxx @@ -0,0 +1,1419 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: document.hxx,v $ + * $Revision: 1.115.36.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +// INCLUDE --------------------------------------------------------------- + +#include "dpcontrol.hxx" +#include "dpcontrol.hrc" + +#include "vcl/outdev.hxx" +#include "vcl/settings.hxx" +#include "vcl/wintypes.hxx" +#include "vcl/decoview.hxx" +#include "strload.hxx" +#include "global.hxx" + +#include "AccessibleFilterMenu.hxx" +#include "AccessibleFilterTopWindow.hxx" + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::accessibility::XAccessible; +using ::com::sun::star::accessibility::XAccessibleContext; +using ::rtl::OUString; +using ::rtl::OUStringHash; +using ::std::vector; +using ::std::hash_map; +using ::std::auto_ptr; + +ScDPFieldButton::ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomX, const Fraction* pZoomY) : + mpOutDev(pOutDev), + mpStyle(pStyle), + mbBaseButton(true), + mbPopupButton(false), + mbHasHiddenMember(false), + mbPopupPressed(false) +{ + if (pZoomX) + maZoomX = *pZoomX; + else + maZoomX = Fraction(1, 1); + + if (pZoomY) + maZoomY = *pZoomY; + else + maZoomY = Fraction(1, 1); +} + +ScDPFieldButton::~ScDPFieldButton() +{ +} + +void ScDPFieldButton::setText(const OUString& rText) +{ + maText = rText; +} + +void ScDPFieldButton::setBoundingBox(const Point& rPos, const Size& rSize) +{ + maPos = rPos; + maSize = rSize; +} + +void ScDPFieldButton::setDrawBaseButton(bool b) +{ + mbBaseButton = b; +} + +void ScDPFieldButton::setDrawPopupButton(bool b) +{ + mbPopupButton = b; +} + +void ScDPFieldButton::setHasHiddenMember(bool b) +{ + mbHasHiddenMember = b; +} + +void ScDPFieldButton::setPopupPressed(bool b) +{ + mbPopupPressed = b; +} + +void ScDPFieldButton::draw() +{ + const long nMargin = 2; + bool bOldMapEnablaed = mpOutDev->IsMapModeEnabled(); + mpOutDev->EnableMapMode(false); + + if (mbBaseButton) + { + // Background + Rectangle aRect(maPos, maSize); + mpOutDev->SetLineColor(mpStyle->GetFaceColor()); + mpOutDev->SetFillColor(mpStyle->GetFaceColor()); + mpOutDev->DrawRect(aRect); + + // Border lines + mpOutDev->SetLineColor(mpStyle->GetLightColor()); + mpOutDev->DrawLine(Point(maPos), Point(maPos.X(), maPos.Y()+maSize.Height()-1)); + mpOutDev->DrawLine(Point(maPos), Point(maPos.X()+maSize.Width()-1, maPos.Y())); + + mpOutDev->SetLineColor(mpStyle->GetShadowColor()); + mpOutDev->DrawLine(Point(maPos.X(), maPos.Y()+maSize.Height()-1), + Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); + mpOutDev->DrawLine(Point(maPos.X()+maSize.Width()-1, maPos.Y()), + Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); + + // Field name. + Font aTextFont( mpStyle->GetLabelFont() ); + double fFontHeight = 12.0; + fFontHeight *= static_cast<double>(maZoomY.GetNumerator()) / static_cast<double>(maZoomY.GetDenominator()); + aTextFont.SetHeight(static_cast<long>(fFontHeight)); + mpOutDev->SetFont(aTextFont); + + Point aTextPos = maPos; + long nTHeight = static_cast<long>(fFontHeight); + aTextPos.setX(maPos.getX() + nMargin); + aTextPos.setY(maPos.getY() + (maSize.Height()-nTHeight)/2); + mpOutDev->DrawText(aTextPos, maText); + } + + if (mbPopupButton) + drawPopupButton(); + + mpOutDev->EnableMapMode(bOldMapEnablaed); +} + +void ScDPFieldButton::getPopupBoundingBox(Point& rPos, Size& rSize) const +{ + long nW = maSize.getWidth() / 2; + long nH = maSize.getHeight(); + if (nW > 18) + nW = 18; + if (nH > 18) + nH = 18; + + rPos.setX(maPos.getX() + maSize.getWidth() - nW); + rPos.setY(maPos.getY() + maSize.getHeight() - nH); + rSize.setWidth(nW); + rSize.setHeight(nH); +} + +bool ScDPFieldButton::isPopupButton() const +{ + return mbPopupButton; +} + +void ScDPFieldButton::drawPopupButton() +{ + Point aPos; + Size aSize; + getPopupBoundingBox(aPos, aSize); + + // Background & outer black border + mpOutDev->SetLineColor(COL_BLACK); + mpOutDev->SetFillColor(mpStyle->GetFaceColor()); + mpOutDev->DrawRect(Rectangle(aPos, aSize)); + + if (!mbPopupPressed) + { + // border lines + mpOutDev->SetLineColor(mpStyle->GetLightColor()); + mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+1), Point(aPos.X()+1, aPos.Y()+aSize.Height()-2)); + mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+1), Point(aPos.X()+aSize.Width()-2, aPos.Y()+1)); + + mpOutDev->SetLineColor(mpStyle->GetShadowColor()); + mpOutDev->DrawLine(Point(aPos.X()+1, aPos.Y()+aSize.Height()-2), + Point(aPos.X()+aSize.Width()-2, aPos.Y()+aSize.Height()-2)); + mpOutDev->DrawLine(Point(aPos.X()+aSize.Width()-2, aPos.Y()+1), + Point(aPos.X()+aSize.Width()-2, aPos.Y()+aSize.Height()-2)); + } + + // the arrowhead + Color aArrowColor = mbHasHiddenMember ? mpStyle->GetHighlightLinkColor() : mpStyle->GetButtonTextColor(); + mpOutDev->SetLineColor(aArrowColor); + mpOutDev->SetFillColor(aArrowColor); + Point aCenter(aPos.X() + (aSize.Width() >> 1), aPos.Y() + (aSize.Height() >> 1)); + Point aPos1, aPos2; + aPos1.X() = aCenter.X() - 4; + aPos2.X() = aCenter.X() + 4; + aPos1.Y() = aCenter.Y() - 3; + aPos2.Y() = aCenter.Y() - 3; + + if (mbPopupPressed) + { + aPos1.X() += 1; + aPos2.X() += 1; + aPos1.Y() += 1; + aPos2.Y() += 1; + } + + do + { + ++aPos1.X(); + --aPos2.X(); + ++aPos1.Y(); + ++aPos2.Y(); + mpOutDev->DrawLine(aPos1, aPos2); + } + while (aPos1 != aPos2); + + if (mbHasHiddenMember) + { + // tiny little box to display in presence of hidden member(s). + Point aBoxPos(aPos.X() + aSize.Width() - 5, aPos.Y() + aSize.Height() - 5); + if (mbPopupPressed) + { + aBoxPos.X() += 1; + aBoxPos.Y() += 1; + } + Size aBoxSize(3, 3); + mpOutDev->DrawRect(Rectangle(aBoxPos, aBoxSize)); + } +} + +// ============================================================================ + +ScMenuFloatingWindow::MenuItemData::MenuItemData() : + mbEnabled(true), + mpAction(static_cast<ScDPFieldPopupWindow::Action*>(NULL)), + mpSubMenuWin(static_cast<ScMenuFloatingWindow*>(NULL)) +{ +} + +// ---------------------------------------------------------------------------- + +ScMenuFloatingWindow::SubMenuItemData::SubMenuItemData(ScMenuFloatingWindow* pParent) : + mpSubMenu(NULL), + mnMenuPos(MENU_NOT_SELECTED), + mpParent(pParent) +{ + maTimer.SetTimeoutHdl( LINK(this, ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl) ); + maTimer.SetTimeout(mpParent->GetSettings().GetMouseSettings().GetMenuDelay()); +} + +void ScMenuFloatingWindow::SubMenuItemData::reset() +{ + mpSubMenu = NULL; + mnMenuPos = MENU_NOT_SELECTED; + maTimer.Stop(); +} + +IMPL_LINK( ScMenuFloatingWindow::SubMenuItemData, TimeoutHdl, void*, EMPTYARG ) +{ + mpParent->handleMenuTimeout(this); + return 0; +} + +// ---------------------------------------------------------------------------- + +size_t ScMenuFloatingWindow::MENU_NOT_SELECTED = 999; + +ScMenuFloatingWindow::ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, USHORT nMenuStackLevel) : + PopupMenuFloatingWindow(pParent), + maOpenTimer(this), + maCloseTimer(this), + maName(OUString::createFromAscii("ScMenuFloatingWindow")), + mnSelectedMenu(MENU_NOT_SELECTED), + mnClickedMenu(MENU_NOT_SELECTED), + mpDoc(pDoc), + mpParentMenu(dynamic_cast<ScMenuFloatingWindow*>(pParent)), + mpActiveSubMenu(NULL) +{ + SetMenuStackLevel(nMenuStackLevel); + + // TODO: How do we get the right font to use here ? + const sal_uInt16 nPopupFontHeight = 12; + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + maLabelFont = rStyle.GetLabelFont(); + maLabelFont.SetHeight(nPopupFontHeight); + SetFont(maLabelFont); + + SetText(OUString::createFromAscii("ScMenuFloatingWindow")); + SetPopupModeEndHdl( LINK(this, ScMenuFloatingWindow, PopupEndHdl) ); +} + +ScMenuFloatingWindow::~ScMenuFloatingWindow() +{ + EndPopupMode(); +} + +void ScMenuFloatingWindow::MouseMove(const MouseEvent& rMEvt) +{ + const Point& rPos = rMEvt.GetPosPixel(); + size_t nSelectedMenu = getEnclosingMenuItem(rPos); + setSelectedMenuItem(nSelectedMenu, true, false); + + Window::MouseMove(rMEvt); +} + +void ScMenuFloatingWindow::MouseButtonDown(const MouseEvent& rMEvt) +{ + const Point& rPos = rMEvt.GetPosPixel(); + mnClickedMenu = getEnclosingMenuItem(rPos); + Window::MouseButtonDown(rMEvt); +} + +void ScMenuFloatingWindow::MouseButtonUp(const MouseEvent& rMEvt) +{ + executeMenuItem(mnClickedMenu); + mnClickedMenu = MENU_NOT_SELECTED; + Window::MouseButtonUp(rMEvt); +} + +void ScMenuFloatingWindow::KeyInput(const KeyEvent& rKEvt) +{ + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + bool bHandled = true; + size_t nSelectedMenu = mnSelectedMenu; + size_t nLastMenuPos = maMenuItems.size() - 1; + switch (rKeyCode.GetCode()) + { + case KEY_UP: + if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == 0) + nSelectedMenu = nLastMenuPos; + else + --nSelectedMenu; + setSelectedMenuItem(nSelectedMenu, false, false); + break; + case KEY_DOWN: + if (nSelectedMenu == MENU_NOT_SELECTED || nSelectedMenu == nLastMenuPos) + nSelectedMenu = 0; + else + ++nSelectedMenu; + setSelectedMenuItem(nSelectedMenu, false, false); + break; + case KEY_LEFT: + if (mpParentMenu) + mpParentMenu->endSubMenu(this); + break; + case KEY_RIGHT: + { + if (mnSelectedMenu >= maMenuItems.size() || mnSelectedMenu == MENU_NOT_SELECTED) + break; + + const MenuItemData& rMenu = maMenuItems[mnSelectedMenu]; + if (!rMenu.mbEnabled || !rMenu.mpSubMenuWin) + break; + + maOpenTimer.mnMenuPos = mnSelectedMenu; + maOpenTimer.mpSubMenu = rMenu.mpSubMenuWin.get(); + launchSubMenu(true); + } + break; + case KEY_RETURN: + if (nSelectedMenu != MENU_NOT_SELECTED) + executeMenuItem(nSelectedMenu); + break; + default: + bHandled = false; + } + + if (!bHandled) + Window::KeyInput(rKEvt); +} + +void ScMenuFloatingWindow::Paint(const Rectangle& /*rRect*/) +{ + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + Color aBackColor = rStyle.GetMenuColor(); + Color aBorderColor = rStyle.GetShadowColor(); + + Rectangle aCtrlRect(Point(0, 0), GetOutputSizePixel()); + + // Window background + bool bNativeDrawn = true; + if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) + { + SetClipRegion(); + bNativeDrawn = DrawNativeControl( + CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, Region(aCtrlRect), CTRL_STATE_ENABLED, + ImplControlValue(), OUString()); + } + else + bNativeDrawn = false; + + if (!bNativeDrawn) + { + SetFillColor(aBackColor); + SetLineColor(aBorderColor); + DrawRect(aCtrlRect); + } + + // Menu items + SetTextColor(rStyle.GetMenuTextColor()); + drawAllMenuItems(); +} + +Reference<XAccessible> ScMenuFloatingWindow::CreateAccessible() +{ + if (!mxAccessible.is()) + { + Reference<XAccessible> xAccParent = mpParentMenu ? + mpParentMenu->GetAccessible() : GetAccessibleParentWindow()->GetAccessible(); + + mxAccessible.set(new ScAccessibleFilterMenu(xAccParent, this, maName, 999, getDoc())); + ScAccessibleFilterMenu* p = static_cast<ScAccessibleFilterMenu*>( + mxAccessible.get()); + + vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); + for (itr = itrBeg; itr != itrEnd; ++itr) + { + size_t nPos = ::std::distance(itrBeg, itr); + p->appendMenuItem(itr->maText, itr->mbEnabled, nPos); + } + } + + return mxAccessible; +} + +void ScMenuFloatingWindow::addMenuItem(const OUString& rText, bool bEnabled, Action* pAction) +{ + MenuItemData aItem; + aItem.maText = rText; + aItem.mbEnabled = bEnabled; + aItem.mpAction.reset(pAction); + maMenuItems.push_back(aItem); +} + +ScMenuFloatingWindow* ScMenuFloatingWindow::addSubMenuItem(const OUString& rText, bool bEnabled) +{ + MenuItemData aItem; + aItem.maText = rText; + aItem.mbEnabled = bEnabled; + aItem.mpSubMenuWin.reset(new ScMenuFloatingWindow(this, mpDoc, GetMenuStackLevel()+1)); + aItem.mpSubMenuWin->setName(rText); + maMenuItems.push_back(aItem); + return aItem.mpSubMenuWin.get(); +} + +void ScMenuFloatingWindow::drawMenuItem(size_t nPos) +{ + if (nPos >= maMenuItems.size()) + return; + + Point aPos; + Size aSize; + getMenuItemPosSize(nPos, aPos, aSize); + + DecorationView aDecoView(this); + long nXOffset = 5; + long nYOffset = (aSize.Height() - maLabelFont.GetHeight())/2; + DrawCtrlText(Point(aPos.X()+nXOffset, aPos.Y() + nYOffset), maMenuItems[nPos].maText, 0, STRING_LEN, + maMenuItems[nPos].mbEnabled ? TEXT_DRAW_MNEMONIC : TEXT_DRAW_DISABLE); + + if (maMenuItems[nPos].mpSubMenuWin) + { + long nFontHeight = maLabelFont.GetHeight(); + Point aMarkerPos = aPos; + aMarkerPos.Y() += aSize.Height()/2 - nFontHeight/4 + 1; + aMarkerPos.X() += aSize.Width() - nFontHeight + nFontHeight/4; + Size aMarkerSize(nFontHeight/2, nFontHeight/2); + aDecoView.DrawSymbol(Rectangle(aMarkerPos, aMarkerSize), + SYMBOL_SPIN_RIGHT, GetTextColor(), 0); + } +} + +void ScMenuFloatingWindow::drawAllMenuItems() +{ + size_t n = maMenuItems.size(); + for (size_t i = 0; i < n; ++i) + highlightMenuItem(i, i == mnSelectedMenu); +} + +const Font& ScMenuFloatingWindow::getLabelFont() const +{ + return maLabelFont; +} + +void ScMenuFloatingWindow::executeMenuItem(size_t nPos) +{ + if (nPos >= maMenuItems.size()) + return; + + if (!maMenuItems[nPos].mpAction) + // no action is defined. + return; + + maMenuItems[nPos].mpAction->execute(); + terminateAllPopupMenus(); +} + +void ScMenuFloatingWindow::setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu) +{ + if (mnSelectedMenu == nPos) + // nothing to do. + return; + + if (bEnsureSubMenu) + { + // Dismiss any child popup menu windows. + if (mnSelectedMenu < maMenuItems.size() && + maMenuItems[mnSelectedMenu].mpSubMenuWin && + maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) + { + maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); + } + + // The popup is not visible, yet a menu item is selected. The request + // most likely comes from the accessible object. Make sure this + // window, as well as all its parent windows are visible. + if (!IsVisible() && mpParentMenu) + mpParentMenu->ensureSubMenuVisible(this); + } + + selectMenuItem(mnSelectedMenu, false, bSubMenuTimer); + selectMenuItem(nPos, true, bSubMenuTimer); + mnSelectedMenu = nPos; + + fireMenuHighlightedEvent(); +} + +size_t ScMenuFloatingWindow::getSelectedMenuItem() const +{ + return mnSelectedMenu; +} + +void ScMenuFloatingWindow::handleMenuTimeout(SubMenuItemData* pTimer) +{ + if (pTimer == &maOpenTimer) + { + // Close any open submenu immediately. + if (maCloseTimer.mpSubMenu) + { + maCloseTimer.mpSubMenu->EndPopupMode(); + maCloseTimer.mpSubMenu = NULL; + maCloseTimer.maTimer.Stop(); + } + + launchSubMenu(false); + } + else if (pTimer == &maCloseTimer) + { + // end submenu. + if (maCloseTimer.mpSubMenu) + { + maOpenTimer.mpSubMenu = NULL; + + maCloseTimer.mpSubMenu->EndPopupMode(); + maCloseTimer.mpSubMenu = NULL; + + highlightMenuItem(maOpenTimer.mnMenuPos, false); + maOpenTimer.mnMenuPos = MENU_NOT_SELECTED; + } + } +} + +void ScMenuFloatingWindow::queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu) +{ + if (!pMenu) + return; + + // Set the submenu on launch queue. + if (maOpenTimer.mpSubMenu) + { + if (maOpenTimer.mpSubMenu == pMenu) + { + if (pMenu == maCloseTimer.mpSubMenu) + maCloseTimer.reset(); + return; + } + + // new submenu is being requested. + queueCloseSubMenu(); + } + + maOpenTimer.mpSubMenu = pMenu; + maOpenTimer.mnMenuPos = nPos; + maOpenTimer.maTimer.Start(); +} + +void ScMenuFloatingWindow::queueCloseSubMenu() +{ + if (!maOpenTimer.mpSubMenu) + // There is no submenu to close. + return; + + // Stop any submenu on queue for opening. + maOpenTimer.maTimer.Stop(); + + maCloseTimer.mpSubMenu = maOpenTimer.mpSubMenu; + maCloseTimer.mnMenuPos = maOpenTimer.mnMenuPos; + maCloseTimer.maTimer.Start(); +} + +void ScMenuFloatingWindow::launchSubMenu(bool bSetMenuPos) +{ + Point aPos; + Size aSize; + getMenuItemPosSize(maOpenTimer.mnMenuPos, aPos, aSize); + ScMenuFloatingWindow* pSubMenu = maOpenTimer.mpSubMenu; + + if (!pSubMenu) + return; + + sal_uInt32 nOldFlags = GetPopupModeFlags(); + SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); + pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. + pSubMenu->StartPopupMode( + Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); + pSubMenu->AddPopupModeWindow(this); + if (bSetMenuPos) + pSubMenu->setSelectedMenuItem(0, false, false); // select menu item after the popup becomes fully visible. + SetPopupModeFlags(nOldFlags); +} + +void ScMenuFloatingWindow::endSubMenu(ScMenuFloatingWindow* pSubMenu) +{ + if (!pSubMenu) + return; + + pSubMenu->EndPopupMode(); + maOpenTimer.reset(); + + size_t nMenuPos = getSubMenuPos(pSubMenu); + if (nMenuPos != MENU_NOT_SELECTED) + { + highlightMenuItem(nMenuPos, true); + mnSelectedMenu = nMenuPos; + fireMenuHighlightedEvent(); + } +} + +void ScMenuFloatingWindow::fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const +{ + vector<MenuItemData>::const_iterator itr, itrBeg = maMenuItems.begin(), itrEnd = maMenuItems.end(); + for (itr = itrBeg; itr != itrEnd; ++itr) + { + size_t nPos = ::std::distance(itrBeg, itr); + pAccMenu->appendMenuItem(itr->maText, itr->mbEnabled, nPos); + } +} + +ScDocument* ScMenuFloatingWindow::getDoc() +{ + return mpDoc; +} + +void ScMenuFloatingWindow::resizeToFitMenuItems() +{ + if (maMenuItems.empty()) + return; + + vector<MenuItemData>::const_iterator itr = maMenuItems.begin(), itrEnd = maMenuItems.end(); + long nTextWidth = 0; + for (; itr != itrEnd; ++itr) + nTextWidth = ::std::max(GetTextWidth(itr->maText), nTextWidth); + + size_t nLastPos = maMenuItems.size()-1; + Point aPos; + Size aSize; + getMenuItemPosSize(nLastPos, aPos, aSize); + aPos.X() += nTextWidth + 15; + aPos.Y() += aSize.Height() + 5; + SetOutputSizePixel(Size(aPos.X(), aPos.Y())); +} + +void ScMenuFloatingWindow::selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer) +{ + if (nPos >= maMenuItems.size() || nPos == MENU_NOT_SELECTED) + { + queueCloseSubMenu(); + return; + } + + if (!maMenuItems[nPos].mbEnabled) + { + queueCloseSubMenu(); + return; + } + + highlightMenuItem(nPos, bSelected); + + if (bSelected) + { + if (mpParentMenu) + mpParentMenu->setSubMenuFocused(this); + + if (bSubMenuTimer) + { + if (maMenuItems[nPos].mpSubMenuWin) + { + ScMenuFloatingWindow* pSubMenu = maMenuItems[nPos].mpSubMenuWin.get(); + queueLaunchSubMenu(nPos, pSubMenu); + } + else + queueCloseSubMenu(); + } + } +} + +void ScMenuFloatingWindow::clearSelectedMenuItem() +{ + selectMenuItem(mnSelectedMenu, false, false); + mnSelectedMenu = MENU_NOT_SELECTED; +} + +ScMenuFloatingWindow* ScMenuFloatingWindow::getSubMenuWindow(size_t nPos) const +{ + if (maMenuItems.size() <= nPos) + return NULL; + + return maMenuItems[nPos].mpSubMenuWin.get(); +} + +size_t ScMenuFloatingWindow::getMenuItemCount() const +{ + return maMenuItems.size(); +} + +OUString ScMenuFloatingWindow::getMenuItemName(size_t nPos) const +{ + if (maMenuItems.size() <= nPos) + return ScGlobal::GetEmptyString(); + + return maMenuItems[nPos].maText; +} + +bool ScMenuFloatingWindow::isMenuItemEnabled(size_t nPos) const +{ + if (maMenuItems.size() <= nPos) + return false; + + return maMenuItems[nPos].mbEnabled; +} + +bool ScMenuFloatingWindow::isMenuItemSelected(size_t nPos) const +{ + return nPos == mnSelectedMenu; +} + +void ScMenuFloatingWindow::setName(const OUString& rName) +{ + maName = rName; +} + +const OUString& ScMenuFloatingWindow::getName() const +{ + return maName; +} + +void ScMenuFloatingWindow::highlightMenuItem(size_t nPos, bool bSelected) +{ + if (nPos == MENU_NOT_SELECTED) + return; + + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + Color aBackColor = rStyle.GetMenuColor(); + SetFillColor(aBackColor); + SetLineColor(aBackColor); + + Point aPos; + Size aSize; + getMenuItemPosSize(nPos, aPos, aSize); + Region aRegion(Rectangle(aPos,aSize)); + + if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_ENTIRE_CONTROL)) + { + Push(PUSH_CLIPREGION); + IntersectClipRegion(Rectangle(aPos, aSize)); + Rectangle aCtrlRect(Point(0,0), GetOutputSizePixel()); + DrawNativeControl( + CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, Region(aCtrlRect), CTRL_STATE_ENABLED, + ImplControlValue(), OUString()); + + Pop(); + } + + bool bNativeDrawn = true; + if (IsNativeControlSupported(CTRL_MENU_POPUP, PART_MENU_ITEM)) + { + ControlState nState = bSelected ? CTRL_STATE_SELECTED : 0; + if (maMenuItems[nPos].mbEnabled) + nState |= CTRL_STATE_ENABLED; + bNativeDrawn = DrawNativeControl( + CTRL_MENU_POPUP, PART_MENU_ITEM, aRegion, nState, ImplControlValue(), OUString()); + } + else + bNativeDrawn = false; + + if (!bNativeDrawn) + { + if (bSelected) + { + aBackColor = rStyle.GetMenuHighlightColor(); + SetFillColor(aBackColor); + SetLineColor(aBackColor); + } + DrawRect(Rectangle(aPos,aSize)); + } + + Color aTextColor = bSelected ? rStyle.GetMenuHighlightTextColor() : rStyle.GetMenuTextColor(); + SetTextColor(aTextColor); + drawMenuItem(nPos); +} + +void ScMenuFloatingWindow::getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const +{ + const sal_uInt16 nLeftMargin = 5; + const sal_uInt16 nTopMargin = 5; + const sal_uInt16 nMenuItemHeight = static_cast< sal_uInt16 >( maLabelFont.GetHeight()*1.8 ); + + Size aWndSize = GetSizePixel(); + + Point aPos1(nLeftMargin, nTopMargin); + Size aSize1(aWndSize.Width() - nLeftMargin*2, nMenuItemHeight); + + rPos = aPos1; + rPos.Y() += aSize1.Height()*nPos; + rSize = aSize1; +} + +ScMenuFloatingWindow* ScMenuFloatingWindow::getParentMenuWindow() const +{ + return mpParentMenu; +} + +size_t ScMenuFloatingWindow::getEnclosingMenuItem(const Point& rPos) const +{ + size_t n = maMenuItems.size(); + for (size_t i = 0; i < n; ++i) + { + Point aPos; + Size aSize; + getMenuItemPosSize(i, aPos, aSize); + Rectangle aRect(aPos, aSize); + if (aRect.IsInside(rPos)) + return i; + } + return MENU_NOT_SELECTED; +} + +size_t ScMenuFloatingWindow::getSubMenuPos(ScMenuFloatingWindow* pSubMenu) +{ + size_t n = maMenuItems.size(); + for (size_t i = 0; i < n; ++i) + { + if (maMenuItems[i].mpSubMenuWin.get() == pSubMenu) + return i; + } + return MENU_NOT_SELECTED; +} + +void ScMenuFloatingWindow::fireMenuHighlightedEvent() +{ + if (mnSelectedMenu == MENU_NOT_SELECTED) + return; + + if (!mxAccessible.is()) + return; + + Reference<XAccessibleContext> xAccCxt = mxAccessible->getAccessibleContext(); + if (!xAccCxt.is()) + return; + + Reference<XAccessible> xAccMenu = xAccCxt->getAccessibleChild(mnSelectedMenu); + if (!xAccMenu.is()) + return; + + VclAccessibleEvent aEvent(VCLEVENT_MENU_HIGHLIGHT, xAccMenu); + FireVclEvent(&aEvent); +} + +void ScMenuFloatingWindow::setSubMenuFocused(ScMenuFloatingWindow* pSubMenu) +{ + maCloseTimer.reset(); + size_t nMenuPos = getSubMenuPos(pSubMenu); + if (mnSelectedMenu != nMenuPos) + { + highlightMenuItem(nMenuPos, true); + mnSelectedMenu = nMenuPos; + } +} + +void ScMenuFloatingWindow::ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu) +{ + if (mpParentMenu) + mpParentMenu->ensureSubMenuVisible(this); + + if (pSubMenu->IsVisible()) + return; + + // Find the menu position of the submenu. + size_t nMenuPos = getSubMenuPos(pSubMenu); + if (nMenuPos != MENU_NOT_SELECTED) + { + setSelectedMenuItem(nMenuPos, false, false); + + Point aPos; + Size aSize; + getMenuItemPosSize(nMenuPos, aPos, aSize); + + sal_uInt32 nOldFlags = GetPopupModeFlags(); + SetPopupModeFlags(nOldFlags | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE); + pSubMenu->resizeToFitMenuItems(); // set the size before launching the popup to get it positioned correctly. + pSubMenu->StartPopupMode( + Rectangle(aPos,aSize), (FLOATWIN_POPUPMODE_RIGHT | FLOATWIN_POPUPMODE_GRABFOCUS)); + pSubMenu->AddPopupModeWindow(this); + SetPopupModeFlags(nOldFlags); + } +} + +void ScMenuFloatingWindow::ensureSubMenuNotVisible() +{ + if (mnSelectedMenu <= maMenuItems.size() && + maMenuItems[mnSelectedMenu].mpSubMenuWin && + maMenuItems[mnSelectedMenu].mpSubMenuWin->IsVisible()) + { + maMenuItems[mnSelectedMenu].mpSubMenuWin->ensureSubMenuNotVisible(); + } + + EndPopupMode(); +} + +void ScMenuFloatingWindow::terminateAllPopupMenus() +{ + EndPopupMode(); + if (mpParentMenu) + mpParentMenu->terminateAllPopupMenus(); +} + +IMPL_LINK( ScMenuFloatingWindow, PopupEndHdl, void*, EMPTYARG ) +{ + clearSelectedMenuItem(); + return 0; +} + +// ============================================================================ + +ScDPFieldPopupWindow::Member::Member() : + mbVisible(true) +{ +} + +// ---------------------------------------------------------------------------- + +ScDPFieldPopupWindow::CancelButton::CancelButton(ScDPFieldPopupWindow* pParent) : + ::CancelButton(pParent), mpParent(pParent) {} + +void ScDPFieldPopupWindow::CancelButton::Click() +{ + mpParent->EndPopupMode(); + ::CancelButton::Click(); +} + +// ---------------------------------------------------------------------------- + +ScDPFieldPopupWindow::ScDPFieldPopupWindow(Window* pParent, ScDocument* pDoc) : + ScMenuFloatingWindow(pParent, pDoc), + maChecks(this, 0), + maChkToggleAll(this, 0), + maBtnSelectSingle (this, 0), + maBtnUnselectSingle(this, 0), + maBtnOk(this), + maBtnCancel(this), + mnCurTabStop(0), + mpExtendedData(NULL), + mpOKAction(NULL), + maWndSize(160, 330), + mePrevToggleAllState(STATE_DONTKNOW) +{ + maTabStopCtrls.reserve(7); + maTabStopCtrls.push_back(this); + maTabStopCtrls.push_back(&maChecks); + maTabStopCtrls.push_back(&maChkToggleAll); + maTabStopCtrls.push_back(&maBtnSelectSingle); + maTabStopCtrls.push_back(&maBtnUnselectSingle); + maTabStopCtrls.push_back(&maBtnOk); + maTabStopCtrls.push_back(&maBtnCancel); + + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + + Point aPos; + Size aSize; + getSectionPosSize(aPos, aSize, WHOLE); + SetOutputSizePixel(aSize); + Size aOutSize = GetOutputSizePixel(); + + getSectionPosSize(aPos, aSize, BTN_OK); + maBtnOk.SetPosSizePixel(aPos, aSize); + maBtnOk.SetFont(getLabelFont()); + maBtnOk.SetClickHdl( LINK(this, ScDPFieldPopupWindow, ButtonHdl) ); + maBtnOk.Show(); + + getSectionPosSize(aPos, aSize, BTN_CANCEL); + maBtnCancel.SetPosSizePixel(aPos, aSize); + maBtnCancel.SetFont(getLabelFont()); + maBtnCancel.Show(); + + getSectionPosSize(aPos, aSize, LISTBOX_AREA_INNER); + maChecks.SetPosSizePixel(aPos, aSize); + maChecks.SetFont(getLabelFont()); + maChecks.SetCheckButtonHdl( LINK(this, ScDPFieldPopupWindow, CheckHdl) ); + maChecks.Show(); + + getSectionPosSize(aPos, aSize, CHECK_TOGGLE_ALL); + maChkToggleAll.SetPosSizePixel(aPos, aSize); + maChkToggleAll.SetFont(getLabelFont()); + maChkToggleAll.SetText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_TOGGLE_ALL).GetString()); + maChkToggleAll.SetControlBackground(rStyle.GetMenuColor()); + maChkToggleAll.SetClickHdl( LINK(this, ScDPFieldPopupWindow, TriStateHdl) ); + maChkToggleAll.Show(); + + getSectionPosSize(aPos, aSize, BTN_SINGLE_SELECT); + maBtnSelectSingle.SetPosSizePixel(aPos, aSize); + maBtnSelectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_SELECT_CURRENT).GetString()); + maBtnSelectSingle.SetModeImage(Image(ScResId(RID_IMG_SELECT_CURRENT)), BMP_COLOR_NORMAL); + maBtnSelectSingle.SetClickHdl( LINK(this, ScDPFieldPopupWindow, ButtonHdl) ); + maBtnSelectSingle.Show(); + + getSectionPosSize(aPos, aSize, BTN_SINGLE_UNSELECT); + maBtnUnselectSingle.SetPosSizePixel(aPos, aSize); + maBtnUnselectSingle.SetQuickHelpText(ScRscStrLoader(RID_POPUP_FILTER, STR_BTN_UNSELECT_CURRENT).GetString()); + maBtnUnselectSingle.SetModeImage(Image(ScResId(RID_IMG_UNSELECT_CURRENT)), BMP_COLOR_NORMAL); + maBtnUnselectSingle.SetClickHdl( LINK(this, ScDPFieldPopupWindow, ButtonHdl) ); + maBtnUnselectSingle.Show(); +} + +ScDPFieldPopupWindow::~ScDPFieldPopupWindow() +{ +} + +void ScDPFieldPopupWindow::getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const +{ + // constant parameters. + const sal_uInt16 nListBoxMargin = 5; // horizontal distance from the side of the dialog to the listbox border. + const sal_uInt16 nListBoxInnerPadding = 5; + const sal_uInt16 nTopMargin = 5; + const sal_uInt16 nMenuHeight = 60; + const sal_uInt16 nSingleItemBtnAreaHeight = 32; // height of the middle area below the list box where the single-action buttons are. + const sal_uInt16 nBottomBtnAreaHeight = 50; // height of the bottom area where the OK and Cancel buttons are. + const sal_uInt16 nBtnWidth = 60; + const sal_uInt16 nLabelHeight = static_cast< sal_uInt16 >( getLabelFont().GetHeight() ); + const sal_uInt16 nBtnHeight = nLabelHeight*2; + const sal_uInt16 nBottomMargin = 10; + const sal_uInt16 nMenuListMargin = 20; + + // parameters calculated from constants. + const sal_uInt16 nListBoxWidth = static_cast< sal_uInt16 >( maWndSize.Width() - nListBoxMargin*2 ); + const sal_uInt16 nListBoxHeight = static_cast< sal_uInt16 >( maWndSize.Height() - nTopMargin - nMenuHeight - + nMenuListMargin - nSingleItemBtnAreaHeight - nBottomBtnAreaHeight ); + + const sal_uInt16 nSingleBtnAreaY = nTopMargin + nMenuHeight + nListBoxHeight + nMenuListMargin - 1; + + switch (eType) + { + case WHOLE: + { + rPos = Point(0, 0); + rSize = maWndSize; + } + break; + case LISTBOX_AREA_OUTER: + { + rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); + rSize = Size(nListBoxWidth, nListBoxHeight); + } + break; + case LISTBOX_AREA_INNER: + { + rPos = Point(nListBoxMargin, nTopMargin + nMenuHeight + nMenuListMargin); + rPos.X() += nListBoxInnerPadding; + rPos.Y() += nListBoxInnerPadding; + + rSize = Size(nListBoxWidth, nListBoxHeight); + rSize.Width() -= nListBoxInnerPadding*2; + rSize.Height() -= nListBoxInnerPadding*2; + } + break; + case SINGLE_BTN_AREA: + { + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rSize = Size(nListBoxWidth, nSingleItemBtnAreaHeight); + } + break; + case CHECK_TOGGLE_ALL: + { + long h = nLabelHeight*3/2; // check box height is heuristically 150% of the text height. + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rPos.X() += 5; + rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; + rSize = Size(70, h); + } + break; + case BTN_SINGLE_SELECT: + { + long h = 26; + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rPos.X() += 75; + rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; + rSize = Size(h, h); + } + break; + case BTN_SINGLE_UNSELECT: + { + long h = 26; + rPos = Point(nListBoxMargin, nSingleBtnAreaY); + rPos.X() += 75 + h + 10; + rPos.Y() += (nSingleItemBtnAreaHeight - h)/2; + rSize = Size(h, h); + } + break; + case BTN_OK: + { + long x = (maWndSize.Width() - nBtnWidth*2)/3; + long y = maWndSize.Height() - nBottomMargin - nBtnHeight; + rPos = Point(x, y); + rSize = Size(nBtnWidth, nBtnHeight); + } + break; + case BTN_CANCEL: + { + long x = (maWndSize.Width() - nBtnWidth*2)/3*2 + nBtnWidth; + long y = maWndSize.Height() - nBottomMargin - nBtnHeight; + rPos = Point(x, y); + rSize = Size(nBtnWidth, nBtnHeight); + } + break; + default: + ; + } +} + +void ScDPFieldPopupWindow::setAllMemberState(bool bSet) +{ + size_t n = maMembers.size(); + for (size_t i = 0; i < n; ++i) + maChecks.CheckEntryPos(static_cast< USHORT >( i ), bSet); +} + +void ScDPFieldPopupWindow::selectCurrentMemberOnly(bool bSet) +{ + setAllMemberState(!bSet); + sal_uInt16 nSelected = maChecks.GetSelectEntryPos(); + maChecks.CheckEntryPos(nSelected, bSet); +} + +void ScDPFieldPopupWindow::cycleFocus(bool bReverse) +{ + maTabStopCtrls[mnCurTabStop]->SetFakeFocus(false); + maTabStopCtrls[mnCurTabStop]->LoseFocus(); + if (mnCurTabStop == 0) + clearSelectedMenuItem(); + + if (bReverse) + { + if (mnCurTabStop > 0) + --mnCurTabStop; + else + mnCurTabStop = maTabStopCtrls.size() - 1; + } + else + { + ++mnCurTabStop; + if (mnCurTabStop >= maTabStopCtrls.size()) + mnCurTabStop = 0; + } + maTabStopCtrls[mnCurTabStop]->SetFakeFocus(true); + maTabStopCtrls[mnCurTabStop]->GrabFocus(); +} + +IMPL_LINK( ScDPFieldPopupWindow, ButtonHdl, Button*, pBtn ) +{ + if (pBtn == &maBtnOk) + close(true); + else if (pBtn == &maBtnSelectSingle) + { + selectCurrentMemberOnly(true); + CheckHdl(&maChecks); + } + else if (pBtn == &maBtnUnselectSingle) + { + selectCurrentMemberOnly(false); + CheckHdl(&maChecks); + } + return 0; +} + +IMPL_LINK( ScDPFieldPopupWindow, TriStateHdl, TriStateBox*, EMPTYARG ) +{ + switch (mePrevToggleAllState) + { + case STATE_NOCHECK: + maChkToggleAll.SetState(STATE_CHECK); + setAllMemberState(true); + break; + case STATE_CHECK: + maChkToggleAll.SetState(STATE_NOCHECK); + setAllMemberState(false); + break; + case STATE_DONTKNOW: + default: + maChkToggleAll.SetState(STATE_CHECK); + setAllMemberState(true); + break; + } + + mePrevToggleAllState = maChkToggleAll.GetState(); + return 0; +} + +IMPL_LINK( ScDPFieldPopupWindow, CheckHdl, SvTreeListBox*, pChecks ) +{ + if (pChecks != &maChecks) + return 0; + + size_t nNumChecked = maChecks.GetCheckedEntryCount(); + if (nNumChecked == maMembers.size()) + // all members visible + maChkToggleAll.SetState(STATE_CHECK); + else if (nNumChecked == 0) + // no members visible + maChkToggleAll.SetState(STATE_NOCHECK); + else + maChkToggleAll.SetState(STATE_DONTKNOW); + + mePrevToggleAllState = maChkToggleAll.GetState(); + return 0; +} + +void ScDPFieldPopupWindow::MouseMove(const MouseEvent& rMEvt) +{ + ScMenuFloatingWindow::MouseMove(rMEvt); + + size_t nSelectedMenu = getSelectedMenuItem(); + if (nSelectedMenu == MENU_NOT_SELECTED) + queueCloseSubMenu(); +} + +long ScDPFieldPopupWindow::Notify(NotifyEvent& rNEvt) +{ + switch (rNEvt.GetType()) + { + case EVENT_KEYUP: + { + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + const KeyCode& rCode = pKeyEvent->GetKeyCode(); + bool bShift = rCode.IsShift(); + if (rCode.GetCode() == KEY_TAB) + { + cycleFocus(bShift); + return true; + } + } + break; + } + return ScMenuFloatingWindow::Notify(rNEvt); +} + +void ScDPFieldPopupWindow::Paint(const Rectangle& rRect) +{ + ScMenuFloatingWindow::Paint(rRect); + + const StyleSettings& rStyle = GetSettings().GetStyleSettings(); + Color aMemberBackColor = rStyle.GetFieldColor(); + Color aBorderColor = rStyle.GetShadowColor(); + + Point aPos; + Size aSize; + getSectionPosSize(aPos, aSize, LISTBOX_AREA_OUTER); + + // Member list box background + SetFillColor(aMemberBackColor); + SetLineColor(aBorderColor); + DrawRect(Rectangle(aPos,aSize)); + + // Single-action button box + getSectionPosSize(aPos, aSize, SINGLE_BTN_AREA); + SetFillColor(rStyle.GetMenuColor()); + DrawRect(Rectangle(aPos,aSize)); +} + +Window* ScDPFieldPopupWindow::GetPreferredKeyInputWindow() +{ + return maTabStopCtrls[mnCurTabStop]; +} + +Reference<XAccessible> ScDPFieldPopupWindow::CreateAccessible() +{ + if (!mxAccessible.is()) + { + mxAccessible.set(new ScAccessibleFilterTopWindow( + GetAccessibleParentWindow()->GetAccessible(), this, getName(), getDoc())); + ScAccessibleFilterTopWindow* pAccTop = static_cast<ScAccessibleFilterTopWindow*>(mxAccessible.get()); + fillMenuItemsToAccessible(pAccTop); + + pAccTop->setAccessibleChild( + maChecks.CreateAccessible(), ScAccessibleFilterTopWindow::LISTBOX); + pAccTop->setAccessibleChild( + maChkToggleAll.CreateAccessible(), ScAccessibleFilterTopWindow::TOGGLE_ALL); + pAccTop->setAccessibleChild( + maBtnSelectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_ON_BTN); + pAccTop->setAccessibleChild( + maBtnUnselectSingle.CreateAccessible(), ScAccessibleFilterTopWindow::SINGLE_OFF_BTN); + pAccTop->setAccessibleChild( + maBtnOk.CreateAccessible(), ScAccessibleFilterTopWindow::OK_BTN); + pAccTop->setAccessibleChild( + maBtnCancel.CreateAccessible(), ScAccessibleFilterTopWindow::CANCEL_BTN); + } + + return mxAccessible; +} + +void ScDPFieldPopupWindow::setMemberSize(size_t n) +{ + maMembers.reserve(n); +} + +void ScDPFieldPopupWindow::addMember(const OUString& rName, bool bVisible) +{ + Member aMember; + aMember.maName = rName; + aMember.mbVisible = bVisible; + maMembers.push_back(aMember); +} + +void ScDPFieldPopupWindow::initMembers() +{ + size_t n = maMembers.size(); + size_t nVisMemCount = 0; + for (size_t i = 0; i < n; ++i) + { + maChecks.InsertEntry(maMembers[i].maName); + maChecks.CheckEntryPos(static_cast< USHORT >( i ), maMembers[i].mbVisible); + if (maMembers[i].mbVisible) + ++nVisMemCount; + } + if (nVisMemCount == n) + { + // all members visible + maChkToggleAll.SetState(STATE_CHECK); + mePrevToggleAllState = STATE_CHECK; + } + else if (nVisMemCount == 0) + { + // no members visible + maChkToggleAll.SetState(STATE_NOCHECK); + mePrevToggleAllState = STATE_NOCHECK; + } + else + { + maChkToggleAll.SetState(STATE_DONTKNOW); + mePrevToggleAllState = STATE_DONTKNOW; + } +} + +const Size& ScDPFieldPopupWindow::getWindowSize() const +{ + return maWndSize; +} + +void ScDPFieldPopupWindow::getResult(hash_map<OUString, bool, OUStringHash>& rResult) +{ + typedef hash_map<OUString, bool, OUStringHash> ResultMap; + ResultMap aResult; + size_t n = maMembers.size(); + for (size_t i = 0; i < n; ++i) + { + bool bState = maChecks.IsChecked(static_cast< USHORT >( i )); + aResult.insert(ResultMap::value_type(maMembers[i].maName, bState)); + } + rResult.swap(aResult); +} + +void ScDPFieldPopupWindow::close(bool bOK) +{ + if (bOK && mpOKAction.get()) + mpOKAction->execute(); + + EndPopupMode(); +} + +void ScDPFieldPopupWindow::setExtendedData(ExtendedData* p) +{ + mpExtendedData.reset(p); +} + +ScDPFieldPopupWindow::ExtendedData* ScDPFieldPopupWindow::getExtendedData() +{ + return mpExtendedData.get(); +} + +void ScDPFieldPopupWindow::setOKAction(Action* p) +{ + mpOKAction.reset(p); +} + diff --git a/sc/source/ui/cctrl/dpcontrol.src b/sc/source/ui/cctrl/dpcontrol.src new file mode 100644 index 000000000000..31cbb62085e5 --- /dev/null +++ b/sc/source/ui/cctrl/dpcontrol.src @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: globstr.src,v $ + * $Revision: 1.74.96.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "dpcontrol.hrc" + +Resource RID_POPUP_FILTER +{ + String STR_MENU_SORT_ASC + { + Text [ en-US ] = "Sort Ascending" ; + }; + + String STR_MENU_SORT_DESC + { + Text [ en-US ] = "Sort Descending" ; + }; + + String STR_MENU_SORT_CUSTOM + { + Text [ en-US ] = "Custom Sort" ; + }; + + String STR_BTN_TOGGLE_ALL + { + Text [ en-US ] = "All" ; + }; + + String STR_BTN_SELECT_CURRENT + { + Text [ en-US ] = "Show only the current item." ; + }; + + String STR_BTN_UNSELECT_CURRENT + { + Text [ en-US ] = "Hide only the current item." ; + }; +}; + +Image RID_IMG_SELECT_CURRENT +{ + ImageBitmap = Bitmap + { + File = "popup_select_current.png"; + }; + MaskColor = STD_MASKCOLOR; +}; + +Image RID_IMG_UNSELECT_CURRENT +{ + ImageBitmap = Bitmap + { + File = "popup_unselect_current.png"; + }; + MaskColor = STD_MASKCOLOR; +}; diff --git a/sc/source/ui/cctrl/makefile.mk b/sc/source/ui/cctrl/makefile.mk index e7b96afd7b9a..541a90cc4347 100644 --- a/sc/source/ui/cctrl/makefile.mk +++ b/sc/source/ui/cctrl/makefile.mk @@ -45,22 +45,30 @@ LIBTARGET=NO # --- Files -------------------------------------------------------- EXCEPTIONSFILES= \ - $(SLO)$/tbzoomsliderctrl.obj + $(SLO)$/tbzoomsliderctrl.obj \ + $(SLO)$/dpcontrol.obj SLOFILES = \ $(SLO)$/popmenu.obj \ $(SLO)$/tbinsert.obj \ $(SLO)$/cbuttonw.obj \ + $(SLO)$/dpcontrol.obj \ $(SLO)$/editfield.obj \ $(EXCEPTIONSFILES) +SRS1NAME=$(TARGET) +SRC1FILES = \ + dpcontrol.src + LIB1TARGET=$(SLB)$/$(TARGET).lib LIB1OBJFILES= \ $(SLO)$/popmenu.obj \ $(SLO)$/tbinsert.obj \ $(SLO)$/cbuttonw.obj \ + $(SLO)$/dpcontrol.obj \ $(SLO)$/tbzoomsliderctrl.obj + # --- Tagets ------------------------------------------------------- .INCLUDE : target.mk diff --git a/sc/source/ui/dbgui/makefile.mk b/sc/source/ui/dbgui/makefile.mk index b495b5eabcc9..9ff21b6c4d08 100644 --- a/sc/source/ui/dbgui/makefile.mk +++ b/sc/source/ui/dbgui/makefile.mk @@ -80,6 +80,7 @@ EXCEPTIONSFILES= \ $(SLO)$/csvsplits.obj \ $(SLO)$/csvtablebox.obj \ $(SLO)$/fieldwnd.obj \ + $(SLO)$/pvfundlg.obj \ $(SLO)$/pvlaydlg.obj \ $(SLO)$/dapidata.obj \ $(SLO)$/validate.obj diff --git a/sc/source/ui/dbgui/pvfundlg.cxx b/sc/source/ui/dbgui/pvfundlg.cxx index d44791ff6972..30ee1a44d384 100644 --- a/sc/source/ui/dbgui/pvfundlg.cxx +++ b/sc/source/ui/dbgui/pvfundlg.cxx @@ -48,12 +48,15 @@ #include "pvfundlg.hrc" #include "globstr.hrc" +#include <vector> + // ============================================================================ using namespace ::com::sun::star::sheet; using ::rtl::OUString; using ::com::sun::star::uno::Sequence; +using ::std::vector; // ============================================================================ @@ -86,6 +89,25 @@ bool lclFillListBox( ListBoxType& rLBox, const Sequence< OUString >& rStrings, U return bEmpty; } +template< typename ListBoxType > +bool lclFillListBox( ListBoxType& rLBox, const vector<ScDPLabelData::Member>& rMembers, USHORT nEmptyPos = LISTBOX_APPEND ) +{ + bool bEmpty = false; + vector<ScDPLabelData::Member>::const_iterator itr = rMembers.begin(), itrEnd = rMembers.end(); + for (; itr != itrEnd; ++itr) + { + OUString aName = itr->getDisplayName(); + if (aName.getLength()) + rLBox.InsertEntry(aName); + else + { + rLBox.InsertEntry(ScGlobal::GetRscString(STR_EMPTYDATA), nEmptyPos); + bEmpty = true; + } + } + return bEmpty; +} + /** Searches for a listbox entry, starts search at specified position. */ USHORT lclFindListBoxEntry( const ListBox& rLBox, const String& rEntry, USHORT nStartPos ) { @@ -253,7 +275,7 @@ void ScDPFunctionDlg::Init( const ScDPLabelData& rLabelData, const ScDPFuncData& maLbFunc.SetSelection( nFuncMask ); // field name - maFtName.SetText( rLabelData.maName ); + maFtName.SetText(rLabelData.getDisplayName()); // "More button" controls maBtnMore.AddWindow( &maFlDisplay ); @@ -271,7 +293,7 @@ void ScDPFunctionDlg::Init( const ScDPLabelData& rLabelData, const ScDPFuncData& // base field list box for( ScDPLabelDataVec::const_iterator aIt = mrLabelVec.begin(), aEnd = mrLabelVec.end(); aIt != aEnd; ++aIt ) - maLbBaseField.InsertEntry( aIt->maName ); + maLbBaseField.InsertEntry(aIt->getDisplayName()); // base item list box maLbBaseItem.SetSeparatorPos( SC_BASEITEM_USER_POS - 1 ); @@ -414,8 +436,6 @@ void ScDPSubtotalDlg::FillLabelData( ScDPLabelData& rLabelData ) const rLabelData.mnUsedHier = maLabelData.mnUsedHier; rLabelData.mbShowAll = maCbShowAll.IsChecked(); rLabelData.maMembers = maLabelData.maMembers; - rLabelData.maVisible = maLabelData.maVisible; - rLabelData.maShowDet = maLabelData.maShowDet; rLabelData.maSortInfo = maLabelData.maSortInfo; rLabelData.maLayoutInfo = maLabelData.maLayoutInfo; rLabelData.maShowInfo = maLabelData.maShowInfo; @@ -424,7 +444,7 @@ void ScDPSubtotalDlg::FillLabelData( ScDPLabelData& rLabelData ) const void ScDPSubtotalDlg::Init( const ScDPLabelData& rLabelData, const ScDPFuncData& rFuncData ) { // field name - maFtName.SetText( rLabelData.maName ); + maFtName.SetText(rLabelData.getDisplayName()); // radio buttons maRbNone.SetClickHdl( LINK( this, ScDPSubtotalDlg, RadioClickHdl ) ); @@ -547,9 +567,8 @@ void ScDPSubtotalOptDlg::FillLabelData( ScDPLabelData& rLabelData ) const rLabelData.maMembers = maLabelData.maMembers; ULONG nVisCount = maLbHide.GetEntryCount(); - rLabelData.maVisible.realloc( nVisCount ); for( USHORT nPos = 0; nPos < nVisCount; ++nPos ) - rLabelData.maVisible[ nPos ] = !maLbHide.IsChecked( nPos ); + rLabelData.maMembers[nPos].mbVisible = !maLbHide.IsChecked(nPos); // *** HIERARCHY *** @@ -563,7 +582,8 @@ void ScDPSubtotalOptDlg::Init( const ScDPNameVec& rDataFields, bool bEnableLayou sal_Int32 nSortMode = maLabelData.maSortInfo.Mode; // sort fields list box - maLbSortBy.InsertEntry( maLabelData.maName ); + maLbSortBy.InsertEntry(maLabelData.getDisplayName()); + for( ScDPNameVec::const_iterator aIt = rDataFields.begin(), aEnd = rDataFields.end(); aIt != aEnd; ++aIt ) { maLbSortBy.InsertEntry( *aIt ); @@ -656,8 +676,9 @@ void ScDPSubtotalOptDlg::InitHideListBox() { maLbHide.Clear(); lclFillListBox( maLbHide, maLabelData.maMembers ); - for( sal_Int32 nVisIdx = 0, nVisSize = maLabelData.maVisible.getLength(); nVisIdx < nVisSize; ++nVisIdx ) - maLbHide.CheckEntryPos( static_cast< USHORT >( nVisIdx ), !maLabelData.maVisible[ nVisIdx ] ); + size_t n = maLabelData.maMembers.size(); + for (size_t i = 0; i < n; ++i) + maLbHide.CheckEntryPos(static_cast<USHORT>(i), !maLabelData.maMembers[i].mbVisible); bool bEnable = maLbHide.GetEntryCount() > 0; maFlHide.Enable( bEnable ); maLbHide.Enable( bEnable ); @@ -690,8 +711,7 @@ IMPL_LINK( ScDPSubtotalOptDlg, SelectHdl, ListBox*, pLBox ) { if( pLBox == &maLbHierarchy ) { - mrDPObj.GetMembers( maLabelData.mnCol, maLbHierarchy.GetSelectEntryPos(), - maLabelData.maMembers, &maLabelData.maVisible, &maLabelData.maShowDet ); + mrDPObj.GetMembers(maLabelData.mnCol, maLbHierarchy.GetSelectEntryPos(), maLabelData.maMembers); InitHideListBox(); } return 0; @@ -705,7 +725,9 @@ ScDPShowDetailDlg::ScDPShowDetailDlg( Window* pParent, ScDPObject& rDPObj, USHOR maLbDims ( this, ScResId( LB_DIMS ) ), maBtnOk ( this, ScResId( BTN_OK ) ), maBtnCancel ( this, ScResId( BTN_CANCEL ) ), - maBtnHelp ( this, ScResId( BTN_HELP ) ) + maBtnHelp ( this, ScResId( BTN_HELP ) ), + + mrDPObj(rDPObj) { FreeResource(); @@ -719,7 +741,13 @@ ScDPShowDetailDlg::ScDPShowDetailDlg( Window* pParent, ScDPObject& rDPObj, USHOR { const ScDPSaveDimension* pDimension = pSaveData ? pSaveData->GetExistingDimensionByName(aName) : 0; if ( !pDimension || (pDimension->GetOrientation() != nOrient) ) + { + const OUString* pLayoutName = pDimension->GetLayoutName(); + if (pLayoutName) + aName = *pLayoutName; maLbDims.InsertEntry( aName ); + maNameIndexMap.insert(DimNameIndexMap::value_type(aName, nDim)); + } } } if( maLbDims.GetEntryCount() ) @@ -735,7 +763,17 @@ short ScDPShowDetailDlg::Execute() String ScDPShowDetailDlg::GetDimensionName() const { - return maLbDims.GetSelectEntry(); + // Look up the internal dimension name which may be different from the + // displayed field name. + String aSelectedName = maLbDims.GetSelectEntry(); + DimNameIndexMap::const_iterator itr = maNameIndexMap.find(aSelectedName); + if (itr == maNameIndexMap.end()) + // This should never happen! + return aSelectedName; + + long nDim = itr->second; + BOOL bIsDataLayout = false; + return mrDPObj.GetDimName(nDim, bIsDataLayout); } IMPL_LINK( ScDPShowDetailDlg, DblClickHdl, ListBox*, pLBox ) diff --git a/sc/source/ui/dbgui/pvlaydlg.cxx b/sc/source/ui/dbgui/pvlaydlg.cxx index 7b03e067a865..6a9bb63e3ae3 100644 --- a/sc/source/ui/dbgui/pvlaydlg.cxx +++ b/sc/source/ui/dbgui/pvlaydlg.cxx @@ -63,6 +63,8 @@ #include "sc.hrc" //CHINA001 #include "scabstdlg.hxx" //CHINA001 using namespace com::sun::star; +using ::rtl::OUString; +using ::std::vector; //---------------------------------------------------------------------------- @@ -378,24 +380,23 @@ void ScDPLayoutDlg::StateChanged( StateChangedType nStateChange ) //---------------------------------------------------------------------------- -void ScDPLayoutDlg::InitWndSelect( LabelData** ppLabelArr, long nLabels ) +void ScDPLayoutDlg::InitWndSelect( const vector<ScDPLabelDataRef>& rLabels ) { - if ( ppLabelArr ) + size_t nLabelCount = rLabels.size(); + if (nLabelCount > MAX_LABELS) + nLabelCount = MAX_LABELS; + size_t nLast = (nLabelCount > PAGE_SIZE) ? (PAGE_SIZE - 1) : (nLabelCount - 1); + + aLabelDataArr.clear(); + aLabelDataArr.reserve( nLabelCount ); + for ( size_t i=0; i < nLabelCount; i++ ) { - size_t nLabelCount = static_cast< size_t >( (nLabels > MAX_LABELS) ? MAX_LABELS : nLabels ); - size_t nLast = (nLabelCount > PAGE_SIZE) ? (PAGE_SIZE - 1) : (nLabelCount - 1); + aLabelDataArr.push_back(*rLabels[i]); - aLabelDataArr.clear(); - aLabelDataArr.reserve( nLabelCount ); - for ( size_t i=0; i < nLabelCount; i++ ) + if ( i <= nLast ) { - aLabelDataArr.push_back( *ppLabelArr[i] ); - - if ( i <= nLast ) - { - aWndSelect.AddField( aLabelDataArr[i].maName, i ); - aSelectArr[i].reset( new ScDPFuncData( aLabelDataArr[i].mnCol, aLabelDataArr[i].mnFuncMask ) ); - } + aWndSelect.AddField(aLabelDataArr[i].getDisplayName(), i); + aSelectArr[i].reset( new ScDPFuncData( aLabelDataArr[i].mnCol, aLabelDataArr[i].mnFuncMask ) ); } } } @@ -493,18 +494,19 @@ void ScDPLayoutDlg::InitFocus() void ScDPLayoutDlg::InitFields() { - InitWndSelect( thePivotData.ppLabelArr, static_cast<long>(thePivotData.nLabels) ); + InitWndSelect(thePivotData.maLabelArray); InitWnd( thePivotData.aPageArr, static_cast<long>(thePivotData.nPageCount), TYPE_PAGE ); InitWnd( thePivotData.aColArr, static_cast<long>(thePivotData.nColCount), TYPE_COL ); InitWnd( thePivotData.aRowArr, static_cast<long>(thePivotData.nRowCount), TYPE_ROW ); InitWnd( thePivotData.aDataArr, static_cast<long>(thePivotData.nDataCount), TYPE_DATA ); + size_t nLabels = thePivotData.maLabelArray.size(); aSlider.SetPageSize( PAGE_SIZE ); aSlider.SetVisibleSize( PAGE_SIZE ); aSlider.SetLineSize( LINE_SIZE ); - aSlider.SetRange( Range( 0, static_cast<long>(((thePivotData.nLabels+LINE_SIZE-1)/LINE_SIZE)*LINE_SIZE) ) ); + aSlider.SetRange( Range( 0, static_cast<long>(((nLabels+LINE_SIZE-1)/LINE_SIZE)*LINE_SIZE) ) ); - if ( thePivotData.nLabels > PAGE_SIZE ) + if ( nLabels > PAGE_SIZE ) { aSlider.SetEndScrollHdl( LINK( this, ScDPLayoutDlg, ScrollHdl ) ); aSlider.Show(); @@ -594,7 +596,7 @@ void ScDPLayoutDlg::AddField( size_t nFromIndex, ScDPFieldType eToType, const Po if ( !bDataArr ) { - if ( toWnd->AddField( rData.maName, + if ( toWnd->AddField( rData.getDisplayName(), DlgPos2WndPos( rAtPos, *toWnd ), nAddedAt ) ) { @@ -605,9 +607,9 @@ void ScDPLayoutDlg::AddField( size_t nFromIndex, ScDPFieldType eToType, const Po else { USHORT nMask = fData.mnFuncMask; - String aStr( GetFuncString( nMask, rData.mbIsValue ) ); + OUString aStr = GetFuncString( nMask, rData.mbIsValue ); - aStr += rData.maName; + aStr += rData.getDisplayName(); if ( toWnd->AddField( aStr, DlgPos2WndPos( rAtPos, *toWnd ), @@ -1215,7 +1217,7 @@ String ScDPLayoutDlg::GetLabelString( SCsCOL nCol ) ScDPLabelData* pData = GetLabelData( nCol ); DBG_ASSERT( pData, "LabelData not found" ); if (pData) - return pData->maName; + return pData->getDisplayName(); return String(); } @@ -1491,6 +1493,8 @@ IMPL_LINK( ScDPLayoutDlg, OkHdl, OKButton *, EMPTYARG ) nPageCount, nColCount, nRowCount, nDataCount ); if ( bFit ) { + ScDPSaveData* pOldSaveData = xDlgDPObject->GetSaveData(); + ScRange aOutRange( aAdrDest ); // bToNewTable is passed separately ScDPSaveData aSaveData; @@ -1522,31 +1526,63 @@ IMPL_LINK( ScDPLayoutDlg, OkHdl, OKButton *, EMPTYARG ) pDim->SetSortInfo( &aIt->maSortInfo ); pDim->SetLayoutInfo( &aIt->maLayoutInfo ); pDim->SetAutoShowInfo( &aIt->maShowInfo ); + ScDPSaveDimension* pOldDim = NULL; + if (pOldSaveData) + { + // Transfer the existing layout names to new dimension instance. + pOldDim = pOldSaveData->GetExistingDimensionByName(aIt->maName); + if (pOldDim) + { + const OUString* pLayoutName = pOldDim->GetLayoutName(); + if (pLayoutName) + pDim->SetLayoutName(*pLayoutName); + + const OUString* pSubtotalName = pOldDim->GetSubtotalName(); + if (pSubtotalName) + pDim->SetSubtotalName(*pSubtotalName); + } + } bool bManualSort = ( aIt->maSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL ); // visibility of members - if( const rtl::OUString* pItem = aIt->maMembers.getConstArray() ) + for (vector<ScDPLabelData::Member>::const_iterator itr = aIt->maMembers.begin(), itrEnd = aIt->maMembers.end(); + itr != itrEnd; ++itr) { - sal_Int32 nIdx = 0; - sal_Int32 nVisSize = aIt->maVisible.getLength(); - sal_Int32 nShowSize = aIt->maShowDet.getLength(); - for( const rtl::OUString* pEnd = pItem + aIt->maMembers.getLength(); pItem != pEnd; ++pItem, ++nIdx ) + ScDPSaveMember* pMember = pDim->GetMemberByName(itr->maName); + + // #i40054# create/access members only if flags are not default + // (or in manual sorting mode - to keep the order) + if (bManualSort || !itr->mbVisible || !itr->mbShowDetails) + { + pMember->SetIsVisible(itr->mbVisible); + pMember->SetShowDetails(itr->mbShowDetails); + } + if (pOldDim) { - // #i40054# create/access members only if flags are not default - // (or in manual sorting mode - to keep the order) - bool bIsVisible = (nIdx >= nVisSize) || aIt->maVisible[ nIdx ]; - bool bShowDetails = (nIdx >= nShowSize) || aIt->maShowDet[ nIdx ]; - if( bManualSort || !bIsVisible || !bShowDetails ) + // Transfer the existing layout name. + ScDPSaveMember* pOldMember = pOldDim->GetMemberByName(itr->maName); + if (pOldMember) { - ScDPSaveMember* pMember = pDim->GetMemberByName( *pItem ); - pMember->SetIsVisible( bIsVisible ); - pMember->SetShowDetails( bShowDetails ); + const OUString* pLayoutName = pOldMember->GetLayoutName(); + if (pLayoutName) + pMember->SetLayoutName(*pLayoutName); } } } } } + ScDPSaveDimension* pDim = aSaveData.GetDataLayoutDimension(); + if (pDim && pOldSaveData) + { + ScDPSaveDimension* pOldDim = pOldSaveData->GetDataLayoutDimension(); + if (pOldDim) + { + const OUString* pLayoutName = pOldDim->GetLayoutName(); + if (pLayoutName) + pDim->SetLayoutName(*pLayoutName); + } + } USHORT nWhichPivot = SC_MOD()->GetPool().GetWhich( SID_PIVOT_TABLE ); ScPivotItem aOutItem( nWhichPivot, &aSaveData, &aOutRange, bToNewTable ); @@ -1720,7 +1756,7 @@ IMPL_LINK( ScDPLayoutDlg, ScrollHdl, ScrollBar *, EMPTYARG ) for ( i=0; i<nFields; i++ ) { const ScDPLabelData& rData = aLabelDataArr[nOffset+i]; - aWndSelect.AddField( rData.maName, i ); + aWndSelect.AddField(rData.getDisplayName(), i); aSelectArr[i].reset( new ScDPFuncData( rData.mnCol, rData.mnFuncMask ) ); } for ( ; i<aSelectArr.size(); i++ ) diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx index 33caccaed815..4042154b9a52 100644 --- a/sc/source/ui/docshell/dbdocfun.cxx +++ b/sc/source/ui/docshell/dbdocfun.cxx @@ -1234,7 +1234,7 @@ BOOL ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewOb aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, SC_MF_AUTO ); - pDoc->GetDPCollection()->Free( pOldObj ); // object is deleted here + pDoc->GetDPCollection()->FreeTable( pOldObj ); // object is deleted here rDocShell.PostPaintGridAll(); //! only necessary parts rDocShell.PostPaint( aRange.aStart.Col(), aRange.aStart.Row(), nTab, @@ -1278,7 +1278,7 @@ BOOL ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewOb pDestObj = new ScDPObject( *pNewObj ); pDestObj->SetAlive(TRUE); - if ( !pDoc->GetDPCollection()->Insert(pDestObj) ) + if ( !pDoc->GetDPCollection()->InsertNewTable(pDestObj) ) { DBG_ERROR("cannot insert DPObject"); DELETEZ( pDestObj ); diff --git a/sc/source/ui/inc/AccessibleContextBase.hxx b/sc/source/ui/inc/AccessibleContextBase.hxx index 98f2afc8e88d..4c79c4388e44 100644 --- a/sc/source/ui/inc/AccessibleContextBase.hxx +++ b/sc/source/ui/inc/AccessibleContextBase.hxx @@ -319,6 +319,8 @@ protected: /// Use this method to set initial Description without notification void SetDescription(const rtl::OUString& rDesc) { msDescription = rDesc; } + void SetRole(sal_Int16 nRole); + /// Reference to the parent object. ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> mxParent; diff --git a/sc/source/ui/inc/dbfunc.hxx b/sc/source/ui/inc/dbfunc.hxx index 82739bfdd274..875576a22889 100644 --- a/sc/source/ui/inc/dbfunc.hxx +++ b/sc/source/ui/inc/dbfunc.hxx @@ -80,7 +80,7 @@ public: void GotoDBArea( const String& rDBName ); // DB-Bereich vom Cursor - ScDBData* GetDBData( BOOL bMarkArea = TRUE, ScGetDBMode eMode = SC_DB_MAKE ); + ScDBData* GetDBData( BOOL bMarkArea = TRUE, ScGetDBMode eMode = SC_DB_MAKE, bool bShrinkToData = false ); void NotifyCloseDbNameDlg( const ScDBCollection& rNewColl, const List& rDelAreaList ); @@ -99,6 +99,7 @@ public: void UngroupDataPilot(); void DataPilotInput( const ScAddress& rPos, const String& rString ); + bool DataPilotSort( const ScAddress& rPos, bool bAscending, sal_uInt16* pUserListId = NULL ); BOOL DataPilotMove( const ScRange& rSource, const ScAddress& rDest ); BOOL HasSelectionForDrillDown( USHORT& rOrientation ); diff --git a/sc/source/ui/inc/dpcontrol.hrc b/sc/source/ui/inc/dpcontrol.hrc new file mode 100644 index 000000000000..2275b601c17a --- /dev/null +++ b/sc/source/ui/inc/dpcontrol.hrc @@ -0,0 +1,43 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: protectiondlg.hrc,v $ + * $Revision: 1.1.2.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __DPCONTROL_HRC__ +#define __DPCONTROL_HRC__ + +#include <sc.hrc> + +#define STR_MENU_SORT_ASC 1 +#define STR_MENU_SORT_DESC 2 +#define STR_MENU_SORT_CUSTOM 3 +#define STR_BTN_TOGGLE_ALL 4 +#define STR_BTN_SELECT_CURRENT 5 +#define STR_BTN_UNSELECT_CURRENT 6 + +#endif diff --git a/sc/source/ui/inc/dpcontrol.hxx b/sc/source/ui/inc/dpcontrol.hxx new file mode 100644 index 000000000000..1b99f6a38842 --- /dev/null +++ b/sc/source/ui/inc/dpcontrol.hxx @@ -0,0 +1,366 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: document.hxx,v $ + * $Revision: 1.115.36.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_DPCONTROL_HXX +#define SC_DPCONTROL_HXX + +#include "rtl/ustring.hxx" +#include "tools/gen.hxx" +#include "tools/fract.hxx" +#include "vcl/popupmenuwindow.hxx" +#include "vcl/button.hxx" +#include "vcl/scrbar.hxx" +#include "vcl/timer.hxx" +#include "svx/checklbx.hxx" + +#include <boost/shared_ptr.hpp> +#include <memory> +#include <hash_map> + +namespace com { namespace sun { namespace star { + + namespace accessibility { + class XAccessible; + } + +}}} + +class OutputDevice; +class Point; +class Size; +class StyleSettings; +class Window; +class ScDocument; +class ScAccessibleFilterMenu; + +/** + * This class takes care of physically drawing field button controls inside + * data pilot tables. + */ +class ScDPFieldButton +{ +public: + ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomX = NULL, const Fraction* pZoomY = NULL); + ~ScDPFieldButton(); + + void setText(const ::rtl::OUString& rText); + void setBoundingBox(const Point& rPos, const Size& rSize); + void setDrawBaseButton(bool b); + void setDrawPopupButton(bool b); + void setHasHiddenMember(bool b); + void setPopupPressed(bool b); + void draw(); + + void getPopupBoundingBox(Point& rPos, Size& rSize) const; + bool isPopupButton() const; + +private: + void drawPopupButton(); + +private: + Point maPos; + Size maSize; + ::rtl::OUString maText; + Fraction maZoomX; + Fraction maZoomY; + OutputDevice* mpOutDev; + const StyleSettings* mpStyle; + bool mbBaseButton; + bool mbPopupButton; + bool mbHasHiddenMember; + bool mbPopupPressed; +}; + +// ============================================================================ + +class ScMenuFloatingWindow : public PopupMenuFloatingWindow +{ +public: + static size_t MENU_NOT_SELECTED; + /** + * Action to perform when an event takes place. Create a sub-class of + * this to implement the desired action. + */ + class Action + { + public: + virtual void execute() = 0; + }; + + explicit ScMenuFloatingWindow(Window* pParent, ScDocument* pDoc, USHORT nMenuStackLevel = 0); + virtual ~ScMenuFloatingWindow(); + + virtual void MouseMove(const MouseEvent& rMEvt); + virtual void MouseButtonDown(const MouseEvent& rMEvt); + virtual void MouseButtonUp(const MouseEvent& rMEvt); + virtual void KeyInput(const KeyEvent& rKEvt); + virtual void Paint(const Rectangle& rRect); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); + + void addMenuItem(const ::rtl::OUString& rText, bool bEnabled, Action* pAction); + ScMenuFloatingWindow* addSubMenuItem(const ::rtl::OUString& rText, bool bEnabled); + void setSelectedMenuItem(size_t nPos, bool bSubMenuTimer, bool bEnsureSubMenu); + void selectMenuItem(size_t nPos, bool bSelected, bool bSubMenuTimer); + void clearSelectedMenuItem(); + ScMenuFloatingWindow* getSubMenuWindow(size_t nPos) const; + size_t getMenuItemCount() const; + ::rtl::OUString getMenuItemName(size_t nPos) const; + bool isMenuItemEnabled(size_t nPos) const; + bool isMenuItemSelected(size_t nPos) const; + size_t getSelectedMenuItem() const; + + void setName(const ::rtl::OUString& rName); + const ::rtl::OUString& getName() const; + + void executeMenuItem(size_t nPos); + void getMenuItemPosSize(size_t nPos, Point& rPos, Size& rSize) const; + ScMenuFloatingWindow* getParentMenuWindow() const; + +protected: + + void drawMenuItem(size_t nPos); + void drawAllMenuItems(); + const Font& getLabelFont() const; + + void queueLaunchSubMenu(size_t nPos, ScMenuFloatingWindow* pMenu); + void queueCloseSubMenu(); + void launchSubMenu(bool bSetMenuPos); + void endSubMenu(ScMenuFloatingWindow* pSubMenu); + + void fillMenuItemsToAccessible(ScAccessibleFilterMenu* pAccMenu) const; + + ScDocument* getDoc(); + +protected: + ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible > mxAccessible; + +private: + struct SubMenuItemData; + void handleMenuTimeout(SubMenuItemData* pTimer); + + void resizeToFitMenuItems(); + void highlightMenuItem(size_t nPos, bool bSelected); + + size_t getEnclosingMenuItem(const Point& rPos) const; + size_t getSubMenuPos(ScMenuFloatingWindow* pSubMenu); + + /** + * Fire a menu highlight event since the accessibility framework needs + * this to track focus on menu items. + */ + void fireMenuHighlightedEvent(); + + /** + * Make sure that the specified submenu is permanently up, the submenu + * close timer is not active, and the correct menu item associated with + * the submenu is highlighted. + */ + void setSubMenuFocused(ScMenuFloatingWindow* pSubMenu); + + /** + * When a menu item of an invisible submenu is selected, we need to make + * sure that all its parent menu(s) are visible, with the right menu item + * highlighted in each of the parents. Calling this method ensures it. + */ + void ensureSubMenuVisible(ScMenuFloatingWindow* pSubMenu); + + /** + * Dismiss any visible child submenus when a menu item of a parent menu is + * selected. + */ + void ensureSubMenuNotVisible(); + + /** + * Dismiss all visible popup menus and set focus back to the application + * window. This method is called e.g. when a menu action is fired. + */ + void terminateAllPopupMenus(); + + DECL_LINK( PopupEndHdl, void* ); + +private: + + struct MenuItemData + { + ::rtl::OUString maText; + bool mbEnabled; + + ::boost::shared_ptr<Action> mpAction; + ::boost::shared_ptr<ScMenuFloatingWindow> mpSubMenuWin; + + MenuItemData(); + }; + + ::std::vector<MenuItemData> maMenuItems; + + struct SubMenuItemData + { + Timer maTimer; + ScMenuFloatingWindow* mpSubMenu; + size_t mnMenuPos; + + DECL_LINK( TimeoutHdl, void* ); + + SubMenuItemData(ScMenuFloatingWindow* pParent); + void reset(); + + private: + ScMenuFloatingWindow* mpParent; + }; + SubMenuItemData maOpenTimer; + SubMenuItemData maCloseTimer; + + Font maLabelFont; + + // Name of this menu window, taken from the menu item of the parent window + // that launches it (if this is a sub menu). If this is a top-level menu + // window, then this name can be anything. + ::rtl::OUString maName; + + size_t mnSelectedMenu; + size_t mnClickedMenu; + + ScDocument* mpDoc; + + ScMenuFloatingWindow* mpParentMenu; + ScMenuFloatingWindow* mpActiveSubMenu; +}; + +// ============================================================================ + +/** + * This class implements a popup window for field button, for quick access + * of hide-item list, and possibly more stuff related to field options. + */ +class ScDPFieldPopupWindow : public ScMenuFloatingWindow +{ +public: + /** + * Extended data that the client code may need to store. Create a + * sub-class of this and store data there. + */ + struct ExtendedData {}; + + explicit ScDPFieldPopupWindow(Window* pParent, ScDocument* pDoc); + virtual ~ScDPFieldPopupWindow(); + + virtual void MouseMove(const MouseEvent& rMEvt); + virtual long Notify(NotifyEvent& rNEvt); + virtual void Paint(const Rectangle& rRect); + virtual Window* GetPreferredKeyInputWindow(); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); + + void setMemberSize(size_t n); + void addMember(const ::rtl::OUString& rName, bool bVisible); + void initMembers(); + + const Size& getWindowSize() const; + + void getResult(::std::hash_map< ::rtl::OUString, bool, ::rtl::OUStringHash>& rResult); + void close(bool bOK); + + /** + * Set auxiliary data that the client code might need. Note that this + * popup window class manages its life time; no explicit deletion of the + * instance is needed in the client code. + */ + void setExtendedData(ExtendedData* p); + + /** + * Get the store auxiliary data, or NULL if no such data is stored. + */ + ExtendedData* getExtendedData(); + + void setOKAction(Action* p); + +private: + struct Member + { + ::rtl::OUString maName; + bool mbVisible; + + Member(); + }; + + class CancelButton : public ::CancelButton + { + public: + CancelButton(ScDPFieldPopupWindow* pParent); + + virtual void Click(); + + private: + ScDPFieldPopupWindow* mpParent; + }; + + enum SectionType { + WHOLE, // entire window + LISTBOX_AREA_OUTER, // box enclosing the check box items. + LISTBOX_AREA_INNER, // box enclosing the check box items. + SINGLE_BTN_AREA, // box enclosing the single-action buttons. + CHECK_TOGGLE_ALL, // check box for toggling all items. + BTN_SINGLE_SELECT, + BTN_SINGLE_UNSELECT, + BTN_OK, // OK button + BTN_CANCEL, // Cancel button + }; + void getSectionPosSize(Point& rPos, Size& rSize, SectionType eType) const; + + void setAllMemberState(bool bSet); + void selectCurrentMemberOnly(bool bSet); + void cycleFocus(bool bReverse = false); + + DECL_LINK( ButtonHdl, Button* ); + DECL_LINK( TriStateHdl, TriStateBox* ); + DECL_LINK( CheckHdl, SvTreeListBox* ); + +private: + SvxCheckListBox maChecks; + + TriStateBox maChkToggleAll; + ImageButton maBtnSelectSingle; + ImageButton maBtnUnselectSingle; + + OKButton maBtnOk; + CancelButton maBtnCancel; + + ::std::vector<Window*> maTabStopCtrls; + size_t mnCurTabStop; + + ::std::vector<Member> maMembers; + ::std::auto_ptr<ExtendedData> mpExtendedData; + ::std::auto_ptr<Action> mpOKAction; + + const Size maWndSize; /// hard-coded window size. + TriState mePrevToggleAllState; +}; + +#endif diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx index 8b680daad6cb..68f7ece9a249 100644 --- a/sc/source/ui/inc/gridwin.hxx +++ b/sc/source/ui/inc/gridwin.hxx @@ -37,15 +37,19 @@ #include "viewdata.hxx" #include "cbutton.hxx" #include <svx/sdr/overlay/overlayobject.hxx> +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> #include <basegfx/matrix/b2dhommatrix.hxx> #include <vector> +#include <memory> // --------------------------------------------------------------------------- struct ScTableInfo; class ScViewSelectionEngine; class ScDPObject; +class ScDPFieldPopupWindow; +class ScDPFieldButton; class ScOutputData; class ScFilterListBox; class AutoFilterPopup; @@ -121,6 +125,8 @@ private: ScFilterListBox* pFilterBox; FloatingWindow* pFilterFloat; + ::std::auto_ptr<ScDPFieldPopupWindow> mpDPFieldPopup; + ::std::auto_ptr<ScDPFieldButton> mpFilterButton; USHORT nCursorHideCount; @@ -187,12 +193,23 @@ private: BOOL TestMouse( const MouseEvent& rMEvt, BOOL bAction ); BOOL DoPageFieldSelection( SCCOL nCol, SCROW nRow ); + bool DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt ); void DoPushButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt ); void DPMouseMove( const MouseEvent& rMEvt ); void DPMouseButtonUp( const MouseEvent& rMEvt ); void DPTestMouse( const MouseEvent& rMEvt, BOOL bMove ); + /** + * Check if the mouse click is on a field popup button. + * + * @return bool true if the field popup menu has been launched and no + * further mouse event handling is necessary, false otherwise. + */ + bool DPTestFieldPopupArrow(const MouseEvent& rMEvt, const ScAddress& rPos, ScDPObject* pDPObj); + void DPLaunchFieldPopupMenu( + const Point& rScrPos, const Size& rScrSize, const ScAddress& rPos, ScDPObject* pDPObj); + void RFMouseMove( const MouseEvent& rMEvt, BOOL bUp ); void PagebreakMove( const MouseEvent& rMEvt, BOOL bUp ); @@ -315,9 +332,11 @@ public: void DoAutoFilterMenue( SCCOL nCol, SCROW nRow, BOOL bDataSelect ); void DoScenarioMenue( const ScRange& rScenRange ); - void DoPageFieldMenue( SCCOL nCol, SCROW nRow ); - BOOL HasPageFieldData( SCCOL nCol, SCROW nRow ) const; + void LaunchPageFieldMenu( SCCOL nCol, SCROW nRow ); + void LaunchDPFieldMenu( SCCOL nCol, SCROW nRow ); + + ::com::sun::star::sheet::DataPilotFieldOrientation GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const; void DrawButtons( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, ScTableInfo& rTabInfo, OutputDevice* pContentDev ); @@ -357,6 +376,8 @@ public: void CheckNeedsRepaint(); + void UpdateDPFromFieldPopupMenu(); + // #114409# void CursorChanged(); void DrawLayerCreated(); diff --git a/sc/source/ui/inc/pvfundlg.hxx b/sc/source/ui/inc/pvfundlg.hxx index eeeb9c4094c4..6b9aa62c37a3 100644 --- a/sc/source/ui/inc/pvfundlg.hxx +++ b/sc/source/ui/inc/pvfundlg.hxx @@ -55,6 +55,8 @@ #include <sfx2/itemconnect.hxx> #include "pivot.hxx" +#include <hash_map> + // ============================================================================ typedef sfx::ListBoxWrapper< sal_Int32 > ScDPListBoxWrapper; @@ -217,6 +219,11 @@ public: virtual short Execute(); + /** + * @return String internal name of the selected field. Note that this may + * be different from the name displayed in the dialog if the field + * has a layout name. + */ String GetDimensionName() const; private: @@ -228,6 +235,10 @@ private: OKButton maBtnOk; CancelButton maBtnCancel; HelpButton maBtnHelp; + + typedef ::std::hash_map<String, long, ScStringHashCode> DimNameIndexMap; + DimNameIndexMap maNameIndexMap; + ScDPObject& mrDPObj; }; // ============================================================================ diff --git a/sc/source/ui/inc/pvlaydlg.hxx b/sc/source/ui/inc/pvlaydlg.hxx index b7a71aebc1fe..c77364d3761f 100644 --- a/sc/source/ui/inc/pvlaydlg.hxx +++ b/sc/source/ui/inc/pvlaydlg.hxx @@ -193,7 +193,7 @@ private: private: ScDPFieldWindow& GetFieldWindow ( ScDPFieldType eType ); void Init (); - void InitWndSelect ( LabelData** ppLabelArr, long nLabels ); + void InitWndSelect ( const ::std::vector<ScDPLabelDataRef>& rLabels ); void InitWnd ( PivotField* pArr, long nCount, ScDPFieldType eType ); void InitFocus (); void InitFields (); diff --git a/sc/source/ui/undo/undodat.cxx b/sc/source/ui/undo/undodat.cxx index 7ab321ac0c1d..5c929ec7a11b 100644 --- a/sc/source/ui/undo/undodat.cxx +++ b/sc/source/ui/undo/undodat.cxx @@ -1876,7 +1876,7 @@ void __EXPORT ScUndoDataPilot::Undo() else { // delete inserted object - pDoc->GetDPCollection()->Free(pDocObj); + pDoc->GetDPCollection()->FreeTable(pDocObj); } } } @@ -1886,7 +1886,7 @@ void __EXPORT ScUndoDataPilot::Undo() ScDPObject* pDestObj = new ScDPObject( *pOldDPObject ); pDestObj->SetAlive(TRUE); - if ( !pDoc->GetDPCollection()->Insert(pDestObj) ) + if ( !pDoc->GetDPCollection()->InsertNewTable(pDestObj) ) { DBG_ERROR("cannot insert DPObject"); DELETEZ( pDestObj ); diff --git a/sc/source/ui/unoobj/dapiuno.cxx b/sc/source/ui/unoobj/dapiuno.cxx index ed40d2f5c96a..a7836b43f740 100644 --- a/sc/source/ui/unoobj/dapiuno.cxx +++ b/sc/source/ui/unoobj/dapiuno.cxx @@ -1626,8 +1626,13 @@ OUString SAL_CALL ScDataPilotFieldObj::getName() throw(RuntimeException) if( pDim->IsDataLayout() ) aName = OUString( RTL_CONSTASCII_USTRINGPARAM( SC_DATALAYOUT_NAME ) ); else - aName = pDim->GetLayoutName(); - } + { + const rtl::OUString* pLayoutName = pDim->GetLayoutName(); + if (pLayoutName) + aName = *pLayoutName; + else + aName = pDim->GetName(); + } } return aName; } @@ -1639,7 +1644,7 @@ void SAL_CALL ScDataPilotFieldObj::setName( const OUString& rName ) throw(Runtim if( pDim && !pDim->IsDataLayout() ) { String aName( rName ); - pDim->SetLayoutName( &aName ); + pDim->SetLayoutName(aName); SetDPObject( pDPObj ); } } @@ -3069,7 +3074,7 @@ Sequence<OUString> SAL_CALL ScDataPilotItemsObj::getElementNames() ScUnoGuard aGuard; Sequence< OUString > aSeq; if( ScDPObject* pDPObj = GetDPObject() ) - pDPObj->GetMembers( lcl_GetObjectIndex( pDPObj, maFieldId ), aSeq ); + pDPObj->GetMemberNames( lcl_GetObjectIndex( pDPObj, maFieldId ), aSeq ); return aSeq; } diff --git a/sc/source/ui/unoobj/miscuno.cxx b/sc/source/ui/unoobj/miscuno.cxx index 3d41da907016..ee2a64bd8c78 100644 --- a/sc/source/ui/unoobj/miscuno.cxx +++ b/sc/source/ui/unoobj/miscuno.cxx @@ -39,6 +39,9 @@ #include "unoguard.hxx" using namespace com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::rtl::OUString; //------------------------------------------------------------------------ @@ -137,6 +140,26 @@ sal_Int32 ScUnoHelpFunctions::GetEnumProperty( const uno::Reference<beans::XProp return nRet; } +// static +OUString ScUnoHelpFunctions::GetStringProperty( + const Reference<beans::XPropertySet>& xProp, const OUString& rName, const OUString& rDefault ) +{ + OUString aRet = rDefault; + if (!xProp.is()) + return aRet; + + try + { + Any any = xProp->getPropertyValue(rName); + any >>= aRet; + } + catch (const uno::Exception&) + { + } + + return aRet; +} + // static sal_Bool ScUnoHelpFunctions::GetBoolFromAny( const uno::Any& aAny ) { @@ -180,6 +203,20 @@ void ScUnoHelpFunctions::SetBoolInAny( uno::Any& rAny, sal_Bool bValue ) rAny.setValue( &bValue, getBooleanCppuType() ); } +// static +void ScUnoHelpFunctions::SetOptionalPropertyValue( + Reference<beans::XPropertySet>& rPropSet, const sal_Char* pPropName, const Any& rVal ) +{ + try + { + rPropSet->setPropertyValue(OUString::createFromAscii(pPropName), rVal); + } + catch (const beans::UnknownPropertyException&) + { + // ignored - not supported. + } +} + //------------------------------------------------------------------------ ScIndexEnumeration::ScIndexEnumeration(const uno::Reference<container::XIndexAccess>& rInd, diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx index cf64a07a2d95..47c55350f278 100644 --- a/sc/source/ui/view/cellsh2.cxx +++ b/sc/source/ui/view/cellsh2.cxx @@ -762,7 +762,7 @@ void ScCellShell::ExecuteDB( SfxRequest& rReq ) { // select database range or data pTabViewShell->GetDBData( TRUE, SC_DB_OLD ); - const ScMarkData& rMark = GetViewData()->GetMarkData(); + ScMarkData& rMark = GetViewData()->GetMarkData(); if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) pTabViewShell->MarkDataArea( FALSE ); @@ -828,6 +828,19 @@ void ScCellShell::ExecuteDB( SfxRequest& rReq ) ScMarkType eType = GetViewData()->GetSimpleArea(aRange); if ( (eType & SC_MARK_SIMPLE) == SC_MARK_SIMPLE ) { + // Shrink the range to the data area. + SCCOL nStartCol = aRange.aStart.Col(), nEndCol = aRange.aEnd.Col(); + SCROW nStartRow = aRange.aStart.Row(), nEndRow = aRange.aEnd.Row(); + if (pDoc->ShrinkToDataArea(aRange.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow)) + { + aRange.aStart.SetCol(nStartCol); + aRange.aStart.SetRow(nStartRow); + aRange.aEnd.SetCol(nEndCol); + aRange.aEnd.SetRow(nEndRow); + rMark.SetMarkArea(aRange); + pTabViewShell->MarkRange(aRange); + } + BOOL bOK = TRUE; if ( pDoc->HasSubTotalCells( aRange ) ) { diff --git a/sc/source/ui/view/dbfunc.cxx b/sc/source/ui/view/dbfunc.cxx index 0d44603b64f8..48b6d3ba11f7 100644 --- a/sc/source/ui/view/dbfunc.cxx +++ b/sc/source/ui/view/dbfunc.cxx @@ -107,14 +107,30 @@ void ScDBFunc::GotoDBArea( const String& rDBName ) // aktuellen Datenbereich fuer Sortieren / Filtern suchen -ScDBData* ScDBFunc::GetDBData( BOOL bMark, ScGetDBMode eMode ) +ScDBData* ScDBFunc::GetDBData( BOOL bMark, ScGetDBMode eMode, bool bShrinkToData ) { ScDocShell* pDocSh = GetViewData()->GetDocShell(); ScDBData* pData = NULL; ScRange aRange; ScMarkType eMarkType = GetViewData()->GetSimpleArea(aRange); if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED ) + { + if (bShrinkToData) + { + // Shrink the range to only include data area. + ScDocument* pDoc = pDocSh->GetDocument(); + SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col(); + SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row(); + if (pDoc->ShrinkToDataArea(aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2)) + { + aRange.aStart.SetCol(nCol1); + aRange.aEnd.SetCol(nCol2); + aRange.aStart.SetRow(nRow1); + aRange.aEnd.SetRow(nRow2); + } + } pData = pDocSh->GetDBData( aRange, eMode, FALSE ); + } else if ( eMode != SC_DB_OLD ) pData = pDocSh->GetDBData( ScRange( GetViewData()->GetCurX(), GetViewData()->GetCurY(), diff --git a/sc/source/ui/view/dbfunc3.cxx b/sc/source/ui/view/dbfunc3.cxx index 5fd4a5f470f5..41a959409727 100644 --- a/sc/source/ui/view/dbfunc3.cxx +++ b/sc/source/ui/view/dbfunc3.cxx @@ -44,19 +44,17 @@ #include <vcl/waitobj.hxx> #include <svl/zforlist.hxx> #include <sfx2/app.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sheet/DataPilotFieldFilter.hpp> +#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp> -#include <com/sun/star/sheet/MemberResultFlags.hpp> - -#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp> +#include <com/sun/star/sheet/GeneralFunction.hpp> #include <com/sun/star/sheet/MemberResultFlags.hpp> -#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> -#include <com/sun/star/sheet/DataPilotFieldFilter.hpp> -#include <com/sun/star/sheet/XDrillDownDataSupplier.hpp> #include <com/sun/star/sheet/XDimensionsSupplier.hpp> -#include <com/sun/star/beans/XPropertySet.hpp> -#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sheet/XDrillDownDataSupplier.hpp> #include "global.hxx" #include "globstr.hrc" @@ -81,9 +79,13 @@ #include "patattr.hxx" #include "unonames.hxx" #include "cell.hxx" +#include "userlist.hxx" #include <hash_set> +#include <hash_map> #include <memory> +#include <list> +#include <vector> using namespace com::sun::star; using ::com::sun::star::uno::Any; @@ -91,7 +93,16 @@ using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::sheet::XDimensionsSupplier; +using ::rtl::OUString; +using ::rtl::OUStringHash; +using ::rtl::OUStringBuffer; using ::std::auto_ptr; +using ::std::list; +using ::std::vector; +using ::std::hash_map; +using ::std::hash_set; // STATIC DATA ----------------------------------------------------------- @@ -1351,123 +1362,323 @@ void ScDBFunc::UngroupDataPilot() } } +static OUString lcl_replaceMemberNameInSubtotal(const OUString& rSubtotal, const OUString& rMemberName) +{ + sal_Int32 n = rSubtotal.getLength(); + const sal_Unicode* p = rSubtotal.getStr(); + OUStringBuffer aBuf, aWordBuf; + for (sal_Int32 i = 0; i < n; ++i) + { + sal_Unicode c = p[i]; + if (c == sal_Unicode(' ')) + { + OUString aWord = aWordBuf.makeStringAndClear(); + if (aWord.equals(rMemberName)) + aBuf.append(sal_Unicode('?')); + else + aBuf.append(aWord); + aBuf.append(c); + } + else if (c == sal_Unicode('\\')) + { + // Escape a backslash character. + aWordBuf.append(c); + aWordBuf.append(c); + } + else if (c == sal_Unicode('?')) + { + // A literal '?' must be escaped with a backslash ('\'); + aWordBuf.append(sal_Unicode('\\')); + aWordBuf.append(c); + } + else + aWordBuf.append(c); + } + + if (aWordBuf.getLength() > 0) + { + OUString aWord = aWordBuf.makeStringAndClear(); + if (aWord.equals(rMemberName)) + aBuf.append(sal_Unicode('?')); + else + aBuf.append(aWord); + } + + return aBuf.makeStringAndClear(); +} + void ScDBFunc::DataPilotInput( const ScAddress& rPos, const String& rString ) { + using namespace ::com::sun::star::sheet; + String aNewName( rString ); ScDocument* pDoc = GetViewData()->GetDocument(); ScDPObject* pDPObj = pDoc->GetDPAtCursor( rPos.Col(), rPos.Row(), rPos.Tab() ); - if ( pDPObj ) + if (!pDPObj) + return; + + String aOldText; + pDoc->GetString( rPos.Col(), rPos.Row(), rPos.Tab(), aOldText ); + + if ( aOldText == rString ) { - String aOldText; - pDoc->GetString( rPos.Col(), rPos.Row(), rPos.Tab(), aOldText ); + // nothing to do: silently exit + return; + } + + USHORT nErrorId = 0; + + pDPObj->BuildAllDimensionMembers(); + ScDPSaveData aData( *pDPObj->GetSaveData() ); + BOOL bChange = FALSE; - if ( aOldText == rString ) + USHORT nOrient = DataPilotFieldOrientation_HIDDEN; + long nField = pDPObj->GetHeaderDim( rPos, nOrient ); + if ( nField >= 0 ) + { + // changing a field title + if ( aData.GetExistingDimensionData() ) { - // nothing to do: silently exit - return; - } + // only group dimensions can be renamed - USHORT nErrorId = 0; + ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); + ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText ); + if ( pGroupDim ) + { + // valid name: not empty, no existing dimension (group or other) + if ( rString.Len() && !pDPObj->IsDimNameInUse(rString) ) + { + pGroupDim->Rename( aNewName ); - ScDPSaveData aData( *pDPObj->GetSaveData() ); - BOOL bChange = FALSE; + // also rename in SaveData to preserve the field settings + ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText ); + pSaveDim->SetName( aNewName ); - USHORT nOrient = sheet::DataPilotFieldOrientation_HIDDEN; - long nField = pDPObj->GetHeaderDim( rPos, nOrient ); - if ( nField >= 0 ) + bChange = TRUE; + } + else + nErrorId = STR_INVALIDNAME; + } + } + else if (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) + { + BOOL bDataLayout = false; + String aDimName = pDPObj->GetDimName(nField, bDataLayout); + ScDPSaveDimension* pDim = bDataLayout ? aData.GetDataLayoutDimension() : aData.GetDimensionByName(aDimName); + if (pDim) + { + if (rString.Len()) + { + if (rString.EqualsIgnoreCaseAscii(aDimName)) + { + pDim->RemoveLayoutName(); + bChange = true; + } + else if (!pDPObj->IsDimNameInUse(rString)) + { + pDim->SetLayoutName(rString); + bChange = true; + } + else + nErrorId = STR_INVALIDNAME; + } + else + nErrorId = STR_INVALIDNAME; + } + } + } + else if (pDPObj->IsDataDescriptionCell(rPos)) + { + // There is only one data dimension. + ScDPSaveDimension* pDim = aData.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA); + if (pDim) { - // changing a field title + if (rString.Len()) + { + if (rString.EqualsIgnoreCaseAscii(pDim->GetName())) + { + pDim->RemoveLayoutName(); + bChange = true; + } + else if (!pDPObj->IsDimNameInUse(rString)) + { + pDim->SetLayoutName(rString); + bChange = true; + } + else + nErrorId = STR_INVALIDNAME; + } + else + nErrorId = STR_INVALIDNAME; + } + } + else + { + // This is not a field header. + sheet::DataPilotTableHeaderData aPosData; + pDPObj->GetHeaderPositionData(rPos, aPosData); - if ( aData.GetExistingDimensionData() ) + if ( (aPosData.Flags & MemberResultFlags::HASMEMBER) && aOldText.Len() ) + { + if ( aData.GetExistingDimensionData() && !(aPosData.Flags & MemberResultFlags::SUBTOTAL)) { - // only group dimensions can be renamed + BOOL bIsDataLayout; + String aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout ); ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); - ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText ); + ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName ); if ( pGroupDim ) { - // valid name: not empty, no existing dimension (group or other) - if ( aNewName.Len() && !pDPObj->IsDimNameInUse( aNewName ) ) + // valid name: not empty, no existing group in this dimension + //! ignore case? + if ( aNewName.Len() && !pGroupDim->GetNamedGroup( aNewName ) ) { - pGroupDim->Rename( aNewName ); + ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText ); + if ( pGroup ) + pGroup->Rename( aNewName ); // rename the existing group + else + { + // create a new group to replace the automatic group + ScDPSaveGroupItem aGroup( aNewName ); + aGroup.AddElement( aOldText ); + pGroupDim->AddGroupItem( aGroup ); + } - // also rename in SaveData to preserve the field settings - ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText ); - pSaveDim->SetName( aNewName ); + // in both cases also adjust savedata, to preserve member settings (show details) + ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName ); + ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText ); + if ( pSaveMember ) + pSaveMember->SetName( aNewName ); bChange = TRUE; } else nErrorId = STR_INVALIDNAME; - } + } } - } - else - { - // renaming a group (item)? - // allow only on the item name itself - not on empty cells, not on subtotals - - sheet::DataPilotTableHeaderData aPosData; - pDPObj->GetHeaderPositionData(rPos, aPosData); - if ( ( aPosData.Flags & sheet::MemberResultFlags::HASMEMBER ) && - ! ( aPosData.Flags & sheet::MemberResultFlags::SUBTOTAL ) && - aOldText.Len() ) + else if ((aPosData.Flags & MemberResultFlags::GRANDTOTAL)) { - if ( aData.GetExistingDimensionData() ) + aData.SetGrandTotalName(rString); + bChange = true; + } + else if (aPosData.Dimension >= 0 && aPosData.MemberName.getLength() > 0) + { + BOOL bDataLayout = false; + String aDimName = pDPObj->GetDimName(static_cast<long>(aPosData.Dimension), bDataLayout); + if (bDataLayout) { - BOOL bIsDataLayout; - String aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout ); + // data dimension + do + { + if ((aPosData.Flags & MemberResultFlags::SUBTOTAL)) + break; + + ScDPSaveDimension* pDim = aData.GetDimensionByName(aPosData.MemberName); + if (!pDim) + break; + + if (!rString.Len()) + { + nErrorId = STR_INVALIDNAME; + break; + } - ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); - ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName ); - if ( pGroupDim ) + if (aPosData.MemberName.equalsIgnoreAsciiCase(rString)) + { + pDim->RemoveLayoutName(); + bChange = true; + } + else if (!pDPObj->IsDimNameInUse(rString)) + { + pDim->SetLayoutName(rString); + bChange = true; + } + else + nErrorId = STR_INVALIDNAME; + } + while (false); + } + else + { + // field member + do { - // valid name: not empty, no existing group in this dimension - //! ignore case? - if ( aNewName.Len() && !pGroupDim->GetNamedGroup( aNewName ) ) + ScDPSaveDimension* pDim = aData.GetDimensionByName(aDimName); + if (!pDim) + break; + + ScDPSaveMember* pMem = pDim->GetExistingMemberByName(aPosData.MemberName); + if (!pMem) + break; + + if ((aPosData.Flags & MemberResultFlags::SUBTOTAL)) { - ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText ); - if ( pGroup ) - pGroup->Rename( aNewName ); // rename the existing group - else - { - // create a new group to replace the automatic group - ScDPSaveGroupItem aGroup( aNewName ); - aGroup.AddElement( aOldText ); - pGroupDim->AddGroupItem( aGroup ); - } + // Change subtotal only when the table has one data dimension. + if (aData.GetDataDimensionCount() > 1) + break; + + // display name for subtotal is allowed only if the subtotal type is 'Automatic'. + if (pDim->GetSubTotalsCount() != 1) + break; - // in both cases also adjust savedata, to preserve member settings (show details) - ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName ); - ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText ); - if ( pSaveMember ) - pSaveMember->SetName( aNewName ); + if (pDim->GetSubTotalFunc(0) != sheet::GeneralFunction_AUTO) + break; - bChange = TRUE; + const OUString* pLayoutName = pMem->GetLayoutName(); + String aMemberName; + if (pLayoutName) + aMemberName = *pLayoutName; + else + aMemberName = aPosData.MemberName; + + String aNew = lcl_replaceMemberNameInSubtotal(rString, aMemberName); + pDim->SetSubtotalName(aNew); + bChange = true; } else - nErrorId = STR_INVALIDNAME; + { + // Check to make sure the member name isn't + // already used. + if (rString.Len()) + { + if (rString.EqualsIgnoreCaseAscii(pMem->GetName())) + { + pMem->RemoveLayoutName(); + bChange = true; + } + else if (!pDim->IsMemberNameInUse(rString)) + { + pMem->SetLayoutName(rString); + bChange = true; + } + else + nErrorId = STR_INVALIDNAME; + } + else + nErrorId = STR_INVALIDNAME; + } } + while (false); } } } + } - if ( bChange ) - { - // apply changes - ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); - ScDPObject* pNewObj = new ScDPObject( *pDPObj ); - pNewObj->SetSaveData( aData ); - aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE ); - delete pNewObj; - } - else - { - if ( !nErrorId ) - nErrorId = STR_ERR_DATAPILOT_INPUT; - ErrorMessage( nErrorId ); - } + if ( bChange ) + { + // apply changes + ScDBDocFunc aFunc( *GetViewData()->GetDocShell() ); + ScDPObject* pNewObj = new ScDPObject( *pDPObj ); + pNewObj->SetSaveData( aData ); + aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE ); + delete pNewObj; + } + else + { + if ( !nErrorId ) + nErrorId = STR_ERR_DATAPILOT_INPUT; + ErrorMessage( nErrorId ); } } @@ -1484,6 +1695,134 @@ void lcl_MoveToEnd( ScDPSaveDimension& rDim, const String& rItemName ) // puts it to the end of the list even if it was in the list before. } +bool ScDBFunc::DataPilotSort( const ScAddress& rPos, bool bAscending, sal_uInt16* pUserListId ) +{ + ScDocument* pDoc = GetViewData()->GetDocument(); + ScDPObject* pDPObj = pDoc->GetDPAtCursor(rPos.Col(), rPos.Row(), rPos.Tab()); + if (!pDPObj) + return false; + + // We need to run this to get all members later. + pDPObj->BuildAllDimensionMembers(); + + USHORT nOrientation; + long nDimIndex = pDPObj->GetHeaderDim(rPos, nOrientation); + if (nDimIndex < 0) + // Invalid dimension index. Bail out. + return false; + + BOOL bDataLayout; + ScDPSaveData* pSaveData = pDPObj->GetSaveData(); + if (!pSaveData) + return false; + + ScDPSaveData aNewSaveData(*pSaveData); + String aDimName = pDPObj->GetDimName(nDimIndex, bDataLayout); + ScDPSaveDimension* pSaveDim = aNewSaveData.GetDimensionByName(aDimName); + if (!pSaveDim) + return false; + + typedef ScDPSaveDimension::MemberList MemList; + const MemList& rDimMembers = pSaveDim->GetMembers(); + list<OUString> aMembers; + hash_set<OUString, ::rtl::OUStringHash> aMemberSet; + size_t nMemberCount = 0; + for (MemList::const_iterator itr = rDimMembers.begin(), itrEnd = rDimMembers.end(); + itr != itrEnd; ++itr) + { + ScDPSaveMember* pMem = *itr; + aMembers.push_back(pMem->GetName()); + aMemberSet.insert(pMem->GetName()); + ++nMemberCount; + } + + // Sort the member list in ascending order. + aMembers.sort(); + + // Collect and rank those custom sort strings that also exist in the member name list. + + typedef hash_map<OUString, sal_uInt16, OUStringHash> UserSortMap; + UserSortMap aSubStrs; + sal_uInt16 nSubCount = 0; + if (pUserListId) + { + ScUserList* pUserList = ScGlobal::GetUserList(); + if (!pUserList) + return false; + + { + sal_uInt16 n = pUserList->GetCount(); + if (!n || *pUserListId >= n) + return false; + } + + ScUserListData* pData = static_cast<ScUserListData*>((*pUserList)[*pUserListId]); + if (pData) + { + sal_uInt16 n = pData->GetSubCount(); + for (sal_uInt16 i = 0; i < n; ++i) + { + OUString aSub = pData->GetSubStr(i); + if (!aMemberSet.count(aSub)) + // This string doesn't exist in the member name set. Don't add this. + continue; + + aSubStrs.insert(UserSortMap::value_type(aSub, nSubCount++)); + } + } + } + + // Rank all members. + + vector<OUString> aRankedNames(nMemberCount); + sal_uInt16 nCurStrId = 0; + for (list<OUString>::const_iterator itr = aMembers.begin(), itrEnd = aMembers.end(); + itr != itrEnd; ++itr) + { + OUString aName = *itr; + sal_uInt16 nRank = 0; + UserSortMap::const_iterator itrSub = aSubStrs.find(aName); + if (itrSub == aSubStrs.end()) + nRank = nSubCount + nCurStrId++; + else + nRank = itrSub->second; + + if (!bAscending) + nRank = static_cast< sal_uInt16 >( nMemberCount - nRank - 1 ); + + aRankedNames[nRank] = aName; + } + + // Re-order ScDPSaveMember instances with the new ranks. + + for (vector<OUString>::const_iterator itr = aRankedNames.begin(), itrEnd = aRankedNames.end(); + itr != itrEnd; ++itr) + { + const ScDPSaveMember* pOldMem = pSaveDim->GetExistingMemberByName(*itr); + if (!pOldMem) + // All members are supposed to be present. + continue; + + ScDPSaveMember* pNewMem = new ScDPSaveMember(*pOldMem); + pSaveDim->AddMember(pNewMem); + } + + // Set the sorting mode to manual for now. We may introduce a new sorting + // mode later on. + + sheet::DataPilotFieldSortInfo aSortInfo; + aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL; + pSaveDim->SetSortInfo(&aSortInfo); + + // Update the datapilot with the newly sorted field members. + + auto_ptr<ScDPObject> pNewObj(new ScDPObject(*pDPObj)); + pNewObj->SetSaveData(aNewSaveData); + ScDBDocFunc aFunc(*GetViewData()->GetDocShell()); + + return aFunc.DataPilotUpdate(pDPObj, pNewObj.get(), true, false); +} + BOOL ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest ) { BOOL bRet = FALSE; @@ -1529,7 +1868,7 @@ BOOL ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest ) // get all member names in source order uno::Sequence<rtl::OUString> aMemberNames; - pDPObj->GetMembers( aDestData.Dimension, aMemberNames ); + pDPObj->GetMemberNames( aDestData.Dimension, aMemberNames ); bool bInserted = false; diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index aca88c554317..7f78461aedb0 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -121,6 +121,7 @@ #include "validat.hxx" #include "tabprotection.hxx" #include "postit.hxx" +#include "dpcontrol.hxx" #include "drawview.hxx" #include <svx/sdrpagewindow.hxx> @@ -369,6 +370,8 @@ ScGridWindow::ScGridWindow( Window* pParent, ScViewData* pData, ScSplitPos eWhic pNoteMarker( NULL ), pFilterBox( NULL ), pFilterFloat( NULL ), + mpDPFieldPopup(NULL), + mpFilterButton(NULL), nCursorHideCount( 0 ), bMarking( FALSE ), nButtonDown( 0 ), @@ -445,14 +448,26 @@ void __EXPORT ScGridWindow::Resize( const Size& ) void ScGridWindow::ClickExtern() { - // #i81298# don't delete the filter box when called from its select handler - // (possible through row header size update) - // #i84277# when initializing the filter box, a Basic error can deactivate the view - if ( pFilterBox && ( pFilterBox->IsInSelect() || pFilterBox->IsInInit() ) ) - return; + do + { + // #i81298# don't delete the filter box when called from its select handler + // (possible through row header size update) + // #i84277# when initializing the filter box, a Basic error can deactivate the view + if ( pFilterBox && ( pFilterBox->IsInSelect() || pFilterBox->IsInInit() ) ) + { + break; + } - DELETEZ(pFilterBox); - DELETEZ(pFilterFloat); + DELETEZ(pFilterBox); + DELETEZ(pFilterFloat); + } + while (false); + + if (mpDPFieldPopup.get()) + { + mpDPFieldPopup->close(false); + mpDPFieldPopup.reset(); + } } IMPL_LINK( ScGridWindow, PopupModeEndHdl, FloatingWindow*, EMPTYARG ) @@ -507,7 +522,7 @@ void ScGridWindow::ExecPageFieldSelect( SCCOL nCol, SCROW nRow, BOOL bHasSelecti } } -void ScGridWindow::DoPageFieldMenue( SCCOL nCol, SCROW nRow ) +void ScGridWindow::LaunchPageFieldMenu( SCCOL nCol, SCROW nRow ) { //! merge position/size handling with DoAutoFilterMenue @@ -658,6 +673,22 @@ void ScGridWindow::DoPageFieldMenue( SCCOL nCol, SCROW nRow ) CaptureMouse(); } +void ScGridWindow::LaunchDPFieldMenu( SCCOL nCol, SCROW nRow ) +{ + SCTAB nTab = pViewData->GetTabNo(); + ScDPObject* pDPObj = pViewData->GetDocument()->GetDPAtCursor(nCol, nRow, nTab); + if (!pDPObj) + return; + + // Get the geometry of the cell. + Point aScrPos = pViewData->GetScrPos(nCol, nRow, eWhich); + long nSizeX, nSizeY; + pViewData->GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY); + Size aScrSize(nSizeX-1, nSizeY-1); + + DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol, nRow, nTab), pDPObj); +} + void ScGridWindow::DoScenarioMenue( const ScRange& rScenRange ) { delete pFilterBox; @@ -1619,52 +1650,8 @@ void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt ) pDoc->GetAttr( nPosX, nPosY, nTab, ATTR_MERGE_FLAG ); if (pAttr->HasAutoFilter()) { - Point aScrPos = pViewData->GetScrPos(nPosX,nPosY,eWhich); - long nSizeX; - long nSizeY; - Point aDiffPix = aPos; - - aDiffPix -= aScrPos; - BOOL bLayoutRTL = pDoc->IsLayoutRTL( nTab ); - if ( bLayoutRTL ) - aDiffPix.X() = -aDiffPix.X(); - - pViewData->GetMergeSizePixel( nPosX, nPosY, nSizeX, nSizeY ); - - // Breite des Buttons ist nicht von der Zellhoehe abhaengig - Size aButSize = aComboButton.GetSizePixel(); - long nButWidth = Min( aButSize.Width(), nSizeX ); - long nButHeight = Min( aButSize.Height(), nSizeY ); - - if ( aDiffPix.X() >= nSizeX - nButWidth && - aDiffPix.Y() >= nSizeY - nButHeight ) - { - if ( DoPageFieldSelection( nPosX, nPosY ) ) - return; - - BOOL bFilterActive = IsAutoFilterActive( nPosX, nPosY, - pViewData->GetTabNo() ); - - aComboButton.SetOptSizePixel(); - DrawComboButton( aScrPos, nSizeX, nSizeY, bFilterActive, TRUE ); - -#if 0 - if ( bWasFilterBox - && (SCsCOL)nOldColFBox == nPosX - && (SCsROW)nOldRowFBox == nPosY ) - { - // Verhindern, dass an gleicher Stelle eine - // FilterBox geoeffnet wird, wenn diese gerade - // geloescht wurde - - nMouseStatus = SC_GM_FILTER; // fuer ButtonDraw im MouseButtonUp(); - return; - } -#endif - DoAutoFilterMenue( nPosX, nPosY, FALSE ); - + if (DoAutoFilterButton(nPosX, nPosY, rMEvt)) return; - } } if (pAttr->HasButton()) { @@ -1794,11 +1781,17 @@ void __EXPORT ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt ) { if ( pFilterBox && pFilterBox->GetMode() == SC_FILTERBOX_FILTER ) { - BOOL bFilterActive = IsAutoFilterActive( pFilterBox->GetCol(), pFilterBox->GetRow(), - pViewData->GetTabNo() ); - HideCursor(); - aComboButton.Draw( bFilterActive ); - ShowCursor(); + if (mpFilterButton.get()) + { + bool bFilterActive = IsAutoFilterActive( + pFilterBox->GetCol(), pFilterBox->GetRow(), pViewData->GetTabNo() ); + + mpFilterButton->setHasHiddenMember(bFilterActive); + mpFilterButton->setPopupPressed(false); + HideCursor(); + mpFilterButton->draw(); + ShowCursor(); + } } nMouseStatus = SC_GM_NONE; ReleaseMouse(); @@ -2218,9 +2211,14 @@ void __EXPORT ScGridWindow::MouseMove( const MouseEvent& rMEvt ) nMouseStatus = SC_GM_NONE; if ( pFilterBox->GetMode() == SC_FILTERBOX_FILTER ) { - HideCursor(); - aComboButton.Draw( FALSE ); - ShowCursor(); + if (mpFilterButton.get()) + { + mpFilterButton->setHasHiddenMember(false); + mpFilterButton->setPopupPressed(false); + HideCursor(); + mpFilterButton->draw(); + ShowCursor(); + } } ReleaseMouse(); pFilterBox->MouseButtonDown( MouseEvent( aRelPos, 1, MOUSE_SIMPLECLICK, MOUSE_LEFT ) ); diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx index 643928a7c8aa..e0dd63ff090e 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 ); diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx index d700ee606731..7719dfcc5474 100644 --- a/sc/source/ui/view/gridwin4.cxx +++ b/sc/source/ui/view/gridwin4.cxx @@ -73,6 +73,7 @@ #include "editutil.hxx" #include "inputopt.hxx" #include "fillinfo.hxx" +#include "dpcontrol.hxx" #include "sc.hrc" #include <vcl/virdev.hxx> @@ -1203,6 +1204,8 @@ void ScGridWindow::DrawButtons( SCCOL nX1, SCROW /*nY1*/, SCCOL nX2, SCROW /*nY2 { aComboButton.SetOutputDevice( pContentDev ); + ScDPFieldButton aCellBtn(pContentDev, &GetSettings().GetStyleSettings(), &pViewData->GetZoomX(), &pViewData->GetZoomY()); + SCCOL nCol; SCROW nRow; SCSIZE nArrY; @@ -1284,14 +1287,14 @@ void ScGridWindow::DrawButtons( SCCOL nX1, SCROW /*nY1*/, SCCOL nX2, SCROW /*nY2 bool bArrowState = bSimpleQuery && bColumnFound; long nSizeX; long nSizeY; - pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); - aComboButton.SetOptSizePixel(); - DrawComboButton( pViewData->GetScrPos( nCol, nRow, eWhich ), - nSizeX, nSizeY, bArrowState ); + Point aScrPos = pViewData->GetScrPos( nCol, nRow, eWhich ); - aComboButton.SetPosPixel( aOldPos ); // alten Zustand - aComboButton.SetSizePixel( aOldSize ); // fuer MouseUp/Down + aCellBtn.setBoundingBox(aScrPos, Size(nSizeX-1, nSizeY-1)); + aCellBtn.setDrawBaseButton(false); + aCellBtn.setDrawPopupButton(true); + aCellBtn.setHasHiddenMember(bArrowState); + aCellBtn.draw(); } } } @@ -1318,13 +1321,14 @@ void ScGridWindow::DrawButtons( SCCOL nX1, SCROW /*nY1*/, SCCOL nX2, SCROW /*nY2 nPosX -= nSizeX - 2; } - pContentDev->SetLineColor( GetSettings().GetStyleSettings().GetLightColor() ); - pContentDev->DrawLine( Point(nPosX,nPosY), Point(nPosX,nPosY+nSizeY-1) ); - pContentDev->DrawLine( Point(nPosX,nPosY), Point(nPosX+nSizeX-1,nPosY) ); - pContentDev->SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() ); - pContentDev->DrawLine( Point(nPosX,nPosY+nSizeY-1), Point(nPosX+nSizeX-1,nPosY+nSizeY-1) ); - pContentDev->DrawLine( Point(nPosX+nSizeX-1,nPosY), Point(nPosX+nSizeX-1,nPosY+nSizeY-1) ); - pContentDev->SetLineColor( COL_BLACK ); + String aStr; + pDoc->GetString(nCol, nRow, nTab, aStr); + aCellBtn.setText(aStr); + aCellBtn.setBoundingBox(Point(nPosX, nPosY), Size(nSizeX-1, nSizeY-1)); + aCellBtn.setDrawBaseButton(true); + aCellBtn.setDrawPopupButton(pInfo->bPopupButton); + aCellBtn.setHasHiddenMember(pInfo->bFilterActive); + aCellBtn.draw(); } } } diff --git a/sc/source/ui/view/makefile.mk b/sc/source/ui/view/makefile.mk index d8f45c8a754f..ed50324f68be 100644 --- a/sc/source/ui/view/makefile.mk +++ b/sc/source/ui/view/makefile.mk @@ -140,7 +140,6 @@ SLOFILES = \ $(SLO)$/dbfunc2.obj \ $(SLO)$/tabvwsh2.obj .ELSE - NOOPTFILES=\ $(SLO)$/drawview.obj \ $(SLO)$/dbfunc2.obj \ @@ -157,7 +156,8 @@ EXCEPTIONSFILES= \ $(SLO)$/cellsh1.obj \ $(SLO)$/drawvie4.obj \ $(SLO)$/formatsh.obj \ - $(SLO)$/scextopt.obj \ + $(SLO)$/gridwin2.obj \ + $(SLO)$/scextopt.obj \ $(SLO)$/tabvwshb.obj \ $(SLO)$/viewdata.obj \ $(SLO)$/viewfun5.obj \ diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx index 3077e852dbaf..c076575d4e6d 100644 --- a/sc/source/ui/view/tabview.cxx +++ b/sc/source/ui/view/tabview.cxx @@ -200,6 +200,8 @@ #include "AccessibilityHints.hxx" #include "appoptio.hxx" +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> + #include <string> #include <algorithm> @@ -212,6 +214,8 @@ // fuer Rad-Maus #define SC_DELTA_ZOOM 10 +using namespace ::com::sun::star; + // STATIC DATA ----------------------------------------------------------- @@ -2476,7 +2480,7 @@ sal_Bool ScTabView::HasPageFieldDataAtCursor() const SCCOL nCol = aViewData.GetCurX(); SCROW nRow = aViewData.GetCurY(); if (pWin) - return pWin->HasPageFieldData( nCol, nRow ); + return pWin->GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE; return sal_False; } @@ -2486,15 +2490,23 @@ void ScTabView::StartDataSelect() ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()]; SCCOL nCol = aViewData.GetCurX(); SCROW nRow = aViewData.GetCurY(); - if (pWin) - { - // #i36598# If the cursor is on a page field's data cell, - // no meaningful input is possible anyway, so this function - // can be used to select a page field entry. - if ( pWin->HasPageFieldData( nCol, nRow ) ) - pWin->DoPageFieldMenue( nCol, nRow ); - else + if (!pWin) + return; + + switch (pWin->GetDPFieldOrientation(nCol, nRow)) + { + case sheet::DataPilotFieldOrientation_PAGE: + // #i36598# If the cursor is on a page field's data cell, + // no meaningful input is possible anyway, so this function + // can be used to select a page field entry. + pWin->LaunchPageFieldMenu( nCol, nRow ); + break; + case sheet::DataPilotFieldOrientation_COLUMN: + case sheet::DataPilotFieldOrientation_ROW: + pWin->LaunchDPFieldMenu( nCol, nRow ); + break; + default: pWin->DoAutoFilterMenue( nCol, nRow, TRUE ); } } diff --git a/sc/util/makefile.mk b/sc/util/makefile.mk index 3c51d15634de..44d2ad9b490d 100644 --- a/sc/util/makefile.mk +++ b/sc/util/makefile.mk @@ -54,6 +54,7 @@ RESLIB1LIST=\ $(SRS)$/formdlgs.srs \ $(SRS)$/pagedlg.srs \ $(SRS)$/navipi.srs \ + $(SRS)$/cctrl.srs \ $(SOLARCOMMONRESDIR)$/sfx.srs RESLIB1NAME=sc |