]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_Workshop.cpp
Salome HOME
Updating property pannel on sketch editing (refs #31)
[modules/shaper.git] / src / XGUI / XGUI_Workshop.cpp
1 #include "XGUI_Module.h"
2 #include "XGUI_Constants.h"
3 #include "XGUI_Command.h"
4 #include "XGUI_MainMenu.h"
5 #include "XGUI_MainWindow.h"
6 #include "XGUI_MenuGroupPanel.h"
7 #include "XGUI_Tools.h"
8 #include "XGUI_Workbench.h"
9 #include "XGUI_Workshop.h"
10 #include "XGUI_Viewer.h"
11 #include "ModuleBase_WidgetFactory.h"
12 #include "XGUI_SelectionMgr.h"
13 #include "XGUI_ObjectsBrowser.h"
14 #include "XGUI_Displayer.h"
15 #include "XGUI_OperationMgr.h"
16 #include "XGUI_SalomeConnector.h"
17 #include "XGUI_SalomeViewer.h"
18 #include "XGUI_ActionsMgr.h"
19 #include "XGUI_ErrorDialog.h"
20 #include "XGUI_ViewerProxy.h"
21 #include "XGUI_PropertyPanel.h"
22
23 #include <Model_Events.h>
24 #include <ModelAPI_PluginManager.h>
25 #include <ModelAPI_Feature.h>
26 #include <ModelAPI_Data.h>
27 #include <ModelAPI_AttributeDocRef.h>
28
29 #include <Events_Loop.h>
30 #include <Events_Error.h>
31 #include <ModuleBase_Operation.h>
32 #include <ModuleBase_Operation.h>
33 #include <ModuleBase_OperationDescription.h>
34 #include <Config_FeatureMessage.h>
35 #include <Config_PointerMessage.h>
36
37 #include <QApplication>
38 #include <QFileDialog>
39 #include <QMessageBox>
40 #include <QMdiSubWindow>
41 #include <QPushButton>
42 #include <QDockWidget>
43 #include <QLayout>
44
45 #ifdef _DEBUG
46 #include <QDebug>
47 #endif
48
49 #ifdef WIN32
50 #include <windows.h>
51 #else
52 #include <dlfcn.h>
53 #endif
54
55 XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
56   : QObject(),
57   myCurrentFile(QString()),
58   myPartSetModule(NULL),
59   mySalomeConnector(theConnector),
60   myPropertyPanel(0),
61   myObjectBrowser(0),
62   myDisplayer(0)
63 {
64   myMainWindow = mySalomeConnector? 0 : new XGUI_MainWindow();
65
66   myDisplayer = new XGUI_Displayer(this);
67
68   mySelector = new XGUI_SelectionMgr(this);
69   connect(mySelector, SIGNAL(selectionChanged()), this, SLOT(changeCurrentDocument()));
70
71   myOperationMgr = new XGUI_OperationMgr(this);
72   myActionsMgr = new XGUI_ActionsMgr(this);
73   myErrorDlg = new XGUI_ErrorDialog(myMainWindow);
74
75   myViewerProxy = new XGUI_ViewerProxy(this);
76
77   connect(myOperationMgr, SIGNAL(operationStarted()),  this, SLOT(onOperationStarted()));
78   connect(myOperationMgr, SIGNAL(operationStopped(ModuleBase_Operation*)),
79           this, SLOT(onOperationStopped(ModuleBase_Operation*)));
80   connect(this, SIGNAL(errorOccurred(const QString&)), myErrorDlg, SLOT(addError(const QString&)));
81 }
82
83 //******************************************************
84 XGUI_Workshop::~XGUI_Workshop(void)
85 {
86 }
87
88 //******************************************************
89 void XGUI_Workshop::startApplication()
90 {
91   initMenu();
92   //Initialize event listening
93   Events_Loop* aLoop = Events_Loop::loop();
94   aLoop->registerListener(this, Events_Error::errorID()); //!< Listening application errors.
95   //TODO(sbh): Implement static method to extract event id [SEID]
96   Events_ID aFeatureId = aLoop->eventByName(EVENT_FEATURE_LOADED);
97   aLoop->registerListener(this, aFeatureId);
98   Events_ID aPartSetId = aLoop->eventByName("PartSetModuleEvent");
99   aLoop->registerListener(this, aPartSetId);
100   Events_ID aFeatureUpdatedId = aLoop->eventByName(EVENT_FEATURE_UPDATED);
101   aLoop->registerListener(this, aFeatureUpdatedId);
102   activateModule();
103   if (myMainWindow) {
104     myMainWindow->show();
105     updateCommandStatus();
106   }
107   onNew();
108 }
109
110 //******************************************************
111 void XGUI_Workshop::initMenu()
112 {
113   if (isSalomeMode()) {
114     // Create only Undo, Redo commands
115     salomeConnector()->addEditCommand("UNDO_CMD", 
116                                       tr("Undo"), tr("Undo last command"),
117                                       QIcon(":pictures/undo.png"), 
118                                       false, this, SLOT(onUndo()),
119                                       QKeySequence::Undo);
120     salomeConnector()->addEditCommand("REDO_CMD", 
121                                       tr("Redo"), tr("Redo last command"),
122                                       QIcon(":pictures/redo.png"), 
123                                       false, this, SLOT(onRedo()),
124                                       QKeySequence::Redo);
125     salomeConnector()->addEditMenuSeparator();
126     return;
127   }
128   XGUI_Workbench* aPage = myMainWindow->menuObject()->generalPage();
129
130   // File commands group
131   XGUI_MenuGroupPanel* aGroup = aPage->addGroup("Default");
132
133   XGUI_Command* aCommand;
134
135   aCommand = aGroup->addFeature("SAVE_CMD", tr("Save..."), tr("Save the document"),
136                                 QIcon(":pictures/save.png"), QKeySequence::Save);
137   aCommand->connectTo(this, SLOT(onSave()));
138   //aCommand->disable();
139
140   aCommand = aGroup->addFeature("UNDO_CMD", tr("Undo"), tr("Undo last command"),
141                                 QIcon(":pictures/undo.png"), QKeySequence::Undo);
142   aCommand->connectTo(this, SLOT(onUndo()));
143
144   aCommand = aGroup->addFeature("REDO_CMD", tr("Redo"), tr("Redo last command"),
145                                 QIcon(":pictures/redo.png"), QKeySequence::Redo);
146   aCommand->connectTo(this, SLOT(onRedo()));
147
148   aCommand = aGroup->addFeature("REBUILD_CMD", tr("Rebuild"), tr("Rebuild data objects"),
149                                 QIcon(":pictures/rebuild.png"));
150
151   aCommand = aGroup->addFeature("SAVEAS_CMD", tr("Save as..."), tr("Save the document into a file"),
152                                 QIcon(":pictures/save.png"));
153   aCommand->connectTo(this, SLOT(onSaveAs()));
154   //aCommand->disable();
155
156   aCommand = aGroup->addFeature("OPEN_CMD", tr("Open..."), tr("Open a new document"),
157                                 QIcon(":pictures/open.png"), QKeySequence::Open);
158   aCommand->connectTo(this, SLOT(onOpen()));
159
160   //aCommand = aGroup->addFeature("NEW_CMD", tr("New"), tr("Create a new document"),
161   //                              QIcon(":pictures/new.png"), QKeySequence::New);
162   //aCommand->connectTo(this, SLOT(onNew()));
163
164   aCommand = aGroup->addFeature("EXIT_CMD", tr("Exit"), tr("Exit application"),
165                                 QIcon(":pictures/close.png"), QKeySequence::Close);
166   aCommand->connectTo(this, SLOT(onExit()));
167
168 }
169
170 //******************************************************
171 XGUI_Workbench* XGUI_Workshop::addWorkbench(const QString& theName)
172 {
173   XGUI_MainMenu* aMenuBar = myMainWindow->menuObject();
174   return aMenuBar->addWorkbench(theName);
175 }
176
177 //******************************************************
178 void XGUI_Workshop::processEvent(const Events_Message* theMessage)
179 {
180   //A message to start feature creation received.
181   static Events_ID aFeatureLoadedId = Events_Loop::loop()->eventByName(EVENT_FEATURE_LOADED);
182   if (theMessage->eventID() == aFeatureLoadedId) {
183     const Config_FeatureMessage* aFeatureMsg = dynamic_cast<const Config_FeatureMessage*>(theMessage);
184     addFeature(aFeatureMsg);
185     return;
186   }
187   //Update property panel on corresponding message. If there is no current operation (no
188   //property panel), or received message has different feature to the current - do nothing.
189   static Events_ID aFeatureUpdatedId = Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED);
190   if (theMessage->eventID() == aFeatureUpdatedId && myOperationMgr->hasOperation())
191   {
192     const Model_FeatureUpdatedMessage* anUpdateMsg =
193         dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
194     boost::shared_ptr<ModelAPI_Feature> aNewFeature = anUpdateMsg->feature();
195     boost::shared_ptr<ModelAPI_Feature> aCurrentFeature = myOperationMgr->currentOperation()->feature();
196     if(aNewFeature == aCurrentFeature) {
197       myPropertyPanel->updateContentWidget(aCurrentFeature);
198     }
199   }
200   //An operation passed by message. Start it, process and commit.
201   const Config_PointerMessage* aPartSetMsg = dynamic_cast<const Config_PointerMessage*>(theMessage);
202   if (aPartSetMsg) {
203     ModuleBase_Operation* anOperation =
204         (ModuleBase_Operation*)(aPartSetMsg->pointer());
205
206     if (myOperationMgr->startOperation(anOperation)) {
207       if (anOperation->getDescription()->xmlRepresentation().isEmpty()) {
208         anOperation->commit();
209         updateCommandStatus();
210       }
211     }
212     return;
213   }
214   //Show error dialog if error message received.
215   const Events_Error* anAppError = dynamic_cast<const Events_Error*>(theMessage);
216   if (anAppError) {
217     emit errorOccurred(QString::fromLatin1(anAppError->description()));
218     myErrorDlg->show();
219     myErrorDlg->raise();
220     myErrorDlg->activateWindow();
221   }
222
223 }
224
225 //******************************************************
226 void XGUI_Workshop::onOperationStarted()
227 {
228   ModuleBase_Operation* aOperation = myOperationMgr->currentOperation();
229
230   if(!aOperation->getDescription()->xmlRepresentation().isEmpty()) { //!< No need for property panel
231     connectWithOperation(aOperation);
232
233     showPropertyPanel();
234
235     ModuleBase_WidgetFactory aFactory = ModuleBase_WidgetFactory(aOperation);
236     QWidget* aContent = myPropertyPanel->contentWidget();
237     qDeleteAll(aContent->children());
238     aFactory.createWidget(aContent);
239     myPropertyPanel->setModelWidgets(aFactory.getModelWidgets());
240     myPropertyPanel->setWindowTitle(aOperation->getDescription()->description());
241   }
242 }
243
244 //******************************************************
245 void XGUI_Workshop::onOperationStopped(ModuleBase_Operation* theOperation)
246 {
247   ModuleBase_Operation* aOperation = myOperationMgr->currentOperation();
248
249   if(aOperation->getDescription()->xmlRepresentation().isEmpty()) { //!< No need for property panel
250     updateCommandStatus();
251   } else {
252     hidePropertyPanel();
253     updateCommandStatus();
254     myActionsMgr->restoreCommandState();
255   }
256 }
257
258 /*
259  *
260  */
261 void XGUI_Workshop::addFeature(const Config_FeatureMessage* theMessage)
262 {
263   if (!theMessage) {
264 #ifdef _DEBUG
265     qDebug() << "XGUI_Workshop::addFeature: NULL message.";
266 #endif
267     return;
268   }
269   //Find or create Workbench
270   QString aWchName = QString::fromStdString(theMessage->workbenchId());
271   QString aNestedFeatures = QString::fromStdString(theMessage->nestedFeatures());
272   bool isUsePropPanel = theMessage->isUseInput();
273   if (isSalomeMode()) {
274     QString aId = QString::fromStdString(theMessage->id());
275     salomeConnector()->addFeature(aWchName,
276                                   QString::fromStdString(theMessage->id()),
277                                   aId,
278                                   QString::fromStdString(theMessage->tooltip()),
279                                   QIcon(theMessage->icon().c_str()),
280                                   isUsePropPanel, this, 
281                                   SLOT(onFeatureTriggered()), QKeySequence());
282     myActionsMgr->addCommand(aId, salomeConnector()->command(aId));
283     salomeConnector()->setNestedActions(aId, aNestedFeatures.split(" "));
284
285   } else {
286
287     XGUI_MainMenu* aMenuBar = myMainWindow->menuObject();
288     XGUI_Workbench* aPage = aMenuBar->findWorkbench(aWchName);
289     if (!aPage) {
290       aPage = addWorkbench(aWchName);
291     }
292     //Find or create Group
293     QString aGroupName = QString::fromStdString(theMessage->groupId());
294     XGUI_MenuGroupPanel* aGroup = aPage->findGroup(aGroupName);
295     if (!aGroup) {
296       aGroup = aPage->addGroup(aGroupName);
297     }
298     //Create feature...
299     XGUI_Command* aCommand = aGroup->addFeature(QString::fromStdString(theMessage->id()),
300                                                 QString::fromStdString(theMessage->text()),
301                                                 QString::fromStdString(theMessage->tooltip()),
302                                                 QIcon(theMessage->icon().c_str()),
303                                                 QKeySequence(), isUsePropPanel);
304     aCommand->setUnblockableCommands(aNestedFeatures.split(" "));
305     myActionsMgr->addCommand(aCommand);
306     myPartSetModule->featureCreated(aCommand);
307   }
308 }
309
310 /*
311  * Makes a signal/slot connections between Property Panel
312  * and given operation. The given operation becomes a
313  * current operation and previous operation if exists
314  */
315 void XGUI_Workshop::connectWithOperation(ModuleBase_Operation* theOperation)
316 {
317   QPushButton* aOkBtn = myPropertyPanel->findChild<QPushButton*>(XGUI::PROP_PANEL_OK);
318   connect(aOkBtn, SIGNAL(clicked()), theOperation, SLOT(commit()));
319   QPushButton* aCancelBtn = myPropertyPanel->findChild<QPushButton*>(XGUI::PROP_PANEL_CANCEL);
320   connect(aCancelBtn, SIGNAL(clicked()), theOperation, SLOT(abort()));
321
322   QAction* aCommand = 0;
323   if (isSalomeMode()) {
324     aCommand = salomeConnector()->command(theOperation->getDescription()->operationId());
325   } else {
326     XGUI_MainMenu* aMenu = myMainWindow->menuObject();
327     aCommand = aMenu->feature(theOperation->getDescription()->operationId());
328   }
329   //Abort operation on uncheck the command
330   connect(aCommand, SIGNAL(triggered(bool)), theOperation, SLOT(setRunning(bool)));
331 }
332
333 /*
334  * Saves document with given name.
335  */
336 void XGUI_Workshop::saveDocument(QString theName)
337 {
338   QApplication::restoreOverrideCursor();
339   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
340   boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
341   aDoc->save(theName.toLatin1().constData());
342   QApplication::restoreOverrideCursor();
343 }
344
345 //******************************************************
346 void XGUI_Workshop::onExit()
347 {
348   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
349   boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
350   if(aDoc->isModified()) {
351     int anAnswer = QMessageBox::question(
352         myMainWindow, tr("Save current file"),
353         tr("The document is modified, save before exit?"),
354         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
355     if(anAnswer == QMessageBox::Save) {
356       onSave();
357     } else if (anAnswer == QMessageBox::Cancel) {
358       return;
359     }
360   }
361   qApp->exit();
362 }
363
364 //******************************************************
365 void XGUI_Workshop::onNew()
366 {
367   QApplication::setOverrideCursor(Qt::WaitCursor);
368   if (objectBrowser() == 0) {
369     createDockWidgets();
370     mySelector->connectViewers();
371   }
372   myViewerProxy->connectToViewer();
373   showObjectBrowser();
374   if (!isSalomeMode()) {
375     myMainWindow->showPythonConsole();
376     QMdiSubWindow* aWnd = myMainWindow->viewer()->createView();
377     aWnd->showMaximized();
378     updateCommandStatus();
379   }
380   QApplication::restoreOverrideCursor();
381 }
382
383 //******************************************************
384 void XGUI_Workshop::onOpen()
385 {
386   //save current file before close if modified
387   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
388   boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
389   if(aDoc->isModified()) {
390     //TODO(sbh): re-launch the app?
391     int anAnswer = QMessageBox::question(
392         myMainWindow, tr("Save current file"),
393         tr("The document is modified, save before opening another?"),
394         QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
395     if(anAnswer == QMessageBox::Save) {
396       onSave();
397     } else if (anAnswer == QMessageBox::Cancel) {
398       return;
399     }
400     aDoc->close();
401     myCurrentFile = "";
402   }
403
404   //show file dialog, check if readable and open
405   myCurrentFile = QFileDialog::getOpenFileName(mainWindow());
406   if(myCurrentFile.isEmpty())
407     return;
408   QFileInfo aFileInfo(myCurrentFile);
409   if(!aFileInfo.exists() || !aFileInfo.isReadable()) {
410     QMessageBox::critical(myMainWindow, tr("Warning"), tr("Unable to open the file."));
411     myCurrentFile = "";
412     return;
413   }
414   QApplication::setOverrideCursor(Qt::WaitCursor);
415   aDoc->load(myCurrentFile.toLatin1().constData());
416   QApplication::restoreOverrideCursor();
417   updateCommandStatus();
418 }
419
420 //******************************************************
421 void XGUI_Workshop::onSave()
422 {
423   if(myCurrentFile.isEmpty()) {
424     onSaveAs();
425     return;
426   }
427   saveDocument(myCurrentFile);
428   updateCommandStatus();
429 }
430
431 //******************************************************
432 void XGUI_Workshop::onSaveAs()
433 {
434   QString aTemp = myCurrentFile;
435   myCurrentFile = QFileDialog::getSaveFileName(mainWindow());
436   if(myCurrentFile.isEmpty()) {
437     myCurrentFile = aTemp;
438     return;
439   }
440   QFileInfo aFileInfo(myCurrentFile);
441   if(aFileInfo.exists() && !aFileInfo.isWritable()) {
442     QMessageBox::critical(myMainWindow, tr("Warning"), tr("Unable to save the file."));
443     return;
444   }
445   onSave();
446 }
447
448 //******************************************************
449 void XGUI_Workshop::onUndo()
450 {
451   objectBrowser()->setCurrentIndex(QModelIndex());
452   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
453   boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
454   aDoc->undo();
455   updateCommandStatus();
456 }
457
458 //******************************************************
459 void XGUI_Workshop::onRedo()
460 {
461   objectBrowser()->setCurrentIndex(QModelIndex());
462   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
463   boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
464   aDoc->redo();
465   updateCommandStatus();
466 }
467
468 //******************************************************
469 XGUI_Module* XGUI_Workshop::loadModule(const QString& theModule)
470 {
471   QString libName = library(theModule);
472   if (libName.isEmpty()) {
473     qWarning(
474     qPrintable( tr( "Information about module \"%1\" doesn't exist." ).arg( theModule ) ));
475     return 0;
476   }
477
478   QString err;
479   CREATE_FUNC crtInst = 0;
480
481 #ifdef WIN32
482
483   HINSTANCE modLib = ::LoadLibrary((LPTSTR) qPrintable(libName));
484   if (!modLib) {
485     LPVOID lpMsgBuf;
486     ::FormatMessage(
487         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
488         0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
489     QString aMsg((char*) &lpMsgBuf);
490     err = QString("Failed to load  %1. %2").arg(libName).arg(aMsg);
491     ::LocalFree(lpMsgBuf);
492   } else {
493     crtInst = (CREATE_FUNC) ::GetProcAddress(modLib, CREATE_MODULE);
494     if (!crtInst) {
495       LPVOID lpMsgBuf;
496       ::FormatMessage(
497           FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
498               | FORMAT_MESSAGE_IGNORE_INSERTS,
499           0, ::GetLastError(), 0, (LPTSTR) & lpMsgBuf, 0, 0);
500       QString aMsg((char*) &lpMsgBuf);
501       err = QString("Failed to find  %1 function. %2").arg( CREATE_MODULE).arg(aMsg);
502       ::LocalFree(lpMsgBuf);
503     }
504   }
505 #else
506   void* modLib = dlopen( libName.toLatin1(), RTLD_LAZY );
507   if ( !modLib )
508   err = QString( "Can not load library %1. %2" ).arg( libName ).arg( dlerror() );
509   else
510   {
511     crtInst = (CREATE_FUNC)dlsym( modLib, CREATE_MODULE );
512     if ( !crtInst )
513     err = QString( "Failed to find function %1. %2" ).arg( CREATE_MODULE ).arg( dlerror() );
514   }
515 #endif
516
517   XGUI_Module* aModule = crtInst ? crtInst(this) : 0;
518
519   if (!err.isEmpty()) {
520     if (mainWindow() && mainWindow()->isVisible())
521       QMessageBox::warning(mainWindow(), tr("Error"), err);
522     else
523       qWarning( qPrintable( err ));
524   }
525   return aModule;
526 }
527
528 //******************************************************
529 bool XGUI_Workshop::activateModule()
530 {
531   myPartSetModule = loadModule("PartSet");
532   if (!myPartSetModule)
533     return false;
534   myPartSetModule->createFeatures();
535   return true;
536 }
537
538 //******************************************************
539 void XGUI_Workshop::updateCommandStatus()
540 {
541   if (isSalomeMode()) // TODO: update commands in SALOME
542     return;
543   XGUI_MainMenu* aMenuBar = myMainWindow->menuObject();
544
545   QList<XGUI_Command*> aCommands = aMenuBar->features();
546   QList<XGUI_Command*>::const_iterator aIt;
547
548   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
549   if (aMgr->hasRootDocument()) {
550     XGUI_Command* aUndoCmd;
551     XGUI_Command* aRedoCmd;
552     for (aIt = aCommands.constBegin(); aIt != aCommands.constEnd(); ++aIt) {
553       if ((*aIt)->id() == "UNDO_CMD")
554         aUndoCmd = (*aIt);
555       else if ((*aIt)->id() == "REDO_CMD")
556         aRedoCmd = (*aIt);
557       else // Enable all commands
558         (*aIt)->enable();
559     }
560     boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
561     aUndoCmd->setEnabled(aDoc->canUndo());
562     aRedoCmd->setEnabled(aDoc->canRedo());
563   } else {
564     for (aIt = aCommands.constBegin(); aIt != aCommands.constEnd(); ++aIt) {
565       if ((*aIt)->id() == "NEW_CMD")
566         (*aIt)->enable();
567       else if ((*aIt)->id() == "EXIT_CMD")
568         (*aIt)->enable();
569       else 
570         (*aIt)->disable();
571     }
572   }
573 }
574
575 //******************************************************
576 QDockWidget* XGUI_Workshop::createObjectBrowser(QWidget* theParent)
577 {
578   QDockWidget* aObjDock = new QDockWidget(theParent);
579   aObjDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
580   aObjDock->setWindowTitle(tr("Object browser"));
581   myObjectBrowser = new XGUI_ObjectsBrowser(aObjDock);
582   aObjDock->setWidget(myObjectBrowser);
583   return aObjDock;
584 }
585
586 //******************************************************
587 /*
588  * Creates dock widgets, places them in corresponding area
589  * and tabifies if necessary.
590  */
591 void XGUI_Workshop::createDockWidgets()
592 {
593   QMainWindow* aDesktop = isSalomeMode()? salomeConnector()->desktop() :
594                                           myMainWindow;
595   QDockWidget* aObjDock = createObjectBrowser(aDesktop);
596   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, aObjDock);
597   myPropertyPanel = new XGUI_PropertyPanel(aDesktop);
598   aDesktop->addDockWidget(Qt::LeftDockWidgetArea, myPropertyPanel);
599   hidePropertyPanel(); //<! Invisible by default
600   hideObjectBrowser();
601   aDesktop->tabifyDockWidget(aObjDock, myPropertyPanel);
602 }
603
604 //******************************************************
605 void XGUI_Workshop::showPropertyPanel()
606 {
607   QAction* aViewAct = myPropertyPanel->toggleViewAction();
608   //<! Restore ability to close panel from the window's menu
609   aViewAct->setEnabled(true);
610   myPropertyPanel->show();
611   myPropertyPanel->raise();
612 }
613
614 //******************************************************
615 void XGUI_Workshop::hidePropertyPanel()
616 {
617   QAction* aViewAct = myPropertyPanel->toggleViewAction();
618   //<! Do not allow to show empty property panel
619   aViewAct->setEnabled(false);
620   myPropertyPanel->hide();
621 }
622
623 //******************************************************
624 void XGUI_Workshop::showObjectBrowser()
625 {
626   myObjectBrowser->parentWidget()->show();
627 }
628
629 //******************************************************
630 void XGUI_Workshop::hideObjectBrowser()
631 {
632   myObjectBrowser->parentWidget()->hide();
633 }
634
635 //******************************************************
636 void XGUI_Workshop::onFeatureTriggered()
637 {
638   QAction* aCmd = dynamic_cast<QAction*>(sender());
639   if (aCmd) {
640     QString aId = salomeConnector()->commandId(aCmd);
641     if (!aId.isNull())
642       myPartSetModule->launchOperation(aId);
643   }
644 }
645
646 //******************************************************
647 void XGUI_Workshop::changeCurrentDocument()
648 {
649   QFeatureList aFeatures = objectBrowser()->selectedFeatures();
650   
651   // Set current document
652   if (aFeatures.size() > 0) {
653     FeaturePtr aFeature = aFeatures.first();
654
655     boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
656     boost::shared_ptr<ModelAPI_AttributeDocRef> aDocRef = aFeature->data()->docRef("PartDocument");
657     if (aDocRef)
658       aMgr->setCurrentDocument(aDocRef->value());
659   }
660 }
661
662 //******************************************************
663 void XGUI_Workshop::salomeViewerSelectionChanged()
664 {
665   emit salomeViewerSelection();
666 }
667
668
669 //**************************************************************
670 XGUI_SalomeViewer* XGUI_Workshop::salomeViewer() const 
671
672   return mySalomeConnector->viewer(); 
673 }