Salome HOME
641de07f7af20dc9875502a7683a08ed0ef8cefc
[modules/shaper.git] / src / XGUI / XGUI_ObjectsBrowser.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 #include "XGUI_ObjectsBrowser.h"
4 #include "XGUI_Tools.h"
5 #include "XGUI_DataModel.h"
6
7 #include <ModelAPI_Data.h>
8 #include <ModelAPI_Session.h>
9 #include <ModelAPI_Document.h>
10 #include <ModelAPI_Tools.h>
11
12 #include <ModuleBase_Tools.h>
13 #include <ModuleBase_IDocumentDataModel.h>
14
15 #include <QLayout>
16 #include <QLabel>
17 #include <QLineEdit>
18 #include <QPixmap>
19 #include <QEvent>
20 #include <QMouseEvent>
21 #include <QAction>
22 #include <QStyledItemDelegate>
23 #include <QMessageBox>
24
25 /// Width of second column (minimum acceptable = 27)
26 #define SECOND_COL_WIDTH 30
27
28
29 /**
30 * \ingroup GUI
31 * Tree item delegate for definition of data in column items editor
32 */
33 class XGUI_TreeViewItemDelegate: public QStyledItemDelegate
34 {
35 public:
36   /// Constructor
37   /// \param theParent a parent of the delegate
38   XGUI_TreeViewItemDelegate(XGUI_DataTree* theParent):QStyledItemDelegate(theParent), myTreedView(theParent) {}
39
40   /// Set data for item editor (name of the item)
41   /// \param editor a widget of editor
42   /// \param index the tree item index
43   virtual void  setEditorData ( QWidget* editor, const QModelIndex& index ) const
44   {
45     QLineEdit* aEditor = dynamic_cast<QLineEdit*>(editor);
46     if (aEditor) {
47       ModuleBase_IDocumentDataModel* aModel = myTreedView->dataModel();
48       ObjectPtr aObj = aModel->object(index);
49       if (aObj.get() != NULL) {
50         aEditor->setText(aObj->data()->name().c_str());
51         return;
52       }
53     }
54     QStyledItemDelegate::setEditorData(editor, index);
55   }
56
57 private:
58   XGUI_DataTree* myTreedView;
59 };
60
61
62 XGUI_DataTree::XGUI_DataTree(QWidget* theParent)
63     : QTreeView(theParent)
64 {
65   setHeaderHidden(true);
66   setEditTriggers(QAbstractItemView::NoEditTriggers);
67   setSelectionBehavior(QAbstractItemView::SelectRows);
68   setSelectionMode(QAbstractItemView::ExtendedSelection);
69
70   setItemDelegateForColumn(0, new XGUI_TreeViewItemDelegate(this));
71 }
72
73 XGUI_DataTree::~XGUI_DataTree()
74 {
75 }
76
77 ModuleBase_IDocumentDataModel* XGUI_DataTree::dataModel() const
78 {
79   return static_cast<ModuleBase_IDocumentDataModel*>(model());
80 }
81
82 void XGUI_DataTree::contextMenuEvent(QContextMenuEvent* theEvent)
83 {
84   emit contextMenuRequested(theEvent);
85 }
86
87 void XGUI_DataTree::commitData(QWidget* theEditor)
88 {
89   QLineEdit* aEditor = dynamic_cast<QLineEdit*>(theEditor);
90   if (aEditor) {
91     QString aName = aEditor->text();
92     QModelIndexList aIndexList = selectionModel()->selectedIndexes();
93     ModuleBase_IDocumentDataModel* aModel = dataModel();
94     ObjectPtr aObj = aModel->object(aIndexList.first());
95     SessionPtr aMgr = ModelAPI_Session::get();
96     aMgr->startOperation("Rename");
97
98     if (!XGUI_Tools::canRename(this, aObj, aName)) {
99       aMgr->abortOperation();
100       return;
101     }
102
103     aObj->data()->setName(qPrintable(aName));
104     aMgr->finishOperation();
105   }
106 }
107
108 void XGUI_DataTree::clear() 
109 {
110   ModuleBase_IDocumentDataModel* aModel = dataModel();
111   aModel->clear();
112   reset();
113 }
114
115 void XGUI_DataTree::resizeEvent(QResizeEvent* theEvent)
116 {
117   QSize aSize = theEvent->size();
118   if (aSize.isValid()) {
119     setColumnWidth(0, aSize.width() - SECOND_COL_WIDTH);
120     setColumnWidth(1, SECOND_COL_WIDTH);
121   }
122 }
123
124
125 //********************************************************************
126 //********************************************************************
127 //********************************************************************
128 XGUI_ObjectsBrowser::XGUI_ObjectsBrowser(QWidget* theParent)
129     : QWidget(theParent), myDocModel(0)
130 {
131   QVBoxLayout* aLayout = new QVBoxLayout(this);
132   ModuleBase_Tools::zeroMargins(aLayout);
133   aLayout->setSpacing(0);
134
135   QFrame* aLabelWgt = new QFrame(this);
136   aLabelWgt->setAutoFillBackground(true);
137   QPalette aPalet = aLabelWgt->palette();
138   aPalet.setColor(QPalette::Window, Qt::white);
139   aLabelWgt->setPalette(aPalet);
140
141   aLayout->addWidget(aLabelWgt);
142   QHBoxLayout* aLabelLay = new QHBoxLayout(aLabelWgt);
143   ModuleBase_Tools::zeroMargins(aLabelLay);
144   aLabelLay->setSpacing(0);
145
146   QLabel* aLbl = new QLabel(aLabelWgt);
147   aLbl->setPixmap(QPixmap(":pictures/assembly.png"));
148   aLbl->setMargin(2);
149
150   aLbl->setAutoFillBackground(true);
151
152   aLabelLay->addWidget(aLbl);
153
154   SessionPtr aMgr = ModelAPI_Session::get();
155   DocumentPtr aDoc = aMgr->moduleDocument();
156   // TODO: Find a name of the root document
157
158   myActiveDocLbl = new QLineEdit(tr("Part set"), aLabelWgt);
159   myActiveDocLbl->setReadOnly(true);
160   myActiveDocLbl->setFrame(false);
161   //myActiveDocLbl->setMargin(2);
162   myActiveDocLbl->setContextMenuPolicy(Qt::CustomContextMenu);
163
164   myActiveDocLbl->installEventFilter(this);
165
166   aLabelLay->addWidget(myActiveDocLbl);
167   aLabelLay->setStretch(1, 1);
168
169   myTreeView = new XGUI_DataTree(this);
170   aLayout->addWidget(myTreeView);
171
172   aLabelWgt->setFrameShape(myTreeView->frameShape());
173   aLabelWgt->setFrameShadow(myTreeView->frameShadow());
174
175   connect(myActiveDocLbl, SIGNAL(customContextMenuRequested(const QPoint&)), this,
176           SLOT(onLabelContextMenuRequested(const QPoint&)));
177   connect(myTreeView, SIGNAL(contextMenuRequested(QContextMenuEvent*)), this,
178           SLOT(onContextMenuRequested(QContextMenuEvent*)));
179
180   // Create internal actions
181   QAction* aAction = new QAction(QIcon(":pictures/rename_edit.png"), tr("Rename"), this);
182   aAction->setData("RENAME_CMD");
183   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onEditItem()));
184   addAction(aAction);
185 }
186
187 //***************************************************
188 XGUI_ObjectsBrowser::~XGUI_ObjectsBrowser()
189 {
190 }
191
192 //***************************************************
193 bool XGUI_ObjectsBrowser::eventFilter(QObject* obj, QEvent* theEvent)
194 {
195   if (obj == myActiveDocLbl) {
196     if (!myActiveDocLbl->isReadOnly()) {
197       // End of editing by mouse click
198       if (theEvent->type() == QEvent::MouseButtonRelease) {
199         QMouseEvent* aEvent = (QMouseEvent*) theEvent;
200         QPoint aPnt = mapFromGlobal(aEvent->globalPos());
201         if (childAt(aPnt) != myActiveDocLbl) {
202           closeDocNameEditing(true);
203         }
204       } else if (theEvent->type() == QEvent::KeyRelease) {
205         QKeyEvent* aEvent = (QKeyEvent*) theEvent;
206         switch (aEvent->key()) {
207           case Qt::Key_Return:
208           case Qt::Key_Enter:  // Accept current input
209             closeDocNameEditing(true);
210             break;
211           case Qt::Key_Escape:  // Cancel the input
212             closeDocNameEditing(false);
213             break;
214         }
215       }
216     } else {
217       if (theEvent->type() == QEvent::MouseButtonDblClick) {
218         emit headerMouseDblClicked(QModelIndex());
219         return true;
220       }  
221     }
222   }
223   return QWidget::eventFilter(obj, theEvent);
224 }
225
226 //***************************************************
227 void XGUI_ObjectsBrowser::closeDocNameEditing(bool toSave)
228 {
229   myActiveDocLbl->deselect();
230   myActiveDocLbl->clearFocus();
231   myActiveDocLbl->releaseMouse();
232   myActiveDocLbl->setReadOnly(true);
233   if (toSave) {
234     // TODO: Save the name of root document
235     SessionPtr aMgr = ModelAPI_Session::get();
236     DocumentPtr aDoc = aMgr->moduleDocument();
237   } else {
238     myActiveDocLbl->setText(myActiveDocLbl->property("OldText").toString());
239   }
240 }
241
242 //***************************************************
243 void XGUI_ObjectsBrowser::onContextMenuRequested(QContextMenuEvent* theEvent)
244 {
245   QModelIndexList aIndexes;
246   QObjectPtrList aSelectedData = selectedObjects(&aIndexes);
247   bool toEnable = false;
248   if (aSelectedData.size() == 1) {
249     Qt::ItemFlags aFlags = dataModel()->flags(aIndexes.first());
250     toEnable = ((aFlags & Qt::ItemIsEditable) != 0);
251   }
252   foreach(QAction* aCmd, actions()) {
253     aCmd->setEnabled(toEnable);
254   }
255   emit contextMenuRequested(theEvent);
256 }
257
258 //***************************************************
259 void XGUI_ObjectsBrowser::onLabelContextMenuRequested(const QPoint& thePnt)
260 {
261   myTreeView->selectionModel()->clearSelection();
262   //Empty feature pointer means that selected root document
263   foreach(QAction* aCmd, actions()) {
264     aCmd->setEnabled(true);
265   }
266   QContextMenuEvent aEvent(QContextMenuEvent::Mouse, thePnt, myActiveDocLbl->mapToGlobal(thePnt));
267   emit contextMenuRequested(&aEvent);
268 }
269
270 //***************************************************
271 void XGUI_ObjectsBrowser::onEditItem()
272 {
273   QObjectPtrList aSelectedData = selectedObjects();
274   if (aSelectedData.size() > 0) {
275     ObjectPtr aFeature = aSelectedData.first();
276     if (aFeature) {  // Selection happens in TreeView
277       QObjectPtrList aList;
278       aList.append(aFeature);
279       // check whether the object can be deleted. There should not be parts which are not loaded
280       if (!XGUI_Tools::canRemoveOrRename((QWidget*)parent(), aList))
281         return;
282
283       // Find index which corresponds the feature
284       QModelIndex aIndex;
285       foreach(QModelIndex aIdx, selectedIndexes()) {
286         ObjectPtr aFea = dataModel()->object(aIdx);
287         if (dataModel()->object(aIdx)->isSame(aFeature)) {
288           aIndex = aIdx;
289           break;
290         }
291       }
292       if (aIndex.isValid()) {
293         myTreeView->setCurrentIndex(aIndex);
294         myTreeView->edit(aIndex);
295       }
296       return;
297     }
298   }
299   //Selection happens in Upper label
300   myActiveDocLbl->setReadOnly(false);
301   myActiveDocLbl->setFocus();
302   myActiveDocLbl->selectAll();
303   myActiveDocLbl->grabMouse();
304   myActiveDocLbl->setProperty("OldText", myActiveDocLbl->text());
305 }
306
307 //***************************************************
308 void XGUI_ObjectsBrowser::rebuildDataTree()
309 {
310   myDocModel->rebuildDataTree();
311   update();
312 }
313
314 //***************************************************
315 void XGUI_ObjectsBrowser::setObjectsSelected(const QObjectPtrList& theObjects)
316 {
317   QList<QModelIndex> theIndexes;
318   QItemSelectionModel* aSelectModel = myTreeView->selectionModel();
319   aSelectModel->clear();
320
321   foreach(ObjectPtr aFeature, theObjects)
322   {
323     QModelIndex aIndex = myDocModel->objectIndex(aFeature);
324     if (aIndex.isValid()) {
325       aSelectModel->select(aIndex, QItemSelectionModel::Select);
326     }
327   }
328 }
329
330 //***************************************************
331 void XGUI_ObjectsBrowser::clearContent()  
332
333   myTreeView->clear(); 
334 }
335
336 void XGUI_ObjectsBrowser::setDataModel(ModuleBase_IDocumentDataModel* theModel)
337 {
338 #ifdef ModuleDataModel
339   myDocModel = theModel;
340 #else
341   myDocModel = new XGUI_DataModel(this);
342 #endif
343   myTreeView->setModel(myDocModel);
344   QItemSelectionModel* aSelMod = myTreeView->selectionModel();
345   connect(aSelMod, SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
346           this, SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&)));
347 }
348
349 void XGUI_ObjectsBrowser::onSelectionChanged(const QItemSelection& theSelected,
350                                        const QItemSelection& theDeselected)
351 {
352   emit selectionChanged();
353 }
354
355 QObjectPtrList XGUI_ObjectsBrowser::selectedObjects(QModelIndexList* theIndexes) const
356 {
357   QObjectPtrList aList;
358   QModelIndexList aIndexes = selectedIndexes();
359 #ifdef ModuleDataModel
360   ModuleBase_IDocumentDataModel* aModel = dataModel();
361 #else
362   XGUI_DataModel* aModel = dataModel();
363 #endif
364   QModelIndexList::const_iterator aIt;
365   for (aIt = aIndexes.constBegin(); aIt != aIndexes.constEnd(); ++aIt) {
366     if ((*aIt).column() == 0) {
367       ObjectPtr aObject = aModel->object(*aIt);
368       if (aObject) {
369         aList.append(aObject);
370         if (theIndexes)
371           theIndexes->append(*aIt);
372       }
373     }
374   }
375   return aList;
376 }