X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FXGUI%2FXGUI_Workshop.cpp;h=e1081a65bd31f6ec7ccd0b511c2de04fbe6c0256;hb=225d6f1701361554ace1069e200002c18cd83771;hp=baa7594cb21d38702667a093818af4ab721a140b;hpb=409ad39d4655a87a91986bf9927e47bfc08b5341;p=modules%2Fshaper.git diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp old mode 100755 new mode 100644 index baa7594cb..1be4d47c6 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -1,32 +1,60 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// -//#include "XGUI_Constants.h" #include "XGUI_Workshop.h" #include "XGUI_ActionsMgr.h" +#include "XGUI_ActiveControlMgr.h" +#include "XGUI_ActiveControlSelector.h" #include "XGUI_MenuMgr.h" #include "XGUI_ColorDialog.h" #include "XGUI_DeflectionDialog.h" +#include "XGUI_TransparencyWidget.h" #include "XGUI_ContextMenuMgr.h" #include "XGUI_Displayer.h" #include "XGUI_ErrorDialog.h" #include "XGUI_ErrorMgr.h" +#include "XGUI_FacesPanel.h" +#include "XGUI_FacesPanelSelector.h" #include "XGUI_ModuleConnector.h" #include "XGUI_ObjectsBrowser.h" #include "XGUI_OperationMgr.h" #include "XGUI_PropertyPanel.h" +#include "XGUI_PropertyPanelSelector.h" +#include "XGUI_PropertyDialog.h" #include "XGUI_SalomeConnector.h" #include "XGUI_Selection.h" +#include "XGUI_SelectionActivate.h" #include "XGUI_SelectionMgr.h" #include "XGUI_Tools.h" #include "XGUI_ViewerProxy.h" #include "XGUI_WorkshopListener.h" -#include #include #include #include +#include +#include -#ifndef HAVE_SALOME +#ifdef HAVE_SALOME +#include +#include +#else #include #include #include @@ -36,9 +64,12 @@ #include #endif +#include + #include #include #include +#include #include #include #include @@ -47,10 +78,12 @@ #include #include #include +#include #include #include -#include #include +#include +#include //#include @@ -58,6 +91,14 @@ #include #include +#include +#include +#include +#include + +#include +#include + #include #include #include @@ -68,11 +109,12 @@ #include #include #include -#include #include #include #include #include +#include +#include #include #include @@ -81,6 +123,8 @@ #include #include #include +#include +#include #include @@ -104,14 +148,20 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #ifdef TINSPECTOR #include #include -#include -#include +#include +#include static TInspector_Communicator* MyTCommunicator; static Handle(VInspector_CallBack) MyVCallBack; @@ -128,28 +178,47 @@ static Handle(VInspector_CallBack) MyVCallBack; #include #endif +//#define DEBUG_WITH_MESSAGE_REPORT + QString XGUI_Workshop::MOVE_TO_END_COMMAND = QObject::tr("Move to the end"); +QString XGUI_Workshop::MOVE_TO_END_SPLIT_COMMAND = QObject::tr("Move to the end and split"); //#define DEBUG_DELETE //#define DEBUG_FEATURE_NAME //#define DEBUG_CLEAN_HISTORY +#ifdef HAVE_SALOME +static QString MyFilter(QObject::tr("SHAPER files (*.shaper *.cadbld)")); +static QString MyFilter2(QObject::tr("SHAPER files (*.shaper)")); +static QString MyExtension(".shaper"); +#else +static QString MyFilter(QObject::tr("CAD Builder files (*.cadbld);;All files (*.*)")); +static QString MyFilter2(QObject::tr("CAD Builder files (*.cadbld)")); +static QString MyExtension(".cadbld"); +#endif + +static QString MyImportPartFilter(QObject::tr("Part files (*.shaperpart);;All files (*.*)")); + + +//****************************************************** XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) : QObject(), - myCurrentDir(QString()), myModule(NULL), - mySalomeConnector(theConnector), - myPropertyPanel(0), myObjectBrowser(0), - myDisplayer(0) - //myViewerSelMode(TopAbs_FACE) + myPropertyPanel(0), + myFacesPanel(0), + myDisplayer(0), + mySalomeConnector(theConnector), + //myViewerSelMode(TopAbs_FACE), + myInspectionPanel(0) { mySelector = new XGUI_SelectionMgr(this); myModuleConnector = new XGUI_ModuleConnector(this); - myOperationMgr = new XGUI_OperationMgr(this, 0); + myOperationMgr = new XGUI_OperationMgr(this, myModuleConnector); ModuleBase_IWorkshop* aWorkshop = moduleConnector(); // Has to be defined first in order to get errors and messages from other components - myEventsListener = new XGUI_WorkshopListener(aWorkshop); + myEventsListener = new XGUI_WorkshopListener(this); + mySelectionActivate = new XGUI_SelectionActivate(aWorkshop); SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr(); #ifndef HAVE_SALOME @@ -167,7 +236,15 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) // Load translations QStringList aLangs; aLangs << "*_en.ts"; // load by default eng translations + + /// If version of OCCT is 7.4.0 or more then it means that + /// this is version of SALOME older then 9.4.0 +#if OCC_VERSION_HEX >= 0x070400 + QString aCurrLang = aResMgr->language(); +#else QString aCurrLang = aResMgr->stringValue("language", "language", "en"); +#endif + if(aCurrLang != "en") { aLangs << "*_" + aCurrLang + ".ts"; // then replace with translated files } @@ -189,6 +266,7 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateCommandStatus())); myActionsMgr = new XGUI_ActionsMgr(this); + myActiveControlMgr = new XGUI_ActiveControlMgr(myModuleConnector); myMenuMgr = new XGUI_MenuMgr(this); myErrorDlg = new XGUI_ErrorDialog(QApplication::desktop()); myContextMenuMgr = new XGUI_ContextMenuMgr(this); @@ -199,8 +277,6 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) //connect(myViewerProxy, SIGNAL(selectionChanged()), // myActionsMgr, SLOT(updateOnViewSelection())); - myOperationMgr->setWorkshop(aWorkshop); - myErrorMgr = new XGUI_ErrorMgr(this, aWorkshop); connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)), @@ -214,35 +290,14 @@ XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector) #ifndef HAVE_SALOME connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit())); - onTrihedronVisibilityChanged(true); + myDisplayer->displayTrihedron(true); #endif connect(myEventsListener, SIGNAL(errorOccurred(std::shared_ptr)), myErrorDlg, SLOT(addError(std::shared_ptr))); - //Config_PropManager::registerProp("Visualization", "object_default_color", "Object color", - // Config_Prop::Color, "225,225,225"); - - Config_PropManager::registerProp("Visualization", "result_body_color", "Result 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()); - - Config_PropManager::registerProp("Visualization", "body_deflection", - "Body deflection coefficient", - Config_Prop::Double, - ModelAPI_ResultBody::DEFAULT_DEFLECTION()); - - Config_PropManager::registerProp("Visualization", "construction_deflection", - "Construction deflection coefficient", - Config_Prop::Double, - ModelAPI_ResultConstruction::DEFAULT_DEFLECTION()); + Config_PropManager::registerProp("Visualization", "selection_color", "Selection color", + Config_Prop::Color, "255,255,255"); if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "face-selection", true)) myViewerSelMode.append(TopAbs_FACE); @@ -267,6 +322,9 @@ XGUI_Workshop::~XGUI_Workshop(void) delete myDisplayer; delete myDataModelXMLReader; + delete mySelectionActivate; + delete myMenuMgr; + clearTemporaryDir(); } //****************************************************** @@ -281,12 +339,31 @@ void XGUI_Workshop::startApplication() Config_PropManager::registerProp("Plugins", "default_path", "Default Path", Config_Prop::Directory, ""); + std::string aDir = Config_XMLReader::resourcesConfigFile(); + Config_PropManager::registerProp("Plugins", "import_initial_path", "Import initial directory", + Config_Prop::Directory, aDir); + +#ifdef _DEBUG + Config_PropManager::registerProp("Plugins", "create_part_by_start", "Create Part by Start", + Config_Prop::Boolean, "false"); + Config_PropManager::registerProp("Plugins", "show_hide_faces", "Show Hide Faces (on the right)", + Config_Prop::Boolean, "false"); +#endif registerValidators(); // Calling of loadCustomProps before activating module is required // by Config_PropManger to restore user-defined path to plugins ModuleBase_Preferences::loadCustomProps(); + std::vector aColor; + try { + aColor = Config_PropManager::color("Visualization", "selection_color"); + } + catch (...) { + } + if (aColor.size() == 3) + myDisplayer->setSelectionColor(aColor); + createModule(); #ifndef HAVE_SALOME @@ -301,11 +378,19 @@ void XGUI_Workshop::startApplication() SLOT(onTrihedronVisibilityChanged(bool))); emit applicationStarted(); + +#ifdef _DEBUG + bool aNewPart = Config_PropManager::boolean("Plugins", "create_part_by_start"); + if (aNewPart) { + module()->launchOperation("Part", false); // PartSetPlugin_Part::ID() + } +#endif } +//****************************************************** void XGUI_Workshop::activateModule() { - myModule->activateSelectionFilters(); + selectionActivate()->updateSelectionFilters(); connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)), myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr))); @@ -321,12 +406,11 @@ void XGUI_Workshop::activateModule() myOperationMgr->activate(); } +//****************************************************** void XGUI_Workshop::deactivateModule() { - myModule->deactivateSelectionFilters(); - // remove internal displayer filter - displayer()->deactivateSelectionFilters(); + displayer()->deactivateSelectionFilters(false); disconnect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)), myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr))); @@ -336,17 +420,10 @@ void XGUI_Workshop::deactivateModule() XGUI_Displayer* aDisplayer = displayer(); QObjectPtrList aDisplayed = aDisplayer->displayedObjects(); aDisplayer->deactivateObjects(aDisplayed, true); - Handle(AIS_InteractiveContext) aContext = viewer()->AISContext(); - Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(aDisplayer->getTrihedron()); - /// deactivate trihedron in selection modes - TColStd_ListOfInteger aTColModes; - aContext->ActivatedModes(aTrihedron, aTColModes); - TColStd_ListIteratorOfListOfInteger itr( aTColModes ); - for (; itr.More(); itr.Next() ) { - Standard_Integer aMode = itr.Value(); - aContext->Deactivate(aTrihedron, aMode); - } + selectionActivate()->deactivateTrihedronInSelectionModes(); + #ifdef BEFORE_TRIHEDRON_PATCH + //Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(aDisplayer->getTrihedron()); /// Trihedron problem: objects stayed in the viewer, should be removed manually /// otherwise in SALOME happens crash by HideAll in the viewer aContext->Remove(aTrihedron->Position(), true); @@ -371,7 +448,7 @@ void XGUI_Workshop::initMenu() QKeySequence::Undo, false, "MEN_DESK_EDIT"); QString aToolBarTitle = tr( "INF_DESK_TOOLBAR_STANDARD" ); - salomeConnector()->addActionInToolbar( aAction,aToolBarTitle ); + salomeConnector()->addActionInToolbar( aAction,aToolBarTitle ); connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onUndo())); addHistoryMenu(aAction, SIGNAL(updateUndoHistory(const QList&)), SLOT(onUndo(int))); @@ -385,27 +462,62 @@ void XGUI_Workshop::initMenu() 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(), + + //aAction = salomeConnector()->addDesktopCommand("AUTOCOMPUTE_CMD", tr("Auto rebuild"), + // tr("Blocks immediate apply of modifications"), + // QIcon(":pictures/autoapply.png"), QKeySequence(), // false, "MEN_DESK_EDIT"); //salomeConnector()->addActionInToolbar( aAction, aToolBarTitle ); - //connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRebuild())); - //salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); + //connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onAutoApply())); - aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Export native..."), - tr("Export the current document into a native file"), - QIcon(), QKeySequence(), - false, "MEN_DESK_FILE"); - connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs())); + salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT"); - aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Import native..."), + + // Add commands to a file menu + // Import sub-menu + aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Part set..."), tr("Import native file"), QIcon(), QKeySequence(), - false, "MEN_DESK_FILE"); + false, "MEN_DESK_FILE", tr("Import"), 10, 10); connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen())); - salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE"); + + aAction = salomeConnector()->addDesktopCommand("IMPORT_PART_CMD", tr("Part..."), + tr("Import structure of a part"), + QIcon(), QKeySequence(), + false, "MEN_DESK_FILE", tr("Import"), 10, 10); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportPart())); + + aAction = salomeConnector()->addDesktopCommand("IMPORT_SHAPE_CMD", tr("From CAD format..."), + tr("Import shape from a CAD format file"), + ModuleBase_IconFactory::loadIcon("icons/Exchange/import.png"), + QKeySequence(), false, "MEN_DESK_FILE", tr("Import"), 10, 10); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportShape())); + + aAction = salomeConnector()->addDesktopCommand("IMPORT_IMAGE_CMD", tr("Picture..."), + tr("Import a picture from an image file"), + QIcon(), + QKeySequence(), false, "MEN_DESK_FILE", tr("Import"), 10, 10); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportImage())); + + // Export sub-menu + aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Part set..."), + tr("Export the current document into a native file"), + QIcon(), QKeySequence(), + false, "MEN_DESK_FILE", tr("Export"), 10, 11); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs())); + + aAction = salomeConnector()->addDesktopCommand("EXPORT_PART_CMD", tr("Part..."), + tr("Export a part of the current document into a file"), + QIcon(), QKeySequence(), + false, "MEN_DESK_FILE", tr("Export"), 10, 11); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onExportPart())); + + aAction = salomeConnector()->addDesktopCommand("EXPORT_SHAPE_CMD", tr("To CAD format..."), + tr("Export shape to a CAD format file"), + ModuleBase_IconFactory::loadIcon("icons/Exchange/export.png"), + QKeySequence(), false, "MEN_DESK_FILE", tr("Export"), 10, 11); + connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onExportShape())); #else // File commands group @@ -440,16 +552,17 @@ void XGUI_Workshop::initMenu() SIGNAL(updateRedoHistory(const QList&)), SLOT(onRedo(int))); - //aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"), - // QIcon(":pictures/rebuild.png"), QKeySequence()); - //aCommand->connectTo(this, SLOT(onRebuild())); - - //aCommand->disable(); - aCommand = aGroup->addFeature("OPEN_CMD", tr("Open..."), tr("Open a new document"), QIcon(":pictures/open.png"), QKeySequence::Open); aCommand->connectTo(this, SLOT(onOpen())); + + aCommand = aGroup->addFeature("AUTOCOMPUTE_CMD", tr("Auto rebuild"), + tr("Blocks immediate apply of modifications"), + QIcon(":pictures/autoapply_start.png"), QKeySequence()); + aCommand->setChecked(ModelAPI_Session::get()->isAutoUpdateBlocked()); + aCommand->connectTo(this, SLOT(onAutoApply())); + aCommand = aGroup->addFeature("PREF_CMD", tr("Preferences"), tr("Edit preferences"), QIcon(":pictures/preferences.png"), QKeySequence::Preferences); aCommand->connectTo(this, SLOT(onPreferences())); @@ -461,6 +574,7 @@ void XGUI_Workshop::initMenu() } #ifndef HAVE_SALOME +//****************************************************** AppElements_Workbench* XGUI_Workshop::addWorkbench(const QString& theName) { AppElements_MainMenu* aMenuBar = myMainWindow->menuObject(); @@ -489,14 +603,26 @@ void XGUI_Workshop::onStartWaiting() //****************************************************** 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->commitOperation(); + } + } +} + +//****************************************************** +void XGUI_Workshop::onAcceptPlusActionClicked() +{ + XGUI_OperationMgr* anOperationMgr = operationMgr(); + if (anOperationMgr) { + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (anOperationMgr->currentOperation()); + if (aFOperation) { + if (myOperationMgr->commitOperation()) + module()->launchOperation(aFOperation->id(), false); } } } @@ -516,11 +642,62 @@ void XGUI_Workshop::onPreviewActionClicked() Events_Loop::loop()->send(aMsg); } + +//****************************************************** +void XGUI_Workshop::onHelpActionClicked() const +{ + XGUI_OperationMgr* anOperationMgr = operationMgr(); + if (anOperationMgr) { + ModuleBase_Operation* aOperation = anOperationMgr->currentOperation(); + if (aOperation) { + showHelpPage(aOperation->helpFileName()); + } + } +} + +void XGUI_Workshop::showHelpPage(const QString& thePage) const +{ + if (!thePage.isEmpty()) { + QString aDocDir; + const QChar aSep = QDir::separator(); +// QString platform; +// SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr(); +//#ifdef WIN32 +// platform = "winapplication"; +//#else +// platform = "application"; +//#endif +// QString aBrowserName = aResMgr->stringValue("ExternalBrowser", platform); + +#ifdef HAVE_SALOME + QString aDir(getenv("SHAPER_ROOT_DIR")); + if (!aDir.isEmpty()) { + aDocDir = aDir + aSep + "share" + aSep + "doc" + aSep + + "salome" + aSep + "gui" + aSep + "SHAPER"; + } +#else + QString aDir(getenv("CADBUILDER_ROOT_DIR")); + aDocDir = aDir + aSep + "doc" + aSep + "gui"; +#endif + QString aFileName = aDocDir + aSep + thePage; + if (QFile::exists(aFileName)) { + SUIT_Application* app = SUIT_Session::session()->activeApplication(); + if (app) + app->onHelpContextModule("SHAPER", aFileName); + else { + QUrl aUrl = QUrl::fromLocalFile(aFileName); + QDesktopServices::openUrl(aUrl); + } + } + } +} + + //****************************************************** void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer) { if (!myModule->canActivateSelection(theObject)) { - if (myDisplayer->isActive(theObject)) { + if (selectionActivate()->isActive(theObject)) { QObjectPtrList anObjects; anObjects.append(theObject); myDisplayer->deactivateObjects(anObjects, theUpdateViewer); @@ -546,6 +723,7 @@ bool XGUI_Workshop::isFeatureOfNested(const FeaturePtr& theFeature) return aHasNested; } +//****************************************************** void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation) { ModuleBase_OperationFeature* aFOperation = @@ -553,12 +731,11 @@ void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation) if (!aFOperation) return; - showPropertyPanel(); myPropertyPanel->cleanContent(); QList aWidgets; - if (!module()->createWidgets(theOperation, aWidgets)) { - QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation(); + QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation(); + if (!module()->createWidgets(aFOperation->feature(), aXmlRepr, aWidgets)) { ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector); aFactory.createWidget(myPropertyPanel->contentWidget()); aWidgets = aFactory.getModelWidgets(); @@ -568,13 +745,15 @@ void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation) FeaturePtr aFeature = aFOperation->feature(); std::string aFeatureKind = aFeature->getKind(); foreach (ModuleBase_ModelWidget* aWidget, aWidgets) { - if (!aWidget->attributeID().empty() && !aFeature->attribute(aWidget->attributeID()).get()) { - std::string anErrorMsg = "The feature '%1' has no attribute '%2' used by widget '%3'."; - Events_InfoMessage("XGUI_Workshop", anErrorMsg) - .arg(aFeatureKind).arg(aWidget->attributeID()) - .arg(aWidget->metaObject()->className()).send(); - myPropertyPanel->cleanContent(); - return; + if (aWidget->usesAttribute()) { + if (!aWidget->attributeID().empty() && !aFeature->attribute(aWidget->attributeID()).get()) { + std::string anErrorMsg = "The feature '%1' has no attribute '%2' used by widget '%3'."; + Events_InfoMessage("XGUI_Workshop", anErrorMsg) + .arg(aFeatureKind).arg(aWidget->attributeID()) + .arg(aWidget->metaObject()->className()).send(); + myPropertyPanel->cleanContent(); + return; + } } } // for performance purpose, flush should be done after all controls are filled @@ -588,17 +767,27 @@ void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation) aWidget->restoreValue(); aWidget->enableFocusProcessing(); } - ModuleBase_Tools::flushUpdated(aFeature); - // update visible state of Preview button + std::shared_ptr aFeatureInfo; #ifdef HAVE_SALOME - bool anIsAutoPreview = - mySalomeConnector->featureInfo(aFeatureKind.c_str())->isAutoPreview(); + aFeatureInfo = mySalomeConnector->featureInfo(aFeatureKind.c_str()); #else AppElements_MainMenu* aMenuBar = mainWindow()->menuObject(); AppElements_Command* aCommand = aMenuBar->feature(aFeatureKind.c_str()); - bool anIsAutoPreview = aCommand && aCommand->featureMessage()->isAutoPreview(); + if (aCommand) + aFeatureInfo = aCommand->featureMessage(); #endif + bool anIsAutoPreview = true; + if (aFeatureInfo.get()) { + anIsAutoPreview = aFeatureInfo->isAutoPreview(); + theOperation->setHelpFileName(aFeatureInfo->helpFileName().c_str()); + } else { + std::string aXmlCfg, aDescription; + module()->getXMLRepresentation(aFeatureKind, aXmlCfg, aDescription); + ModuleBase_WidgetFactory aFactory(aXmlCfg, moduleConnector()); + anIsAutoPreview = aFactory.widgetAPI()->getBooleanAttribute(FEATURE_AUTO_PREVIEW, true); + } + if (!anIsAutoPreview) { myPropertyPanel->findButton(PROP_PANEL_PREVIEW)->setVisible(true); // send signal about preview should not be computed automatically, click on preview @@ -607,23 +796,35 @@ void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation) new Events_Message(Events_Loop::eventByName(EVENT_PREVIEW_BLOCKED))); Events_Loop::loop()->send(aMsg); } + // if update happens after preview is blocked, it does nothing when blocked + // it improves performance for valid objects on feature start + ModuleBase_Tools::flushUpdated(aFeature); + myPropertyPanel->setModelWidgets(aWidgets); aFOperation->setPropertyPanel(myPropertyPanel); myModule->propertyPanelDefined(theOperation); #ifndef DEBUG_FEATURE_NAME - myPropertyPanel->setWindowTitle(theOperation->getDescription()->description()); + myPropertyPanel->setWindowTitle(ModuleBase_Tools::translate("workshop", + theOperation->getDescription()->description().toStdString())); #else std::string aFeatureName = aFeature->name(); myPropertyPanel->setWindowTitle(QString("%1: %2") - .arg(theOperation->getDescription()->description()) - .arg(aFeatureName.c_str())); + .arg(translate(theOperation->getDescription()->description())) + .arg(translate(aFeatureName.c_str()))); #endif myErrorMgr->setPropertyPanel(myPropertyPanel); + if (Config_PropManager::boolean("Windows", "use_hide_faces_panel")) { + theOperation->setHideFacesVisible(myFacesPanel->isVisible()); + if (aFeatureInfo.get() && aFeatureInfo->isHideFacesPanel() && !myFacesPanel->isVisible()) + myFacesPanel->show(); + } + showPanel(myPropertyPanel); } +//****************************************************** void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect) { XGUI_PropertyPanel* aPropertyPanel = propertyPanel(); @@ -653,13 +854,18 @@ void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation) if (theOperation->getDescription()->hasXmlRepresentation()) { //!< No need for property panel fillPropertyPanel(theOperation); connectToPropertyPanel(true); + ModuleBase_OperationFeature* aFOperation = dynamic_cast + (theOperation); + if (aFOperation) + myPropertyPanel->updateApplyPlusButton(aFOperation->feature()); + else + myPropertyPanel->updateApplyPlusButton(FeaturePtr()); } updateCommandStatus(); myModule->operationResumed(theOperation); } - //****************************************************** void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation) { @@ -673,7 +879,7 @@ void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation) ModuleBase_ISelection* aSel = mySelector->selection(); QObjectPtrList aObj = aSel->selectedPresentations(); //!< No need for property panel - hidePropertyPanel(); + hidePanel(myPropertyPanel); myPropertyPanel->cleanContent(); connectToPropertyPanel(false); @@ -684,32 +890,39 @@ void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation) QObjectPtrList anObjects; FeaturePtr aFeature = aFOperation->feature(); if (aFeature.get()) { // feature may be not created (plugin load fail) - if (myDisplayer->isVisible(aFeature) && !myDisplayer->isActive(aFeature)) + if (myDisplayer->isVisible(aFeature) && !selectionActivate()->isActive(aFeature)) anObjects.append(aFeature); std::list aResults; ModelAPI_Tools::allResults(aFeature, aResults); std::list::const_iterator aIt; for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) { ResultPtr anObject = *aIt; - if (myDisplayer->isVisible(anObject) && !myDisplayer->isActive(anObject)) { + if (myDisplayer->isVisible(anObject) && !selectionActivate()->isActive(anObject)) { anObjects.append(anObject); } } } activateObjectsSelection(anObjects); -} + if (Config_PropManager::boolean("Windows", "use_hide_faces_panel")) { + if (!theOperation->isHideFacesVisible()) + myFacesPanel->close(); + } +} +//****************************************************** void XGUI_Workshop::onOperationCommitted(ModuleBase_Operation* theOperation) { myModule->operationCommitted(theOperation); } +//****************************************************** void XGUI_Workshop::onOperationAborted(ModuleBase_Operation* theOperation) { myModule->operationAborted(theOperation); } +//****************************************************** void XGUI_Workshop::setGrantedFeatures(ModuleBase_Operation* theOperation) { ModuleBase_OperationFeature* aFOperation = @@ -779,7 +992,6 @@ void XGUI_Workshop::onOpen() //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( desktop(), tr("Save current file"), tr("The document is modified, save before opening another?"), @@ -789,25 +1001,30 @@ void XGUI_Workshop::onOpen() } else if (anAnswer == QMessageBox::Cancel) { return; } - myCurrentDir = ""; + myCurrentFile = QString(); } //show file dialog, check if readable and open - QString aDirectory = QFileDialog::getExistingDirectory(desktop(), tr("Select directory")); - openDirectory(aDirectory); + qreal aRatio = ModuleBase_Tools::currentPixelRatio(); + // If the ratio is > 1 (HD screen) then QT has a bug in + // displaying of system open file dialog (too small) + QString aFile = QFileDialog::getOpenFileName(desktop(), tr("Open file"), QString(), MyFilter, + Q_NULLPTR, ((aRatio > 1)? QFileDialog::DontUseNativeDialog : QFileDialog::Options())); + if (!aFile.isNull()) + openFile(aFile); } //****************************************************** -void XGUI_Workshop::openDirectory(const QString& theDirectory) +void XGUI_Workshop::openFile(const QString& theDirectory) { - myCurrentDir = theDirectory; - if (myCurrentDir.isEmpty()) + myCurrentFile = theDirectory; + if (myCurrentFile.isEmpty()) return; - QFileInfo aFileInfo(myCurrentDir); + QFileInfo aFileInfo(myCurrentFile); if (!aFileInfo.exists() || !aFileInfo.isReadable()) { QMessageBox::critical(desktop(), tr("Warning"), tr("Unable to open the file.")); - myCurrentDir = ""; + myCurrentFile = QString(); return; } @@ -815,7 +1032,12 @@ void XGUI_Workshop::openDirectory(const QString& theDirectory) module()->closeDocument(); SessionPtr aSession = ModelAPI_Session::get(); aSession->closeAll(); - aSession->load(myCurrentDir.toLatin1().constData()); + + clearTemporaryDir(); + if (!XGUI_CompressFiles::uncompress(myCurrentFile, myTmpDir.path())) + return; + + aSession->load(myTmpDir.path().toLatin1().constData()); myObjectBrowser->rebuildDataTree(); // Open first level of data tree @@ -826,8 +1048,22 @@ void XGUI_Workshop::openDirectory(const QString& theDirectory) updateCommandStatus(); #ifndef HAVE_SALOME - myMainWindow->setCurrentDir(myCurrentDir, true); + myMainWindow->setCurrentDir(myCurrentFile, true); +#endif + +#ifdef _DEBUG + bool aNewPart = Config_PropManager::boolean("Plugins", "create_part_by_start"); + if (aNewPart) { + int aSize = aRootDoc->size(ModelAPI_ResultPart::group()); + if (aSize > 0 ) { + ObjectPtr anObject = aRootDoc->object(ModelAPI_ResultPart::group(), 0); + ResultPartPtr aPart = std::dynamic_pointer_cast(anObject); + if (aPart.get()) + aPart->activate(); + } + } #endif + QApplication::restoreOverrideCursor(); } @@ -846,6 +1082,8 @@ void XGUI_Workshop::onNew() QMdiSubWindow* aWnd = myMainWindow->viewer()->createView(); aWnd->showMaximized(); updateCommandStatus(); + PyConsole_Console* aConsole = myMainWindow->pythonConsole(); + connect(aConsole, SIGNAL(scriptLoaded()), SLOT(updateCommandStatus())); #endif myContextMenuMgr->connectViewer(); QApplication::restoreOverrideCursor(); @@ -879,8 +1117,7 @@ void XGUI_Workshop::onPreferences() ModuleBase_Preferences::editPreferences(aModif); if (aModif.size() > 0) { QString aSection; - foreach (ModuleBase_Pref aPref, aModif) - { + foreach (ModuleBase_Pref aPref, aModif) { aSection = aPref.first; if (aSection == ModuleBase_Preferences::VIEWER_SECTION) { myMainWindow->viewer()->updateFromResources(); @@ -888,6 +1125,15 @@ void XGUI_Workshop::onPreferences() myMainWindow->menuObject()->updateFromResources(); } } + std::vector aColor; + try { + aColor = Config_PropManager::color("Visualization", "selection_color"); + } + catch (...) { + } + if (aColor.size() == 3) + displayer()->setSelectionColor(aColor); + displayer()->redisplayObjects(); } } @@ -897,60 +1143,62 @@ void XGUI_Workshop::onPreferences() void XGUI_Workshop::onTrihedronVisibilityChanged(bool theState) { XGUI_Displayer* aDisplayer = displayer(); - if (aDisplayer) + if (aDisplayer) { aDisplayer->displayTrihedron(theState); + aDisplayer->updateViewer(); + } } //****************************************************** bool XGUI_Workshop::onSave() { - if(!abortAllOperations()) + if(!myOperationMgr->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage)) return false; - if (myCurrentDir.isEmpty()) { + if (myCurrentFile.isEmpty()) { return onSaveAs(); } + SessionPtr aMgr = ModelAPI_Session::get(); + if (aMgr->isAutoUpdateBlocked()) + aMgr->blockAutoUpdate(false); + std::list aFiles; - saveDocument(myCurrentDir, aFiles); - updateCommandStatus(); + // issue #2899: create a temporary directory, save and then remove it +#ifdef HAVE_SALOME + std::string aTmpDir = XGUI_Tools::getTmpDirByEnv("SALOME_TMP_DIR"); +#else + std::string aTmpDir = XGUI_Tools::getTmpDirByEnv(""); +#endif + saveDocument(QString(aTmpDir.c_str()), aFiles); + bool aResult = XGUI_CompressFiles::compress(myCurrentFile, aFiles); + XGUI_Tools::removeTemporaryFiles(aTmpDir, aFiles); + + if (aResult) { + updateCommandStatus(); #ifndef HAVE_SALOME myMainWindow->setModifiedState(false); #endif - return true; + } + return aResult; } //****************************************************** bool XGUI_Workshop::onSaveAs() { - if(!abortAllOperations()) - return false; - QFileDialog dialog(desktop()); - dialog.setWindowTitle(tr("Select directory to save files...")); - dialog.setFileMode(QFileDialog::Directory); - dialog.setFilter(QDir::AllDirs); - dialog.setOptions(QFileDialog::HideNameFilterDetails | QFileDialog::ShowDirsOnly); - dialog.setViewMode(QFileDialog::Detail); - - if (!dialog.exec()) { + if(!myOperationMgr->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage)) return false; - } - - QString aTempDir = dialog.selectedFiles().first(); - QDir aDir(aTempDir); - if (aDir.exists() && !aDir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).isEmpty()) { - int answer = QMessageBox::question( - desktop(), - // Title of the dialog which asks user if he wants to save study - // in existing non-empty folder - tr("Save"), - tr("The directory already contains some files, save anyway?"), - QMessageBox::Save | QMessageBox::Cancel); - if (answer == QMessageBox::Cancel) { - return false; + qreal aRatio = ModuleBase_Tools::currentPixelRatio(); + myCurrentFile = QFileDialog::getSaveFileName(desktop(), tr("Select name to save file..."), + QString(), MyFilter2, + Q_NULLPTR, ((aRatio > 1) ? QFileDialog::DontUseNativeDialog : QFileDialog::Options())); + if (!myCurrentFile.isNull()) { + if (!myCurrentFile.endsWith(MyExtension)) { + myCurrentFile += MyExtension; } } - myCurrentDir = aTempDir; + else + return false; #ifndef HAVE_SALOME - myMainWindow->setCurrentDir(myCurrentDir, false); + myMainWindow->setCurrentDir(myCurrentFile, false); myMainWindow->setModifiedState(false); #endif return onSave(); @@ -959,85 +1207,93 @@ bool XGUI_Workshop::onSaveAs() //****************************************************** void XGUI_Workshop::onUndo(int theTimes) { - objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); - SessionPtr aMgr = ModelAPI_Session::get(); - std::list aUndoList = aMgr->undoList(); - 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(); - } - std::list::const_iterator aIt = aUndoList.cbegin(); - for (int i = 0; (i < theTimes) && (aIt != aUndoList.cend()); ++i, ++aIt) { - aMgr->undo(); - if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND) - myObjectBrowser->rebuildDataTree(); - } - - operationMgr()->updateApplyOfOperations(); - updateCommandStatus(); + processUndoRedo(ActionUndo, theTimes); + myObjectBrowser->updateAllIndexes(1); } //****************************************************** void XGUI_Workshop::onRedo(int theTimes) { + processUndoRedo(ActionRedo, theTimes); + myObjectBrowser->updateAllIndexes(1); +} + +//****************************************************** +void XGUI_Workshop::processUndoRedo(const ModuleBase_ActionType theActionType, int theTimes) +{ + ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget(); + if (anActiveWidget) { + ActionIntParamPtr aParam(new ModuleBase_ActionIntParameter(theTimes)); + if (anActiveWidget->processAction(theActionType, aParam)) + return; + } + else + { + XGUI_FacesPanel * anFacePannel = facesPanel(); + if(ActionUndo == theActionType && anFacePannel->isActivePanel()) + { + anFacePannel->processUndo(); + return; + } + } // the viewer update should be blocked in order to avoid the features blinking. For the created // feature a results are created, the flush of the created signal caused the viewer redisplay for // each created result. After a redisplay signal is flushed. So, the viewer update is blocked // until redo of all possible objects happens bool isUpdateEnabled = myDisplayer->enableUpdateViewer(false); - objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); + int aTimes = theTimes; SessionPtr aMgr = ModelAPI_Session::get(); - std::list aRedoList = aMgr->redoList(); if (aMgr->isOperation()) { + XGUI_OperationMgr* aOpMgr = operationMgr(); /// this is important for nested operations /// when sketch operation is active, this condition is false and /// the sketch operation is not aborted - operationMgr()->onAbortOperation(); + if (aOpMgr->canStopOperation(aOpMgr->currentOperation())) { + aOpMgr->abortOperation(aOpMgr->currentOperation()); + aTimes--; + } + else + { + myDisplayer->enableUpdateViewer(isUpdateEnabled); + return; + } } - std::list::const_iterator aIt = aRedoList.cbegin(); - for (int i = 0; (i < theTimes) && (aIt != aRedoList.cend()); ++i, ++aIt) { - aMgr->redo(); - if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND) + objectBrowser()->treeView()->setCurrentIndex(QModelIndex()); + std::list anActionList = theActionType == ActionUndo ? aMgr->undoList() + : aMgr->redoList(); + std::list::const_iterator aIt = anActionList.cbegin(); + for (int i = 0; (i < aTimes) && (aIt != anActionList.cend()); ++i, ++aIt) { + if (theActionType == ActionUndo) + aMgr->undo(); + else + aMgr->redo(); + + if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND || + QString((*aIt).c_str()) == MOVE_TO_END_SPLIT_COMMAND) myObjectBrowser->rebuildDataTree(); } operationMgr()->updateApplyOfOperations(); + facesPanel()->reset(true); updateCommandStatus(); // unblock the viewer update functionality and make update on purpose myDisplayer->enableUpdateViewer(isUpdateEnabled); myDisplayer->updateViewer(); + // Clear messages in status bar from previous operations if exists + setStatusBarMessage(""); } -//****************************************************** -//void XGUI_Workshop::onRebuild() -//{ -// SessionPtr aMgr = ModelAPI_Session::get(); -// bool aWasOperation = aMgr->isOperation(); // keep this value -// if (!aWasOperation) { -// aMgr->startOperation("Rebuild"); -// } -// static const Events_ID aRebuildEvent = Events_Loop::loop()->eventByName("Rebuild"); -// Events_Loop::loop()->send(std::shared_ptr( -// new Events_Message(aRebuildEvent, this))); -// if (!aWasOperation) { -// aMgr->finishOperation(); -// } -// updateCommandStatus(); -//} - //****************************************************** void XGUI_Workshop::onWidgetStateChanged(int thePreviousState) { - ModuleBase_ModelWidget* anActiveWidget = 0; - ModuleBase_Operation* anOperation = myOperationMgr->currentOperation(); - if (anOperation) { - ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel(); - if (aPanel) - anActiveWidget = aPanel->activeWidget(); - } + ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget(); + //ModuleBase_Operation* anOperation = myOperationMgr->currentOperation(); + //if (anOperation) { + // ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel(); + // if (aPanel) + // anActiveWidget = aPanel->activeWidget(); + //} if (anActiveWidget) operationMgr()->onValidateOperation(); @@ -1066,11 +1322,79 @@ void XGUI_Workshop::onValuesChanged() } } +//****************************************************** void XGUI_Workshop::onWidgetObjectUpdated() { operationMgr()->onValidateOperation(); + myDisplayer->updateViewer(); +} + +//****************************************************** +void XGUI_Workshop::onImportPart() +{ + if (abortAllOperations()) { + ModuleBase_OperationFeature* anImportPartOp = dynamic_cast( + module()->createOperation(ExchangePlugin_ImportPart::ID())); + anImportPartOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() + + "importFeature.html"); + myPropertyPanel->updateApplyPlusButton(anImportPartOp->feature()); + operationMgr()->startOperation(anImportPartOp); + } +} + +//****************************************************** +void XGUI_Workshop::onImportShape() +{ + if (abortAllOperations()) { + ModuleBase_OperationFeature* anImportOp = dynamic_cast( + module()->createOperation(ExchangePlugin_Import::ID())); + anImportOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() + + "importFeature.html"); + myPropertyPanel->updateApplyPlusButton(anImportOp->feature()); + operationMgr()->startOperation(anImportOp); + } +} + +//****************************************************** +void XGUI_Workshop::onImportImage() +{ + if (abortAllOperations()) { + ModuleBase_OperationFeature* anImportOp = dynamic_cast( + module()->createOperation(ExchangePlugin_Import_Image::ID())); + anImportOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() + + "importFeature.html"); + myPropertyPanel->updateApplyPlusButton(anImportOp->feature()); + operationMgr()->startOperation(anImportOp); + } +} + +//****************************************************** +void XGUI_Workshop::onExportShape() +{ + if (abortAllOperations()) { + ModuleBase_OperationFeature* anExportOp = dynamic_cast( + module()->createOperation(ExchangePlugin_ExportFeature::ID())); + anExportOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() + + "exportFeature.html"); + myPropertyPanel->updateApplyPlusButton(anExportOp->feature()); + operationMgr()->startOperation(anExportOp); + } +} + +//****************************************************** +void XGUI_Workshop::onExportPart() +{ + if (abortAllOperations()) { + ModuleBase_OperationFeature* anExportPartOp = dynamic_cast( + module()->createOperation(ExchangePlugin_ExportPart::ID())); + anExportPartOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() + + "exportFeature.html"); + myPropertyPanel->updateApplyPlusButton(anExportPartOp->feature()); + operationMgr()->startOperation(anExportPartOp); + } } +//****************************************************** ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule) { QString libName = QString::fromStdString(library(theModule.toStdString())); @@ -1083,7 +1407,7 @@ ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule) CREATE_FUNC crtInst = 0; #ifdef WIN32 - HINSTANCE modLib = ::LoadLibrary((LPTSTR) qPrintable(libName)); + HINSTANCE modLib = ::LoadLibraryA(qPrintable(libName)); if (!modLib) { LPVOID lpMsgBuf; ::FormatMessage( @@ -1166,10 +1490,29 @@ void XGUI_Workshop::updateCommandStatus() if (aMgr->hasModuleDocument()) { foreach(QAction* aCmd, aCommands) { QString aId = aCmd->data().toString(); - if (aId == "UNDO_CMD") - aCmd->setEnabled(myModule->canUndo()); - else if (aId == "REDO_CMD") - aCmd->setEnabled(myModule->canRedo()); + if (aId == "UNDO_CMD") { + bool isActionEnabled = false; + // if ultimate is true -> using result of operation only, or using OR combination + ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget(); + if (anActiveWidget && anActiveWidget->canProcessAction(ActionUndo, isActionEnabled)) + aCmd->setEnabled(isActionEnabled); + else + aCmd->setEnabled(myModule->canUndo()); + } + else if (aId == "REDO_CMD") { + bool isActionEnabled = false; + // if ultimate is true -> using result of operation only, or using OR combination + ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget(); + if (anActiveWidget && anActiveWidget->canProcessAction(ActionRedo, isActionEnabled)) + aCmd->setEnabled(isActionEnabled); + else + aCmd->setEnabled(myModule->canRedo()); + } + else if (aId == "AUTOCOMPUTE_CMD") { + aCmd->setIcon(aMgr->isAutoUpdateBlocked() ? + QIcon(":pictures/autoapply_stop.png") : + QIcon(":pictures/autoapply_start.png")); + } else // Enable all commands aCmd->setEnabled(true); @@ -1190,14 +1533,24 @@ void XGUI_Workshop::updateCommandStatus() emit commandStatusUpdated(); } +//****************************************************** void XGUI_Workshop::updateHistory() { - std::list aUndoList = ModelAPI_Session::get()->undoList(); - QList aUndoRes = processHistoryList(aUndoList); - emit updateUndoHistory(aUndoRes); + bool isActionEnabled = false; + ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget(); + QList aUndoRes; + QList aRedoRes; + if (anActiveWidget && anActiveWidget->canProcessAction(ActionUndo, isActionEnabled)) { + aUndoRes = anActiveWidget->actionsList(ActionUndo); + aRedoRes = anActiveWidget->actionsList(ActionRedo); + } else { + std::list aUndoList = ModelAPI_Session::get()->undoList(); + aUndoRes = processHistoryList(aUndoList); - std::list aRedoList = ModelAPI_Session::get()->redoList(); - QList aRedoRes = processHistoryList(aRedoList); + std::list aRedoList = ModelAPI_Session::get()->redoList(); + aRedoRes = processHistoryList(aRedoList); + } + emit updateUndoHistory(aUndoRes); emit updateRedoHistory(aRedoRes); } @@ -1206,15 +1559,17 @@ QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent) { QDockWidget* aObjDock = new QDockWidget(theParent); aObjDock->setAllowedAreas(Qt::LeftDockWidgetArea | - Qt::RightDockWidgetArea | - Qt::BottomDockWidgetArea); + Qt::RightDockWidgetArea); aObjDock->setWindowTitle(tr("Object browser")); aObjDock->setStyleSheet( "::title { position: relative; padding-left: 5px; text-align: left center }"); - myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock); - myObjectBrowser->setXMLReader(myDataModelXMLReader); + myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock, this); + myObjectBrowser->initialize(myModule->rootNode()); myModule->customizeObjectBrowser(myObjectBrowser); aObjDock->setWidget(myObjectBrowser); + aObjDock->setObjectName("Object browser"); + + connect(myObjectBrowser, SIGNAL(sizeChanged()), SLOT(onDockSizeChanged())); myContextMenuMgr->connectObjectBrowser(); return aObjDock; @@ -1231,25 +1586,77 @@ void XGUI_Workshop::createDockWidgets() QDockWidget* aObjDock = createObjectBrowser(aDesktop); aDesktop->addDockWidget(Qt::LeftDockWidgetArea, aObjDock); myPropertyPanel = new XGUI_PropertyPanel(aDesktop, myOperationMgr); + myActiveControlMgr->addSelector(new XGUI_PropertyPanelSelector(myPropertyPanel)); + myPropertyPanel->setupActions(myActionsMgr); myPropertyPanel->setAllowedAreas(Qt::LeftDockWidgetArea | - Qt::RightDockWidgetArea | - Qt::BottomDockWidgetArea); + Qt::RightDockWidgetArea); aDesktop->addDockWidget(Qt::LeftDockWidgetArea, myPropertyPanel); - hidePropertyPanel(); ///addSelector(new XGUI_FacesPanelSelector(myFacesPanel)); + myFacesPanel->setAllowedAreas(Qt::LeftDockWidgetArea | + Qt::RightDockWidgetArea | + Qt::BottomDockWidgetArea); + connect(myFacesPanel, SIGNAL(closed()), myFacesPanel, SLOT(onClosed())); + + myInspectionPanel = new XGUI_InspectionPanel(aDesktop, this); + myInspectionPanel->setAllowedAreas(Qt::LeftDockWidgetArea | + Qt::RightDockWidgetArea); + aDesktop->addDockWidget(Qt::RightDockWidgetArea, myInspectionPanel); + + myInspectionPanel->hide(); + + aDesktop->addDockWidget( +#ifdef HAVE_SALOME + Qt::RightDockWidgetArea, +#else + Qt::LeftDockWidgetArea, +#endif + myFacesPanel); + hidePanel(myFacesPanel); ///addDockWidget(Qt::RightDockWidgetArea, myFacesPanel); + showPanel(myFacesPanel); + } +#endif hideObjectBrowser(); + +#ifndef HAVE_SALOME +#ifdef _DEBUG + if (!aShowOnTheRight) + { +#endif // _DEBUG + aDesktop->tabifyDockWidget(myFacesPanel, aObjDock); +#ifdef _DEBUG + } +#endif // _DEBUG + +#endif // HAVE_SALOME + aDesktop->tabifyDockWidget(aObjDock, myPropertyPanel); myPropertyPanel->installEventFilter(myOperationMgr); QAction* aOkAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept); connect(aOkAct, SIGNAL(triggered()), this, SLOT(onAcceptActionClicked())); + QAction* aOkContAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptPlus); + connect(aOkContAct, SIGNAL(triggered()), this, SLOT(onAcceptPlusActionClicked())); + QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort); connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation())); QAction* aPreviewAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Preview); connect(aPreviewAct, SIGNAL(triggered()), this, SLOT(onPreviewActionClicked())); + QAction* aHelpAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Help); + connect(aHelpAct, SIGNAL(triggered()), this, SLOT(onHelpActionClicked())); + connect(myPropertyPanel, SIGNAL(keyReleased(QObject*, QKeyEvent*)), myOperationMgr, SLOT(onKeyReleased(QObject*, QKeyEvent*))); connect(myPropertyPanel, SIGNAL(enterClicked(QObject*)), @@ -1257,47 +1664,50 @@ void XGUI_Workshop::createDockWidgets() } //****************************************************** -void XGUI_Workshop::showPropertyPanel() +void XGUI_Workshop::showPanel(QDockWidget* theDockWidget) { - QAction* aViewAct = myPropertyPanel->toggleViewAction(); - ///setEnabled(true); - myPropertyPanel->show(); - myPropertyPanel->raise(); + if (theDockWidget == myPropertyPanel) { + QAction* aViewAct = myPropertyPanel->toggleViewAction(); + ///setEnabled(true); + } + theDockWidget->show(); + theDockWidget->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) - ModuleBase_Tools::activateWindow(myPropertyPanel, "XGUI_Workshop::showPropertyPanel()"); - ModuleBase_Tools::setFocus(myPropertyPanel, "XGUI_Workshop::showPropertyPanel()"); + //ModuleBase_Tools::setFocus(theDockWidget, "XGUI_Workshop::showPanel()"); } //****************************************************** -void XGUI_Workshop::hidePropertyPanel() +void XGUI_Workshop::hidePanel(QDockWidget* theDockWidget) { - QAction* aViewAct = myPropertyPanel->toggleViewAction(); - ///setEnabled(false); - myPropertyPanel->hide(); + if (theDockWidget && theDockWidget == myPropertyPanel) { + QAction* aViewAct = theDockWidget->toggleViewAction(); + ///setEnabled(false); + } + theDockWidget->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, + // in SALOME mode, work-stack 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 SHAPER package QMainWindow* aDesktop = desktop(); - ModuleBase_Tools::activateWindow(aDesktop, "XGUI_Workshop::hidePropertyPanel()"); - ModuleBase_Tools::setFocus(aDesktop, "XGUI_Workshop::showPropertyPanel()"); + ModuleBase_Tools::setFocus(aDesktop, "XGUI_Workshop::hidePanel()"); } //****************************************************** void XGUI_Workshop::showObjectBrowser() { - if (!isSalomeMode()) + if (!isSalomeMode()) { myObjectBrowser->parentWidget()->show(); + } } //****************************************************** @@ -1322,35 +1732,50 @@ ModuleBase_IViewer* XGUI_Workshop::salomeViewer() const //************************************************************** void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) { - QObjectPtrList aObjects = mySelector->selection()->selectedObjects(); + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); if (theId == "DELETE_CMD") deleteObjects(); else if (theId == "CLEAN_HISTORY_CMD") cleanHistory(); - else if (theId == "MOVE_CMD") - moveObjects(); + else if (theId == "MOVE_CMD" || theId == "MOVE_SPLIT_CMD") + moveObjects(theId == "MOVE_SPLIT_CMD"); else if (theId == "COLOR_CMD") - changeColor(aObjects); - else if (theId == "DEFLECTION_CMD") - changeDeflection(aObjects); - else if (theId == "SHOW_CMD") { - showObjects(aObjects, true); + changeColor(anObjects); + else if (theId == "AUTOCOLOR_CMD") + changeAutoColor(anObjects); + else if (theId == "ISOLINES_CMD") + changeIsoLines(anObjects); + else if (theId == "SHOW_ISOLINES_CMD") { + foreach(ObjectPtr aObj, anObjects) { + ResultPtr aResult = std::dynamic_pointer_cast(aObj); + if (aResult.get()) + ModelAPI_Tools::showIsoLines(aResult, !ModelAPI_Tools::isShownIsoLines(aResult)); + } + mySelector->clearSelection(); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + } + else if (theId == "DEFLECTION_CMD") + changeDeflection(anObjects); + else if (theId == "TRANSPARENCY_CMD") + changeTransparency(anObjects); + else if (theId == "SHOW_CMD") { + showObjects(anObjects, true); mySelector->updateSelectionBy(ModuleBase_ISelection::Browser); updateCommandStatus(); } else if (theId == "HIDE_CMD") { - showObjects(aObjects, false); + showObjects(anObjects, false); updateCommandStatus(); } else if (theId == "SHOW_ONLY_CMD") { - showOnlyObjects(aObjects); + showOnlyObjects(anObjects); mySelector->updateSelectionBy(ModuleBase_ISelection::Browser); updateCommandStatus(); } else if (theId == "SHADING_CMD") - setDisplayMode(aObjects, XGUI_Displayer::Shading); + setDisplayMode(anObjects, XGUI_Displayer::Shading); else if (theId == "WIREFRAME_CMD") - setDisplayMode(aObjects, XGUI_Displayer::Wireframe); + setDisplayMode(anObjects, XGUI_Displayer::Wireframe); else if (theId == "HIDEALL_CMD") { QObjectPtrList aList = myDisplayer->displayedObjects(); foreach (ObjectPtr aObj, aList) { @@ -1358,22 +1783,42 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) aObj->setDisplayed(false); } Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); +#ifdef HAVE_SALOME + //issue #2159 Hide all incomplete behavior + viewer()->eraseAll(); +#endif updateCommandStatus(); + // Necessary for update icons in ObjectBrowser on Linux + myObjectBrowser->updateAllIndexes(); } else if (theId == "SELECT_VERTEX_CMD") { setViewerSelectionMode(TopAbs_VERTEX); } else if (theId == "SELECT_EDGE_CMD") { setViewerSelectionMode(TopAbs_EDGE); } else if (theId == "SELECT_FACE_CMD") { setViewerSelectionMode(TopAbs_FACE); + } else if (theId == "INSERT_FOLDER_CMD") { + insertFeatureFolder(); + } else if (theId == "ADD_TO_FOLDER_BEFORE_CMD") { + insertToFolder(true); + } else if (theId == "ADD_TO_FOLDER_AFTER_CMD") { + insertToFolder(false); + } else if (theId == "ADD_OUT_FOLDER_BEFORE_CMD") { + moveOutFolder(true); + } else if (theId == "ADD_OUT_FOLDER_AFTER_CMD") { + moveOutFolder(false); } else if (theId == "SELECT_RESULT_CMD") { //setViewerSelectionMode(-1); //IMP: an attempt to use result selection with other selection modes setViewerSelectionMode(ModuleBase_ResultPrs::Sel_Result); setViewerSelectionMode(TopAbs_COMPSOLID); } else if (theId == "SHOW_RESULTS_CMD") { - highlightResults(aObjects); + highlightResults(anObjects); } else if (theId == "SHOW_FEATURE_CMD") { - highlightFeature(aObjects); + highlightFeature(anObjects); + } else if (theId == "SET_VIEW_NORMAL_CMD") { + setNormalView(); + } else if (theId == "SET_VIEW_INVERTEDNORMAL_CMD") { + setNormalView(true); } #ifdef TINSPECTOR else if (theId == "TINSPECTOR_VIEW") { @@ -1390,6 +1835,13 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) if (!aContext.IsNull()) aParameters.Append(aContext); +#ifdef DEBUG_WITH_MESSAGE_REPORT + Handle(Message_Report) aContextReport = aContext->GetReport(); + aContext->SetReportActive (Standard_True); + aContextReport->SetLimit (1000); + if (!aContextReport.IsNull()) + aParameters.Append(aContextReport); +#endif MyVCallBack = new VInspector_CallBack(); myDisplayer->setCallBack(MyVCallBack); #ifndef HAVE_SALOME @@ -1399,11 +1851,28 @@ void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked) #endif aParameters.Append(MyVCallBack); - MyTCommunicator->init(aParameters); + MyTCommunicator->RegisterPlugin("TKDFBrowser"); + MyTCommunicator->RegisterPlugin("TKShapeView"); + MyTCommunicator->RegisterPlugin("TKVInspector"); +#ifdef DEBUG_WITH_MESSAGE_REPORT + MyTCommunicator->RegisterPlugin("TKMessageView"); +#endif + //MyTCommunicator->RegisterPlugin("SMBrowser"); // custom plugin to view ModelAPI + //MyTCommunicator->RegisterPlugin("TKSMBrowser"); // custom plugin to view ModelAPI + + MyTCommunicator->Init(aParameters); + MyTCommunicator->Activate("TKSMBrowser"); // to have button in TInspector +#ifndef DEBUG_WITH_MESSAGE_REPORT MyTCommunicator->Activate("TKVInspector"); // to have filled callback by model +#endif MyTCommunicator->Activate("TKDFBrowser"); + +#ifdef DEBUG_WITH_MESSAGE_REPORT + MyTCommunicator->Activate("TKMessageView"); // temporary + MyTCommunicator->Activate("TKVInspector"); // to have filled callback by model +#endif } - MyTCommunicator->setVisible(true); + MyTCommunicator->SetVisible(true); } } #endif @@ -1420,7 +1889,7 @@ void XGUI_Workshop::setViewerSelectionMode(int theMode) else myViewerSelMode.append(theMode); } - activateObjectsSelection(myDisplayer->displayedObjects()); + selectionActivate()->updateSelectionModes(); } //************************************************************** @@ -1430,7 +1899,61 @@ void XGUI_Workshop::activateObjectsSelection(const QObjectPtrList& theList) module()->activeSelectionModes(aModes); if (aModes.isEmpty() && (myViewerSelMode.length() > 0)) aModes.append(myViewerSelMode); - myDisplayer->activateObjects(aModes, theList); + selectionActivate()->activateObjects(aModes, theList); +} + +//************************************************************** +bool XGUI_Workshop::prepareForDisplay(const std::set& theObjects) const +{ + if (facesPanel()->isEmpty()) + return true; + + // generate container of objects taking into account sub elments of compsolid + std::set anAllProcessedObjects; + for (std::set::const_iterator anObjectsIt = theObjects.begin(); + anObjectsIt != theObjects.end(); anObjectsIt++) { + ObjectPtr anObject = *anObjectsIt; + ResultBodyPtr aCompRes = std::dynamic_pointer_cast(anObject); + if (aCompRes.get()) { + std::list allRes; + ModelAPI_Tools::allSubs(aCompRes, allRes); + if (allRes.empty()) { + anAllProcessedObjects.insert(anObject); + } else { + for(std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + ResultBodyPtr aBody = std::dynamic_pointer_cast(*aRes); + if (aBody.get() && aBody->numberOfSubs() == 0) + anAllProcessedObjects.insert(aBody); + } + } + } else + anAllProcessedObjects.insert(anObject); + } + + // find hidden objects in faces panel + std::set aHiddenObjects; + QStringList aHiddenObjectNames; + for (std::set::const_iterator anObjectsIt = anAllProcessedObjects.begin(); + anObjectsIt != anAllProcessedObjects.end(); anObjectsIt++) { + if (!facesPanel()->isObjectHiddenByPanel(*anObjectsIt)) + continue; + aHiddenObjects.insert(*anObjectsIt); + aHiddenObjectNames.append(QString::fromStdWString((*anObjectsIt)->data()->name())); + } + if (aHiddenObjects.empty()) // in parameter objects there are no hidden objects in hide face + return true; + + int anAnswer = QMessageBox::question( + desktop(), tr("Show object"), + tr("'%1'\n are hidden by %2:\nRemove objects from the panel to be displayed?") + .arg(aHiddenObjectNames.join(", ")).arg(facesPanel()->windowTitle()), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + bool aToBeDisplayed = anAnswer == QMessageBox::Yes; + if (aToBeDisplayed) + facesPanel()->restoreObjects(aHiddenObjects); + + return aToBeDisplayed; } //************************************************************** @@ -1440,10 +1963,14 @@ void XGUI_Workshop::deleteObjects() // allow the module to delete objects, do nothing if it has succeed if (aModule->deleteObjects()) { updateCommandStatus(); + myDisplayer->updateViewer(); return; } QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + if (anObjects.isEmpty()) + return; + if (!abortAllOperations()) return; @@ -1451,20 +1978,41 @@ void XGUI_Workshop::deleteObjects() bool hasFeature = false; bool hasParameter = false; bool hasCompositeOwner = false; - ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasCompositeOwner); - if (!(hasFeature || hasParameter)) + bool hasResultInHistory = false; + bool hasFolder = false; + ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasCompositeOwner, + hasResultInHistory, hasFolder); + if (!(hasResult || hasFeature || hasParameter || hasFolder)) return; + // Remove from the list non-deletable objects: infinite constructions which are not in history + bool notDelete = true; + QObjectPtrList::iterator aIt; + for (aIt = anObjects.begin(); aIt != anObjects.end(); aIt++) { + ObjectPtr aObj = (*aIt); + ResultConstructionPtr aConstr = std::dynamic_pointer_cast(aObj); + FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); + if (aFeature) { + notDelete = (!aFeature->isInHistory()) && (aConstr && aConstr->isInfinite()); + if (notDelete) { + anObjects.removeAll(aObj); + aIt--; + } + } + } // delete objects std::map > aReferences; std::set aFeatures; ModuleBase_Tools::convertToFeatures(anObjects, aFeatures); ModelAPI_Tools::findAllReferences(aFeatures, aReferences); + std::set aFolders; + ModuleBase_Tools::convertToFolders(anObjects, aFolders); + bool aDone = false; QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1"; aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", ")); - ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); + ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module()); operationMgr()->startOperation(anOpAction); @@ -1479,10 +2027,36 @@ void XGUI_Workshop::deleteObjects() aFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end()); aDone = ModelAPI_Tools::removeFeatures(aFeatures, false); } + if (aFolders.size() > 0) { + std::set::const_iterator anIt = aFolders.begin(), + aLast = aFolders.end(); + for (; anIt != aLast; anIt++) { + FolderPtr aFolder = *anIt; + if (aFolder.get()) { + DocumentPtr aDoc = aFolder->document(); + aDoc->removeFolder(aFolder); + } + } + } + // remove results selected + std::list aResults; + for(QObjectPtrList::const_iterator anIt = anObjects.begin(); anIt != anObjects.end(); anIt++) { + ResultPtr aRes = std::dynamic_pointer_cast(*anIt); + if (aRes.get() && aRes->data()->isValid() && !aRes->data()->isDeleted() && + aRes->groupName() != ModelAPI_ResultGroup::group() && // don't remove groups and fields + aRes->groupName() != ModelAPI_ResultField::group()) // because they are badly selected + aResults.push_back(aRes); + } + if (!aResults.empty()) { + ModelAPI_Tools::removeResults(aResults); + } + if (aDone) operationMgr()->commitOperation(); else operationMgr()->abortOperation(operationMgr()->currentOperation()); + + myDisplayer->updateViewer(); } //************************************************************** @@ -1532,11 +2106,11 @@ void XGUI_Workshop::cleanHistory() ModelAPI_Tools::findAllReferences(aFeatures, aReferences, true, false); // find for each object whether all reference values are in the map as key, that means that there // is no other reference in the model to this object, so it might be removed by cleaning history - // sk_1(ext_1, vertex_1) + (sk_3, bool_1) - cann't be deleted, dependency to bool_1 - // ext_1(bool_1, sk_3) - cann't be deleted, dependency to bool_1 + // sk_1(ext_1, vertex_1) + (sk_3, bool_1) - can't be deleted, dependency to bool_1 + // ext_1(bool_1, sk_3) - can't be deleted, dependency to bool_1 // vertex_1() - // sk_2(ext_2) + (bool_1) - cann't be deleted, dependency to bool_1 - // ext_2(bool_1) - cann't be deleted, dependency to bool_1 + // sk_2(ext_2) + (bool_1) - can't be deleted, dependency to bool_1 + // ext_2(bool_1) - can't be deleted, dependency to bool_1 // sk_3() // Information: bool_1 is not selected std::set anUnusedObjects; @@ -1570,13 +2144,14 @@ void XGUI_Workshop::cleanHistory() if (!anUnusedObjects.empty()) { QStringList aNames; foreach (const FeaturePtr& aFeature, anUnusedObjects) { - aNames.append(aFeature->name().c_str()); + aNames.append(QString::fromStdWString(aFeature->name())); } aNames.sort(); QString anUnusedNames = aNames.join(", "); QString anActionId = "CLEAN_HISTORY_CMD"; - QString aDescription = contextMenuMgr()->action(anActionId)->text(); + QString aDescription = ModuleBase_Tools::translate("workshop", + contextMenuMgr()->action(anActionId)->text().toStdString()); QMessageBox aMessageBox(desktop()); aMessageBox.setWindowTitle(aDescription); @@ -1594,7 +2169,7 @@ void XGUI_Workshop::cleanHistory() // 1. start operation aDescription += "by deleting of " + aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", ")); - ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module()); + ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module()); operationMgr()->startOperation(anOpAction); // WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree @@ -1633,17 +2208,17 @@ void XGUI_Workshop::cleanHistory() } //************************************************************** -void XGUI_Workshop::moveObjects() +bool compareFeature(const FeaturePtr& theF1, const FeaturePtr& theF2) { + DocumentPtr aDoc = theF1->document(); + return aDoc->index(theF1) < aDoc->index(theF2); +} +void XGUI_Workshop::moveObjects(const bool theSplit) { 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 @@ -1654,30 +2229,40 @@ void XGUI_Workshop::moveObjects() if (!XGUI_Tools::canRemoveOrRename(desktop(), aFeatures)) return; + QString anActionId = theSplit ? "MOVE_CMD" : "MOVE_SPLIT_CMD"; + QString aDescription = contextMenuMgr()->action(anActionId)->text(); + aMgr->startOperation(aDescription.toStdString()); + + // Sort features by index in document + std::list aFList(aFeatures.begin(), aFeatures.end()); + aFList.sort(compareFeature); + DocumentPtr anActiveDocument = aMgr->activeDocument(); FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true); - std::set::const_iterator anIt = aFeatures.begin(), aLast = aFeatures.end(); + std::list::const_iterator anIt = aFList.begin(), aLast = aFList.end(); for (; anIt != aLast; anIt++) { FeaturePtr aFeature = *anIt; if (!aFeature.get() || !myModule->canApplyAction(aFeature, anActionId)) continue; - anActiveDocument->moveFeature(aFeature, aCurrentFeature); + anActiveDocument->moveFeature(aFeature, aCurrentFeature, theSplit); aCurrentFeature = anActiveDocument->currentFeature(true); } aMgr->finishOperation(); + updateCommandStatus(); + myViewerProxy->update(); } //************************************************************** bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theObjects) { - std::map > aReferences; std::set aFeatures; ModuleBase_Tools::convertToFeatures(theObjects, aFeatures); return ModelAPI_Tools::removeFeaturesAndReferences(aFeatures); } +//****************************************************** bool hasResults(QObjectPtrList theObjects, const std::set& theTypes) { bool isFoundResultType = false; @@ -1712,8 +2297,8 @@ std::list allFeatures(const DocumentPtr& theDocument) 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()); + std::list aPartFeatures = allFeatures(aResultPart->partDoc()); + aResultList.insert(aResultList.end(), aPartFeatures.begin(), aPartFeatures.end()); } } @@ -1731,9 +2316,9 @@ std::list toCurrentFeatures(const ObjectPtr& theObject) DocumentPtr aDocument = theObject->document(); std::list anAllFeatures = allFeatures(aDocument); // find the object iterator - std::list::iterator aObjectIt = + std::list::iterator anObjectIt = std::find(anAllFeatures.begin(), anAllFeatures.end(), theObject); - if (aObjectIt == anAllFeatures.end()) + if (anObjectIt == anAllFeatures.end()) return aResult; // find the current feature iterator std::list::iterator aCurrentIt = @@ -1741,48 +2326,60 @@ std::list toCurrentFeatures(const ObjectPtr& theObject) if (aCurrentIt == anAllFeatures.end()) return aResult; // check the right order - if (std::distance(aObjectIt, anAllFeatures.end()) <= + if (std::distance(anObjectIt, anAllFeatures.end()) <= std::distance(aCurrentIt, anAllFeatures.end())) return aResult; // exclude the object - std::advance(aObjectIt, 1); + std::advance(anObjectIt, 1); // include the current feature std::advance(aCurrentIt, 1); - return std::list(aObjectIt, aCurrentIt); + return std::list(anObjectIt, aCurrentIt); } +//****************************************************** bool XGUI_Workshop::canMoveFeature() { QString anActionId = "MOVE_CMD"; - QObjectPtrList aObjects = mySelector->selection()->selectedObjects(); + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); QObjectPtrList aValidatedObjects; - foreach (ObjectPtr aObject, aObjects) { - if (!myModule->canApplyAction(aObject, anActionId)) + foreach (ObjectPtr anObject, anObjects) { + if (!myModule->canApplyAction(anObject, anActionId)) continue; // To be moved feature should be in active document - if (aObject->document() != ModelAPI_Session::get()->activeDocument()) + if (anObject->document() != ModelAPI_Session::get()->activeDocument()) continue; - aValidatedObjects.append(aObject); + aValidatedObjects.append(anObject); } - if (aValidatedObjects.size() != aObjects.size()) - aObjects = aValidatedObjects; + if (aValidatedObjects.size() != anObjects.size()) + anObjects = aValidatedObjects; - bool aCanMove = !aObjects.empty(); + bool aCanMove = !anObjects.empty(); - QObjectPtrList::const_iterator anIt = aObjects.begin(), aLast = aObjects.end(); + QObjectPtrList::const_iterator anIt = anObjects.begin(), aLast = anObjects.end(); for (; anIt != aLast && aCanMove; anIt++) { - ObjectPtr aObject = *anIt; + ObjectPtr anObject = *anIt; + if (!anObject.get() || !anObject->data().get() || !anObject->data()->isValid()) { + aCanMove = false; + break; + } + FeaturePtr aFeat = std::dynamic_pointer_cast(anObject); + // only groups can be moved to the end for now (#2451) + if (aFeat.get() && aFeat->getKind() != "Group") { + aCanMove = false; + break; + } + // 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 + std::list aFeaturesBetween = toCurrentFeatures(anObject); + // if aFeaturesBetween is empty it means wrong order or anObject 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; - ModuleBase_Tools::refsToFeatureInFeatureDocument(aObject, aRefFeatures); + ModuleBase_Tools::refsToFeatureInFeatureDocument(anObject, aRefFeatures); if (aRefFeatures.empty()) continue; @@ -1806,43 +2403,67 @@ 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)); + ResultBodyPtr aCompRes = std::dynamic_pointer_cast(theObject); + if (aCompRes.get() != NULL) { // change colors for all sub-solids + std::list allRes; + ModelAPI_Tools::allSubs(aCompRes, allRes); + std::list::iterator aRes = allRes.begin(); + for(; aRes != allRes.end() && !aCanBeShaded; aRes++) { + aCanBeShaded = myDisplayer->canBeShaded(*aRes); + } } } return aCanBeShaded; } //************************************************************** -bool XGUI_Workshop::canChangeColor() const +bool XGUI_Workshop::canChangeProperty(const QString& theActionName) const { - QObjectPtrList aObjects = mySelector->selection()->selectedObjects(); + if (theActionName == "COLOR_CMD" || + theActionName == "DEFLECTION_CMD" || + theActionName == "TRANSPARENCY_CMD") { + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); - std::set aTypes; - aTypes.insert(ModelAPI_ResultGroup::group()); - aTypes.insert(ModelAPI_ResultConstruction::group()); - aTypes.insert(ModelAPI_ResultBody::group()); - aTypes.insert(ModelAPI_ResultPart::group()); + std::set aTypes; + aTypes.insert(ModelAPI_ResultGroup::group()); + aTypes.insert(ModelAPI_ResultConstruction::group()); + aTypes.insert(ModelAPI_ResultBody::group()); + aTypes.insert(ModelAPI_ResultPart::group()); - return hasResults(aObjects, aTypes); + return hasResults(anObjects, aTypes); + } + if (theActionName == "AUTOCOLOR_CMD") { + + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + + std::set aTypes; + aTypes.insert(ModelAPI_ResultGroup::group()); + + return hasResults(anObjects, aTypes); + } + return false; } -void setColor(ResultPtr theResult, const std::vector& theColor) -{ - if (!theResult.get()) - return; - AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID()); - if (aColorAttr.get() != NULL) { - if (!aColorAttr->size()) { - aColorAttr->setSize(3); +//************************************************************** +void getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid, + std::vector& theColor) +{ + theColor.clear(); + // get default color from the preferences manager for the given result + if (theColor.empty()) { + std::string aSection, aName, aDefault; + theObject->colorConfigInfo(aSection, aName, aDefault); + if (!aSection.empty() && !aName.empty()) { + theColor = Config_PropManager::color(aSection, aName); } - aColorAttr->setValue(0, theColor[0]); - aColorAttr->setValue(1, theColor[1]); - aColorAttr->setValue(2, theColor[2]); + } + if (!isEmptyColorValid && theColor.empty()) { + // all AIS objects, where the color is not set, are in black. + // The color should be defined in XML or set in the attribute + theColor = Config_PropManager::color("Visualization", "object_default_color"); + Events_InfoMessage("XGUI_CustomPrs", + "A default color is not defined in the preferences for this kind of result").send(); } } @@ -1857,21 +2478,18 @@ void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects) foreach(ObjectPtr anObject, theObjects) { 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]); + ModelAPI_Tools::getColor(aResult, aColor); + if (aColor.empty()) { + AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject); + if (anAISObj.get()) { + aColor.resize(3); + anAISObj->getColor(aColor[0], aColor[1], aColor[2]); + } + } + if (aColor.empty()) { + getDefaultColor(aResult, false, aColor); } } - if (!aColor.empty()) - break; } if (aColor.size() != 3) return; @@ -1891,6 +2509,7 @@ void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects) // 3. abort the previous operation and start a new one SessionPtr aMgr = ModelAPI_Session::get(); QString aDescription = contextMenuMgr()->action("COLOR_CMD")->text(); + aMgr->startOperation(aDescription.toStdString()); // 4. set the value to all results @@ -1898,62 +2517,145 @@ void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects) foreach(ObjectPtr anObj, theObjects) { ResultPtr aResult = std::dynamic_pointer_cast(anObj); if (aResult.get() != NULL) { - 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()); + ResultBodyPtr aBodyResult = std::dynamic_pointer_cast(aResult); + if (aBodyResult.get() != NULL) { // change colors for all sub-solids + std::list allRes; + ModelAPI_Tools::allSubs(aBodyResult, allRes); + for(std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + ModelAPI_Tools::setColor(*aRes, !isRandomColor ? aColorResult : aDlg->getRandomColor()); } } - setColor(aResult, !isRandomColor ? aColorResult : aDlg->getRandomColor()); + ModelAPI_Tools::setColor(aResult, !isRandomColor ? aColorResult : aDlg->getRandomColor()); } } + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); aMgr->finishOperation(); updateCommandStatus(); + myViewerProxy->update(); } //************************************************************** -bool XGUI_Workshop::canChangeDeflection() const +void XGUI_Workshop::changeAutoColor(const QObjectPtrList& theObjects) { - QObjectPtrList aObjects = mySelector->selection()->selectedObjects(); + if (!abortAllOperations()) + return; + + std::vector aColor; + + // abort the previous operation and start a new one + SessionPtr aMgr = ModelAPI_Session::get(); + QString aDescription = contextMenuMgr()->action("AUTOCOLOR_CMD")->text(); + aMgr->startOperation(aDescription.toStdString()); + + Config_Prop* aProp = Config_PropManager::findProp("Visualization", "result_group_auto_color"); - std::set aTypes; - aTypes.insert(ModelAPI_ResultGroup::group()); - aTypes.insert(ModelAPI_ResultConstruction::group()); - aTypes.insert(ModelAPI_ResultBody::group()); - aTypes.insert(ModelAPI_ResultPart::group()); + if (aProp) { + bool anIsAutoColor = Config_PropManager::boolean("Visualization", "result_group_auto_color"); - return hasResults(aObjects, aTypes); + if (anIsAutoColor) { + contextMenuMgr()->action("AUTOCOLOR_CMD")->setText(tr("Auto color")); + aProp->setValue("false"); + ModelAPI_Tools::findRandomColor(aColor, true); + } else { + // set the value to all results + foreach (ObjectPtr anObj, theObjects) { + DocumentPtr aDocument = anObj->document(); + std::list anAllFeatures = allFeatures(aDocument); + // find the object iterator + std::list::iterator anObjectIt = anAllFeatures.begin(); + for (; anObjectIt != anAllFeatures.end(); ++ anObjectIt) { + FeaturePtr aFeature = *anObjectIt; + if (aFeature.get()) { + std::list aResults; + ModelAPI_Tools::allResults(aFeature, aResults); + std::list >::const_iterator aIt; + for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) { + ResultPtr aGroupResult = *aIt; + if (aGroupResult.get() && + aGroupResult->groupName() == ModelAPI_ResultGroup::group()) { + ModelAPI_Tools::findRandomColor(aColor); + ModelAPI_Tools::setColor(aGroupResult, aColor); + } + } + } + } + } + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + aMgr->finishOperation(); + updateCommandStatus(); + myViewerProxy->update(); + contextMenuMgr()->action("AUTOCOLOR_CMD")->setText(tr("Disable auto color")); + aProp->setValue("true"); + } + } } -void setDeflection(ResultPtr theResult, const double theDeflection) +//************************************************************** +void setTransparency(double theTransparency, const QObjectPtrList& theObjects) { - if (!theResult.get()) - return; - - AttributeDoublePtr aDeflectionAttr = theResult->data()->real(ModelAPI_Result::DEFLECTION_ID()); - if (aDeflectionAttr.get() != NULL) - aDeflectionAttr->setValue(theDeflection); + foreach(ObjectPtr anObj, theObjects) { + ResultPtr aResult = std::dynamic_pointer_cast(anObj); + if (aResult.get() != NULL) { + ResultBodyPtr aBodyResult = std::dynamic_pointer_cast(aResult); + if (aBodyResult.get() != NULL) { // change property for all sub-solids + std::list allRes; + ModelAPI_Tools::allSubs(aBodyResult, allRes); + std::list::iterator aRes; + for(aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + ModelAPI_Tools::setTransparency(*aRes, theTransparency); + } + } + ModelAPI_Tools::setTransparency(aResult, theTransparency); + } + } } +//************************************************************** +double getDefaultDeflection(const ObjectPtr& theObject) +{ + double aDeflection = -1; + ResultPtr aResult = std::dynamic_pointer_cast(theObject); + if (aResult.get()) { + bool isConstruction = false; + + std::string aResultGroup = aResult->groupName(); + if (aResultGroup == ModelAPI_ResultConstruction::group()) + isConstruction = true; + else if (aResultGroup == ModelAPI_ResultBody::group()) { + GeomShapePtr aGeomShape = aResult->shape(); + if (aGeomShape.get()) { + // if the shape could not be exploded on faces, it contains only wires, edges, and vertices + // correction of deviation for them should not influence to the application performance + GeomAPI_ShapeExplorer anExp(aGeomShape, GeomAPI_Shape::FACE); + isConstruction = !anExp.more(); + } + } + if (isConstruction) + aDeflection = Config_PropManager::real("Visualization", "construction_deflection"); + else + aDeflection = Config_PropManager::real("Visualization", "body_deflection"); + } + return aDeflection; +} //************************************************************** void XGUI_Workshop::changeDeflection(const QObjectPtrList& theObjects) { AttributeDoublePtr aDoubleAttr; - // 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 + // 1. find the current property of the object. This is a property of AIS presentation + // The objects are iterated until a first valid property is found double aDeflection = -1; foreach(ObjectPtr anObject, theObjects) { ResultPtr aResult = std::dynamic_pointer_cast(anObject); if (aResult.get()) { - aDeflection = XGUI_CustomPrs::getResultDeflection(aResult); + aDeflection = ModelAPI_Tools::getDeflection(aResult); + if (aDeflection < 0) + aDeflection = getDefaultDeflection(aResult); } else { - // TODO: remove the obtaining a color from the AIS object + // TODO: remove the obtaining a property from the AIS object // this does not happen never because: - // 1. The color can be changed only on results + // 1. The property 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()) { @@ -1986,56 +2688,233 @@ void XGUI_Workshop::changeDeflection(const QObjectPtrList& theObjects) foreach(ObjectPtr anObj, theObjects) { ResultPtr aResult = std::dynamic_pointer_cast(anObj); if (aResult.get() != NULL) { - 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++) { - setDeflection(aCompsolidResult->subResult(i), aDeflection); + ResultBodyPtr aBodyResult = std::dynamic_pointer_cast(aResult); + if (aBodyResult.get() != NULL) { // change property for all sub-solids + std::list allRes; + ModelAPI_Tools::allSubs(aBodyResult, allRes); + for(std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + ModelAPI_Tools::setDeflection(*aRes, aDeflection); } } - setDeflection(aResult, aDeflection); + ModelAPI_Tools::setDeflection(aResult, aDeflection); } } + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); aMgr->finishOperation(); updateCommandStatus(); } //************************************************************** -#define SET_DISPLAY_GROUP(aGroupName, aDisplay) \ -for (int i = 0; i < aDoc->size(aGroupName); i++) { \ - aDoc->object(aGroupName, i)->setDisplayed(aDisplay); \ +double getDefaultTransparency(const ResultPtr& theResult) +{ + return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.; } + +//************************************************************** +void XGUI_Workshop::changeTransparency(const QObjectPtrList& theObjects) +{ + AttributeDoublePtr aDoubleAttr; + // 1. find the current property of the object. This is a property of AIS presentation + // The objects are iterated until a first valid property is found + double aCurrentValue = -1; + foreach(ObjectPtr anObject, theObjects) { + ResultPtr aResult = std::dynamic_pointer_cast(anObject); + if (aResult.get()) { + aCurrentValue = ModelAPI_Tools::getTransparency(aResult); + if (aCurrentValue < 0) + aCurrentValue = getDefaultTransparency(aResult); + } + if (aCurrentValue > 0) + break; + } + if (aCurrentValue < 0) + return; + + if (!abortAllOperations()) + return; + + // 2. show the dialog to change the value + XGUI_PropertyDialog* aDlg = new XGUI_PropertyDialog(desktop()); + aDlg->setWindowTitle(tr("Transparency")); + XGUI_TransparencyWidget* aTransparencyWidget = new XGUI_TransparencyWidget(aDlg); + connect(aTransparencyWidget, SIGNAL(transparencyValueChanged()), + this, SLOT(onTransparencyValueChanged())); + aDlg->setContent(aTransparencyWidget); + aTransparencyWidget->setValue(aCurrentValue); + + // 3. abort the previous operation and start a new one + SessionPtr aMgr = ModelAPI_Session::get(); + QString aDescription = contextMenuMgr()->action("TRANSPARENCY_CMD")->text(); + aMgr->startOperation(aDescription.toStdString()); + + if (aDlg->exec() == QDialog::Accepted) { + // 4. set the value to all results + aCurrentValue = aTransparencyWidget->getValue(); + setTransparency(aCurrentValue, theObjects); + aMgr->finishOperation(); + } else { + aMgr->abortOperation(); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + } + + updateCommandStatus(); +} + +//************************************************************** +void XGUI_Workshop::onTransparencyValueChanged() +{ + XGUI_TransparencyWidget* aTransparencyWidget = (XGUI_TransparencyWidget*)sender(); + if (!aTransparencyWidget) + return; + + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + setTransparency(aTransparencyWidget->getValue(), anObjects); + static const Events_ID kRedisplayEvent = + Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); + Events_Loop::loop()->flush(kRedisplayEvent); + + myViewerProxy->update(); +} + + +//****************************************************** void XGUI_Workshop::showObjects(const QObjectPtrList& theList, bool isVisible) { + if (isVisible) { + std::set anObjects; + foreach (ObjectPtr aObj, theList) { + anObjects.insert(aObj); + } + if (!prepareForDisplay(anObjects)) + return; + } + foreach (ObjectPtr aObj, theList) { aObj->setDisplayed(isVisible); } Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + myObjectBrowser->updateAllIndexes(); + + updateColorScaleVisibility(); + displayer()->updateViewer(); } //************************************************************** void XGUI_Workshop::showOnlyObjects(const QObjectPtrList& theList) { + QObjectPtrList aSrcList = theList; // Hide all displayed objects QObjectPtrList aList = myDisplayer->displayedObjects(); foreach (ObjectPtr aObj, aList) { - if (module()->canEraseObject(aObj)) + if ((!aSrcList.contains(aObj)) && (module()->canEraseObject(aObj))) aObj->setDisplayed(false); + else + aSrcList.removeAll(aObj); + } + //Do not use eraseAll if you didn't send Redisplay event: + //all objects are erased from viewer, but considered as displayed in displayer + // Problem in bug 2218 + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); +#ifdef HAVE_SALOME + //issue #2159 Hide all incomplete behavior + viewer()->eraseAll(); +#endif + + std::set anObjects; + foreach (ObjectPtr aObj, aSrcList) { + anObjects.insert(aObj); } + if (!prepareForDisplay(anObjects)) + return; + // Show only objects from the list - foreach (ObjectPtr aObj, theList) { + foreach (ObjectPtr aObj, aSrcList) { aObj->setDisplayed(true); } Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + + // Necessary for update icons in ObjectBrowser on Linux + myObjectBrowser->updateAllIndexes(); + updateColorScaleVisibility(); + displayer()->updateViewer(); +} + + +//************************************************************** +void XGUI_Workshop::updateColorScaleVisibility() +{ + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + viewer()->setColorScaleShown(false); + if (anObjects.size() == 1) { + FieldStepPtr aStep = + std::dynamic_pointer_cast(anObjects.first()); + if (aStep.get() && myDisplayer->isVisible(aStep)) { + AISObjectPtr aAisPtr = myDisplayer->getAISObject(aStep); + Handle(AIS_InteractiveObject) aIO = aAisPtr->impl(); + ModuleBase_IStepPrs* aPrs = dynamic_cast(aIO.get()); + if (aPrs) { + ModelAPI_AttributeTables::ValueType aType = aPrs->dataType(); + if ((aType == ModelAPI_AttributeTables::DOUBLE) || + (aType == ModelAPI_AttributeTables::INTEGER) || + (aType == ModelAPI_AttributeTables::BOOLEAN)) { + myViewerProxy->setupColorScale(); + if (aType == ModelAPI_AttributeTables::BOOLEAN) { + myViewerProxy->setColorScaleIntervals(2); + myViewerProxy->setColorScaleRange(0., 1.); + } + else { + double aMin, aMax; + aPrs->dataRange(aMin, aMax); + myViewerProxy->setColorScaleRange(aMin, aMax); + } + myViewerProxy->setColorScaleTitle(QString::fromStdWString(aStep->name())); + myViewerProxy->setColorScaleShown(true); + } + } + } + } } +//************************************************************** +void XGUI_Workshop::setNormalView(bool toInvert) +{ + QList aPrsList = + mySelector->selection()->getSelected(ModuleBase_ISelection::Viewer); + GeomShapePtr aPlanarFace; + foreach(ModuleBase_ViewerPrsPtr aPrs, aPrsList) { + GeomShapePtr aShape = aPrs->shape(); + if (aShape.get() && aShape->isFace() && aShape->isPlanar()) { + aPlanarFace = aShape; + break; + } + } + if (aPlanarFace.get()) { + GeomFacePtr aFace(new GeomAPI_Face(aPlanarFace)); + GeomPlanePtr aPlane = aFace->getPlane(); + GeomDirPtr aNormal = aPlane->direction(); + if (toInvert) + aNormal->reverse(); + GeomPointPtr aPos = aPlane->location(); + + double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; + aFace->computeSize(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + + Handle(V3d_View) aView = myViewerProxy->activeView(); + aView->SetAt(aPos->x(), aPos->y(), aPos->z()); + aView->SetProj(aNormal->x(), aNormal->y(), aNormal->z()); + Bnd_Box aBox; + aBox.Update(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + aView->FitAll(aBox); + } +} + //************************************************************** void XGUI_Workshop::registerValidators() const { SessionPtr aMgr = ModelAPI_Session::get(); - ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); + MAYBE_UNUSED ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); } //************************************************************** @@ -2059,14 +2938,15 @@ void XGUI_Workshop::displayGroupResults(DocumentPtr theDoc, std::string theGroup //************************************************************** void XGUI_Workshop::setDisplayMode(const QObjectPtrList& theList, int theMode) { - foreach(ObjectPtr aObj, theList) { - myDisplayer->setDisplayMode(aObj, (XGUI_Displayer::DisplayMode)theMode, false); + foreach(ObjectPtr anObj, theList) { + myDisplayer->setDisplayMode(anObj, (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); + ResultBodyPtr aBodyResult = std::dynamic_pointer_cast(anObj); + if (aBodyResult.get() != NULL) { // change display mode for all sub-solids + std::list allRes; + ModelAPI_Tools::allSubs(aBodyResult, allRes); + for(std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + myDisplayer->setDisplayMode(*aRes, (XGUI_Displayer::DisplayMode)theMode, false); } } } @@ -2087,6 +2967,9 @@ void XGUI_Workshop::closeDocument() objectBrowser()->clearContent(); module()->closeDocument(); + // we need to clear viewer (with created filters) to do not have problems in 2nd SALOME study + module()->clearViewer(); + // data model need not process the document's signals about objects modifications as // the document is closed @@ -2098,6 +2981,7 @@ void XGUI_Workshop::closeDocument() //objectBrowser()->dataModel()->blockEventsProcessing(isBlocked); } +//****************************************************** void XGUI_Workshop::addHistoryMenu(QObject* theObject, const char* theSignal, const char* theSlot) { XGUI_HistoryMenu* aMenu = NULL; @@ -2114,6 +2998,7 @@ void XGUI_Workshop::addHistoryMenu(QObject* theObject, const char* theSignal, co connect(aMenu, SIGNAL(actionSelected(int)), this, theSlot); } +//****************************************************** QList XGUI_Workshop::processHistoryList(const std::list& theList) const { QList aResult; @@ -2139,6 +3024,7 @@ QList XGUI_Workshop::processHistoryList(const std::list return aResult; } +//****************************************************** void XGUI_Workshop::setStatusBarMessage(const QString& theMessage) { #ifdef HAVE_SALOME @@ -2148,42 +3034,84 @@ void XGUI_Workshop::setStatusBarMessage(const QString& theMessage) #endif } +#ifdef HAVE_SALOME +//****************************************************** void XGUI_Workshop::synchronizeViewer() { SessionPtr aMgr = ModelAPI_Session::get(); - DocumentPtr aDoc = aMgr->activeDocument(); + QList aDocs; + aDocs.append(aMgr->activeDocument()); + aDocs.append(aMgr->moduleDocument()); - synchronizeGroupInViewer(aDoc, ModelAPI_ResultConstruction::group(), false); - synchronizeGroupInViewer(aDoc, ModelAPI_ResultBody::group(), false); - synchronizeGroupInViewer(aDoc, ModelAPI_ResultPart::group(), false); - synchronizeGroupInViewer(aDoc, ModelAPI_ResultGroup::group(), false); + foreach(DocumentPtr aDoc, aDocs) { + synchronizeGroupInViewer(aDoc, false); + } } +//****************************************************** void XGUI_Workshop::synchronizeGroupInViewer(const DocumentPtr& theDoc, - const std::string& theGroup, bool theUpdateViewer) { - ObjectPtr aObj; - int aSize = theDoc->size(theGroup); + FeaturePtr aFeature; + ResultPtr aRes; + int aSize = theDoc->numInternalFeatures(); for (int i = 0; i < aSize; i++) { - aObj = theDoc->object(theGroup, i); - if (aObj->isDisplayed()) { - // Hide the presentation with an empty shape. But isDisplayed state of the object should not - // be changed to the object becomes visible when the shape becomes not empty - ResultPtr aRes = std::dynamic_pointer_cast(aObj); - if (aRes.get() && (!aRes->shape().get() || aRes->shape()->isNull())) - continue; - myDisplayer->display(aObj, false); + aFeature = theDoc->internalFeature(i); + if (!aFeature.get()) + continue; + const std::list& aResults = aFeature->results(); + std::list::const_iterator aIt; + aFeature->setDisplayed(false); + for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) { + aRes = (*aIt); + if (aRes->isDisplayed() && !aRes->isConcealed()) { + // Hide the presentation with an empty shape. But isDisplayed state of the object should not + // be changed to the object becomes visible when the shape becomes not empty + if (!aRes->shape().get() || aRes->shape()->isNull()) + continue; + ResultBodyPtr aResBody = std::dynamic_pointer_cast(aRes); + if (aResBody.get()) + synchronizeResultTree(aResBody, false); + else { + if (aRes->isInHistory()) { + if (aRes->isDisplayed()) + myDisplayer->display(aRes, false); + else + myDisplayer->erase(aRes, false); + } + else + aRes->setDisplayed(false); + } + } } } if (theUpdateViewer) myDisplayer->updateViewer(); } +void XGUI_Workshop::synchronizeResultTree(const ResultBodyPtr& theRes, bool theUpdateViewer) +{ + if (theRes->numberOfSubs() > 0) + for (int i = 0; i < theRes->numberOfSubs(); i++) { + ResultBodyPtr aRes = theRes->subResult(i); + if (aRes.get()) + synchronizeResultTree(aRes, theUpdateViewer); + } + else { + if (theRes->isDisplayed()) + myDisplayer->display(theRes, theUpdateViewer); + else + myDisplayer->erase(theRes, theUpdateViewer); + } +} +#endif + +//****************************************************** void XGUI_Workshop::highlightResults(const QObjectPtrList& theObjects) { FeaturePtr aFeature; QObjectPtrList aSelList = theObjects; + QObjectPtrList aNewSel; bool aHasHidden = false; foreach(ObjectPtr aObj, theObjects) { aFeature = std::dynamic_pointer_cast(aObj); @@ -2194,24 +3122,26 @@ void XGUI_Workshop::highlightResults(const QObjectPtrList& theObjects) for(aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) { aHasHidden |= (*aIt)->isConcealed(); aSelList.append(*aIt); + aNewSel.append(*aIt); } } } if (aSelList.count() > theObjects.count()) { // if something was found - bool aBlocked = objectBrowser()->blockSignals(true); objectBrowser()->setObjectsSelected(aSelList); - objectBrowser()->blockSignals(aBlocked); + objectBrowser()->ensureVisible(aNewSel.first()); } if (aHasHidden) QMessageBox::information(desktop(), tr("Find results"), tr("Results not found"), QMessageBox::Ok); } +//****************************************************** void XGUI_Workshop::highlightFeature(const QObjectPtrList& theObjects) { ResultPtr aResult; QObjectPtrList aSelList = theObjects; + QObjectPtrList aNewSel; FeaturePtr aFeature; foreach(ObjectPtr aObj, theObjects) { aResult = std::dynamic_pointer_cast(aObj); @@ -2219,13 +3149,213 @@ void XGUI_Workshop::highlightFeature(const QObjectPtrList& theObjects) aFeature = ModelAPI_Feature::feature(aResult); if (aFeature.get()) { aSelList.append(aFeature); + aNewSel.append(aFeature); } } } if (aSelList.count() > theObjects.count()) { // if something was found - bool aBlocked = objectBrowser()->blockSignals(true); objectBrowser()->setObjectsSelected(aSelList); - objectBrowser()->blockSignals(aBlocked); + objectBrowser()->ensureVisible(aNewSel.first()); + } +} + +void XGUI_Workshop::insertFeatureFolder() +{ + QObjectPtrList anObjects = mySelector->selection()->selectedObjects(); + if (anObjects.isEmpty()) + return; + ObjectPtr aObj = anObjects.first(); + FeaturePtr aFeature = std::dynamic_pointer_cast(aObj); + if (aFeature.get() == NULL) + return; + SessionPtr aMgr = ModelAPI_Session::get(); + DocumentPtr aDoc = aMgr->activeDocument(); + + QString aDescription = contextMenuMgr()->action("INSERT_FOLDER_CMD")->text(); + + aMgr->startOperation(aDescription.toStdString()); + aDoc->addFolder(aFeature); + aMgr->finishOperation(); + + updateCommandStatus(); +} + + +void XGUI_Workshop::insertToFolder(bool isBefore) +{ + std::list aFeatures = mySelector->getSelectedFeatures(); + if (aFeatures.empty()) + return; + + SessionPtr aMgr = ModelAPI_Session::get(); + DocumentPtr aDoc = aMgr->activeDocument(); + + FolderPtr aFolder = isBefore? aDoc->findFolderAbove(aFeatures): + aDoc->findFolderBelow(aFeatures); + if (!aFolder.get()) + return; + + QString aDescription = contextMenuMgr()->action( + isBefore ? "ADD_TO_FOLDER_BEFORE_CMD" : "ADD_TO_FOLDER_AFTER_CMD")->text(); + + QMap aStates = myObjectBrowser->getFoldersState(aDoc); + + aMgr->startOperation(aDescription.toStdString()); + aDoc->moveToFolder(aFeatures, aFolder); + aMgr->finishOperation(); + + myObjectBrowser->setFoldersState(aStates); + + updateCommandStatus(); +} + +void XGUI_Workshop::moveOutFolder(bool isBefore) +{ + std::list aFeatures = mySelector->getSelectedFeatures(); + if (aFeatures.empty()) + return; + + SessionPtr aMgr = ModelAPI_Session::get(); + DocumentPtr aDoc = aMgr->activeDocument(); + + QString aDescription = contextMenuMgr()->action( + isBefore ? "ADD_OUT_FOLDER_BEFORE_CMD" : "ADD_OUT_FOLDER_AFTER_CMD")->text(); + + QMap aStates = myObjectBrowser->getFoldersState(aDoc); + + aMgr->startOperation(aDescription.toStdString()); + aDoc->removeFromFolder(aFeatures, isBefore); + aMgr->finishOperation(); + + myObjectBrowser->setFoldersState(aStates); + + updateCommandStatus(); +} + +void XGUI_Workshop::onAutoApply() +{ + SessionPtr aMgr = ModelAPI_Session::get(); + bool isBlocked = aMgr->isAutoUpdateBlocked(); + aMgr->blockAutoUpdate(!isBlocked); + myDisplayer->updateViewer(); +} + +void XGUI_Workshop::updateAutoComputeState() +{ + SessionPtr aMgr = ModelAPI_Session::get(); +#ifdef HAVE_SALOME +// QAction* aUpdateCmd; +// QList aCommands = mySalomeConnector->commandList(); +// foreach(QAction* aCmd, aCommands) { +// if (aCmd->data().toString() == "AUTOCOMPUTE_CMD") { +// aUpdateCmd = aCmd; +// break; +// } +// } +// aUpdateCmd->setIcon(isComputeBlocked? QIcon(":pictures/autoapply_stop.png") : +// QIcon(":pictures/autoapply_start.png")); +#else + bool isComputeBlocked = aMgr->isAutoUpdateBlocked(); + AppElements_MainMenu* aMenuBar = myMainWindow->menuObject(); + AppElements_Command* aUpdateCmd = aMenuBar->feature("AUTOCOMPUTE_CMD"); + aUpdateCmd->button()->setIcon(isComputeBlocked? QIcon(":pictures/autoapply_stop.png") : + QIcon(":pictures/autoapply_start.png")); +#endif +} + + +void XGUI_Workshop::clearTemporaryDir() +{ + QDir aDir(myTmpDir.path()); + if (!aDir.isEmpty()) { + QStringList aEntries; + aDir.entryList(aEntries); + foreach(QString aFile, aEntries) { + aDir.remove(aFile); + } + } +} + + +void XGUI_Workshop::onDockSizeChanged() +{ + QDockWidget* aDockWgt = dynamic_cast(myObjectBrowser->parentWidget()); + int aObWidth = aDockWgt->size().width(); + if (myPropertyPanel->width() != aObWidth) { + QList aWgtList; + aWgtList << myPropertyPanel << aDockWgt; + QList aSizeList; + aSizeList << aObWidth << aObWidth; + desktop()->resizeDocks(aWgtList, aSizeList, Qt::Horizontal); + disconnect(myObjectBrowser, SIGNAL(sizeChanged()), this, SLOT(onDockSizeChanged())); + } +} + +void XGUI_Workshop::deactivateCurrentSelector() +{ + myActiveControlMgr->deactivateSelector(myActiveControlMgr->activeSelector()); +} + +void XGUI_Workshop::changeIsoLines(const QObjectPtrList& theObjects) +{ + if (theObjects.isEmpty()) + return; + + QList aResultList; + ResultPtr aRes; + foreach(ObjectPtr aObj, theObjects) { + aRes = std::dynamic_pointer_cast(aObj); + if (aRes.get()) + aResultList.append(aRes); + } + + std::vector aValues; + bool isVisible; + if (aResultList.size() == 1) { + ResultPtr aResult = aResultList.first(); + if (aResult.get()) + ModelAPI_Tools::getIsoLines(aResult, isVisible, aValues); + else + return; + } + if (aValues.size() == 0) { + aValues.push_back(1); + aValues.push_back(1); + } + + if (!abortAllOperations()) + return; + + XGUI_PropertyDialog aDlg(desktop()); + aDlg.setWindowTitle(tr("Number of Iso-lines")); + + QWidget* aIsosWgt = new QWidget(&aDlg); + QFormLayout* aLayout = new QFormLayout(aIsosWgt); + ModuleBase_Tools::adjustMargins(aLayout); + aDlg.setContent(aIsosWgt); + + QSpinBox* aUNb = new QSpinBox(&aDlg); + aUNb->setValue(aValues[0]); + aLayout->addRow("U:", aUNb); + + QSpinBox* aVNb = new QSpinBox(&aDlg); + aVNb->setValue(aValues[1]); + aLayout->addRow("V:", aVNb); + + if (aDlg.exec() == QDialog::Accepted) { + SessionPtr aMgr = ModelAPI_Session::get(); + QString aDescription = contextMenuMgr()->action("ISOLINES_CMD")->text(); + aMgr->startOperation(aDescription.toStdString()); + + aValues[0] = aUNb->value(); + aValues[1] = aVNb->value(); + foreach(ResultPtr aResult, aResultList) { + ModelAPI_Tools::setIsoLines(aResult, aValues); + } + mySelector->clearSelection(); + Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); + aMgr->finishOperation(); + updateCommandStatus(); } }