Salome HOME
73d716a490d9911833512f871e9ae124b5d8292a
[modules/gui.git] / src / SUIT / SUIT_DataBrowser.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
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, or (at your option) any later version.
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/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File   : SUIT_DataBrowser.cxx
21 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
22 //
23 #include "SUIT_DataBrowser.h"
24 #include "SUIT_TreeModel.h"
25 #include <QtxTreeView.h>
26
27 #include <QShortcut>
28
29 /*!
30   \class SUIT_DataBrowser
31   \brief Object browser customization.
32 */
33
34 /*!
35   \brief Constructor.
36   \param parent parent widget
37 */
38 SUIT_DataBrowser::SUIT_DataBrowser( QWidget* parent )
39 : OB_Browser( parent )
40 {
41   init( 0 );
42 }
43
44 /*!
45   \brief Constructor.
46   \param root root data object
47   \param parent parent widget
48 */
49 SUIT_DataBrowser::SUIT_DataBrowser( SUIT_DataObject* root, QWidget* parent )
50 : OB_Browser( parent )
51 {
52   init( root );
53 }
54
55 /*!
56   \brief Destructor.
57 */
58 SUIT_DataBrowser::~SUIT_DataBrowser()
59 {
60 }
61
62 /*!
63   \brief Get popup menu client type.
64   \return popup client type
65 */
66 QString SUIT_DataBrowser::popupClientType() const
67 {
68   return "ObjectBrowser";
69 }
70
71 /*!
72   \brief Get root object.
73   \return root object
74 */
75 SUIT_DataObject* SUIT_DataBrowser::root() const
76 {
77   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
78   return m ? m->root() : 0;
79 }
80
81 /*!
82   \brief Set root object.
83   \param r new root object
84 */
85 void SUIT_DataBrowser::setRoot( SUIT_DataObject* r )
86 {
87   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
88   if ( m ) 
89     m->setRoot( r );
90 }
91
92 /*!
93   \brief Get 'auto-update tree' flag value.
94   \return 'auto-update tree' flag value
95   \sa setAutoUpdate(), updateTree()
96 */
97 bool SUIT_DataBrowser::autoUpdate() const
98 {
99   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
100   return m ? m->autoUpdate() : false;
101 }
102
103 /*!
104   \brief Set 'auto-update tree' flag value.
105
106   If this flag is set to \c true (by default), the object browser is updated
107   automatically when data tree is changed.
108
109   \param on 'auto-update tree' flag value
110   \sa autoUpdate(), updateTree()
111 */
112 void SUIT_DataBrowser::setAutoUpdate( const bool on )
113 {
114   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
115   if ( m ) 
116     m->setAutoUpdate( on );
117 }
118
119 /*!
120   \brief Get 'updateModified' flag value.
121   \return 'updateModified' flag value
122 */
123 bool SUIT_DataBrowser::updateModified() const
124 {
125   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
126   return m ? m->updateModified() : false;
127 }
128
129 /*!
130   \brief Set 'updateModified' flag value.
131   \param on 'updateModified' flag value
132 */
133 void SUIT_DataBrowser::setUpdateModified( const bool on )
134 {
135   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
136   if ( m ) 
137     m->setUpdateModified( on );
138 }
139
140 /*!
141   \brief Update object browser starting from the object \obj;
142   open all branches automatically if \a autoOpen is \c true.
143   \param obj starting object for updating
144   \param autoOpen if \c true automatically open branches
145 */
146 void SUIT_DataBrowser::updateTree( SUIT_DataObject* obj, const bool autoOpen )
147 {
148   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
149   if ( m ) {
150     m->updateTree( obj );
151     openLevels();
152
153     if (myAutoSizeFirstColumn)
154       adjustFirstColumnWidth();
155     if (myAutoSizeColumns)
156       adjustColumnsWidth();
157   }
158 }
159
160 /*!
161   \brief Get current key accelerator by id.
162   \return current key accelerator
163   \sa setShortcutKey(), requestUpdate(), requestRename()
164 */
165 int SUIT_DataBrowser::shortcutKey(const int id) const
166 {
167   return myShortcutMap.value(id)->key();
168 }
169
170 /*!
171   \brief Assign the key accelerator for the shortcut.
172   
173   \param id id of the shortcut
174   \param key new key accelerator
175   \sa shortcutKey(), requestUpdate(), requestRename()
176 */
177 void SUIT_DataBrowser::setShortcutKey( const int id, const int key )
178
179   ShortcutMap::iterator it = myShortcutMap.find( id );
180   if( it != myShortcutMap.end() )
181     (*it)->setKey(key);
182 }
183
184 /*!
185   \brief Get list of selected data objects.
186   \return list of the currently selected data objects
187 */
188 DataObjectList SUIT_DataBrowser::getSelected() const
189 {
190   DataObjectList lst;
191   getSelected( lst );
192   return lst;
193 }
194
195 /*!
196   \brief Get list of selected data objects.
197   \overload
198   \param lst list to be filled with the currently selected data objects
199 */
200 void SUIT_DataBrowser::getSelected( DataObjectList& lst ) const
201 {
202   lst.clear();
203
204   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
205
206   if ( m ) {
207     QModelIndexList sel = selectedIndexes();
208     QModelIndex idx;
209   
210     foreach( idx, sel ) {
211       SUIT_DataObject* obj = m->object( idx );
212       if ( obj )
213         lst.append( obj );
214     }
215   }
216 }
217
218 /*!
219   \brief Set selected object.
220   \param obj data object to set selected
221   \param append if \c true, the object is added to the current selection;
222   otherwise the previous selection is first cleared
223 */
224 void SUIT_DataBrowser::setSelected( const SUIT_DataObject* obj, const bool append )
225 {
226   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
227
228   if ( m ) {
229     QModelIndex index = m->index( obj );
230     if ( index.isValid() )
231       select( index, true, append );
232   }
233 }
234
235 /*!
236   \brief function to sort QModelIndexList with qSort
237 */
238 bool modelIndexLessThan(const QModelIndex& lhs, const QModelIndex& rhs)
239 {
240   QModelIndex lhs_parent=lhs.parent();
241   QModelIndex rhs_parent=rhs.parent();
242   if(lhs_parent < rhs_parent)return true;
243   if(lhs_parent == rhs_parent) return lhs < rhs;
244   return false;
245 }
246
247 /*!
248   \brief Set list of selected data objects.
249   \param lst list of the data object to set selected
250   \param append if \c true, the objects are added to the current selection;
251   otherwise the previous selection is first cleared
252 */
253 void SUIT_DataBrowser::setSelected( const DataObjectList& lst, const bool append )
254 {
255   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
256
257   if ( m ) {
258     QModelIndexList indexes;
259     SUIT_DataObject* obj;
260
261     foreach( obj, lst ) {
262       QModelIndex index = m->index( obj );
263       if ( index.isValid() )
264         indexes.append( index );
265     }
266     qSort(indexes.begin(), indexes.end(), modelIndexLessThan);
267
268     select( indexes, true, append ); // if !indexes.isEmpty() ???
269   }
270 }
271
272 /*!
273   \brief Make the view item for specified data object is visible.
274   \param obj data object
275 */
276 void SUIT_DataBrowser::ensureVisible( SUIT_DataObject* obj )
277 {
278   if ( !obj )
279     return;
280
281   DataObjectList lst;
282   lst.append( obj );
283   ensureVisible( lst );
284 }
285
286 /*!
287   \brief Make the view items for specified data objects is visible.
288   \param lst data object list
289 */
290 void SUIT_DataBrowser::ensureVisible( const DataObjectList& lst )
291 {
292   QtxTreeView* tv = treeView();
293   SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( model() );
294   if ( !tv || !treeModel )
295     return;
296
297   for ( DataObjectList::const_iterator it = lst.begin(); it != lst.end(); ++it )
298   {
299     QModelIndex idx = treeModel->index( *it );
300     if ( idx.isValid() )
301       tv->scrollTo( idx );
302   }
303 }
304
305 /*!
306   \brief Add custom actions to the popup menu.
307   \param menu popup menu
308 */
309 void SUIT_DataBrowser::contextMenuPopup( QMenu* menu )
310 {
311   createPopupMenu( menu );
312 }
313
314 /*!
315   \brief Set 'auto-size first column' flag value.
316
317   If this flag is set to \c true (by default), the first column width is resized
318   to its contents.
319
320   \param on 'auto-size first column' flag value
321   \sa setAutoSizeColumns()
322 */
323 void SUIT_DataBrowser::setAutoSizeFirstColumn( const bool on )
324 {
325   myAutoSizeFirstColumn = on;
326 }
327
328 /*!
329   \brief Set 'auto-size columns' flag value.
330
331   If this flag is set to \c true (by default is false), columns width except 
332   the first column is resized to its contents.
333
334   \param on 'auto-size columns' flag value
335   \sa setAutoSizeFirstColumn()
336 */
337 void SUIT_DataBrowser::setAutoSizeColumns( const bool on )
338 {
339   myAutoSizeColumns = on;
340 }
341
342 /*!
343   \brief Process context menu request event.
344   \param e context menu event
345 */
346 void SUIT_DataBrowser::contextMenuEvent( QContextMenuEvent* e )
347 {
348   contextMenuRequest( e );
349 }
350
351 /*!
352   \brief Set 'resize on expand item' flag value.
353
354   If this flag is set to \c true (by default is false), after
355   expanding an item columns will be resized to its contents.
356
357   \param on 'resize on expand item' flag value
358 */
359 void SUIT_DataBrowser::setResizeOnExpandItem( const bool on )
360 {
361   myResizeOnExpandItem = on;
362 }
363
364 /*!
365   \brief Initialize object browser.
366   \param root root data object
367 */
368 void SUIT_DataBrowser::init( SUIT_DataObject* root )
369 {
370   SUIT_ProxyModel* m = new SUIT_ProxyModel( root, this );
371   connect( m, SIGNAL( modelUpdated() ), this, SLOT( onModelUpdated() ) );
372   
373   setModel( m );
374   setItemDelegate( qobject_cast<SUIT_ProxyModel*>( model() )->delegate() );
375   connect( treeView(), SIGNAL( sortingEnabled( bool ) ), 
376            model(),    SLOT( setSortingEnabled( bool ) ) );
377   connect( treeView(), SIGNAL( clicked( const QModelIndex& ) ), 
378            this,       SLOT( onClicked( const QModelIndex& ) ) );
379   connect( treeView(), SIGNAL( doubleClicked( const QModelIndex& ) ), 
380            this,       SLOT( onDblClicked( const QModelIndex& ) ) );
381   connect( treeView(), SIGNAL( expanded( const QModelIndex& ) ), 
382            this,       SLOT( onExpanded( const QModelIndex& ) ) );
383   connect( this      , SIGNAL( requestRename() ),
384            this      , SLOT ( onStartEditing() ));
385
386   myShortcutMap.insert(UpdateShortcut , new QShortcut( Qt::Key_F5, this, SIGNAL( requestUpdate() ), SIGNAL( requestUpdate() ) ) );
387   myShortcutMap.insert(RenameShortcut , new QShortcut( Qt::Key_F2, this, SIGNAL( requestRename() ), SIGNAL( requestRename() ) ) );
388
389   myAutoSizeFirstColumn = true;
390   myAutoSizeColumns = false;
391   myResizeOnExpandItem = false;
392 }
393
394 /*!
395   \fn void SUIT_DataBrowser::requestUpdate();
396   \brief The signal is emitted when the key accelerator
397   assigned for the update operation is pressed by the user.
398
399   By default, \c [F5] key is assigned for the update operation.
400   The key accelerator can be changed with the setShortcutKey() method.
401
402   \sa shortcutKey(), setShortcutKey()
403 */
404
405 /*!
406   \fn void SUIT_DataBrowser::clicked( SUIT_DataObject* o );
407   \brief This signal is emitted when a mouse button is clicked.
408
409   The data object the mouse was clicked on is specified by \a o.
410   The signal is only emitted when the object is valid.
411
412   \param o data object which is clicked
413 */
414
415 /*!
416   \fn void SUIT_DataBrowser::doubleClicked( SUIT_DataObject* o );
417   \brief This signal is emitted when a mouse button is double-clicked.
418
419   The data object the mouse was double-clicked on is specified by \a o.
420   The signal is only emitted when the object is valid.
421
422   \param o data object which is double-clicked
423 */
424
425 /*!
426   \brief Update internal modification time just after data model update
427 */
428 void SUIT_DataBrowser::onModelUpdated()
429 {
430   setModified();
431 }
432
433 /*!
434   \brief Called when item is clicked in the tree view
435   \internal
436   
437   Emits signal clicked( SUIT_DataObject* );
438 */
439 void SUIT_DataBrowser::onClicked( const QModelIndex& index )
440 {
441   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
442
443   if ( m ) {
444     SUIT_DataObject* obj = m->object( index );
445     if ( obj ) { 
446       emit( clicked( obj ) );
447       m->emitClicked(obj, index);
448     }
449   }
450 }
451
452 /*!
453   \brief Called when item is double-clicked in the tree view
454   \internal
455   
456   Emits signal doubleClicked( SUIT_DataObject* );
457 */
458 void SUIT_DataBrowser::onDblClicked( const QModelIndex& index )
459 {
460   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
461
462   if ( m ) {
463     SUIT_DataObject* obj = m->object( index );
464     if ( obj ) emit( doubleClicked( obj ) );
465   }
466 }
467
468 /*!
469   \brief Called when item specified by index is expanded.
470   \internal
471 */
472 void SUIT_DataBrowser::onExpanded( const QModelIndex& index )
473 {
474   if (myResizeOnExpandItem) {
475     adjustFirstColumnWidth();
476     adjustColumnsWidth();
477   }
478 }
479
480 /*!
481   \brief Make editable selected item in place.
482   \internal
483 */
484 void SUIT_DataBrowser::onStartEditing() {
485   DataObjectList sel = getSelected();
486   SUIT_ProxyModel* m = qobject_cast<SUIT_ProxyModel*>( model() );
487   if(treeView() && m && sel.count() == 1){
488     treeView()->edit(m->index( sel.first(), SUIT_DataObject::NameId ));
489   }
490 }
491