diff options
Diffstat (limited to 'sfx2/source/sidebar/SidebarController.cxx')
-rw-r--r-- | sfx2/source/sidebar/SidebarController.cxx | 448 |
1 files changed, 326 insertions, 122 deletions
diff --git a/sfx2/source/sidebar/SidebarController.cxx b/sfx2/source/sidebar/SidebarController.cxx index c4584422856c..7a6ef5e20192 100644 --- a/sfx2/source/sidebar/SidebarController.cxx +++ b/sfx2/source/sidebar/SidebarController.cxx @@ -23,6 +23,7 @@ #include "SidebarResource.hxx" #include "TabBar.hxx" #include "sfx2/sidebar/Theme.hxx" +#include "sfx2/sidebar/SidebarChildWindow.hxx" #include "SidebarDockingWindow.hxx" #include "Context.hxx" #include "Tools.hxx" @@ -32,6 +33,7 @@ #include "sfx2/titledockwin.hxx" #include "sfxlocal.hrc" #include <vcl/floatwin.hxx> +#include <vcl/fixed.hxx> #include "splitwin.hxx" #include <svl/smplhint.hxx> #include <tools/link.hxx> @@ -61,6 +63,15 @@ using ::rtl::OUString; #undef VERBOSE +namespace +{ + const static OUString gsReadOnlyCommandName (A2S(".uno:EditDoc")); + const static sal_Int32 gnMaximumSidebarWidth (400); + const static sal_Int32 gnWidthCloseThreshold (70); + const static sal_Int32 gnWidthOpenThreshold (40); +} + + namespace sfx2 { namespace sidebar { namespace { @@ -85,15 +96,22 @@ SidebarController::SidebarController ( mpTabBar(new TabBar( mpParentWindow, rxFrame, - ::boost::bind(&SidebarController::SwitchToDeck, this, _1), + ::boost::bind(&SidebarController::OpenThenSwitchToDeck, this, _1), ::boost::bind(&SidebarController::ShowPopupMenu, this, _1,_2,_3))), mxFrame(rxFrame), maCurrentContext(OUString(), OUString()), msCurrentDeckId(A2S("PropertyDeck")), maPropertyChangeForwarder(::boost::bind(&SidebarController::BroadcastPropertyChange, this)), maContextChangeUpdate(::boost::bind(&SidebarController::UpdateConfigurations, this)), - mbIsDeckClosed(false), - mnSavedSidebarWidth(pParentWindow->GetSizePixel().Width()) + mbIsDeckRequestedOpen(), + mbIsDeckOpen(), + mbCanDeckBeOpened(true), + mnSavedSidebarWidth(pParentWindow->GetSizePixel().Width()), + mxReadOnlyModeDispatch(), + mbIsDocumentReadOnly(false), + mpSplitWindow(NULL), + mnWidthOnSplitterButtonDown(0), + mpCloseIndicator() { if (pParentWindow == NULL) { @@ -118,6 +136,13 @@ SidebarController::SidebarController ( A2S(""), static_cast<css::beans::XPropertyChangeListener*>(this)); + // Get the dispatch object as preparation to listen for changes of + // the read-only state. + const util::URL aURL (GetURL(gsReadOnlyCommandName)); + mxReadOnlyModeDispatch = GetDispatch(aURL); + if (mxReadOnlyModeDispatch.is()) + mxReadOnlyModeDispatch->addStatusListener(this, aURL); + SwitchToDeck(A2S("default")); } @@ -142,6 +167,14 @@ void SAL_CALL SidebarController::disposing (void) xMultiplexer->removeAllContextChangeEventListeners( static_cast<css::ui::XContextChangeEventListener*>(this)); + if (mxReadOnlyModeDispatch.is()) + mxReadOnlyModeDispatch->removeStatusListener(this, GetURL(gsReadOnlyCommandName)); + if (mpSplitWindow != NULL) + { + mpSplitWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler)); + mpSplitWindow = NULL; + } + if (mpParentWindow != NULL) { mpParentWindow->RemoveEventListener(LINK(this, SidebarController, WindowEventHandler)); @@ -203,6 +236,25 @@ void SAL_CALL SidebarController::propertyChange (const css::beans::PropertyChang +void SAL_CALL SidebarController::statusChanged (const css::frame::FeatureStateEvent& rEvent) + throw(cssu::RuntimeException) +{ + bool bIsReadWrite (true); + if (rEvent.IsEnabled) + rEvent.State >>= bIsReadWrite; + + if (mbIsDocumentReadOnly != !bIsReadWrite) + { + mbIsDocumentReadOnly = !bIsReadWrite; + + // Force the current deck to update its panel list. + SwitchToDeck(msCurrentDeckId); + } +} + + + + void SAL_CALL SidebarController::requestLayout (void) throw(cssu::RuntimeException) { @@ -237,12 +289,36 @@ void SidebarController::NotifyResize (void) const sal_Int32 nWidth (pParentWindow->GetSizePixel().Width()); const sal_Int32 nHeight (pParentWindow->GetSizePixel().Height()); + mbIsDeckOpen = (nWidth > TabBar::GetDefaultWidth()); + + if (mnSavedSidebarWidth <= 0) + mnSavedSidebarWidth = nWidth; + + bool bIsDeckVisible; + if (mbCanDeckBeOpened) + { + const bool bIsOpening (nWidth > mnWidthOnSplitterButtonDown); + if (bIsOpening) + bIsDeckVisible = nWidth >= TabBar::GetDefaultWidth() + gnWidthOpenThreshold; + else + bIsDeckVisible = nWidth >= TabBar::GetDefaultWidth() + gnWidthCloseThreshold; + mbIsDeckRequestedOpen = bIsDeckVisible; + UpdateCloseIndicator(!bIsDeckVisible); + } + else + bIsDeckVisible = false; + // Place the deck. if (mpCurrentDeck) { - mpCurrentDeck->setPosSizePixel(0,0, nWidth-TabBar::GetDefaultWidth(), nHeight); - mpCurrentDeck->Show(); - mpCurrentDeck->RequestLayout(); + if (bIsDeckVisible) + { + mpCurrentDeck->setPosSizePixel(0,0, nWidth-TabBar::GetDefaultWidth(), nHeight); + mpCurrentDeck->Show(); + mpCurrentDeck->RequestLayout(); + } + else + mpCurrentDeck->Hide(); } // Place the tab bar. @@ -257,26 +333,34 @@ void SidebarController::NotifyResize (void) pTitleBar->SetCloserVisible(CanModifyChildWindowWidth()); } - if (nWidth > TabBar::GetDefaultWidth()) - mnSavedSidebarWidth = nWidth; - RestrictWidth(); -#ifdef VERBOSE - if (mpCurrentDeck) +} + + + + +void SidebarController::ProcessNewWidth (const sal_Int32 nNewWidth) +{ + if ( ! mbIsDeckRequestedOpen) + return; + + if (mbIsDeckRequestedOpen.get()) + { + // Deck became large enough to be shown. Show it. + mnSavedSidebarWidth = nNewWidth; + RequestOpenDeck(); + } + else { - mpCurrentDeck->PrintWindowTree(); - sal_Int32 nPanelIndex (0); - for (SharedPanelContainer::const_iterator - iPanel(mpCurrentDeck->GetPanels().begin()), - iEnd(mpCurrentDeck->GetPanels().end()); - iPanel!=iEnd; - ++iPanel,++nPanelIndex) - { - OSL_TRACE("panel %d:", nPanelIndex); - (*iPanel)->PrintWindowTree(); - } + // Deck became too small. Close it completely. + // If window is wider than the tab bar then mark the deck as being visible, even when it its not. + // This is to trigger an adjustment of the width to the width of the tab bar. + mbIsDeckOpen = true; + RequestCloseDeck(); + + if (mnWidthOnSplitterButtonDown > TabBar::GetDefaultWidth()) + mnSavedSidebarWidth = mnWidthOnSplitterButtonDown; } -#endif } @@ -288,44 +372,56 @@ void SidebarController::UpdateConfigurations (void) { maCurrentContext = maRequestedContext; - // Notify the tab bar about the updated set of decks. - ResourceManager::IdContainer aDeckIds; + // Find the set of decks that could be displayed for the new context. + ResourceManager::DeckContextDescriptorContainer aDecks; ResourceManager::Instance().GetMatchingDecks ( - aDeckIds, + aDecks, maCurrentContext, + mbIsDocumentReadOnly, mxFrame); - mpTabBar->SetDecks(aDeckIds); + mpTabBar->SetDecks(aDecks); - // Check if the current deck is among the matching decks. - bool bCurrentDeckMatches (false); - for (ResourceManager::IdContainer::const_iterator - iDeck(aDeckIds.begin()), - iEnd(aDeckIds.end()); + // Notify the tab bar about the updated set of decks. + mpTabBar->SetDecks(aDecks); + + // Find the new deck. By default that is the same as the old + // one. If that is not set or not enabled, then choose the + // first enabled deck. + OUString sNewDeckId; + for (ResourceManager::DeckContextDescriptorContainer::const_iterator + iDeck(aDecks.begin()), + iEnd(aDecks.end()); iDeck!=iEnd; ++iDeck) { - if (iDeck->equals(msCurrentDeckId)) + if (iDeck->mbIsEnabled) { - bCurrentDeckMatches = true; - break; + if (iDeck->msId.equals(msCurrentDeckId)) + { + sNewDeckId = msCurrentDeckId; + break; + } + else if (sNewDeckId.getLength() == 0) + sNewDeckId = iDeck->msId; } } - DeckDescriptor const* pDeckDescriptor = NULL; - if ( ! bCurrentDeckMatches) - pDeckDescriptor = ResourceManager::Instance().GetBestMatchingDeck(maCurrentContext, mxFrame); - else - pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(msCurrentDeckId); - if (pDeckDescriptor != NULL) + if (sNewDeckId.getLength() == 0) { - msCurrentDeckId = pDeckDescriptor->msId; - SwitchToDeck(*pDeckDescriptor, maCurrentContext); + // We did not find a valid deck. + RequestCloseDeck(); + return; // Tell the tab bar to highlight the button associated // with the deck. - mpTabBar->HighlightDeck(msCurrentDeckId); + mpTabBar->HighlightDeck(sNewDeckId); } + msCurrentDeckId = sNewDeckId; + SwitchToDeck( + *ResourceManager::Instance().GetDeckDescriptor(sNewDeckId), + maCurrentContext); + #ifdef DEBUG // Show the context name in the deck title bar. if (mpCurrentDeck) @@ -341,10 +437,20 @@ void SidebarController::UpdateConfigurations (void) +void SidebarController::OpenThenSwitchToDeck ( + const ::rtl::OUString& rsDeckId) +{ + RequestOpenDeck(); + SwitchToDeck(rsDeckId); +} + + + + void SidebarController::SwitchToDeck ( const ::rtl::OUString& rsDeckId) { - if ( ! msCurrentDeckId.equals(rsDeckId) || mbIsDeckClosed) + if ( ! msCurrentDeckId.equals(rsDeckId) || ! mbIsDeckOpen) { const DeckDescriptor* pDeckDescriptor = ResourceManager::Instance().GetDeckDescriptor(rsDeckId); if (pDeckDescriptor != NULL) @@ -374,9 +480,6 @@ void SidebarController::SwitchToDeck ( msCurrentDeckId = rDeckDescriptor.msId; } - // Reopen the deck when necessary. - OpenDeck(); - // Determine the panels to display in the deck. ResourceManager::PanelContextDescriptorContainer aPanelContextDescriptors; ResourceManager::Instance().GetMatchingPanels( @@ -413,6 +516,12 @@ void SidebarController::SwitchToDeck ( return; } + // When the document is read-only, check if there are any panels that can still be displayed. + if (mbIsDocumentReadOnly) + { + } + + // Provide a configuration and Deck object. if ( ! mpCurrentDeck) { @@ -420,7 +529,7 @@ void SidebarController::SwitchToDeck ( new Deck( rDeckDescriptor, mpParentWindow, - ::boost::bind(&SidebarController::CloseDeck, this))); + ::boost::bind(&SidebarController::RequestCloseDeck, this))); msCurrentDeckTitle = rDeckDescriptor.msTitle; } if ( ! mpCurrentDeck) @@ -438,6 +547,11 @@ void SidebarController::SwitchToDeck ( const ResourceManager::PanelContextDescriptor& rPanelContexDescriptor ( aPanelContextDescriptors[nReadIndex]); + // Determine if the panel can be displayed. + const bool bIsPanelVisible (!mbIsDocumentReadOnly || rPanelContexDescriptor.mbShowForReadOnlyDocuments); + if ( ! bIsPanelVisible) + continue; + // Find the corresponding panel among the currently active // panels. SharedPanelContainer::const_iterator iPanel (::std::find_if( @@ -501,28 +615,6 @@ bool SidebarController::ArePanelSetsEqual ( const SharedPanelContainer& rCurrentPanels, const ResourceManager::PanelContextDescriptorContainer& rRequestedPanels) { -#ifdef VERBOSE - OSL_TRACE("current panel list:"); - for (SharedPanelContainer::const_iterator - iPanel(rCurrentPanels.begin()), - iEnd(rCurrentPanels.end()); - iPanel!=iEnd; - ++iPanel) - { - OSL_TRACE(" panel %s", S2A((*iPanel)->GetId())); - } - - OSL_TRACE("requested panels: "); - for (ResourceManager::PanelContextDescriptorContainer::const_iterator - iId(rRequestedPanels.begin()), - iEnd(rRequestedPanels.end()); - iId!=iEnd; - ++iId) - { - OSL_TRACE(" panel %s", S2A(iId->msId)); - } -#endif - if (rCurrentPanels.size() != rRequestedPanels.size()) return false; for (sal_Int32 nIndex=0,nCount=rCurrentPanels.size(); nIndex<nCount; ++nIndex) @@ -531,6 +623,11 @@ bool SidebarController::ArePanelSetsEqual ( return false; if ( ! rCurrentPanels[nIndex]->GetId().equals(rRequestedPanels[nIndex].msId)) return false; + + // Check if the panels still can be displayed. This may not be the case when + // the document just become rea-only. + if (mbIsDocumentReadOnly && ! rRequestedPanels[nIndex].mbShowForReadOnlyDocuments) + return false; } return true; } @@ -626,14 +723,13 @@ Reference<ui::XUIElement> SidebarController::CreateUIElement ( IMPL_LINK(SidebarController, WindowEventHandler, VclWindowEvent*, pEvent) { - if (pEvent != NULL) + if (pEvent==NULL) + return sal_False; + + if (pEvent->GetWindow() == mpParentWindow) { switch (pEvent->GetId()) { - case VCLEVENT_WINDOW_GETFOCUS: - case VCLEVENT_WINDOW_LOSEFOCUS: - break; - case VCLEVENT_WINDOW_SHOW: case VCLEVENT_WINDOW_RESIZE: NotifyResize(); @@ -651,10 +747,34 @@ IMPL_LINK(SidebarController, WindowEventHandler, VclWindowEvent*, pEvent) dispose(); break; + case VCLEVENT_WINDOW_PAINT: + OSL_TRACE("Paint"); + break; + default: break; } } + else if (pEvent->GetWindow()==mpSplitWindow && mpSplitWindow!=NULL) + { + switch (pEvent->GetId()) + { + case VCLEVENT_WINDOW_MOUSEBUTTONDOWN: + mnWidthOnSplitterButtonDown = mpParentWindow->GetSizePixel().Width(); + break; + + case VCLEVENT_WINDOW_MOUSEBUTTONUP: + { + ProcessNewWidth(mpParentWindow->GetSizePixel().Width()); + mnWidthOnSplitterButtonDown = 0; + break; + } + + case SFX_HINT_DYING: + dispose(); + break; + } + } return sal_True; } @@ -683,16 +803,8 @@ void SidebarController::ShowDetailMenu (const ::rtl::OUString& rsMenuCommand) co { try { - util::URL aURL; - aURL.Complete = rsMenuCommand; - - const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory()); - const Reference<util::XURLTransformer> xParser ( - aComponentContext.createComponent("com.sun.star.util.URLTransformer"), - UNO_QUERY_THROW); - xParser->parseStrict(aURL); - Reference<frame::XDispatchProvider> xProvider (mxFrame, UNO_QUERY_THROW); - Reference<frame::XDispatch> xDispatch (xProvider->queryDispatch(aURL, OUString(), 0)); + const util::URL aURL (GetURL(rsMenuCommand)); + Reference<frame::XDispatch> xDispatch (GetDispatch(aURL)); if (xDispatch.is()) xDispatch->dispatch(aURL, Sequence<beans::PropertyValue>()); } @@ -706,6 +818,33 @@ void SidebarController::ShowDetailMenu (const ::rtl::OUString& rsMenuCommand) co +util::URL SidebarController::GetURL (const ::rtl::OUString& rsCommand) const +{ + util::URL aURL; + aURL.Complete = rsCommand; + + const ::comphelper::ComponentContext aComponentContext (::comphelper::getProcessServiceFactory()); + const Reference<util::XURLTransformer> xParser ( + aComponentContext.createComponent("com.sun.star.util.URLTransformer"), + UNO_QUERY_THROW); + xParser->parseStrict(aURL); + + return aURL; +} + + + + +Reference<frame::XDispatch> SidebarController::GetDispatch (const util::URL& rURL) const +{ + Reference<frame::XDispatchProvider> xProvider (mxFrame, UNO_QUERY_THROW); + Reference<frame::XDispatch> xDispatch (xProvider->queryDispatch(rURL, OUString(), 0)); + return xDispatch; +} + + + + ::boost::shared_ptr<PopupMenu> SidebarController::CreatePopupMenu ( const ::std::vector<TabBar::DeckMenuData>& rDeckSelectionData, const ::std::vector<TabBar::DeckMenuData>& rDeckShowData) const @@ -819,35 +958,54 @@ IMPL_LINK(SidebarController, OnMenuItemSelected, Menu*, pMenu) -void SidebarController::CloseDeck (void) +void SidebarController::RequestCloseDeck (void) { - if ( ! mbIsDeckClosed) - { - mbIsDeckClosed = true; - if ( ! mpParentWindow->IsFloatingMode()) - mnSavedSidebarWidth = SetChildWindowWidth(TabBar::GetDefaultWidth()); - mpParentWindow->SetStyle(mpParentWindow->GetStyle() & ~WB_SIZEABLE); + mbIsDeckRequestedOpen = false; + UpdateDeckOpenState(); +} - if (mpCurrentDeck) - mpCurrentDeck->Hide(); - NotifyResize(); - } + + +void SidebarController::RequestOpenDeck (void) +{ + mbIsDeckRequestedOpen = true; + UpdateDeckOpenState(); } -void SidebarController::OpenDeck (void) +void SidebarController::UpdateDeckOpenState (void) { - if (mbIsDeckClosed) - { - mbIsDeckClosed = false; - SetChildWindowWidth(mnSavedSidebarWidth); + if ( ! mbIsDeckRequestedOpen) + // No state requested. + return; - if (mpCurrentDeck) - mpCurrentDeck->Show(); + // Update (change) the open state when it either has not yet been initialized + // or when its value differs from the requested state. + if ( ! mbIsDeckOpen + || mbIsDeckOpen.get() != mbIsDeckRequestedOpen.get()) + { + if (mbIsDeckRequestedOpen.get()) + { + if (mnSavedSidebarWidth <= TabBar::GetDefaultWidth()) + SetChildWindowWidth(SidebarChildWindow::GetDefaultWidth(mpParentWindow)); + else + SetChildWindowWidth(mnSavedSidebarWidth); + } + else + { + if ( ! mpParentWindow->IsFloatingMode()) + mnSavedSidebarWidth = SetChildWindowWidth(TabBar::GetDefaultWidth()); + if (mnWidthOnSplitterButtonDown > TabBar::GetDefaultWidth()) + mnSavedSidebarWidth = mnWidthOnSplitterButtonDown; + mpParentWindow->SetStyle(mpParentWindow->GetStyle() & ~WB_SIZEABLE); + } + mbIsDeckOpen = mbIsDeckRequestedOpen.get(); + if (mbIsDeckOpen.get() && mpCurrentDeck) + mpCurrentDeck->Show(mbIsDeckOpen.get()); NotifyResize(); } } @@ -863,13 +1021,11 @@ FocusManager& SidebarController::GetFocusManager (void) -bool SidebarController::CanModifyChildWindowWidth (void) const +bool SidebarController::CanModifyChildWindowWidth (void) { - SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); + SfxSplitWindow* pSplitWindow = GetSplitWindow(); if (pSplitWindow == NULL) - { - return 0; - } + return false; sal_uInt16 nRow (0xffff); sal_uInt16 nColumn (0xffff); @@ -877,7 +1033,7 @@ bool SidebarController::CanModifyChildWindowWidth (void) const sal_uInt16 nRowCount (pSplitWindow->GetWindowCount(nColumn)); - return nRowCount == 1; + return nRowCount==1; } @@ -885,7 +1041,7 @@ bool SidebarController::CanModifyChildWindowWidth (void) const sal_Int32 SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth) { - SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); + SfxSplitWindow* pSplitWindow = GetSplitWindow(); if (pSplitWindow == NULL) return 0; @@ -903,6 +1059,7 @@ sal_Int32 SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth) Size(nNewWidth, aWindowSize.Height()), nColumn, nRow); + static_cast<SplitWindow*>(pSplitWindow)->Split(); return static_cast<sal_Int32>(nColumnWidth); } @@ -912,23 +1069,70 @@ sal_Int32 SidebarController::SetChildWindowWidth (const sal_Int32 nNewWidth) void SidebarController::RestrictWidth (void) { - SfxSplitWindow* pSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); + SfxSplitWindow* pSplitWindow = GetSplitWindow(); if (pSplitWindow != NULL) { const sal_uInt16 nId (pSplitWindow->GetItemId(mpParentWindow)); const sal_uInt16 nSetId (pSplitWindow->GetSet(nId)); - // Minimum width is always that of the tabbar. - const sal_Int32 nMinimumWidth (TabBar::GetDefaultWidth()); - // Maximum width depends on whether the deck is open or closed. - const sal_Int32 nMaximumWidth ( - mbIsDeckClosed - ? TabBar::GetDefaultWidth() - : 400); pSplitWindow->SetItemSizeRange( nSetId, - Range(nMinimumWidth, nMaximumWidth)); - if (nMinimumWidth == nMaximumWidth) - pSplitWindow->SetItemSize(nSetId, nMinimumWidth); + Range(TabBar::GetDefaultWidth(), gnMaximumSidebarWidth)); + } +} + + + + +SfxSplitWindow* SidebarController::GetSplitWindow (void) +{ + if (mpSplitWindow == NULL) + { + if (mpParentWindow != NULL) + { + mpSplitWindow = dynamic_cast<SfxSplitWindow*>(mpParentWindow->GetParent()); + if (mpSplitWindow != NULL) + mpSplitWindow->AddEventListener(LINK(this, SidebarController, WindowEventHandler)); + } + } + + return mpSplitWindow; +} + + + + +void SidebarController::UpdateCloseIndicator (const bool bCloseAfterDrag) +{ + if (mpParentWindow == NULL) + return; + + if (bCloseAfterDrag) + { + // Make sure that the indicator exists. + if ( ! mpCloseIndicator) + { + mpCloseIndicator.reset(new FixedImage(mpParentWindow)); + FixedImage* pFixedImage = static_cast<FixedImage*>(mpCloseIndicator.get()); + const Image aImage (Theme::GetImage(Theme::Image_CloseIndicator)); + pFixedImage->SetImage(aImage); + pFixedImage->SetSizePixel(aImage.GetSizePixel()); + pFixedImage->SetBackground(Theme::GetWallpaper(Theme::Paint_DeckBackground)); + } + + // Place and show the indicator. + const Size aWindowSize (mpParentWindow->GetSizePixel()); + const Size aImageSize (mpCloseIndicator->GetSizePixel()); + mpCloseIndicator->SetPosPixel( + Point( + aWindowSize.Width() - TabBar::GetDefaultWidth() - aImageSize.Width(), + (aWindowSize.Height() - aImageSize.Height())/2)); + mpCloseIndicator->Show(); + } + else + { + // Hide but don't delete the indicator. + if (mpCloseIndicator) + mpCloseIndicator->Hide(); } } |