Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / Qtx / QtxMRUAction.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:      QtxMRUAction.cxx
23 // Author:    Sergey TELKOV
24 //
25 #include "QtxMRUAction.h"
26
27 #include "QtxResourceMgr.h"
28
29 #include <QMenu>
30 #include <QIcon>
31
32 /*!
33   \class QtxMRUAction
34   \brief Menu action which provides most recent used items support.
35 */
36
37 /*!
38   \brief Constructor.
39   \param parent parent object
40 */
41 QtxMRUAction::QtxMRUAction( QObject* parent )
42 : QtxAction( tr( "Most Recently Used" ), tr( "Most Recently Used" ), 0, parent ),
43   myVisCount( 5 ),
44   myHistoryCount( -1 ),
45   myLinkType( LinkAuto ),
46   myInsertMode( MoveFirst )
47 {
48   myClear = new QAction( tr( "Clear" ), this );
49   myClear->setVisible( false );
50
51   setMenu( new QMenu( 0 ) );
52
53   connect( menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
54   connect( myClear, SIGNAL( triggered( bool ) ), this, SLOT( onCleared( bool ) ) );
55 }
56
57 /*!
58   \brief Constructor.
59   \param description (tooltip) text
60   \param menuText menu text
61   \param parent parent object
62 */
63 QtxMRUAction::QtxMRUAction( const QString& text, const QString& menuText, QObject* parent )
64 : QtxAction( text, menuText, 0, parent ),
65   myVisCount( 5 ),
66   myHistoryCount( -1 ),
67   myLinkType( LinkAuto ),
68   myInsertMode( MoveFirst )
69 {
70   myClear = new QAction( tr( "Clear" ), this );
71   myClear->setVisible( false );
72
73   setMenu( new QMenu( 0 ) );
74   connect( menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
75   connect( myClear, SIGNAL( triggered( bool ) ), this, SLOT( onCleared( bool ) ) );
76 }
77
78 /*!
79   \brief Constructor.
80   \param description (tooltip) text
81   \param icon action icon
82   \param menuText menu text
83   \param parent parent object
84 */
85 QtxMRUAction::QtxMRUAction( const QString& text, const QIcon& icon,
86                             const QString& menuText, QObject* parent )
87 : QtxAction( text, icon, menuText, 0, parent ),
88   myVisCount( 5 ),
89   myHistoryCount( -1 ),
90   myLinkType( LinkAuto ),
91   myInsertMode( MoveFirst )
92 {
93   myClear = new QAction( tr( "Clear" ), this );
94   myClear->setVisible( false );
95
96   setMenu( new QMenu( 0 ) );
97   connect( menu(), SIGNAL( aboutToShow() ), this, SLOT( onAboutToShow() ) );
98   connect( myClear, SIGNAL( triggered( bool ) ), this, SLOT( onCleared( bool ) ) );
99 }
100
101 /*!
102   \brief Destructor.
103 */
104 QtxMRUAction::~QtxMRUAction()
105 {
106   delete menu();
107 }
108
109 /*!
110   \brief Get items insertion policy.
111   \return insertion policy (QtxMRUAction::InsertionMode)
112 */
113 int QtxMRUAction::insertMode() const
114 {
115   return myInsertMode;
116 }
117
118 /*!
119   \brief Set items insertion policy.
120   \param mode insertion policy (QtxMRUAction::InsertionMode)
121 */
122 void QtxMRUAction::setInsertMode( const int mode )
123 {
124   myInsertMode = mode;
125 }
126
127 /*!
128   \brief Get the type of link menu name.
129   \return link type (QtxMRUAction::LinkType)
130 */
131 int QtxMRUAction::linkType() const
132 {
133   return myLinkType;
134 }
135
136 /*!
137   \brief Set the type of link menu name.
138   \param link type (QtxMRUAction::LinkType)
139 */
140 void QtxMRUAction::setLinkType( const int type )
141 {
142   myLinkType = type;
143 }
144
145 /*!
146   \brief Get number of MRU items.
147   \return number of MRU items
148 */
149 int QtxMRUAction::count() const
150 {
151   return myLinks.count();
152 }
153
154 /*!
155   \brief Check if the MRU items list is empty.
156   \return \c true if there are no MRU items
157 */
158 bool QtxMRUAction::isEmpty() const
159 {
160   return myLinks.isEmpty();
161 }
162
163 /*!
164   \brief Get number of visible MRU items.
165   \return visible MRU items number
166   \sa setVisibleCount()
167 */
168 int QtxMRUAction::visibleCount() const
169 {
170   return myVisCount;
171 }
172
173 /*!
174   \brief Set number of visible MRU items.
175
176   This method sets the maximum number of MRU items
177   to be displayed in the popup menu (5 by default).
178
179   If \a num < 1, then all MRU items will be displayed.
180
181   \param num visible MRU items number
182 */
183 void QtxMRUAction::setVisibleCount( int num )
184 {
185   if ( myVisCount == num )
186     return;
187
188   myVisCount = num;
189 }
190
191 /*!
192   \brief Return visible status of the menu item which clear all MRU items.
193 */
194 bool QtxMRUAction::isClearPossible() const
195 {
196   return myClear->isVisible();
197 }
198
199 /*!
200   \brief Set visible the menu item which clear all MRU items.
201 */
202 void QtxMRUAction::setClearPossible( const bool on )
203 {
204   myClear->setVisible( on );
205 }
206
207 /*!
208   \brief Get number of totally stored MRU items.
209   \return number of MRU items stored in the preferences
210   \sa setHistoryCount(), saveLinks(), loadLinks()
211 */
212 int QtxMRUAction::historyCount() const
213 {
214   return myHistoryCount;
215 }
216
217 /*!
218   \brief Set number of totally stored MRU items.
219
220   This option allows setting number of MRU items to be stored
221   in the preferences file.
222
223   If \a num < 0, then number of stored MRU items is not limited.
224
225   \return number of MRU items stored in the preferences
226   \sa historyCount(), saveLinks(), loadLinks()
227 */
228 void QtxMRUAction::setHistoryCount( const int num )
229 {
230   myHistoryCount = num;
231 }
232
233 /*!
234   \brief Insert MRU item.
235
236   The item is inserted according to the current insertion policy.
237
238   \param link MRU item to be added
239 */
240 void QtxMRUAction::insert( const QString& link )
241 {
242   if ( myLinks.contains( link ) && ( insertMode() == AddFirst || insertMode() == AddLast ) )
243     return;
244
245   myLinks.removeAll( link );
246
247   switch ( insertMode() )
248   {
249   case AddFirst:
250   case MoveFirst:
251     myLinks.prepend( link );
252     break;
253   case AddLast:
254   case MoveLast:
255     myLinks.append( link );
256     break;
257   }
258 }
259
260 /*!
261   \brief Remove MRU item.
262
263   Does nothing if \a idx is out of range.
264
265   \param idx MRU item index
266 */
267 void QtxMRUAction::remove( const int idx )
268 {
269   if ( idx < 0 || idx >= (int)myLinks.count() )
270     return;
271
272   myLinks.removeAt( idx );
273 }
274
275 /*!
276   \brief Remove MRU item.
277
278   Does nothing if there is no speicified item in the list.
279
280   \param link MRU item to be removed
281 */
282 void QtxMRUAction::remove( const QString& link )
283 {
284   myLinks.removeAll( link );
285 }
286
287 /*!
288   \brief Remove all MRU items.
289 */
290 void QtxMRUAction::clear()
291 {
292   myLinks.clear();
293 }
294
295 /*!
296   \brief Get MRU item
297   \param idx MRU item index
298   \return MRU item or null QString if \a idx is out of range
299 */
300 QString QtxMRUAction::item( const int idx ) const
301 {
302   QString res;
303   if ( idx >= 0 && idx < (int)myLinks.count() )
304     res = myLinks[idx];
305   return res;
306 }
307
308 /*!
309   \brief Get MRU item index.
310   \param link MRU item
311   \return MRU item index or -1 if item is not found
312 */
313 int QtxMRUAction::find( const QString& link ) const
314 {
315   return myLinks.indexOf( link );
316 }
317
318 /*!
319   \brief Check if MRU item is in the list.
320   \param link MRU item
321   \return \c true if specified item is already added to the list
322 */
323 bool QtxMRUAction::contains( const QString& link ) const
324 {
325   return myLinks.contains( link );
326 }
327
328 /*!
329   \brief Load the MRU items from specified resources section.
330   \param resMgr resources manager
331   \param section resources section
332   \param clear if \c true, previous MRU items list is cleared
333 */
334 void QtxMRUAction::loadLinks( QtxResourceMgr* resMgr, const QString& section, const bool clear )
335 {
336   if ( !resMgr || section.isEmpty() )
337     return;
338
339   if ( clear )
340     myLinks.clear();
341
342   QString itemPrefix( "item_" );
343
344   QMap<QString, int> map;
345   for ( QStringList::const_iterator itr = myLinks.begin(); itr != myLinks.end(); ++ itr )
346     map.insert( *itr, 0 );
347
348   QStringList items = resMgr->parameters( section );
349   for ( QStringList::const_iterator it = items.begin(); it != items.end(); ++it )
350   {
351     if ( !(*it).startsWith( itemPrefix ) )
352       continue;
353
354     QString link = resMgr->stringValue( section, *it, QString() );
355     if ( link.isEmpty() || map.contains( link ) )
356       continue;
357
358     myLinks.append( link );
359     map.insert( link, 0 );
360   }
361 }
362
363 /*!
364   \brief Save the MRU items to specified resources section.
365   \param resMgr resources manager
366   \param section resources section
367   \param clear if \c true, the resources section is first cleared
368 */
369 void QtxMRUAction::saveLinks( QtxResourceMgr* resMgr, const QString& section, const bool clear ) const
370 {
371   if ( !resMgr || section.isEmpty() )
372     return;
373
374   QString itemPrefix( "item_" );
375
376   if ( clear ) {
377     QStringList items = resMgr->parameters( section );
378     for ( QStringList::const_iterator it = items.begin(); it != items.end(); ++it )
379     {
380       if ( (*it).startsWith( itemPrefix ) )
381         resMgr->remove( section, *it );
382     }
383   }
384
385   QStringList lst;
386   QMap<QString, int> map;
387   for ( QStringList::const_iterator itr = myLinks.begin(); itr != myLinks.end(); ++itr )
388   {
389     lst.append( *itr );
390     map.insert( *itr, 0 );
391   }
392
393   QStringList items = resMgr->parameters( section );
394   for ( QStringList::const_iterator it = items.begin(); it != items.end(); ++it )
395   {
396     if ( !(*it).startsWith( itemPrefix ) )
397       continue;
398
399     QString link = resMgr->stringValue( section, *it, QString() );
400     if ( !link.isEmpty() && !map.contains( link ) )
401     {
402       lst.append( link );
403       map.insert( link, 0 );
404     }
405
406     resMgr->remove( section, *it );
407   }
408
409   int counter = 0;
410   for ( QStringList::const_iterator iter = lst.begin();
411         iter != lst.end() && ( myHistoryCount < 0 || counter < myHistoryCount );
412         ++iter, counter++ )
413     resMgr->setValue( section, itemPrefix + QString().sprintf( "%03d", counter ), *iter );
414 }
415
416 /*!
417   \brief Prepare MRU items popup menu.
418
419   This method is called when the parent menu is shown.
420   Enables or disables sub menu item according to the number of MRU items.
421 */
422 void QtxMRUAction::onAboutToShow()
423 {
424   updateMenu();
425 }
426
427 /*!
428   \brief Called when any MRU item is selected by the user.
429
430   Emits signal activated(const QString&) passing selected MRU item as parameter.
431 */
432 void QtxMRUAction::onActivated()
433 {
434   QAction* a = ::qobject_cast<QAction*>( sender() );
435   if ( !a )
436     return;
437
438   QString link = a->data().toString();
439   if ( !link.isEmpty() && myLinks.contains( link ) )
440     emit activated( link );
441 }
442
443 void QtxMRUAction::onCleared( bool )
444 {
445   clear();
446 }
447
448 /*!
449   \brief Update MRU items popup menu.
450 */
451 void QtxMRUAction::updateMenu()
452 {
453   QMenu* pm = menu();
454   if ( !pm )
455     return;
456
457   pm->clear();
458
459   QStringList links;
460   QMap<QString, int> map;
461   int count = visibleCount() < 0 ? myLinks.count() : visibleCount();
462   int i = insertMode() == AddLast || insertMode() == MoveLast ? qMax( 0, myLinks.count()-count ) : 0;
463   for ( ; i < myLinks.count() && count > 0; ++i, count-- )
464   {
465     links.append( myLinks[i] );
466     if ( linkType() == LinkAuto )
467     {
468       QString shortName = Qtx::file( myLinks[i] );
469       if ( map.contains( shortName ) )
470         map[shortName]++;
471       else
472         map.insert( shortName, 0 );
473     }
474   }
475
476   i = 1;
477   for ( QStringList::const_iterator it = links.begin(); it != links.end(); ++it, i++ )
478   {
479     QString linkName;
480     switch( linkType() )
481     {
482     case LinkAuto:
483       linkName = Qtx::file( *it );
484       if ( map.contains( linkName ) && map[linkName] )
485         linkName = *it;
486       break;
487     case LinkShort:
488       linkName = Qtx::file( *it );
489       break;
490     case LinkFull:
491     default:
492       linkName = *it;
493       break;
494     }
495
496     if ( links.count() < 10 )
497       linkName = QString( "&%1 %2" ).arg( i ).arg( linkName );
498
499     pm->addAction( linkName, this, SLOT( onActivated() ) )->setData( *it );
500   }
501
502   if ( pm->isEmpty() )
503     pm->addAction( tr( "<Empty>" ) )->setEnabled( false );
504
505   if ( isClearPossible() )
506   {
507     pm->addSeparator();
508     pm->addAction( myClear );
509     myClear->setEnabled( !pm->isEmpty() );
510   }
511 }
512
513 /*!
514   \fn void QtxMRUAction::activated( const QString& link );
515   \brief Emitted when user selects any MRU item in the menu.
516   \param link selected MRU item
517 */