Salome HOME
9b6d98ae66e99b69321f46489cde0f9734817312
[modules/gui.git] / src / Qtx / QtxWorkspaceAction.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:      QtxWorkspaceAction.cxx
20 // Author:    Sergey TELKOV
21
22 #include "QtxWorkspaceAction.h"
23
24 #include <qpopupmenu.h>
25 #include <qworkspace.h>
26 #include <qwidgetlist.h>
27
28 /*!
29   Constructor
30 */
31 QtxWorkspaceAction::QtxWorkspaceAction( QWorkspace* ws, QObject* parent, const char* name )
32 : QtxAction( tr( "Controls windows into workspace" ), tr( "Workspace management" ), 0, parent, name ),
33 myFlags( Standard ),
34 myWorkspace( ws )
35 {
36   myItem.insert( Cascade, new QtxAction( tr( "Arranges the windows as overlapping tiles" ),
37                                          tr( "Cascade" ), 0, this, 0, false ) );
38   myItem.insert( Tile,    new QtxAction( tr( "Arranges the windows as nonoverlapping tiles" ),
39                                          tr( "Tile" ), 0, this, 0, false ) );
40   myItem.insert( HTile,   new QtxAction( tr( "Arranges the windows as nonoverlapping horizontal tiles" ),
41                                          tr( "Tile horizontally" ), 0, this, 0, false ) );
42   myItem.insert( VTile,   new QtxAction( tr( "Arranges the windows as nonoverlapping vertical tiles" ),
43                                          tr( "Tile vertically" ), 0, this, 0, false ) );
44
45   connect( myItem[Tile], SIGNAL( activated() ), this, SLOT( tile() ) );
46   connect( myItem[Cascade], SIGNAL( activated() ), this, SLOT( cascade() ) );
47   connect( myItem[HTile], SIGNAL( activated() ), this, SLOT( tileVertical() ) );
48   connect( myItem[VTile], SIGNAL( activated() ), this, SLOT( tileHorizontal() ) );
49 }
50
51 /*!
52   Destructor
53 */
54 QtxWorkspaceAction::~QtxWorkspaceAction()
55 {
56 }
57
58 /*!
59   \return corresponding workspace
60 */
61 QWorkspace* QtxWorkspaceAction::workspace() const
62 {
63   return myWorkspace;
64 }
65
66 /*!
67   \return set of action flags
68 */
69 int QtxWorkspaceAction::items() const
70 {
71   return myFlags;
72 }
73
74 /*!
75   Sets action flags
76   \param flags - new set of flags
77 */
78 void QtxWorkspaceAction::setItems( const int flags )
79 {
80   if ( !flags || flags == myFlags || !( flags & Operations ) )
81     return;
82
83   myFlags = flags;
84 }
85
86 /*!
87   \return true if action contains all flags
88   \param flags - new set of flags
89 */
90 bool QtxWorkspaceAction::hasItems( const int flags ) const
91 {
92   return ( myFlags & flags ) == flags;
93 }
94
95 /*!
96   \return accelerator of item
97   \param id - item id
98 */
99 int QtxWorkspaceAction::accel( const int id ) const
100 {
101   int a = 0;
102   if ( myItem.contains( id ) )
103     a = myItem[id]->accel();
104   return a;
105 }
106
107 /*!
108   \return icons of item
109   \param id - item id
110 */
111 QIconSet QtxWorkspaceAction::iconSet( const int id ) const
112 {
113   QIconSet ico;
114   if ( myItem.contains( id ) )
115     ico = myItem[id]->iconSet();
116   return ico;
117 }
118
119 /*!
120   \return menu text of item
121   \param id - item id
122 */
123 QString QtxWorkspaceAction::menuText( const int id ) const
124 {
125   QString txt;
126   if ( myItem.contains( id ) )
127     txt = myItem[id]->menuText();
128   return txt;
129 }
130
131 /*!
132   \return status tip of item
133   \param id - item id
134 */
135 QString QtxWorkspaceAction::statusTip( const int id ) const
136 {
137   QString txt;
138   if ( myItem.contains( id ) )
139     txt = myItem[id]->statusTip();
140   return txt;
141 }
142
143 /*!
144   Changes accelerator of item
145   \param id - item id
146   \param a - new accelerator
147 */
148 void QtxWorkspaceAction::setAccel( const int id, const int a )
149 {
150   if ( myItem.contains( id ) )
151     myItem[id]->setAccel( a );
152 }
153
154 /*!
155   Changes icons of item
156   \param id - item id
157   \param ico - new icons
158 */
159 void QtxWorkspaceAction::setIconSet( const int id, const QIconSet& ico )
160 {
161   if ( myItem.contains( id ) )
162     myItem[id]->setIconSet( ico );
163 }
164
165 /*!
166   Changes menu text of item
167   \param id - item id
168   \param txt - new menu text
169 */
170 void QtxWorkspaceAction::setMenuText( const int id, const QString& txt )
171 {
172   if ( myItem.contains( id ) )
173     myItem[id]->setMenuText( txt );
174 }
175
176 /*!
177   Changes status tip of item
178   \param id - item id
179   \param txt - new status tip
180 */
181 void QtxWorkspaceAction::setStatusTip( const int id, const QString& txt )
182 {
183   if ( myItem.contains( id ) )
184     myItem[id]->setStatusTip( txt );
185 }
186
187 /*!
188   Adds action to widget
189   \param wid - widget
190 */
191 bool QtxWorkspaceAction::addTo( QWidget* wid )
192 {
193   return addTo( wid, -1 );
194 }
195
196 /*!
197   Adds action to widget
198   \param wid - widget
199   \param idx - position
200 */
201 bool QtxWorkspaceAction::addTo( QWidget* wid, const int idx )
202 {
203   if ( !wid || !wid->inherits( "QPopupMenu" ) )
204     return false;
205
206   QPopupMenu* pm = (QPopupMenu*)wid;
207   checkPopup( pm );
208
209   if ( myMenu.contains( pm ) )
210     return false;
211
212   myMenu.insert( pm, QIntList() );
213   fillPopup( pm, idx );
214
215   connect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
216   connect( pm, SIGNAL( destroyed( QObject* ) ), this, SLOT( onPopupDestroyed( QObject* ) ) );
217
218   return true;
219 }
220
221 /*!
222   Removes action from widget
223   \param wid - widget
224 */
225 bool QtxWorkspaceAction::removeFrom( QWidget* wid )
226 {
227   if ( !wid || !wid->inherits( "QPopupMenu" ) )
228     return false;
229
230   QPopupMenu* pm = (QPopupMenu*)wid;
231   if ( !myMenu.contains( pm ) )
232     return false;
233
234   clearPopup( pm );
235
236   disconnect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
237   disconnect( pm, SIGNAL( destroyed( QObject* ) ), this, SLOT( onPopupDestroyed( QObject* ) ) );
238
239   myMenu.remove( pm );
240
241   return true;
242 }
243
244 /*!
245   Performs action
246   \param type - action type
247 */
248 void QtxWorkspaceAction::perform( const int type )
249 {
250   switch ( type )
251   {
252   case Cascade:
253     cascade();
254     break;
255   case Tile:
256     tile();
257     break;
258   case VTile:
259     tileVertical();
260     break;
261   case HTile:
262     tileHorizontal();
263     break;
264   }
265 }
266
267 /*!
268   Performs tile action
269 */
270 void QtxWorkspaceAction::tile()
271 {
272   QWorkspace* ws = workspace();
273   if ( !ws )
274     return;
275
276   ws->tile();
277 }
278
279 /*!
280   Performs cascade action
281 */
282 void QtxWorkspaceAction::cascade()
283 {
284   QWorkspace* ws = workspace();
285   if ( !ws )
286     return;
287
288   ws->cascade();
289
290         int w = ws->width();
291         int h = ws->height();
292
293         QWidgetList winList = ws->windowList();
294         for ( QWidgetListIt it( winList ); it.current(); ++it )
295                 it.current()->resize( int( w * 0.8 ), int( h * 0.8 ) );
296 }
297
298 /*!
299   Performs tile vertical action
300 */
301 void QtxWorkspaceAction::tileVertical()
302 {
303   QWorkspace* wrkSpace = workspace();
304         if ( !wrkSpace )
305                 return;
306         
307         QWidgetList winList = wrkSpace->windowList();
308         if ( winList.isEmpty() )
309     return;
310
311   int count = 0;
312         for ( QWidgetListIt itr( winList ); itr.current(); ++itr )
313     if ( !itr.current()->testWState( WState_Minimized ) )
314       count++;
315
316   if ( !count )
317     return;
318
319         int y = 0;
320
321         int heightForEach = wrkSpace->height() / count;
322         for ( QWidgetListIt it( winList ); it.current(); ++it )
323         {
324     QWidget* win = it.current();
325     if ( win->testWState( WState_Minimized ) )
326       continue;
327
328     if ( win->testWState( WState_Maximized ) )
329                 {
330                         win->hide();
331                         win->showNormal();
332     }
333     int prefH = win->minimumHeight() + win->parentWidget()->baseSize().height();
334     int actualH = QMAX( heightForEach, prefH );
335
336     win->parentWidget()->setGeometry( 0, y, wrkSpace->width(), actualH );
337     y += actualH;
338         }
339 }
340
341 /*!
342   Performs tile horizontal action
343 */
344 void QtxWorkspaceAction::tileHorizontal()
345 {
346   QWorkspace* wrkSpace = workspace();
347         if ( !wrkSpace )
348                 return;
349
350         QWidgetList winList = wrkSpace->windowList();
351         if ( winList.isEmpty() )
352     return;
353
354   int count = 0;
355         for ( QWidgetListIt itr( winList ); itr.current(); ++itr )
356     if ( !itr.current()->testWState( WState_Minimized ) )
357       count++;
358
359   if ( !count )
360     return;
361
362         int x = 0;
363         int widthForEach = wrkSpace->width() / count;
364         for ( QWidgetListIt it( winList ); it.current(); ++it )
365         {
366     QWidget* win = it.current();
367     if ( win->testWState( WState_Minimized ) )
368       continue;
369
370     if ( win->testWState( WState_Maximized ) )
371                 {
372                         win->hide();
373                         win->showNormal();
374     }
375     int prefW = win->minimumWidth();
376     int actualW = QMAX( widthForEach, prefW );
377         
378                 win->parentWidget()->setGeometry( x, 0, actualW, wrkSpace->height() );
379     x += actualW;
380         }
381 }
382
383 /*!
384   SLOT: called just before the popup menu is displayed, updates popup
385 */
386 void QtxWorkspaceAction::onAboutToShow()
387 {
388   const QObject* obj = sender();
389   if ( !obj || !obj->inherits( "QPopupMenu" ) )
390     return;
391
392   updatePopup( (QPopupMenu*)obj );
393 }
394
395 /*!
396   SLOT: called when popup menu is destroyed, removes it from menu
397 */
398 void QtxWorkspaceAction::onPopupDestroyed( QObject* obj )
399 {
400   myMenu.remove( (QPopupMenu*)obj );
401 }
402
403 /*!
404   Updates popup
405   \param pm - popup menu
406 */
407 void QtxWorkspaceAction::checkPopup( QPopupMenu* pm )
408 {
409   if ( !myMenu.contains( pm ) )
410     return;
411
412   QIntList updList;
413   for ( QIntList::const_iterator it = myMenu[pm].begin(); it != myMenu[pm].end(); ++it )
414   {
415     if ( pm->indexOf( *it ) != -1 )
416       updList.append( *it );
417   }
418
419   myMenu.remove( pm );
420
421   if ( !updList.isEmpty() )
422     myMenu.insert( pm, updList );
423   else
424   {
425     disconnect( pm, SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
426     disconnect( pm, SIGNAL( destroyed( QObject* ) ), this, SLOT( onPopupDestroyed( QObject* ) ) );
427   }
428 }
429
430 /*!
431   Clears and refills popup and updates state of actions
432   \param pm - popup menu
433 */
434 void QtxWorkspaceAction::updatePopup( QPopupMenu* pm )
435 {
436   if ( !myMenu.contains( pm ) )
437     return;
438
439   fillPopup( pm, clearPopup( pm ) );
440
441   bool count = workspace() ? workspace()->windowList().count() : 0;
442   myItem[Cascade]->setEnabled( count );
443   myItem[Tile]->setEnabled( count );
444   myItem[HTile]->setEnabled( count );
445   myItem[VTile]->setEnabled( count );
446 }
447
448 /*!
449   Clears popup
450   \param pm - popup menu
451 */
452 int QtxWorkspaceAction::clearPopup( QPopupMenu* pm )
453 {
454   if ( !myMenu.contains( pm ) )
455     return -1;
456
457   int idx = -1;
458   const QIntList& lst = myMenu[pm];
459   for ( QIntList::const_iterator it = lst.begin(); it != lst.end() && idx == -1; ++it )
460     idx = pm->indexOf( *it );
461
462   for ( ItemMap::ConstIterator mit = myItem.begin(); mit != myItem.end(); ++mit )
463     mit.data()->removeFrom( pm );
464
465   for ( QIntList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr )
466     pm->removeItem( *itr );
467
468   return idx;
469 }
470
471 /*!
472   Fills popup with items
473   \param pm - popup menu
474   \param idx - position
475 */
476 void QtxWorkspaceAction::fillPopup( QPopupMenu* pm, const int idx )
477 {
478   if ( !pm )
479     return;
480
481   int index = idx < 0 ? pm->count() : QMIN( (int)pm->count(), idx );
482
483   myMenu.insert( pm, QIntList() );
484   QIntList& lst = myMenu[pm];
485
486   for ( ItemMap::ConstIterator mit = myItem.begin(); mit != myItem.end(); ++mit )
487   {
488     if ( !hasItems( mit.key() ) )
489       continue;
490
491     mit.data()->addTo( pm, index );
492     lst.append( pm->idAt( index++ ) );
493   }
494
495   QWorkspace* ws = workspace();
496   if ( !ws || !hasItems( Windows ) )
497     return;
498
499   QWidgetList wList = ws->windowList();
500   if ( wList.isEmpty() )
501     return;
502
503   lst.append( pm->insertSeparator( index++ ) );
504
505   int param = 0;
506   pm->setCheckable( true );
507   for ( QWidgetListIt it( wList ); it.current(); ++it )
508   {
509     int id = pm->insertItem( it.current()->caption(), this, SLOT( onItemActivated( int ) ), 0, -1, index++ );
510     pm->setItemParameter( id, param++ );
511     pm->setItemChecked( id, it.current() == ws->activeWindow() );
512     lst.append( id );
513   }
514 }
515
516 /*!
517   SLOT: called when popup item corresponding to window is activated, activates window
518 */
519 void QtxWorkspaceAction::onItemActivated( int idx )
520 {
521   QWorkspace* ws = workspace();
522   if ( !ws )
523     return;
524
525   QWidgetList wList = ws->windowList();
526   if ( idx < 0 || idx >= (int)wList.count() )
527     return;
528
529   wList.at( idx )->setFocus();
530 }