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