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