Salome HOME
Merge branch 'BR_PY3'
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_DataBrowser.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include "HYDROGUI_DataBrowser.h"
20 #include "HYDROGUI_Module.h"
21 #include "HYDROGUI_DataObject.h"
22 #include "HYDROGUI_Tool.h"
23
24 #include <LightApp_Application.h>
25 #include <LightApp_OBSelector.h>
26 #include <LightApp_SelectionMgr.h>
27 #include <QHeaderView>
28 #include <QtxSearchTool.h>
29 #include <QtxTreeView.h>
30 #include <SUIT_DataObject.h>
31 #include <SUIT_ResourceMgr.h>
32 #include <SUIT_SelectionMgr.h>
33 #include <SUIT_DataObjectIterator.h>
34
35 #define VISIBILITY_COLUMN_WIDTH 25
36
37
38 #include <SUIT_Selector.h>
39 #include <SUIT_DataOwner.h>
40
41 #include <QObject>
42 #include <QShortcut>
43 #include <QMenu>
44
45 class SUIT_DataBrowser;
46 class LightApp_DataObject;
47
48
49 #include "LightApp_DataOwner.h"
50 #include "LightApp_DataObject.h"
51 #include "LightApp_Application.h"
52 #include <SUIT_DataBrowser.h>
53 #include <SUIT_Session.h>
54 #include <SUIT_DataObjectIterator.h>
55 #include <QTime>
56 #include <time.h>
57
58
59 // The selector is redefined in order to correct the selection in the browser.
60 // The main modification is to call fillEntries without the selector modified
61 // time compare. The modified time is result of the clock() method.
62 // On Linux, the method clock() returns the same values with some delay. So, it is possible,
63 // that time has the same value, but the browser has already other objects.
64 // So, the obsole entries can be in the saved entries by the filled method.
65 // May be it will be improved in the latest version of GUI_SRC.
66 // This redefinition is done for tag V7_3_0 of GUI_SRC.
67 class HYDROGUI_OBSelector : public LightApp_OBSelector
68 {
69 public:
70   HYDROGUI_OBSelector( SUIT_DataBrowser*, SUIT_SelectionMgr* );
71   virtual ~HYDROGUI_OBSelector();
72
73 protected:
74   virtual void       getSelection( SUIT_DataOwnerPtrList& ) const;
75   virtual void       setSelection( const SUIT_DataOwnerPtrList& );
76
77 private:
78   void               fillEntries( QMap<QString, LightApp_DataObject*>& );
79
80 private:
81   SUIT_DataOwnerPtrList               mySelectedList;
82   QMap<QString, LightApp_DataObject*> myEntries;
83 };
84
85 HYDROGUI_OBSelector::HYDROGUI_OBSelector( SUIT_DataBrowser* ob, SUIT_SelectionMgr* mgr )
86 : LightApp_OBSelector( ob, mgr )
87 {
88 }
89
90 /*!
91   \brief Destructor.
92 */
93 HYDROGUI_OBSelector::~HYDROGUI_OBSelector()
94 {
95 }
96
97 /*!
98   \brief Get list of currently selected objects.
99   \param theList list to be filled with the selected objects owners
100   \ This method is necessary to fill the cach containter mySelectedList
101   \ It is the same as in LightApp_OBSelector
102 */
103 void HYDROGUI_OBSelector::getSelection( SUIT_DataOwnerPtrList& theList ) const
104 {
105   SUIT_DataBrowser* aBrowser = browser();
106
107   if ( mySelectedList.count() == 0 ) {
108     SUIT_Session* session = SUIT_Session::session();
109     SUIT_Application* sapp = session ? session->activeApplication() : 0;
110     LightApp_Application* app = dynamic_cast<LightApp_Application*>( sapp );
111     if( !app || !aBrowser )
112       return;
113
114     DataObjectList objlist;
115     aBrowser->getSelected( objlist );
116     HYDROGUI_OBSelector* that = (HYDROGUI_OBSelector*)this;
117     QListIterator<SUIT_DataObject*> it( objlist );
118     while ( it.hasNext() ) {
119       LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( it.next() );
120       if ( obj && app->checkDataObject( obj) ) {
121 #ifndef DISABLE_SALOMEOBJECT
122         Handle(SALOME_InteractiveObject) aSObj = new SALOME_InteractiveObject
123           ( obj->entry().toLatin1().constData(),
124             obj->componentDataType().toLatin1().constData(),
125             obj->name().toLatin1().constData() );
126         LightApp_DataOwner* owner = new LightApp_DataOwner( aSObj  );
127 #else
128         LightApp_DataOwner* owner = new LightApp_DataOwner( obj->entry() );
129 #endif
130         that->mySelectedList.append( SUIT_DataOwnerPtr( owner ) );
131       }
132     }
133   }
134   theList = mySelectedList;
135 }
136
137 /*!
138   \brief Set selection.
139   \param theList list of the object owners to be set selected
140   \ It is the same as in LightApp_OBSelector. The difference is in the row with
141   \ the modification time check.
142 */
143 void HYDROGUI_OBSelector::setSelection( const SUIT_DataOwnerPtrList& theList )
144 {
145   SUIT_DataBrowser* aBrowser = browser();
146   if ( !aBrowser )
147     return;
148
149   // this is the difference to LightApp_OBSelector. For this, this class is redefined
150   //if( myEntries.count() == 0 || myModifiedTime < aBrowser->getModifiedTime() )
151   {
152     fillEntries( myEntries );
153   }
154
155   DataObjectList objList;
156   for ( SUIT_DataOwnerPtrList::const_iterator it = theList.begin();
157         it != theList.end(); ++it ) {
158     const LightApp_DataOwner* owner = dynamic_cast<const LightApp_DataOwner*>( (*it).operator->() );
159
160     if ( owner && myEntries.contains( owner->entry() ) )
161       objList.append( myEntries[owner->entry()] );
162   }
163
164   aBrowser->setSelected( objList );
165   mySelectedList.clear();
166 }
167
168 /*!
169   \brief Fill map of the data objects currently shown in the Object Browser.
170   \param entries map to be filled
171   \ It is the same as in LightApp_OBSelector
172 */
173 void HYDROGUI_OBSelector::fillEntries( QMap<QString, LightApp_DataObject*>& entries )
174 {
175   entries.clear();
176
177   SUIT_DataBrowser* aBrowser = browser();
178   if ( !aBrowser )
179     return;
180
181   for ( SUIT_DataObjectIterator it( aBrowser->root(),
182                                     SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
183     LightApp_DataObject* obj = dynamic_cast<LightApp_DataObject*>( it.current() );
184     if ( obj )
185       entries.insert( obj->entry(), obj );
186   }
187
188   setModified();
189 }
190
191
192 HYDROGUI_DataBrowser::HYDROGUI_DataBrowser( HYDROGUI_Module* theModule,
193                                             SUIT_DataObject* theRoot,
194                                             QWidget* theParent,
195                                             bool theLandCover/* = false*/)
196 : SUIT_DataBrowser( theRoot, theParent ), myModule( theModule )
197 {
198   SUIT_ResourceMgr* resMgr = theModule->getApp()->resourceMgr();
199
200   if ( ( !theRoot ) && theModule )
201   {
202     // Initialize the root with the module data model
203     setRoot( new CAM_ModuleObject( theModule->dataModel(), NULL ) );
204   }
205
206   setSortMenuEnabled( true );
207   setAutoUpdate( true );
208   setUpdateModified( true );
209
210   if ( resMgr->hasValue( "ObjectBrowser", "auto_hide_search_tool" ) )
211     searchTool()->enableAutoHide( resMgr->booleanValue( "ObjectBrowser", "auto_hide_search_tool" ) );
212
213   setWindowTitle( tr( "OBJECT_BROWSER" ) );
214   connect( this, SIGNAL( requestUpdate() ), theModule->getApp(), SLOT( onRefresh() ) );
215
216   QString EntryCol = QObject::tr( "ENTRY_COLUMN" );
217   QString RefObjCol = tr( "REF_OBJECT_COLUMN" );
218   QString AltitudeCol;
219   if ( theLandCover )
220     AltitudeCol = tr( "LAND_COVER_COLUMN" );
221   else
222     AltitudeCol = tr( "ALTITUDE_COLUMN" );
223
224   SUIT_AbstractModel* treeModel = dynamic_cast<SUIT_AbstractModel*>( model() );
225   //RKV: treeModel->setSearcher( theModule->getApp() );
226   treeModel->setSearcher( this ); //RKV
227   treeModel->registerColumn( 0, EntryCol, LightApp_DataObject::EntryId );
228   treeModel->setAppropriate( EntryCol, Qtx::Toggled );
229   treeModel->registerColumn( 0, RefObjCol, HYDROGUI_DataObject::RefObjectId );
230   treeModel->setAppropriate( RefObjCol, Qtx::Toggled );
231   treeModel->registerColumn( 0, AltitudeCol, HYDROGUI_DataObject::AltitudeObjId );
232   treeModel->setAppropriate( AltitudeCol, Qtx::Toggled );
233
234   // Mantis issue 0020136: Drag&Drop in OB
235   SUIT_ProxyModel* proxyModel = dynamic_cast<SUIT_ProxyModel*>(treeModel);
236   if ( proxyModel ) {
237     connect( proxyModel,
238       SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ),
239       SIGNAL( dropped( const QList<SUIT_DataObject*>&, SUIT_DataObject*, int, Qt::DropAction ) ) );
240
241     //// Connect signal emitted after editing for updating after objects renaming
242     SUIT_TreeModel* aMiniModel = dynamic_cast<SUIT_TreeModel*>( proxyModel->sourceModel() );
243     if ( aMiniModel )
244     {
245       connect( aMiniModel, SIGNAL( dataChanged( const QModelIndex &, const QModelIndex & ) ),
246         SIGNAL( dataChanged() ) );
247     }
248
249     // Do updating also in the module's main object browser.
250     if ( theModule )
251     {
252       SUIT_DataBrowser* aModulBrowser = theModule->getApp()->objectBrowser();
253       if ( aModulBrowser )
254       {
255         SUIT_ProxyModel* aPModel = dynamic_cast<SUIT_ProxyModel*>(aModulBrowser->model());
256         if ( aPModel )
257         {
258           SUIT_TreeModel* aModel = dynamic_cast<SUIT_TreeModel*>(aPModel->sourceModel());
259           //connect( proxyModel, SIGNAL( dataChanged( const QModelIndex &, const QModelIndex & ) ),
260           //  aPModel, SIGNAL( dataChanged( const QModelIndex &, const QModelIndex & ) ) );
261           //connect( proxyModel, SIGNAL( dataChanged( const QModelIndex &, const QModelIndex & ) ),
262           //  aModel, SIGNAL( dataChanged( const QModelIndex &, const QModelIndex & ) ) );
263           connect( proxyModel, SIGNAL( modelUpdated() ), aModel, SIGNAL( modelUpdated() ) );
264         }
265       }
266     }
267   }
268
269   // temporary commented
270   /*
271   OB_ListView* ob_list = dynamic_cast<OB_ListView*>( const_cast<QListView*>( listView() ) );
272   if( ob_list )
273     ob_list->setColumnMaxWidth( 0, theModule->getApp()->desktop()->width()/4 );
274
275   setFilter( new LightApp_OBFilter( theModule->getApp()->selectionMgr() ) );
276   */
277
278   // Create OBSelector
279   new HYDROGUI_OBSelector( this, theModule->getApp()->selectionMgr() );
280
281   treeView()->header()->setSectionResizeMode(SUIT_DataObject::VisibilityId, QHeaderView::Fixed);
282   treeView()->header()->moveSection(SUIT_DataObject::NameId,SUIT_DataObject::VisibilityId);
283   treeView()->setColumnWidth(SUIT_DataObject::VisibilityId, VISIBILITY_COLUMN_WIDTH);
284   treeView()->hideColumn( SUIT_DataObject::VisibilityId );
285   treeView()->hideColumn( LightApp_DataObject::EntryId );
286   connectPopupRequest( theModule->getApp(), SLOT( onConnectPopupRequest( SUIT_PopupClient*, QContextMenuEvent* ) ) );
287 }
288
289 HYDROGUI_DataBrowser::~HYDROGUI_DataBrowser()
290 {
291 }
292
293 SUIT_DataObject* HYDROGUI_DataBrowser::findObject( const QString& theEntry ) const
294 {
295   LightApp_DataObject* aCurObj;
296   for ( SUIT_DataObjectIterator it( root(), SUIT_DataObjectIterator::DepthLeft ); it.current(); ++it ) {
297     aCurObj = dynamic_cast<LightApp_DataObject*>( it.current() );
298     if ( aCurObj && aCurObj->entry() == theEntry )
299       return aCurObj;
300   }
301   return NULL;
302 }
303
304 /*!
305   \brief Switch read only mode for the Object Browser.
306   \param theIsReadOnly if true - read only mode will be turned on
307 */
308 void HYDROGUI_DataBrowser::setReadOnly( const bool theIsReadOnly )
309 {
310   //TODO: to be reimplemented
311
312   // Enable/disable edit triggers
313   foreach ( QTreeView* aView, findChildren<QTreeView*>() ) {
314     aView->setDragEnabled ( !theIsReadOnly );
315     aView->setEditTriggers ( theIsReadOnly ?
316                              QAbstractItemView::NoEditTriggers :
317                              QAbstractItemView::DoubleClicked );
318   }
319
320   // Enable/disable rename shortcut
321   QList<QShortcut*> aShortcuts = findChildren<QShortcut*>();
322   QShortcut* aShortcut;
323   foreach( aShortcut, aShortcuts ) {
324     if ( aShortcut->key() == QKeySequence( shortcutKey( RenameShortcut ) ) ) {
325       aShortcut->setEnabled( !theIsReadOnly );
326     }
327   }
328 }
329
330 void HYDROGUI_DataBrowser::createPopupMenu( QMenu* theMenu )
331 {
332   theMenu->clear();
333   DataObjectList aSelection = getSelected();
334   bool isOnlyZones = aSelection.size() > 0;
335   foreach( SUIT_DataObject* anObj, aSelection )
336   {
337     HYDROGUI_DataObject* aHydroObj = dynamic_cast<HYDROGUI_DataObject*>( anObj );
338     if( aHydroObj )
339     {
340       Handle(HYDROData_Entity) aModelObj = aHydroObj->modelObject();
341       if( !aModelObj.IsNull() )
342       {
343         isOnlyZones = aModelObj->GetKind()==KIND_ZONE;
344         if( !isOnlyZones )
345           break;
346
347         SUIT_DataObject* aParentObj = aHydroObj->parent();
348         if ( aParentObj )
349         {
350           isOnlyZones = aParentObj->childCount() > 1;
351           if( !isOnlyZones )
352             break;
353         }
354       }
355       else
356       {
357         isOnlyZones = false;
358         break;
359       }
360     }
361     else
362     {
363       isOnlyZones = false;
364       break;
365     }
366   }
367
368   if( isOnlyZones )
369     theMenu->addAction( tr( "ZONE_TO_NEW_REGION" ), this, SIGNAL( newRegion() ) );
370 }