Salome HOME
Issue #3224: Provide help button for feature dialog boxes
[modules/shaper.git] / src / XGUI / XGUI_Workshop.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "XGUI_Workshop.h"
21
22 #include "XGUI_ActionsMgr.h"
23 #include "XGUI_ActiveControlMgr.h"
24 #include "XGUI_ActiveControlSelector.h"
25 #include "XGUI_MenuMgr.h"
26 #include "XGUI_ColorDialog.h"
27 #include "XGUI_DeflectionDialog.h"
28 #include "XGUI_TransparencyWidget.h"
29 #include "XGUI_ContextMenuMgr.h"
30 #include "XGUI_Displayer.h"
31 #include "XGUI_ErrorDialog.h"
32 #include "XGUI_ErrorMgr.h"
33 #include "XGUI_FacesPanel.h"
34 #include "XGUI_FacesPanelSelector.h"
35 #include "XGUI_ModuleConnector.h"
36 #include "XGUI_ObjectsBrowser.h"
37 #include "XGUI_OperationMgr.h"
38 #include "XGUI_PropertyPanel.h"
39 #include "XGUI_PropertyPanelSelector.h"
40 #include "XGUI_PropertyDialog.h"
41 #include "XGUI_SalomeConnector.h"
42 #include "XGUI_Selection.h"
43 #include "XGUI_SelectionActivate.h"
44 #include "XGUI_SelectionMgr.h"
45 #include "XGUI_Tools.h"
46 #include "XGUI_ViewerProxy.h"
47 #include "XGUI_WorkshopListener.h"
48 #include <XGUI_HistoryMenu.h>
49 #include <XGUI_QtEvents.h>
50 #include <XGUI_DataModel.h>
51 #include <XGUI_InspectionPanel.h>
52 #include <XGUI_CompressFiles.h>
53
54 #ifndef HAVE_SALOME
55 #include <AppElements_Button.h>
56 #include <AppElements_Command.h>
57 #include <AppElements_MainMenu.h>
58 #include <AppElements_MainWindow.h>
59 #include <AppElements_MenuGroupPanel.h>
60 #include <AppElements_Viewer.h>
61 #include <AppElements_Workbench.h>
62 #endif
63
64 #include <Config_XMLReader.h>
65
66 #include <ModelAPI_AttributeDocRef.h>
67 #include <ModelAPI_AttributeIntArray.h>
68 #include <ModelAPI_AttributeDouble.h>
69 #include <ModelAPI_AttributeString.h>
70 #include <ModelAPI_Data.h>
71 #include <ModelAPI_Events.h>
72 #include <ModelAPI_Feature.h>
73 #include <ModelAPI_Object.h>
74 #include <ModelAPI_ResultBody.h>
75 #include <ModelAPI_ResultConstruction.h>
76 #include <ModelAPI_ResultGroup.h>
77 #include <ModelAPI_ResultParameter.h>
78 #include <ModelAPI_ResultField.h>
79 #include <ModelAPI_Session.h>
80 #include <ModelAPI_Validator.h>
81 #include <ModelAPI_Tools.h>
82 #include <ModelAPI_ResultField.h>
83 #include <ModuleBase_IconFactory.h>
84
85 //#include <PartSetPlugin_Part.h>
86
87 #include <Events_Loop.h>
88 #include <Events_InfoMessage.h>
89 #include <Events_LongOp.h>
90
91 #include <ExchangePlugin_ExportPart.h>
92 #include <ExchangePlugin_ImportPart.h>
93 #include <ExchangePlugin_Import.h>
94 #include <ExchangePlugin_ExportFeature.h>
95
96 #include <GeomAPI_Pnt.h>
97 #include <GeomAPI_ShapeExplorer.h>
98
99 #include <ModuleBase_IModule.h>
100 #include <ModuleBase_IViewer.h>
101 #include <ModuleBase_Operation.h>
102 #include <ModuleBase_OperationDescription.h>
103 #include <ModuleBase_PageBase.h>
104 #include <ModuleBase_Preferences.h>
105 #include <ModuleBase_SelectionValidator.h>
106 #include <ModuleBase_Tools.h>
107 #include <ModuleBase_WidgetFactory.h>
108 #include <ModuleBase_OperationFeature.h>
109 #include <ModuleBase_PagedContainer.h>
110 #include <ModuleBase_WidgetValidated.h>
111 #include <ModuleBase_ModelWidget.h>
112 #include <ModuleBase_ResultPrs.h>
113 #include <ModuleBase_ActionIntParameter.h>
114 #include <ModuleBase_IStepPrs.h>
115
116 #include <Config_Common.h>
117 #include <Config_FeatureMessage.h>
118 #include <Config_ModuleReader.h>
119 #include <Config_PointerMessage.h>
120 #include <Config_PropManager.h>
121 #include <Config_DataModelReader.h>
122 #include <Config_Translator.h>
123 #include <Config_WidgetAPI.h>
124 #include <Config_Keywords.h>
125
126 #include <SUIT_ResourceMgr.h>
127
128 #include <AIS_Trihedron.hxx>
129 #ifdef BEFORE_TRIHEDRON_PATCH
130 #include <AIS_Point.hxx>
131 #include <AIS_Axis.hxx>
132 #endif
133
134 #include <QApplication>
135 #include <QFileDialog>
136 #include <QMessageBox>
137 #include <QMdiSubWindow>
138 #include <QMainWindow>
139 #include <QPushButton>
140 #include <QDockWidget>
141 #include <QLayout>
142 #include <QThread>
143 #include <QObject>
144 #include <QMenu>
145 #include <QToolButton>
146 #include <QAction>
147 #include <QDesktopWidget>
148 #include <QProcess>
149 #include <QDesktopServices>
150 #include <QFormLayout>
151 #include <QSpinBox>
152 #include <QDialogButtonBox>
153
154 #include <iterator>
155
156 #ifdef TINSPECTOR
157 #include <CDF_Session.hxx>
158 #include <CDF_Application.hxx>
159 #include <inspector/TInspector_Communicator.hxx>
160 #include <inspector/VInspector_CallBack.hxx>
161 static TInspector_Communicator* MyTCommunicator;
162 static Handle(VInspector_CallBack) MyVCallBack;
163
164 #endif
165
166 #ifdef _DEBUG
167 #include <QDebug>
168 #include <iostream>
169 #endif
170
171 #ifdef WIN32
172 #include <windows.h>
173 #else
174 #include <dlfcn.h>
175 #endif
176
177 //#define DEBUG_WITH_MESSAGE_REPORT
178
179 QString XGUI_Workshop::MOVE_TO_END_COMMAND = QObject::tr("Move to the end");
180 QString XGUI_Workshop::MOVE_TO_END_SPLIT_COMMAND = QObject::tr("Move to the end and split");
181
182 //#define DEBUG_DELETE
183 //#define DEBUG_FEATURE_NAME
184 //#define DEBUG_CLEAN_HISTORY
185
186 #ifdef HAVE_SALOME
187 static QString MyFilter(QObject::tr("SHAPER files (*.shaper *.cadbld)"));
188 static QString MyFilter2(QObject::tr("SHAPER files (*.shaper)"));
189 static QString MyExtension(".shaper");
190 #else
191 static QString MyFilter(QObject::tr("CAD Builder files (*.cadbld);;All files (*.*)"));
192 static QString MyFilter2(QObject::tr("CAD Builder files (*.cadbld)"));
193 static QString MyExtension(".cadbld");
194 #endif
195
196 static QString MyImportPartFilter(QObject::tr("Part files (*.shaperpart);;All files (*.*)"));
197
198
199 //******************************************************
200 XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
201     : QObject(),
202       myModule(NULL),
203       mySalomeConnector(theConnector),
204       myPropertyPanel(0),
205       myInspectionPanel(0),
206       myFacesPanel(0),
207       myObjectBrowser(0),
208       myDisplayer(0)
209       //myViewerSelMode(TopAbs_FACE)
210 {
211   mySelector = new XGUI_SelectionMgr(this);
212   myModuleConnector = new XGUI_ModuleConnector(this);
213   myOperationMgr = new XGUI_OperationMgr(this, 0);
214   ModuleBase_IWorkshop* aWorkshop = moduleConnector();
215   // Has to be defined first in order to get errors and messages from other components
216   myEventsListener = new XGUI_WorkshopListener(this);
217   mySelectionActivate = new XGUI_SelectionActivate(aWorkshop);
218
219   SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr();
220 #ifndef HAVE_SALOME
221   myMainWindow = new AppElements_MainWindow();
222
223   bool aCloc = aResMgr->booleanValue("language", "locale", true);
224   if (aCloc)
225     QLocale::setDefault( QLocale::c() );
226   else
227     QLocale::setDefault( QLocale::system() );
228 #endif
229   QString aPath = Config_XMLReader::pluginConfigFile().c_str();
230   QDir aDir(aPath);
231
232   // Load translations
233   QStringList aLangs;
234   aLangs << "*_en.ts"; // load by default eng translations
235
236   /// If version of OCCT is 7.4.0 or more then it means that
237   /// this is version of SALOME older then 9.4.0
238 #if OCC_VERSION_HEX >= 0x070400
239   QString aCurrLang = aResMgr->language();
240 #else
241   QString aCurrLang = aResMgr->stringValue("language", "language", "en");
242 #endif
243
244   if(aCurrLang != "en") {
245     aLangs << "*_" + aCurrLang + ".ts"; // then replace with translated files
246   }
247
248   foreach(QString aLang, aLangs) {
249     QStringList aFilters;
250     aFilters << aLang;
251     QStringList aTsFiles = aDir.entryList(aFilters, QDir::Files);
252     foreach(QString aFileName, aTsFiles) {
253       Config_Translator::load(aFileName.toStdString());
254     }
255   }
256
257   myDataModelXMLReader = new Config_DataModelReader();
258   //myDataModelXMLReader->readAll();
259
260   myDisplayer = new XGUI_Displayer(this);
261
262   connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(updateCommandStatus()));
263
264   myActionsMgr = new XGUI_ActionsMgr(this);
265   myActiveControlMgr = new XGUI_ActiveControlMgr(myModuleConnector);
266   myMenuMgr = new XGUI_MenuMgr(this);
267   myErrorDlg = new XGUI_ErrorDialog(QApplication::desktop());
268   myContextMenuMgr = new XGUI_ContextMenuMgr(this);
269   connect(myContextMenuMgr, SIGNAL(actionTriggered(const QString&, bool)), this,
270           SLOT(onContextMenuCommand(const QString&, bool)));
271
272   myViewerProxy = new XGUI_ViewerProxy(this);
273   //connect(myViewerProxy, SIGNAL(selectionChanged()),
274   //        myActionsMgr,  SLOT(updateOnViewSelection()));
275
276   myOperationMgr->setWorkshop(aWorkshop);
277
278   myErrorMgr = new XGUI_ErrorMgr(this, aWorkshop);
279
280   connect(myOperationMgr, SIGNAL(operationResumed(ModuleBase_Operation*)),
281           SLOT(onOperationResumed(ModuleBase_Operation*)));
282   connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
283           SLOT(onOperationStopped(ModuleBase_Operation*)));
284   connect(myOperationMgr, SIGNAL(operationCommitted(ModuleBase_Operation*)),
285           SLOT(onOperationCommitted(ModuleBase_Operation*)));
286   connect(myOperationMgr, SIGNAL(operationAborted(ModuleBase_Operation*)),
287           SLOT(onOperationAborted(ModuleBase_Operation*)));
288
289 #ifndef HAVE_SALOME
290   connect(myMainWindow, SIGNAL(exitKeySequence()), SLOT(onExit()));
291   myDisplayer->displayTrihedron(true);
292 #endif
293
294   connect(myEventsListener, SIGNAL(errorOccurred(std::shared_ptr<Events_InfoMessage>)),
295           myErrorDlg, SLOT(addError(std::shared_ptr<Events_InfoMessage>)));
296
297   Config_PropManager::registerProp("Visualization", "selection_color", "Selection color",
298     Config_Prop::Color, "255,255,255");
299
300   if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "face-selection", true))
301     myViewerSelMode.append(TopAbs_FACE);
302   if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "edge-selection", true))
303     myViewerSelMode.append(TopAbs_EDGE);
304   if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "vertex-selection", true))
305     myViewerSelMode.append(TopAbs_VERTEX);
306   //IMP: an attempt to use result selection with other selection modes
307   myViewerSelMode.append(ModuleBase_ResultPrs::Sel_Result);//TopAbs_VERTEX);
308   myViewerSelMode.append(TopAbs_COMPSOLID);
309 }
310
311 //******************************************************
312 XGUI_Workshop::~XGUI_Workshop(void)
313 {
314 #ifdef _DEBUG
315 #ifdef MISSED_TRANSLATION
316   // Save Missed translations
317   Config_Translator::saveMissedTranslations();
318 #endif
319 #endif
320
321   delete myDisplayer;
322   delete myDataModelXMLReader;
323   delete mySelectionActivate;
324   delete myMenuMgr;
325   clearTemporaryDir();
326 }
327
328 //******************************************************
329 void XGUI_Workshop::startApplication()
330 {
331   //Initialize event listening
332   myEventsListener->initializeEventListening();
333
334   myDataModelXMLReader->readAll();
335   initMenu();
336
337   Config_PropManager::registerProp("Plugins", "default_path", "Default Path",
338                                    Config_Prop::Directory, "");
339
340   std::string aDir = Config_XMLReader::resourcesConfigFile();
341   Config_PropManager::registerProp("Plugins", "import_initial_path", "Import initial directory",
342                                    Config_Prop::Directory, aDir);
343
344 #ifdef _DEBUG
345   Config_PropManager::registerProp("Plugins", "create_part_by_start", "Create Part by Start",
346     Config_Prop::Boolean, "false");
347
348   Config_PropManager::registerProp("Plugins", "show_hide_faces", "Show Hide Faces (on the right)",
349     Config_Prop::Boolean, "false");
350 #endif
351   registerValidators();
352
353   // Calling of  loadCustomProps before activating module is required
354   // by Config_PropManger to restore user-defined path to plugins
355   ModuleBase_Preferences::loadCustomProps();
356   std::vector<int> aColor;
357   try {
358     aColor = Config_PropManager::color("Visualization", "selection_color");
359   }
360   catch (...) {
361   }
362   if (aColor.size() == 3)
363     myDisplayer->setSelectionColor(aColor);
364
365   createModule();
366
367 #ifndef HAVE_SALOME
368   myMainWindow->show();
369   updateCommandStatus();
370 #endif
371
372   onNew();
373
374   myViewerProxy->connectViewProxy();
375   connect(myViewerProxy, SIGNAL(trihedronVisibilityChanged(bool)),
376           SLOT(onTrihedronVisibilityChanged(bool)));
377
378   emit applicationStarted();
379
380 #ifdef _DEBUG
381   bool aNewPart = Config_PropManager::boolean("Plugins", "create_part_by_start");
382   if (aNewPart) {
383       module()->launchOperation("Part", false); // PartSetPlugin_Part::ID()
384   }
385 #endif
386 }
387
388 //******************************************************
389 void XGUI_Workshop::activateModule()
390 {
391   selectionActivate()->updateSelectionFilters();
392
393   connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
394     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
395   connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
396     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
397
398   updateCommandStatus();
399
400   // TODO: get default selection mode
401
402   // activate visualized objects in the viewer
403   activateObjectsSelection(displayer()->displayedObjects());
404   myOperationMgr->activate();
405 }
406
407 //******************************************************
408 void XGUI_Workshop::deactivateModule()
409 {
410   // remove internal displayer filter
411   displayer()->deactivateSelectionFilters(false);
412
413   disconnect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
414     myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
415   disconnect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
416     myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
417
418   XGUI_Displayer* aDisplayer = displayer();
419   QObjectPtrList aDisplayed = aDisplayer->displayedObjects();
420   aDisplayer->deactivateObjects(aDisplayed, true);
421   selectionActivate()->deactivateTrihedronInSelectionModes();
422
423 #ifdef BEFORE_TRIHEDRON_PATCH
424   //Handle(AIS_Trihedron) aTrihedron = Handle(AIS_Trihedron)::DownCast(aDisplayer->getTrihedron());
425   /// Trihedron problem: objects stayed in the viewer, should be removed manually
426   /// otherwise in SALOME happens crash by HideAll in the viewer
427   aContext->Remove(aTrihedron->Position(), true);
428   aContext->Remove(aTrihedron->Axis(), true);
429   aContext->Remove(aTrihedron->XAxis(), true);
430   aContext->Remove(aTrihedron->YAxis(), true);
431 #endif
432
433   myOperationMgr->deactivate();
434 }
435
436 //******************************************************
437 void XGUI_Workshop::initMenu()
438 {
439   myContextMenuMgr->createActions();
440
441 #ifdef HAVE_SALOME
442   // Create only Undo, Redo commands
443   QAction* aAction = salomeConnector()->addDesktopCommand("UNDO_CMD", tr("Undo"),
444                                                         tr("Undo last command"),
445                                                         QIcon(":pictures/undo.png"),
446                                                         QKeySequence::Undo, false,
447                                                         "MEN_DESK_EDIT");
448   QString aToolBarTitle = tr( "INF_DESK_TOOLBAR_STANDARD" );
449   salomeConnector()->addActionInToolbar( aAction,aToolBarTitle );
450
451   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onUndo()));
452   addHistoryMenu(aAction, SIGNAL(updateUndoHistory(const QList<ActionInfo>&)), SLOT(onUndo(int)));
453
454   aAction = salomeConnector()->addDesktopCommand("REDO_CMD", tr("Redo"), tr("Redo last command"),
455                                               QIcon(":pictures/redo.png"), QKeySequence::Redo,
456                                               false, "MEN_DESK_EDIT");
457   salomeConnector()->addActionInToolbar( aAction, aToolBarTitle );
458
459   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onRedo()));
460   addHistoryMenu(aAction, SIGNAL(updateRedoHistory(const QList<ActionInfo>&)), SLOT(onRedo(int)));
461
462   salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
463
464   //aAction = salomeConnector()->addDesktopCommand("AUTOCOMPUTE_CMD", tr("Auto rebuild"),
465   //                                            tr("Blocks immediate apply of modifications"),
466   //                                            QIcon(":pictures/autoapply.png"), QKeySequence(),
467   //                                            false, "MEN_DESK_EDIT");
468   //salomeConnector()->addActionInToolbar( aAction, aToolBarTitle );
469
470   //connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onAutoApply()));
471
472   salomeConnector()->addDesktopMenuSeparator("MEN_DESK_EDIT");
473
474
475   // Add commands to a file menu
476   // Import sub-menu
477   aAction = salomeConnector()->addDesktopCommand("OPEN_CMD", tr("Part set..."),
478                                               tr("Import native file"),
479                                               QIcon(), QKeySequence(),
480                                               false, "MEN_DESK_FILE", tr("Import"), 10, 10);
481   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen()));
482
483   aAction = salomeConnector()->addDesktopCommand("IMPORT_PART_CMD", tr("Part..."),
484                                           tr("Import structure of a part"),
485                                           QIcon(), QKeySequence(),
486                                           false, "MEN_DESK_FILE", tr("Import"), 10, 10);
487   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportPart()));
488
489   aAction = salomeConnector()->addDesktopCommand("IMPORT_SHAPE_CMD", tr("From CAD format..."),
490     tr("Import shape from a CAD format file"),
491     ModuleBase_IconFactory::loadIcon("icons/Exchange/import.png"),
492     QKeySequence(), false, "MEN_DESK_FILE", tr("Import"), 10, 10);
493   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportShape()));
494
495   // Export sub-menu
496   aAction = salomeConnector()->addDesktopCommand("SAVEAS_CMD", tr("Part set..."),
497                                              tr("Export the current document into a native file"),
498                                               QIcon(), QKeySequence(),
499                                               false, "MEN_DESK_FILE", tr("Export"), 10, 11);
500   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onSaveAs()));
501
502   aAction = salomeConnector()->addDesktopCommand("EXPORT_PART_CMD", tr("Part..."),
503                                           tr("Export a part of the current document into a file"),
504                                           QIcon(), QKeySequence(),
505                                           false, "MEN_DESK_FILE", tr("Export"), 10, 11);
506   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onExportPart()));
507
508   aAction = salomeConnector()->addDesktopCommand("EXPORT_SHAPE_CMD", tr("To CAD format..."),
509     tr("Export shape to a CAD format file"),
510     ModuleBase_IconFactory::loadIcon("icons/Exchange/export.png"),
511     QKeySequence(), false, "MEN_DESK_FILE", tr("Export"), 10, 11);
512   connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onExportShape()));
513
514 #else
515   // File commands group
516   AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage();
517
518   AppElements_Command* aCommand;
519
520   aCommand = aGroup->addFeature("SAVE_CMD", tr("Save"), tr("Save the document"),
521                                 QIcon(":pictures/save.png"), QKeySequence::Save);
522   aCommand->connectTo(this, SLOT(onSave()));
523   //aCommand->disable();
524
525   aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"),
526                                 QIcon(":pictures/save.png"), QKeySequence());
527   aCommand->connectTo(this, SLOT(onSaveAs()));
528
529   QString aUndoId = "UNDO_CMD";
530   aCommand = aGroup->addFeature(aUndoId, tr("Undo"), tr("Undo last command"),
531                                 QIcon(":pictures/undo.png"), QKeySequence::Undo);
532   aCommand->connectTo(this, SLOT(onUndo()));
533   AppElements_Button* aUndoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aUndoId));
534   addHistoryMenu(aUndoButton,
535                  SIGNAL(updateUndoHistory(const QList<ActionInfo>&)),
536                  SLOT(onUndo(int)));
537
538   QString aRedoId = "REDO_CMD";
539   aCommand = aGroup->addFeature(aRedoId, tr("Redo"), tr("Redo last command"),
540                                 QIcon(":pictures/redo.png"), QKeySequence::Redo);
541   aCommand->connectTo(this, SLOT(onRedo()));
542   AppElements_Button* aRedoButton = qobject_cast<AppElements_Button*>(aGroup->widget(aRedoId));
543   addHistoryMenu(aRedoButton,
544                  SIGNAL(updateRedoHistory(const QList<ActionInfo>&)),
545                  SLOT(onRedo(int)));
546
547   aCommand = aGroup->addFeature("OPEN_CMD", tr("Open..."), tr("Open a new document"),
548                                 QIcon(":pictures/open.png"), QKeySequence::Open);
549   aCommand->connectTo(this, SLOT(onOpen()));
550
551
552   aCommand = aGroup->addFeature("AUTOCOMPUTE_CMD", tr("Auto rebuild"),
553                                 tr("Blocks immediate apply of modifications"),
554                                 QIcon(":pictures/autoapply_start.png"), QKeySequence());
555   aCommand->setChecked(ModelAPI_Session::get()->isAutoUpdateBlocked());
556   aCommand->connectTo(this, SLOT(onAutoApply()));
557
558   aCommand = aGroup->addFeature("PREF_CMD", tr("Preferences"), tr("Edit preferences"),
559                                 QIcon(":pictures/preferences.png"), QKeySequence::Preferences);
560   aCommand->connectTo(this, SLOT(onPreferences()));
561
562   aCommand = aGroup->addFeature("EXIT_CMD", tr("Exit"), tr("Exit application"),
563                                 QIcon(":pictures/close.png"), QKeySequence::Close);
564   aCommand->connectTo(this, SLOT(onExit()));
565 #endif
566 }
567
568 #ifndef HAVE_SALOME
569 //******************************************************
570 AppElements_Workbench* XGUI_Workshop::addWorkbench(const QString& theName)
571 {
572   AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
573   return aMenuBar->addWorkbench(theName);
574 }
575 #endif
576
577 //******************************************************
578 QMainWindow* XGUI_Workshop::desktop() const
579 {
580 #ifdef HAVE_SALOME
581   return salomeConnector()->desktop();
582 #else
583   return myMainWindow;
584 #endif
585 }
586
587 //******************************************************
588 void XGUI_Workshop::onStartWaiting()
589 {
590   if (Events_LongOp::isPerformed()) {
591     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
592   }
593 }
594
595 //******************************************************
596 void XGUI_Workshop::onAcceptActionClicked()
597 {
598   QAction* anAction = dynamic_cast<QAction*>(sender());
599   XGUI_OperationMgr* anOperationMgr = operationMgr();
600   if (anOperationMgr) {
601     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
602                                                     (anOperationMgr->currentOperation());
603     if (aFOperation) {
604       //if (errorMgr()->canProcessClick(anAction, aFOperation->feature()))
605       myOperationMgr->commitOperation();
606     }
607   }
608 }
609
610 //******************************************************
611 void XGUI_Workshop::onAcceptPlusActionClicked()
612 {
613   QAction* anAction = dynamic_cast<QAction*>(sender());
614   XGUI_OperationMgr* anOperationMgr = operationMgr();
615   if (anOperationMgr) {
616     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
617                                                     (anOperationMgr->currentOperation());
618     if (aFOperation) {
619       if (myOperationMgr->commitOperation())
620         module()->launchOperation(aFOperation->id(), false);
621     }
622   }
623 }
624
625 //******************************************************
626 void XGUI_Workshop::onPreviewActionClicked()
627 {
628   ModuleBase_IPropertyPanel* aPanel = propertyPanel();
629   if (aPanel) {
630     ModuleBase_ModelWidget* anActiveWidget = aPanel->activeWidget();
631     if (anActiveWidget && anActiveWidget->getValueState() == ModuleBase_ModelWidget::ModifiedInPP) {
632       anActiveWidget->storeValue();
633     }
634   }
635   std::shared_ptr<Events_Message> aMsg = std::shared_ptr<Events_Message>(
636                 new Events_Message(Events_Loop::eventByName(EVENT_PREVIEW_REQUESTED)));
637   Events_Loop::loop()->send(aMsg);
638 }
639
640
641 //******************************************************
642 void XGUI_Workshop::onHelpActionClicked() const
643 {
644   XGUI_OperationMgr* anOperationMgr = operationMgr();
645   if (anOperationMgr) {
646     ModuleBase_Operation* aOperation = anOperationMgr->currentOperation();
647     if (aOperation) {
648       showHelpPage(aOperation->helpFileName());
649     }
650   }
651 }
652
653 void XGUI_Workshop::showHelpPage(const QString& thePage) const
654 {
655   if (!thePage.isEmpty()) {
656     QString aDocDir;
657     const QChar aSep = QDir::separator();
658 //        QString platform;
659 //        SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr();
660 //#ifdef WIN32
661 //        platform = "winapplication";
662 //#else
663 //        platform = "application";
664 //#endif
665 //        QString aBrowserName = aResMgr->stringValue("ExternalBrowser", platform);
666
667 #ifdef HAVE_SALOME
668     QString aDir(getenv("SHAPER_ROOT_DIR"));
669     if (!aDir.isEmpty()) {
670       aDocDir = aDir + aSep + "share" + aSep + "doc" + aSep +
671         "salome" + aSep + "gui" + aSep + "SHAPER";
672     }
673 #else
674     QString aDir(getenv("CADBUILDER_ROOT_DIR"));
675     aDocDir = aDir + aSep + "doc" + aSep + "gui";
676 #endif
677     QString aFileName = aDocDir + aSep + thePage;
678     if (QFile::exists(aFileName)) {
679       QUrl aUrl = QUrl::fromLocalFile(aFileName);
680       QDesktopServices::openUrl(aUrl);
681     }
682   }
683 }
684
685
686 //******************************************************
687 void XGUI_Workshop::deactivateActiveObject(const ObjectPtr& theObject, const bool theUpdateViewer)
688 {
689   if (!myModule->canActivateSelection(theObject)) {
690     if (selectionActivate()->isActive(theObject)) {
691       QObjectPtrList anObjects;
692       anObjects.append(theObject);
693       myDisplayer->deactivateObjects(anObjects, theUpdateViewer);
694     }
695   }
696 }
697
698 //******************************************************
699 bool XGUI_Workshop::isFeatureOfNested(const FeaturePtr& theFeature)
700 {
701   bool aHasNested = false;
702   std::string aFeatureKind = theFeature->getKind();
703 #ifdef HAVE_SALOME
704     XGUI_SalomeConnector* aSalomeConnector = salomeConnector();
705     if (aSalomeConnector->isFeatureOfNested(actionsMgr()->action(aFeatureKind.c_str())))
706       aHasNested = true;
707 #else
708     AppElements_MainMenu* aMenuBar = mainWindow()->menuObject();
709     AppElements_Command* aCommand = aMenuBar->feature(aFeatureKind.c_str());
710     if (aCommand && aCommand->button()->additionalButtonWidget())
711       aHasNested = true;
712 #endif
713   return aHasNested;
714 }
715
716 //******************************************************
717 void XGUI_Workshop::fillPropertyPanel(ModuleBase_Operation* theOperation)
718 {
719   ModuleBase_OperationFeature* aFOperation =
720     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
721   if (!aFOperation)
722     return;
723
724   myPropertyPanel->cleanContent();
725
726   QList<ModuleBase_ModelWidget*> aWidgets;
727   QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
728   if (!module()->createWidgets(aFOperation->feature(), aXmlRepr, aWidgets)) {
729     ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector);
730     aFactory.createWidget(myPropertyPanel->contentWidget());
731     aWidgets = aFactory.getModelWidgets();
732   }
733
734   // check compatibility of feature and widgets
735   FeaturePtr aFeature = aFOperation->feature();
736   std::string aFeatureKind = aFeature->getKind();
737   foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
738     if (aWidget->usesAttribute()) {
739       if (!aWidget->attributeID().empty() && !aFeature->attribute(aWidget->attributeID()).get()) {
740         std::string anErrorMsg = "The feature '%1' has no attribute '%2' used by widget '%3'.";
741         Events_InfoMessage("XGUI_Workshop", anErrorMsg)
742           .arg(aFeatureKind).arg(aWidget->attributeID())
743           .arg(aWidget->metaObject()->className()).send();
744         myPropertyPanel->cleanContent();
745         return;
746       }
747     }
748   }
749   // for performance purpose, flush should be done after all controls are filled
750   bool isUpdateFlushed = false;
751   foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
752     bool isStoreValue = !aFOperation->isEditOperation() &&
753                         !aWidget->getDefaultValue().empty() &&
754                         !aWidget->isComputedDefault();
755     aWidget->setFeature(aFeature, isStoreValue, isUpdateFlushed);
756     if (!isStoreValue)
757       aWidget->restoreValue();
758     aWidget->enableFocusProcessing();
759   }
760   // update visible state of Preview button
761   std::shared_ptr<Config_FeatureMessage> aFeatureInfo;
762 #ifdef HAVE_SALOME
763   aFeatureInfo = mySalomeConnector->featureInfo(aFeatureKind.c_str());
764 #else
765   AppElements_MainMenu* aMenuBar = mainWindow()->menuObject();
766   AppElements_Command* aCommand = aMenuBar->feature(aFeatureKind.c_str());
767   if (aCommand)
768     aFeatureInfo = aCommand->featureMessage();
769 #endif
770   bool anIsAutoPreview = true;
771   if (aFeatureInfo.get()) {
772     anIsAutoPreview = aFeatureInfo->isAutoPreview();
773     theOperation->setHelpFileName(aFeatureInfo->helpFileName().c_str());
774   } else {
775     std::string aXmlCfg, aDescription;
776     module()->getXMLRepresentation(aFeatureKind, aXmlCfg, aDescription);
777     ModuleBase_WidgetFactory aFactory(aXmlCfg, moduleConnector());
778     anIsAutoPreview = aFactory.widgetAPI()->getBooleanAttribute(FEATURE_AUTO_PREVIEW, true);
779   }
780
781   if (!anIsAutoPreview) {
782     myPropertyPanel->findButton(PROP_PANEL_PREVIEW)->setVisible(true);
783     // send signal about preview should not be computed automatically, click on preview
784     // button should initiate it
785     std::shared_ptr<Events_Message> aMsg = std::shared_ptr<Events_Message>(
786                   new Events_Message(Events_Loop::eventByName(EVENT_PREVIEW_BLOCKED)));
787     Events_Loop::loop()->send(aMsg);
788   }
789   // if update happens after preview is blocked, it does nothing when blocked
790   // it improves performance for valid objects on feature start
791   ModuleBase_Tools::flushUpdated(aFeature);
792
793   myPropertyPanel->setModelWidgets(aWidgets);
794   aFOperation->setPropertyPanel(myPropertyPanel);
795
796   myModule->propertyPanelDefined(theOperation);
797
798 #ifndef DEBUG_FEATURE_NAME
799   myPropertyPanel->setWindowTitle(ModuleBase_Tools::translate("workshop",
800     theOperation->getDescription()->description().toStdString()));
801 #else
802   std::string aFeatureName = aFeature->name();
803   myPropertyPanel->setWindowTitle(QString("%1: %2")
804     .arg(translate(theOperation->getDescription()->description()))
805     .arg(translate(aFeatureName.c_str())));
806 #endif
807
808   myErrorMgr->setPropertyPanel(myPropertyPanel);
809   if (Config_PropManager::boolean("Windows", "use_hide_faces_panel")) {
810     theOperation->setHideFacesVisible(myFacesPanel->isVisible());
811     if (aFeatureInfo.get() && aFeatureInfo->isHideFacesPanel() && !myFacesPanel->isVisible())
812       myFacesPanel->show();
813   }
814   showPanel(myPropertyPanel);
815 }
816
817 //******************************************************
818 void XGUI_Workshop::connectToPropertyPanel(const bool isToConnect)
819 {
820   XGUI_PropertyPanel* aPropertyPanel = propertyPanel();
821   if (aPropertyPanel) {
822     const QList<ModuleBase_ModelWidget*>& aWidgets = aPropertyPanel->modelWidgets();
823     foreach (ModuleBase_ModelWidget* aWidget, aWidgets) {
824        myModule->connectToPropertyPanel(aWidget, isToConnect);
825        if (isToConnect) {
826         connect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int)));
827         connect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChanged()));
828         connect(aWidget, SIGNAL(objectUpdated()), this, SLOT(onWidgetObjectUpdated()));
829        }
830       else {
831         disconnect(aWidget, SIGNAL(valueStateChanged(int)), this, SLOT(onWidgetStateChanged(int)));
832         disconnect(aWidget, SIGNAL(valuesChanged()), this, SLOT(onValuesChanged()));
833         disconnect(aWidget, SIGNAL(objectUpdated()), this, SLOT(onWidgetObjectUpdated()));
834       }
835     }
836   }
837 }
838
839 //******************************************************
840 void XGUI_Workshop::onOperationResumed(ModuleBase_Operation* theOperation)
841 {
842   setGrantedFeatures(theOperation);
843
844   if (theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
845     fillPropertyPanel(theOperation);
846     connectToPropertyPanel(true);
847     ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
848       (theOperation);
849     if (aFOperation)
850       myPropertyPanel->updateApplyPlusButton(aFOperation->feature());
851     else
852       myPropertyPanel->updateApplyPlusButton(FeaturePtr());
853   }
854   updateCommandStatus();
855
856   myModule->operationResumed(theOperation);
857 }
858
859 //******************************************************
860 void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
861 {
862   updateCommandStatus();
863
864   ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
865                                                                         (theOperation);
866   if (!aFOperation)
867     return;
868
869   ModuleBase_ISelection* aSel = mySelector->selection();
870   QObjectPtrList aObj = aSel->selectedPresentations();
871   //!< No need for property panel
872   hidePanel(myPropertyPanel);
873   myPropertyPanel->cleanContent();
874
875   connectToPropertyPanel(false);
876   myModule->operationStopped(aFOperation);
877
878   // the deactivated objects of the current operation should be activated back.
879   // They were deactivated on operation start or an object redisplay
880   QObjectPtrList anObjects;
881   FeaturePtr aFeature = aFOperation->feature();
882   if (aFeature.get()) { // feature may be not created (plugin load fail)
883     if (myDisplayer->isVisible(aFeature) && !selectionActivate()->isActive(aFeature))
884       anObjects.append(aFeature);
885     std::list<ResultPtr> aResults;
886     ModelAPI_Tools::allResults(aFeature, aResults);
887     std::list<ResultPtr>::const_iterator aIt;
888     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
889       ResultPtr anObject = *aIt;
890       if (myDisplayer->isVisible(anObject) && !selectionActivate()->isActive(anObject)) {
891         anObjects.append(anObject);
892       }
893     }
894   }
895   activateObjectsSelection(anObjects);
896
897   if (Config_PropManager::boolean("Windows", "use_hide_faces_panel")) {
898     if (!theOperation->isHideFacesVisible())
899       myFacesPanel->close();
900   }
901 }
902
903 //******************************************************
904 void XGUI_Workshop::onOperationCommitted(ModuleBase_Operation* theOperation)
905 {
906   myModule->operationCommitted(theOperation);
907 }
908
909 //******************************************************
910 void XGUI_Workshop::onOperationAborted(ModuleBase_Operation* theOperation)
911 {
912   myModule->operationAborted(theOperation);
913 }
914
915 //******************************************************
916 void XGUI_Workshop::setGrantedFeatures(ModuleBase_Operation* theOperation)
917 {
918   ModuleBase_OperationFeature* aFOperation =
919     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
920   if (!aFOperation)
921     return;
922
923   QStringList aGrantedIds;
924   if (isSalomeMode()) {
925     const std::shared_ptr<Config_FeatureMessage>& anInfo =
926                          mySalomeConnector->featureInfo(theOperation->id());
927     if (anInfo.get())
928       aGrantedIds = QString::fromStdString(anInfo->nestedFeatures())
929                                    .split(" ", QString::SkipEmptyParts);
930   }
931   else
932     aGrantedIds = myActionsMgr->nestedCommands(theOperation->id());
933
934   ModuleBase_IModule* aModule = module();
935   if (aModule)
936     aModule->grantedOperationIds(theOperation, aGrantedIds);
937
938   aFOperation->setGrantedOperationIds(aGrantedIds);
939 }
940
941 //******************************************************
942 void XGUI_Workshop::saveDocument(const QString& theName, std::list<std::string>& theFileNames)
943 {
944   QApplication::restoreOverrideCursor();
945   SessionPtr aMgr = ModelAPI_Session::get();
946
947   std::list<DocumentPtr> aDocList = aMgr->allOpenedDocuments();
948   std::list<DocumentPtr>::const_iterator aIt;
949   for (aIt = aDocList.cbegin(); aIt != aDocList.cend(); aIt++) {
950     std::list<bool> aState = myObjectBrowser->getStateForDoc(*aIt);
951     (*aIt)->storeNodesState(aState);
952   }
953
954   aMgr->save(theName.toLatin1().constData(), theFileNames);
955
956   QApplication::restoreOverrideCursor();
957 }
958
959 //******************************************************
960 bool XGUI_Workshop::abortAllOperations()
961 {
962   return myOperationMgr->abortAllOperations();
963 }
964
965 //******************************************************
966 void XGUI_Workshop::operationStarted(ModuleBase_Operation* theOperation)
967 {
968   setGrantedFeatures(theOperation);
969   if (!theOperation->getDescription()->hasXmlRepresentation()) {  //!< No need for property panel
970     updateCommandStatus();
971   }
972   else {
973     myModule->operationStarted(theOperation);
974   }
975 }
976
977 //******************************************************
978 void XGUI_Workshop::onOpen()
979 {
980   if(!abortAllOperations())
981     return;
982   //save current file before close if modified
983   SessionPtr aSession = ModelAPI_Session::get();
984   if (aSession->isModified()) {
985     int anAnswer = QMessageBox::question(
986         desktop(), tr("Save current file"),
987         tr("The document is modified, save before opening another?"),
988         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
989     if (anAnswer == QMessageBox::Save) {
990       onSave();
991     } else if (anAnswer == QMessageBox::Cancel) {
992       return;
993     }
994     myCurrentFile = QString();
995   }
996
997   //show file dialog, check if readable and open
998   qreal aRatio = ModuleBase_Tools::currentPixelRatio();
999   // If the ratio is > 1 (HD screen) then QT has a bug in
1000   // displaying of system open file dialog (too small)
1001   QString aFile = QFileDialog::getOpenFileName(desktop(), tr("Open file"), QString(), MyFilter,
1002     Q_NULLPTR, ((aRatio > 1)? QFileDialog::DontUseNativeDialog : QFileDialog::Options()));
1003   if (!aFile.isNull())
1004     openFile(aFile);
1005 }
1006
1007 //******************************************************
1008 void XGUI_Workshop::openFile(const QString& theDirectory)
1009 {
1010   myCurrentFile = theDirectory;
1011   if (myCurrentFile.isEmpty())
1012     return;
1013
1014   QFileInfo aFileInfo(myCurrentFile);
1015   if (!aFileInfo.exists() || !aFileInfo.isReadable()) {
1016     QMessageBox::critical(desktop(), tr("Warning"), tr("Unable to open the file."));
1017     myCurrentFile = QString();
1018     return;
1019   }
1020
1021   QApplication::setOverrideCursor(Qt::WaitCursor);
1022   module()->closeDocument();
1023   SessionPtr aSession = ModelAPI_Session::get();
1024   aSession->closeAll();
1025
1026   clearTemporaryDir();
1027   if (!XGUI_CompressFiles::uncompress(myCurrentFile, myTmpDir.path()))
1028     return;
1029
1030   aSession->load(myTmpDir.path().toLatin1().constData());
1031   myObjectBrowser->rebuildDataTree();
1032
1033   // Open first level of data tree
1034   DocumentPtr aRootDoc = aSession->moduleDocument();
1035   std::list<bool> aStates;
1036   aRootDoc->restoreNodesState(aStates);
1037   myObjectBrowser->setStateForDoc(aRootDoc, aStates);
1038
1039   updateCommandStatus();
1040 #ifndef HAVE_SALOME
1041   myMainWindow->setCurrentDir(myCurrentFile, true);
1042 #endif
1043
1044 #ifdef _DEBUG
1045   bool aNewPart = Config_PropManager::boolean("Plugins", "create_part_by_start");
1046   if (aNewPart) {
1047
1048     DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
1049     int aSize = aRootDoc->size(ModelAPI_ResultPart::group());
1050     if (aSize > 0 ) {
1051       ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), 0);
1052       ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObject);
1053       if (aPart.get())
1054         aPart->activate();
1055     }
1056   }
1057 #endif
1058
1059   QApplication::restoreOverrideCursor();
1060 }
1061
1062 //******************************************************
1063 void XGUI_Workshop::onNew()
1064 {
1065   QApplication::setOverrideCursor(Qt::WaitCursor);
1066   if (objectBrowser() == 0) {
1067     createDockWidgets();
1068     mySelector->connectViewers();
1069   }
1070   myViewerProxy->connectToViewer();
1071   showObjectBrowser();
1072 #ifndef HAVE_SALOME
1073   myMainWindow->showPythonConsole();
1074   QMdiSubWindow* aWnd = myMainWindow->viewer()->createView();
1075   aWnd->showMaximized();
1076   updateCommandStatus();
1077   PyConsole_Console* aConsole = myMainWindow->pythonConsole();
1078   connect(aConsole, SIGNAL(scriptLoaded()), SLOT(updateCommandStatus()));
1079 #endif
1080   myContextMenuMgr->connectViewer();
1081   QApplication::restoreOverrideCursor();
1082 }
1083
1084 #ifndef HAVE_SALOME
1085 //******************************************************
1086 void XGUI_Workshop::onExit()
1087 {
1088   SessionPtr aMgr = ModelAPI_Session::get();
1089   if (aMgr->isModified()) {
1090     int anAnswer = QMessageBox::question(
1091         myMainWindow, tr("Save current file"), tr("The document is modified, save before exit?"),
1092         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
1093     if (anAnswer == QMessageBox::Save) {
1094       bool saved = onSave();
1095       if (!saved) {
1096         return;
1097       }
1098     } else if (anAnswer == QMessageBox::Cancel) {
1099       return;
1100     }
1101   }
1102   qApp->exit();
1103 }
1104
1105 //******************************************************
1106 void XGUI_Workshop::onPreferences()
1107 {
1108   ModuleBase_Prefs aModif;
1109   ModuleBase_Preferences::editPreferences(aModif);
1110   if (aModif.size() > 0) {
1111     QString aSection;
1112     foreach (ModuleBase_Pref aPref, aModif) {
1113       aSection = aPref.first;
1114       if (aSection == ModuleBase_Preferences::VIEWER_SECTION) {
1115         myMainWindow->viewer()->updateFromResources();
1116       } else if (aSection == ModuleBase_Preferences::MENU_SECTION) {
1117         myMainWindow->menuObject()->updateFromResources();
1118       }
1119     }
1120     std::vector<int> aColor;
1121     try {
1122       aColor = Config_PropManager::color("Visualization", "selection_color");
1123     }
1124     catch (...) {
1125     }
1126     if (aColor.size() == 3)
1127       displayer()->setSelectionColor(aColor);
1128
1129     displayer()->redisplayObjects();
1130   }
1131 }
1132 #endif
1133
1134 //******************************************************
1135 void XGUI_Workshop::onTrihedronVisibilityChanged(bool theState)
1136 {
1137   XGUI_Displayer* aDisplayer = displayer();
1138   if (aDisplayer) {
1139     aDisplayer->displayTrihedron(theState);
1140     aDisplayer->updateViewer();
1141   }
1142 }
1143
1144 //******************************************************
1145 bool XGUI_Workshop::onSave()
1146 {
1147   if(!myOperationMgr->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
1148     return false;
1149   if (myCurrentFile.isEmpty()) {
1150     return onSaveAs();
1151   }
1152   SessionPtr aMgr = ModelAPI_Session::get();
1153   if (aMgr->isAutoUpdateBlocked())
1154     aMgr->blockAutoUpdate(false);
1155
1156   std::list<std::string> aFiles;
1157   // issue #2899: create a temporary directory, save and then remove it
1158 #ifdef HAVE_SALOME
1159   std::string aTmpDir = XGUI_Tools::getTmpDirByEnv("SALOME_TMP_DIR");
1160 #else
1161   std::string aTmpDir = XGUI_Tools::getTmpDirByEnv("");
1162 #endif
1163   saveDocument(QString(aTmpDir.c_str()), aFiles);
1164   bool aResult = XGUI_CompressFiles::compress(myCurrentFile, aFiles);
1165   XGUI_Tools::removeTemporaryFiles(aTmpDir, aFiles);
1166
1167   if (aResult) {
1168     updateCommandStatus();
1169 #ifndef HAVE_SALOME
1170     myMainWindow->setModifiedState(false);
1171 #endif
1172   }
1173   return aResult;
1174 }
1175
1176 //******************************************************
1177 bool XGUI_Workshop::onSaveAs()
1178 {
1179   if(!myOperationMgr->abortAllOperations(XGUI_OperationMgr::XGUI_InformationMessage))
1180     return false;
1181   qreal aRatio = ModuleBase_Tools::currentPixelRatio();
1182   myCurrentFile = QFileDialog::getSaveFileName(desktop(), tr("Select name to save file..."),
1183     QString(), MyFilter2,
1184     Q_NULLPTR, ((aRatio > 1) ? QFileDialog::DontUseNativeDialog : QFileDialog::Options()));
1185   if (!myCurrentFile.isNull()) {
1186     if (!myCurrentFile.endsWith(MyExtension)) {
1187       myCurrentFile += MyExtension;
1188     }
1189   }
1190   else
1191     return false;
1192 #ifndef HAVE_SALOME
1193     myMainWindow->setCurrentDir(myCurrentFile, false);
1194     myMainWindow->setModifiedState(false);
1195 #endif
1196   return onSave();
1197 }
1198
1199 //******************************************************
1200 void XGUI_Workshop::onUndo(int theTimes)
1201 {
1202   processUndoRedo(ActionUndo, theTimes);
1203   myObjectBrowser->updateAllIndexes(1);
1204 }
1205
1206 //******************************************************
1207 void XGUI_Workshop::onRedo(int theTimes)
1208 {
1209   processUndoRedo(ActionRedo, theTimes);
1210   myObjectBrowser->updateAllIndexes(1);
1211 }
1212
1213 //******************************************************
1214 void XGUI_Workshop::processUndoRedo(const ModuleBase_ActionType theActionType, int theTimes)
1215 {
1216   ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget();
1217   if (anActiveWidget) {
1218     ActionIntParamPtr aParam(new ModuleBase_ActionIntParameter(theTimes));
1219     if (anActiveWidget->processAction(theActionType, aParam))
1220       return;
1221   }
1222   // the viewer update should be blocked in order to avoid the features blinking. For the created
1223   // feature a results are created, the flush of the created signal caused the viewer redisplay for
1224   // each created result. After a redisplay signal is flushed. So, the viewer update is blocked
1225   // until redo of all possible objects happens
1226   bool isUpdateEnabled = myDisplayer->enableUpdateViewer(false);
1227
1228   SessionPtr aMgr = ModelAPI_Session::get();
1229   if (aMgr->isOperation()) {
1230     XGUI_OperationMgr* aOpMgr = operationMgr();
1231     /// this is important for nested operations
1232     /// when sketch operation is active, this condition is false and
1233     /// the sketch operation is not aborted
1234     if (aOpMgr->canStopOperation(aOpMgr->currentOperation()))
1235       aOpMgr->abortOperation(aOpMgr->currentOperation());
1236     else
1237     {
1238       myDisplayer->enableUpdateViewer(isUpdateEnabled);
1239       return;
1240     }
1241   }
1242   objectBrowser()->treeView()->setCurrentIndex(QModelIndex());
1243   std::list<std::string> anActionList = theActionType == ActionUndo ? aMgr->undoList()
1244     : aMgr->redoList();
1245   std::list<std::string>::const_iterator aIt = anActionList.cbegin();
1246   for (int i = 0; (i < theTimes) && (aIt != anActionList.cend()); ++i, ++aIt) {
1247     if (theActionType == ActionUndo)
1248       aMgr->undo();
1249     else
1250       aMgr->redo();
1251
1252     if (QString((*aIt).c_str()) == MOVE_TO_END_COMMAND ||
1253         QString((*aIt).c_str()) == MOVE_TO_END_SPLIT_COMMAND)
1254       myObjectBrowser->rebuildDataTree();
1255   }
1256   operationMgr()->updateApplyOfOperations();
1257   facesPanel()->reset(true);
1258   updateCommandStatus();
1259
1260   // unblock the viewer update functionality and make update on purpose
1261   myDisplayer->enableUpdateViewer(isUpdateEnabled);
1262   myDisplayer->updateViewer();
1263   // Clear messages in status bar from previous operations if exists
1264   setStatusBarMessage("");
1265 }
1266
1267 //******************************************************
1268 void XGUI_Workshop::onWidgetStateChanged(int thePreviousState)
1269 {
1270   ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget();
1271   //ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
1272   //if (anOperation) {
1273   //  ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
1274   //  if (aPanel)
1275   //    anActiveWidget = aPanel->activeWidget();
1276   //}
1277   if (anActiveWidget)
1278     operationMgr()->onValidateOperation();
1279
1280   myModule->widgetStateChanged(thePreviousState);
1281 }
1282
1283 //******************************************************
1284 void XGUI_Workshop::onValuesChanged()
1285 {
1286   ModuleBase_ModelWidget* aSenderWidget = (ModuleBase_ModelWidget*)(sender());
1287   if (!aSenderWidget || aSenderWidget->canAcceptFocus())
1288     return;
1289
1290   ModuleBase_ModelWidget* anActiveWidget = 0;
1291   ModuleBase_Operation* anOperation = myOperationMgr->currentOperation();
1292   if (anOperation) {
1293     ModuleBase_IPropertyPanel* aPanel = anOperation->propertyPanel();
1294     if (aPanel)
1295       anActiveWidget = aPanel->activeWidget();
1296   }
1297   if (anActiveWidget) {
1298     ModuleBase_WidgetValidated* aWidgetValidated = dynamic_cast<ModuleBase_WidgetValidated*>
1299                                                                            (anActiveWidget);
1300     if (aWidgetValidated)
1301       aWidgetValidated->clearValidatedCash();
1302   }
1303 }
1304
1305 //******************************************************
1306 void XGUI_Workshop::onWidgetObjectUpdated()
1307 {
1308   operationMgr()->onValidateOperation();
1309   myDisplayer->updateViewer();
1310 }
1311
1312 //******************************************************
1313 void XGUI_Workshop::onImportPart()
1314 {
1315   if (abortAllOperations()) {
1316     ModuleBase_OperationFeature* anImportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
1317         module()->createOperation(ExchangePlugin_ImportPart::ID()));
1318     anImportPartOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() +
1319       "importFeature.html");
1320     myPropertyPanel->updateApplyPlusButton(anImportPartOp->feature());
1321     operationMgr()->startOperation(anImportPartOp);
1322   }
1323 }
1324
1325 //******************************************************
1326 void XGUI_Workshop::onImportShape()
1327 {
1328   if (abortAllOperations()) {
1329     ModuleBase_OperationFeature* anImportOp = dynamic_cast<ModuleBase_OperationFeature*>(
1330         module()->createOperation(ExchangePlugin_Import::ID()));
1331     anImportOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() +
1332       "importFeature.html");
1333     myPropertyPanel->updateApplyPlusButton(anImportOp->feature());
1334     operationMgr()->startOperation(anImportOp);
1335   }
1336 }
1337
1338 //******************************************************
1339 void XGUI_Workshop::onExportShape()
1340 {
1341   if (abortAllOperations()) {
1342     ModuleBase_OperationFeature* anExportOp = dynamic_cast<ModuleBase_OperationFeature*>(
1343         module()->createOperation(ExchangePlugin_ExportFeature::ID()));
1344     anExportOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() +
1345       "exportFeature.html");
1346     myPropertyPanel->updateApplyPlusButton(anExportOp->feature());
1347     operationMgr()->startOperation(anExportOp);
1348   }
1349 }
1350
1351 //******************************************************
1352 void XGUI_Workshop::onExportPart()
1353 {
1354   if (abortAllOperations()) {
1355     ModuleBase_OperationFeature* anExportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
1356         module()->createOperation(ExchangePlugin_ExportPart::ID()));
1357     anExportPartOp->setHelpFileName(QString("ExchangePlugin") + QDir::separator() +
1358       "exportFeature.html");
1359     myPropertyPanel->updateApplyPlusButton(anExportPartOp->feature());
1360     operationMgr()->startOperation(anExportPartOp);
1361   }
1362 }
1363
1364 //******************************************************
1365 ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule)
1366 {
1367   QString libName = QString::fromStdString(library(theModule.toStdString()));
1368   if (libName.isEmpty()) {
1369     qWarning(qPrintable(tr("Information about module \"%1\" doesn't exist.").arg(theModule)));
1370     return 0;
1371   }
1372
1373   QString err;
1374   CREATE_FUNC crtInst = 0;
1375
1376 #ifdef WIN32
1377   HINSTANCE modLib = ::LoadLibraryA(qPrintable(libName));
1378   if (!modLib) {
1379     LPVOID lpMsgBuf;
1380     ::FormatMessage(
1381         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1382         0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
1383     QString aMsg((char*) &lpMsgBuf);
1384     err = QString("Failed to load  %1. %2").arg(libName).arg(aMsg);
1385     ::LocalFree(lpMsgBuf);
1386   } else {
1387     crtInst = (CREATE_FUNC) ::GetProcAddress(modLib, CREATE_MODULE);
1388     if (!crtInst) {
1389       LPVOID lpMsgBuf;
1390       ::FormatMessage(
1391           FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
1392               | FORMAT_MESSAGE_IGNORE_INSERTS,
1393           0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
1394       QString aMsg((char*) &lpMsgBuf);
1395       err = QString("Failed to find  %1 function. %2").arg( CREATE_MODULE).arg(aMsg);
1396       ::LocalFree(lpMsgBuf);
1397     }
1398   }
1399 #else
1400   void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY | RTLD_GLOBAL );
1401   if ( !modLib ) {
1402     err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
1403   } else {
1404     crtInst = (CREATE_FUNC)dlsym( modLib, CREATE_MODULE );
1405     if ( !crtInst ) {
1406       err = QString( "Failed to find function %1. %2" ).arg( CREATE_MODULE ).arg( dlerror() );
1407     }
1408   }
1409 #endif
1410
1411   ModuleBase_IModule* aModule = crtInst ? crtInst(myModuleConnector) : 0;
1412
1413   if (!err.isEmpty()) {
1414     if (desktop()) {
1415       Events_InfoMessage("XGUI_Workshop", err.toStdString()).send();
1416     } else {
1417       qWarning(qPrintable(err));
1418     }
1419   }
1420   return aModule;
1421 }
1422
1423 //******************************************************
1424 bool XGUI_Workshop::createModule()
1425 {
1426   Config_ModuleReader aModuleReader;
1427   QString moduleName = QString::fromStdString(aModuleReader.getModuleName());
1428   myModule = loadModule(moduleName);
1429   if (!myModule)
1430     return false;
1431
1432   //connect(myDisplayer, SIGNAL(objectDisplayed(ObjectPtr, AISObjectPtr)),
1433   //  myModule, SLOT(onObjectDisplayed(ObjectPtr, AISObjectPtr)));
1434   //connect(myDisplayer, SIGNAL(beforeObjectErase(ObjectPtr, AISObjectPtr)),
1435   //  myModule, SLOT(onBeforeObjectErase(ObjectPtr, AISObjectPtr)));
1436
1437   myModule->createFeatures();
1438 #ifdef HAVE_SALOME
1439   salomeConnector()->createFeatureActions();
1440 #endif
1441   //myActionsMgr->update();
1442   return true;
1443 }
1444
1445 //******************************************************
1446 void XGUI_Workshop::updateCommandStatus()
1447 {
1448   QList<QAction*> aCommands;
1449 #ifdef HAVE_SALOME
1450     aCommands = salomeConnector()->commandList();
1451 #else
1452     AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
1453     foreach (AppElements_Command* aCmd, aMenuBar->features())
1454       aCommands.append(aCmd);
1455 #endif
1456   SessionPtr aMgr = ModelAPI_Session::get();
1457   if (aMgr->hasModuleDocument()) {
1458     foreach(QAction* aCmd, aCommands) {
1459       QString aId = aCmd->data().toString();
1460       if (aId == "UNDO_CMD") {
1461         bool isActionEnabled = false;
1462         // if ultimate is true -> using result of operation only, or using OR combination
1463         ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget();
1464         if (anActiveWidget && anActiveWidget->canProcessAction(ActionUndo, isActionEnabled))
1465           aCmd->setEnabled(isActionEnabled);
1466         else
1467           aCmd->setEnabled(myModule->canUndo());
1468       }
1469       else if (aId == "REDO_CMD") {
1470         bool isActionEnabled = false;
1471         // if ultimate is true -> using result of operation only, or using OR combination
1472         ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget();
1473         if (anActiveWidget && anActiveWidget->canProcessAction(ActionRedo, isActionEnabled))
1474           aCmd->setEnabled(isActionEnabled);
1475         else
1476           aCmd->setEnabled(myModule->canRedo());
1477       }
1478       else if (aId == "AUTOCOMPUTE_CMD") {
1479         aCmd->setIcon(aMgr->isAutoUpdateBlocked() ?
1480           QIcon(":pictures/autoapply_stop.png") :
1481           QIcon(":pictures/autoapply_start.png"));
1482       }
1483       else
1484         // Enable all commands
1485         aCmd->setEnabled(true);
1486     }
1487     updateHistory();
1488   } else {
1489     foreach(QAction* aCmd, aCommands) {
1490       QString aId = aCmd->data().toString();
1491       if (aId == "NEW_CMD")
1492         aCmd->setEnabled(true);
1493       else if (aId == "EXIT_CMD")
1494         aCmd->setEnabled(true);
1495       else
1496         aCmd->setEnabled(false);
1497     }
1498   }
1499   myActionsMgr->updateCommandsStatus();
1500   emit commandStatusUpdated();
1501 }
1502
1503 //******************************************************
1504 void XGUI_Workshop::updateHistory()
1505 {
1506   bool isActionEnabled = false;
1507   ModuleBase_ModelWidget* anActiveWidget = myOperationMgr->activeWidget();
1508   QList<ActionInfo> aUndoRes;
1509   QList<ActionInfo> aRedoRes;
1510   if (anActiveWidget && anActiveWidget->canProcessAction(ActionUndo, isActionEnabled)) {
1511     aUndoRes = anActiveWidget->actionsList(ActionUndo);
1512     aRedoRes = anActiveWidget->actionsList(ActionRedo);
1513   } else {
1514     std::list<std::string> aUndoList = ModelAPI_Session::get()->undoList();
1515     aUndoRes = processHistoryList(aUndoList);
1516
1517     std::list<std::string> aRedoList = ModelAPI_Session::get()->redoList();
1518     aRedoRes = processHistoryList(aRedoList);
1519   }
1520   emit updateUndoHistory(aUndoRes);
1521   emit updateRedoHistory(aRedoRes);
1522 }
1523
1524 //******************************************************
1525 QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
1526 {
1527   QDockWidget* aObjDock = new QDockWidget(theParent);
1528   aObjDock->setAllowedAreas(Qt::LeftDockWidgetArea |
1529                             Qt::RightDockWidgetArea);
1530   aObjDock->setWindowTitle(tr("Object browser"));
1531   aObjDock->setStyleSheet(
1532       "::title { position: relative; padding-left: 5px; text-align: left center }");
1533   myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock, this);
1534   myObjectBrowser->initialize(myModule->rootNode());
1535   myModule->customizeObjectBrowser(myObjectBrowser);
1536   aObjDock->setWidget(myObjectBrowser);
1537   aObjDock->setObjectName("Object browser");
1538
1539   connect(myObjectBrowser, SIGNAL(sizeChanged()), SLOT(onDockSizeChanged()));
1540
1541   myContextMenuMgr->connectObjectBrowser();
1542   return aObjDock;
1543 }
1544
1545 //******************************************************
1546 /*
1547  * Creates dock widgets, places them in corresponding area
1548  * and tabifies if necessary.
1549  */
1550 void XGUI_Workshop::createDockWidgets()
1551 {
1552   QMainWindow* aDesktop = desktop();
1553   QDockWidget* aObjDock = createObjectBrowser(aDesktop);
1554   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, aObjDock);
1555   myPropertyPanel = new XGUI_PropertyPanel(aDesktop, myOperationMgr);
1556   myActiveControlMgr->addSelector(new XGUI_PropertyPanelSelector(myPropertyPanel));
1557
1558   myPropertyPanel->setupActions(myActionsMgr);
1559   myPropertyPanel->setAllowedAreas(Qt::LeftDockWidgetArea |
1560                                    Qt::RightDockWidgetArea);
1561   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, myPropertyPanel);
1562
1563   hidePanel(myPropertyPanel);  ///<! Invisible by default
1564
1565   myFacesPanel = new XGUI_FacesPanel(aDesktop, this);
1566   myActiveControlMgr->addSelector(new XGUI_FacesPanelSelector(myFacesPanel));
1567   myFacesPanel->setAllowedAreas(Qt::LeftDockWidgetArea |
1568                                 Qt::RightDockWidgetArea |
1569                                 Qt::BottomDockWidgetArea);
1570   connect(myFacesPanel, SIGNAL(closed()), myFacesPanel, SLOT(onClosed()));
1571
1572   myInspectionPanel = new XGUI_InspectionPanel(aDesktop, this);
1573   myInspectionPanel->setAllowedAreas(Qt::LeftDockWidgetArea |
1574     Qt::RightDockWidgetArea);
1575   aDesktop->addDockWidget(Qt::RightDockWidgetArea, myInspectionPanel);
1576
1577   myInspectionPanel->hide();
1578
1579   aDesktop->addDockWidget(
1580 #ifdef HAVE_SALOME
1581     Qt::RightDockWidgetArea,
1582 #else
1583     Qt::LeftDockWidgetArea,
1584 #endif
1585     myFacesPanel);
1586   hidePanel(myFacesPanel);  ///<! Invisible by default
1587
1588 #ifdef _DEBUG
1589   bool aShowOnTheRight = Config_PropManager::boolean("Plugins", "show_hide_faces");
1590   if (aShowOnTheRight) {
1591     aDesktop->addDockWidget(Qt::RightDockWidgetArea, myFacesPanel);
1592     showPanel(myFacesPanel);
1593   }
1594 #endif
1595   hideObjectBrowser();
1596
1597 #ifndef HAVE_SALOME
1598 #ifdef _DEBUG
1599   if (!aShowOnTheRight)
1600   {
1601 #endif // _DEBUG
1602   aDesktop->tabifyDockWidget(myFacesPanel, aObjDock);
1603 #ifdef _DEBUG
1604   }
1605 #endif // _DEBUG
1606
1607 #endif // HAVE_SALOME
1608
1609   aDesktop->tabifyDockWidget(aObjDock, myPropertyPanel);
1610   myPropertyPanel->installEventFilter(myOperationMgr);
1611
1612   QAction* aOkAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Accept);
1613   connect(aOkAct, SIGNAL(triggered()), this, SLOT(onAcceptActionClicked()));
1614
1615   QAction* aOkContAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::AcceptPlus);
1616   connect(aOkContAct, SIGNAL(triggered()), this, SLOT(onAcceptPlusActionClicked()));
1617
1618   QAction* aCancelAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
1619   connect(aCancelAct, SIGNAL(triggered()), myOperationMgr, SLOT(onAbortOperation()));
1620
1621   QAction* aPreviewAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Preview);
1622   connect(aPreviewAct, SIGNAL(triggered()), this, SLOT(onPreviewActionClicked()));
1623
1624   QAction* aHelpAct = myActionsMgr->operationStateAction(XGUI_ActionsMgr::Help);
1625   connect(aHelpAct, SIGNAL(triggered()), this, SLOT(onHelpActionClicked()));
1626
1627   connect(myPropertyPanel, SIGNAL(keyReleased(QObject*, QKeyEvent*)),
1628           myOperationMgr,  SLOT(onKeyReleased(QObject*, QKeyEvent*)));
1629   connect(myPropertyPanel, SIGNAL(enterClicked(QObject*)),
1630           myOperationMgr,  SLOT(onProcessEnter(QObject*)));
1631 }
1632
1633 //******************************************************
1634 void XGUI_Workshop::showPanel(QDockWidget* theDockWidget)
1635 {
1636   if (theDockWidget == myPropertyPanel) {
1637     QAction* aViewAct = myPropertyPanel->toggleViewAction();
1638     ///<! Restore ability to close panel from the window's menu
1639     aViewAct->setEnabled(true);
1640   }
1641   theDockWidget->show();
1642   theDockWidget->raise();
1643
1644   // The next code is necessary to made the property panel the active window
1645   // in order to operation manager could process key events of the panel.
1646   // otherwise they are ignored. It happens only if the same(activateWindow) is
1647   // not happened by property panel activation(e.g. resume operation of Sketch)
1648   //ModuleBase_Tools::setFocus(theDockWidget, "XGUI_Workshop::showPanel()");
1649 }
1650
1651 //******************************************************
1652 void XGUI_Workshop::hidePanel(QDockWidget* theDockWidget)
1653 {
1654   if (theDockWidget && theDockWidget == myPropertyPanel) {
1655     QAction* aViewAct = theDockWidget->toggleViewAction();
1656     ///<! Do not allow to show empty property panel
1657     aViewAct->setEnabled(false);
1658   }
1659   theDockWidget->hide();
1660
1661   // the property panel is active window of the desktop, when it is
1662   // hidden, it is undefined which window becomes active. By this reason
1663   // it is defined to perform the desktop as the active window.
1664   // in SALOME mode, work-stack made the PyConsole the active window,
1665   // set the focus on it. As a result, shortcuts of the application, like
1666   // are processed by this console. For example Undo actions.
1667   // It is possible that this code is to be moved to SHAPER package
1668   QMainWindow* aDesktop = desktop();
1669   ModuleBase_Tools::setFocus(aDesktop, "XGUI_Workshop::hidePanel()");
1670 }
1671
1672 //******************************************************
1673 void XGUI_Workshop::showObjectBrowser()
1674 {
1675   if (!isSalomeMode()) {
1676     myObjectBrowser->parentWidget()->show();
1677   }
1678 }
1679
1680 //******************************************************
1681 void XGUI_Workshop::hideObjectBrowser()
1682 {
1683   if (!isSalomeMode())
1684     myObjectBrowser->parentWidget()->hide();
1685 }
1686
1687 //******************************************************
1688 void XGUI_Workshop::salomeViewerSelectionChanged()
1689 {
1690   emit salomeViewerSelection();
1691 }
1692
1693 //**************************************************************
1694 ModuleBase_IViewer* XGUI_Workshop::salomeViewer() const
1695 {
1696   return mySalomeConnector->viewer();
1697 }
1698
1699 //**************************************************************
1700 void XGUI_Workshop::onContextMenuCommand(const QString& theId, bool isChecked)
1701 {
1702   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
1703   if (theId == "DELETE_CMD")
1704     deleteObjects();
1705   else if (theId == "CLEAN_HISTORY_CMD")
1706     cleanHistory();
1707   else if (theId == "MOVE_CMD" || theId == "MOVE_SPLIT_CMD")
1708     moveObjects(theId == "MOVE_SPLIT_CMD");
1709   else if (theId == "COLOR_CMD")
1710     changeColor(aObjects);
1711   else if (theId == "ISOLINES_CMD")
1712     changeIsoLines(aObjects);
1713   else if (theId == "SHOW_ISOLINES_CMD") {
1714     foreach(ObjectPtr aObj, aObjects) {
1715       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
1716       if (aResult.get())
1717         ModelAPI_Tools::showIsoLines(aResult, !ModelAPI_Tools::isShownIsoLines(aResult));
1718     }
1719     mySelector->clearSelection();
1720     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1721   }
1722   else if (theId == "DEFLECTION_CMD")
1723     changeDeflection(aObjects);
1724   else if (theId == "TRANSPARENCY_CMD")
1725     changeTransparency(aObjects);
1726   else if (theId == "SHOW_CMD") {
1727     showObjects(aObjects, true);
1728     mySelector->updateSelectionBy(ModuleBase_ISelection::Browser);
1729     updateCommandStatus();
1730   }
1731   else if (theId == "HIDE_CMD") {
1732     showObjects(aObjects, false);
1733     updateCommandStatus();
1734   }
1735   else if (theId == "SHOW_ONLY_CMD") {
1736     showOnlyObjects(aObjects);
1737     mySelector->updateSelectionBy(ModuleBase_ISelection::Browser);
1738     updateCommandStatus();
1739   }
1740   else if (theId == "SHADING_CMD")
1741     setDisplayMode(aObjects, XGUI_Displayer::Shading);
1742   else if (theId == "WIREFRAME_CMD")
1743     setDisplayMode(aObjects, XGUI_Displayer::Wireframe);
1744   else if (theId == "HIDEALL_CMD") {
1745     QObjectPtrList aList = myDisplayer->displayedObjects();
1746     foreach (ObjectPtr aObj, aList) {
1747       if (module()->canEraseObject(aObj))
1748         aObj->setDisplayed(false);
1749     }
1750     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
1751 #ifdef HAVE_SALOME
1752     //issue #2159 Hide all incomplete behavior
1753     viewer()->eraseAll();
1754 #endif
1755     updateCommandStatus();
1756     // Necessary for update icons in ObjectBrowser on Linux
1757     myObjectBrowser->updateAllIndexes();
1758   } else if (theId == "SELECT_VERTEX_CMD") {
1759     setViewerSelectionMode(TopAbs_VERTEX);
1760   } else if (theId == "SELECT_EDGE_CMD") {
1761     setViewerSelectionMode(TopAbs_EDGE);
1762   } else if (theId == "SELECT_FACE_CMD") {
1763     setViewerSelectionMode(TopAbs_FACE);
1764   } else if (theId == "INSERT_FOLDER_CMD") {
1765     insertFeatureFolder();
1766   } else if (theId == "ADD_TO_FOLDER_BEFORE_CMD") {
1767     insertToFolder(true);
1768   } else if (theId == "ADD_TO_FOLDER_AFTER_CMD") {
1769     insertToFolder(false);
1770   } else if (theId == "ADD_OUT_FOLDER_BEFORE_CMD") {
1771     moveOutFolder(true);
1772   } else if (theId == "ADD_OUT_FOLDER_AFTER_CMD") {
1773     moveOutFolder(false);
1774   } else if (theId == "SELECT_RESULT_CMD") {
1775     //setViewerSelectionMode(-1);
1776     //IMP: an attempt to use result selection with other selection modes
1777     setViewerSelectionMode(ModuleBase_ResultPrs::Sel_Result);
1778     setViewerSelectionMode(TopAbs_COMPSOLID);
1779   } else if (theId == "SHOW_RESULTS_CMD") {
1780     highlightResults(aObjects);
1781   } else if (theId == "SHOW_FEATURE_CMD") {
1782     highlightFeature(aObjects);
1783   } else if (theId == "SET_VIEW_NORMAL_CMD") {
1784     setNormalView();
1785   } else if (theId == "SET_VIEW_INVERTEDNORMAL_CMD") {
1786     setNormalView(true);
1787   }
1788 #ifdef TINSPECTOR
1789   else if (theId == "TINSPECTOR_VIEW") {
1790     Handle(CDF_Application) anApplication = CDF_Session::CurrentSession()->CurrentApplication();
1791     if (!anApplication.IsNull())
1792     {
1793       if (!MyTCommunicator)
1794       {
1795         MyTCommunicator = new TInspector_Communicator();
1796
1797         NCollection_List<Handle(Standard_Transient)> aParameters;
1798         aParameters.Append(anApplication);
1799         Handle(AIS_InteractiveContext) aContext = viewer()->AISContext();
1800         if (!aContext.IsNull())
1801           aParameters.Append(aContext);
1802
1803 #ifdef DEBUG_WITH_MESSAGE_REPORT
1804         Handle(Message_Report) aContextReport = aContext->GetReport();
1805         aContext->SetReportActive (Standard_True);
1806         aContextReport->SetLimit (1000);
1807         if (!aContextReport.IsNull())
1808           aParameters.Append(aContextReport);
1809 #endif
1810         MyVCallBack = new VInspector_CallBack();
1811         myDisplayer->setCallBack(MyVCallBack);
1812         #ifndef HAVE_SALOME
1813         AppElements_Viewer* aViewer = mainWindow()->viewer();
1814         if (aViewer)
1815           aViewer->setCallBack(MyVCallBack);
1816         #endif
1817         aParameters.Append(MyVCallBack);
1818
1819         MyTCommunicator->RegisterPlugin("TKDFBrowser");
1820         MyTCommunicator->RegisterPlugin("TKShapeView");
1821         MyTCommunicator->RegisterPlugin("TKVInspector");
1822 #ifdef DEBUG_WITH_MESSAGE_REPORT
1823         MyTCommunicator->RegisterPlugin("TKMessageView");
1824 #endif
1825         //MyTCommunicator->RegisterPlugin("SMBrowser"); // custom plugin to view ModelAPI
1826         //MyTCommunicator->RegisterPlugin("TKSMBrowser"); // custom plugin to view ModelAPI
1827
1828         MyTCommunicator->Init(aParameters);
1829         MyTCommunicator->Activate("TKSMBrowser"); // to have button in TInspector
1830 #ifndef DEBUG_WITH_MESSAGE_REPORT
1831         MyTCommunicator->Activate("TKVInspector"); // to have filled callback by model
1832 #endif
1833         MyTCommunicator->Activate("TKDFBrowser");
1834
1835 #ifdef DEBUG_WITH_MESSAGE_REPORT
1836         MyTCommunicator->Activate("TKMessageView"); // temporary
1837         MyTCommunicator->Activate("TKVInspector"); // to have filled callback by model
1838 #endif
1839       }
1840       MyTCommunicator->SetVisible(true);
1841     }
1842   }
1843 #endif
1844 }
1845
1846 //**************************************************************
1847 void XGUI_Workshop::setViewerSelectionMode(int theMode)
1848 {
1849   if (theMode == -1)
1850     myViewerSelMode.clear();
1851   else {
1852     if (myViewerSelMode.contains(theMode))
1853       myViewerSelMode.removeAll(theMode);
1854     else
1855       myViewerSelMode.append(theMode);
1856   }
1857   selectionActivate()->updateSelectionModes();
1858 }
1859
1860 //**************************************************************
1861 void XGUI_Workshop::activateObjectsSelection(const QObjectPtrList& theList)
1862 {
1863   QIntList aModes;
1864   module()->activeSelectionModes(aModes);
1865   if (aModes.isEmpty() && (myViewerSelMode.length() > 0))
1866     aModes.append(myViewerSelMode);
1867   selectionActivate()->activateObjects(aModes, theList);
1868 }
1869
1870 //**************************************************************
1871 bool XGUI_Workshop::prepareForDisplay(const std::set<ObjectPtr>& theObjects) const
1872 {
1873   if (facesPanel()->isEmpty())
1874     return true;
1875
1876   // generate container of objects taking into account sub elments of compsolid
1877   std::set<ObjectPtr> anAllProcessedObjects;
1878   for (std::set<ObjectPtr>::const_iterator anObjectsIt = theObjects.begin();
1879     anObjectsIt != theObjects.end(); anObjectsIt++) {
1880     ObjectPtr anObject = *anObjectsIt;
1881     ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anObject);
1882     if (aCompRes.get()) {
1883       std::list<ResultPtr> allRes;
1884       ModelAPI_Tools::allSubs(aCompRes, allRes);
1885       if (allRes.empty()) {
1886         anAllProcessedObjects.insert(anObject);
1887       } else {
1888         for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
1889           ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRes);
1890           if (aBody.get() && aBody->numberOfSubs() == 0)
1891             anAllProcessedObjects.insert(aBody);
1892         }
1893       }
1894     } else
1895       anAllProcessedObjects.insert(anObject);
1896   }
1897
1898   // find hidden objects in faces panel
1899   std::set<ObjectPtr> aHiddenObjects;
1900   QStringList aHiddenObjectNames;
1901   for (std::set<ObjectPtr>::const_iterator anObjectsIt = anAllProcessedObjects.begin();
1902        anObjectsIt != anAllProcessedObjects.end(); anObjectsIt++) {
1903     if (!facesPanel()->isObjectHiddenByPanel(*anObjectsIt))
1904       continue;
1905     aHiddenObjects.insert(*anObjectsIt);
1906     aHiddenObjectNames.append((*anObjectsIt)->data()->name().c_str());
1907   }
1908   if (aHiddenObjects.empty()) // in parameter objects there are no hidden objects in hide face
1909     return true;
1910
1911   int anAnswer = QMessageBox::question(
1912         desktop(), tr("Show object"),
1913         tr("'%1'\n are hidden by %2:\nRemove objects from the panel to be displayed?")
1914         .arg(aHiddenObjectNames.join(", ")).arg(facesPanel()->windowTitle()),
1915         QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
1916
1917   bool aToBeDisplayed = anAnswer == QMessageBox::Yes;
1918   if (aToBeDisplayed)
1919     facesPanel()->restoreObjects(aHiddenObjects);
1920
1921   return aToBeDisplayed;
1922 }
1923
1924 //**************************************************************
1925 void XGUI_Workshop::deleteObjects()
1926 {
1927   ModuleBase_IModule* aModule = module();
1928   // allow the module to delete objects, do nothing if it has succeed
1929   if (aModule->deleteObjects()) {
1930     updateCommandStatus();
1931     myDisplayer->updateViewer();
1932     return;
1933   }
1934
1935   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
1936   if (anObjects.isEmpty())
1937     return;
1938
1939   if (!abortAllOperations())
1940     return;
1941
1942   bool hasResult = false;
1943   bool hasFeature = false;
1944   bool hasParameter = false;
1945   bool hasCompositeOwner = false;
1946   bool hasResultInHistory = false;
1947   bool hasFolder = false;
1948   ModuleBase_Tools::checkObjects(anObjects, hasResult, hasFeature, hasParameter, hasCompositeOwner,
1949                                  hasResultInHistory, hasFolder);
1950   if (!(hasResult || hasFeature || hasParameter || hasFolder))
1951     return;
1952
1953   // Remove from the list non-deletable objects: infinite constructions which are not in history
1954   bool notDelete = true;
1955   QObjectPtrList::iterator aIt;
1956   for (aIt = anObjects.begin(); aIt != anObjects.end(); aIt++) {
1957     ObjectPtr aObj = (*aIt);
1958     ResultConstructionPtr aConstr = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aObj);
1959     FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
1960     if (aFeature) {
1961       notDelete = (!aFeature->isInHistory()) && aConstr->isInfinite();
1962       if (notDelete) {
1963         anObjects.removeAll(aObj);
1964         aIt--;
1965       }
1966     }
1967   }
1968   // delete objects
1969   std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;
1970   std::set<FeaturePtr> aFeatures;
1971   ModuleBase_Tools::convertToFeatures(anObjects, aFeatures);
1972   ModelAPI_Tools::findAllReferences(aFeatures, aReferences);
1973
1974   std::set<FolderPtr> aFolders;
1975   ModuleBase_Tools::convertToFolders(anObjects, aFolders);
1976
1977   bool aDone = false;
1978   QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1";
1979   aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
1980   ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module());
1981
1982   operationMgr()->startOperation(anOpAction);
1983
1984   std::set<FeaturePtr> aFeatureRefsToDelete;
1985   if (ModuleBase_Tools::askToDelete(aFeatures, aReferences, desktop(), aFeatureRefsToDelete)) {
1986     // WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree
1987     // It is necessary to clear selection in order to avoid selection changed event during
1988     // deletion and negative consequences connected with processing of already deleted items
1989     mySelector->clearSelection();
1990
1991     if (!aFeatureRefsToDelete.empty())
1992       aFeatures.insert(aFeatureRefsToDelete.begin(), aFeatureRefsToDelete.end());
1993     aDone = ModelAPI_Tools::removeFeatures(aFeatures, false);
1994   }
1995   if (aFolders.size() > 0) {
1996     std::set<FolderPtr>::const_iterator anIt = aFolders.begin(),
1997                                          aLast = aFolders.end();
1998     for (; anIt != aLast; anIt++) {
1999       FolderPtr aFolder = *anIt;
2000       if (aFolder.get()) {
2001         DocumentPtr aDoc = aFolder->document();
2002         aDoc->removeFolder(aFolder);
2003       }
2004     }
2005   }
2006   // remove results selected
2007   std::list<ResultPtr> aResults;
2008   for(QObjectPtrList::const_iterator anIt = anObjects.begin(); anIt != anObjects.end(); anIt++) {
2009     ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(*anIt);
2010     if (aRes.get() && aRes->data()->isValid() && !aRes->data()->isDeleted() &&
2011         aRes->groupName() != ModelAPI_ResultGroup::group() && // don't remove groups and fields
2012         aRes->groupName() != ModelAPI_ResultField::group()) // because they are badly selected
2013       aResults.push_back(aRes);
2014   }
2015   if (!aResults.empty()) {
2016     ModelAPI_Tools::removeResults(aResults);
2017   }
2018
2019   if (aDone)
2020     operationMgr()->commitOperation();
2021   else
2022     operationMgr()->abortOperation(operationMgr()->currentOperation());
2023
2024   myDisplayer->updateViewer();
2025 }
2026
2027 //**************************************************************
2028 void addRefsToFeature(const FeaturePtr& theFeature,
2029                       const std::map<FeaturePtr, std::set<FeaturePtr> >& theMainList,
2030                       std::set<FeaturePtr>& theReferences)
2031 {
2032   //if (theReferences.find(theFeature) != theReferences.end())
2033   //  return;
2034   if (theMainList.find(theFeature) == theMainList.end())
2035     return; // this feature is not in the selection list, so exists without references to it
2036   std::set<FeaturePtr> aMainReferences = theMainList.at(theFeature);
2037
2038   std::set<FeaturePtr>::const_iterator anIt = aMainReferences.begin(),
2039                                        aLast = aMainReferences.end();
2040   for (; anIt != aLast; anIt++) {
2041     FeaturePtr aRefFeature = *anIt;
2042     if (theReferences.find(aRefFeature) == theReferences.end())
2043       theReferences.insert(aRefFeature);
2044     addRefsToFeature(aRefFeature, theMainList, theReferences);
2045   }
2046 }
2047
2048 //**************************************************************
2049 void XGUI_Workshop::cleanHistory()
2050 {
2051   if (!abortAllOperations())
2052     return;
2053
2054   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
2055   std::set<FeaturePtr> aFeatures;
2056   ModuleBase_Tools::convertToFeatures(anObjects, aFeatures);
2057
2058 #ifdef DEBUG_CLEAN_HISTORY
2059   QStringList anInfo;
2060   std::set<FeaturePtr>::const_iterator aFIt;
2061   for (aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
2062     FeaturePtr aFeature = ModelAPI_Feature::feature(*aFIt);
2063     anInfo.append(aFeature->name().c_str());
2064   }
2065   QString anInfoStr = anInfo.join(";\t");
2066   qDebug(QString("cleanHistory for: [%1] - %2").
2067     arg(aFeatures.size()).arg(anInfoStr).toStdString().c_str());
2068 #endif
2069
2070   std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;
2071   ModelAPI_Tools::findAllReferences(aFeatures, aReferences, true, false);
2072   // find for each object whether all reference values are in the map as key, that means that there
2073   // is no other reference in the model to this object, so it might be removed by cleaning history
2074   // sk_1(ext_1, vertex_1) + (sk_3, bool_1) - can't be deleted, dependency to bool_1
2075   // ext_1(bool_1, sk_3)  - can't be deleted, dependency to bool_1
2076   // vertex_1()
2077   // sk_2(ext_2) + (bool_1)  - can't be deleted, dependency to bool_1
2078   // ext_2(bool_1)  - can't be deleted, dependency to bool_1
2079   // sk_3()
2080   // Information: bool_1 is not selected
2081   std::set<FeaturePtr> anUnusedObjects;
2082   std::map<FeaturePtr, std::set<FeaturePtr> >::const_iterator aMainIt = aReferences.begin(),
2083                                                               aMainLast = aReferences.end();
2084   for (; aMainIt != aMainLast; aMainIt++) {
2085     FeaturePtr aMainListFeature = aMainIt->first;
2086     std::set<FeaturePtr> aMainRefList = aMainIt->second;
2087     std::set<FeaturePtr>::const_iterator aRefIt = aMainRefList.begin(),
2088                                                   aRefLast = aMainRefList.end();
2089     bool aFeatureOutOfTheList = false;
2090     for (; aRefIt != aRefLast && !aFeatureOutOfTheList; aRefIt++) {
2091       FeaturePtr aRefFeature = *aRefIt;
2092       aFeatureOutOfTheList = aReferences.find(aRefFeature) == aReferences.end();
2093     }
2094     if (!aFeatureOutOfTheList)
2095       anUnusedObjects.insert(aMainListFeature);
2096   }
2097
2098 #ifdef DEBUG_CLEAN_HISTORY
2099   anInfo.clear();
2100   for (aFIt = anUnusedObjects.begin(); aFIt != anUnusedObjects.end(); ++aFIt) {
2101     FeaturePtr aFeature = *aFIt;
2102     anInfo.append(aFeature->name().c_str());
2103   }
2104   qDebug(QString("unused objects: [%1] - %2").
2105     arg(anInfo.size()).arg(anInfo.join(";\t")).toStdString().c_str());
2106 #endif
2107
2108   // warn about the references remove, break the delete operation if the user chose it
2109   if (!anUnusedObjects.empty()) {
2110     QStringList aNames;
2111     foreach (const FeaturePtr& aFeature, anUnusedObjects) {
2112       aNames.append(aFeature->name().c_str());
2113     }
2114     aNames.sort();
2115     QString anUnusedNames = aNames.join(", ");
2116
2117     QString anActionId = "CLEAN_HISTORY_CMD";
2118     QString aDescription = ModuleBase_Tools::translate("workshop",
2119         contextMenuMgr()->action(anActionId)->text().toStdString());
2120
2121     QMessageBox aMessageBox(desktop());
2122     aMessageBox.setWindowTitle(aDescription);
2123     aMessageBox.setIcon(QMessageBox::Warning);
2124     aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
2125     aMessageBox.setDefaultButton(QMessageBox::No);
2126
2127     const char* aKeyStr = "Unused features are the following: "
2128                           "%1.\nThese features will be deleted.\nWould you like to continue?";
2129     QString aText = QString(tr(aKeyStr).arg(anUnusedNames));
2130     aMessageBox.setText(aText);
2131     if (aMessageBox.exec() == QMessageBox::No)
2132       return;
2133
2134     // 1. start operation
2135     aDescription += "by deleting of " +
2136       aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
2137     ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module());
2138     operationMgr()->startOperation(anOpAction);
2139
2140     // WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree
2141     // It is necessary to clear selection in order to avoid selection changed event during
2142     // deletion and negative consequences connected with processing of already deleted items
2143     mySelector->clearSelection();
2144
2145     std::set<FeaturePtr> anIgnoredFeatures;
2146     if (ModelAPI_Tools::removeFeatures(anUnusedObjects, true)) {
2147       operationMgr()->commitOperation();
2148     }
2149     else {
2150       operationMgr()->abortOperation(operationMgr()->currentOperation());
2151     }
2152   }
2153   else {
2154     QString anActionId = "CLEAN_HISTORY_CMD";
2155     QString aDescription = contextMenuMgr()->action(anActionId)->text();
2156
2157     QMessageBox aMessageBox(desktop());
2158     aMessageBox.setWindowTitle(aDescription);
2159     aMessageBox.setIcon(QMessageBox::Warning);
2160     aMessageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
2161     aMessageBox.setDefaultButton(QMessageBox::No);
2162
2163     QString aText;
2164     aMessageBox.setStandardButtons(QMessageBox::Ok);
2165     aMessageBox.setDefaultButton(QMessageBox::Ok);
2166
2167     aText = QString(tr("All features are relevant, there is nothing to be deleted"));
2168     aMessageBox.setText(aText);
2169
2170     if (aMessageBox.exec() == QMessageBox::No)
2171       return;
2172   }
2173 }
2174
2175 //**************************************************************
2176 bool compareFeature(const FeaturePtr& theF1, const FeaturePtr& theF2) {
2177   DocumentPtr aDoc = theF1->document();
2178   return aDoc->index(theF1) < aDoc->index(theF2);
2179 }
2180 void XGUI_Workshop::moveObjects(const bool theSplit)
2181 {
2182   if (!abortAllOperations())
2183     return;
2184
2185   SessionPtr aMgr = ModelAPI_Session::get();
2186
2187   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
2188   // It is necessary to clear selection in order to avoid selection changed event during
2189   // moving and negative consequences connected with processing of already moved items
2190   mySelector->clearSelection();
2191   // check whether the object can be moved. There should not be parts which are not loaded
2192   std::set<FeaturePtr> aFeatures;
2193   ModuleBase_Tools::convertToFeatures(anObjects, aFeatures);
2194   if (!XGUI_Tools::canRemoveOrRename(desktop(), aFeatures))
2195     return;
2196
2197   QString anActionId = theSplit ? "MOVE_CMD" : "MOVE_SPLIT_CMD";
2198   QString aDescription = contextMenuMgr()->action(anActionId)->text();
2199   aMgr->startOperation(aDescription.toStdString());
2200
2201   // Sort features by index in document
2202   std::list<FeaturePtr> aFList(aFeatures.begin(), aFeatures.end());
2203   aFList.sort(compareFeature);
2204
2205   DocumentPtr anActiveDocument = aMgr->activeDocument();
2206   FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true);
2207   std::list<FeaturePtr>::const_iterator anIt = aFList.begin(), aLast = aFList.end();
2208   for (; anIt != aLast; anIt++) {
2209     FeaturePtr aFeature = *anIt;
2210     if (!aFeature.get() || !myModule->canApplyAction(aFeature, anActionId))
2211       continue;
2212
2213     anActiveDocument->moveFeature(aFeature, aCurrentFeature, theSplit);
2214     aCurrentFeature = anActiveDocument->currentFeature(true);
2215   }
2216   aMgr->finishOperation();
2217   updateCommandStatus();
2218   myViewerProxy->update();
2219 }
2220
2221 //**************************************************************
2222 bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theObjects)
2223 {
2224   std::set<FeaturePtr> aFeatures;
2225   ModuleBase_Tools::convertToFeatures(theObjects, aFeatures);
2226
2227   return ModelAPI_Tools::removeFeaturesAndReferences(aFeatures);
2228 }
2229
2230 //******************************************************
2231 bool hasResults(QObjectPtrList theObjects, const std::set<std::string>& theTypes)
2232 {
2233   bool isFoundResultType = false;
2234   foreach(ObjectPtr anObj, theObjects)
2235   {
2236     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
2237     if (aResult.get() == NULL)
2238       continue;
2239
2240     isFoundResultType = theTypes.find(aResult->groupName()) != theTypes.end();
2241     if (isFoundResultType)
2242       break;
2243   }
2244   return isFoundResultType;
2245 }
2246
2247 //**************************************************************
2248 // Returns the list of all features for theDocument and all features of
2249 // all nested parts.
2250 std::list<FeaturePtr> allFeatures(const DocumentPtr& theDocument)
2251 {
2252   std::list<FeaturePtr> aResultList;
2253   std::list<FeaturePtr> anAllFeatures = theDocument->allFeatures();
2254   foreach (const FeaturePtr& aFeature, anAllFeatures) {
2255     // The order of appending features of the part and the part itself is important
2256
2257     // Append features from a part feature
2258     std::list<ResultPtr> aResults;
2259     ModelAPI_Tools::allResults(aFeature, aResults);
2260     foreach (const ResultPtr& aResult, aResults) {
2261       ResultPartPtr aResultPart =
2262           std::dynamic_pointer_cast<ModelAPI_ResultPart>(aResult);
2263       if (aResultPart.get() && aResultPart->partDoc().get()) {
2264         // Recursion
2265         std::list<FeaturePtr> anAllFeatures = allFeatures(aResultPart->partDoc());
2266         aResultList.insert(aResultList.end(), anAllFeatures.begin(), anAllFeatures.end());
2267       }
2268     }
2269
2270     aResultList.push_back(aFeature);
2271   }
2272   return aResultList;
2273 }
2274
2275 //**************************************************************
2276 // Returns the list of features placed between theObject and the current feature
2277 // in the same document. Excludes theObject, includes the current feature.
2278 std::list<FeaturePtr> toCurrentFeatures(const ObjectPtr& theObject)
2279 {
2280   std::list<FeaturePtr> aResult;
2281   DocumentPtr aDocument = theObject->document();
2282   std::list<FeaturePtr> anAllFeatures = allFeatures(aDocument);
2283   // find the object iterator
2284   std::list<FeaturePtr>::iterator aObjectIt =
2285     std::find(anAllFeatures.begin(), anAllFeatures.end(), theObject);
2286   if (aObjectIt == anAllFeatures.end())
2287     return aResult;
2288   // find the current feature iterator
2289   std::list<FeaturePtr>::iterator aCurrentIt =
2290     std::find(anAllFeatures.begin(), anAllFeatures.end(), aDocument->currentFeature(true));
2291   if (aCurrentIt == anAllFeatures.end())
2292     return aResult;
2293   // check the right order
2294   if (std::distance(aObjectIt, anAllFeatures.end()) <=
2295       std::distance(aCurrentIt, anAllFeatures.end()))
2296     return aResult;
2297   // exclude the object
2298   std::advance(aObjectIt, 1);
2299   // include the current feature
2300   std::advance(aCurrentIt, 1);
2301   return std::list<FeaturePtr>(aObjectIt, aCurrentIt);
2302 }
2303
2304 //******************************************************
2305 bool XGUI_Workshop::canMoveFeature()
2306 {
2307   QString anActionId = "MOVE_CMD";
2308
2309   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
2310   QObjectPtrList aValidatedObjects;
2311   foreach (ObjectPtr aObject, aObjects) {
2312     if (!myModule->canApplyAction(aObject, anActionId))
2313       continue;
2314     // To be moved feature should be in active document
2315     if (aObject->document() != ModelAPI_Session::get()->activeDocument())
2316       continue;
2317     aValidatedObjects.append(aObject);
2318   }
2319   if (aValidatedObjects.size() != aObjects.size())
2320     aObjects = aValidatedObjects;
2321
2322   bool aCanMove = !aObjects.empty();
2323
2324   QObjectPtrList::const_iterator anIt = aObjects.begin(), aLast = aObjects.end();
2325   for (; anIt != aLast && aCanMove; anIt++) {
2326     ObjectPtr aObject = *anIt;
2327     if (!aObject.get() || !aObject->data().get() || !aObject->data()->isValid()) {
2328       aCanMove = false;
2329       break;
2330     }
2331     FeaturePtr aFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(aObject);
2332     // only groups can be moved to the end for now (#2451)
2333     if (aFeat.get() && aFeat->getKind() != "Group") {
2334       aCanMove = false;
2335       break;
2336     }
2337
2338     // 1. Get features placed between selected and current in the document
2339     std::list<FeaturePtr> aFeaturesBetween = toCurrentFeatures(aObject);
2340     // if aFeaturesBetween is empty it means wrong order or aObject is the current feature
2341     if (aFeaturesBetween.empty())
2342       aCanMove = false;
2343     else {
2344       std::set<FeaturePtr> aPlacedFeatures(aFeaturesBetween.begin(), aFeaturesBetween.end());
2345       // 2. Get all reference features to the selected object in the document
2346       std::set<FeaturePtr> aRefFeatures;
2347       ModuleBase_Tools::refsToFeatureInFeatureDocument(aObject, aRefFeatures);
2348
2349       if (aRefFeatures.empty())
2350         continue;
2351       else {
2352         // 3. Find any placed features in all reference features
2353         std::set<FeaturePtr> aIntersectionFeatures;
2354         std::set_intersection(aRefFeatures.begin(), aRefFeatures.end(),
2355                               aPlacedFeatures.begin(), aPlacedFeatures.end(),
2356                               std::inserter(aIntersectionFeatures, aIntersectionFeatures.begin()));
2357         // 4. Return false if any reference feature is placed before current feature
2358         if (!aIntersectionFeatures.empty())
2359           aCanMove = false;
2360       }
2361     }
2362   }
2363   return aCanMove;
2364 }
2365
2366 //**************************************************************
2367 bool XGUI_Workshop::canBeShaded(const ObjectPtr& theObject) const
2368 {
2369   bool aCanBeShaded = myDisplayer->canBeShaded(theObject);
2370   if (!aCanBeShaded) {
2371     ResultBodyPtr aCompRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theObject);
2372     if (aCompRes.get() != NULL) { // change colors for all sub-solids
2373       std::list<ResultPtr> allRes;
2374       ModelAPI_Tools::allSubs(aCompRes, allRes);
2375       std::list<ResultPtr>::iterator aRes = allRes.begin();
2376       for(; aRes != allRes.end() && !aCanBeShaded; aRes++) {
2377         aCanBeShaded = myDisplayer->canBeShaded(*aRes);
2378       }
2379     }
2380   }
2381   return aCanBeShaded;
2382 }
2383
2384 //**************************************************************
2385 bool XGUI_Workshop::canChangeProperty(const QString& theActionName) const
2386 {
2387   if (theActionName == "COLOR_CMD" ||
2388       theActionName == "DEFLECTION_CMD" ||
2389       theActionName == "TRANSPARENCY_CMD") {
2390     QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
2391
2392     std::set<std::string> aTypes;
2393     aTypes.insert(ModelAPI_ResultGroup::group());
2394     aTypes.insert(ModelAPI_ResultConstruction::group());
2395     aTypes.insert(ModelAPI_ResultBody::group());
2396     aTypes.insert(ModelAPI_ResultPart::group());
2397
2398     return hasResults(aObjects, aTypes);
2399   }
2400   return false;
2401 }
2402
2403
2404 //**************************************************************
2405 void getDefaultColor(ObjectPtr theObject, const bool isEmptyColorValid,
2406   std::vector<int>& theColor)
2407 {
2408   theColor.clear();
2409   // get default color from the preferences manager for the given result
2410   if (theColor.empty()) {
2411     std::string aSection, aName, aDefault;
2412     theObject->colorConfigInfo(aSection, aName, aDefault);
2413     if (!aSection.empty() && !aName.empty()) {
2414       theColor = Config_PropManager::color(aSection, aName);
2415     }
2416   }
2417   if (!isEmptyColorValid && theColor.empty()) {
2418     // all AIS objects, where the color is not set, are in black.
2419     // The color should be defined in XML or set in the attribute
2420     theColor = Config_PropManager::color("Visualization", "object_default_color");
2421     Events_InfoMessage("XGUI_CustomPrs",
2422       "A default color is not defined in the preferences for this kind of result").send();
2423   }
2424 }
2425
2426 //**************************************************************
2427 void XGUI_Workshop::changeColor(const QObjectPtrList& theObjects)
2428 {
2429
2430   AttributeIntArrayPtr aColorAttr;
2431   // 1. find the current color of the object. This is a color of AIS presentation
2432   // The objects are iterated until a first valid color is found
2433   std::vector<int> aColor;
2434   foreach(ObjectPtr anObject, theObjects) {
2435     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
2436     if (aResult.get()) {
2437       ModelAPI_Tools::getColor(aResult, aColor);
2438       if (aColor.empty())
2439         getDefaultColor(aResult, false, aColor);
2440     }
2441     else {
2442       // TODO: remove the obtaining a color from the AIS object
2443       // this does not happen never because:
2444       // 1. The color can be changed only on results
2445       // 2. The result can be not visualized in the viewer(e.g. Origin Construction)
2446       AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject);
2447       if (anAISObj.get()) {
2448         aColor.resize(3);
2449         anAISObj->getColor(aColor[0], aColor[1], aColor[2]);
2450       }
2451     }
2452     if (!aColor.empty())
2453       break;
2454   }
2455   if (aColor.size() != 3)
2456     return;
2457
2458   if (!abortAllOperations())
2459   return;
2460   // 2. show the dialog to change the value
2461   XGUI_ColorDialog* aDlg = new XGUI_ColorDialog(desktop());
2462   aDlg->setColor(aColor);
2463   aDlg->move(QCursor::pos());
2464   bool isDone = aDlg->exec() == QDialog::Accepted;
2465   if (!isDone)
2466     return;
2467
2468   bool isRandomColor = aDlg->isRandomColor();
2469
2470   // 3. abort the previous operation and start a new one
2471   SessionPtr aMgr = ModelAPI_Session::get();
2472   QString aDescription = contextMenuMgr()->action("COLOR_CMD")->text();
2473   aMgr->startOperation(aDescription.toStdString());
2474
2475   // 4. set the value to all results
2476   std::vector<int> aColorResult = aDlg->getColor();
2477   foreach(ObjectPtr anObj, theObjects) {
2478     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
2479     if (aResult.get() != NULL) {
2480       ResultBodyPtr aBodyResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResult);
2481       if (aBodyResult.get() != NULL) { // change colors for all sub-solids
2482         std::list<ResultPtr> allRes;
2483         ModelAPI_Tools::allSubs(aBodyResult, allRes);
2484         for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
2485           ModelAPI_Tools::setColor(*aRes, !isRandomColor ? aColorResult : aDlg->getRandomColor());
2486         }
2487       }
2488       ModelAPI_Tools::setColor(aResult, !isRandomColor ? aColorResult : aDlg->getRandomColor());
2489     }
2490   }
2491   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2492   aMgr->finishOperation();
2493   updateCommandStatus();
2494   myViewerProxy->update();
2495 }
2496
2497 //**************************************************************
2498 void setTransparency(double theTransparency, const QObjectPtrList& theObjects)
2499 {
2500   foreach(ObjectPtr anObj, theObjects) {
2501     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
2502     if (aResult.get() != NULL) {
2503       ResultBodyPtr aBodyResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResult);
2504       if (aBodyResult.get() != NULL) { // change property for all sub-solids
2505         std::list<ResultPtr> allRes;
2506         ModelAPI_Tools::allSubs(aBodyResult, allRes);
2507         std::list<ResultPtr>::iterator aRes;
2508         for(aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
2509           ModelAPI_Tools::setTransparency(*aRes, theTransparency);
2510         }
2511       }
2512       ModelAPI_Tools::setTransparency(aResult, theTransparency);
2513     }
2514   }
2515 }
2516
2517 //**************************************************************
2518 double getDefaultDeflection(const ObjectPtr& theObject)
2519 {
2520   double aDeflection = -1;
2521   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
2522   if (aResult.get()) {
2523     bool isConstruction = false;
2524
2525     std::string aResultGroup = aResult->groupName();
2526     if (aResultGroup == ModelAPI_ResultConstruction::group())
2527       isConstruction = true;
2528     else if (aResultGroup == ModelAPI_ResultBody::group()) {
2529       GeomShapePtr aGeomShape = aResult->shape();
2530       if (aGeomShape.get()) {
2531         // if the shape could not be exploded on faces, it contains only wires, edges, and vertices
2532         // correction of deviation for them should not influence to the application performance
2533         GeomAPI_ShapeExplorer anExp(aGeomShape, GeomAPI_Shape::FACE);
2534         isConstruction = !anExp.more();
2535       }
2536     }
2537     if (isConstruction)
2538       aDeflection = Config_PropManager::real("Visualization", "construction_deflection");
2539     else
2540       aDeflection = Config_PropManager::real("Visualization", "body_deflection");
2541   }
2542   return aDeflection;
2543 }
2544
2545 //**************************************************************
2546 void XGUI_Workshop::changeDeflection(const QObjectPtrList& theObjects)
2547 {
2548   AttributeDoublePtr aDoubleAttr;
2549   // 1. find the current property of the object. This is a property of AIS presentation
2550   // The objects are iterated until a first valid property is found
2551   double aDeflection = -1;
2552   foreach(ObjectPtr anObject, theObjects) {
2553     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
2554     if (aResult.get()) {
2555       aDeflection = ModelAPI_Tools::getDeflection(aResult);
2556       if (aDeflection < 0)
2557         aDeflection = getDefaultDeflection(aResult);
2558     }
2559     else {
2560       // TODO: remove the obtaining a property from the AIS object
2561       // this does not happen never because:
2562       // 1. The property can be changed only on results
2563       // 2. The result can be not visualized in the viewer(e.g. Origin Construction)
2564       AISObjectPtr anAISObj = myDisplayer->getAISObject(anObject);
2565       if (anAISObj.get()) {
2566         aDeflection = anAISObj->getDeflection();
2567       }
2568     }
2569     if (aDeflection > 0)
2570       break;
2571   }
2572   if (aDeflection < 0)
2573     return;
2574
2575   if (!abortAllOperations())
2576   return;
2577   // 2. show the dialog to change the value
2578   XGUI_DeflectionDialog* aDlg = new XGUI_DeflectionDialog(desktop());
2579   aDlg->setDeflection(aDeflection);
2580   aDlg->move(QCursor::pos());
2581   bool isDone = aDlg->exec() == QDialog::Accepted;
2582   if (!isDone)
2583     return;
2584
2585   // 3. abort the previous operation and start a new one
2586   SessionPtr aMgr = ModelAPI_Session::get();
2587   QString aDescription = contextMenuMgr()->action("DEFLECTION_CMD")->text();
2588   aMgr->startOperation(aDescription.toStdString());
2589
2590   // 4. set the value to all results
2591   aDeflection = aDlg->getDeflection();
2592   foreach(ObjectPtr anObj, theObjects) {
2593     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObj);
2594     if (aResult.get() != NULL) {
2595       ResultBodyPtr aBodyResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aResult);
2596       if (aBodyResult.get() != NULL) { // change property for all sub-solids
2597         std::list<ResultPtr> allRes;
2598         ModelAPI_Tools::allSubs(aBodyResult, allRes);
2599         for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
2600           ModelAPI_Tools::setDeflection(*aRes, aDeflection);
2601         }
2602       }
2603       ModelAPI_Tools::setDeflection(aResult, aDeflection);
2604     }
2605   }
2606   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2607   aMgr->finishOperation();
2608   updateCommandStatus();
2609 }
2610
2611 //**************************************************************
2612 double getDefaultTransparency(const ResultPtr& theResult)
2613 {
2614   return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.;
2615 }
2616
2617 //**************************************************************
2618 void XGUI_Workshop::changeTransparency(const QObjectPtrList& theObjects)
2619 {
2620   AttributeDoublePtr aDoubleAttr;
2621   // 1. find the current property of the object. This is a property of AIS presentation
2622   // The objects are iterated until a first valid property is found
2623   double aCurrentValue = -1;
2624   foreach(ObjectPtr anObject, theObjects) {
2625     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
2626     if (aResult.get()) {
2627       aCurrentValue = ModelAPI_Tools::getTransparency(aResult);
2628       if (aCurrentValue < 0)
2629         aCurrentValue = getDefaultTransparency(aResult);
2630     }
2631     if (aCurrentValue > 0)
2632       break;
2633   }
2634   if (aCurrentValue < 0)
2635     return;
2636
2637   if (!abortAllOperations())
2638     return;
2639
2640   // 2. show the dialog to change the value
2641   XGUI_PropertyDialog* aDlg = new XGUI_PropertyDialog(desktop());
2642   aDlg->setWindowTitle(tr("Transparency"));
2643   XGUI_TransparencyWidget* aTransparencyWidget = new XGUI_TransparencyWidget(aDlg);
2644   connect(aTransparencyWidget, SIGNAL(transparencyValueChanged()),
2645           this, SLOT(onTransparencyValueChanged()));
2646   aDlg->setContent(aTransparencyWidget);
2647   aTransparencyWidget->setValue(aCurrentValue);
2648
2649   // 3. abort the previous operation and start a new one
2650   SessionPtr aMgr = ModelAPI_Session::get();
2651   QString aDescription = contextMenuMgr()->action("TRANSPARENCY_CMD")->text();
2652   aMgr->startOperation(aDescription.toStdString());
2653
2654   if (aDlg->exec() == QDialog::Accepted) {
2655     // 4. set the value to all results
2656     aCurrentValue = aTransparencyWidget->getValue();
2657     setTransparency(aCurrentValue, theObjects);
2658     aMgr->finishOperation();
2659   } else {
2660     aMgr->abortOperation();
2661     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2662   }
2663
2664   updateCommandStatus();
2665 }
2666
2667 //**************************************************************
2668 void XGUI_Workshop::onTransparencyValueChanged()
2669 {
2670   XGUI_TransparencyWidget* aTransparencyWidget = (XGUI_TransparencyWidget*)sender();
2671   if (!aTransparencyWidget)
2672     return;
2673
2674   QObjectPtrList anObjects = mySelector->selection()->selectedObjects();
2675   setTransparency(aTransparencyWidget->getValue(), anObjects);
2676   static const Events_ID kRedisplayEvent =
2677     Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
2678   Events_Loop::loop()->flush(kRedisplayEvent);
2679
2680   myViewerProxy->update();
2681 }
2682
2683
2684 //******************************************************
2685 void XGUI_Workshop::showObjects(const QObjectPtrList& theList, bool isVisible)
2686 {
2687   if (isVisible) {
2688     std::set<ObjectPtr> anObjects;
2689     foreach (ObjectPtr aObj, theList) {
2690       anObjects.insert(aObj);
2691     }
2692     if (!prepareForDisplay(anObjects))
2693       return;
2694   }
2695
2696   foreach (ObjectPtr aObj, theList) {
2697     aObj->setDisplayed(isVisible);
2698   }
2699   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2700   myObjectBrowser->updateAllIndexes();
2701
2702   updateColorScaleVisibility();
2703   displayer()->updateViewer();
2704 }
2705
2706 //**************************************************************
2707 void XGUI_Workshop::showOnlyObjects(const QObjectPtrList& theList)
2708 {
2709   QObjectPtrList aSrcList = theList;
2710   // Hide all displayed objects
2711   QObjectPtrList aList = myDisplayer->displayedObjects();
2712   foreach (ObjectPtr aObj, aList) {
2713     if ((!aSrcList.contains(aObj)) && (module()->canEraseObject(aObj)))
2714       aObj->setDisplayed(false);
2715     else
2716       aSrcList.removeAll(aObj);
2717   }
2718   //Do not use eraseAll if you didn't send Redisplay event:
2719   //all objects are erased from viewer, but considered as displayed in displayer
2720   // Problem in bug 2218
2721   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2722 #ifdef HAVE_SALOME
2723     //issue #2159 Hide all incomplete behavior
2724     viewer()->eraseAll();
2725 #endif
2726
2727   std::set<ObjectPtr> anObjects;
2728   foreach (ObjectPtr aObj, aSrcList) {
2729     anObjects.insert(aObj);
2730   }
2731
2732   if (!prepareForDisplay(anObjects))
2733     return;
2734
2735   // Show only objects from the list
2736   foreach (ObjectPtr aObj, aSrcList) {
2737     aObj->setDisplayed(true);
2738   }
2739   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2740
2741   // Necessary for update icons in ObjectBrowser on Linux
2742   myObjectBrowser->updateAllIndexes();
2743   updateColorScaleVisibility();
2744   displayer()->updateViewer();
2745 }
2746
2747
2748 //**************************************************************
2749 void XGUI_Workshop::updateColorScaleVisibility()
2750 {
2751   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
2752   viewer()->setColorScaleShown(false);
2753   if (aObjects.size() == 1) {
2754     FieldStepPtr aStep =
2755       std::dynamic_pointer_cast<ModelAPI_ResultField::ModelAPI_FieldStep>(aObjects.first());
2756     if (aStep.get() && myDisplayer->isVisible(aStep)) {
2757       AISObjectPtr aAisPtr = myDisplayer->getAISObject(aStep);
2758       Handle(AIS_InteractiveObject) aIO = aAisPtr->impl<Handle(AIS_InteractiveObject)>();
2759       ModuleBase_IStepPrs* aPrs = dynamic_cast<ModuleBase_IStepPrs*>(aIO.get());
2760       if (aPrs) {
2761         ModelAPI_AttributeTables::ValueType aType = aPrs->dataType();
2762         if ((aType == ModelAPI_AttributeTables::DOUBLE) ||
2763           (aType == ModelAPI_AttributeTables::INTEGER) ||
2764           (aType == ModelAPI_AttributeTables::BOOLEAN)) {
2765           myViewerProxy->setupColorScale();
2766           if (aType == ModelAPI_AttributeTables::BOOLEAN) {
2767             myViewerProxy->setColorScaleIntervals(2);
2768             myViewerProxy->setColorScaleRange(0., 1.);
2769           }
2770           else {
2771             double aMin, aMax;
2772             aPrs->dataRange(aMin, aMax);
2773             myViewerProxy->setColorScaleRange(aMin, aMax);
2774           }
2775           myViewerProxy->setColorScaleTitle(aStep->name().c_str());
2776           myViewerProxy->setColorScaleShown(true);
2777         }
2778       }
2779     }
2780   }
2781 }
2782
2783
2784 //**************************************************************
2785 void XGUI_Workshop::setNormalView(bool toInvert)
2786 {
2787   QList<ModuleBase_ViewerPrsPtr> aPrsList =
2788     mySelector->selection()->getSelected(ModuleBase_ISelection::Viewer);
2789   GeomShapePtr aPlanarFace;
2790   foreach(ModuleBase_ViewerPrsPtr aPrs, aPrsList) {
2791     GeomShapePtr aShape = aPrs->shape();
2792     if (aShape.get() && aShape->isPlanar()) {
2793       aPlanarFace = aShape;
2794       break;
2795     }
2796   }
2797   if (aPlanarFace.get()) {
2798     GeomFacePtr aFace(new GeomAPI_Face(aPlanarFace));
2799     GeomPlanePtr aPlane = aFace->getPlane();
2800     GeomDirPtr aNormal = aPlane->direction();
2801     if (toInvert)
2802       aNormal->reverse();
2803     GeomPointPtr aPos = aPlane->location();
2804
2805     double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
2806     aFace->computeSize(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
2807
2808     Handle(V3d_View) aView = myViewerProxy->activeView();
2809     double aScale = aView->Scale();
2810     aView->SetAt(aPos->x(), aPos->y(), aPos->z());
2811     aView->SetProj(aNormal->x(), aNormal->y(), aNormal->z());
2812     Bnd_Box aBox;
2813     aBox.Update(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
2814     aView->FitAll(aBox);
2815   }
2816 }
2817
2818 //**************************************************************
2819 void XGUI_Workshop::registerValidators() const
2820 {
2821   SessionPtr aMgr = ModelAPI_Session::get();
2822   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
2823 }
2824
2825 //**************************************************************
2826 void XGUI_Workshop::displayDocumentResults(DocumentPtr theDoc)
2827 {
2828   if (!theDoc)
2829     return;
2830   displayGroupResults(theDoc, ModelAPI_ResultConstruction::group());
2831   displayGroupResults(theDoc, ModelAPI_ResultBody::group());
2832 }
2833
2834 //**************************************************************
2835 void XGUI_Workshop::displayGroupResults(DocumentPtr theDoc, std::string theGroup)
2836 {
2837   for (int i = 0; i < theDoc->size(theGroup); i++)
2838     theDoc->object(theGroup, i)->setDisplayed(true);
2839     //displayObject(theDoc->object(theGroup, i));
2840   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
2841 }
2842
2843 //**************************************************************
2844 void XGUI_Workshop::setDisplayMode(const QObjectPtrList& theList, int theMode)
2845 {
2846   foreach(ObjectPtr anObj, theList) {
2847     myDisplayer->setDisplayMode(anObj, (XGUI_Displayer::DisplayMode)theMode, false);
2848
2849     ResultBodyPtr aBodyResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anObj);
2850     if (aBodyResult.get() != NULL) { // change display mode for all sub-solids
2851       std::list<ResultPtr> allRes;
2852       ModelAPI_Tools::allSubs(aBodyResult, allRes);
2853       for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
2854         myDisplayer->setDisplayMode(*aRes, (XGUI_Displayer::DisplayMode)theMode, false);
2855       }
2856     }
2857   }
2858   if (theList.size() > 0)
2859     myDisplayer->updateViewer();
2860 }
2861
2862 //**************************************************************
2863 void XGUI_Workshop::closeDocument()
2864 {
2865   ModuleBase_Operation* anOperation = operationMgr()->currentOperation();
2866   while (anOperation) {
2867     anOperation->abort();
2868     anOperation = operationMgr()->currentOperation();
2869   }
2870   //myDisplayer->closeLocalContexts();
2871   myDisplayer->eraseAll();
2872   objectBrowser()->clearContent();
2873
2874   module()->closeDocument();
2875   // we need to clear viewer (with created filters) to do not have problems in 2nd SALOME study
2876   module()->clearViewer();
2877
2878
2879   // data model need not process the document's signals about objects modifications as
2880   // the document is closed
2881   //bool isBlocked = objectBrowser()->dataModel()->blockEventsProcessing(true);
2882
2883   SessionPtr aMgr = ModelAPI_Session::get();
2884   aMgr->closeAll();
2885
2886   //objectBrowser()->dataModel()->blockEventsProcessing(isBlocked);
2887 }
2888
2889 //******************************************************
2890 void XGUI_Workshop::addHistoryMenu(QObject* theObject, const char* theSignal, const char* theSlot)
2891 {
2892   XGUI_HistoryMenu* aMenu = NULL;
2893   if (isSalomeMode()) {
2894     QAction* anAction = qobject_cast<QAction*>(theObject);
2895     if (!anAction)
2896       return;
2897     aMenu = new XGUI_HistoryMenu(anAction);
2898   } else {
2899     QToolButton* aButton =  qobject_cast<QToolButton*>(theObject);
2900     aMenu = new XGUI_HistoryMenu(aButton);
2901   }
2902   connect(this, theSignal, aMenu, SLOT(setHistory(const QList<ActionInfo>&)));
2903   connect(aMenu, SIGNAL(actionSelected(int)), this, theSlot);
2904 }
2905
2906 //******************************************************
2907 QList<ActionInfo> XGUI_Workshop::processHistoryList(const std::list<std::string>& theList) const
2908 {
2909   QList<ActionInfo> aResult;
2910   std::list<std::string>::const_iterator it = theList.cbegin();
2911   for (; it != theList.cend(); it++) {
2912     QString anId = QString::fromStdString(*it);
2913     bool isEditing = anId.endsWith(ModuleBase_OperationFeature::EditSuffix());
2914     if (isEditing) {
2915       anId.chop(ModuleBase_OperationFeature::EditSuffix().size());
2916     }
2917     ActionInfo anInfo;
2918     QAction* aContextMenuAct = myContextMenuMgr->actionByName(anId);
2919     if (aContextMenuAct) {
2920       anInfo.initFrom(aContextMenuAct);
2921     } else {
2922       anInfo = myActionsMgr->actionInfoById(anId);
2923     }
2924     if (isEditing) {
2925       anInfo.text = anInfo.text.prepend("Modify ");
2926     }
2927     aResult << anInfo;
2928   }
2929   return aResult;
2930 }
2931
2932 //******************************************************
2933 void XGUI_Workshop::setStatusBarMessage(const QString& theMessage)
2934 {
2935 #ifdef HAVE_SALOME
2936   salomeConnector()->putInfo(theMessage, -1);
2937 #else
2938   myMainWindow->putInfo(theMessage, -1);
2939 #endif
2940 }
2941
2942 #ifdef HAVE_SALOME
2943 //******************************************************
2944 void XGUI_Workshop::synchronizeViewer()
2945 {
2946   SessionPtr aMgr = ModelAPI_Session::get();
2947   QList<DocumentPtr> aDocs;
2948   aDocs.append(aMgr->activeDocument());
2949   aDocs.append(aMgr->moduleDocument());
2950
2951   foreach(DocumentPtr aDoc, aDocs) {
2952     synchronizeGroupInViewer(aDoc, false);
2953   }
2954 }
2955
2956 //******************************************************
2957 void XGUI_Workshop::synchronizeGroupInViewer(const DocumentPtr& theDoc,
2958                                              bool theUpdateViewer)
2959 {
2960   FeaturePtr aFeature;
2961   ResultPtr aRes;
2962   int aSize = theDoc->numInternalFeatures();
2963   for (int i = 0; i < aSize; i++) {
2964     aFeature = theDoc->internalFeature(i);
2965     if (!aFeature.get())
2966       continue;
2967     const std::list<ResultPtr>& aResults = aFeature->results();
2968     std::list<ResultPtr>::const_iterator aIt;
2969     aFeature->setDisplayed(false);
2970     for (aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
2971       aRes = (*aIt);
2972       if (aRes->isDisplayed() && !aRes->isConcealed()) {
2973         // Hide the presentation with an empty shape. But isDisplayed state of the object should not
2974         // be changed to the object becomes visible when the shape becomes not empty
2975         if (!aRes->shape().get() || aRes->shape()->isNull())
2976           continue;
2977         ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aRes);
2978         if (aResBody.get())
2979           synchronizeResultTree(aResBody, false);
2980         else {
2981           if (aRes->isInHistory()) {
2982             if (aRes->isDisplayed())
2983               myDisplayer->display(aRes, false);
2984             else
2985               myDisplayer->erase(aRes, false);
2986           }
2987           else
2988             aRes->setDisplayed(false);
2989         }
2990       }
2991     }
2992   }
2993   if (theUpdateViewer)
2994     myDisplayer->updateViewer();
2995 }
2996
2997 void XGUI_Workshop::synchronizeResultTree(const ResultBodyPtr& theRes, bool theUpdateViewer)
2998 {
2999   if (theRes->numberOfSubs() > 0)
3000     for (int i = 0; i < theRes->numberOfSubs(); i++) {
3001       ResultBodyPtr aRes = theRes->subResult(i);
3002       if (aRes.get())
3003         synchronizeResultTree(aRes, theUpdateViewer);
3004     }
3005   else {
3006     if (theRes->isDisplayed())
3007       myDisplayer->display(theRes, theUpdateViewer);
3008     else
3009       myDisplayer->erase(theRes, theUpdateViewer);
3010   }
3011 }
3012 #endif
3013
3014 //******************************************************
3015 void XGUI_Workshop::highlightResults(const QObjectPtrList& theObjects)
3016 {
3017   FeaturePtr aFeature;
3018   QObjectPtrList aSelList = theObjects;
3019   QObjectPtrList aNewSel;
3020   bool aHasHidden = false;
3021   foreach(ObjectPtr aObj, theObjects) {
3022     aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
3023     if (aFeature.get()) {
3024       std::list<ResultPtr> aResults;
3025       ModelAPI_Tools::allResults(aFeature, aResults);
3026       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aIt;
3027       for(aIt = aResults.cbegin(); aIt != aResults.cend(); aIt++) {
3028         aHasHidden |= (*aIt)->isConcealed();
3029         aSelList.append(*aIt);
3030         aNewSel.append(*aIt);
3031       }
3032     }
3033   }
3034   if (aSelList.count() > theObjects.count()) {
3035     // if something was found
3036     objectBrowser()->setObjectsSelected(aSelList);
3037     objectBrowser()->ensureVisible(aNewSel.first());
3038   }
3039   if (aHasHidden)
3040     QMessageBox::information(desktop(), tr("Find results"),
3041                              tr("Results not found"), QMessageBox::Ok);
3042 }
3043
3044 //******************************************************
3045 void XGUI_Workshop::highlightFeature(const QObjectPtrList& theObjects)
3046 {
3047   ResultPtr aResult;
3048   QObjectPtrList aSelList = theObjects;
3049   QObjectPtrList aNewSel;
3050   FeaturePtr aFeature;
3051   foreach(ObjectPtr aObj, theObjects) {
3052     aResult = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
3053     if (aResult.get()) {
3054       aFeature = ModelAPI_Feature::feature(aResult);
3055       if (aFeature.get()) {
3056         aSelList.append(aFeature);
3057         aNewSel.append(aFeature);
3058       }
3059     }
3060   }
3061   if (aSelList.count() > theObjects.count()) {
3062     // if something was found
3063     objectBrowser()->setObjectsSelected(aSelList);
3064     objectBrowser()->ensureVisible(aNewSel.first());
3065   }
3066 }
3067
3068 void XGUI_Workshop::insertFeatureFolder()
3069 {
3070   QObjectPtrList aObjects = mySelector->selection()->selectedObjects();
3071   if (aObjects.isEmpty())
3072     return;
3073   ObjectPtr aObj = aObjects.first();
3074   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aObj);
3075   if (aFeature.get() == NULL)
3076     return;
3077   SessionPtr aMgr = ModelAPI_Session::get();
3078   DocumentPtr aDoc = aMgr->activeDocument();
3079
3080   QString aDescription = contextMenuMgr()->action("INSERT_FOLDER_CMD")->text();
3081
3082   aMgr->startOperation(aDescription.toStdString());
3083   aDoc->addFolder(aFeature);
3084   aMgr->finishOperation();
3085
3086   updateCommandStatus();
3087 }
3088
3089
3090 void XGUI_Workshop::insertToFolder(bool isBefore)
3091 {
3092   std::list<FeaturePtr> aFeatures = mySelector->getSelectedFeatures();
3093   if (aFeatures.empty())
3094     return;
3095
3096   SessionPtr aMgr = ModelAPI_Session::get();
3097   DocumentPtr aDoc = aMgr->activeDocument();
3098
3099   FolderPtr aFolder = isBefore? aDoc->findFolderAbove(aFeatures):
3100                                 aDoc->findFolderBelow(aFeatures);
3101   if (!aFolder.get())
3102     return;
3103
3104   QString aDescription = contextMenuMgr()->action(
3105     isBefore ? "ADD_TO_FOLDER_BEFORE_CMD" : "ADD_TO_FOLDER_AFTER_CMD")->text();
3106
3107   QMap<ObjectPtr, bool> aStates = myObjectBrowser->getFoldersState(aDoc);
3108
3109   aMgr->startOperation(aDescription.toStdString());
3110   aDoc->moveToFolder(aFeatures, aFolder);
3111   aMgr->finishOperation();
3112
3113   myObjectBrowser->setFoldersState(aStates);
3114
3115   updateCommandStatus();
3116 }
3117
3118 void XGUI_Workshop::moveOutFolder(bool isBefore)
3119 {
3120   std::list<FeaturePtr> aFeatures = mySelector->getSelectedFeatures();
3121   if (aFeatures.empty())
3122     return;
3123
3124   SessionPtr aMgr = ModelAPI_Session::get();
3125   DocumentPtr aDoc = aMgr->activeDocument();
3126
3127   QString aDescription = contextMenuMgr()->action(
3128     isBefore ? "ADD_OUT_FOLDER_BEFORE_CMD" : "ADD_OUT_FOLDER_AFTER_CMD")->text();
3129
3130   QMap<ObjectPtr, bool> aStates = myObjectBrowser->getFoldersState(aDoc);
3131
3132   aMgr->startOperation(aDescription.toStdString());
3133   aDoc->removeFromFolder(aFeatures, isBefore);
3134   aMgr->finishOperation();
3135
3136   myObjectBrowser->setFoldersState(aStates);
3137
3138   updateCommandStatus();
3139 }
3140
3141 void XGUI_Workshop::onAutoApply()
3142 {
3143   SessionPtr aMgr = ModelAPI_Session::get();
3144   bool isBlocked = aMgr->isAutoUpdateBlocked();
3145   aMgr->blockAutoUpdate(!isBlocked);
3146   myDisplayer->updateViewer();
3147 }
3148
3149 void XGUI_Workshop::updateAutoComputeState()
3150 {
3151   SessionPtr aMgr = ModelAPI_Session::get();
3152   bool isComputeBlocked = aMgr->isAutoUpdateBlocked();
3153 #ifdef HAVE_SALOME
3154 //  QAction* aUpdateCmd;
3155 //  QList<QAction*> aCommands = mySalomeConnector->commandList();
3156 //  foreach(QAction* aCmd, aCommands) {
3157 //    if (aCmd->data().toString() == "AUTOCOMPUTE_CMD") {
3158 //      aUpdateCmd = aCmd;
3159 //      break;
3160 //    }
3161 //  }
3162 //  aUpdateCmd->setIcon(isComputeBlocked? QIcon(":pictures/autoapply_stop.png") :
3163 //    QIcon(":pictures/autoapply_start.png"));
3164 #else
3165   AppElements_MainMenu* aMenuBar = myMainWindow->menuObject();
3166   AppElements_Command* aUpdateCmd = aMenuBar->feature("AUTOCOMPUTE_CMD");
3167   aUpdateCmd->button()->setIcon(isComputeBlocked? QIcon(":pictures/autoapply_stop.png") :
3168     QIcon(":pictures/autoapply_start.png"));
3169 #endif
3170 }
3171
3172
3173 void XGUI_Workshop::clearTemporaryDir()
3174 {
3175   QDir aDir(myTmpDir.path());
3176   if (!aDir.isEmpty()) {
3177     QStringList aEntries;
3178     aDir.entryList(aEntries);
3179     foreach(QString aFile, aEntries) {
3180       aDir.remove(aFile);
3181     }
3182   }
3183 }
3184
3185
3186 void XGUI_Workshop::onDockSizeChanged()
3187 {
3188   QDockWidget* aDockWgt = dynamic_cast<QDockWidget*>(myObjectBrowser->parentWidget());
3189   int aObWidth = aDockWgt->size().width();
3190   if (myPropertyPanel->width() != aObWidth) {
3191     QList<QDockWidget*> aWgtList;
3192     aWgtList << myPropertyPanel << aDockWgt;
3193     QList<int> aSizeList;
3194     aSizeList << aObWidth << aObWidth;
3195     desktop()->resizeDocks(aWgtList, aSizeList, Qt::Horizontal);
3196     disconnect(myObjectBrowser, SIGNAL(sizeChanged()), this, SLOT(onDockSizeChanged()));
3197   }
3198 }
3199
3200 void XGUI_Workshop::deactivateCurrentSelector()
3201 {
3202   myActiveControlMgr->deactivateSelector(myActiveControlMgr->activeSelector());
3203 }
3204
3205 void XGUI_Workshop::changeIsoLines(const QObjectPtrList& theObjects)
3206 {
3207   if (theObjects.isEmpty())
3208     return;
3209
3210   QList<ResultPtr> aResultList;
3211   ResultPtr aRes;
3212   foreach(ObjectPtr aObj, theObjects) {
3213     aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aObj);
3214     if (aRes.get())
3215       aResultList.append(aRes);
3216   }
3217
3218   std::vector<int> aValues;
3219   bool isVisible;
3220   if (aResultList.size() == 1) {
3221     ResultPtr aRes = aResultList.first();
3222     if (aRes.get())
3223       ModelAPI_Tools::getIsoLines(aRes, isVisible, aValues);
3224     else
3225       return;
3226   }
3227   if (aValues.size() == 0) {
3228     aValues.push_back(1);
3229     aValues.push_back(1);
3230   }
3231
3232   if (!abortAllOperations())
3233     return;
3234
3235   XGUI_PropertyDialog aDlg(desktop());
3236   aDlg.setWindowTitle(tr("Number of Iso-lines"));
3237
3238   QWidget* aIsosWgt = new QWidget(&aDlg);
3239   QFormLayout* aLayout = new QFormLayout(aIsosWgt);
3240   ModuleBase_Tools::adjustMargins(aLayout);
3241   aDlg.setContent(aIsosWgt);
3242
3243   QSpinBox* aUNb = new QSpinBox(&aDlg);
3244   aUNb->setValue(aValues[0]);
3245   aLayout->addRow("U:", aUNb);
3246
3247   QSpinBox* aVNb = new QSpinBox(&aDlg);
3248   aVNb->setValue(aValues[1]);
3249   aLayout->addRow("V:", aVNb);
3250
3251   if (aDlg.exec() == QDialog::Accepted) {
3252     SessionPtr aMgr = ModelAPI_Session::get();
3253     QString aDescription = contextMenuMgr()->action("ISOLINES_CMD")->text();
3254     aMgr->startOperation(aDescription.toStdString());
3255
3256     aValues[0] = aUNb->value();
3257     aValues[1] = aVNb->value();
3258     foreach(ResultPtr aRes, aResultList) {
3259       ModelAPI_Tools::setIsoLines(aRes, aValues);
3260     }
3261     mySelector->clearSelection();
3262     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
3263     aMgr->finishOperation();
3264     updateCommandStatus();
3265   }
3266 }