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