From c23358fff93a754447d421ca606ae6f570e5c7a5 Mon Sep 17 00:00:00 2001 From: vsv Date: Fri, 16 May 2014 19:24:49 +0400 Subject: [PATCH] Issue #23: Last discussed scenario (#14) for document activation was implemented. --- src/XGUI/XGUI_ContextMenuMgr.cpp | 15 ++- src/XGUI/XGUI_DocumentDataModel.cpp | 20 +++- src/XGUI/XGUI_DocumentDataModel.h | 7 ++ src/XGUI/XGUI_ObjectsBrowser.cpp | 159 +++++++++++++++++++++++++--- src/XGUI/XGUI_ObjectsBrowser.h | 64 +++++++++-- src/XGUI/XGUI_SelectionMgr.cpp | 2 +- src/XGUI/XGUI_Workshop.cpp | 32 +++++- src/XGUI/XGUI_Workshop.h | 5 + src/XGUI/XGUI_pictures.qrc | 2 + src/XGUI/pictures/activate.png | Bin 0 -> 908 bytes src/XGUI/pictures/assembly.png | Bin 0 -> 3639 bytes 11 files changed, 272 insertions(+), 34 deletions(-) create mode 100644 src/XGUI/pictures/activate.png create mode 100644 src/XGUI/pictures/assembly.png diff --git a/src/XGUI/XGUI_ContextMenuMgr.cpp b/src/XGUI/XGUI_ContextMenuMgr.cpp index b191e7fa3..2a8fe108b 100644 --- a/src/XGUI/XGUI_ContextMenuMgr.cpp +++ b/src/XGUI/XGUI_ContextMenuMgr.cpp @@ -22,6 +22,12 @@ void XGUI_ContextMenuMgr::createActions() { QAction* aAction = new QAction(QIcon(":pictures/edit.png"), tr("Edit..."), this); addAction("EDIT_CMD", aAction); + + aAction = new QAction(QIcon(":pictures/activate.png"), tr("Activate"), this); + addAction("ACTIVATE_PART_CMD", aAction); + + aAction = new QAction(QIcon(":pictures/assembly.png"), tr("Deactivate"), this); + addAction("DEACTIVATE_PART_CMD", aAction); } void XGUI_ContextMenuMgr::addAction(const QString& theId, QAction* theAction) @@ -73,11 +79,14 @@ QMenu* XGUI_ContextMenuMgr::objectBrowserMenu() const QFeatureList aFeatures = aSelMgr->selectedFeatures(); if (aFeatures.size() == 1) { FeaturePtr aFeature = aFeatures.first(); - if (aFeature->getKind() != "Part") { - QMenu* aMenu = new QMenu(); + QMenu* aMenu = new QMenu(); + if (aFeature->getKind() == "Part") { + //TODO: Check that feature is active + aMenu->addAction(action("ACTIVATE_PART_CMD")); + } else { aMenu->addAction(action("EDIT_CMD")); - return aMenu; } + return aMenu; } return 0; } diff --git a/src/XGUI/XGUI_DocumentDataModel.cpp b/src/XGUI/XGUI_DocumentDataModel.cpp index c5b0cbd9b..2c4470cce 100644 --- a/src/XGUI/XGUI_DocumentDataModel.cpp +++ b/src/XGUI/XGUI_DocumentDataModel.cpp @@ -431,7 +431,15 @@ bool XGUI_DocumentDataModel::activatedIndex(const QModelIndex& theIndex) // if this is root node (Part item index) if (!aIndex->parent().isValid()) { if (myActivePart) myActivePart->setItemsColor(PASSIVE_COLOR); - myActivePart = (myActivePart == aModel)? 0 : (XGUI_PartModel*)aModel; + + if (myActivePart == aModel) { + myActivePart = 0; + myActivePartIndex = QModelIndex(); + } else { + myActivePart = (XGUI_PartModel*)aModel; + myActivePartIndex = theIndex; + } + if (myActivePart) { myActivePart->setItemsColor(ACTIVE_COLOR); myModel->setItemsColor(PASSIVE_COLOR); @@ -448,4 +456,12 @@ FeaturePtr XGUI_DocumentDataModel::activePart() const if (myActivePart) return myActivePart->part(); return FeaturePtr(); -} \ No newline at end of file +} + +void XGUI_DocumentDataModel::deactivatePart() +{ + if (myActivePart) + myActivePart->setItemsColor(PASSIVE_COLOR); + myActivePart = 0; + myModel->setItemsColor(ACTIVE_COLOR); +} diff --git a/src/XGUI/XGUI_DocumentDataModel.h b/src/XGUI/XGUI_DocumentDataModel.h index 68bfa4062..f6ce80eac 100644 --- a/src/XGUI/XGUI_DocumentDataModel.h +++ b/src/XGUI/XGUI_DocumentDataModel.h @@ -60,6 +60,11 @@ public: FeaturePtr activePart() const; + QModelIndex activePartIndex() const { return myActivePartIndex; } + + //! Deactivates a Part + void deactivatePart(); + private: enum {PartsFolder, HistoryNode}; @@ -104,6 +109,8 @@ private: //! Active part in part editing mode XGUI_PartModel* myActivePart; + QModelIndex myActivePartIndex; + //! List of saved QModelIndexes created by sub-models QList myIndexes; diff --git a/src/XGUI/XGUI_ObjectsBrowser.cpp b/src/XGUI/XGUI_ObjectsBrowser.cpp index 21530908e..cf0e8577d 100644 --- a/src/XGUI/XGUI_ObjectsBrowser.cpp +++ b/src/XGUI/XGUI_ObjectsBrowser.cpp @@ -1,49 +1,176 @@ #include "XGUI_ObjectsBrowser.h" #include "XGUI_DocumentDataModel.h" -XGUI_ObjectsBrowser::XGUI_ObjectsBrowser(QWidget* theParent) +#include + +#include +#include +#include +#include +#include + + + +XGUI_DataTree::XGUI_DataTree(QWidget* theParent) : QTreeView(theParent) { setHeaderHidden(true); - myDocModel = new XGUI_DocumentDataModel(this); - setModel(myDocModel); + setModel(new XGUI_DocumentDataModel(this)); connect(selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), - this, SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&))); + this, SLOT(onSelectionChanged(const QItemSelection&, const QItemSelection&))); } - -XGUI_ObjectsBrowser::~XGUI_ObjectsBrowser() +XGUI_DataTree::~XGUI_DataTree() { } +XGUI_DocumentDataModel* XGUI_DataTree::dataModel() const +{ + return static_cast(model()); +} -void XGUI_ObjectsBrowser::onSelectionChanged(const QItemSelection& theSelected, +void XGUI_DataTree::onSelectionChanged(const QItemSelection& theSelected, const QItemSelection& theDeselected) { mySelectedData.clear(); QModelIndexList aIndexes = selectionModel()->selectedIndexes(); + XGUI_DocumentDataModel* aModel = dataModel(); QModelIndexList::const_iterator aIt; for (aIt = aIndexes.constBegin(); aIt != aIndexes.constEnd(); ++aIt) { - FeaturePtr aFeature = myDocModel->feature(*aIt); + FeaturePtr aFeature = aModel->feature(*aIt); if (aFeature) mySelectedData.append(aFeature); } emit selectionChanged(); } -void XGUI_ObjectsBrowser::mouseDoubleClickEvent(QMouseEvent* theEvent) +void XGUI_DataTree::mouseDoubleClickEvent(QMouseEvent* theEvent) { - QModelIndex aIndex = currentIndex(); - bool isChanged = myDocModel->activatedIndex(aIndex); - QTreeView::mouseDoubleClickEvent(theEvent); - if (isChanged) { - emit activePartChanged(myDocModel->activePart()); - } + if (theEvent->button() == Qt::LeftButton) { + QModelIndex aIndex = currentIndex(); + XGUI_DocumentDataModel* aModel = dataModel(); + + if ((aModel->activePartIndex() != aIndex) && aModel->activePartIndex().isValid()) { + setExpanded(aModel->activePartIndex(), false); + } + bool isChanged = aModel->activatedIndex(aIndex); + QTreeView::mouseDoubleClickEvent(theEvent); + if (isChanged) { + if (aModel->activePartIndex().isValid()) + setExpanded(aIndex, true); + emit activePartChanged(aModel->activePart()); + } + } else + QTreeView::mouseDoubleClickEvent(theEvent); } -void XGUI_ObjectsBrowser::contextMenuEvent(QContextMenuEvent* theEvent) +void XGUI_DataTree::contextMenuEvent(QContextMenuEvent* theEvent) { emit contextMenuRequested(theEvent); +} + +//******************************************************************** +//******************************************************************** +//******************************************************************** +XGUI_ObjectsBrowser::XGUI_ObjectsBrowser(QWidget* theParent) + : QWidget(theParent) +{ + QVBoxLayout* aLayout = new QVBoxLayout(this); + aLayout->setContentsMargins(0, 0, 0, 0); + aLayout->setSpacing(0); + + QWidget* aLabelWgt = new QWidget(this); + aLayout->addWidget(aLabelWgt); + QHBoxLayout* aLabelLay = new QHBoxLayout(aLabelWgt); + aLabelLay->setContentsMargins(3, 3, 3, 3); + + QLabel* aLbl = new QLabel(aLabelWgt); + aLbl->setPixmap(QPixmap(":pictures/assembly.png")); + aLabelLay->addWidget(aLbl); + + myActiveDocLbl = new QLabel("", aLabelWgt); + myActiveDocLbl->setAlignment(Qt::AlignHCenter); + + QFont aFnt = myActiveDocLbl->font(); + aFnt.setBold(true); + myActiveDocLbl->setFont(aFnt); + + myActiveDocLbl->installEventFilter(this); + + aLabelLay->addWidget(myActiveDocLbl); + aLabelLay->setStretch(1,1); + + myTreeView = new XGUI_DataTree(this); + aLayout->addWidget(myTreeView); + + myDocModel = myTreeView->dataModel(); + + connect(myTreeView, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged())); + connect(myTreeView, SIGNAL(activePartChanged(FeaturePtr)), this, SLOT(onActivePartChanged(FeaturePtr))); + connect(myTreeView, SIGNAL(activePartChanged(FeaturePtr)), this, SIGNAL(activePartChanged(FeaturePtr))); + connect(myTreeView, SIGNAL(contextMenuRequested(QContextMenuEvent*)), + this, SIGNAL(contextMenuRequested(QContextMenuEvent*))); + + onActivePartChanged(FeaturePtr()); +} + + +XGUI_ObjectsBrowser::~XGUI_ObjectsBrowser() +{ +} + + +void XGUI_ObjectsBrowser::onActivePartChanged(FeaturePtr thePart) +{ + QPalette aPalet = myActiveDocLbl->palette(); + if (thePart) { + myActiveDocLbl->setText(tr("Activate Part set")); + aPalet.setColor(QPalette::Foreground, Qt::black); + myActiveDocLbl->setCursor(Qt::PointingHandCursor); + } else { + myActiveDocLbl->setText(tr("Part set is active")); + aPalet.setColor(QPalette::Foreground, QColor(0, 72, 140)); + myActiveDocLbl->unsetCursor(); + } + myActiveDocLbl->setPalette(aPalet); +} + +bool XGUI_ObjectsBrowser::eventFilter(QObject* obj, QEvent* theEvent) +{ + if (obj == myActiveDocLbl) { + if (theEvent->type() == QEvent::MouseButtonDblClick) { + if (myDocModel->activePartIndex().isValid()) { + myTreeView->setExpanded(myDocModel->activePartIndex(), false); + } + myDocModel->deactivatePart(); + onActivePartChanged(FeaturePtr()); + emit activePartChanged(FeaturePtr()); + } + } + return QWidget::eventFilter(obj, theEvent); +} + +void XGUI_ObjectsBrowser::activateCurrentPart(bool toActivate) +{ + if (toActivate) { + QModelIndex aIndex = myTreeView->currentIndex(); + + if ((myDocModel->activePartIndex() != aIndex) && myDocModel->activePartIndex().isValid()) { + myTreeView->setExpanded(myDocModel->activePartIndex(), false); + } + bool isChanged = myDocModel->activatedIndex(aIndex); + if ((isChanged) && (myDocModel->activePartIndex().isValid())) { + myTreeView->setExpanded(aIndex, true); + onActivePartChanged(myDocModel->feature(aIndex)); + } + } else { + QModelIndex aIndex = myDocModel->activePartIndex(); + if (aIndex.isValid()) { + myDocModel->activatedIndex(aIndex); + myTreeView->setExpanded(aIndex, false); + onActivePartChanged(FeaturePtr()); + } + } } \ No newline at end of file diff --git a/src/XGUI/XGUI_ObjectsBrowser.h b/src/XGUI/XGUI_ObjectsBrowser.h index fd1adbed8..18c03d2cc 100644 --- a/src/XGUI/XGUI_ObjectsBrowser.h +++ b/src/XGUI/XGUI_ObjectsBrowser.h @@ -5,15 +5,52 @@ #include "XGUI.h" #include "XGUI_Constants.h" +#include #include class XGUI_DocumentDataModel; +class QLabel; + + +class XGUI_DataTree: public QTreeView +{ + Q_OBJECT +public: + XGUI_DataTree(QWidget* theParent); + virtual ~XGUI_DataTree(); + + //! Returns list of currently selected features + QFeatureList selectedFeatures() const { return mySelectedData; } + + XGUI_DocumentDataModel* dataModel() const; + +signals: + //! Emited when selection is changed + void selectionChanged(); + void activePartChanged(FeaturePtr thePart); + + //! Emited on context menu request + void contextMenuRequested(QContextMenuEvent* theEvent); + +protected: + virtual void mouseDoubleClickEvent(QMouseEvent* theEvent); + virtual void contextMenuEvent(QContextMenuEvent* theEvent); + +private slots: + //! Called when selection in Data Tree is changed + void onSelectionChanged(const QItemSelection& theSelected, const QItemSelection& theDeselected); + +private: + //! List of currently selected data + QFeatureList mySelectedData; +}; + /**\class XGUI_ObjectsBrowser * \ingroup GUI * \brief Object browser window object. Represents data tree of current data structure */ - class XGUI_EXPORT XGUI_ObjectsBrowser : public QTreeView + class XGUI_EXPORT XGUI_ObjectsBrowser : public QWidget { Q_OBJECT public: @@ -24,32 +61,39 @@ public: XGUI_DocumentDataModel* dataModel() const { return myDocModel; } //! Returns list of currently selected features - QFeatureList selectedFeatures() const { return mySelectedData; } + QFeatureList selectedFeatures() const { return myTreeView->selectedFeatures(); } + + //! Returns currently selected indexes + QModelIndexList selectedIndexes() const { return myTreeView->selectionModel()->selectedIndexes(); } + + //! Returns TreeView widget + XGUI_DataTree* treeView() const { return myTreeView; } + + //! Activates currently selected part. Signal activePartChanged will not be sent + void activateCurrentPart(bool toActivate); signals: //! Emited when selection is changed void selectionChanged(); + + //! Emited when current active document is changed void activePartChanged(FeaturePtr thePart); //! Emited on context menu request void contextMenuRequested(QContextMenuEvent* theEvent); protected: - virtual void mouseDoubleClickEvent(QMouseEvent* theEvent); - virtual void contextMenuEvent(QContextMenuEvent* theEvent); + virtual bool eventFilter(QObject* obj, QEvent* theEvent); private slots: - //! Called when selection in Data Tree is changed - void onSelectionChanged(const QItemSelection& theSelected, const QItemSelection& theDeselected); + void onActivePartChanged(FeaturePtr thePart); private: //! Internal model XGUI_DocumentDataModel* myDocModel; - //! List of currently selected data - QFeatureList mySelectedData; - - //QModelIndex myActivePartIndex; + QLabel* myActiveDocLbl; + XGUI_DataTree* myTreeView; }; #endif \ No newline at end of file diff --git a/src/XGUI/XGUI_SelectionMgr.cpp b/src/XGUI/XGUI_SelectionMgr.cpp index 8365772e7..f949c782a 100644 --- a/src/XGUI/XGUI_SelectionMgr.cpp +++ b/src/XGUI/XGUI_SelectionMgr.cpp @@ -63,7 +63,7 @@ QFeatureList XGUI_SelectionMgr::selectedFeatures() const //************************************************************** QModelIndexList XGUI_SelectionMgr::selectedIndexes() const { - return myWorkshop->objectBrowser()->selectionModel()->selectedIndexes(); + return myWorkshop->objectBrowser()->selectedIndexes(); } //************************************************************** diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index 9b391a44e..a935975d2 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -85,6 +85,8 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) myActionsMgr = new XGUI_ActionsMgr(this); myErrorDlg = new XGUI_ErrorDialog(myMainWindow); myContextMenuMgr = new XGUI_ContextMenuMgr(this); + connect(myContextMenuMgr, SIGNAL(actionTriggered(const QString&, bool)), + this, SLOT(onContextMenuCommand(const QString&, bool))); myViewerProxy = new XGUI_ViewerProxy(this); @@ -470,7 +472,7 @@ void XGUI_Workshop::onSaveAs() //****************************************************** void XGUI_Workshop::onUndo() { - objectBrowser()->setCurrentIndex(QModelIndex()); + objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); boost::shared_ptr aMgr = ModelAPI_PluginManager::get(); boost::shared_ptr aDoc = aMgr->rootDocument(); if (aDoc->isOperation()) @@ -482,7 +484,7 @@ void XGUI_Workshop::onUndo() //****************************************************** void XGUI_Workshop::onRedo() { - objectBrowser()->setCurrentIndex(QModelIndex()); + objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); boost::shared_ptr aMgr = ModelAPI_PluginManager::get(); boost::shared_ptr aDoc = aMgr->rootDocument(); aDoc->redo(); @@ -698,3 +700,29 @@ XGUI_SalomeViewer* XGUI_Workshop::salomeViewer() const { return mySalomeConnector->viewer(); } + +//************************************************************** +void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) +{ + if (theId == "ACTIVATE_PART_CMD") + activatePart(true); + else if (theId == "DEACTIVATE_PART_CMD") + activatePart(false); + +} + +//************************************************************** +void XGUI_Workshop::activatePart(bool toActivate) +{ + if (toActivate) { + QFeatureList aFeatures = mySelector->selectedFeatures(); + if (aFeatures.size() > 0) { + changeCurrentDocument(aFeatures.first()); + myObjectBrowser->activateCurrentPart(true); + } + } else { + changeCurrentDocument(FeaturePtr()); + myObjectBrowser->activateCurrentPart(false); + } +} + diff --git a/src/XGUI/XGUI_Workshop.h b/src/XGUI/XGUI_Workshop.h index f0121474b..cd77d3b13 100644 --- a/src/XGUI/XGUI_Workshop.h +++ b/src/XGUI/XGUI_Workshop.h @@ -139,6 +139,8 @@ protected slots: /// \param theOpertion a stopped operation void onOperationStopped(ModuleBase_Operation* theOperation); + void onContextMenuCommand(const QString& theId, bool isChecked); + private: void initMenu(); @@ -151,6 +153,9 @@ private: // Creates Dock widgets: Object browser and Property panel void createDockWidgets(); + //! Activates or deactivates currently selected part + void activatePart(bool toActivate); + QString myCurrentFile; XGUI_MainWindow* myMainWindow; XGUI_Module* myPartSetModule; diff --git a/src/XGUI/XGUI_pictures.qrc b/src/XGUI/XGUI_pictures.qrc index 893d8d7b6..30d9ba286 100644 --- a/src/XGUI/XGUI_pictures.qrc +++ b/src/XGUI/XGUI_pictures.qrc @@ -52,5 +52,7 @@ pictures/tile_views.png pictures/new_view.png pictures/edit.png + pictures/assembly.png + pictures/activate.png diff --git a/src/XGUI/pictures/activate.png b/src/XGUI/pictures/activate.png new file mode 100644 index 0000000000000000000000000000000000000000..f82917927bcb5c36b85115d7da7dc3630e088ff7 GIT binary patch literal 908 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 JPDHLkV1iSH(2@WE literal 0 HcmV?d00001 -- 2.39.2