1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 #include "XGUI_ObjectsBrowser.h"
4 #include "XGUI_Tools.h"
5 #include "XGUI_DataModel.h"
7 #include <ModelAPI_Data.h>
8 #include <ModelAPI_Session.h>
9 #include <ModelAPI_Document.h>
10 #include <ModelAPI_Tools.h>
12 #include <ModuleBase_Tools.h>
18 #include <QMouseEvent>
20 #include <QStyledItemDelegate>
21 #include <QMessageBox>
25 // PORTING_TO_SALOME_8
26 //#include <QWindowsStyle>
27 #include <QCommonStyle>
32 /// Width of second column (minimum acceptable = 27)
33 #define SECOND_COL_WIDTH 30
38 * Tree item delegate for definition of data in column items editor
40 class XGUI_TreeViewItemDelegate: public QStyledItemDelegate
44 /// \param theParent a parent of the delegate
45 XGUI_TreeViewItemDelegate(XGUI_DataTree* theParent):QStyledItemDelegate(theParent),
46 myTreedView(theParent) {}
48 /// Set data for item editor (name of the item)
49 /// \param editor a widget of editor
50 /// \param index the tree item index
51 virtual void setEditorData ( QWidget* editor, const QModelIndex& index ) const
53 QLineEdit* aEditor = dynamic_cast<QLineEdit*>(editor);
55 XGUI_DataModel* aModel = myTreedView->dataModel();
56 ObjectPtr aObj = aModel->object(index);
57 if (aObj.get() != NULL) {
58 aEditor->setText(aObj->data()->name().c_str());
62 QStyledItemDelegate::setEditorData(editor, index);
66 XGUI_DataTree* myTreedView;
70 XGUI_DataTree::XGUI_DataTree(QWidget* theParent)
71 : QTreeView(theParent)
75 // setStyle(new QCommonStyle());
77 // myStyle = new XGUI_TreeViewStyle();
82 setHeaderHidden(true);
83 setEditTriggers(QAbstractItemView::NoEditTriggers);
84 setSelectionBehavior(QAbstractItemView::SelectRows);
85 setSelectionMode(QAbstractItemView::ExtendedSelection);
87 setItemDelegateForColumn(0, new XGUI_TreeViewItemDelegate(this));
89 connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
90 SLOT(onDoubleClick(const QModelIndex&)));
93 XGUI_DataTree::~XGUI_DataTree()
97 XGUI_DataModel* XGUI_DataTree::dataModel() const
99 return static_cast<XGUI_DataModel*>(model());
102 void XGUI_DataTree::contextMenuEvent(QContextMenuEvent* theEvent)
104 emit contextMenuRequested(theEvent);
107 void XGUI_DataTree::commitData(QWidget* theEditor)
109 static int aEntrance = 0;
110 if (aEntrance == 0) {
111 // We have to check number of enter and exit of this function because it can be called
112 // recursively by Qt in order to avoid double modifying of a data
114 QLineEdit* aEditor = dynamic_cast<QLineEdit*>(theEditor);
116 QString aName = aEditor->text();
117 QModelIndexList aIndexList = selectionModel()->selectedIndexes();
118 XGUI_DataModel* aModel = dataModel();
119 ObjectPtr aObj = aModel->object(aIndexList.first());
121 if (XGUI_Tools::canRename(aObj, aName)) {
122 SessionPtr aMgr = ModelAPI_Session::get();
123 aMgr->startOperation("Rename");
124 aObj->data()->setName(qPrintable(aName));
125 aMgr->finishOperation();
132 void XGUI_DataTree::clear()
134 dataModel()->clear();
138 void XGUI_DataTree::resizeEvent(QResizeEvent* theEvent)
140 QTreeView::resizeEvent(theEvent);
141 QSize aSize = theEvent->size();
142 if (aSize.isValid()) {
143 setColumnWidth(0, aSize.width() - SECOND_COL_WIDTH - 6);
144 setColumnWidth(1, SECOND_COL_WIDTH);
148 void XGUI_DataTree::onDoubleClick(const QModelIndex& theIndex)
150 if (theIndex.column() != 1)
152 SessionPtr aMgr = ModelAPI_Session::get();
153 // When operation is opened then we can not change history
154 if (aMgr->isOperation())
156 XGUI_DataModel* aModel = dataModel();
157 if (aModel->flags(theIndex) == 0)
159 ObjectPtr aObj = aModel->object(theIndex);
161 DocumentPtr aDoc = aMgr->activeDocument();
163 std::string aOpName = tr("History change").toStdString();
165 if (aObj->document() != aDoc)
167 aMgr->startOperation(aOpName);
168 aDoc->setCurrentFeature(std::dynamic_pointer_cast<ModelAPI_Feature>(aObj), true);
169 aMgr->finishOperation();
171 // Ignore clicks on folders outside current document
172 if ((theIndex.internalId() == 0) && (aDoc != aMgr->moduleDocument()))
173 // Clicked folder under root but active document is another
175 if ((theIndex.internalId() != 0) && (aDoc.get() != theIndex.internalPointer()))
176 // Cliced not on active document folder
179 aMgr->startOperation(aOpName);
180 aDoc->setCurrentFeature(FeaturePtr(), true);
181 aMgr->finishOperation();
183 QModelIndex aNewIndex = aModel->lastHistoryIndex();
184 QModelIndex aParent = theIndex.parent();
185 int aSize = aModel->rowCount(aParent);
186 for (int i = 0; i < aSize; i++) {
187 update(aModel->index(i, 0, aParent));
188 update(aModel->index(i, 1, aParent));
192 //#if (!defined HAVE_SALOME) && (defined WIN32)
193 //void XGUI_DataTree::drawRow(QPainter* thePainter,
194 // const QStyleOptionViewItem& theOptions,
195 // const QModelIndex& theIndex) const
197 // QStyleOptionViewItemV4 aOptions = theOptions;
198 // myStyle->setIndex(theIndex);
199 // QTreeView::drawRow(thePainter, aOptions, theIndex);
202 ////********************************************************************
203 ////********************************************************************
204 ////********************************************************************
205 //void XGUI_TreeViewStyle::drawPrimitive(PrimitiveElement theElement,
206 // const QStyleOption* theOption,
207 // QPainter* thePainter, const QWidget* theWidget) const
209 // if ((theElement == QStyle::PE_PanelItemViewRow) || (theElement == QStyle::PE_PanelItemViewItem)) {
210 // const QStyleOptionViewItemV4* aOptions =
211 // qstyleoption_cast<const QStyleOptionViewItemV4 *>(theOption);
212 // if (myIndex.isValid() && ((myIndex.flags() & Qt::ItemIsSelectable) == 0)) {
213 // QStyle::State aState = aOptions->state;
214 // if ((aState & QStyle::State_MouseOver) != 0)
215 // aState &= ~QStyle::State_MouseOver;
216 // QStyleOptionViewItemV4* aOpt = (QStyleOptionViewItemV4*) aOptions;
217 // aOpt->state = aState;
218 // QCommonStyle::drawPrimitive(theElement, aOpt, thePainter, theWidget);
221 // QCommonStyle::drawPrimitive(theElement, theOption, thePainter, theWidget);
226 //********************************************************************
227 //********************************************************************
228 //********************************************************************
229 XGUI_ActiveDocLbl::XGUI_ActiveDocLbl(const QString& theText, QWidget* theParent )
230 : QLabel(theText, theParent),
231 myPreSelectionStyle(""),
233 mySelectionStyle(""),
238 void XGUI_ActiveDocLbl::setTreeView(QTreeView* theView)
240 myTreeView = theView;
241 setFont(myTreeView->font());
243 QPalette aPalet = myTreeView->palette();
244 QColor aHighlight = aPalet.highlight().color();
245 QColor aHighlightText = aPalet.highlightedText().color();
247 myPreSelectionStyle = "QLabel {background-color: ";
248 myPreSelectionStyle += aHighlight.lighter(170).name() + "}";
249 //myPreSelectionStyle += "qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:1 " +
250 // aHighlight.lighter(170).name() + ");";
251 //myPreSelectionStyle += "border: 1px solid lightblue; border-radius: 2px }";
253 QString aName = aPalet.color(QPalette::Base).name();
254 myNeutralStyle = "QLabel { border: 1px solid " + aName + " }";
257 #if (!defined HAVE_SALOME) && (defined WIN32)
258 mySelectionStyle = "QLabel {background-color: ";
259 mySelectionStyle += "rgb(205, 232, 255); ";
260 //mySelectionStyle += "qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgb(236, 245, 255)";
261 //mySelectionStyle += ", stop:1 rgb(208, 229, 255));";
262 //mySelectionStyle += "border: 1px solid rgb(132, 172, 221); border-radius: 2px }";
263 mySelectionStyle += "border: 1px solid rgb(153, 209, 255) }";
265 mySelectionStyle = "QLabel {background-color: " + aHighlight.name();
266 mySelectionStyle += "; color : " + aHighlightText.name() + "}";
269 myTreeView->viewport()->installEventFilter(this);
273 #if (!defined HAVE_SALOME) && (defined WIN32)
274 bool XGUI_ActiveDocLbl::event(QEvent* theEvent)
276 switch (theEvent->type()) {
279 setStyleSheet(myPreSelectionStyle);
283 setStyleSheet(myNeutralStyle);
286 return QLabel::event(theEvent);
290 bool XGUI_ActiveDocLbl::eventFilter(QObject* theObj, QEvent* theEvent)
292 if (theObj == myTreeView->viewport()) {
293 if (theEvent->type() == QEvent::MouseButtonRelease)
296 return QLabel::eventFilter(theObj, theEvent);
299 static bool MYClearing = false;
300 void XGUI_ActiveDocLbl::mouseReleaseEvent( QMouseEvent* e)
304 setStyleSheet(mySelectionStyle);
305 // We can not block signals because on
306 // clear selection the View state will not be updated
307 myTreeView->clearSelection();
308 QLabel::mouseReleaseEvent(e);
312 void XGUI_ActiveDocLbl::unselect()
315 myIsSelected = false;
316 setStyleSheet(myNeutralStyle);
321 //********************************************************************
322 //********************************************************************
323 //********************************************************************
324 XGUI_ObjectsBrowser::XGUI_ObjectsBrowser(QWidget* theParent)
325 : QWidget(theParent), myDocModel(0)
327 QVBoxLayout* aLayout = new QVBoxLayout(this);
328 ModuleBase_Tools::zeroMargins(aLayout);
329 aLayout->setSpacing(0);
331 QWidget* aLabelWgt = new QWidget(this);
332 aLabelWgt->setAutoFillBackground(true);
334 aLayout->addWidget(aLabelWgt);
335 QHBoxLayout* aLabelLay = new QHBoxLayout(aLabelWgt);
336 ModuleBase_Tools::zeroMargins(aLabelLay);
337 aLabelLay->setSpacing(0);
339 QLabel* aLbl = new QLabel(aLabelWgt);
340 aLbl->setPixmap(QPixmap(":pictures/assembly.png"));
342 // Do not paint background of the label (in order to show icon)
343 aLbl->setAutoFillBackground(false);
345 aLabelLay->addWidget(aLbl);
347 SessionPtr aMgr = ModelAPI_Session::get();
348 DocumentPtr aDoc = aMgr->moduleDocument();
350 myActiveDocLbl = new XGUI_ActiveDocLbl(tr("Part set"), aLabelWgt);
351 // myActiveDocLbl->setReadOnly(true);
352 // myActiveDocLbl->setFrame(false);
353 myActiveDocLbl->setContextMenuPolicy(Qt::CustomContextMenu);
355 aLabelLay->addWidget(myActiveDocLbl);
356 aLabelLay->setStretch(1, 1);
358 myTreeView = new XGUI_DataTree(this);
359 myTreeView->setFrameShape(QFrame::NoFrame);
360 aLayout->addWidget(myTreeView);
362 QPalette aTreePalet = myTreeView->palette();
363 QColor aTreeBack = aTreePalet.color(QPalette::Base);
366 aPalet.setColor(QPalette::Base, aTreeBack);
367 aPalet.setColor(QPalette::Window, aTreeBack);
368 aLabelWgt->setPalette(aPalet);
370 myDocModel = new XGUI_DataModel(this);
371 connect(myDocModel, SIGNAL(modelAboutToBeReset()), SLOT(onBeforeReset()));
372 connect(myDocModel, SIGNAL(treeRebuilt()), SLOT(onAfterModelReset()));
374 connect(myTreeView, SIGNAL(contextMenuRequested(QContextMenuEvent*)), this,
375 SLOT(onContextMenuRequested(QContextMenuEvent*)));
378 //***************************************************
379 XGUI_ObjectsBrowser::~XGUI_ObjectsBrowser()
383 void XGUI_ObjectsBrowser::setXMLReader(Config_DataModelReader* theReader)
385 myDocModel->setXMLReader(theReader);
386 myTreeView->setModel(myDocModel);
388 // It has to be done after setting of model
389 myActiveDocLbl->setTreeView(myTreeView);
391 QItemSelectionModel* aSelMod = myTreeView->selectionModel();
392 connect(aSelMod, SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
393 this, SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&)));
396 //***************************************************
397 void XGUI_ObjectsBrowser::onContextMenuRequested(QContextMenuEvent* theEvent)
399 QModelIndexList aIndexes;
400 QObjectPtrList aSelectedData = selectedObjects(&aIndexes);
401 bool toEnable = false;
403 if (aSelectedData.size() == 1) {
404 QModelIndex aSelected = myTreeView->indexAt(theEvent->pos());
405 if (!aIndexes.contains(aSelected))
406 return; // menu is called on non selected item
408 Qt::ItemFlags aFlags = dataModel()->flags(aIndexes.first());
409 toEnable = ((aFlags & Qt::ItemIsEditable) != 0);
411 foreach(QAction* aCmd, actions()) {
412 aCmd->setEnabled(toEnable);
414 emit contextMenuRequested(theEvent);
417 //***************************************************
418 void XGUI_ObjectsBrowser::onLabelContextMenuRequested(const QPoint& thePnt)
420 myTreeView->selectionModel()->clearSelection();
421 //Empty feature pointer means that selected root document
422 foreach(QAction* aCmd, actions()) {
423 aCmd->setEnabled(true);
425 QContextMenuEvent aEvent(QContextMenuEvent::Mouse, thePnt, myActiveDocLbl->mapToGlobal(thePnt));
426 emit contextMenuRequested(&aEvent);
429 //***************************************************
430 void XGUI_ObjectsBrowser::onEditItem()
432 QObjectPtrList aSelectedData = selectedObjects();
433 if (aSelectedData.size() > 0) {
434 ObjectPtr anObject = aSelectedData.first();
435 if (anObject.get()) { // Selection happens in TreeView
436 // check whether the object can be renamed. There should not be parts which are not loaded
437 std::set<FeaturePtr> aFeatures;
438 aFeatures.insert(ModelAPI_Feature::feature(anObject));
439 if (!XGUI_Tools::canRemoveOrRename((QWidget*)parent(), aFeatures))
442 // Find index which corresponds the feature
444 foreach(QModelIndex aIdx, selectedIndexes()) {
445 ObjectPtr aFea = dataModel()->object(aIdx);
446 if (dataModel()->object(aIdx)->isSame(anObject)) {
451 if (aIndex.isValid()) {
452 myTreeView->setCurrentIndex(aIndex);
453 myTreeView->edit(aIndex);
460 //***************************************************
461 QModelIndexList XGUI_ObjectsBrowser::expandedItems(const QModelIndex& theParent) const
463 QModelIndexList aIndexes;
465 for (int i = 0; i < myDocModel->rowCount(theParent); i++) {
466 aIndex = myDocModel->index(i, 0, theParent);
467 if (myDocModel->hasChildren(aIndex)) {
468 if (myTreeView->isExpanded(aIndex)) {
469 aIndexes.append(aIndex);
470 QModelIndexList aSubIndexes = expandedItems(aIndex);
471 if (!aSubIndexes.isEmpty())
472 aIndexes.append(aSubIndexes);
479 //***************************************************
480 void XGUI_ObjectsBrowser::rebuildDataTree()
482 myDocModel->rebuildDataTree();
486 //***************************************************
487 void XGUI_ObjectsBrowser::setObjectsSelected(const QObjectPtrList& theObjects)
489 QList<QModelIndex> theIndexes;
490 QItemSelectionModel* aSelectModel = myTreeView->selectionModel();
491 aSelectModel->clear();
493 foreach(ObjectPtr aFeature, theObjects)
495 QModelIndex aIndex = myDocModel->objectIndex(aFeature);
496 if (aIndex.isValid()) {
497 aSelectModel->select(aIndex, QItemSelectionModel::Select);
502 //***************************************************
503 void XGUI_ObjectsBrowser::clearContent()
508 void XGUI_ObjectsBrowser::onSelectionChanged(const QItemSelection& theSelected,
509 const QItemSelection& theDeselected)
511 emit selectionChanged();
514 QObjectPtrList XGUI_ObjectsBrowser::selectedObjects(QModelIndexList* theIndexes) const
516 QObjectPtrList aList;
517 QModelIndexList aIndexes = selectedIndexes();
518 XGUI_DataModel* aModel = dataModel();
519 QModelIndexList::const_iterator aIt;
520 for (aIt = aIndexes.constBegin(); aIt != aIndexes.constEnd(); ++aIt) {
521 if ((*aIt).column() == 0) {
522 ObjectPtr aObject = aModel->object(*aIt);
524 aList.append(aObject);
526 theIndexes->append(*aIt);
533 void XGUI_ObjectsBrowser::onBeforeReset()
535 myExpandedItems = expandedItems();
538 void XGUI_ObjectsBrowser::onAfterModelReset()
540 foreach(QModelIndex aIndex, myExpandedItems) {
541 myTreeView->setExpanded(aIndex, true);
545 std::list<bool> XGUI_ObjectsBrowser::getStateForDoc(DocumentPtr theDoc) const
547 std::list<bool> aStates;
548 XGUI_DataModel* aModel = dataModel();
549 QModelIndex aRootIdx = aModel->documentRootIndex(theDoc);
550 int aNbChild = aModel->rowCount(aRootIdx);
551 for (int i = 0; i < aNbChild; i++) {
552 QModelIndex aIdx = aModel->index(i, 0, aRootIdx);
553 aStates.push_back(myTreeView->isExpanded(aIdx));
558 void XGUI_ObjectsBrowser::setStateForDoc(DocumentPtr theDoc, const std::list<bool>& theStates)
560 if (theStates.size() == 0)
562 XGUI_DataModel* aModel = dataModel();
563 QModelIndex aRootIdx = aModel->documentRootIndex(theDoc);
564 int aNbChild = aModel->rowCount(aRootIdx);
566 std::list<bool>::const_iterator aIt;
568 for (aIt = theStates.cbegin(); aIt != theStates.cend(); aIt++, i++) {
571 QModelIndex aIdx = aModel->index(i, 0, aRootIdx);
572 myTreeView->setExpanded(aIdx, (*aIt));