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