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