| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "precompiled_svtools.hxx" |
| |
| #include "dummypanel.hxx" |
| #include "toolpanelcollection.hxx" |
| #include "paneldecklisteners.hxx" |
| #include "toolpaneldeckpeer.hxx" |
| #include "svtools/toolpanel/toolpaneldeck.hxx" |
| #include "svtools/toolpanel/tablayouter.hxx" |
| #include "svtools/toolpanel/drawerlayouter.hxx" |
| |
| /** === begin UNO includes === **/ |
| #include <com/sun/star/accessibility/XAccessible.hpp> |
| #include <com/sun/star/accessibility/AccessibleRole.hpp> |
| /** === end UNO includes === **/ |
| |
| #include <tools/diagnose_ex.h> |
| |
| #include <boost/optional.hpp> |
| |
| //........................................................................ |
| namespace svt |
| { |
| //........................................................................ |
| |
| /** === begin UNO using === **/ |
| using ::com::sun::star::uno::Reference; |
| using ::com::sun::star::accessibility::XAccessible; |
| using ::com::sun::star::awt::XWindowPeer; |
| using ::com::sun::star::uno::UNO_SET_THROW; |
| /** === end UNO using === **/ |
| namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole; |
| |
| enum DeckAction |
| { |
| /// activates the first panel |
| ACTION_ACTIVATE_FIRST, |
| // activates the panel after the currently active panel |
| ACTION_ACTIVATE_NEXT, |
| // activates the panel before the currently active panel |
| ACTION_ACTIVATE_PREV, |
| // activates the last panel |
| ACTION_ACTIVATE_LAST, |
| |
| // toggles the focus between the active panel and the panel selector |
| ACTION_TOGGLE_FOCUS, |
| }; |
| |
| //==================================================================== |
| //= ToolPanelDeck_Impl |
| //==================================================================== |
| class ToolPanelDeck_Impl : public IToolPanelDeckListener |
| { |
| public: |
| ToolPanelDeck_Impl( ToolPanelDeck& i_rDeck ) |
| :m_rDeck( i_rDeck ) |
| ,m_aPanelAnchor( &i_rDeck, WB_DIALOGCONTROL | WB_CHILDDLGCTRL ) |
| ,m_aPanels() |
| ,m_pDummyPanel( new DummyPanel ) |
| ,m_pLayouter() |
| ,m_bInDtor( false ) |
| ,m_pAccessibleParent( NULL ) |
| { |
| m_aPanels.AddListener( *this ); |
| m_aPanelAnchor.Show(); |
| m_aPanelAnchor.SetAccessibleRole( AccessibleRole::PANEL ); |
| } |
| |
| ~ToolPanelDeck_Impl() |
| { |
| m_bInDtor = true; |
| } |
| |
| PDeckLayouter GetLayouter() const { return m_pLayouter; } |
| void SetLayouter( const PDeckLayouter& i_pNewLayouter ); |
| |
| Window& GetPanelWindowAnchor() { return m_aPanelAnchor; } |
| const Window& GetPanelWindowAnchor() const { return m_aPanelAnchor; } |
| |
| bool IsDead() const { return m_bInDtor; } |
| |
| /// notifies our listeners that we're going to die. Only to be called from with our anti-impl's destructor |
| void NotifyDying() |
| { |
| m_aPanels.RemoveListener( *this ); |
| m_aListeners.Dying(); |
| } |
| |
| // IToolPanelDeck equivalents |
| size_t GetPanelCount() const; |
| PToolPanel GetPanel( const size_t i_nPos ) const; |
| ::boost::optional< size_t > |
| GetActivePanel() const; |
| void ActivatePanel( const ::boost::optional< size_t >& i_rPanel ); |
| size_t InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ); |
| PToolPanel RemovePanel( const size_t i_nPosition ); |
| void AddListener( IToolPanelDeckListener& i_rListener ); |
| void RemoveListener( IToolPanelDeckListener& i_rListener ); |
| |
| /// re-layouts everything |
| void LayoutAll() { ImplDoLayout(); } |
| |
| void DoAction( const DeckAction i_eAction ); |
| |
| bool FocusActivePanel(); |
| |
| void SetAccessibleParentWindow( Window* i_pAccessibleParent ); |
| Window* GetAccessibleParentWindow() const { return m_pAccessibleParent; } |
| |
| protected: |
| // IToolPanelDeckListener |
| virtual void PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ); |
| virtual void PanelRemoved( const size_t i_nPosition ); |
| virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); |
| virtual void LayouterChanged( const PDeckLayouter& i_rNewLayouter ); |
| virtual void Dying(); |
| |
| private: |
| void ImplDoLayout(); |
| PToolPanel GetActiveOrDummyPanel_Impl(); |
| |
| private: |
| ToolPanelDeck& m_rDeck; |
| Window m_aPanelAnchor; |
| ToolPanelCollection m_aPanels; |
| PToolPanel m_pDummyPanel; |
| PanelDeckListeners m_aListeners; |
| PDeckLayouter m_pLayouter; |
| bool m_bInDtor; |
| Window* m_pAccessibleParent; |
| }; |
| |
| //-------------------------------------------------------------------- |
| PToolPanel ToolPanelDeck_Impl::GetActiveOrDummyPanel_Impl() |
| { |
| ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() ); |
| if ( !aActivePanel ) |
| return m_pDummyPanel; |
| return m_aPanels.GetPanel( *aActivePanel ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::SetLayouter( const PDeckLayouter& i_pNewLayouter ) |
| { |
| ENSURE_OR_RETURN_VOID( i_pNewLayouter.get(), "invalid layouter" ); |
| |
| if ( m_pLayouter.get() ) |
| m_pLayouter->Destroy(); |
| |
| m_pLayouter = i_pNewLayouter; |
| |
| ImplDoLayout(); |
| |
| m_aListeners.LayouterChanged( m_pLayouter ); |
| } |
| |
| //-------------------------------------------------------------------- |
| size_t ToolPanelDeck_Impl::GetPanelCount() const |
| { |
| return m_aPanels.GetPanelCount(); |
| } |
| |
| //-------------------------------------------------------------------- |
| PToolPanel ToolPanelDeck_Impl::GetPanel( const size_t i_nPos ) const |
| { |
| return m_aPanels.GetPanel( i_nPos ); |
| } |
| |
| //-------------------------------------------------------------------- |
| ::boost::optional< size_t > ToolPanelDeck_Impl::GetActivePanel() const |
| { |
| return m_aPanels.GetActivePanel(); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::ActivatePanel( const ::boost::optional< size_t >& i_rPanel ) |
| { |
| m_aPanels.ActivatePanel( i_rPanel ); |
| } |
| |
| //-------------------------------------------------------------------- |
| size_t ToolPanelDeck_Impl::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ) |
| { |
| return m_aPanels.InsertPanel( i_pPanel, i_nPosition ); |
| } |
| |
| //-------------------------------------------------------------------- |
| PToolPanel ToolPanelDeck_Impl::RemovePanel( const size_t i_nPosition ) |
| { |
| return m_aPanels.RemovePanel( i_nPosition ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::ImplDoLayout() |
| { |
| const Rectangle aDeckPlayground( Point(), m_rDeck.GetOutputSizePixel() ); |
| |
| // ask the layouter what is left for our panel, and position the panel container window appropriately |
| Rectangle aPlaygroundArea( aDeckPlayground ); |
| OSL_ENSURE( m_pLayouter.get(), "ToolPanelDeck_Impl::ImplDoLayout: no layouter!" ); |
| if ( m_pLayouter.get() ) |
| { |
| aPlaygroundArea = m_pLayouter->Layout( aDeckPlayground ); |
| } |
| m_aPanelAnchor.SetPosSizePixel( aPlaygroundArea.TopLeft(), aPlaygroundArea.GetSize() ); |
| |
| // position the active panel |
| const PToolPanel pActive( GetActiveOrDummyPanel_Impl() ); |
| pActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::AddListener( IToolPanelDeckListener& i_rListener ) |
| { |
| m_aListeners.AddListener( i_rListener ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::RemoveListener( IToolPanelDeckListener& i_rListener ) |
| { |
| m_aListeners.RemoveListener( i_rListener ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::DoAction( const DeckAction i_eAction ) |
| { |
| const size_t nPanelCount( m_aPanels.GetPanelCount() ); |
| ::boost::optional< size_t > aActivatePanel; |
| ::boost::optional< size_t > aCurrentPanel( GetActivePanel() ); |
| |
| switch ( i_eAction ) |
| { |
| case ACTION_ACTIVATE_FIRST: |
| if ( nPanelCount > 0 ) |
| aActivatePanel = 0; |
| break; |
| case ACTION_ACTIVATE_PREV: |
| if ( !aCurrentPanel && ( nPanelCount > 0 ) ) |
| aActivatePanel = nPanelCount - 1; |
| else |
| if ( !!aCurrentPanel && ( *aCurrentPanel > 0 ) ) |
| aActivatePanel = *aCurrentPanel - 1; |
| break; |
| case ACTION_ACTIVATE_NEXT: |
| if ( !aCurrentPanel && ( nPanelCount > 0 ) ) |
| aActivatePanel = 0; |
| else |
| if ( !!aCurrentPanel && ( *aCurrentPanel < nPanelCount - 1 ) ) |
| aActivatePanel = *aCurrentPanel + 1; |
| break; |
| case ACTION_ACTIVATE_LAST: |
| if ( nPanelCount > 0 ) |
| aActivatePanel = nPanelCount - 1; |
| break; |
| case ACTION_TOGGLE_FOCUS: |
| { |
| PToolPanel pActivePanel( GetActiveOrDummyPanel_Impl() ); |
| if ( !m_aPanelAnchor.HasChildPathFocus() ) |
| pActivePanel->GrabFocus(); |
| else |
| GetLayouter()->SetFocusToPanelSelector(); |
| } |
| break; |
| } |
| |
| if ( !!aActivatePanel ) |
| { |
| ActivatePanel( aActivatePanel ); |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| bool ToolPanelDeck_Impl::FocusActivePanel() |
| { |
| ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() ); |
| if ( !aActivePanel ) |
| return false; |
| |
| PToolPanel pActivePanel( m_aPanels.GetPanel( *aActivePanel ) ); |
| pActivePanel->GrabFocus(); |
| return true; |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ) |
| { |
| // multiplex to our own listeners |
| m_aListeners.PanelInserted( i_pPanel, i_nPosition ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::PanelRemoved( const size_t i_nPosition ) |
| { |
| // multiplex to our own listeners |
| m_aListeners.PanelRemoved( i_nPosition ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) |
| { |
| // hide the old panel |
| if ( !!i_rOldActive ) |
| { |
| const PToolPanel pOldActive( m_aPanels.GetPanel( *i_rOldActive ) ); |
| pOldActive->Deactivate(); |
| } |
| |
| // position and show the new panel |
| const PToolPanel pNewActive( !i_rNewActive ? m_pDummyPanel : m_aPanels.GetPanel( *i_rNewActive ) ); |
| pNewActive->Activate( m_aPanelAnchor ); |
| pNewActive->GrabFocus(); |
| |
| // resize the panel (cannot guarantee it has ever been resized before |
| pNewActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() ); |
| |
| // multiplex to our own listeners |
| m_aListeners.ActivePanelChanged( i_rOldActive, i_rNewActive ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter ) |
| { |
| // not interested in |
| (void)i_rNewLayouter; |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::Dying() |
| { |
| // not interested in. Since the ToolPanelCollection is our member, this just means we ourself |
| // are dying, and we already sent this notification in our dtor. |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck_Impl::SetAccessibleParentWindow( Window* i_pAccessibleParent ) |
| { |
| m_pAccessibleParent = i_pAccessibleParent; |
| } |
| |
| //==================================================================== |
| //= ToolPanelDeck |
| //==================================================================== |
| //-------------------------------------------------------------------- |
| ToolPanelDeck::ToolPanelDeck( Window& i_rParent, const WinBits i_nStyle ) |
| :Control( &i_rParent, i_nStyle ) |
| ,m_pImpl( new ToolPanelDeck_Impl( *this ) ) |
| { |
| // use a default layouter |
| // SetLayouter( PDeckLayouter( new TabDeckLayouter( *this, *this, TABS_RIGHT, TABITEM_IMAGE_AND_TEXT ) ) ); |
| SetLayouter( PDeckLayouter( new DrawerDeckLayouter( *this, *this ) ) ); |
| } |
| |
| //-------------------------------------------------------------------- |
| ToolPanelDeck::~ToolPanelDeck() |
| { |
| m_pImpl->NotifyDying(); |
| GetLayouter()->Destroy(); |
| |
| Hide(); |
| for ( size_t i=0; i<GetPanelCount(); ++i ) |
| { |
| PToolPanel pPanel( GetPanel( i ) ); |
| pPanel->Dispose(); |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| size_t ToolPanelDeck::GetPanelCount() const |
| { |
| return m_pImpl->GetPanelCount(); |
| } |
| |
| //-------------------------------------------------------------------- |
| PToolPanel ToolPanelDeck::GetPanel( const size_t i_nPos ) const |
| { |
| return m_pImpl->GetPanel( i_nPos ); |
| } |
| |
| //-------------------------------------------------------------------- |
| ::boost::optional< size_t > ToolPanelDeck::GetActivePanel() const |
| { |
| return m_pImpl->GetActivePanel(); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck::ActivatePanel( const ::boost::optional< size_t >& i_rPanel ) |
| { |
| m_pImpl->ActivatePanel( i_rPanel ); |
| } |
| |
| //-------------------------------------------------------------------- |
| size_t ToolPanelDeck::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ) |
| { |
| return m_pImpl->InsertPanel( i_pPanel, i_nPosition ); |
| } |
| |
| //-------------------------------------------------------------------- |
| PToolPanel ToolPanelDeck::RemovePanel( const size_t i_nPosition ) |
| { |
| return m_pImpl->RemovePanel( i_nPosition ); |
| } |
| |
| //-------------------------------------------------------------------- |
| PDeckLayouter ToolPanelDeck::GetLayouter() const |
| { |
| return m_pImpl->GetLayouter(); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck::SetLayouter( const PDeckLayouter& i_pNewLayouter ) |
| { |
| return m_pImpl->SetLayouter( i_pNewLayouter ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck::AddListener( IToolPanelDeckListener& i_rListener ) |
| { |
| m_pImpl->AddListener( i_rListener ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck::RemoveListener( IToolPanelDeckListener& i_rListener ) |
| { |
| m_pImpl->RemoveListener( i_rListener ); |
| } |
| |
| //-------------------------------------------------------------------- |
| Window& ToolPanelDeck::GetPanelWindowAnchor() |
| { |
| return m_pImpl->GetPanelWindowAnchor(); |
| } |
| |
| //-------------------------------------------------------------------- |
| const Window& ToolPanelDeck::GetPanelWindowAnchor() const |
| { |
| return m_pImpl->GetPanelWindowAnchor(); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck::Resize() |
| { |
| Control::Resize(); |
| m_pImpl->LayoutAll(); |
| } |
| |
| //-------------------------------------------------------------------- |
| long ToolPanelDeck::Notify( NotifyEvent& i_rNotifyEvent ) |
| { |
| bool bHandled = false; |
| if ( i_rNotifyEvent.GetType() == EVENT_KEYINPUT ) |
| { |
| const KeyEvent* pEvent = i_rNotifyEvent.GetKeyEvent(); |
| const KeyCode& rKeyCode = pEvent->GetKeyCode(); |
| if ( rKeyCode.GetModifier() == KEY_MOD1 ) |
| { |
| bHandled = true; |
| switch ( rKeyCode.GetCode() ) |
| { |
| case KEY_HOME: |
| m_pImpl->DoAction( ACTION_ACTIVATE_FIRST ); |
| break; |
| case KEY_PAGEUP: |
| m_pImpl->DoAction( ACTION_ACTIVATE_PREV ); |
| break; |
| case KEY_PAGEDOWN: |
| m_pImpl->DoAction( ACTION_ACTIVATE_NEXT ); |
| break; |
| case KEY_END: |
| m_pImpl->DoAction( ACTION_ACTIVATE_LAST ); |
| break; |
| default: |
| bHandled = false; |
| break; |
| } |
| } |
| else if ( rKeyCode.GetModifier() == ( KEY_MOD1 | KEY_SHIFT ) ) |
| { |
| if ( rKeyCode.GetCode() == KEY_E ) |
| { |
| m_pImpl->DoAction( ACTION_TOGGLE_FOCUS ); |
| bHandled = true; |
| } |
| } |
| } |
| |
| if ( bHandled ) |
| return 1; |
| |
| return Control::Notify( i_rNotifyEvent ); |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck::GetFocus() |
| { |
| Control::GetFocus(); |
| if ( m_pImpl->IsDead() ) |
| return; |
| if ( !m_pImpl->FocusActivePanel() ) |
| { |
| PDeckLayouter pLayouter( GetLayouter() ); |
| ENSURE_OR_RETURN_VOID( pLayouter.get(), "ToolPanelDeck::GetFocus: no layouter?!" ); |
| pLayouter->SetFocusToPanelSelector(); |
| } |
| } |
| |
| //-------------------------------------------------------------------- |
| void ToolPanelDeck::SetAccessibleParentWindow( Window* i_pAccessibleParent ) |
| { |
| m_pImpl->SetAccessibleParentWindow( i_pAccessibleParent ); |
| } |
| |
| //-------------------------------------------------------------------- |
| Window* ToolPanelDeck::GetAccessibleParentWindow() const |
| { |
| Window* pAccessibleParent( m_pImpl->GetAccessibleParentWindow() ); |
| if ( !pAccessibleParent ) |
| pAccessibleParent = Window::GetAccessibleParentWindow(); |
| return pAccessibleParent; |
| } |
| |
| //-------------------------------------------------------------------- |
| Reference< XWindowPeer > ToolPanelDeck::GetComponentInterface( sal_Bool i_bCreate ) |
| { |
| Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( sal_False ) ); |
| if ( !xWindowPeer.is() && i_bCreate ) |
| { |
| xWindowPeer.set( new ToolPanelDeckPeer( *this ) ); |
| SetComponentInterface( xWindowPeer ); |
| } |
| return xWindowPeer; |
| } |
| |
| //........................................................................ |
| } // namespace svt |
| //........................................................................ |