X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FXGUI%2FXGUI_Workshop.cpp;h=52212d11bff20202126610c9e6f0ffc706be39e7;hb=c3ae28ba30027cc4a6a757ef623f40adaae96ead;hp=e56e696f5d2b79aef5f5c3937986be1bc3716b9d;hpb=b6ec94fb365b2e63057f78ae0e63fe9a72ecb829;p=modules%2Fshaper.git diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp old mode 100644 new mode 100755 index e56e696f5..52212d11b --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -1,48 +1,52 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> //#include "XGUI_Constants.h" -#include "XGUI_Tools.h" #include "XGUI_Workshop.h" -#include "XGUI_SelectionMgr.h" -#include "XGUI_Selection.h" -#include "XGUI_ObjectsBrowser.h" -#include "XGUI_Displayer.h" -#include "XGUI_OperationMgr.h" -#include "XGUI_SalomeConnector.h" + #include "XGUI_ActionsMgr.h" -#include "XGUI_ErrorDialog.h" #include "XGUI_ColorDialog.h" -#include "XGUI_ViewerProxy.h" -#include "XGUI_PropertyPanel.h" #include "XGUI_ContextMenuMgr.h" +#include "XGUI_Displayer.h" +#include "XGUI_ErrorDialog.h" +#include "XGUI_ErrorMgr.h" #include "XGUI_ModuleConnector.h" -#include -#include +#include "XGUI_ObjectsBrowser.h" +#include "XGUI_OperationMgr.h" +#include "XGUI_PropertyPanel.h" +#include "XGUI_SalomeConnector.h" +#include "XGUI_Selection.h" +#include "XGUI_SelectionMgr.h" +#include "XGUI_Tools.h" +#include "XGUI_ViewerProxy.h" +#include "XGUI_WorkshopListener.h" #include +#include +#include -#include -#include +#ifndef HAVE_SALOME +#include #include #include #include #include -#include - -#include -#include +#include +#include +#endif +#include +#include +#include #include -#include #include -#include -#include #include -#include -#include -#include #include -#include +#include +#include #include +#include +#include +#include +#include //#include @@ -50,28 +54,33 @@ #include #include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include #include +#include +#include #include +#include +#include +#include #include #include -#include #include +#include #include #include +#include + #include #include #include #include +#include #include #include #include @@ -80,6 +89,9 @@ #include #include #include +#include + +#include #ifdef _DEBUG #include @@ -92,8 +104,6 @@ #include #endif -//#define DEBUG_FEATURE_CREATED -//#define DEBUG_FEATURE_REDISPLAY //#define DEBUG_DELETE XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) @@ -103,21 +113,27 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) mySalomeConnector(theConnector), myPropertyPanel(0), myObjectBrowser(0), - myDisplayer(0), - myUpdatePrefs(false), - myPartActivating(false), - myIsLoadingData(false) + myDisplayer(0) { - myMainWindow = mySalomeConnector ? 0 : new AppElements_MainWindow(); +#ifndef HAVE_SALOME + myMainWindow = new AppElements_MainWindow(); + + SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr(); + bool aCloc = aResMgr->booleanValue("language", "locale", true); + if (aCloc) + QLocale::setDefault( QLocale::c() ); + else + QLocale::setDefault( QLocale::system() ); +#endif myDisplayer = new XGUI_Displayer(this); mySelector = new XGUI_SelectionMgr(this); //connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateModuleCommands())); - myOperationMgr = new XGUI_OperationMgr(this); + myOperationMgr = new XGUI_OperationMgr(this, 0); myActionsMgr = new XGUI_ActionsMgr(this); - myErrorDlg = new XGUI_ErrorDialog(myMainWindow); + myErrorDlg = new XGUI_ErrorDialog(QApplication::desktop()); myContextMenuMgr = new XGUI_ContextMenuMgr(this); connect(myContextMenuMgr, SIGNAL(actionTriggered(const QString&, bool)), this, SLOT(onContextMenuCommand(const QString&, bool))); @@ -128,6 +144,12 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) myModuleConnector = new XGUI_ModuleConnector(this); + ModuleBase_IWorkshop* aWorkshop = moduleConnector(); + myOperationMgr->setWorkshop(aWorkshop); + + myErrorMgr = new XGUI_ErrorMgr(this, aWorkshop); + myEventsListener = new XGUI_WorkshopListener(aWorkshop); + connect(myOperationMgr, SIGNAL(operationStarted(ModuleBase_Operation*)), SLOT(onOperationStarted(ModuleBase_Operation*))); connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)), @@ -138,8 +160,28 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) SLOT(onOperationCommitted(ModuleBase_Operation*))); connect(myOperationMgr, SIGNAL(operationAborted(ModuleBase_Operation*)), SLOT(onOperationAborted(ModuleBase_Operation*))); + //connect(myOperationMgr, SIGNAL(validationStateChanged(bool)), + // myErrorMgr, SLOT(onValidationStateChanged())); + +#ifndef HAVE_SALOME connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit())); +#endif + connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&))); + connect(myEventsListener, SIGNAL(errorOccurred(const QString&)), + myErrorDlg, SLOT(addError(const QString&))); + + //Config_PropManager::registerProp("Visualization", "object_default_color", "Object color", + // Config_Prop::Color, "225,225,225"); + + Config_PropManager::registerProp("Visualization", "result_body_color", "Body color", + Config_Prop::Color, ModelAPI_ResultBody::DEFAULT_COLOR()); + Config_PropManager::registerProp("Visualization", "result_group_color", "Group color", + Config_Prop::Color, ModelAPI_ResultGroup::DEFAULT_COLOR()); + Config_PropManager::registerProp("Visualization", "result_construction_color", "Construction color", + Config_Prop::Color, ModelAPI_ResultConstruction::DEFAULT_COLOR()); + Config_PropManager::registerProp("Visualization", "result_part_color", "Part color", + Config_Prop::Color, ModelAPI_ResultPart::DEFAULT_COLOR()); } //****************************************************** @@ -157,82 +199,113 @@ void XGUI_Workshop::startApplication() Config_Prop::Directory, ""); //Initialize event listening - Events_Loop* aLoop = Events_Loop::loop(); - aLoop->registerListener(this, Events_Error::errorID()); //!< Listening application errors. - aLoop->registerListener(this, Events_Loop::eventByName(Config_FeatureMessage::GUI_EVENT())); - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OPERATION_LAUNCHED)); - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); - aLoop->registerListener(this, Events_LongOp::eventID()); - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_PLUGIN_LOADED)); - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_SELFILTER_LOADED)); - - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_UPDATE_VIEWER_BLOCKED)); - aLoop->registerListener(this, Events_Loop::eventByName(EVENT_UPDATE_VIEWER_UNBLOCKED)); + myEventsListener->initializeEventListening(); registerValidators(); // Calling of loadCustomProps before activating module is required // by Config_PropManger to restore user-defined path to plugins ModuleBase_Preferences::loadCustomProps(); - activateModule(); - if (myMainWindow) { - myMainWindow->show(); - updateCommandStatus(); - } + createModule(); + +#ifndef HAVE_SALOME + myMainWindow->show(); + updateCommandStatus(); +#endif onNew(); emit applicationStarted(); } +void XGUI_Workshop::activateModule() +{ + myModule->activateSelectionFilters(); + + connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)), + myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr))); + connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)), + myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr))); + + myActionsMgr->update(); + + // activate visualized objects in the viewer + XGUI_Displayer* aDisplayer = displayer(); + QObjectPtrList aDisplayed = aDisplayer->displayedObjects(); + QIntList aModes; + module()->activeSelectionModes(aModes); + aDisplayer->activateObjects(aModes, aDisplayed); +} + +void XGUI_Workshop::deactivateModule() +{ + myModule->deactivateSelectionFilters(); + + // remove internal displayer filter + displayer()->deactivateSelectionFilters(); + + disconnect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)), + myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr))); + disconnect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)), + myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr))); + + XGUI_Displayer* aDisplayer = displayer(); + QObjectPtrList aDisplayed = aDisplayer->displayedObjects(); + aDisplayer->deactivateObjects(aDisplayed, true); +} + //****************************************************** void XGUI_Workshop::initMenu() { myContextMenuMgr->createActions(); - if (isSalomeMode()) { - // Create only Undo, Redo commands - QAction* aAction = salomeConnector()->addDesktopCommand("UNDO_CMD", tr("Undo"), - tr("Undo last command"), - QIcon(":pictures/undo.png"), - QKeySequence::Undo, false, "MEN_DESK_EDIT"); - connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onUndo())); - addHistoryMenu(aAction, SIGNAL(updateUndoHistory(const QList&)), SLOT(onUndo(int))); - - aAction = salomeConnector()->addDesktopCommand("REDO_CMD", tr("Redo"), tr("Redo last command"), - QIcon(":pictures/redo.png"), QKeySequence::Redo, - false, "MEN_DESK_EDIT"); - connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRedo())); - addHistoryMenu(aAction, SIGNAL(updateRedoHistory(const QList&)), SLOT(onRedo(int))); - - salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); - aAction = salomeConnector()->addDesktopCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"), - QIcon(":pictures/rebuild.png"), QKeySequence(), - false, "MEN_DESK_EDIT"); - connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild())); - salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); - - aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export NewGeom..."), tr("Export the current document into a NewGeom file"), - QIcon(), QKeySequence(), - false, "MEN_DESK_FILE"); - connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs())); - - aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import NewGeom..."), tr("Import a NewGeom file"), - QIcon(), QKeySequence(), - false, "MEN_DESK_FILE"); - connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen())); - salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE"); +#ifdef HAVE_SALOME + // Create only Undo, Redo commands + QAction* aAction = salomeConnector()->addDesktopCommand("UNDO_CMD", tr("Undo"), + tr("Undo last command"), + QIcon(":pictures/undo.png"), + QKeySequence::Undo, false, "MEN_DESK_EDIT"); + QString aToolBarTitle = tr( "INF_DESK_TOOLBAR_STANDARD" ); + salomeConnector()->addActionInToolbar( aAction,aToolBarTitle ); + + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onUndo())); + addHistoryMenu(aAction, SIGNAL(updateUndoHistory(const QList&)), SLOT(onUndo(int))); + + aAction = salomeConnector()->addDesktopCommand("REDO_CMD", tr("Redo"), tr("Redo last command"), + QIcon(":pictures/redo.png"), QKeySequence::Redo, + false, "MEN_DESK_EDIT"); + salomeConnector()->addActionInToolbar( aAction, aToolBarTitle ); + + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRedo())); + addHistoryMenu(aAction, SIGNAL(updateRedoHistory(const QList&)), SLOT(onRedo(int))); + + salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); + aAction = salomeConnector()->addDesktopCommand("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"), + QIcon(":pictures/rebuild.png"), QKeySequence(), + false, "MEN_DESK_EDIT"); + salomeConnector()->addActionInToolbar( aAction, aToolBarTitle ); + + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild())); + salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); + + aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export NewGeom..."), tr("Export the current document into a NewGeom file"), + QIcon(), QKeySequence(), + false, "MEN_DESK_FILE"); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs())); + + aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import NewGeom..."), tr("Import a NewGeom file"), + QIcon(), QKeySequence(), + false, "MEN_DESK_FILE"); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen())); + salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE"); - return; - } +#else // File commands group AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage(); AppElements_Command* aCommand; - aCommand = aGroup->addFeature("SAVE_CMD", tr("Save..."), tr("Save the document"), + aCommand = aGroup->addFeature("SAVE_CMD", tr("Save"), tr("Save the document"), QIcon(":pictures/save.png"), QKeySequence::Save); aCommand->connectTo(this, SLOT(onSave())); //aCommand->disable(); @@ -268,10 +341,6 @@ void XGUI_Workshop::initMenu() QIcon(":pictures/open.png"), QKeySequence::Open); aCommand->connectTo(this, SLOT(onOpen())); - //aCommand = aGroup->addFeature("NEW_CMD", tr("New"), tr("Create a new document"), - // QIcon(":pictures/new.png"), QKeySequence::New); - //aCommand->connectTo(this, SLOT(onNew())); - aCommand = aGroup->addFeature("PREF_CMD", tr("Preferences"), tr("Edit preferences"), QIcon(":pictures/preferences.png"), QKeySequence::Preferences); aCommand->connectTo(this, SLOT(onPreferences())); @@ -279,125 +348,25 @@ void XGUI_Workshop::initMenu() aCommand = aGroup->addFeature("EXIT_CMD", tr("Exit"), tr("Exit application"), QIcon(":pictures/close.png"), QKeySequence::Close); aCommand->connectTo(this, SLOT(onExit())); - //FIXME: SBH's test action. Can be used for some GUI tests. -// #ifdef _DEBUG -// aCommand = aGroup->addFeature("TEST_CMD", "Test!", "Private debug button", -// QIcon(":pictures/close.png"), QKeySequence(), true); -// aCommand->connectTo(myMainWindow, SLOT(dockPythonConsole())); -// #endif +#endif } -//****************************************************** +#ifndef HAVE_SALOME AppElements_Workbench* XGUI_Workshop::addWorkbench(const QString& theName) { AppElements_MainMenu* aMenuBar = myMainWindow->menuObject(); return aMenuBar->addWorkbench(theName); } - -//****************************************************** -void XGUI_Workshop::processEvent(const std::shared_ptr& theMessage) -{ - if (QApplication::instance()->thread() != QThread::currentThread()) { - #ifdef _DEBUG - std::cout << "XGUI_Workshop::processEvent: " << "Working in another thread." << std::endl; - #endif - SessionPtr aMgr = ModelAPI_Session::get(); - PostponeMessageQtEvent* aPostponeEvent = new PostponeMessageQtEvent(theMessage); - QApplication::postEvent(this, aPostponeEvent); - return; - } - - //A message to start feature creation received. - if (theMessage->eventID() == Events_Loop::loop()->eventByName(Config_FeatureMessage::GUI_EVENT())) { - std::shared_ptr aFeatureMsg = - std::dynamic_pointer_cast(theMessage); - if (!aFeatureMsg->isInternal()) { - addFeature(aFeatureMsg); - } - } - // Process creation of Part - else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) { - std::shared_ptr aUpdMsg = - std::dynamic_pointer_cast(theMessage); - onFeatureCreatedMsg(aUpdMsg); - if (myUpdatePrefs) { - if (mySalomeConnector) - mySalomeConnector->createPreferences(); - myUpdatePrefs = false; - } - } - else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_PLUGIN_LOADED)) { - myUpdatePrefs = true; - } - // Redisplay feature - else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY)) { - std::shared_ptr aUpdMsg = - std::dynamic_pointer_cast(theMessage); - onFeatureRedisplayMsg(aUpdMsg); - } - //Update property panel on corresponding message. If there is no current operation (no - //property panel), or received message has different feature to the current - do nothing. - else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)) { - std::shared_ptr anUpdateMsg = - std::dynamic_pointer_cast(theMessage); - onFeatureUpdatedMsg(anUpdateMsg); - } else if (theMessage->eventID() == Events_LongOp::eventID()) { - if (Events_LongOp::isPerformed()) { - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - } else { - QApplication::restoreOverrideCursor(); - } - } - //An operation passed by message. Start it, process and commit. - else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OPERATION_LAUNCHED)) { - std::shared_ptr aPartSetMsg = - std::dynamic_pointer_cast(theMessage); - //myPropertyPanel->cleanContent(); - ModuleBase_Operation* anOperation = (ModuleBase_Operation*) aPartSetMsg->pointer(); - - if (myOperationMgr->startOperation(anOperation)) { - myPropertyPanel->updateContentWidget(anOperation->feature()); - if (!anOperation->getDescription()->hasXmlRepresentation()) { - if (anOperation->commit()) - updateCommandStatus(); - } - } - } - else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_SELFILTER_LOADED)) { - std::shared_ptr aMsg = - std::dynamic_pointer_cast(theMessage); - if (aMsg) { - ModuleBase_FilterFactory* aFactory = moduleConnector()->selectionFilters(); - if (!aMsg->attributeId().empty()) { - aFactory->assignFilter(aMsg->selectionFilterId(), aMsg->featureId(), aMsg->attributeId(), - aMsg->parameters()); - } - } - } else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_UPDATE_VIEWER_BLOCKED)) { - // the viewer's update context will not happens until viewer updated is emitted - myDisplayer->enableUpdateViewer(false); - } else if (theMessage->eventID() == Events_Loop::eventByName(EVENT_UPDATE_VIEWER_UNBLOCKED)) { - // the viewer's update context is unblocked, the viewer's update works - myDisplayer->enableUpdateViewer(true); - } else { - //Show error dialog if error message received. - std::shared_ptr anAppError = std::dynamic_pointer_cast(theMessage); - if (anAppError) { - emit errorOccurred(QString::fromLatin1(anAppError->description())); - } - return; - } - if (!isSalomeMode()) { - SessionPtr aMgr = ModelAPI_Session::get(); - if (aMgr->isModified() != myMainWindow->isModifiedState()) - myMainWindow->setModifiedState(aMgr->isModified()); - } -} +#endif //****************************************************** QMainWindow* XGUI_Workshop::desktop() const { - return isSalomeMode() ? salomeConnector()->desktop() : myMainWindow; +#ifdef HAVE_SALOME + return salomeConnector()->desktop(); +#else + return myMainWindow; +#endif } //****************************************************** @@ -409,158 +378,113 @@ void XGUI_Workshop::onStartWaiting() } //****************************************************** -void XGUI_Workshop::onFeatureUpdatedMsg(const std::shared_ptr& theMsg) -{ - std::set aFeatures = theMsg->objects(); - if (myOperationMgr->hasOperation()) { - FeaturePtr aCurrentFeature = myOperationMgr->currentOperation()->feature(); - std::set::const_iterator aIt; - for (aIt = aFeatures.begin(); aIt != aFeatures.end(); ++aIt) { - ObjectPtr aNewFeature = (*aIt); - if (aNewFeature == aCurrentFeature) { - myPropertyPanel->updateContentWidget(aCurrentFeature); - break; - } +void XGUI_Workshop::onAcceptActionClicked() +{ + QAction* anAction = dynamic_cast(sender()); + XGUI_OperationMgr* anOperationMgr = operationMgr(); + if (anOperationMgr) { + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (anOperationMgr->currentOperation()); + if (aFOperation) { + if (errorMgr()->canProcessClick(anAction, aFOperation->feature())) + myOperationMgr->onCommitOperation(); } } - myOperationMgr->onValidateOperation(); - //if (myObjectBrowser) - // myObjectBrowser->processEvent(theMsg); } //****************************************************** -void XGUI_Workshop::onFeatureRedisplayMsg(const std::shared_ptr& theMsg) +/*void XGUI_Workshop::onValidationStateChanged(bool theEnabled) { - std::set aObjects = theMsg->objects(); - std::set::const_iterator aIt; - -#ifdef DEBUG_FEATURE_REDISPLAY - QStringList anInfo; - for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) { - anInfo.append(ModuleBase_Tools::objectInfo((*aIt))); + XGUI_OperationMgr* anOperationMgr = operationMgr(); + if (anOperationMgr) { + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (anOperationMgr->currentOperation()); + if (aFOperation) { + QAction* anAction = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept); + myErrorMgr->updateActionState(anAction, aFOperation->feature(), theEnabled); + } } - QString anInfoStr = anInfo.join(", "); - qDebug(QString("onFeatureRedisplayMsg: %1, %2").arg(aObjects.size()).arg(anInfoStr).toStdString().c_str()); -#endif +}*/ - for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) { - ObjectPtr aObj = (*aIt); - // Hide the object if it is invalid or concealed one - bool aHide = !aObj->data() || !aObj->data()->isValid() || - aObj->isDisabled() || (!aObj->isDisplayed()); - if (!aHide) { // check that this is not hidden result - ResultPtr aRes = std::dynamic_pointer_cast(aObj); - aHide = aRes && aRes->isConcealed(); - } - if (aHide) - myDisplayer->erase(aObj, false); - else { - // Redisplay the visible object or the object of the current operation - bool isVisibleObject = myDisplayer->isVisible(aObj); - #ifdef DEBUG_FEATURE_REDISPLAY - //QString anObjInfo = ModuleBase_Tools::objectInfo((aObj)); - //qDebug(QString("visible=%1 : display= %2").arg(isVisibleObject).arg(anObjInfo).toStdString().c_str()); - #endif - - if (isVisibleObject) { // redisplay visible object - //displayObject(aObj); // In order to update presentation - // in order to avoid the check whether the object can be redisplayed, the exact method - // of redisplay is called. This modification is made in order to have the line is updated - // by creation of a horizontal constraint on the line by preselection - myDisplayer->redisplay(aObj, false); - //if (myOperationMgr->hasOperation()) { - // ModuleBase_Operation* aOperation = myOperationMgr->currentOperation(); - // if (!aOperation->isEditOperation() && - // aOperation->hasObject(aObj) && myDisplayer->isActive(aObj)) - if (!myModule->canActivateSelection(aObj)) { - if (myDisplayer->isActive(aObj)) - myDisplayer->deactivate(aObj); - } - } else { // display object if the current operation has it - if (displayObject(aObj)) { - //ModuleBase_Operation* aOperation = myOperationMgr->currentOperation(); - //if (aOperation && aOperation->hasObject(aObj)) { - if (!myModule->canActivateSelection(aObj)) { - #ifdef DEBUG_FEATURE_REDISPLAY - QString anObjInfo = ModuleBase_Tools::objectInfo((aObj)); - qDebug(QString(" display object = %1").arg(anObjInfo).toStdString().c_str()); - #endif - // Deactivate object of current operation from selection - if (myDisplayer->isActive(aObj)) - myDisplayer->deactivate(aObj); - } - } - } +//****************************************************** +void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer) +{ + if (!myModule->canActivateSelection(theObject)) { + if (myDisplayer->isActive(theObject)) { + QObjectPtrList anObjects; + anObjects.append(theObject); + myDisplayer->deactivateObjects(anObjects, theUpdateViewer); } } - myDisplayer->updateViewer(); } //****************************************************** -void XGUI_Workshop::onFeatureCreatedMsg(const std::shared_ptr& theMsg) -{ - std::set aObjects = theMsg->objects(); - std::set::const_iterator aIt; -#ifdef DEBUG_FEATURE_CREATED - QStringList anInfo; - for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) { - anInfo.append(ModuleBase_Tools::objectInfo((*aIt))); - } - QString anInfoStr = anInfo.join(", "); - qDebug(QString("onFeatureCreatedMsg: %1, %2").arg(aObjects.size()).arg(anInfoStr).toStdString().c_str()); +bool XGUI_Workshop::isFeatureOfNested(const FeaturePtr& theFeature) +{ + bool aHasNested = false; + std::string aFeatureKind = theFeature->getKind(); +#ifdef HAVE_SALOME + XGUI_SalomeConnector* aSalomeConnector = salomeConnector(); + if (aSalomeConnector->isFeatureOfNested(actionsMgr()->action(aFeatureKind.c_str()))) + aHasNested = true; +#else + AppElements_MainMenu* aMenuBar = mainWindow()->menuObject(); + AppElements_Command* aCommand = aMenuBar->feature(aFeatureKind.c_str()); + if (aCommand && aCommand->button()->additionalButtonWidget()) + aHasNested = true; #endif - - //bool aHasPart = false; - bool isDisplayed = false; - for (aIt = aObjects.begin(); aIt != aObjects.end(); ++aIt) { - ObjectPtr anObject = *aIt; - // the validity of the data should be checked here in order to avoid display of the objects, - // which were created, then deleted, but flush for the creation event happens after that - // we should not display disabled objects - bool aHide = !anObject->data()->isValid() || - anObject->isDisabled() || - !anObject->isDisplayed(); - if (!aHide) { - // setDisplayed has to be called in order to synchronize internal state of the object - // with list of displayed objects - if (myModule->canDisplayObject(anObject)) { - anObject->setDisplayed(true); - isDisplayed = displayObject(*aIt); - } else - anObject->setDisplayed(false); - } - } - //if (myObjectBrowser) - // myObjectBrowser->processEvent(theMsg); - if (isDisplayed) - myDisplayer->updateViewer(); - //if (aHasPart) { // TODO: Avoid activate last part on loading of document - // activateLastPart(); - //} + return aHasNested; } //****************************************************** void XGUI_Workshop::onOperationStarted(ModuleBase_Operation* theOperation) { - setNestedFeatures(theOperation); + setGrantedFeatures(theOperation); - if (theOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel - connectWithOperation(theOperation); - setPropertyPanel(theOperation); + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (theOperation); + if (!aFOperation) + return; + + if (aFOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel + setPropertyPanel(aFOperation); + // filling the operation values by the current selection + // if the operation can be committed after the controls filling, the method perform should + // be stopped. Otherwise unnecessary presentations can be shown(e.g. operation prs in sketch) + if (!aFOperation->isEditOperation()) { + aFOperation->activateByPreselection(); + if (operationMgr()->currentOperation() != aFOperation) + return; + } } updateCommandStatus(); - myModule->operationStarted(theOperation); + connectToPropertyPanel(true); + myModule->operationStarted(aFOperation); + + // the objects of the current operation should be deactivated + QObjectPtrList anObjects; + FeaturePtr aFeature = aFOperation->feature(); + anObjects.append(aFeature); + std::list aResults = aFeature->results(); + std::list::const_iterator aIt; + for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) { + anObjects.append(*aIt); + } + QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end(); + for (; anIt != aLast; anIt++) + deactivateActiveObject(*anIt, false); + if (anObjects.size() > 0) + myDisplayer->updateViewer(); } //****************************************************** void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation) { - setNestedFeatures(theOperation); + setGrantedFeatures(theOperation); if (theOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel - // connectWithOperation(theOperation); already connected setPropertyPanel(theOperation); } updateCommandStatus(); @@ -572,35 +496,41 @@ void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation) //****************************************************** void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation) { + updateCommandStatus(); + + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (theOperation); + if (!aFOperation) + return; + ModuleBase_ISelection* aSel = mySelector->selection(); QObjectPtrList aObj = aSel->selectedPresentations(); //!< No need for property panel - updateCommandStatus(); hidePropertyPanel(); myPropertyPanel->cleanContent(); - // Activate objects created by current operation - // in order to clean selection modes - // the deactivation should be pefromed in the same place, where the mode is activated, - // e.g. activation in the current widget activation, deactivation - in the widget's deactivation - //QIntList aModes; - //myDisplayer->activateObjects(aModes); - myModule->operationStopped(theOperation); - - // if the operation is nested, do not deactivate objects - //if (myOperationMgr->operationsCount() == 0) { - // Activate selection mode for all objects + connectToPropertyPanel(false); + myModule->operationStopped(aFOperation); + + // the deactivated objects of the current operation should be activated back. + // They were deactivated on operation start or an object redisplay + QObjectPtrList anObjects; + FeaturePtr aFeature = aFOperation->feature(); + if (aFeature.get()) { // feature may be not created (plugin load fail) + if (myDisplayer->isVisible(aFeature) && !myDisplayer->isActive(aFeature)) + anObjects.append(aFeature); + std::list aResults = aFeature->results(); + std::list::const_iterator aIt; + for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) { + ResultPtr anObject = *aIt; + if (myDisplayer->isVisible(anObject) && !myDisplayer->isActive(anObject)) { + anObjects.append(anObject); + } + } + } QIntList aModes; - // TODO: check on OCC_6.9.0 - // the module current active modes should not be deactivated in order to save the objects selected - // the deactivate object in the mode of selection leads to the object is deselected in the viewer. - // But, in OCC_6.8.0 this deselection does not happened automatically. It is necessary to call - // ClearOutdatedSelection, but this method has an error in the realization, which should be fixed in - // the OCC_6.9.0 release. Moreother, it is possible that ClearOutdatedSelection will be called inside - // Deactivate method of AIS_InteractiveContext. In this case, we need not call it. module()->activeSelectionModes(aModes); - myDisplayer->activateObjects(aModes); - //} + myDisplayer->activateObjects(aModes, anObjects); } @@ -614,149 +544,85 @@ void XGUI_Workshop::onOperationAborted(ModuleBase_Operation* theOperation) myModule->operationAborted(theOperation); } -void XGUI_Workshop::setNestedFeatures(ModuleBase_Operation* theOperation) +void XGUI_Workshop::setGrantedFeatures(ModuleBase_Operation* theOperation) { - if (this->isSalomeMode()) - theOperation->setNestedFeatures(mySalomeConnector->nestedActions(theOperation->id())); - else - theOperation->setNestedFeatures(myActionsMgr->nestedCommands(theOperation->id())); + ModuleBase_OperationFeature* aFOperation = dynamic_cast(theOperation); + if (!aFOperation) + return; + + QStringList aGrantedIds; + if (isSalomeMode()) + aGrantedIds = mySalomeConnector->nestedActions(theOperation->id()); + else + aGrantedIds = myActionsMgr->nestedCommands(theOperation->id()); + + ModuleBase_IModule* aModule = module(); + if (aModule) + aModule->grantedOperationIds(theOperation, aGrantedIds); + + aFOperation->setGrantedOperationIds(aGrantedIds); } void XGUI_Workshop::setPropertyPanel(ModuleBase_Operation* theOperation) { + ModuleBase_OperationFeature* aFOperation = dynamic_cast(theOperation); + if (!aFOperation) + return; + showPropertyPanel(); - QString aXmlRepr = theOperation->getDescription()->xmlRepresentation(); - ModuleBase_WidgetFactory aFactory = ModuleBase_WidgetFactory(aXmlRepr.toStdString(), - myModuleConnector); + QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation(); + ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector); myPropertyPanel->cleanContent(); aFactory.createWidget(myPropertyPanel->contentWidget()); QList aWidgets = aFactory.getModelWidgets(); + + // check compatibility of feature and widgets + FeaturePtr aFeature = aFOperation->feature(); foreach (ModuleBase_ModelWidget* aWidget, aWidgets) { - bool isStoreValue = !theOperation->isEditOperation() && + if (!aWidget->attributeID().empty() && !aFeature->attribute(aWidget->attributeID()).get()) { + std::string anErrorMsg = "The feature '" + aFeature->getKind() + "' has no attribute '" + + aWidget->attributeID() + "' used by widget '" + + aWidget->metaObject()->className() + "'."; + Events_Error::send(anErrorMsg); + myPropertyPanel->cleanContent(); + return; + } + } + + foreach (ModuleBase_ModelWidget* aWidget, aWidgets) { + bool isStoreValue = !aFOperation->isEditOperation() && !aWidget->getDefaultValue().empty() && !aWidget->isComputedDefault(); - aWidget->setFeature(theOperation->feature(), isStoreValue); + aWidget->setFeature(aFOperation->feature(), isStoreValue); aWidget->enableFocusProcessing(); } - + myPropertyPanel->setModelWidgets(aWidgets); - theOperation->setPropertyPanel(myPropertyPanel); + aFOperation->setPropertyPanel(myPropertyPanel); myModule->propertyPanelDefined(theOperation); myPropertyPanel->setWindowTitle(theOperation->getDescription()->description()); -} -bool XGUI_Workshop::event(QEvent * theEvent) -{ - PostponeMessageQtEvent* aPostponedEv = dynamic_cast(theEvent); - if (aPostponedEv) { - std::shared_ptr aEventPtr = aPostponedEv->postponedMessage(); - processEvent(aEventPtr); - return true; - } - return false; + myErrorMgr->setPropertyPanel(myPropertyPanel); } -/* - * - */ -void XGUI_Workshop::addFeature(const std::shared_ptr& theMessage) +void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect) { - if (!theMessage) { -#ifdef _DEBUG - qDebug() << "XGUI_Workshop::addFeature: NULL message."; -#endif - return; - } - ActionInfo aFeatureInfo; - aFeatureInfo.initFrom(theMessage); - - QString aWchName = QString::fromStdString(theMessage->workbenchId()); - QStringList aNestedFeatures = - QString::fromStdString(theMessage->nestedFeatures()).split(" ", QString::SkipEmptyParts); - QString aDocKind = QString::fromStdString(theMessage->documentKind()); - QList aNestedActList; - bool isColumnButton = !aNestedFeatures.isEmpty(); - if (isColumnButton) { - QString aNestedActions = QString::fromStdString(theMessage->actionsWhenNested()); - if (aNestedActions.contains("accept")) { - QAction* anAction = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptAll, NULL); - connect(anAction, SIGNAL(triggered()), myOperationMgr, SLOT(commitAllOperations())); - aNestedActList << anAction; - } - if (aNestedActions.contains("abort")) { - QAction* anAction = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AbortAll, NULL); - connect(anAction, SIGNAL(triggered()), myOperationMgr, SLOT(abortAllOperations())); - aNestedActList << anAction; - } - } - - if (isSalomeMode()) { - QAction* aAction; - if (isColumnButton) { - aAction = salomeConnector()->addNestedFeature(aWchName, aFeatureInfo, aNestedActList); - } else { - aAction = salomeConnector()->addFeature(aWchName, aFeatureInfo); - } - salomeConnector()->setNestedActions(aFeatureInfo.id, aNestedFeatures); - salomeConnector()->setDocumentKind(aFeatureInfo.id, aDocKind); - - myActionsMgr->addCommand(aAction); - myModule->actionCreated(aAction); - } else { - //Find or create Workbench - AppElements_MainMenu* aMenuBar = myMainWindow->menuObject(); - AppElements_Workbench* aPage = aMenuBar->findWorkbench(aWchName); - if (!aPage) { - aPage = addWorkbench(aWchName); - } - //Find or create Group - QString aGroupName = QString::fromStdString(theMessage->groupId()); - AppElements_MenuGroupPanel* aGroup = aPage->findGroup(aGroupName); - if (!aGroup) { - aGroup = aPage->addGroup(aGroupName); - } - // Check if hotkey sequence is already defined: - QKeySequence aHotKey = myActionsMgr->registerShortcut(aFeatureInfo.shortcut); - if(aHotKey != aFeatureInfo.shortcut) { - aFeatureInfo.shortcut = aHotKey; - } - // Create feature... - AppElements_Command* aCommand = aGroup->addFeature(aFeatureInfo, - aDocKind, - aNestedFeatures); - // Enrich created button with accept/abort buttons if necessary - AppElements_Button* aButton = aCommand->button(); - if (aButton->isColumnButton()) { - aButton->setAdditionalButtons(aNestedActList); + XGUI_PropertyPanel* aPropertyPanel = propertyPanel(); + if (aPropertyPanel) { + const QList& aWidgets = aPropertyPanel->modelWidgets(); + foreach (ModuleBase_ModelWidget* aWidget, aWidgets) { + myModule->connectToPropertyPanel(aWidget, isToConnect); + if (isToConnect) { + connect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int))); + } + else { + disconnect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int))); + } } - myActionsMgr->addCommand(aCommand); - myModule->actionCreated(aCommand); - } -} - -/* - * Makes a signal/slot connections between Property Panel - * and given operation. The given operation becomes a - * current operation and previous operation if exists - */ -void XGUI_Workshop::connectWithOperation(ModuleBase_Operation* theOperation) -{ - QAction* aCommand = 0; - if (isSalomeMode()) { - aCommand = salomeConnector()->command(theOperation->getDescription()->operationId()); - } else { - AppElements_MainMenu* aMenu = myMainWindow->menuObject(); - FeaturePtr aFeature = theOperation->feature(); - if(aFeature) - aCommand = aMenu->feature(QString::fromStdString(aFeature->getKind())); - } - //Abort operation on uncheck the command - if (aCommand) { - connect(aCommand, SIGNAL(triggered(bool)), theOperation, SLOT(setRunning(bool))); } } @@ -771,29 +637,48 @@ void XGUI_Workshop::saveDocument(const QString& theName, std::list& QApplication::restoreOverrideCursor(); } -bool XGUI_Workshop::isActiveOperationAborted() +bool XGUI_Workshop::abortAllOperations() { return myOperationMgr->abortAllOperations(); } //****************************************************** -void XGUI_Workshop::onExit() +void XGUI_Workshop::onOpen() { - SessionPtr aMgr = ModelAPI_Session::get(); - if (aMgr->isModified()) { + if(!abortAllOperations()) + return; + //save current file before close if modified + SessionPtr aSession = ModelAPI_Session::get(); + if (aSession->isModified()) { + //TODO(sbh): re-launch the app? int anAnswer = QMessageBox::question( - myMainWindow, tr("Save current file"), tr("The document is modified, save before exit?"), + desktop(), tr("Save current file"), + tr("The document is modified, save before opening another?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel); if (anAnswer == QMessageBox::Save) { - bool saved = onSave(); - if (!saved) { - return; - } + onSave(); } else if (anAnswer == QMessageBox::Cancel) { return; } + myCurrentDir = ""; } - qApp->exit(); + + //show file dialog, check if readable and open + myCurrentDir = QFileDialog::getExistingDirectory(desktop(), tr("Select directory")); + if (myCurrentDir.isEmpty()) + return; + QFileInfo aFileInfo(myCurrentDir); + if (!aFileInfo.exists() || !aFileInfo.isReadable()) { + QMessageBox::critical(desktop(), tr("Warning"), tr("Unable to open the file.")); + myCurrentDir = ""; + return; + } + QApplication::setOverrideCursor(Qt::WaitCursor); + aSession->closeAll(); + aSession->load(myCurrentDir.toLatin1().constData()); + myObjectBrowser->rebuildDataTree(); + updateCommandStatus(); + QApplication::restoreOverrideCursor(); } //****************************************************** @@ -806,62 +691,62 @@ void XGUI_Workshop::onNew() } myViewerProxy->connectToViewer(); showObjectBrowser(); - if (!isSalomeMode()) { - myMainWindow->showPythonConsole(); - QMdiSubWindow* aWnd = myMainWindow->viewer()->createView(); - aWnd->showMaximized(); - updateCommandStatus(); - } +#ifndef HAVE_SALOME + myMainWindow->showPythonConsole(); + QMdiSubWindow* aWnd = myMainWindow->viewer()->createView(); + aWnd->showMaximized(); + updateCommandStatus(); +#endif myContextMenuMgr->connectViewer(); QApplication::restoreOverrideCursor(); } +#ifndef HAVE_SALOME //****************************************************** -void XGUI_Workshop::onOpen() +void XGUI_Workshop::onExit() { - if(!isActiveOperationAborted()) - return; - //save current file before close if modified - SessionPtr aSession = ModelAPI_Session::get(); - if (aSession->isModified()) { - //TODO(sbh): re-launch the app? + SessionPtr aMgr = ModelAPI_Session::get(); + if (aMgr->isModified()) { int anAnswer = QMessageBox::question( - myMainWindow, tr("Save current file"), - tr("The document is modified, save before opening another?"), + myMainWindow, tr("Save current file"), tr("The document is modified, save before exit?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel); if (anAnswer == QMessageBox::Save) { - onSave(); + bool saved = onSave(); + if (!saved) { + return; + } } else if (anAnswer == QMessageBox::Cancel) { return; } - myCurrentDir = ""; } + qApp->exit(); +} - //show file dialog, check if readable and open - myCurrentDir = QFileDialog::getExistingDirectory(mainWindow()); - if (myCurrentDir.isEmpty()) - return; - QFileInfo aFileInfo(myCurrentDir); - if (!aFileInfo.exists() || !aFileInfo.isReadable()) { - QMessageBox::critical(myMainWindow, tr("Warning"), tr("Unable to open the file.")); - myCurrentDir = ""; - return; +//****************************************************** +void XGUI_Workshop::onPreferences() +{ + ModuleBase_Prefs aModif; + ModuleBase_Preferences::editPreferences(aModif); + if (aModif.size() > 0) { + QString aSection; + foreach (ModuleBase_Pref aPref, aModif) + { + aSection = aPref.first; + if (aSection == ModuleBase_Preferences::VIEWER_SECTION) { + myMainWindow->viewer()->updateFromResources(); + } else if (aSection == ModuleBase_Preferences::MENU_SECTION) { + myMainWindow->menuObject()->updateFromResources(); + } + } + displayer()->redisplayObjects(); } - QApplication::setOverrideCursor(Qt::WaitCursor); - myIsLoadingData = true; - aSession->closeAll(); - aSession->load(myCurrentDir.toLatin1().constData()); - myObjectBrowser->rebuildDataTree(); - //displayAllResults(); - updateCommandStatus(); - myIsLoadingData = false; - QApplication::restoreOverrideCursor(); } +#endif //****************************************************** bool XGUI_Workshop::onSave() { - if(!isActiveOperationAborted()) + if(!abortAllOperations()) return false; if (myCurrentDir.isEmpty()) { return onSaveAs(); @@ -869,44 +754,46 @@ bool XGUI_Workshop::onSave() std::list aFiles; saveDocument(myCurrentDir, aFiles); updateCommandStatus(); - if (!isSalomeMode()) +#ifndef HAVE_SALOME myMainWindow->setModifiedState(false); +#endif return true; } //****************************************************** bool XGUI_Workshop::onSaveAs() { - if(!isActiveOperationAborted()) + if(!abortAllOperations()) return false; - QFileDialog dialog(mainWindow()); + QFileDialog dialog(desktop()); dialog.setWindowTitle(tr("Select directory to save files...")); dialog.setFileMode(QFileDialog::Directory); - dialog.setFilter(tr("Folders (*)")); + dialog.setFilter(tr("Directories (*)")); dialog.setOptions(QFileDialog::HideNameFilterDetails | QFileDialog::ShowDirsOnly); dialog.setViewMode(QFileDialog::Detail); if (!dialog.exec()) { return false; } + QString aTempDir = dialog.selectedFiles().first(); QDir aDir(aTempDir); if (aDir.exists() && !aDir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty()) { int answer = QMessageBox::question( - myMainWindow, + desktop(), //: Title of the dialog which asks user if he wants to save study in existing non-empty folder tr("Save"), - tr("The folder already contains some files, save anyway?"), + tr("The directory already contains some files, save anyway?"), QMessageBox::Save | QMessageBox::Cancel); if (answer == QMessageBox::Cancel) { return false; } } myCurrentDir = aTempDir; - if (!isSalomeMode()) { +#ifndef HAVE_SALOME myMainWindow->setCurrentDir(myCurrentDir, false); myMainWindow->setModifiedState(false); - } +#endif return onSave(); } @@ -915,11 +802,17 @@ void XGUI_Workshop::onUndo(int theTimes) { objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); SessionPtr aMgr = ModelAPI_Session::get(); - if (aMgr->isOperation()) + if (aMgr->isOperation()) { + /// this is important for nested operations + /// when sketch operation is active, this condition is false and + /// the sketch operation is not aborted operationMgr()->onAbortOperation(); + } for (int i = 0; i < theTimes; ++i) { aMgr->undo(); } + + operationMgr()->updateApplyOfOperations(); updateCommandStatus(); } @@ -934,11 +827,16 @@ void XGUI_Workshop::onRedo(int theTimes) objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); SessionPtr aMgr = ModelAPI_Session::get(); - if (aMgr->isOperation()) + if (aMgr->isOperation()) { + /// this is important for nested operations + /// when sketch operation is active, this condition is false and + /// the sketch operation is not aborted operationMgr()->onAbortOperation(); + } for (int i = 0; i < theTimes; ++i) { aMgr->redo(); } + operationMgr()->updateApplyOfOperations(); updateCommandStatus(); // unblock the viewer update functionality and make update on purpose @@ -964,27 +862,21 @@ void XGUI_Workshop::onRebuild() } //****************************************************** -void XGUI_Workshop::onPreferences() +void XGUI_Workshop::onWidgetStateChanged(int thePreviousState) { - ModuleBase_Prefs aModif; - ModuleBase_Preferences::editPreferences(aModif); - if (aModif.size() > 0) { - QString aSection; - foreach (ModuleBase_Pref aPref, aModif) - { - aSection = aPref.first; - if (aSection == ModuleBase_Preferences::VIEWER_SECTION) { - if (!isSalomeMode()) - myMainWindow->viewer()->updateFromResources(); - } else if (aSection == ModuleBase_Preferences::MENU_SECTION) { - if (!isSalomeMode()) - myMainWindow->menuObject()->updateFromResources(); - } - } + ModuleBase_ModelWidget* anActiveWidget = 0; + ModuleBase_Operation* anOperation = myOperationMgr->currentOperation(); + if (anOperation) { + ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel(); + if (aPanel) + anActiveWidget = aPanel->activeWidget(); } + if (anActiveWidget) + operationMgr()->onValidateOperation(); + + myModule->widgetStateChanged(thePreviousState); } -//****************************************************** ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule) { QString libName = QString::fromStdString(library(theModule.toStdString())); @@ -1034,7 +926,7 @@ ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule) ModuleBase_IModule* aModule = crtInst ? crtInst(myModuleConnector) : 0; if (!err.isEmpty()) { - if (mainWindow()) { + if (desktop()) { Events_Error::send(err.toStdString()); } else { qWarning(qPrintable(err)); @@ -1044,7 +936,7 @@ ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule) } //****************************************************** -bool XGUI_Workshop::activateModule() +bool XGUI_Workshop::createModule() { Config_ModuleReader aModuleReader; QString moduleName = QString::fromStdString(aModuleReader.getModuleName()); @@ -1052,13 +944,13 @@ bool XGUI_Workshop::activateModule() if (!myModule) return false; - connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)), - myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr))); - connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)), - myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr))); + //connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)), + // myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr))); + //connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)), + // myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr))); myModule->createFeatures(); - myActionsMgr->update(); + //myActionsMgr->update(); return true; } @@ -1066,29 +958,25 @@ bool XGUI_Workshop::activateModule() void XGUI_Workshop::updateCommandStatus() { QList aCommands; - if (isSalomeMode()) { // update commands in SALOME mode +#ifdef HAVE_SALOME aCommands = salomeConnector()->commandList(); - } else { +#else AppElements_MainMenu* aMenuBar = myMainWindow->menuObject(); foreach (AppElements_Command* aCmd, aMenuBar->features()) aCommands.append(aCmd); - } +#endif SessionPtr aMgr = ModelAPI_Session::get(); if (aMgr->hasModuleDocument()) { - QAction *aUndoCmd, *aRedoCmd; foreach(QAction* aCmd, aCommands) { QString aId = aCmd->data().toString(); if (aId == "UNDO_CMD") - aUndoCmd = aCmd; + aCmd->setEnabled(myModule->canUndo()); else if (aId == "REDO_CMD") - aRedoCmd = aCmd; + aCmd->setEnabled(myModule->canRedo()); else // Enable all commands aCmd->setEnabled(true); } - - aUndoCmd->setEnabled(myModule->canUndo()); - aRedoCmd->setEnabled(myModule->canRedo()); updateHistory(); } else { foreach(QAction* aCmd, aCommands) { @@ -1125,7 +1013,6 @@ QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent) aObjDock->setStyleSheet( "::title { position: relative; padding-left: 5px; text-align: left center }"); myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock); - myObjectBrowser->setDataModel(myModule->dataModel()); myModule->customizeObjectBrowser(myObjectBrowser); aObjDock->setWidget(myObjectBrowser); @@ -1140,10 +1027,10 @@ QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent) */ void XGUI_Workshop::createDockWidgets() { - QMainWindow* aDesktop = isSalomeMode() ? salomeConnector()->desktop() : myMainWindow; + QMainWindow* aDesktop = desktop(); QDockWidget* aObjDock = createObjectBrowser(aDesktop); aDesktop->addDockWidget(Qt::LeftDockWidgetArea, aObjDock); - myPropertyPanel = new XGUI_PropertyPanel(aDesktop); + myPropertyPanel = new XGUI_PropertyPanel(aDesktop, myOperationMgr); myPropertyPanel->setupActions(myActionsMgr); myPropertyPanel->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); aDesktop->addDockWidget(Qt::LeftDockWidgetArea, myPropertyPanel); @@ -1153,18 +1040,15 @@ void XGUI_Workshop::createDockWidgets() myPropertyPanel->installEventFilter(myOperationMgr); QAction* aOkAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept); - connect(aOkAct, SIGNAL(triggered()), myOperationMgr, SLOT(onCommitOperation())); + connect(aOkAct, SIGNAL(triggered()), this, SLOT(onAcceptActionClicked())); + QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort); connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation())); connect(myPropertyPanel, SIGNAL(noMoreWidgets()), myModule, SLOT(onNoMoreWidgets())); connect(myPropertyPanel, SIGNAL(keyReleased(QKeyEvent*)), myOperationMgr, SLOT(onKeyReleased(QKeyEvent*))); - connect(myOperationMgr, SIGNAL(validationStateChanged(bool)), - aOkAct, SLOT(setEnabled(bool))); - QAction* aAcceptAllAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptAll); - connect(myOperationMgr, SIGNAL(nestedStateChanged(bool)), - aAcceptAllAct, SLOT(setEnabled(bool))); - + //connect(myOperationMgr, SIGNAL(validationStateChanged(bool)), + // this, SLOT(onValidationStateChanged(bool))); } //****************************************************** @@ -1175,6 +1059,13 @@ void XGUI_Workshop::showPropertyPanel() aViewAct->setEnabled(true); myPropertyPanel->show(); myPropertyPanel->raise(); + + // The next code is necessary to made the property panel the active window + // in order to operation manager could process key events of the panel. + // otherwise they are ignored. It happens only if the same(activateWindow) is + // not happened by property panel activation(e.g. resume operation of Sketch) + myPropertyPanel->activateWindow(); + myPropertyPanel->setFocus(); } //****************************************************** @@ -1184,6 +1075,17 @@ void XGUI_Workshop::hidePropertyPanel() ///setEnabled(false); myPropertyPanel->hide(); + + // the property panel is active window of the desktop, when it is + // hidden, it is undefined which window becomes active. By this reason + // it is defined to perform the desktop as the active window. + // in SALOME mode, workstack made the PyConsole the active window, + // set the focus on it. As a result, shortcuts of the application, like + // are processed by this console. For example Undo actions. + // It is possible that this code is to be moved to NewGeom package + QMainWindow* aDesktop = desktop(); + aDesktop->activateWindow(); + aDesktop->setFocus(); } //****************************************************** @@ -1198,17 +1100,6 @@ void XGUI_Workshop::hideObjectBrowser() myObjectBrowser->parentWidget()->hide(); } -//****************************************************** -void XGUI_Workshop::onFeatureTriggered() -{ - QAction* aCmd = dynamic_cast(sender()); - if (aCmd) { - QString aId = salomeConnector()->commandId(aCmd); - if (!aId.isNull()) - myModule->launchOperation(aId); - } -} - //****************************************************** void XGUI_Workshop::salomeViewerSelectionChanged() { @@ -1227,6 +1118,8 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) QObjectPtrList aObjects = mySelector->selection()->selectedObjects(); if (theId == "DELETE_CMD") deleteObjects(); + else if (theId == "MOVE_CMD") + moveObjects(); else if (theId == "COLOR_CMD") changeColor(aObjects); else if (theId == "SHOW_CMD") @@ -1241,8 +1134,10 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) setDisplayMode(aObjects, XGUI_Displayer::Wireframe); else if (theId == "HIDEALL_CMD") { QObjectPtrList aList = myDisplayer->displayedObjects(); - foreach (ObjectPtr aObj, aList) - aObj->setDisplayed(false); + foreach (ObjectPtr aObj, aList) { + if (module()->canEraseObject(aObj)) + aObj->setDisplayed(false); + } Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); } } @@ -1257,13 +1152,21 @@ void XGUI_Workshop::deleteObjects() return; } - if (!isActiveOperationAborted()) - return; QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + if (!abortAllOperations()) + return; + // It is necessary to clear selection in order to avoid selection changed event during + // deletion and negative consequences connected with processing of already deleted items + mySelector->clearSelection(); + // check whether the object can be deleted. There should not be parts which are not loaded + if (!XGUI_Tools::canRemoveOrRename(desktop(), anObjects)) + return; + bool hasResult = false; bool hasFeature = false; bool hasParameter = false; - ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter); + bool hasSubFeature = false; + ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasSubFeature); if (!(hasFeature || hasParameter)) return; @@ -1277,165 +1180,189 @@ void XGUI_Workshop::deleteObjects() aObjectNames << QString::fromStdString(aObj->data()->name()); } aDescription = aDescription.arg(aObjectNames.join(", ")); + ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); - SessionPtr aMgr = ModelAPI_Session::get(); - aMgr->startOperation(aDescription.toStdString()); - // 2. close the documents of the removed parts if the result part is in a list of selected objects - // this is performed in the RemoveFeature of Part object. - /*foreach (ObjectPtr aObj, anObjects) - { - ResultPartPtr aPart = std::dynamic_pointer_cast(aObj); - if (aPart) { - DocumentPtr aDoc = aObj->document(); - if (aDoc == aMgr->activeDocument()) { - aDoc->close(); - } - } - }*/ + operationMgr()->startOperation(anOpAction); // 3. delete objects - QMainWindow* aDesktop = isSalomeMode() ? salomeConnector()->desktop() : myMainWindow; std::set anIgnoredFeatures; - if (deleteFeatures(anObjects, anIgnoredFeatures, aDesktop, true)) { - myDisplayer->updateViewer(); - aMgr->finishOperation(); - updateCommandStatus(); + if (deleteFeatures(anObjects, anIgnoredFeatures, desktop(), true)) { + operationMgr()->commitOperation(); } else { - aMgr->abortOperation(); + operationMgr()->abortOperation(operationMgr()->currentOperation()); } } +//************************************************************** +void XGUI_Workshop::moveObjects() +{ + if (!abortAllOperations()) + return; + + SessionPtr aMgr = ModelAPI_Session::get(); + + QString anActionId = "MOVE_CMD"; + QString aDescription = contextMenuMgr()->action(anActionId)->text(); + aMgr->startOperation(aDescription.toStdString()); + + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + // It is necessary to clear selection in order to avoid selection changed event during + // moving and negative consequences connected with processing of already moved items + mySelector->clearSelection(); + // check whether the object can be moved. There should not be parts which are not loaded + if (!XGUI_Tools::canRemoveOrRename(desktop(), anObjects)) + return; + + DocumentPtr anActiveDocument = aMgr->activeDocument(); + FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true); + foreach (ObjectPtr aObject, anObjects) { + if (!myModule->canApplyAction(aObject, anActionId)) + continue; + + FeaturePtr aFeature = std::dynamic_pointer_cast(aObject); + if (aFeature.get()) { + anActiveDocument->moveFeature(aFeature, aCurrentFeature); + aCurrentFeature = anActiveDocument->currentFeature(true); + } + } + aMgr->finishOperation(); +} + //************************************************************** bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, - std::set theIgnoredFeatures, + const std::set& theIgnoredFeatures, QWidget* theParent, const bool theAskAboutDeleteReferences) { +#ifdef DEBUG_DELETE + QStringList aDInfo; + QObjectPtrList::const_iterator aDIt = theList.begin(), aDLast = theList.end(); + for (; aDIt != aDLast; ++aDIt) { + aDInfo.append(ModuleBase_Tools::objectInfo((*aDIt))); + } + QString anInfoStr = aDInfo.join(", "); + qDebug(QString("deleteFeatures: %1, %2").arg(theList.size()).arg(anInfoStr).toStdString().c_str()); +#endif + // 1. find all referenced features - std::set aRefFeatures; + std::set aDirectRefFeatures, aIndirectRefFeatures; foreach (ObjectPtr aDeletedObj, theList) { - FeaturePtr aDeletedFeature = ModelAPI_Feature::feature(aDeletedObj); - if (aDeletedFeature.get() != NULL) { - DocumentPtr aDeletedFeatureDoc = aDeletedObj->document(); - // 1.1 find references in the current document - aDeletedFeatureDoc->refsToFeature(aDeletedFeature, aRefFeatures, false); - // 1.2 find references in all documents if the document of the feature is - // "PartSet". Features of this document can be used in all other documents - SessionPtr aMgr = ModelAPI_Session::get(); - DocumentPtr aModuleDoc = aMgr->moduleDocument(); - if (aDeletedFeatureDoc == aModuleDoc) { - // the deleted feature and results of the feature should be found in references - std::list aDeletedObjects; - aDeletedObjects.push_back(aDeletedFeature); - typedef std::list > ResultsList; - const ResultsList& aDeletedResults = aDeletedFeature->results(); - ResultsList::const_iterator aRIter = aDeletedResults.begin(); - for (; aRIter != aDeletedResults.cend(); aRIter++) { - ResultPtr aRes = *aRIter; - if (aRes.get()) - aDeletedObjects.push_back(aRes); - } - // get all opened documents; found features in the documents; - // get a list of objects where a feature refers; - // search in these objects the deleted objects. - std::list anOpenedDocs = aMgr->allOpenedDocuments(); - std::list::const_iterator anIt = anOpenedDocs.begin(), - aLast = anOpenedDocs.end(); - std::list > > aRefs; - for (; anIt != aLast; anIt++) { - DocumentPtr aDocument = *anIt; - if (aDocument == aDeletedFeatureDoc) - continue; // this document has been already processed in 1.1 - - int aFeaturesCount = aDocument->size(ModelAPI_Feature::group()); - for (int aId = 0; aId < aFeaturesCount; aId++) { - ObjectPtr anObject = aDocument->object(ModelAPI_Feature::group(), aId); - FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); - if (!aFeature.get()) - continue; - - aRefs.clear(); - aFeature->data()->referencesToObjects(aRefs); - std::list > >::iterator aRef = aRefs.begin(); - bool aHasReferenceToDeleted = false; - for(; aRef != aRefs.end() && !aHasReferenceToDeleted; aRef++) { - std::list::iterator aRefObj = aRef->second.begin(); - for(; aRefObj != aRef->second.end() && !aHasReferenceToDeleted; aRefObj++) { - std::list::const_iterator aDelIt = aDeletedObjects.begin(); - for(; aDelIt != aDeletedObjects.end() && !aHasReferenceToDeleted; aDelIt++) { - aHasReferenceToDeleted = *aDelIt == *aRefObj; - } - } - } - if (aHasReferenceToDeleted) - aRefFeatures.insert(aFeature); - } - } - } - } + std::set alreadyProcessed; + XGUI_Tools::refsToFeatureInAllDocuments( + aDeletedObj, aDeletedObj, aDirectRefFeatures, aIndirectRefFeatures, alreadyProcessed); + std::set aDifference; + std::set_difference(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end(), + aDirectRefFeatures.begin(), aDirectRefFeatures.end(), + std::inserter(aDifference, aDifference.begin())); + aIndirectRefFeatures = aDifference; } + + bool doDeleteReferences = true; + // 2. warn about the references remove, break the delete operation if the user chose it - if (theAskAboutDeleteReferences && !aRefFeatures.empty()) { - QStringList aRefNames; - std::set::const_iterator anIt = aRefFeatures.begin(), - aLast = aRefFeatures.end(); - for (; anIt != aLast; anIt++) { - aRefNames.append((*anIt)->name().c_str()); + if (theAskAboutDeleteReferences && !aDirectRefFeatures.empty()) { + QStringList aDirectRefNames; + foreach (const FeaturePtr& aFeature, aDirectRefFeatures) + aDirectRefNames.append(aFeature->name().c_str()); + QString aDirectNames = aDirectRefNames.join(", "); + + QStringList aIndirectRefNames; + foreach (const FeaturePtr& aFeature, aIndirectRefFeatures) + aIndirectRefNames.append(aFeature->name().c_str()); + QString aIndirectNames = aIndirectRefNames.join(", "); + + bool canReplaceParameters = true; + foreach (ObjectPtr aObj, theList) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); + if (!std::dynamic_pointer_cast(aFeature->firstResult()).get()) { // the feature is not a parameter + canReplaceParameters = false; + break; + } } - QString aNames = aRefNames.join(", "); - - QMessageBox::StandardButton aRes = QMessageBox::warning( - theParent, tr("Delete features"), - QString(tr("Selected features are used in the following features: %1.\ -These features will be deleted also. Would you like to continue?")).arg(aNames), - QMessageBox::No | QMessageBox::Yes, QMessageBox::No); - if (aRes != QMessageBox::Yes) + + QMessageBox aMessageBox(theParent); + aMessageBox.setWindowTitle(tr("Delete features")); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + aMessageBox.setDefaultButton(QMessageBox::No); + + QString aText; + if (canReplaceParameters) { + aText = QString(tr("Selected parameters are used in the following features: %1.\nThese features will be deleted.\n%2Or parameters could be replaced by their values.\nWould you like to continue?")) + .arg(aDirectNames).arg(aIndirectNames.isEmpty() ? QString() : QString(tr("(Also these features will be deleted: %1)\n")).arg(aIndirectNames)); + QPushButton *aReplaceButton = aMessageBox.addButton(tr("Replace"), QMessageBox::ActionRole); + } else { + aText = QString(tr("Selected features are used in the following features: %1.\nThese features will be deleted.\n%2Would you like to continue?")) + .arg(aDirectNames).arg(aIndirectNames.isEmpty() ? QString() : QString(tr("Also these features will be deleted: %1.\n")).arg(aIndirectNames)); + } + aMessageBox.setText(aText); + aMessageBox.exec(); + QMessageBox::ButtonRole aButtonRole = aMessageBox.buttonRole(aMessageBox.clickedButton()); + + if (aButtonRole == QMessageBox::NoRole) return false; + + if (aButtonRole == QMessageBox::ActionRole) { + foreach (ObjectPtr aObj, theList) + ModelAPI_ReplaceParameterMessage::send(aObj, this); + doDeleteReferences = false; + } } // 3. remove referenced features - std::set::const_iterator anIt = aRefFeatures.begin(), - aLast = aRefFeatures.end(); + if (doDeleteReferences) { + std::set aFeaturesToDelete = aDirectRefFeatures; + aFeaturesToDelete.insert(aIndirectRefFeatures.begin(), aIndirectRefFeatures.end()); + std::set::const_iterator anIt = aFeaturesToDelete.begin(), + aLast = aFeaturesToDelete.end(); #ifdef DEBUG_DELETE - QStringList anInfo; + QStringList anInfo; #endif - for (; anIt != aLast; anIt++) { - FeaturePtr aFeature = (*anIt); - DocumentPtr aDoc = aFeature->document(); - if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) { - aDoc->removeFeature(aFeature); + for (; anIt != aLast; anIt++) { + FeaturePtr aFeature = (*anIt); + DocumentPtr aDoc = aFeature->document(); + if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) { + aDoc->removeFeature(aFeature); #ifdef DEBUG_DELETE - anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str()); + anInfo.append(ModuleBase_Tools::objectInfo(aFeature).toStdString().c_str()); #endif + } } - } #ifdef DEBUG_DELETE - qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str()); - anInfo.clear(); + qDebug(QString("remove references:%1").arg(anInfo.join("; ")).toStdString().c_str()); + anInfo.clear(); #endif + } + QString anActionId = "DELETE_CMD"; + QString anId = QString::fromStdString(anActionId.toStdString().c_str()); + QStringList anObjectGroups = contextMenuMgr()->actionObjectGroups(anId); // 4. remove the parameter features foreach (ObjectPtr aObj, theList) { - ResultPtr aResult = std::dynamic_pointer_cast(aObj); - if (aResult.get() != NULL) { // results could not be removed, - // they are removed by a corresponded feature remove + // features and parameters can be removed here, + // the results are removed only by a corresponded feature remove + std::string aGroupName = aObj->groupName(); + if (!anObjectGroups.contains(aGroupName.c_str())) continue; - } + + if (!myModule->canApplyAction(aObj, anActionId)) + continue; + FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); if (aFeature) { - // TODO: to learn the workshop to delegate the Part object deletion to the PartSet module + /*// TODO: to learn the workshop to delegate the Part object deletion to the PartSet module // part features are removed in the PartSet module. This condition should be moved there if (aFeature->getKind() == "Part") continue; - + */ DocumentPtr aDoc = aObj->document(); if (theIgnoredFeatures.find(aFeature) == theIgnoredFeatures.end()) { - aDoc->removeFeature(aFeature); #ifdef DEBUG_DELETE QString anInfoStr = ModuleBase_Tools::objectInfo(aFeature); anInfo.append(anInfoStr); qDebug(QString("remove feature :%1").arg(anInfoStr).toStdString().c_str()); #endif + aDoc->removeFeature(aFeature); } } } @@ -1461,6 +1388,123 @@ bool hasResults(QObjectPtrList theObjects, const std::set& theTypes return isFoundResultType; } +//************************************************************** +// Returns the list of all features for theDocument and all features of +// all nested parts. +std::list allFeatures(const DocumentPtr& theDocument) +{ + std::list aResultList; + std::list anAllFeatures = theDocument->allFeatures(); + foreach (const FeaturePtr& aFeature, anAllFeatures) { + // The order of appending features of the part and the part itself is important + + // Append features from a part feature + foreach (const ResultPtr& aResult, aFeature->results()) { + ResultPartPtr aResultPart = + std::dynamic_pointer_cast(aResult); + if (aResultPart.get() && aResultPart->partDoc().get()) { + // Recursion + std::list anAllFeatures = allFeatures(aResultPart->partDoc()); + aResultList.insert(aResultList.end(), anAllFeatures.begin(), anAllFeatures.end()); + } + } + + aResultList.push_back(aFeature); + } + return aResultList; +} + +//************************************************************** +// Returns the list of features placed between theObject and the current feature +// in the same document. Excludes theObject, includes the current feature. +std::list toCurrentFeatures(const ObjectPtr& theObject) +{ + std::list aResult; + DocumentPtr aDocument = theObject->document(); + std::list anAllFeatures = allFeatures(aDocument); + // find the object iterator + std::list::iterator aObjectIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), theObject); + if (aObjectIt == anAllFeatures.end()) + return aResult; + // find the current feature iterator + std::list::iterator aCurrentIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), aDocument->currentFeature(true)); + if (aCurrentIt == anAllFeatures.end()) + return aResult; + // check the right order + if (std::distance(aObjectIt, anAllFeatures.end()) <= std::distance(aCurrentIt, anAllFeatures.end())) + return aResult; + // exclude the object + std::advance(aObjectIt, 1); + // include the current feature + std::advance(aCurrentIt, 1); + return std::list(aObjectIt, aCurrentIt); +} + +bool XGUI_Workshop::canMoveFeature() +{ + QString anActionId = "MOVE_CMD"; + + QObjectPtrList aObjects = mySelector->selection()->selectedObjects(); + QObjectPtrList aValidatedObjects; + foreach (ObjectPtr aObject, aObjects) { + if (!myModule->canApplyAction(aObject, anActionId)) + continue; + // To be moved feature should be in active document + if (aObject->document() != ModelAPI_Session::get()->activeDocument()) + continue; + aValidatedObjects.append(aObject); + } + if (aValidatedObjects.size() != aObjects.size()) + aObjects = aValidatedObjects; + + bool aCanMove = !aObjects.empty(); + + QObjectPtrList::const_iterator anIt = aObjects.begin(), aLast = aObjects.end(); + for (; anIt != aLast && aCanMove; anIt++) { + ObjectPtr aObject = *anIt; + // 1. Get features placed between selected and current in the document + std::list aFeaturesBetween = toCurrentFeatures(aObject); + // if aFeaturesBetween is empty it means wrong order or aObject is the current feature + if (aFeaturesBetween.empty()) + aCanMove = false; + else { + std::set aPlacedFeatures(aFeaturesBetween.begin(), aFeaturesBetween.end()); + // 2. Get all reference features to the selected object in the document + std::set aRefFeatures; + XGUI_Tools::refsToFeatureInFeatureDocument(aObject, aRefFeatures); + + if (aRefFeatures.empty()) + continue; + else { + // 3. Find any placed features in all reference features + std::set aIntersectionFeatures; + std::set_intersection(aRefFeatures.begin(), aRefFeatures.end(), + aPlacedFeatures.begin(), aPlacedFeatures.end(), + std::inserter(aIntersectionFeatures, aIntersectionFeatures.begin())); + // 4. Return false if any reference feature is placed before current feature + if (!aIntersectionFeatures.empty()) + aCanMove = false; + } + } + } + return aCanMove; +} + +//************************************************************** +bool XGUI_Workshop::canBeShaded(const ObjectPtr& theObject) const +{ + bool aCanBeShaded = myDisplayer->canBeShaded(theObject); + if (!aCanBeShaded) { + ResultCompSolidPtr aCompsolidResult = + std::dynamic_pointer_cast(theObject); + if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids + for(int i = 0; i < aCompsolidResult->numberOfSubs() && !aCanBeShaded; i++) + aCanBeShaded = myDisplayer->canBeShaded(aCompsolidResult->subResult(i)); + } + } + return aCanBeShaded; +} + //************************************************************** bool XGUI_Workshop::canChangeColor() const { @@ -1475,7 +1519,7 @@ bool XGUI_Workshop::canChangeColor() const return hasResults(aObjects, aTypes); } -void setColor(ResultPtr theResult, std::vector& theColor) +void setColor(ResultPtr theResult, const std::vector& theColor) { if (!theResult.get()) return; @@ -1494,43 +1538,25 @@ void setColor(ResultPtr theResult, std::vector& theColor) //************************************************************** void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects) { + AttributeIntArrayPtr aColorAttr; // 1. find the current color of the object. This is a color of AIS presentation // The objects are iterated until a first valid color is found std::vector aColor; foreach(ObjectPtr anObject, theObjects) { - if (anObject->groupName() == ModelAPI_ResultPart::group()) { - ResultPartPtr aPart = std::dynamic_pointer_cast(anObject); - DocumentPtr aPartDoc = aPart->partDoc(); - // the document should be checked on null, because in opened document if the part - // has not been activated yet, the part document is empty - if (!aPartDoc.get()) { - emit errorOccurred(QString::fromLatin1("Color can not be changed on a part with an empty document")); - } - else { - if (aPartDoc->size(ModelAPI_ResultBody::group()) > 0) { - ObjectPtr aObject = aPartDoc->object(ModelAPI_ResultBody::group(), 0); - ResultBodyPtr aBody = std::dynamic_pointer_cast(aObject); - if (aBody.get()) { - XGUI_CustomPrs::getResultColor(aBody, aColor); - } - } - } + ResultPtr aResult = std::dynamic_pointer_cast(anObject); + if (aResult.get()) { + XGUI_CustomPrs::getResultColor(aResult, aColor); } else { - ResultPtr aResult = std::dynamic_pointer_cast(anObject); - if (aResult.get()) - XGUI_CustomPrs::getResultColor(aResult, aColor); - else { - // TODO: remove the obtaining a color from the AIS object - // this does not happen never because: - // 1. The color can be changed only on results - // 2. The result can be not visualized in the viewer(e.g. Origin Construction) - AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject); - if (anAISObj.get()) { - aColor.resize(3); - anAISObj->getColor(aColor[0], aColor[1], aColor[2]); - } + // TODO: remove the obtaining a color from the AIS object + // this does not happen never because: + // 1. The color can be changed only on results + // 2. The result can be not visualized in the viewer(e.g. Origin Construction) + AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject); + if (anAISObj.get()) { + aColor.resize(3); + anAISObj->getColor(aColor[0], aColor[1], aColor[2]); } } if (!aColor.empty()) @@ -1539,8 +1565,10 @@ void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects) if (aColor.size() != 3) return; + if (!abortAllOperations()) + return; // 2. show the dialog to change the value - XGUI_ColorDialog* aDlg = new XGUI_ColorDialog(mainWindow()); + XGUI_ColorDialog* aDlg = new XGUI_ColorDialog(desktop()); aDlg->setColor(aColor); aDlg->move(QCursor::pos()); bool isDone = aDlg->exec() == QDialog::Accepted; @@ -1551,65 +1579,74 @@ void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects) // 3. abort the previous operation and start a new one SessionPtr aMgr = ModelAPI_Session::get(); - bool aWasOperation = aMgr->isOperation(); // keep this value - if (!aWasOperation) { - QString aDescription = contextMenuMgr()->action("COLOR_CMD")->text(); - aMgr->startOperation(aDescription.toStdString()); - } + QString aDescription = contextMenuMgr()->action("COLOR_CMD")->text(); + aMgr->startOperation(aDescription.toStdString()); // 4. set the value to all results + std::vector aColorResult = aDlg->getColor(); foreach(ObjectPtr anObj, theObjects) { ResultPtr aResult = std::dynamic_pointer_cast(anObj); if (aResult.get() != NULL) { - if (aResult->groupName() == ModelAPI_ResultPart::group()) { - ResultPartPtr aPart = std::dynamic_pointer_cast(aResult); - DocumentPtr aPartDoc = aPart->partDoc(); - // the document should be checked on null, because in opened document if the part - // has not been activated yet, the part document is empty - if (aPartDoc.get()) { - for (int i = 0; i < aPartDoc->size(ModelAPI_ResultBody::group()); i++) { - ObjectPtr aObject = aPartDoc->object(ModelAPI_ResultBody::group(), i); - ResultBodyPtr aBody = std::dynamic_pointer_cast(aObject); - std::vector aColorResult = aDlg->getColor(); - setColor(aBody, aColorResult); - } + ResultCompSolidPtr aCompsolidResult = std::dynamic_pointer_cast(aResult); + if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids + for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) { + setColor(aCompsolidResult->subResult(i), !isRandomColor ? aColorResult : aDlg->getRandomColor()); } } - else { - std::vector aColorResult = aDlg->getColor(); - setColor(aResult, aColorResult); - } + setColor(aResult, !isRandomColor ? aColorResult : aDlg->getRandomColor()); } } - if (!aWasOperation) - aMgr->finishOperation(); + aMgr->finishOperation(); updateCommandStatus(); } //************************************************************** +#define SET_DISPLAY_GROUP(aGroupName, aDisplay) \ +for (int i = 0; i < aDoc->size(aGroupName); i++) { \ + aDoc->object(aGroupName, i)->setDisplayed(aDisplay); \ +} void XGUI_Workshop::showObjects(const QObjectPtrList& theList, bool isVisible) { foreach (ObjectPtr aObj, theList) { - if (isVisible) { - aObj->setDisplayed(true); - //displayObject(aObj); + /* + ResultPartPtr aPartRes = std::dynamic_pointer_cast(aObj); + if (aPartRes) { + DocumentPtr aDoc = aPartRes->partDoc(); + SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), isVisible) + SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), isVisible) + SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), isVisible) } else { - aObj->setDisplayed(false); - //myDisplayer->erase(aObj, false); - } + */ + aObj->setDisplayed(isVisible); + //} } Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); - //myDisplayer->updateViewer(); } //************************************************************** void XGUI_Workshop::showOnlyObjects(const QObjectPtrList& theList) { + // Hide all displayed objects QObjectPtrList aList = myDisplayer->displayedObjects(); - foreach (ObjectPtr aObj, aList) - aObj->setDisplayed(false); - foreach (ObjectPtr aObj, theList) - aObj->setDisplayed(true); + foreach (ObjectPtr aObj, aList) { + if (module()->canEraseObject(aObj)) + aObj->setDisplayed(false); + } + + // Show only objects from the list + foreach (ObjectPtr aObj, theList) { + /* + ResultPartPtr aPartRes = std::dynamic_pointer_cast(aObj); + if (aPartRes) { + DocumentPtr aDoc = aPartRes->partDoc(); + SET_DISPLAY_GROUP(ModelAPI_ResultBody::group(), true) + SET_DISPLAY_GROUP(ModelAPI_ResultConstruction::group(), true) + SET_DISPLAY_GROUP(ModelAPI_ResultGroup::group(), true) + } else { + */ + aObj->setDisplayed(true); + //} + } Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); } @@ -1622,20 +1659,6 @@ void XGUI_Workshop::registerValidators() const ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); } -//************************************************************** -/*void XGUI_Workshop::displayAllResults() -{ - SessionPtr aMgr = ModelAPI_Session::get(); - DocumentPtr aRootDoc = aMgr->moduleDocument(); - displayDocumentResults(aRootDoc); - for (int i = 0; i < aRootDoc->size(ModelAPI_ResultPart::group()); i++) { - ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), i); - ResultPartPtr aPart = std::dynamic_pointer_cast(aObject); - displayDocumentResults(aPart->partDoc()); - } - myDisplayer->updateViewer(); -}*/ - //************************************************************** void XGUI_Workshop::displayDocumentResults(DocumentPtr theDoc) { @@ -1659,6 +1682,14 @@ void XGUI_Workshop::setDisplayMode(const QObjectPtrList& theList, int theMode) { foreach(ObjectPtr aObj, theList) { myDisplayer->setDisplayMode(aObj, (XGUI_Displayer::DisplayMode)theMode, false); + + ResultCompSolidPtr aCompsolidResult = std::dynamic_pointer_cast(aObj); + if (aCompsolidResult.get() != NULL) { // change colors for all sub-solids + for(int i = 0; i < aCompsolidResult->numberOfSubs(); i++) { + myDisplayer->setDisplayMode(aCompsolidResult->subResult(i), + (XGUI_Displayer::DisplayMode)theMode, false); + } + } } if (theList.size() > 0) myDisplayer->updateViewer(); @@ -1676,28 +1707,12 @@ void XGUI_Workshop::closeDocument() myDisplayer->eraseAll(); objectBrowser()->clearContent(); + module()->closeDocument(); + SessionPtr aMgr = ModelAPI_Session::get(); aMgr->closeAll(); } -//************************************************************** -bool XGUI_Workshop::displayObject(ObjectPtr theObj) -{ - if (!myModule->canDisplayObject(theObj)) - return false; - - ResultBodyPtr aBody = std::dynamic_pointer_cast(theObj); - if (aBody.get() != NULL) { - int aNb = myDisplayer->objectsCount(); - myDisplayer->display(theObj, false); - if (aNb == 0) - viewer()->fitAll(); - } else if (!(myIsLoadingData || myPartActivating)) - myDisplayer->display(theObj, false); - - return true; -} - void XGUI_Workshop::addHistoryMenu(QObject* theObject, const char* theSignal, const char* theSlot) { XGUI_HistoryMenu* aMenu = NULL; @@ -1720,9 +1735,9 @@ QList XGUI_Workshop::processHistoryList(const std::list std::list::const_iterator it = theList.cbegin(); for (; it != theList.cend(); it++) { QString anId = QString::fromStdString(*it); - bool isEditing = anId.endsWith(ModuleBase_Operation::EditSuffix()); + bool isEditing = anId.endsWith(ModuleBase_OperationFeature::EditSuffix()); if (isEditing) { - anId.chop(ModuleBase_Operation::EditSuffix().size()); + anId.chop(ModuleBase_OperationFeature::EditSuffix().size()); } ActionInfo anInfo; QAction* aContextMenuAct = myContextMenuMgr->actionByName(anId); @@ -1738,3 +1753,29 @@ QList XGUI_Workshop::processHistoryList(const std::list } return aResult; } + +void XGUI_Workshop::synchronizeViewer() +{ + SessionPtr aMgr = ModelAPI_Session::get(); + DocumentPtr aDoc = aMgr->activeDocument(); + + synchronizeGroupInViewer(aDoc, ModelAPI_ResultConstruction::group(), false); + synchronizeGroupInViewer(aDoc, ModelAPI_ResultBody::group(), false); + synchronizeGroupInViewer(aDoc, ModelAPI_ResultPart::group(), false); + synchronizeGroupInViewer(aDoc, ModelAPI_ResultGroup::group(), false); +} + +void XGUI_Workshop::synchronizeGroupInViewer(const DocumentPtr& theDoc, + const std::string& theGroup, + bool theUpdateViewer) +{ + ObjectPtr aObj; + int aSize = theDoc->size(theGroup); + for (int i = 0; i < aSize; i++) { + aObj = theDoc->object(theGroup, i); + if (aObj->isDisplayed()) + myDisplayer->display(aObj, false); + } + if (theUpdateViewer) + myDisplayer->updateViewer(); +}