Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / Qtx / QtxDockWidget.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File:      QtxDockWidget.cxx
23 // Author:    Sergey TELKOV
24 //
25 #include "QtxDockWidget.h"
26
27 #include <QAction>
28 #include <QLayout>
29 #include <QMainWindow>
30 #include <QResizeEvent>
31 #include <QApplication>
32
33 /*!
34   \class QtxDockWidget::Watcher
35   \internal
36   \brief Internal class which goal is to watch parent dockable widget state changing.
37 */
38
39 class QtxDockWidget::Watcher : public QObject
40 {
41 public:
42   Watcher( QtxDockWidget* );
43
44   void           shown( QtxDockWidget* );
45   void           hidden( QtxDockWidget* );
46
47   virtual bool   eventFilter( QObject*, QEvent* );
48
49   bool           isEmpty() const;
50   bool           isVisible() const;
51
52 protected:
53   enum { Update = QEvent::User, Remove };
54
55   virtual void   customEvent( QEvent* );
56
57 private:
58   void           installFilters();
59
60   void           showContainer();
61   void           hideContainer();
62
63   void           updateIcon();
64   void           updateCaption();
65   void           updateVisibility();
66
67   void           setEmpty( const bool );
68   void           setVisible( const bool );
69
70 private:
71   QtxDockWidget* myCont;
72   bool           myState;
73   bool           myEmpty;
74   bool           myBlock;
75   bool           myShown;
76 };
77
78 /*!
79   \brief Constructor.
80   \param cont dockable widget to be watched
81 */
82 QtxDockWidget::Watcher::Watcher( QtxDockWidget* cont )
83 : QObject( cont ), myCont( cont ),
84   myState( true ),
85   myEmpty( false ),
86   myBlock( false )
87 {
88   myCont->installEventFilter( this );
89
90   installFilters();
91
92   myShown = myCont->isVisibleTo( myCont->parentWidget() );
93 }
94
95 /*!
96   \brief Custom event filter.
97   \param o event receiver object
98   \param e event sent to object
99   \return \c true if further event processing should be stopped
100 */
101 bool QtxDockWidget::Watcher::eventFilter( QObject* o, QEvent* e )
102 {
103   if ( o == myCont && ( e->type() == QEvent::Show || e->type() == QEvent::ShowToParent ||
104                         e->type() == QEvent::Hide || e->type() == QEvent::HideToParent ) )
105   {
106     installFilters();
107   }
108
109   if ( o == myCont && e->type() == QEvent::ChildAdded )
110   {
111     QChildEvent* ce = (QChildEvent*)e;
112     if ( ce->child()->isWidgetType() )
113       ce->child()->installEventFilter( this );
114
115     QApplication::postEvent( this, new QEvent( (QEvent::Type)Update ) );
116   }
117
118   if ( o != myCont && e->type() == QEvent::WindowIconChange )
119     updateIcon();
120
121   if ( o != myCont && e->type() == QEvent::WindowTitleChange )
122     updateCaption();
123
124   if ( o != myCont && ( e->type() == QEvent::HideToParent || e->type() == QEvent::ShowToParent ) )
125     updateVisibility();
126
127   if ( o == myCont && e->type() == QEvent::ChildRemoved )
128   {
129     QApplication::postEvent( this, new QEvent( (QEvent::Type)Remove ) );
130   }
131
132   return false;
133 }
134
135 /*!
136   \brief Set internal status to "shown"
137   \param dw dockable widget
138 */
139 void QtxDockWidget::Watcher::shown( QtxDockWidget* dw )
140 {
141   if ( dw != myCont )
142     return;
143
144   setVisible( true );
145 }
146
147 /*!
148   \brief Set internal status to "hidden"
149   \param dw dockable widget
150 */
151 void QtxDockWidget::Watcher::hidden( QtxDockWidget* dw )
152 {
153   if ( dw != myCont )
154     return;
155
156   setVisible( false );
157 }
158
159 bool QtxDockWidget::Watcher::isEmpty() const
160 {
161   return myEmpty;
162 }
163
164 bool QtxDockWidget::Watcher::isVisible() const
165 {
166   return myShown;
167 }
168
169 void QtxDockWidget::Watcher::setEmpty( const bool on )
170 {
171   myEmpty = on;
172 }
173
174 void QtxDockWidget::Watcher::setVisible( const bool on )
175 {
176   myShown = on;
177 }
178
179 /*!
180   \brief Show the dock window being watched
181 */
182 void QtxDockWidget::Watcher::showContainer()
183 {
184   if ( !myCont )
185     return;
186
187   bool vis = isVisible();
188
189   QtxDockWidget* cont = myCont;
190   myCont = 0;
191   cont->show();
192   myCont = cont;
193
194   setVisible( vis );
195 }
196
197 /*!
198   \brief Hide the dock window being watched
199 */
200 void QtxDockWidget::Watcher::hideContainer()
201 {
202   if ( !myCont )
203     return;
204
205   bool vis = isVisible();
206
207   QtxDockWidget* cont = myCont;
208   myCont = 0;
209   cont->hide();
210   myCont = cont;
211
212   setVisible( vis );
213 }
214
215 /*!
216   \brief Proces custom events.
217   \param e custom event (not used)
218 */
219 void QtxDockWidget::Watcher::customEvent( QEvent* e )
220 {
221   if ( e->type() == Update )
222   {
223     updateIcon();
224     updateCaption();
225     updateVisibility();
226   }
227   else if ( myCont && e->type() == Remove && !myCont->widget() )
228   {
229     myCont->deleteLater();
230     myCont = 0;
231   }
232 }
233
234 /*!
235   \brief Install this object as event filter to all children widgets
236          of the dockable widget being watched.
237 */
238 void QtxDockWidget::Watcher::installFilters()
239 {
240   if ( !myCont )
241     return;
242
243   QLayout* l = myCont->layout();
244   if ( !l )
245     return;
246
247   for ( int i = 0; i < (int)l->count(); i++ )
248   {
249     if ( l->itemAt( i ) && l->itemAt( i )->widget() )
250       l->itemAt( i )->widget()->installEventFilter( this );
251   }
252 }
253
254 /*!
255   \brief Update visibility state of all children widgets of the dockable widget
256          being watched.
257 */
258 void QtxDockWidget::Watcher::updateVisibility()
259 {
260   if ( !myCont )
261     return;
262
263   bool vis = false;
264   if ( myCont->widget() )
265     vis = myCont->widget()->isVisibleTo( myCont );
266   else
267   {
268     QLayout* l = myCont->layout();
269     if ( l )
270     {
271       for ( int i = 0; i < (int)l->count() && !vis; i++ )
272         vis = l->itemAt( i ) && l->itemAt( i )->widget() && l->itemAt( i )->widget()->isVisibleTo( myCont );
273     }
274   }
275
276   bool empty = isEmpty();
277   if ( empty == vis )
278   {
279     empty = !vis;
280     setEmpty( empty );
281     if ( !empty )
282       myCont->toggleViewAction()->setVisible( myState );
283     else
284     {
285       myState = myCont->toggleViewAction()->isVisible();
286       myCont->toggleViewAction()->setVisible( false );
287     }
288   }
289
290   vis = !empty && isVisible();
291   if ( vis != myCont->isVisibleTo( myCont->parentWidget() ) )
292     vis ? showContainer() : hideContainer();
293 }
294
295 /*!
296   \brief Update the icon of dockable window being watched
297 */
298 void QtxDockWidget::Watcher::updateIcon()
299 {
300   if ( !myCont || !myCont->widget() || myBlock )
301     return;
302
303   myBlock = true;
304   myCont->setWindowIcon( myCont->widget()->windowIcon() );
305   myBlock = false;
306 }
307
308 /*!
309   \brief Update the title of dockable window being watched
310 */
311 void QtxDockWidget::Watcher::updateCaption()
312 {
313   if ( myCont && myCont->widget() && !myCont->widget()->windowTitle().isNull() )
314     myCont->setWindowTitle( myCont->widget()->windowTitle() );
315 }
316
317 /*!
318   \class QtxDockWidget
319   \brief Enhanced dockable widget class.
320 */
321
322 /*!
323   \brief Constructor.
324   \param title dockable widget title
325   \param parent parent widget
326   \param f widget flags
327 */
328 QtxDockWidget::QtxDockWidget( const QString& title, QWidget* parent, Qt::WindowFlags f )
329 : QDockWidget( title, parent, f ),
330   myWatcher( 0 ),
331   myOrientation( (Qt::Orientation)-1 )
332 {
333   updateState();
334 }
335
336 /*!
337   \brief Constructor.
338   \param watch if \c true the event filter is installed to watch wigdet state changes
339          to update it properly
340   \param parent parent widget
341   \param f widget flags
342 */
343 QtxDockWidget::QtxDockWidget( const bool watch, QWidget* parent, Qt::WindowFlags f )
344 : QDockWidget( parent, f ),
345   myWatcher( 0 ),
346   myOrientation( (Qt::Orientation)-1 )
347 {
348   if ( watch )
349     myWatcher = new Watcher( this );
350
351   updateState();
352 }
353
354 /*!
355   \brief Constructor.
356   \param parent parent widget
357   \param f widget flags
358 */
359 QtxDockWidget::QtxDockWidget( QWidget* parent, Qt::WindowFlags f )
360 : QDockWidget( parent, f ),
361 myWatcher( 0 )
362 {
363 }
364
365 /*!
366   \brief Destructor.
367 */
368 QtxDockWidget::~QtxDockWidget()
369 {
370 }
371
372 /*!
373   \brief Get the recommended size for the widget.
374   \return recommended dockable widget size
375 */
376 QSize QtxDockWidget::sizeHint() const
377 {
378   QSize sz = QDockWidget::sizeHint();
379
380   printf( "----------------> QtxDockWidget::sizeHint()\n" );
381
382   return QSize( 500, 100 );
383
384   return sz;
385 }
386
387 /*!
388   \brief Get the recommended minimum size for the widget.
389   \return recommended dockable widget minimum size
390 */
391 QSize QtxDockWidget::minimumSizeHint() const
392 {
393   QSize sz = QDockWidget::minimumSizeHint();
394
395   return sz;
396 }
397
398 /*!
399   \brief Show/hide the dockable window.
400   \param on new visibility state
401 */
402 void QtxDockWidget::setVisible( bool on )
403 {
404   updateGeometry();
405   if ( widget() )
406     widget()->updateGeometry();
407
408   QDockWidget::setVisible( on && ( myWatcher ? !myWatcher->isEmpty() : true )  );
409
410   if ( myWatcher )
411   {
412     if ( on )
413       myWatcher->shown( this );
414     else
415       myWatcher->hidden( this );
416   }
417 }
418
419 /*!
420   \brief Process resize event
421   \param e event
422 */
423 void QtxDockWidget::resizeEvent( QResizeEvent* e )
424 {
425   QDockWidget::resizeEvent( e );
426   updateState();
427 }
428
429 /*!
430   \brief Get dockable window orientation.
431   \return orientation type
432 */
433 Qt::Orientation QtxDockWidget::orientation() const
434 {
435   QMainWindow* mw = 0;
436   QWidget* wid = parentWidget();
437   while ( wid && !mw )
438   {
439     mw = ::qobject_cast<QMainWindow*>( wid );
440     wid = wid->parentWidget();
441   }
442
443   Qt::Orientation res = (Qt::Orientation)-1;
444
445   if ( !mw )
446     return res;
447
448   Qt::DockWidgetArea area = mw->dockWidgetArea( (QtxDockWidget*)this );
449   switch ( area )
450   {
451   case Qt::LeftDockWidgetArea:
452   case Qt::RightDockWidgetArea:
453     res = Qt::Vertical;
454     break;
455   case Qt::TopDockWidgetArea:
456   case Qt::BottomDockWidgetArea:
457     res = Qt::Horizontal;
458     break;
459   default:
460     break;
461   }
462
463   return res;
464 }
465
466 /*!
467   \brief Update dockable window state.
468 */
469 void QtxDockWidget::updateState()
470 {
471   Qt::Orientation o = orientation();
472   if ( myOrientation == o )
473     return;
474
475   myOrientation = o;
476
477   emit orientationChanged( myOrientation );
478 }
479
480 /*!
481   \fn QtxDockWidget::orientationChanged(Qt::Orientation o)
482   \brief Emitted when the dockable window orientation is changed.
483   \param o new window orientation
484 */