Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "dummypanel.hxx"
22 : #include "toolpanelcollection.hxx"
23 : #include "paneldecklisteners.hxx"
24 : #include "toolpaneldeckpeer.hxx"
25 : #include "svtools/toolpanel/toolpaneldeck.hxx"
26 : #include "svtools/toolpanel/tablayouter.hxx"
27 : #include "svtools/toolpanel/drawerlayouter.hxx"
28 :
29 : #include <com/sun/star/accessibility/XAccessible.hpp>
30 : #include <com/sun/star/accessibility/AccessibleRole.hpp>
31 :
32 : #include <tools/diagnose_ex.h>
33 :
34 : #include <boost/optional.hpp>
35 :
36 : //........................................................................
37 : namespace svt
38 : {
39 : //........................................................................
40 :
41 : using ::com::sun::star::uno::Reference;
42 : using ::com::sun::star::accessibility::XAccessible;
43 : using ::com::sun::star::awt::XWindowPeer;
44 : using ::com::sun::star::uno::UNO_SET_THROW;
45 :
46 : namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole;
47 :
48 : enum DeckAction
49 : {
50 : /// activates the first panel
51 : ACTION_ACTIVATE_FIRST,
52 : // activates the panel after the currently active panel
53 : ACTION_ACTIVATE_NEXT,
54 : // activates the panel before the currently active panel
55 : ACTION_ACTIVATE_PREV,
56 : // activates the last panel
57 : ACTION_ACTIVATE_LAST,
58 :
59 : // toggles the focus between the active panel and the panel selector
60 : ACTION_TOGGLE_FOCUS,
61 : };
62 :
63 : //====================================================================
64 : //= ToolPanelDeck_Impl
65 : //====================================================================
66 : class ToolPanelDeck_Impl : public IToolPanelDeckListener
67 : {
68 : public:
69 13 : ToolPanelDeck_Impl( ToolPanelDeck& i_rDeck )
70 : :m_rDeck( i_rDeck )
71 : ,m_aPanelAnchor( &i_rDeck, WB_DIALOGCONTROL | WB_CHILDDLGCTRL )
72 : ,m_aPanels()
73 13 : ,m_pDummyPanel( new DummyPanel )
74 : ,m_pLayouter()
75 : ,m_bInDtor( false )
76 26 : ,m_pAccessibleParent( NULL )
77 : {
78 13 : m_aPanels.AddListener( *this );
79 13 : m_aPanelAnchor.Show();
80 13 : m_aPanelAnchor.SetAccessibleRole( AccessibleRole::PANEL );
81 13 : }
82 :
83 26 : virtual ~ToolPanelDeck_Impl()
84 26 : {
85 13 : m_bInDtor = true;
86 26 : }
87 :
88 26 : PDeckLayouter GetLayouter() const { return m_pLayouter; }
89 : void SetLayouter( const PDeckLayouter& i_pNewLayouter );
90 :
91 32 : Window& GetPanelWindowAnchor() { return m_aPanelAnchor; }
92 : const Window& GetPanelWindowAnchor() const { return m_aPanelAnchor; }
93 :
94 0 : bool IsDead() const { return m_bInDtor; }
95 :
96 : /// notifies our listeners that we're going to die. Only to be called from with our anti-impl's destructor
97 13 : void NotifyDying()
98 : {
99 13 : m_aPanels.RemoveListener( *this );
100 13 : m_aListeners.Dying();
101 13 : }
102 :
103 : // IToolPanelDeck equivalents
104 : size_t GetPanelCount() const;
105 : PToolPanel GetPanel( const size_t i_nPos ) const;
106 : ::boost::optional< size_t >
107 : GetActivePanel() const;
108 : void ActivatePanel( const ::boost::optional< size_t >& i_rPanel );
109 : size_t InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition );
110 : PToolPanel RemovePanel( const size_t i_nPosition );
111 : void AddListener( IToolPanelDeckListener& i_rListener );
112 : void RemoveListener( IToolPanelDeckListener& i_rListener );
113 :
114 : /// re-layouts everything
115 108 : void LayoutAll() { ImplDoLayout(); }
116 :
117 : void DoAction( const DeckAction i_eAction );
118 :
119 : bool FocusActivePanel();
120 :
121 : void SetAccessibleParentWindow( Window* i_pAccessibleParent );
122 0 : Window* GetAccessibleParentWindow() const { return m_pAccessibleParent; }
123 :
124 : protected:
125 : // IToolPanelDeckListener
126 : virtual void PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition );
127 : virtual void PanelRemoved( const size_t i_nPosition );
128 : virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive );
129 : virtual void LayouterChanged( const PDeckLayouter& i_rNewLayouter );
130 : virtual void Dying();
131 :
132 : private:
133 : void ImplDoLayout();
134 : PToolPanel GetActiveOrDummyPanel_Impl();
135 :
136 : private:
137 : ToolPanelDeck& m_rDeck;
138 : Window m_aPanelAnchor;
139 : ToolPanelCollection m_aPanels;
140 : PToolPanel m_pDummyPanel;
141 : PanelDeckListeners m_aListeners;
142 : PDeckLayouter m_pLayouter;
143 : bool m_bInDtor;
144 : Window* m_pAccessibleParent;
145 : };
146 :
147 : //--------------------------------------------------------------------
148 121 : PToolPanel ToolPanelDeck_Impl::GetActiveOrDummyPanel_Impl()
149 : {
150 121 : ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() );
151 121 : if ( !aActivePanel )
152 101 : return m_pDummyPanel;
153 20 : return m_aPanels.GetPanel( *aActivePanel );
154 : }
155 :
156 : //--------------------------------------------------------------------
157 13 : void ToolPanelDeck_Impl::SetLayouter( const PDeckLayouter& i_pNewLayouter )
158 : {
159 26 : ENSURE_OR_RETURN_VOID( i_pNewLayouter.get(), "invalid layouter" );
160 :
161 13 : if ( m_pLayouter.get() )
162 0 : m_pLayouter->Destroy();
163 :
164 13 : m_pLayouter = i_pNewLayouter;
165 :
166 13 : ImplDoLayout();
167 :
168 13 : m_aListeners.LayouterChanged( m_pLayouter );
169 : }
170 :
171 : //--------------------------------------------------------------------
172 536 : size_t ToolPanelDeck_Impl::GetPanelCount() const
173 : {
174 536 : return m_aPanels.GetPanelCount();
175 : }
176 :
177 : //--------------------------------------------------------------------
178 311 : PToolPanel ToolPanelDeck_Impl::GetPanel( const size_t i_nPos ) const
179 : {
180 311 : return m_aPanels.GetPanel( i_nPos );
181 : }
182 :
183 : //--------------------------------------------------------------------
184 124 : ::boost::optional< size_t > ToolPanelDeck_Impl::GetActivePanel() const
185 : {
186 124 : return m_aPanels.GetActivePanel();
187 : }
188 :
189 : //--------------------------------------------------------------------
190 25 : void ToolPanelDeck_Impl::ActivatePanel( const ::boost::optional< size_t >& i_rPanel )
191 : {
192 25 : m_aPanels.ActivatePanel( i_rPanel );
193 25 : }
194 :
195 : //--------------------------------------------------------------------
196 65 : size_t ToolPanelDeck_Impl::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition )
197 : {
198 65 : return m_aPanels.InsertPanel( i_pPanel, i_nPosition );
199 : }
200 :
201 : //--------------------------------------------------------------------
202 0 : PToolPanel ToolPanelDeck_Impl::RemovePanel( const size_t i_nPosition )
203 : {
204 0 : return m_aPanels.RemovePanel( i_nPosition );
205 : }
206 :
207 : //--------------------------------------------------------------------
208 121 : void ToolPanelDeck_Impl::ImplDoLayout()
209 : {
210 121 : const Rectangle aDeckPlayground( Point(), m_rDeck.GetOutputSizePixel() );
211 :
212 : // ask the layouter what is left for our panel, and position the panel container window appropriately
213 121 : Rectangle aPlaygroundArea( aDeckPlayground );
214 : OSL_ENSURE( m_pLayouter.get(), "ToolPanelDeck_Impl::ImplDoLayout: no layouter!" );
215 121 : if ( m_pLayouter.get() )
216 : {
217 121 : aPlaygroundArea = m_pLayouter->Layout( aDeckPlayground );
218 : }
219 121 : m_aPanelAnchor.SetPosSizePixel( aPlaygroundArea.TopLeft(), aPlaygroundArea.GetSize() );
220 :
221 : // position the active panel
222 121 : const PToolPanel pActive( GetActiveOrDummyPanel_Impl() );
223 121 : pActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() );
224 121 : }
225 :
226 : //--------------------------------------------------------------------
227 39 : void ToolPanelDeck_Impl::AddListener( IToolPanelDeckListener& i_rListener )
228 : {
229 39 : m_aListeners.AddListener( i_rListener );
230 39 : }
231 :
232 : //--------------------------------------------------------------------
233 52 : void ToolPanelDeck_Impl::RemoveListener( IToolPanelDeckListener& i_rListener )
234 : {
235 52 : m_aListeners.RemoveListener( i_rListener );
236 52 : }
237 :
238 : //--------------------------------------------------------------------
239 0 : void ToolPanelDeck_Impl::DoAction( const DeckAction i_eAction )
240 : {
241 0 : const size_t nPanelCount( m_aPanels.GetPanelCount() );
242 0 : ::boost::optional< size_t > aActivatePanel;
243 0 : ::boost::optional< size_t > aCurrentPanel( GetActivePanel() );
244 :
245 0 : switch ( i_eAction )
246 : {
247 : case ACTION_ACTIVATE_FIRST:
248 0 : if ( nPanelCount > 0 )
249 0 : aActivatePanel = 0;
250 0 : break;
251 : case ACTION_ACTIVATE_PREV:
252 0 : if ( !aCurrentPanel && ( nPanelCount > 0 ) )
253 0 : aActivatePanel = nPanelCount - 1;
254 0 : else if ( !!aCurrentPanel && ( *aCurrentPanel > 0 ) )
255 0 : aActivatePanel = *aCurrentPanel - 1;
256 0 : break;
257 : case ACTION_ACTIVATE_NEXT:
258 0 : if ( !aCurrentPanel && ( nPanelCount > 0 ) )
259 0 : aActivatePanel = 0;
260 0 : else if ( !!aCurrentPanel && ( *aCurrentPanel < nPanelCount - 1 ) )
261 0 : aActivatePanel = *aCurrentPanel + 1;
262 0 : break;
263 : case ACTION_ACTIVATE_LAST:
264 0 : if ( nPanelCount > 0 )
265 0 : aActivatePanel = nPanelCount - 1;
266 0 : break;
267 : case ACTION_TOGGLE_FOCUS:
268 : {
269 0 : PToolPanel pActivePanel( GetActiveOrDummyPanel_Impl() );
270 0 : if ( !m_aPanelAnchor.HasChildPathFocus() )
271 0 : pActivePanel->GrabFocus();
272 : else
273 0 : GetLayouter()->SetFocusToPanelSelector();
274 : }
275 0 : break;
276 : }
277 :
278 0 : if ( !!aActivatePanel )
279 : {
280 0 : ActivatePanel( aActivatePanel );
281 0 : }
282 0 : }
283 :
284 : //--------------------------------------------------------------------
285 0 : bool ToolPanelDeck_Impl::FocusActivePanel()
286 : {
287 0 : ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() );
288 0 : if ( !aActivePanel )
289 0 : return false;
290 :
291 0 : PToolPanel pActivePanel( m_aPanels.GetPanel( *aActivePanel ) );
292 0 : pActivePanel->GrabFocus();
293 0 : return true;
294 : }
295 :
296 : //--------------------------------------------------------------------
297 65 : void ToolPanelDeck_Impl::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition )
298 : {
299 : // multiplex to our own listeners
300 65 : m_aListeners.PanelInserted( i_pPanel, i_nPosition );
301 65 : }
302 :
303 : //--------------------------------------------------------------------
304 0 : void ToolPanelDeck_Impl::PanelRemoved( const size_t i_nPosition )
305 : {
306 : // multiplex to our own listeners
307 0 : m_aListeners.PanelRemoved( i_nPosition );
308 0 : }
309 :
310 : //--------------------------------------------------------------------
311 16 : void ToolPanelDeck_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive )
312 : {
313 : // hide the old panel
314 16 : if ( !!i_rOldActive )
315 : {
316 3 : const PToolPanel pOldActive( m_aPanels.GetPanel( *i_rOldActive ) );
317 3 : pOldActive->Deactivate();
318 : }
319 :
320 : // position and show the new panel
321 16 : const PToolPanel pNewActive( !i_rNewActive ? m_pDummyPanel : m_aPanels.GetPanel( *i_rNewActive ) );
322 16 : pNewActive->Activate( m_aPanelAnchor );
323 16 : pNewActive->GrabFocus();
324 :
325 : // resize the panel (cannot guarantee it has ever been resized before
326 16 : pNewActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() );
327 :
328 : // multiplex to our own listeners
329 16 : m_aListeners.ActivePanelChanged( i_rOldActive, i_rNewActive );
330 16 : }
331 :
332 : //--------------------------------------------------------------------
333 0 : void ToolPanelDeck_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter )
334 : {
335 : // not interested in
336 : (void)i_rNewLayouter;
337 0 : }
338 :
339 : //--------------------------------------------------------------------
340 0 : void ToolPanelDeck_Impl::Dying()
341 : {
342 : // not interested in. Since the ToolPanelCollection is our member, this just means we ourself
343 : // are dying, and we already sent this notification in our dtor.
344 0 : }
345 :
346 : //--------------------------------------------------------------------
347 13 : void ToolPanelDeck_Impl::SetAccessibleParentWindow( Window* i_pAccessibleParent )
348 : {
349 13 : m_pAccessibleParent = i_pAccessibleParent;
350 13 : }
351 :
352 : //====================================================================
353 : //= ToolPanelDeck
354 : //====================================================================
355 : //--------------------------------------------------------------------
356 13 : ToolPanelDeck::ToolPanelDeck( Window& i_rParent, const WinBits i_nStyle )
357 : :Control( &i_rParent, i_nStyle )
358 13 : ,m_pImpl( new ToolPanelDeck_Impl( *this ) )
359 : {
360 : // use a default layouter
361 : // SetLayouter( PDeckLayouter( new TabDeckLayouter( *this, *this, TABS_RIGHT, TABITEM_IMAGE_AND_TEXT ) ) );
362 13 : SetLayouter( PDeckLayouter( new DrawerDeckLayouter( *this, *this ) ) );
363 13 : }
364 :
365 : //--------------------------------------------------------------------
366 26 : ToolPanelDeck::~ToolPanelDeck()
367 : {
368 13 : m_pImpl->NotifyDying();
369 13 : GetLayouter()->Destroy();
370 :
371 13 : Hide();
372 78 : for ( size_t i=0; i<GetPanelCount(); ++i )
373 : {
374 65 : PToolPanel pPanel( GetPanel( i ) );
375 65 : pPanel->Dispose();
376 65 : }
377 13 : }
378 :
379 : //--------------------------------------------------------------------
380 536 : size_t ToolPanelDeck::GetPanelCount() const
381 : {
382 536 : return m_pImpl->GetPanelCount();
383 : }
384 :
385 : //--------------------------------------------------------------------
386 311 : PToolPanel ToolPanelDeck::GetPanel( const size_t i_nPos ) const
387 : {
388 311 : return m_pImpl->GetPanel( i_nPos );
389 : }
390 :
391 : //--------------------------------------------------------------------
392 124 : ::boost::optional< size_t > ToolPanelDeck::GetActivePanel() const
393 : {
394 124 : return m_pImpl->GetActivePanel();
395 : }
396 :
397 : //--------------------------------------------------------------------
398 25 : void ToolPanelDeck::ActivatePanel( const ::boost::optional< size_t >& i_rPanel )
399 : {
400 25 : m_pImpl->ActivatePanel( i_rPanel );
401 25 : }
402 :
403 : //--------------------------------------------------------------------
404 65 : size_t ToolPanelDeck::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition )
405 : {
406 65 : return m_pImpl->InsertPanel( i_pPanel, i_nPosition );
407 : }
408 :
409 : //--------------------------------------------------------------------
410 0 : PToolPanel ToolPanelDeck::RemovePanel( const size_t i_nPosition )
411 : {
412 0 : return m_pImpl->RemovePanel( i_nPosition );
413 : }
414 :
415 : //--------------------------------------------------------------------
416 26 : PDeckLayouter ToolPanelDeck::GetLayouter() const
417 : {
418 26 : return m_pImpl->GetLayouter();
419 : }
420 :
421 : //--------------------------------------------------------------------
422 13 : void ToolPanelDeck::SetLayouter( const PDeckLayouter& i_pNewLayouter )
423 : {
424 13 : return m_pImpl->SetLayouter( i_pNewLayouter );
425 : }
426 :
427 : //--------------------------------------------------------------------
428 39 : void ToolPanelDeck::AddListener( IToolPanelDeckListener& i_rListener )
429 : {
430 39 : m_pImpl->AddListener( i_rListener );
431 39 : }
432 :
433 : //--------------------------------------------------------------------
434 52 : void ToolPanelDeck::RemoveListener( IToolPanelDeckListener& i_rListener )
435 : {
436 52 : m_pImpl->RemoveListener( i_rListener );
437 52 : }
438 :
439 : //--------------------------------------------------------------------
440 32 : Window& ToolPanelDeck::GetPanelWindowAnchor()
441 : {
442 32 : return m_pImpl->GetPanelWindowAnchor();
443 : }
444 :
445 : //--------------------------------------------------------------------
446 0 : const Window& ToolPanelDeck::GetPanelWindowAnchor() const
447 : {
448 0 : return m_pImpl->GetPanelWindowAnchor();
449 : }
450 :
451 : //--------------------------------------------------------------------
452 108 : void ToolPanelDeck::Resize()
453 : {
454 108 : Control::Resize();
455 108 : m_pImpl->LayoutAll();
456 108 : }
457 :
458 : //--------------------------------------------------------------------
459 345 : long ToolPanelDeck::Notify( NotifyEvent& i_rNotifyEvent )
460 : {
461 345 : bool bHandled = false;
462 345 : if ( i_rNotifyEvent.GetType() == EVENT_KEYINPUT )
463 : {
464 0 : const KeyEvent* pEvent = i_rNotifyEvent.GetKeyEvent();
465 0 : const KeyCode& rKeyCode = pEvent->GetKeyCode();
466 0 : if ( rKeyCode.GetModifier() == KEY_MOD1 )
467 : {
468 0 : bHandled = true;
469 0 : switch ( rKeyCode.GetCode() )
470 : {
471 : case KEY_HOME:
472 0 : m_pImpl->DoAction( ACTION_ACTIVATE_FIRST );
473 0 : break;
474 : case KEY_PAGEUP:
475 0 : m_pImpl->DoAction( ACTION_ACTIVATE_PREV );
476 0 : break;
477 : case KEY_PAGEDOWN:
478 0 : m_pImpl->DoAction( ACTION_ACTIVATE_NEXT );
479 0 : break;
480 : case KEY_END:
481 0 : m_pImpl->DoAction( ACTION_ACTIVATE_LAST );
482 0 : break;
483 : default:
484 0 : bHandled = false;
485 0 : break;
486 : }
487 : }
488 0 : else if ( rKeyCode.GetModifier() == ( KEY_MOD1 | KEY_SHIFT ) )
489 : {
490 0 : if ( rKeyCode.GetCode() == KEY_E )
491 : {
492 0 : m_pImpl->DoAction( ACTION_TOGGLE_FOCUS );
493 0 : bHandled = true;
494 : }
495 : }
496 : }
497 :
498 345 : if ( bHandled )
499 0 : return 1;
500 :
501 345 : return Control::Notify( i_rNotifyEvent );
502 : }
503 :
504 : //--------------------------------------------------------------------
505 0 : void ToolPanelDeck::GetFocus()
506 : {
507 0 : Control::GetFocus();
508 0 : if ( m_pImpl->IsDead() )
509 0 : return;
510 0 : if ( !m_pImpl->FocusActivePanel() )
511 : {
512 0 : PDeckLayouter pLayouter( GetLayouter() );
513 0 : ENSURE_OR_RETURN_VOID( pLayouter.get(), "ToolPanelDeck::GetFocus: no layouter?!" );
514 0 : pLayouter->SetFocusToPanelSelector();
515 : }
516 : }
517 :
518 : //--------------------------------------------------------------------
519 13 : void ToolPanelDeck::SetAccessibleParentWindow( Window* i_pAccessibleParent )
520 : {
521 13 : m_pImpl->SetAccessibleParentWindow( i_pAccessibleParent );
522 13 : }
523 :
524 : //--------------------------------------------------------------------
525 0 : Window* ToolPanelDeck::GetAccessibleParentWindow() const
526 : {
527 0 : Window* pAccessibleParent( m_pImpl->GetAccessibleParentWindow() );
528 0 : if ( !pAccessibleParent )
529 0 : pAccessibleParent = Window::GetAccessibleParentWindow();
530 0 : return pAccessibleParent;
531 : }
532 :
533 : //--------------------------------------------------------------------
534 13 : Reference< XWindowPeer > ToolPanelDeck::GetComponentInterface( sal_Bool i_bCreate )
535 : {
536 13 : Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( sal_False ) );
537 13 : if ( !xWindowPeer.is() && i_bCreate )
538 : {
539 13 : xWindowPeer.set( new ToolPanelDeckPeer( *this ) );
540 13 : SetComponentInterface( xWindowPeer );
541 : }
542 13 : return xWindowPeer;
543 : }
544 :
545 : //........................................................................
546 465 : } // namespace svt
547 : //........................................................................
548 :
549 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|