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