]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_ObjectsBrowser.cpp
Salome HOME
Unselect root label in object browser on mouse click in Object browser
[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 #include <Events_Error.h>
12
13 #include <ModuleBase_Tools.h>
14
15 #include <QLayout>
16 #include <QLabel>
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   static int aEntrance = 0;
92   if (aEntrance == 0) {
93     // We have to check number of enter and exit of this function because it can be called recursively by Qt
94     // in order to avoid double modifying of a data
95     aEntrance = 1;
96     QLineEdit* aEditor = dynamic_cast<QLineEdit*>(theEditor);
97     if (aEditor) {
98       QString aName = aEditor->text();
99       QModelIndexList aIndexList = selectionModel()->selectedIndexes();
100       XGUI_DataModel* aModel = dataModel();
101       ObjectPtr aObj = aModel->object(aIndexList.first());
102
103       if (XGUI_Tools::canRename(aObj, aName)) {
104         SessionPtr aMgr = ModelAPI_Session::get();
105         aMgr->startOperation("Rename");
106         aObj->data()->setName(qPrintable(aName));
107         aMgr->finishOperation();
108       }
109     }
110   }
111   aEntrance = 0;
112 }
113
114 void XGUI_DataTree::clear() 
115 {
116   dataModel()->clear();
117   reset();
118 }
119
120 void XGUI_DataTree::resizeEvent(QResizeEvent* theEvent)
121 {
122   QSize aSize = theEvent->size();
123   if (aSize.isValid()) {
124     setColumnWidth(0, aSize.width() - SECOND_COL_WIDTH);
125     setColumnWidth(1, SECOND_COL_WIDTH);
126   }
127 }
128
129 void XGUI_DataTree::onDoubleClick(const QModelIndex& theIndex)
130 {
131   if (theIndex.column() != 1)
132     return;
133   SessionPtr aMgr = ModelAPI_Session::get();
134   // When operation is opened then we can not change history
135   if (aMgr->isOperation())
136     return;
137   XGUI_DataModel* aModel = dataModel();
138   if (aModel->flags(theIndex) == 0)
139     return;
140   ObjectPtr aObj = aModel->object(theIndex);
141
142   DocumentPtr aDoc = aMgr->activeDocument();
143   
144   std::string aOpName = tr("History change").toStdString();
145   if (aObj.get()) {
146     if (aObj->document() != aDoc)
147       return;
148     aMgr->startOperation(aOpName);
149     aDoc->setCurrentFeature(std::dynamic_pointer_cast<ModelAPI_Feature>(aObj), true);
150     aMgr->finishOperation();
151   } else {
152     // Ignore clicks on folders outside current document
153     if ((theIndex.internalId() == -1) && (aDoc != aMgr->moduleDocument()))
154       // Clicked folder under root but active document is another
155       return;
156     if ((theIndex.internalId() != -1) && (aDoc.get() != theIndex.internalPointer()))
157       // Cliced not on active document folder
158       return;
159
160     aMgr->startOperation(aOpName);
161     aDoc->setCurrentFeature(FeaturePtr(), true);
162     aMgr->finishOperation();
163   }
164   QModelIndex aNewIndex = aModel->lastHistoryIndex();
165   QModelIndex aParent = theIndex.parent();
166   int aSize = aModel->rowCount(aParent);
167   for (int i = 0; i < aSize; i++) {
168     update(aModel->index(i, 0, aParent));
169   }
170 }
171
172 //********************************************************************
173 //********************************************************************
174 //********************************************************************
175 XGUI_ActiveDocLbl::XGUI_ActiveDocLbl(const QString& theText, QWidget* theParent )
176   : QLineEdit(theText, theParent), 
177   myPreSelectionStyle(""), 
178   myNeutralStyle(""), 
179   mySelectionStyle(""),
180   myIsSelected(false)
181 {
182 }
183
184 void XGUI_ActiveDocLbl::setTreeView(QTreeView* theView)
185 {
186   myTreeView = theView;
187   QPalette aPalet = myTreeView->palette();
188   QColor aHighlight = aPalet.highlight().color();
189
190   myPreSelectionStyle = "QLineEdit {background-color: ";
191   myPreSelectionStyle += "qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:1 " + aHighlight.lighter(170).name() + ");"; 
192   myPreSelectionStyle += "border: 1px solid lightblue; border-radius: 2px }";
193
194   QString aName = aPalet.color(QPalette::Base).name();
195   myNeutralStyle = "QLineEdit { border: 1px solid " + aName + " }";
196
197   mySelectionStyle = "QLineEdit {background-color: ";
198   mySelectionStyle += "qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 " + aHighlight.lighter(170).name();
199   mySelectionStyle += ", stop:1 " + aHighlight.lighter().name() + ");"; 
200   mySelectionStyle += "border: 1px solid lightblue; border-radius: 2px }";
201
202   myTreeView->viewport()->installEventFilter(this);
203 }
204
205
206 bool XGUI_ActiveDocLbl::event(QEvent* theEvent)
207 {
208   switch (theEvent->type()) {
209     case QEvent::Enter:
210       if (!myIsSelected)
211         setStyleSheet(myPreSelectionStyle);
212       break;
213     case QEvent::Leave:
214       if (!myIsSelected)
215         setStyleSheet(myNeutralStyle);
216       break;
217   }
218   return QLineEdit::event(theEvent);
219 }
220
221 bool XGUI_ActiveDocLbl::eventFilter(QObject* theObj, QEvent* theEvent)
222 {
223   if (theObj == myTreeView->viewport()) {
224     if (theEvent->type() == QEvent::MouseButtonRelease)
225       unselect();
226   }
227   return QLineEdit::eventFilter(theObj, theEvent);
228 }
229
230 static bool MYClearing = false;
231 void XGUI_ActiveDocLbl::mouseReleaseEvent( QMouseEvent* e)
232 {
233   MYClearing = true;
234   myIsSelected = true;
235   setStyleSheet(mySelectionStyle);
236   // We can not block signals because on 
237   // clear selection the View state will not be updated
238   myTreeView->clearSelection();
239   QLineEdit::mouseReleaseEvent(e);
240   MYClearing = false;
241 }
242
243 void XGUI_ActiveDocLbl::unselect()
244 {
245   if (!MYClearing) {
246     myIsSelected = false;
247     setStyleSheet(myNeutralStyle);
248   }
249 }
250
251
252 //********************************************************************
253 //********************************************************************
254 //********************************************************************
255 XGUI_ObjectsBrowser::XGUI_ObjectsBrowser(QWidget* theParent)
256     : QWidget(theParent), myDocModel(0)
257 {
258   QVBoxLayout* aLayout = new QVBoxLayout(this);
259   ModuleBase_Tools::zeroMargins(aLayout);
260   aLayout->setSpacing(0);
261
262   QWidget* aLabelWgt = new QWidget(this);
263   aLabelWgt->setAutoFillBackground(true);
264
265   aLayout->addWidget(aLabelWgt);
266   QHBoxLayout* aLabelLay = new QHBoxLayout(aLabelWgt);
267   ModuleBase_Tools::zeroMargins(aLabelLay);
268   aLabelLay->setSpacing(0);
269
270   QLabel* aLbl = new QLabel(aLabelWgt);
271   aLbl->setPixmap(QPixmap(":pictures/assembly.png"));
272   aLbl->setMargin(2);
273   // Do not paint background of the label (in order to show icon)
274   aLbl->setAutoFillBackground(false); 
275
276   aLabelLay->addWidget(aLbl);
277
278   SessionPtr aMgr = ModelAPI_Session::get();
279   DocumentPtr aDoc = aMgr->moduleDocument();
280
281   myActiveDocLbl = new XGUI_ActiveDocLbl(tr("Part set"), aLabelWgt);
282   myActiveDocLbl->setReadOnly(true);
283   myActiveDocLbl->setFrame(false);
284   myActiveDocLbl->setContextMenuPolicy(Qt::CustomContextMenu);
285
286   aLabelLay->addWidget(myActiveDocLbl);
287   aLabelLay->setStretch(1, 1);
288
289   myTreeView = new XGUI_DataTree(this);
290   myTreeView->setFrameShape(QFrame::NoFrame);
291   aLayout->addWidget(myTreeView);
292
293   QPalette aTreePalet = myTreeView->palette();
294   QColor aTreeBack = aTreePalet.color(QPalette::Base);
295
296   QPalette aPalet;
297   aPalet.setColor(QPalette::Base, aTreeBack);
298   aPalet.setColor(QPalette::Window, aTreeBack);
299   aLabelWgt->setPalette(aPalet);
300
301   myDocModel = new XGUI_DataModel(this);
302   myTreeView->setModel(myDocModel);
303
304   // It has to be done after setting of model
305   myActiveDocLbl->setTreeView(myTreeView);
306
307   QItemSelectionModel* aSelMod = myTreeView->selectionModel();
308   connect(aSelMod, SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
309           this, SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&)));
310
311   connect(myTreeView, SIGNAL(contextMenuRequested(QContextMenuEvent*)), this,
312           SLOT(onContextMenuRequested(QContextMenuEvent*)));
313 }
314
315 //***************************************************
316 XGUI_ObjectsBrowser::~XGUI_ObjectsBrowser()
317 {
318 }
319
320
321 //***************************************************
322 void XGUI_ObjectsBrowser::onContextMenuRequested(QContextMenuEvent* theEvent)
323 {
324   QModelIndexList aIndexes;
325   QObjectPtrList aSelectedData = selectedObjects(&aIndexes);
326   bool toEnable = false;
327
328   if (aSelectedData.size() == 1) {
329     QModelIndex aSelected = myTreeView->indexAt(theEvent->pos());
330     if (!aIndexes.contains(aSelected))
331       return; // menu is called on non selected item
332
333     Qt::ItemFlags aFlags = dataModel()->flags(aIndexes.first());
334     toEnable = ((aFlags & Qt::ItemIsEditable) != 0);
335   }
336   foreach(QAction* aCmd, actions()) {
337     aCmd->setEnabled(toEnable);
338   }
339   emit contextMenuRequested(theEvent);
340 }
341
342 //***************************************************
343 void XGUI_ObjectsBrowser::onLabelContextMenuRequested(const QPoint& thePnt)
344 {
345   myTreeView->selectionModel()->clearSelection();
346   //Empty feature pointer means that selected root document
347   foreach(QAction* aCmd, actions()) {
348     aCmd->setEnabled(true);
349   }
350   QContextMenuEvent aEvent(QContextMenuEvent::Mouse, thePnt, myActiveDocLbl->mapToGlobal(thePnt));
351   emit contextMenuRequested(&aEvent);
352 }
353
354 //***************************************************
355 void XGUI_ObjectsBrowser::onEditItem()
356 {
357   QObjectPtrList aSelectedData = selectedObjects();
358   if (aSelectedData.size() > 0) {
359     ObjectPtr aFeature = aSelectedData.first();
360     if (aFeature) {  // Selection happens in TreeView
361       QObjectPtrList aList;
362       aList.append(aFeature);
363       // check whether the object can be deleted. There should not be parts which are not loaded
364       if (!XGUI_Tools::canRemoveOrRename((QWidget*)parent(), aList))
365         return;
366
367       // Find index which corresponds the feature
368       QModelIndex aIndex;
369       foreach(QModelIndex aIdx, selectedIndexes()) {
370         ObjectPtr aFea = dataModel()->object(aIdx);
371         if (dataModel()->object(aIdx)->isSame(aFeature)) {
372           aIndex = aIdx;
373           break;
374         }
375       }
376       if (aIndex.isValid()) {
377         myTreeView->setCurrentIndex(aIndex);
378         myTreeView->edit(aIndex);
379       }
380       return;
381     }
382   }
383 }
384
385 //***************************************************
386 void XGUI_ObjectsBrowser::rebuildDataTree()
387 {
388   myDocModel->rebuildDataTree();
389   update();
390 }
391
392 //***************************************************
393 void XGUI_ObjectsBrowser::setObjectsSelected(const QObjectPtrList& theObjects)
394 {
395   QList<QModelIndex> theIndexes;
396   QItemSelectionModel* aSelectModel = myTreeView->selectionModel();
397   aSelectModel->clear();
398
399   foreach(ObjectPtr aFeature, theObjects)
400   {
401     QModelIndex aIndex = myDocModel->objectIndex(aFeature);
402     if (aIndex.isValid()) {
403       aSelectModel->select(aIndex, QItemSelectionModel::Select);
404     }
405   }
406 }
407
408 //***************************************************
409 void XGUI_ObjectsBrowser::clearContent()  
410
411   myTreeView->clear(); 
412 }
413
414 void XGUI_ObjectsBrowser::onSelectionChanged(const QItemSelection& theSelected,
415                                        const QItemSelection& theDeselected)
416 {
417   emit selectionChanged();
418 }
419
420 QObjectPtrList XGUI_ObjectsBrowser::selectedObjects(QModelIndexList* theIndexes) const
421 {
422   QObjectPtrList aList;
423   QModelIndexList aIndexes = selectedIndexes();
424   XGUI_DataModel* aModel = dataModel();
425   QModelIndexList::const_iterator aIt;
426   for (aIt = aIndexes.constBegin(); aIt != aIndexes.constEnd(); ++aIt) {
427     if ((*aIt).column() == 0) {
428       ObjectPtr aObject = aModel->object(*aIt);
429       if (aObject) {
430         aList.append(aObject);
431         if (theIndexes)
432           theIndexes->append(*aIt);
433       }
434     }
435   }
436   return aList;
437 }