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