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