diff options
author | Thomas Benisch <tbe@openoffice.org> | 2010-02-17 16:24:29 +0100 |
---|---|---|
committer | Thomas Benisch <tbe@openoffice.org> | 2010-02-17 16:24:29 +0100 |
commit | eee5ae330a49c18c4fe8666bc1c2dbc949dc0914 (patch) | |
tree | 8450428110c4300040e8d20bfba601bd231114da /sc/source/ui | |
parent | 6fae3f3921beb7214a77887e083852f27011179a (diff) | |
parent | 25b005cbda460837f063ddf996c1ec72d4f4865b (diff) |
chartlayout: merge with DEV300_m71
Diffstat (limited to 'sc/source/ui')
43 files changed, 4225 insertions, 275 deletions
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..0c663af87fd1 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx @@ -0,0 +1,401 @@ +/************************************************************************* + * + * 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 "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/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx index 4827366d3924..3ab36ce131ad 100644 --- a/sc/source/ui/docshell/docsh4.cxx +++ b/sc/source/ui/docshell/docsh4.cxx @@ -2145,15 +2145,20 @@ void ScDocShell::Print( SfxProgress& rProgress, PrintDialog* pPrintDialog, } } - if ( n+1 < nCollateCopies && pPrinter->GetDuplexMode() == DUPLEX_ON && ( nPrinted % 2 ) == 1 ) + if ( n+1 < nCollateCopies && + (pPrinter->GetDuplexMode() == DUPLEX_SHORTEDGE || pPrinter->GetDuplexMode() == DUPLEX_LONGEDGE) && + ( nPrinted % 2 ) == 1 ) { // #105584# when several collated copies are printed in duplex mode, and there is // an odd number of pages, print an empty page between copies, so the first page of // the second copy isn't printed on the back of the last page of the first copy. // (same as in Writer ViewShell::Prt) + // FIXME: needs to be adapted to XRenderable interface + #if 0 pPrinter->StartPage(); pPrinter->EndPage(); + #endif } } } 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/pfuncache.hxx b/sc/source/ui/inc/pfuncache.hxx index 93ff22fad0a8..a35084d453d6 100644 --- a/sc/source/ui/inc/pfuncache.hxx +++ b/sc/source/ui/inc/pfuncache.hxx @@ -34,6 +34,7 @@ #include <vector> #include <tools/gen.hxx> #include "rangelst.hxx" +#include "printopt.hxx" class ScDocShell; class ScMarkData; @@ -58,6 +59,7 @@ class ScPrintSelectionStatus { ScPrintSelectionMode eMode; ScRangeList aRanges; + ScPrintOptions aOptions; public: ScPrintSelectionStatus() : eMode(SC_PRINTSEL_INVALID) {} @@ -65,11 +67,13 @@ public: void SetMode(ScPrintSelectionMode eNew) { eMode = eNew; } void SetRanges(const ScRangeList& rNew) { aRanges = rNew; } + void SetOptions(const ScPrintOptions& rNew) { aOptions = rNew; } BOOL operator==(const ScPrintSelectionStatus& rOther) const - { return eMode == rOther.eMode && aRanges == rOther.aRanges; } + { return eMode == rOther.eMode && aRanges == rOther.aRanges && aOptions == rOther.aOptions; } ScPrintSelectionMode GetMode() const { return eMode; } + const ScPrintOptions& GetOptions() const { return aOptions; } }; 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/src/scstring.src b/sc/source/ui/src/scstring.src index efe9a0312b02..2dfcd84a4726 100644 --- a/sc/source/ui/src/scstring.src +++ b/sc/source/ui/src/scstring.src @@ -738,3 +738,29 @@ String SCSTR_MOREBTN_FEWEROPTIONS Text [ en-US ] = "Fewer ~Options"; }; +StringArray SCSTR_PRINT_OPTIONS +{ + ItemList [en-US] = + { + < "Pages"; >; + < "~Include output of empty pages"; >; + < "If checked empty pages that have no cell contents or draw objects are not printed."; >; + < "Sheets"; >; + < "Print ~only selected sheets"; >; + < "If checked only contents from selected sheets are printed, even if you specify a wider range in the Format - Print Ranges dialog. Content from sheets that are not selected will not be printed."; >; + < "Print content"; >; + < "~All sheets"; >; + < "The printout will be created from all sheets in the document."; >; + < "~Selected sheets"; >; + < "The printout will be created only from the currently selected sheets."; >; + < "Selected cells"; >; + < "The printout will be created only from the currently selected cells."; >; + < "Thereof print"; >; + < "All ~pages"; >; + < "Print all pages of the printable content."; >; + < "Pa~ges"; >; + < "Print only some pages of the printable content."; >; + < "%PRODUCTNAME %s"; >; + }; +}; + 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/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx index 5f4f1a7aa93f..71f4706085d8 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -43,12 +43,14 @@ #include <svl/numuno.hxx> #include <svl/smplhint.hxx> #include <unotools/undoopt.hxx> +#include <unotools/moduleoptions.hxx> #include <sfx2/printer.hxx> #include <sfx2/bindings.hxx> #include <vcl/pdfextoutdevdata.hxx> #include <vcl/waitobj.hxx> #include <unotools/charclass.hxx> #include <tools/multisel.hxx> +#include <tools/resary.hxx> #include <toolkit/awt/vclxdevice.hxx> #include <ctype.h> #include <float.h> // DBL_MAX @@ -90,11 +92,15 @@ #include "unoguard.hxx" #include "unonames.hxx" #include "shapeuno.hxx" +#include "viewuno.hxx" +#include "tabvwsh.hxx" #include "printfun.hxx" #include "pfuncache.hxx" #include "scmod.hxx" #include "rangeutl.hxx" #include "ViewSettingsSequenceDefines.hxx" +#include "sc.hrc" +#include "scresid.hxx" #ifndef _SVX_UNOSHAPE_HXX #include <svx/unoshape.hxx> @@ -209,6 +215,147 @@ SC_SIMPLE_SERVICE_INFO( ScTableSheetsObj, "ScTableSheetsObj", "com.sun.star.shee //------------------------------------------------------------------------ +class ScPrintUIOptions : public vcl::PrinterOptionsHelper +{ +public: + ScPrintUIOptions(); + void SetDefaults(); +}; + +ScPrintUIOptions::ScPrintUIOptions() +{ + const ScPrintOptions& rPrintOpt = SC_MOD()->GetPrintOptions(); + sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1; + sal_Bool bSuppress = rPrintOpt.GetSkipEmpty(); + + ResStringArray aStrings( ScResId( SCSTR_PRINT_OPTIONS ) ); + DBG_ASSERT( aStrings.Count() >= 19, "resource incomplete" ); + if( aStrings.Count() < 19 ) // bad resource ? + return; + + m_aUIProperties.realloc( 8 ); + + // create Section for spreadsheet (results in an extra tab page in dialog) + SvtModuleOptions aOpt; + String aAppGroupname( aStrings.GetString( 18 ) ); + aAppGroupname.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "%s" ) ), + aOpt.GetModuleName( SvtModuleOptions::E_SCALC ) ); + m_aUIProperties[0].Value = getGroupControlOpt( aAppGroupname, rtl::OUString() ); + + // create subgroup for pages + m_aUIProperties[1].Value = getSubgroupControlOpt( rtl::OUString( aStrings.GetString( 0 ) ), rtl::OUString() ); + + // create a bool option for empty pages + m_aUIProperties[2].Value = getBoolControlOpt( rtl::OUString( aStrings.GetString( 1 ) ), + rtl::OUString( aStrings.GetString( 2 ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsIncludeEmptyPages" ) ), + ! bSuppress + ); + // create Subgroup for print content + vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt; + aPrintRangeOpt.maGroupHint = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintRange" ) ); + m_aUIProperties[3].Value = getSubgroupControlOpt( rtl::OUString( aStrings.GetString( 6 ) ), + rtl::OUString(), + aPrintRangeOpt + ); + + // create a choice for the content to create + uno::Sequence< rtl::OUString > aChoices( 3 ), aHelpTexts( 3 ); + aChoices[0] = aStrings.GetString( 7 ); + aHelpTexts[0] = aStrings.GetString( 8 ); + aChoices[1] = aStrings.GetString( 9 ); + aHelpTexts[1] = aStrings.GetString( 10 ); + aChoices[2] = aStrings.GetString( 11 ); + aHelpTexts[2] = aStrings.GetString( 12 ); + m_aUIProperties[4].Value = getChoiceControlOpt( rtl::OUString(), + aHelpTexts, + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintContent" ) ), + aChoices, + nContent ); + + // create Subgroup for print range + aPrintRangeOpt.mbInternalOnly = sal_True; + m_aUIProperties[5].Value = getSubgroupControlOpt( rtl::OUString( aStrings.GetString( 13 ) ), + rtl::OUString(), + aPrintRangeOpt + ); + + // create a choice for the range to print + rtl::OUString aPrintRangeName( RTL_CONSTASCII_USTRINGPARAM( "PrintRange" ) ); + aChoices.realloc( 2 ); + aHelpTexts.realloc( 2 ); + aChoices[0] = aStrings.GetString( 14 ); + aHelpTexts[0] = aStrings.GetString( 15 ); + aChoices[1] = aStrings.GetString( 16 ); + aHelpTexts[1] = aStrings.GetString( 17 ); + m_aUIProperties[6].Value = getChoiceControlOpt( rtl::OUString(), + aHelpTexts, + aPrintRangeName, + aChoices, + 0 ); + + // create a an Edit dependent on "Pages" selected + vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, sal_True ); + m_aUIProperties[7].Value = getEditControlOpt( rtl::OUString(), + rtl::OUString(), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ), + rtl::OUString(), + aPageRangeOpt + ); + + // "Print only selected sheets" isn't needed because of the "Selected Sheets" choice in "Print content" +#if 0 + // create subgroup for sheets + m_aUIProperties[8].Value = getSubgroupControlOpt( rtl::OUString( aStrings.GetString( 3 ) ), rtl::OUString() ); + + // create a bool option for selected pages only + m_aUIProperties[9].Value = getBoolControlOpt( rtl::OUString( aStrings.GetString( 4 ) ), + rtl::OUString( aStrings.GetString( 5 ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsOnlySelectedSheets" ) ), + i_bSelectedOnly + ); +#endif +} + +void ScPrintUIOptions::SetDefaults() +{ + // re-initialize the default values from print options + + const ScPrintOptions& rPrintOpt = SC_MOD()->GetPrintOptions(); + sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1; + sal_Bool bSuppress = rPrintOpt.GetSkipEmpty(); + + for (sal_Int32 nUIPos=0; nUIPos<m_aUIProperties.getLength(); ++nUIPos) + { + uno::Sequence<beans::PropertyValue> aUIProp; + if ( m_aUIProperties[nUIPos].Value >>= aUIProp ) + { + for (sal_Int32 nPropPos=0; nPropPos<aUIProp.getLength(); ++nPropPos) + { + rtl::OUString aName = aUIProp[nPropPos].Name; + if ( aName.equalsAscii("Property") ) + { + beans::PropertyValue aPropertyValue; + if ( aUIProp[nPropPos].Value >>= aPropertyValue ) + { + if ( aPropertyValue.Name.equalsAscii( "PrintContent" ) ) + { + aPropertyValue.Value <<= nContent; + aUIProp[nPropPos].Value <<= aPropertyValue; + } + else if ( aPropertyValue.Name.equalsAscii( "IsIncludeEmptyPages" ) ) + { + ScUnoHelpFunctions::SetBoolInAny( aPropertyValue.Value, ! bSuppress ); + aUIProp[nPropPos].Value <<= aPropertyValue; + } + } + } + } + m_aUIProperties[nUIPos].Value <<= aUIProp; + } + } +} + // static void ScModelObj::CreateAndSet(ScDocShell* pDocSh) { @@ -221,6 +368,7 @@ ScModelObj::ScModelObj( ScDocShell* pDocSh ) : aPropSet( lcl_GetDocOptPropertyMap() ), pDocShell( pDocSh ), pPrintFuncCache( NULL ), + pPrinterOptions( NULL ), maChangesListeners( m_aMutex ), mnXlsWriteProtPass( 0 ) { @@ -240,6 +388,7 @@ ScModelObj::~ScModelObj() xNumberAgg->setDelegator(uno::Reference<uno::XInterface>()); delete pPrintFuncCache; + delete pPrinterOptions; } uno::Reference< uno::XAggregation> ScModelObj::GetFormatter() @@ -599,20 +748,65 @@ bool lcl_ParseTarget( const String& rTarget, ScRange& rTargetRange, Rectangle& r return bRangeValid; } -BOOL ScModelObj::FillRenderMarkData( const uno::Any& aSelection, ScMarkData& rMark, - ScPrintSelectionStatus& rStatus ) const +BOOL ScModelObj::FillRenderMarkData( const uno::Any& aSelection, + const uno::Sequence< beans::PropertyValue >& rOptions, + ScMarkData& rMark, + ScPrintSelectionStatus& rStatus, String& rPagesStr ) const { DBG_ASSERT( !rMark.IsMarked() && !rMark.IsMultiMarked(), "FillRenderMarkData: MarkData must be empty" ); DBG_ASSERT( pDocShell, "FillRenderMarkData: DocShell must be set" ); BOOL bDone = FALSE; + uno::Reference<frame::XController> xView; + + // defaults when no options are passed: all sheets, include empty pages + sal_Bool bSelectedSheetsOnly = sal_False; + sal_Bool bIncludeEmptyPages = sal_True; + + bool bHasPrintContent = false; + sal_Int32 nPrintContent = 0; // all sheets / selected sheets / selected cells + sal_Int32 nPrintRange = 0; // all pages / pages + rtl::OUString aPageRange; // "pages" edit value + + for( sal_Int32 i = 0, nLen = rOptions.getLength(); i < nLen; i++ ) + { + if( rOptions[i].Name.equalsAscii( "IsOnlySelectedSheets" ) ) + { + rOptions[i].Value >>= bSelectedSheetsOnly; + } + else if( rOptions[i].Name.equalsAscii( "IsIncludeEmptyPages" ) ) + { + rOptions[i].Value >>= bIncludeEmptyPages; + } + else if( rOptions[i].Name.equalsAscii( "PageRange" ) ) + { + rOptions[i].Value >>= aPageRange; + } + else if( rOptions[i].Name.equalsAscii( "PrintRange" ) ) + { + rOptions[i].Value >>= nPrintRange; + } + else if( rOptions[i].Name.equalsAscii( "PrintContent" ) ) + { + bHasPrintContent = true; + rOptions[i].Value >>= nPrintContent; + } + else if( rOptions[i].Name.equalsAscii( "View" ) ) + { + rOptions[i].Value >>= xView; + } + } + + // "Print Content" selection wins over "Selected Sheets" option + if ( bHasPrintContent ) + bSelectedSheetsOnly = ( nPrintContent != 0 ); + uno::Reference<uno::XInterface> xInterface(aSelection, uno::UNO_QUERY); if ( xInterface.is() ) { ScCellRangesBase* pSelObj = ScCellRangesBase::getImplementation( xInterface ); uno::Reference< drawing::XShapes > xShapes( xInterface, uno::UNO_QUERY ); - if ( pSelObj && pSelObj->GetDocShell() == pDocShell ) { BOOL bSheet = ( ScTableSheetObj::getImplementation( xInterface ) != NULL ); @@ -685,12 +879,41 @@ BOOL ScModelObj::FillRenderMarkData( const uno::Any& aSelection, ScMarkData& rMa // other selection types aren't supported } + // restrict to selected sheets if a view is available + if ( bSelectedSheetsOnly && xView.is() ) + { + ScTabViewObj* pViewObj = ScTabViewObj::getImplementation( xView ); + if (pViewObj) + { + ScTabViewShell* pViewSh = pViewObj->GetViewShell(); + if (pViewSh) + { + const ScMarkData& rViewMark = pViewSh->GetViewData()->GetMarkData(); + SCTAB nTabCount = pDocShell->GetDocument()->GetTableCount(); + for (SCTAB nTab = 0; nTab < nTabCount; nTab++) + if (!rViewMark.GetTableSelect(nTab)) + rMark.SelectTable( nTab, FALSE ); + } + } + } + + ScPrintOptions aNewOptions; + aNewOptions.SetSkipEmpty( !bIncludeEmptyPages ); + aNewOptions.SetAllSheets( !bSelectedSheetsOnly ); + rStatus.SetOptions( aNewOptions ); + + // "PrintRange" enables (1) or disables (0) the "PageRange" edit + if ( nPrintRange == 1 ) + rPagesStr = aPageRange; + else + rPagesStr.Erase(); + return bDone; } sal_Int32 SAL_CALL ScModelObj::getRendererCount( const uno::Any& aSelection, - const uno::Sequence<beans::PropertyValue>& /* xOptions */ ) + const uno::Sequence<beans::PropertyValue>& rOptions ) throw (lang::IllegalArgumentException, uno::RuntimeException) { ScUnoGuard aGuard; @@ -699,7 +922,8 @@ sal_Int32 SAL_CALL ScModelObj::getRendererCount( const uno::Any& aSelection, ScMarkData aMark; ScPrintSelectionStatus aStatus; - if ( !FillRenderMarkData( aSelection, aMark, aStatus ) ) + String aPagesStr; + if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr ) ) return 0; // The same ScPrintFuncCache object in pPrintFuncCache is used as long as @@ -711,11 +935,37 @@ sal_Int32 SAL_CALL ScModelObj::getRendererCount( const uno::Any& aSelection, delete pPrintFuncCache; pPrintFuncCache = new ScPrintFuncCache( pDocShell, aMark, aStatus ); } - return pPrintFuncCache->GetPageCount(); + sal_Int32 nPages = pPrintFuncCache->GetPageCount(); + + sal_Int32 nSelectCount = nPages; + if ( aPagesStr.Len() ) + { + MultiSelection aPageRanges( aPagesStr ); + aPageRanges.SetTotalRange( Range( 1, nPages ) ); + nSelectCount = aPageRanges.GetSelectCount(); + } + return nSelectCount; } -uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 nRenderer, - const uno::Any& aSelection, const uno::Sequence<beans::PropertyValue>& /* xOptions */ ) +sal_Int32 lcl_GetRendererNum( sal_Int32 nSelRenderer, const String& rPagesStr, sal_Int32 nTotalPages ) +{ + if ( !rPagesStr.Len() ) + return nSelRenderer; + + MultiSelection aPageRanges( rPagesStr ); + aPageRanges.SetTotalRange( Range( 1, nTotalPages ) ); + + sal_Int32 nSelected = aPageRanges.FirstSelected(); + while ( nSelRenderer > 0 ) + { + nSelected = aPageRanges.NextSelected(); + --nSelRenderer; + } + return nSelected - 1; // selection is 1-based +} + +uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 nSelRenderer, + const uno::Any& aSelection, const uno::Sequence<beans::PropertyValue>& rOptions ) throw (lang::IllegalArgumentException, uno::RuntimeException) { ScUnoGuard aGuard; @@ -724,7 +974,8 @@ uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 ScMarkData aMark; ScPrintSelectionStatus aStatus; - if ( !FillRenderMarkData( aSelection, aMark, aStatus ) ) + String aPagesStr; + if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr ) ) throw lang::IllegalArgumentException(); if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) ) @@ -733,8 +984,33 @@ uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 pPrintFuncCache = new ScPrintFuncCache( pDocShell, aMark, aStatus ); } long nTotalPages = pPrintFuncCache->GetPageCount(); + sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages ); if ( nRenderer >= nTotalPages ) - throw lang::IllegalArgumentException(); + { + if ( nSelRenderer == 0 ) + { + // getRenderer(0) is used to query the settings, so it must always return something + + SCTAB nCurTab = 0; //! use current sheet from view? + ScPrintFunc aDefaultFunc( pDocShell, pDocShell->GetPrinter(), nCurTab ); + Size aTwips = aDefaultFunc.GetPageSize(); + awt::Size aPageSize( TwipsToHMM( aTwips.Width() ), TwipsToHMM( aTwips.Height() ) ); + + uno::Sequence<beans::PropertyValue> aSequence(1); + beans::PropertyValue* pArray = aSequence.getArray(); + pArray[0].Name = rtl::OUString::createFromAscii( SC_UNONAME_PAGESIZE ); + pArray[0].Value <<= aPageSize; + + if( ! pPrinterOptions ) + pPrinterOptions = new ScPrintUIOptions; + else + pPrinterOptions->SetDefaults(); + pPrinterOptions->appendPrintUIOptions( aSequence ); + return aSequence; + } + else + throw lang::IllegalArgumentException(); + } // printer is used as device (just for page layout), draw view is not needed @@ -748,7 +1024,7 @@ uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 pSelRange = &aRange; } ScPrintFunc aFunc( pDocShell, pDocShell->GetPrinter(), nTab, - pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange ); + pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange, &aStatus.GetOptions() ); aFunc.SetRenderFlag( TRUE ); Range aPageRange( nRenderer+1, nRenderer+1 ); @@ -779,10 +1055,21 @@ uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 pArray[1].Name = rtl::OUString::createFromAscii( SC_UNONAME_SOURCERANGE ); pArray[1].Value <<= aRangeAddress; } + + #if 0 + const ScPrintOptions& rPrintOpt = + #endif + // FIXME: is this for side effects ? + SC_MOD()->GetPrintOptions(); + if( ! pPrinterOptions ) + pPrinterOptions = new ScPrintUIOptions; + else + pPrinterOptions->SetDefaults(); + pPrinterOptions->appendPrintUIOptions( aSequence ); return aSequence; } -void SAL_CALL ScModelObj::render( sal_Int32 nRenderer, const uno::Any& aSelection, +void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelection, const uno::Sequence<beans::PropertyValue>& rOptions ) throw(lang::IllegalArgumentException, uno::RuntimeException) { @@ -792,7 +1079,8 @@ void SAL_CALL ScModelObj::render( sal_Int32 nRenderer, const uno::Any& aSelectio ScMarkData aMark; ScPrintSelectionStatus aStatus; - if ( !FillRenderMarkData( aSelection, aMark, aStatus ) ) + String aPagesStr; + if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr ) ) throw lang::IllegalArgumentException(); if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) ) @@ -801,6 +1089,7 @@ void SAL_CALL ScModelObj::render( sal_Int32 nRenderer, const uno::Any& aSelectio pPrintFuncCache = new ScPrintFuncCache( pDocShell, aMark, aStatus ); } long nTotalPages = pPrintFuncCache->GetPageCount(); + sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages ); if ( nRenderer >= nTotalPages ) throw lang::IllegalArgumentException(); @@ -835,7 +1124,7 @@ void SAL_CALL ScModelObj::render( sal_Int32 nRenderer, const uno::Any& aSelectio // to increase performance, ScPrintState might be used here for subsequent // pages of the same sheet - ScPrintFunc aFunc( pDev, pDocShell, nTab, pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange ); + ScPrintFunc aFunc( pDev, pDocShell, nTab, pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange, &aStatus.GetOptions() ); aFunc.SetDrawView( pDrawView ); aFunc.SetRenderFlag( TRUE ); if( aStatus.GetMode() == SC_PRINTSEL_RANGE_EXCLUSIVELY_OLE_AND_DRAW_OBJECTS ) @@ -849,11 +1138,11 @@ void SAL_CALL ScModelObj::render( sal_Int32 nRenderer, const uno::Any& aSelectio long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab ); long nTabStart = pPrintFuncCache->GetTabStart( nTab ); + vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); if ( nRenderer == nTabStart ) { // first page of a sheet: add outline item for the sheet name - vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); if ( pPDFData && pPDFData->GetIsExportBookmarks() ) { // the sheet starts at the top of the page @@ -866,7 +1155,7 @@ void SAL_CALL ScModelObj::render( sal_Int32 nRenderer, const uno::Any& aSelectio } //--->i56629 // add the named destination stuff - if( pPDFData->GetIsExportNamedDestinations() ) + if( pPDFData && pPDFData->GetIsExportNamedDestinations() ) { Rectangle aArea( pDev->PixelToLogic( Rectangle( 0,0,0,0 ) ) ); String aTabName; @@ -881,7 +1170,6 @@ void SAL_CALL ScModelObj::render( sal_Int32 nRenderer, const uno::Any& aSelectio // resolve the hyperlinks for PDF export - vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() ); if ( pPDFData ) { // iterate over the hyperlinks that were output for this page 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/unoobj/viewuno.cxx b/sc/source/ui/unoobj/viewuno.cxx index c1af5ac9bb99..0883c24a14f0 100644 --- a/sc/source/ui/unoobj/viewuno.cxx +++ b/sc/source/ui/unoobj/viewuno.cxx @@ -337,11 +337,11 @@ namespace } // XFormLayerAccess -uno::Reference< form::XFormController > SAL_CALL ScViewPaneBase::getFormController( const uno::Reference< form::XForm >& _Form ) throw (uno::RuntimeException) +uno::Reference< form::runtime::XFormController > SAL_CALL ScViewPaneBase::getFormController( const uno::Reference< form::XForm >& _Form ) throw (uno::RuntimeException) { ScUnoGuard aGuard; - uno::Reference< form::XFormController > xController; + uno::Reference< form::runtime::XFormController > xController; Window* pWindow( NULL ); SdrView* pSdrView( NULL ); 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/gridwin3.cxx b/sc/source/ui/view/gridwin3.cxx index 6683a75e777b..fbff54b1408f 100644..100755 --- a/sc/source/ui/view/gridwin3.cxx +++ b/sc/source/ui/view/gridwin3.cxx @@ -215,6 +215,7 @@ void ScGridWindow::DrawRedraw( ScOutputData& rOutputData, ScUpdateMode eMode, UL pDrView->setHideOle(!bDrawOle); pDrView->setHideChart(!bDrawChart); pDrView->setHideDraw(!bDrawDraw); + pDrView->setHideFormControl(!bDrawDraw); } if(SC_UPDATE_CHANGED == eMode) 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/olkact.cxx b/sc/source/ui/view/olkact.cxx index 31f5297e92fe..3feb69044f43 100644 --- a/sc/source/ui/view/olkact.cxx +++ b/sc/source/ui/view/olkact.cxx @@ -229,7 +229,7 @@ //#define _SVDLAYER_HXX //#define _SVDRAG_HXX #define _SVINCVW_HXX -#define _SV_MULTISEL_HXX +//#define _SV_MULTISEL_HXX #define _SVRTV_HXX #define _SVTABBX_HXX diff --git a/sc/source/ui/view/output3.cxx b/sc/source/ui/view/output3.cxx index c4c51fb3f02a..ffc1112667f2 100644..100755 --- a/sc/source/ui/view/output3.cxx +++ b/sc/source/ui/view/output3.cxx @@ -166,7 +166,8 @@ void ScOutputData::PrintDrawingLayer(const sal_uInt16 nLayer, const Point& rMMOf if(pLocalDrawView) { - bHideAllDrawingLayer = pLocalDrawView->getHideOle() && pLocalDrawView->getHideChart() && pLocalDrawView->getHideDraw(); + bHideAllDrawingLayer = pLocalDrawView->getHideOle() && pLocalDrawView->getHideChart() + && pLocalDrawView->getHideDraw() && pLocalDrawView->getHideFormControl(); } } diff --git a/sc/source/ui/view/pfuncache.cxx b/sc/source/ui/view/pfuncache.cxx index 4712b6a3cf85..ef014bd90f79 100644 --- a/sc/source/ui/view/pfuncache.cxx +++ b/sc/source/ui/view/pfuncache.cxx @@ -75,7 +75,7 @@ ScPrintFuncCache::ScPrintFuncCache( ScDocShell* pD, const ScMarkData& rMark, long nThisTab = 0; if ( rMark.GetTableSelect( nTab ) ) { - ScPrintFunc aFunc( pDocSh, pPrinter, nTab, nAttrPage, 0, pSelRange ); + ScPrintFunc aFunc( pDocSh, pPrinter, nTab, nAttrPage, 0, pSelRange, &aSelection.GetOptions() ); nThisTab = aFunc.GetTotalPages(); nFirstAttr[nTab] = aFunc.GetFirstPageNo(); // from page style or previous sheet } @@ -113,7 +113,7 @@ void ScPrintFuncCache::InitLocations( const ScMarkData& rMark, OutputDevice* pDe { if ( rMark.GetTableSelect( nTab ) ) { - ScPrintFunc aFunc( pDev, pDocSh, nTab, nFirstAttr[nTab], nTotalPages, pSelRange ); + ScPrintFunc aFunc( pDev, pDocSh, nTab, nFirstAttr[nTab], nTotalPages, pSelRange, &aSelection.GetOptions() ); aFunc.SetRenderFlag( TRUE ); long nDisplayStart = GetDisplayStart( nTab ); diff --git a/sc/source/ui/view/prevwsh2.cxx b/sc/source/ui/view/prevwsh2.cxx index 58dc2d913c58..d37d0c85046d 100644 --- a/sc/source/ui/view/prevwsh2.cxx +++ b/sc/source/ui/view/prevwsh2.cxx @@ -67,7 +67,7 @@ //#define _FSYS_HXX //#define _STREAM_HXX #define _CACHESTR_HXX -#define _SV_MULTISEL_HXX +//#define _SV_MULTISEL_HXX //SV //#define _CLIP_HXX *** diff --git a/sc/source/ui/view/printfun.cxx b/sc/source/ui/view/printfun.cxx index b7b8b9fbadf6..9c8b1f1d4ce6 100644..100755 --- a/sc/source/ui/view/printfun.cxx +++ b/sc/source/ui/view/printfun.cxx @@ -1648,7 +1648,8 @@ void ScPrintFunc::PrintArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, // test if all paint parts are hidden, then a paint is not necessary at all const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY)); - const bool bHideAllDrawingLayer(pDrawView && pDrawView->getHideOle() && pDrawView->getHideChart() && pDrawView->getHideDraw()); + const bool bHideAllDrawingLayer( pDrawView && pDrawView->getHideOle() && pDrawView->getHideChart() + && pDrawView->getHideDraw() && pDrawView->getHideFormControl() ); if(!bHideAllDrawingLayer) { @@ -2043,7 +2044,10 @@ long ScPrintFunc::PrintNotes( long nPageNo, long nNoteStart, BOOL bDoPrint, ScPr } if ( pPrinter && bDoPrint ) - pPrinter->StartPage(); + { + DBG_ERROR( "StartPage does not exist anymore" ); + // pPrinter->StartPage(); + } if ( bDoPrint || pLocationData ) { @@ -2064,7 +2068,10 @@ long ScPrintFunc::PrintNotes( long nPageNo, long nNoteStart, BOOL bDoPrint, ScPr long nCount = DoNotes( nNoteStart, bDoPrint, pLocationData ); if ( pPrinter && bDoPrint ) - pPrinter->EndPage(); + { + DBG_ERROR( "EndPage does not exist anymore" ); + // pPrinter->EndPage(); + } return nCount; } @@ -2123,10 +2130,14 @@ void ScPrintFunc::PrintPage( long nPageNo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCRO pDrawView->setHideOle(!aTableParam.bObjects); pDrawView->setHideChart(!aTableParam.bCharts); pDrawView->setHideDraw(!aTableParam.bDrawings); + pDrawView->setHideFormControl(!aTableParam.bDrawings); } if ( pPrinter && bDoPrint ) - pPrinter->StartPage(); + { + DBG_ERROR( "StartPage does not exist anymore" ); + // pPrinter->StartPage(); + } // Kopf- und Fusszeilen (ohne Zentrierung) @@ -2408,7 +2419,10 @@ void ScPrintFunc::PrintPage( long nPageNo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCRO } if ( pPrinter && bDoPrint ) - pPrinter->EndPage(); + { + DBG_ERROR( "EndPage does not exist anymore" ); + // pPrinter->EndPage(); + } aLastSourceRange = ScRange( nX1, nY1, nPrintTab, nX2, nY2, nPrintTab ); bSourceRangeValid = TRUE; 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/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx index 3327ea3fe88d..6c0408c8c33f 100644 --- a/sc/source/ui/view/viewfun3.cxx +++ b/sc/source/ui/view/viewfun3.cxx @@ -142,7 +142,7 @@ #define _SVDRAG_HXX #define _SVINCVW_HXX -#define _SV_MULTISEL_HXX +//#define _SV_MULTISEL_HXX #define _SVRTV_HXX #define _SVTABBX_HXX #define _SVTREEBOX_HXX |