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