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