Salome HOME
0a02955594b27611f7a77b21dc2d4d145405e22b
[modules/gui.git] / src / Qtx / QtxDockAction.cxx
1 // Copyright (C) 2005  OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D
2 // 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either 
6 // version 2.1 of the License.
7 // 
8 // This library is distributed in the hope that it will be useful 
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public  
14 // License along with this library; if not, write to the Free Software 
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/
18 //
19 // File:      QtxDockAction.cxx
20 // Author:    Sergey TELKOV
21
22 #include "QtxDockAction.h"
23
24 #include "QtxResourceMgr.h"
25
26 #include <qevent.h>
27 #include <qtoolbar.h>
28 #include <qdockarea.h>
29 #include <qdockwindow.h>
30 #include <qmainwindow.h>
31 #include <qobjectlist.h>
32 #include <qapplication.h>
33
34 /*!
35         Name: QtxDockAction [public]
36         Desc: Constructs an Dock action with given main window and name.
37 */
38
39 QtxDockAction::QtxDockAction( QMainWindow* mw, const char* name )
40 : QtxAction( "Windows and Toolbars", "Windows and Toolbars", 0, mw, name ),
41 myMain( mw ),
42 myAutoAdd( true ),
43 mySeparate( true ),
44 myAutoPlace( false )
45 {
46   initialize( mw );
47 }
48
49 /*!
50         Name: QtxDockAction [public]
51         Desc: This constructor creates an action with the following properties: the
52                     description text, the menu text and. It is a child of given main window
53         and named specified name.
54 */
55
56 QtxDockAction::QtxDockAction( const QString& text, const QString& menuText, QMainWindow* mw, const char* name )
57 : QtxAction( text, menuText, 0, mw, name ),
58 myMain( mw ),
59 myAutoAdd( true ),
60 mySeparate( true ),
61 myAutoPlace( false )
62 {
63   initialize( mw );
64 }
65
66 /*!
67         Name: QtxDockAction [public]
68         Desc: This constructor creates an action with the following properties: the
69                     description text, the menu text, the icon or iconset icon and keyboard
70         accelerator. It is a child of given main window and named specified name.
71 */
72
73 QtxDockAction::QtxDockAction( const QString& text, const QIconSet& icon, const QString& menuText, QMainWindow* mw, const char* name )
74 : QtxAction( text, icon, menuText, 0, mw, name ),
75 myMain( mw ),
76 myAutoAdd( true ),
77 mySeparate( true ),
78 myAutoPlace( false )
79 {
80   initialize( mw );
81 }
82
83 /*!
84         Name: ~QtxDockAction [public]
85         Desc: Removes all added popup items.
86 */
87
88 QtxDockAction::~QtxDockAction()
89 {
90   for ( MenuMap::ConstIterator mIt = myMenu.begin(); mIt != myMenu.end(); ++mIt )
91     removeFrom( mIt.key() );
92
93   for ( InfoMap::ConstIterator iIt = myInfo.begin(); iIt != myInfo.end(); ++iIt )
94     delete iIt.data().a;
95 }
96
97 /*!
98         Name: mainWindow [public]
99         Desc: Returns the main window which contains managed dock windows.
100 */
101
102 QMainWindow* QtxDockAction::mainWindow() const
103 {
104   return myMain;
105 }
106
107 /*!
108         Name: isAutoAdd [public]
109         Desc: Returns the auto add property. If this property is setted then all newly
110         appeared dock windows will be automatically added.
111 */
112
113 bool QtxDockAction::isAutoAdd() const
114 {
115   return myAutoAdd;
116 }
117
118 /*!
119         Name: setAutoAdd [public]
120         Desc: Sets the auto add property. If this property is setted then all newly
121         appeared dock windows will be automatically added.
122 */
123
124 void QtxDockAction::setAutoAdd( const bool on )
125 {
126   myAutoAdd = on;
127 }
128
129 /*!
130         Name: isAutoPlace [public]
131         Desc: Returns the auto place property. If this property is setted then all newly
132         added dock windows will be automatically placed according stored place information.
133 */
134
135 bool QtxDockAction::isAutoPlace() const
136 {
137   return myAutoPlace;
138 }
139
140 /*!
141         Name: setAutoPlace [public]
142         Desc: Sets the auto place property. If this property is setted then all newly
143         added dock windows will be automatically placed according stored place
144         information.
145 */
146
147 void QtxDockAction::setAutoPlace( const bool on )
148 {
149   myAutoPlace = on;
150 }
151
152 /*!
153         Name: isSeparate [public]
154         Desc: Returns the 'separate' property.
155 */
156
157 bool QtxDockAction::isSeparate() const
158 {
159   return mySeparate;
160 }
161
162 /*!
163         Name: setSeparate [public]
164         Desc: Sets the 'separate' property. If this property is 'true' then toolbars and
165         dock windows menu items will be placed in different popup menus  otherwise
166         their will  be placed  in  one  common  popup  menu. This property will be
167         affected in next method 'addTo'.
168 */
169
170 void QtxDockAction::setSeparate( const bool on )
171 {
172   if ( mySeparate == on )
173     return;
174
175   mySeparate = on;
176   updateMenus();
177 }
178
179 /*!
180         Name: addTo [public]
181         Desc: Add the dock windows sub menu item to the end of specified popup.
182 */
183
184 bool QtxDockAction::addTo( QWidget* wid )
185 {
186   return addTo( wid, -1 );
187 }
188
189 /*!
190         Name: addTo [public]
191         Desc: Add the dock windows sub menu item to specified popup at the given index.
192 */
193
194 bool QtxDockAction::addTo( QWidget* wid, const int idx )
195 {
196   if ( !wid || !wid->inherits( "QPopupMenu" ) )
197     return false;
198
199   QPopupMenu* pm = (QPopupMenu*)wid;
200   checkPopup( pm );
201
202   if ( myMenu.contains( pm ) )
203     return false;
204
205   MenuInfo mInfo;
206   mInfo.dock = new QPopupMenu( pm );
207   mInfo.tool = isSeparate() ? new QPopupMenu( pm ) : 0;
208
209   QString dock, tool;
210   splitMenuText( dock, tool );
211
212   myMenu.insert( pm, mInfo );
213
214   int index = idx;
215
216   if ( mInfo.dock )
217     iconSet().isNull() ? pm->insertItem ( dock, mInfo.dock, -1, index ) :
218                          pm->insertItem ( iconSet(), dock, mInfo.dock, -1, index );
219
220   if ( index >= 0 )
221     index++;
222
223   if ( mInfo.tool )
224     iconSet().isNull() ? pm->insertItem ( tool, mInfo.tool, -1, index ) :
225                          pm->insertItem ( iconSet(), tool, mInfo.tool, -1, index );
226
227   connect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
228   connect( pm, SIGNAL( destroyed( QObject* ) ), this, SLOT( onPopupDestroyed( QObject* ) ) );
229
230   return true;
231 }
232
233 /*!
234         Name: removeFrom [public]
235         Desc: Removes dock window sub menu from specified popup.
236 */
237
238 bool QtxDockAction::removeFrom( QWidget* wid )
239 {
240   QPopupMenu* pm = (QPopupMenu*)wid;
241
242   if ( myMenu.contains( pm ) )
243   {
244     pm->removeItem( findId( pm, myMenu[pm].dock ) );
245     pm->removeItem( findId( pm, myMenu[pm].tool ) );
246
247     delete myMenu[pm].dock;
248     delete myMenu[pm].tool;
249     myMenu.remove( pm );
250
251     disconnect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
252     disconnect( pm, SIGNAL( destroyed( QObject* ) ), this, SLOT( onPopupDestroyed( QObject* ) ) );
253   }
254
255   return QtxAction::removeFrom( wid );
256 }
257
258 void QtxDockAction::setMenuText( const QString& txt )
259 {
260   if ( menuText() == txt )
261     return;
262
263   QtxAction::setMenuText( txt );
264   updateMenus();
265 }
266
267 /*!
268         Name: addDockWindow [public]
269         Desc: Add dock window to internal data structures. Action will be include all added
270         dock windows in to menu and manage their place configuration.
271 */
272
273 bool QtxDockAction::addDockWindow( QDockWindow* dw )
274 {
275   if ( !dw || !mainWindow() )
276     return false;
277
278   if ( myInfo.contains( dw ) )
279     return false;
280
281   myInfo.insert( dw, DockInfo() );
282
283   DockInfo& inf = myInfo[dw];
284   inf.name = windowName( dw );
285   QAction* a = inf.a = new QAction( mainWindow(), 0, true );
286
287   autoLoadPlaceInfo( dw );
288
289   bool block = a->signalsBlocked();
290   a->blockSignals( true );
291   a->setOn( dw->isVisibleTo( mainWindow() ) );
292   a->blockSignals( block );
293
294   updateInfo( dw );
295   savePlaceInfo( dw );
296
297   dw->installEventFilter( this );
298
299   connect( a, SIGNAL( toggled( bool ) ), this, SLOT( onToggled( bool ) ) );
300   connect( dw, SIGNAL( destroyed( QObject* ) ), this, SLOT( onWindowDestroyed( QObject* ) ) );
301   connect( dw, SIGNAL( visibilityChanged( bool ) ), this, SLOT( onVisibilityChanged( bool ) ) );
302
303   return true;
304 }
305
306 /*!
307         Name: removeDockWindow [public]
308         Desc: Remove dock window from internal data structures. Action will not manage this window.
309 */
310
311 bool QtxDockAction::removeDockWindow( QDockWindow* dw )
312 {
313   if ( !myInfo.contains( dw ) )
314     return false;
315
316   myGeom.remove( myInfo[dw].name );
317
318   delete myInfo[dw].a;
319   myInfo.remove( dw );
320
321   dw->removeEventFilter( this );
322
323   disconnect( dw, SIGNAL( destroyed( QObject* ) ), this, SLOT( onWindowDestroyed( QObject* ) ) );
324   disconnect( dw, SIGNAL( visibilityChanged( bool ) ), this, SLOT( onVisibilityChanged( bool ) ) );
325
326   return true;
327 }
328
329 /*!
330         Name: eventFilter [public]
331         Desc: Event filter process caption and icon changing of managed dock windows
332         and try to add newly appeared dock windows.
333 */
334
335 bool QtxDockAction::eventFilter( QObject* o, QEvent* e )
336 {
337   if ( o->inherits( "QDockWindow" ) && ( e->type() == QEvent::CaptionChange ||
338                                          e->type() == QEvent::IconChange ) )
339     updateInfo( (QDockWindow*)o );
340
341   if ( o->inherits( "QDockArea" ) && e->type() == QEvent::ChildRemoved )
342   {
343     QChildEvent* ce = (QChildEvent*)e;
344     if ( ce->child() && ce->child()->inherits( "QDockWindow" ) )
345       savePlaceInfo( (QDockWindow*)ce->child() );
346   }
347
348   if ( o->inherits( "QDockArea" ) && e->type() == QEvent::ChildInserted )
349   {
350     QChildEvent* ce = (QChildEvent*)e;
351     if ( ce->child() && ce->child()->inherits( "QDockWindow" ) )
352       QApplication::postEvent( this, new QCustomEvent( (QEvent::Type)AutoAdd, ce->child() ) );
353   }
354
355   return false;
356 }
357
358 /*!
359         Name: restoreGeometry [public]
360         Desc: Retrieve the dock window geometry. If dock window specified as 0
361         then all windows geometry will be restored.
362 */
363
364 void QtxDockAction::restoreGeometry( QDockWindow* dw ) const
365 {
366   if ( !dw )
367     loadPlaceInfo();
368   else
369     loadPlaceInfo( dw );
370 }
371
372 /*!
373         Name: storeGeometry [public]
374         Desc: Store the dock window geometry. If dock window specified as 0
375         then all windows geometry will be stored.
376 */
377
378 void QtxDockAction::storeGeometry( QDockWindow* dw )
379 {
380   QPtrList<QDockWindow> dwList;
381
382   if ( dw )
383     dwList.append( dw );
384   else
385     dockWindows( dwList );
386
387   for ( QPtrListIterator<QDockWindow> it( dwList ); it.current(); ++it )
388     savePlaceInfo( it.current() );
389 }
390
391 /*!
392         Name: loadGeometry [public]
393         Desc: Retrieve the dock windows geometry information from the specified resource manager section.
394 */
395
396 void QtxDockAction::loadGeometry( QtxResourceMgr* resMgr, const QString& section, const bool clear )
397 {
398   QString sec = section.stripWhiteSpace();
399   if ( !resMgr || sec.isEmpty() )
400     return;
401
402   myNames = QStringList::split( "|", resMgr->stringValue( sec, "windows_list", QString::null ) );
403
404   QMap<QString, int> map;
405   QStringList params = resMgr->parameters( sec );
406   for ( QStringList::const_iterator it = params.begin(); it != params.end(); ++it )
407   {
408     QString p = QStringList::split( ".", *it, true ).first().stripWhiteSpace();
409     if ( !p.isEmpty() )
410       map.insert( p, 0 );
411   }
412
413   for ( QMap<QString, int>::ConstIterator itr = map.begin(); itr != map.end(); ++itr )
414   {
415     GeomInfo inf;
416     if ( !clear && myGeom.contains( itr.key() ) )
417       inf = myGeom[itr.key()];
418     else
419     {
420       inf.vis = true; inf.newLine = false; inf.place = DockTop;
421       inf.index = 0; inf.offset = 0;
422       inf.x = 0; inf.y = 0; inf.w = 0; inf.h = 0;
423       inf.fixW = -1; inf.fixH = -1;
424     }
425     if ( loadGeometry( resMgr, sec, itr.key(), inf ) )
426       myGeom.insert( itr.key(), inf );
427   }
428 }
429
430 /*!
431         Name: saveGeometry [public]
432         Desc: Store the dock windows geometry information into the specified resource manager section.
433 */
434
435 void QtxDockAction::saveGeometry( QtxResourceMgr* resMgr, const QString& section, const bool clear ) const
436 {
437   QString sec = section.stripWhiteSpace();
438   if ( !resMgr || sec.isEmpty() )
439     return;
440
441   QtxDockAction* that = (QtxDockAction*)this;
442   that->storeGeometry();
443
444   that->myNames.clear();
445   collectNames( Minimized, that->myNames );
446   for ( int i = DockTornOff; i < Minimized; i++ )
447     collectNames( i, that->myNames );
448
449   if ( clear )
450     resMgr->remove( sec );
451
452   resMgr->setValue( sec, "windows_list", myNames.join( "|" ) );
453
454   for ( GeomMap::ConstIterator it = myGeom.begin(); it != myGeom.end(); ++it )
455     saveGeometry( resMgr, sec, it.key(), it.data() );
456 }
457
458 /*!
459         Name: onAboutToShow [private slots]
460         Desc: Prepare sub popup with dock windows list when parent popup is shown.
461 */
462
463 void QtxDockAction::onAboutToShow()
464 {
465   const QObject* obj = sender();
466   if ( obj && obj->inherits( "QPopupMenu" ) )
467   {
468     QPopupMenu* pm = (QPopupMenu*)obj;
469     fillPopup( pm );
470     pm->setItemEnabled( findId( pm, myMenu[pm].dock ), isEnabled() && myMenu[pm].dock && myMenu[pm].dock->count() );
471     pm->setItemEnabled( findId( pm, myMenu[pm].tool ), isEnabled() && myMenu[pm].tool && myMenu[pm].tool->count() );
472   }
473 }
474
475 /*!
476         Name: onToggled [private slots]
477         Desc: Show or hide dock window when user toggled window item in popup.
478 */
479
480 void QtxDockAction::onToggled( bool on )
481 {
482   QDockWindow* dw = dockWindow( (QAction*)sender() );
483   if ( dw )
484     on ? dw->show() : dw->hide();
485 }
486
487 /*!
488         Name: onPopupDestroyed [private slots]
489         Desc: Remove destroyed popup from data structures.
490 */
491
492 void QtxDockAction::onPopupDestroyed( QObject* obj )
493 {
494   myMenu.remove( (QPopupMenu*)obj );
495 }
496
497 /*!
498         Name: onWindowDestroyed [private slots]
499         Desc: Remove information about destroyed dock window.
500 */
501
502 void QtxDockAction::onWindowDestroyed( QObject* obj )
503 {
504   QDockWindow* dw = (QDockWindow*)obj;
505   if ( !myInfo.contains( dw ) )
506     return;
507
508   delete myInfo[dw].a;
509   myInfo.remove( dw );
510 }
511
512 /*!
513         Name: onVisibilityChanged [private slots]
514         Desc: Toggle corresponded action when visibility state of dock window changed.
515 */
516
517 void QtxDockAction::onVisibilityChanged( bool on )
518 {
519   const QObject* obj = sender();
520   if ( !obj || !obj->inherits( "QDockWindow" ) )
521     return;
522
523   QDockWindow* dw = (QDockWindow*)obj;
524
525   QAction* a = action( dw );
526   if ( a && a->isOn() != on )
527   {
528     bool block = a->signalsBlocked();
529     a->blockSignals( true );
530     a->setOn( on );
531     a->blockSignals( block );
532   }
533
534   savePlaceInfo( dw );
535 }
536
537 /*!
538         Name: onDockWindowPositionChanged [private slots]
539         Desc: Update dock window place information
540 */
541
542 void QtxDockAction::onDockWindowPositionChanged( QDockWindow* dw )
543 {
544   savePlaceInfo( dw );
545 }
546
547 /*!
548         Name: event [protected]
549         Desc: Check consistency the popup content and internal datas.
550         Synchronize internal data structures with popup content.
551 */
552
553 bool QtxDockAction::event( QEvent* e )
554 {
555   if ( e->type() == (int)AutoAdd )
556   {
557     QCustomEvent* ce = (QCustomEvent*)e;
558     QDockWindow* dw = (QDockWindow*)ce->data();
559     if ( !myInfo.contains( dw ) )
560     {
561       autoAddDockWindow( dw );
562       autoLoadPlaceInfo( dw );
563     }
564   }
565
566   return QtxAction::event( e );
567 }
568
569 /*!
570         Name: checkPopup [private]
571         Desc: Check consistency the popup content and internal datas.
572         Synchronize internal data structures with popup content.
573 */
574
575 void QtxDockAction::checkPopup( QPopupMenu* pm )
576 {
577   if ( !myMenu.contains( pm ) )
578     return;
579
580   int id = findId( pm, myMenu[pm].dock );
581   if ( id == -1 )
582   {
583     delete myMenu[pm].dock;
584     myMenu[pm].dock = 0;
585   }
586   id = findId( pm, myMenu[pm].tool );
587   if ( id == -1 )
588   {
589     delete myMenu[pm].tool;
590     myMenu[pm].tool = 0;
591   }
592
593   if ( !myMenu[pm].dock )
594   {
595     delete myMenu[pm].tool;
596     myMenu.remove( pm );
597     disconnect( pm, SIGNAL( destroyed( QObject* ) ), this, SLOT( onDestroyed( QObject* ) ) );
598   }
599 }
600
601 /*!
602         Name: fillPopup [private]
603         Desc: Clear the popup and the add to it required actions.
604 */
605
606 void QtxDockAction::fillPopup( QPopupMenu* pm ) const
607 {
608   if ( !pm || !mainWindow() )
609     return;
610
611   if ( !myMenu.contains( pm ) )
612     return;
613
614   QPopupMenu* dockMenu = myMenu[pm].dock;
615   QPopupMenu* toolMenu = myMenu[pm].tool;
616
617   for ( InfoMap::ConstIterator mit = myInfo.begin(); mit != myInfo.end(); ++mit )
618   {
619     mit.data().a->removeFrom( dockMenu );
620     mit.data().a->removeFrom( toolMenu );
621   }
622
623   if ( dockMenu )
624     dockMenu->clear();
625
626   if ( toolMenu )
627     toolMenu->clear();
628
629   QPtrList<QDockWindow> dockList;
630   dockWindows( dockList, mainWindow() );
631
632   if ( dockList.isEmpty() )
633     return;
634
635   QPtrList<QAction> toolBars, windows;
636   for ( QPtrListIterator<QDockWindow> it( dockList ); it.current(); ++it )
637   {
638     if ( !myInfo.contains( it.current() ) )
639     {
640       QtxDockAction* that = (QtxDockAction*)this;
641       that->autoAddDockWindow( it.current() );
642     }
643
644     if ( !mainWindow()->appropriate( it.current() ) ||
645          it.current()->caption().isEmpty() || !action( it.current() ) )
646       continue;
647
648     if ( isToolBar( it.current() ) )
649       toolBars.append( action( it.current() ) );
650     else
651       windows.append( action( it.current() ) );
652   }
653
654   for ( QPtrListIterator<QAction> wit( windows ); wit.current(); ++wit )
655     wit.current()->addTo( dockMenu );
656
657   dockMenu->insertSeparator();
658
659   for ( QPtrListIterator<QAction> tit( toolBars ); tit.current(); ++tit )
660     tit.current()->addTo( toolMenu ? toolMenu : dockMenu );
661
662   Qtx::simplifySeparators( dockMenu );
663   Qtx::simplifySeparators( toolMenu );
664 }
665
666 /*!
667         Name: isToolBar [private]
668         Desc: Returns 'true' if dock window is a toolbar.
669 */
670
671 bool QtxDockAction::isToolBar( QDockWindow* dw ) const
672 {
673   return dw && dw->inherits( "QToolBar" );
674 }
675
676 /*!
677         Name: findId [private]
678         Desc: Returns identificator of popup item which contains sub popup 'pm' in the popup 'cont'.
679 */
680
681 int QtxDockAction::findId( QPopupMenu* cont, QPopupMenu* pm ) const
682 {
683   if ( !cont || !pm )
684     return -1;
685
686   int id = -1;
687
688   for ( int i = 0; i < (int)cont->count() && id == -1; i++ )
689   {
690     QMenuData* md = 0;
691     QMenuItem* item = cont->findItem( cont->idAt( i ), &md );
692     if ( item && md == cont && item->popup() == pm )
693       id = item->id();
694   }
695   return id;
696 }
697
698 /*!
699         Name: dockWindows [private]
700         Desc: Returns all dock windows of the main window.
701 */
702
703 void QtxDockAction::dockWindows( QPtrList<QDockWindow>& lst, QMainWindow* main ) const
704 {
705   lst.clear();
706
707   QMainWindow* mw = main ? main : mainWindow();
708   if ( !mw )
709     return;
710
711   QObjectList* objs = mw->queryList( "QDockWindow" );
712   if ( objs )
713   {
714     for ( QObjectListIt it( *objs ); it.current(); ++it )
715     {
716       QDockWindow* dockWin = ::qt_cast<QDockWindow*>( it.current() );
717       if ( dockWin && dockMainWindow( mw, dockWin ) )
718         lst.append( dockWin );
719     }
720   }
721   delete objs;
722 }
723
724 bool QtxDockAction::dockMainWindow( QMainWindow* mw, QObject* win ) const
725 {
726   if ( !mw || !win )
727     return false;
728
729   while ( win )
730   {
731     if ( win->parent() && win->parent() == mw )
732       return true;
733
734     if ( ::qt_cast<QMainWindow*>( win->parent() ) )
735       return false;
736
737     win = win->parent();
738   }
739
740   return false;
741 }
742
743 /*!
744         Name: updateInfo [private]
745         Desc: Updates icon and caption info of dock window in the corresponded action.
746 */
747
748 void QtxDockAction::updateInfo( QDockWindow* dw )
749 {
750   QAction* a = action( dw );
751   if ( !a )
752     return;
753
754   a->setText( dw->caption() );
755   a->setMenuText( dw->caption() );
756
757   if ( isToolBar( dw ) )
758     a->setStatusTip( tr( "Toggles toolbar \"%1\" on/off" ).arg( dw->caption() ) );
759   else
760     a->setStatusTip( tr( "Toggles window \"%1\" on/off" ).arg( dw->caption() ) );
761
762   const QPixmap* icon = dw->icon();
763   if ( icon )
764     a->setIconSet( *icon );
765 }
766
767 /*!
768         Name: savePlaceInfo [private]
769         Desc: Store the place and geometry information from specified dock window.
770 */
771
772 void QtxDockAction::savePlaceInfo( QDockWindow* dw )
773 {
774   if ( !myInfo.contains( dw ) )
775     return;
776
777   if ( !myGeom.contains( myInfo[dw].name ) )
778     myGeom.insert( myInfo[dw].name, GeomInfo() );
779
780   GeomInfo& inf = myGeom[myInfo[dw].name];
781
782   Dock dock;
783   inf.vis = dw->isVisibleTo( mainWindow() );
784   mainWindow()->getLocation( dw, dock, inf.index, inf.newLine, inf.offset );
785
786   inf.place = dock;
787   inf.x = dw->x();
788   inf.y = dw->y();
789   inf.w = dw->width();
790   inf.h = dw->height();
791   inf.fixW = dw->fixedExtent().width();
792   inf.fixH = dw->fixedExtent().height();
793 }
794
795 /*!
796         Name: loadPlaceInfo [private]
797         Desc: Retrieve the stored place and geometry information to specified dock window.
798 */
799
800 void QtxDockAction::loadPlaceInfo( QDockWindow* dw ) const
801 {
802   if ( !myInfo.contains( dw ) )
803     return;
804
805   QMainWindow* mw = mainWindow();
806   if ( !mw )
807     return;
808
809   QObject* p = dw->parent();
810   if ( !( !p || p == mw || ( p->parent() && p->parent() == mw ) ) )
811     return;
812
813   QString winName = myInfo[dw].name;
814   if ( winName.isEmpty() || !myGeom.contains( winName ) )
815     return;
816
817   GeomInfo inf = myGeom[myInfo[dw].name];
818
819   mainWindow()->moveDockWindow( dw, (Qt::Dock)inf.place, inf.newLine, inf.index, inf.offset );
820   dw->setGeometry( inf.x, inf.y, inf.w, inf.h );
821
822   dw->setFixedExtentWidth( inf.fixW );
823   dw->setFixedExtentHeight( inf.fixH );
824
825   QtxDockAction* that = (QtxDockAction*)this;
826   that->myGeom.insert( myInfo[dw].name, inf );
827 }
828
829 /*!
830         Name: loadPlaceInfo [private]
831         Desc: Retrieve the stored place and geometry information to all dock windows.
832 */
833
834 void QtxDockAction::loadPlaceInfo() const
835 {
836   QMainWindow* mw = mainWindow();
837   if ( !mw )
838     return;
839
840   typedef QPtrList<QDockWindow> DockWinList;
841
842   DockWinList lst;
843   dockWindows( lst, mw );
844
845   QMap<QString, QDockWindow*> nameMap;
846   for ( QPtrListIterator<QDockWindow> itr( lst ); itr.current(); ++itr )
847   {
848     QObject* p = itr.current()->parent();
849     if ( !( !p || p == mw || ( p->parent() && p->parent() == mw ) ) )
850       continue;
851
852     QString name;
853     if ( myInfo.contains( itr.current() ) )
854       name = myInfo[itr.current()].name;
855
856     if ( !myGeom.contains( name ) )
857       continue;
858
859     nameMap.insert( name, itr.current() );
860   }
861
862   DockWinList winList;
863   for ( QStringList::const_iterator iter = myNames.begin(); iter != myNames.end(); ++iter )
864   {
865     if ( nameMap.contains( *iter ) )
866       winList.append( nameMap[*iter] );
867     nameMap.remove( *iter );
868   }
869
870   for ( QMap<QString, QDockWindow*>::ConstIterator mIt = nameMap.begin(); mIt != nameMap.end(); ++mIt )
871     winList.append( mIt.data() );
872
873   QMap<int, DockWinList> winMap;
874   QMap<QDockWindow*, GeomInfo*> geomMap;
875
876   for ( QPtrListIterator<QDockWindow> it( winList ); it.current(); ++it )
877   {
878     QString name;
879     if ( myInfo.contains( it.current() ) )
880       name = myInfo[it.current()].name;
881
882     if ( !myGeom.contains( name ) )
883       continue;
884
885     //! collect pointer of info to have fresh info data after processEvents();
886     GeomInfo* inf = (GeomInfo*)&( myGeom[name] );
887     geomMap.insert( it.current(), inf );
888     if ( !winMap.contains( inf->place ) )
889       winMap.insert( inf->place, DockWinList() );
890     winMap[inf->place].append( it.current() );
891   }
892
893   loadPlaceArea( DockMinimized, mw, 0,
894                  winMap.contains( DockMinimized ) ? winMap[DockMinimized] : DockWinList(), geomMap );
895   for ( int i = DockTornOff; i < DockMinimized; i++ )
896   {
897     loadPlaceArea( i, mw, dockArea( i ), winMap.contains( i ) ? winMap[i] : DockWinList(), geomMap );
898   }
899 }
900
901 /*!
902         Name: loadPlaceArea [private]
903         Desc: Set the place and geometry information to all dock windows in the area.
904 */
905
906 void QtxDockAction::loadPlaceArea( const int place, QMainWindow* mw, QDockArea* area,
907                                    const QPtrList<QDockWindow>& dockList,
908                                    const QMap<QDockWindow*, GeomInfo*>& geomMap ) const
909 {
910   for ( QPtrListIterator<QDockWindow> it( dockList ); it.current(); ++it )
911   {
912     if ( !geomMap.contains( it.current() ) )
913       continue;
914
915     GeomInfo* inf = geomMap[it.current()];
916     mw->moveDockWindow( it.current(), (Qt::Dock)place, inf->newLine, inf->index, inf->offset );
917   }
918
919   if ( !area )
920     return;
921
922   qApp->processEvents();
923
924   for ( QPtrListIterator<QDockWindow> itr( dockList ); itr.current(); ++itr )
925   {
926     QDockWindow* dw = itr.current();
927     if ( !geomMap.contains( dw ) )
928       continue;
929
930     GeomInfo* inf = geomMap[dw];
931     if ( place != DockTornOff )
932     {
933       dw->setNewLine( inf->newLine );
934                   dw->setOffset( inf->offset );
935                   dw->setFixedExtentWidth( inf->fixW );
936                   dw->setFixedExtentHeight( inf->fixH );
937     }
938     dw->setGeometry( inf->x, inf->y, inf->w, inf->h );
939
940     QAction* a = action( dw );
941     if ( a )
942     {
943       bool block = a->signalsBlocked();
944       a->blockSignals( true );
945       a->setOn( inf->vis );
946       a->blockSignals( block );
947     }
948
949     if ( mainWindow() && mainWindow()->appropriate( dw ) )
950       inf->vis ? dw->show() : dw->hide();
951   }
952
953   QWidget* wid = area;
954   if ( wid->layout() )
955   {
956     wid->layout()->invalidate();
957     wid->layout()->activate();
958   }
959 }
960
961 /*!
962         Name: action [private]
963         Desc: Returns action for the given dock window.
964 */
965
966 QAction* QtxDockAction::action( QDockWindow* dw ) const
967 {
968   QAction* a = 0;
969   if ( myInfo.contains( dw ) )
970     a = myInfo[dw].a;
971   return a;
972 }
973
974 /*!
975         Name: dockWindow [private]
976         Desc: Returns dock window for the given action.
977 */
978
979 QDockWindow* QtxDockAction::dockWindow( const QAction* a ) const
980 {
981   QDockWindow* dw = 0;
982   for ( InfoMap::ConstIterator it = myInfo.begin(); it != myInfo.end() && !dw; ++it )
983   {
984     if ( it.data().a == a )
985       dw = it.key();
986   }
987   return dw;
988 }
989
990 /*!
991         Name: initialize [private]
992         Desc: Initialisation of the object. Sets the event filters and add existing dock windows.
993 */
994
995 void QtxDockAction::initialize( QMainWindow* mw )
996 {
997   if ( !mw )
998     return;
999
1000   QPtrList<QDockWindow> lst;
1001   dockWindows( lst, mw );
1002
1003   for ( QPtrListIterator<QDockWindow> it( lst ); it.current(); ++it )
1004     QApplication::postEvent( this, new QCustomEvent( (QEvent::Type)AutoAdd, it.current() ) );
1005
1006   if ( mw->topDock() )
1007     mw->topDock()->installEventFilter( this );
1008   if ( mw->leftDock() )
1009     mw->leftDock()->installEventFilter( this );
1010   if ( mw->rightDock() )
1011     mw->rightDock()->installEventFilter( this );
1012   if ( mw->bottomDock() )
1013     mw->bottomDock()->installEventFilter( this );
1014
1015   connect( mw, SIGNAL( dockWindowPositionChanged( QDockWindow* ) ),
1016            this, SLOT( onDockWindowPositionChanged( QDockWindow* ) ) );
1017 }
1018
1019 /*!
1020         Name: windowName [private]
1021         Desc: Generate the dock window name.
1022 */
1023
1024 QString QtxDockAction::windowName( QDockWindow* dw ) const
1025 {
1026   QString name;
1027
1028   if ( dw )
1029   {
1030     name = dw->name( "" );
1031     if ( name.isEmpty() )
1032       name = dw->caption();
1033   }
1034
1035   return name;
1036 }
1037
1038 /*!
1039         Name: autoAddDockWindow [private]
1040         Desc: Add the dock window if auto add property is setted.
1041 */
1042
1043 bool QtxDockAction::autoAddDockWindow( QDockWindow* dw )
1044 {
1045   if ( !isAutoAdd() )
1046     return false;
1047
1048   return addDockWindow( dw );
1049 }
1050
1051 /*!
1052         Name: autoLoadPlaceInfo [private]
1053         Desc: Retieve the dock window place geometry if auto place property is setted.
1054 */
1055
1056 void QtxDockAction::autoLoadPlaceInfo( QDockWindow* dw )
1057 {
1058   if ( isAutoPlace() )
1059     loadPlaceInfo( dw );
1060 }
1061
1062 /*!
1063         Name: splitMenuText [private]
1064         Desc: 
1065 */
1066
1067 void QtxDockAction::splitMenuText( QString& dock, QString& tool ) const
1068 {
1069   dock = tool = menuText();
1070   if ( !isSeparate() )
1071     return;
1072
1073   QStringList lst = splitText( menuText(), "|" );
1074   if ( lst.count() < 2 )
1075     lst = splitText( menuText(), "and" );
1076
1077   dock = lst.first();
1078   tool = lst.last();
1079 }
1080
1081 /*!
1082         Name: splitText [private]
1083         Desc: 
1084 */
1085
1086 QStringList QtxDockAction::splitText( const QString& str, const QString& sep ) const
1087 {
1088   QStringList res;
1089
1090   int idx = str.lower().find( sep.lower() );
1091   if ( idx != -1 )
1092   {
1093     res.append( str.mid( 0, idx ).stripWhiteSpace() );
1094     res.append( str.mid( idx + sep.length() ).stripWhiteSpace() );
1095   }
1096
1097   return res;
1098 }
1099
1100 /*!
1101         Name: dockPlace [private]
1102         Desc: 
1103 */
1104
1105 int QtxDockAction::dockPlace( const QString& dockName ) const
1106 {
1107   static QMap<QString, int> dockNameMap;
1108   if ( dockNameMap.isEmpty() )
1109   {
1110     dockNameMap["top"]       = DockTop;
1111     dockNameMap["bottom"]    = DockBottom;
1112     dockNameMap["left"]      = DockLeft;
1113     dockNameMap["right"]     = DockRight;
1114     dockNameMap["tornoff"]   = DockTornOff;
1115     dockNameMap["torn_off"]  = DockTornOff;
1116     dockNameMap["outside"]   = DockTornOff;
1117     dockNameMap["undock"]    = DockTornOff;
1118     dockNameMap["minimized"] = DockMinimized;
1119     dockNameMap["unmanaged"] = DockUnmanaged;
1120   }
1121
1122   int res = -1;
1123   if ( dockNameMap.contains( dockName.lower() ) )
1124     res = dockNameMap[dockName.lower()];
1125   return res;
1126 }
1127
1128 /*!
1129         Name: dockArea [private]
1130         Desc: 
1131 */
1132
1133 QDockArea* QtxDockAction::dockArea( const int place ) const
1134 {
1135   if ( !mainWindow() )
1136     return 0;
1137
1138   QDockArea* area = 0;
1139   switch ( place )
1140   {
1141   case DockTop:
1142     area = mainWindow()->topDock();
1143     break;
1144   case DockBottom:
1145     area = mainWindow()->bottomDock();
1146     break;
1147   case DockLeft:
1148     area = mainWindow()->leftDock();
1149     break;
1150   case DockRight:
1151     area = mainWindow()->rightDock();
1152     break;
1153   }
1154   return area;
1155 }
1156
1157 /*!
1158         Name: loadGeometry [private]
1159         Desc: 
1160 */
1161
1162 bool QtxDockAction::loadGeometry( QtxResourceMgr* resMgr, const QString& sec,
1163                                   const QString& name, GeomInfo& inf ) const
1164 {
1165   if ( !resMgr || sec.isEmpty() || name.isEmpty() )
1166     return false;
1167
1168   QString tmpl = QString( "%1.%2" ).arg( name );
1169
1170   inf.vis     = resMgr->booleanValue( sec, tmpl.arg( "visible" ), inf.vis );
1171   inf.newLine = resMgr->booleanValue( sec, tmpl.arg( "new_line" ), inf.newLine );
1172
1173   inf.index   = resMgr->integerValue( sec, tmpl.arg( "index" ), inf.index );
1174   inf.offset  = resMgr->integerValue( sec, tmpl.arg( "offset" ), inf.offset );
1175
1176   inf.x       = resMgr->integerValue( sec, tmpl.arg( "x" ), inf.x );
1177   inf.y       = resMgr->integerValue( sec, tmpl.arg( "y" ), inf.y );
1178   inf.w       = resMgr->integerValue( sec, tmpl.arg( "width" ), inf.w );
1179   inf.h       = resMgr->integerValue( sec, tmpl.arg( "height" ), inf.h );
1180
1181   inf.fixW    = resMgr->integerValue( sec, tmpl.arg( "fixed_width" ), inf.fixW );
1182   inf.fixH    = resMgr->integerValue( sec, tmpl.arg( "fixed_height" ), inf.fixH );
1183
1184   int place = -1;
1185   if ( !resMgr->value( sec, tmpl.arg( "place" ), place ) )
1186   {
1187     QString placeStr;
1188     if ( resMgr->value( sec, tmpl.arg( "place" ), placeStr ) )
1189       place = dockPlace( placeStr );
1190   }
1191
1192   if ( place >= DockUnmanaged && place <= DockMinimized )
1193     inf.place = place;
1194
1195   return true;
1196 }
1197
1198 /*!
1199         Name: saveGeometry [private]
1200         Desc: 
1201 */
1202
1203 bool QtxDockAction::saveGeometry( QtxResourceMgr* resMgr, const QString& sec,
1204                                   const QString& name, const GeomInfo& inf ) const
1205 {
1206   if ( !resMgr || sec.isEmpty() || name.isEmpty() )
1207     return false;
1208
1209   QString tmpl = QString( "%1.%2" ).arg( name );
1210
1211   resMgr->setValue( sec, tmpl.arg( "visible" ), inf.vis );
1212   resMgr->setValue( sec, tmpl.arg( "new_line" ), inf.newLine );
1213   resMgr->setValue( sec, tmpl.arg( "index" ), inf.index );
1214   resMgr->setValue( sec, tmpl.arg( "offset" ), inf.offset );
1215   resMgr->setValue( sec, tmpl.arg( "x" ), inf.x );
1216   resMgr->setValue( sec, tmpl.arg( "y" ), inf.y );
1217   resMgr->setValue( sec, tmpl.arg( "width" ), inf.w );
1218   resMgr->setValue( sec, tmpl.arg( "height" ), inf.h );
1219   resMgr->setValue( sec, tmpl.arg( "fixed_width" ), inf.fixW );
1220   resMgr->setValue( sec, tmpl.arg( "fixed_height" ), inf.fixH );
1221   resMgr->setValue( sec, tmpl.arg( "place" ), inf.place );
1222
1223   return true;
1224 }
1225
1226 /*!
1227         Name: collectNames [private]
1228         Desc: 
1229 */
1230
1231 void QtxDockAction::collectNames( const int place, QStringList& lst ) const
1232 {
1233   QPtrList<QDockWindow> winList;
1234   QDockArea* area = dockArea( place );
1235   if ( area )
1236     winList = area->dockWindowList();
1237   else
1238     winList = mainWindow()->dockWindows( (Qt::Dock)place );
1239
1240   for ( QPtrListIterator<QDockWindow> it( winList ); it.current(); ++it )
1241   {
1242     QString name;
1243     if ( myInfo.contains( it.current() ) )
1244       name = myInfo[it.current()].name;
1245     if ( name.isEmpty() )
1246       name = windowName( it.current() );
1247     if ( name.isEmpty() )
1248       continue;
1249
1250     lst.append( name );
1251   }
1252 }
1253
1254 void QtxDockAction::updateMenus()
1255 {
1256   for ( MenuMap::Iterator it = myMenu.begin(); it != myMenu.end(); ++it )
1257   {
1258     QPopupMenu* pm = it.key();
1259     MenuInfo& inf = it.data();
1260
1261     int toolId = findId( pm, inf.tool );
1262     int dockId = findId( pm, inf.dock );
1263
1264     int index = pm->indexOf( dockId );
1265
1266     if ( isSeparate() && !inf.tool )
1267       inf.tool = new QPopupMenu( pm );
1268
1269     pm->removeItem( dockId );
1270     pm->removeItem( toolId );
1271
1272     if ( !isSeparate() && inf.tool )
1273     {
1274       delete inf.tool;
1275       inf.tool = 0;
1276     }
1277
1278     QString dock, tool;
1279     splitMenuText( dock, tool );
1280
1281     if ( inf.dock )
1282       iconSet().isNull() ? pm->insertItem ( dock, inf.dock, -1, index ) :
1283                            pm->insertItem ( iconSet(), dock, inf.dock, -1, index );
1284
1285     if ( index >= 0 )
1286       index++;
1287
1288     if ( inf.tool )
1289       iconSet().isNull() ? pm->insertItem ( tool, inf.tool, -1, index ) :
1290                           pm->insertItem ( iconSet(), tool, inf.tool, -1, index );
1291   }
1292 }