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