8bb89ab31a8e73bcf2590ec4c18b4cd33c861145
[occt.git] / tools / TInspector / TInspector_Window.cxx
1 // Created on: 2017-06-16
2 // Created by: Natalia ERMOLAEVA
3 // Copyright (c) 2017 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement. 
15
16 #include <inspector/TInspector_Window.hxx>
17
18 #include <inspector/TInspectorAPI_Communicator.hxx>
19 #include <inspector/TInspector_PluginParameters.hxx>
20 #include <inspector/TInspector_Shortcut.hxx>
21 #include <inspector/TreeModel_Tools.hxx>
22
23 #include <inspector/ViewControl_Tools.hxx>
24
25 #include <OSD_Directory.hxx>
26 #include <OSD_Environment.hxx>
27 #include <OSD_Path.hxx>
28 #include <OSD_Protection.hxx>
29
30 #include <Standard_WarningsDisable.hxx>
31 #include <QApplication>
32 #include <QButtonGroup>
33 #include <QDockWidget>
34 #include <QLabel>
35 #include <QMainWindow>
36 #include <QMenu>
37 #include <QPushButton>
38 #include <QStackedWidget>
39 #include <QToolButton>
40 #include <QVBoxLayout>
41 #include <Standard_WarningsRestore.hxx>
42
43 const int TINSPECTOR_DEFAULT_WIDTH = 650;
44 const int TINSPECTOR_DEFAULT_HEIGHT = 500;//350;
45 const int TINSPECTOR_DEFAULT_POSITION_X = 200;
46 const int TINSPECTOR_DEFAULT_POSITION_Y = 60;
47
48 // =======================================================================
49 // function : Constructor
50 // purpose :
51 // =======================================================================
52 TInspector_Window::TInspector_Window()
53 : QObject(), myOpenButton (0)
54 {
55   myMainWindow = new QMainWindow();
56
57   QWidget* aCentralWidget = new QWidget (myMainWindow);
58   myMainWindow->setCentralWidget (aCentralWidget);
59   QVBoxLayout* aCentralLayout = new QVBoxLayout (aCentralWidget);
60   aCentralLayout->setContentsMargins (0, 0, 0, 0);
61   aCentralLayout->setSpacing (0);
62
63   myToolsStack = new QStackedWidget (aCentralWidget);
64   myToolsStack->setFrameShape (QFrame::Box);
65   aCentralLayout->addWidget (myToolsStack);
66
67   myEmptyWidget = new QWidget (aCentralWidget);
68   myToolsStack->addWidget (myEmptyWidget);
69
70   QWidget* aTopWidget = new QWidget (aCentralWidget);
71   QHBoxLayout* aTopWidgetLayout = new QHBoxLayout (aTopWidget);
72   aTopWidgetLayout->setContentsMargins (0, 0, 0, 0);
73   aTopWidgetLayout->setSpacing (0);
74
75   myButtonWidget = new QWidget (aCentralWidget);
76   myButtonLay = new QHBoxLayout (myButtonWidget);
77   myButtonLay->setContentsMargins (0, 0, 0, 0);
78   myButtonLay->setSpacing (0);
79   myButtonLay->insertStretch (0, 1);
80
81   myButtonGroup = new QButtonGroup (aCentralWidget);
82   myButtonGroup->setExclusive (true);
83
84   myActionsWidget = new QToolButton(aCentralWidget);
85   myActionsWidget->setPopupMode(QToolButton::InstantPopup);
86   myActionsWidget->setIcon (QIcon (":/icons/plugin_actions.png"));
87   myActionsWidget->setIconSize (QSize (20, 20));
88   QMenu* anActionsMenu = new QMenu(myActionsWidget);
89   myActionsWidget->setMenu(anActionsMenu);
90   connect (anActionsMenu, SIGNAL (aboutToShow()), this, SLOT (onShowActionsMenu()));
91
92   aTopWidgetLayout->addWidget(myButtonWidget, 1);
93   aTopWidgetLayout->addWidget(myActionsWidget);
94
95   aCentralLayout->addWidget (aTopWidget);
96   aCentralLayout->addWidget (myToolsStack);
97
98   myMainWindow->resize (TINSPECTOR_DEFAULT_WIDTH, TINSPECTOR_DEFAULT_HEIGHT);
99   myMainWindow->move (TINSPECTOR_DEFAULT_POSITION_X, TINSPECTOR_DEFAULT_POSITION_Y);
100   myMainWindow->setDockOptions (QMainWindow::VerticalTabs);
101
102   myParameters = new TInspector_PluginParameters (this);
103
104   myDefaultDirectory = defaultTemporaryDirectory();
105   myParameters->SetTemporaryDirectory (myDefaultDirectory);
106
107   applyPreferences();
108
109   myShortcut = new TInspector_Shortcut (myMainWindow, this);
110 }
111
112 // =======================================================================
113 // function : RegisterPlugin
114 // purpose :
115 // =======================================================================
116 void TInspector_Window::RegisterPlugin (const TCollection_AsciiString& thePluginName)
117 {
118   TInspector_ToolInfo anInfo;
119   int aToolId;
120   if (findPlugin (thePluginName, anInfo, aToolId))
121     return;
122
123   myToolNames.append (TInspector_ToolInfo (thePluginName));
124 }
125
126 // =======================================================================
127 // function : RegisteredPlugins
128 // purpose :
129 // =======================================================================
130 NCollection_List<TCollection_AsciiString> TInspector_Window::RegisteredPlugins() const
131 {
132   NCollection_List<TCollection_AsciiString> aPlugins;
133
134   for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
135     aPlugins.Append (myToolNames[aToolId].myName);
136
137   return aPlugins;
138 }
139
140 // =======================================================================
141 // function : Init
142 // purpose :
143 // =======================================================================
144 void TInspector_Window::Init (const TCollection_AsciiString& thePluginName,
145                               const NCollection_List<Handle(Standard_Transient)>& theParameters,
146                               const Standard_Boolean theAppend)
147 {
148   if (thePluginName.IsEmpty())
149   {
150     // Init all plugins by the given parameters
151     for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
152       Init (myToolNames[aToolId].myName, theParameters, theAppend);
153
154     // temporary activation of the first tool
155     if (!myToolNames.isEmpty())
156       ActivateTool (myToolNames[0].myName);
157     return;
158   }
159
160   if (theAppend)
161   {
162     NCollection_List<Handle(Standard_Transient)> aParameters;
163     if (myParameters->FindParameters (thePluginName))
164       aParameters = myParameters->Parameters (thePluginName);
165
166     for (NCollection_List<Handle(Standard_Transient)>::Iterator anIterator (theParameters);
167       anIterator.More(); anIterator.Next())
168       aParameters.Append (anIterator.Value());
169
170     myParameters->SetParameters (thePluginName, aParameters, Standard_False);
171   }
172   else
173     myParameters->SetParameters (thePluginName, theParameters, Standard_False);
174
175   TInspector_ToolInfo anInfo;
176   int aToolId;
177   if (!findPlugin (thePluginName, anInfo, aToolId))
178     return;
179
180   if (anInfo.myButton)
181     return;
182
183   QString aButtonName = anInfo.myName.ToCString();
184   if (aButtonName.indexOf("TK") == 0)
185     aButtonName = aButtonName.mid(2);
186
187   QPushButton* aButton = new QPushButton(aButtonName, myButtonWidget);
188   aButton->setCheckable (true);
189   connect (aButton, SIGNAL (clicked (bool)), this, SLOT (onButtonClicked()));
190   myButtonLay->insertWidget (myButtonLay->count()-1, aButton);
191   myButtonGroup->addButton (aButton);
192   anInfo.myButton = aButton;
193   myToolNames[aToolId] = anInfo;
194 }
195
196 // =======================================================================
197 // function : ActivateTool
198 // purpose :
199 // =======================================================================
200 void TInspector_Window::ActivateTool (const TCollection_AsciiString& thePluginName)
201 {
202   int aToolIndex = -1;
203   for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
204   {
205     if (myToolNames[aToolId].myName != thePluginName)
206       continue;
207     aToolIndex = aToolId;
208     break;
209   }
210
211   if (aToolIndex < 0)
212     return;
213
214   TInspector_ToolInfo anInfo = myToolNames[aToolIndex];
215   bool isPluginLoaded = false;
216   if (!anInfo.myWidget)
217   {
218     if (!LoadPlugin (thePluginName, anInfo))
219     {
220       anInfo.myButton->setEnabled (false);
221       return;
222     }
223     isPluginLoaded = true;
224     myToolsStack->addWidget (anInfo.myWidget);
225     myToolNames[aToolIndex] = anInfo;
226   }
227
228   QWidget* aWidget = anInfo.myWidget;
229   myToolsStack->setCurrentWidget (aWidget);
230   if (myOpenButton)
231     myOpenButton->setObjectName (thePluginName.ToCString());
232
233   anInfo.myCommunicator->UpdateContent();
234   if (isPluginLoaded)
235   {
236     // apply preferences
237     TInspectorAPI_PreferencesDataMap aPreferences;
238     myParameters->GetPreferences (thePluginName, aPreferences);
239     anInfo.myCommunicator->SetPreferences (aPreferences);
240   }
241   onCommuncatorNameChanged();
242 }
243
244 // =======================================================================
245 // function : SetSelected
246 // purpose :
247 // =======================================================================
248 void TInspector_Window::SetSelected (const NCollection_List<TCollection_AsciiString>& theItemNames)
249 {
250   TInspector_ToolInfo anInfo;
251   if (!activeToolInfo (anInfo))
252     return;
253
254   myParameters->SetSelectedNames (anInfo.myName, theItemNames);
255
256   TInspectorAPI_Communicator* aCommunicator = anInfo.myCommunicator;
257   if (aCommunicator)
258   {
259     aCommunicator->UpdateContent();
260   }
261 }
262
263 // =======================================================================
264 // function : SetSelected
265 // purpose :
266 // =======================================================================
267 void TInspector_Window::SetSelected (const NCollection_List<Handle(Standard_Transient)>& theObjects)
268 {
269   TInspector_ToolInfo anInfo;
270   if (!activeToolInfo (anInfo))
271     return;
272
273   myParameters->SetSelected (anInfo.myName, theObjects);
274
275   TInspectorAPI_Communicator* aCommunicator = anInfo.myCommunicator;
276   if (aCommunicator)
277   {
278     aCommunicator->UpdateContent();
279   }
280 }
281
282 // =======================================================================
283 // function : SetOpenButton
284 // purpose :
285 // =======================================================================
286 void TInspector_Window::SetOpenButton (QPushButton* theButton)
287 {
288   myOpenButton = theButton;
289   TInspector_ToolInfo anInfo;
290   if (activeToolInfo (anInfo))
291     myOpenButton->setObjectName (anInfo.myName.ToCString());
292   myButtonLay->insertWidget (0, theButton);
293 }
294
295 // =======================================================================
296 // function : OpenFile
297 // purpose :
298 // =======================================================================
299 void TInspector_Window::OpenFile (const TCollection_AsciiString& thePluginName,
300                                   const TCollection_AsciiString& theFileName)
301 {
302   if (thePluginName.IsEmpty())
303   {
304     // Apply file name to all plugins
305     for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
306       OpenFile (myToolNames[aToolId].myName, theFileName);
307     return;
308   }
309
310   myParameters->AddFileName (thePluginName, theFileName);
311
312   TInspector_ToolInfo anInfo;
313   if (!activeToolInfo (anInfo) || anInfo.myName != thePluginName)
314     return;
315
316   TInspectorAPI_Communicator* aCommunicator = anInfo.myCommunicator;
317   if (aCommunicator)
318     aCommunicator->UpdateContent();
319 }
320
321 // =======================================================================
322 // function : UpdateContent
323 // purpose :
324 // =======================================================================
325 void TInspector_Window::UpdateContent()
326 {
327   TInspector_ToolInfo anInfo;
328   if (activeToolInfo (anInfo) && anInfo.myCommunicator)
329     anInfo.myCommunicator->UpdateContent();
330 }
331
332 // =======================================================================
333 // function : LoadPlugin
334 // purpose :
335 // =======================================================================
336 bool TInspector_Window::LoadPlugin (const TCollection_AsciiString& thePluginName, TInspector_ToolInfo& theInfo)
337 {
338   bool aLoaded = false;
339
340   QApplication::setOverrideCursor (Qt::WaitCursor);
341   TInspectorAPI_Communicator* aCommunicator = TInspectorAPI_Communicator::LoadPluginLibrary (thePluginName);
342
343   if (aCommunicator)
344   {
345     aCommunicator->SetParameters (myParameters);
346     QWidget* aParentWidget = new QWidget (myMainWindow);
347     QVBoxLayout* aLayout = new QVBoxLayout (aParentWidget);
348     aLayout->setContentsMargins (0, 0, 0, 0);
349     aLayout->setSpacing (0);
350     aParentWidget->setLayout (aLayout);
351     aCommunicator->SetParent (aParentWidget);
352     theInfo.myWidget = aParentWidget;
353     theInfo.myCommunicator = aCommunicator;
354 #if QT_VERSION >= 0x050000
355     connect (aParentWidget, SIGNAL (objectNameChanged (const QString&)), this, SLOT (onCommuncatorNameChanged()));
356 #endif
357     aLoaded = true;
358   }
359   QApplication::restoreOverrideCursor();
360   return aLoaded;
361 }
362
363 // =======================================================================
364 // function : GetPreferences
365 // purpose :
366 // =======================================================================
367 void TInspector_Window::GetPreferences (TInspectorAPI_PreferencesDataMap& theItem)
368 {
369   theItem.Bind ("geometry", TreeModel_Tools::ToString (myMainWindow->saveGeometry()).toStdString().c_str());
370 }
371
372 // =======================================================================
373 // function : SetPreferences
374 // purpose :
375 // =======================================================================
376 void TInspector_Window::SetPreferences (const TInspectorAPI_PreferencesDataMap& theItem)
377 {
378   for (TInspectorAPI_IteratorOfPreferencesDataMap anItemIt (theItem); anItemIt.More(); anItemIt.Next())
379   {
380     if (anItemIt.Key().IsEqual ("geometry"))
381       myMainWindow->restoreGeometry (TreeModel_Tools::ToByteArray (anItemIt.Value().ToCString()));
382   }
383 }
384
385 // =======================================================================
386 // function : Dump
387 // purpose :
388 // =======================================================================
389 void TInspector_Window::Dump (Standard_OStream& theStream) const
390 {
391   TInspector_ToolInfo anInfo;
392   activeToolInfo(anInfo);
393
394   theStream << "Active Plugin: " << anInfo.myName << "\n";
395   theStream << "Temporary Directory: " << GetTemporaryDirectory() << "\n";
396 }
397
398 // =======================================================================
399 // function : OnStorePreferences
400 // purpose :
401 // =======================================================================
402 void TInspector_Window::OnStorePreferences()
403 {
404   Handle(TInspector_PluginParameters) aParameters = Handle(TInspector_PluginParameters)::DownCast (myParameters);
405   TInspectorAPI_PreferencesDataMap aPreferences;
406   GetPreferences (aPreferences);
407   aParameters->SetPreferences ("Desktop", aPreferences);
408
409   TInspector_ToolInfo anInfo;
410   for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
411   {
412     anInfo = myToolNames[aToolId];
413     if (!anInfo.myCommunicator)
414       continue;
415
416     aParameters->GetPreferences (anInfo.myName, aPreferences);
417     anInfo.myCommunicator->GetPreferences (aPreferences);
418     myParameters->SetPreferences (anInfo.myName, aPreferences);
419   }
420
421   // store preferences parameters into a file
422   aParameters->StorePreferences();
423 }
424
425 // =======================================================================
426 // function : OnRemovePreferences
427 // purpose :
428 // =======================================================================
429 void TInspector_Window::OnRemovePreferences()
430 {
431   Handle(TInspector_PluginParameters) aParameters = Handle(TInspector_PluginParameters)::DownCast (myParameters);
432
433   // remove preferences file
434   aParameters->RemovePreferences();
435
436   // restore plugins default state
437   TInspector_ToolInfo anInfo;
438   for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
439   {
440     anInfo = myToolNames[aToolId];
441     if (!anInfo.myCommunicator)
442       continue;
443     anInfo.myCommunicator->SetPreferences (TInspectorAPI_PreferencesDataMap());
444   }
445 }
446
447 // =======================================================================
448 // function : onButtonClicked
449 // purpose :
450 // =======================================================================
451 void TInspector_Window::onButtonClicked()
452 {
453   QPushButton* aButton = (QPushButton*)sender();
454
455   TCollection_AsciiString aPluginName = aButton->text().toStdString().c_str();
456
457   TInspector_ToolInfo anInfo;
458   int aToolId;
459   if (!findPlugin (aPluginName, anInfo, aToolId))
460     aPluginName = TCollection_AsciiString ("TK") + aPluginName;
461
462   ActivateTool (aPluginName);
463 }
464
465 // =======================================================================
466 // function : onShowActionsMenu
467 // purpose :
468 // =======================================================================
469 void TInspector_Window::onShowActionsMenu()
470 {
471   myActionsWidget->menu()->clear();
472
473   TInspector_ToolInfo anInfo;
474   activeToolInfo(anInfo);
475
476   QMenu* aMenu = myActionsWidget->menu();
477   anInfo.myCommunicator->FillActionsMenu(aMenu);
478
479   aMenu->addSeparator();
480   aMenu->addAction (ViewControl_Tools::CreateAction (tr ("Store Preferences"),
481                     SLOT (OnStorePreferences()), myMainWindow, this));
482   QAction* anAction = ViewControl_Tools::CreateAction (tr ("Remove Preferences"),
483                     SLOT (OnRemovePreferences()), myMainWindow, this);
484   anAction->setToolTip ("Default state will be restored after restarting the application");
485   aMenu->addAction (anAction);
486 }
487
488 // =======================================================================
489 // function : onCommuncatorNameChanged
490 // purpose :
491 // =======================================================================
492 void TInspector_Window::onCommuncatorNameChanged()
493 {
494 #if QT_VERSION >= 0x050000
495   TInspector_ToolInfo anInfo;
496   if (!activeToolInfo (anInfo))
497     return;
498   myMainWindow->setWindowTitle (anInfo.myWidget->objectName());
499 #endif
500 }
501
502 // =======================================================================
503 // function : activeToolInfo
504 // purpose :
505 // =======================================================================
506 bool TInspector_Window::activeToolInfo (TInspector_Window::TInspector_ToolInfo& theToolInfo) const
507 {
508   QWidget* anActiveWidget = myToolsStack->currentWidget();
509   if (anActiveWidget == myEmptyWidget)
510     return false;
511
512   for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
513   {
514     if (myToolNames[aToolId].myWidget && myToolNames[aToolId].myWidget == anActiveWidget)
515     {
516       theToolInfo = myToolNames[aToolId];
517       return true;
518     }
519   }
520   return false;
521 }
522
523 // =======================================================================
524 // function : findPlugin
525 // purpose :
526 // =======================================================================
527 bool TInspector_Window::findPlugin (const TCollection_AsciiString& thePluginName, TInspector_ToolInfo& theToolInfo,
528                                     int& theToolId)
529 {
530   for (int aToolId = 0, aSize = myToolNames.size(); aToolId < aSize; aToolId++)
531   {
532     TInspector_ToolInfo anInfo = myToolNames[aToolId];
533     if (anInfo.myName != thePluginName)
534       continue;
535     theToolInfo = anInfo;
536     theToolId = aToolId;
537     return true;
538   }
539
540   return false;
541 }
542
543 // =======================================================================
544 // function : applyPreferences
545 // purpose :
546 // =======================================================================
547 void TInspector_Window::applyPreferences()
548 {
549   TInspectorAPI_PreferencesDataMap aPreferences;
550   myParameters->GetPreferences ("Desktop", aPreferences);
551   SetPreferences (aPreferences);
552 }
553
554 // =======================================================================
555 // function : defaultTemporaryDirectory
556 // purpose :
557 // =======================================================================
558 TCollection_AsciiString TInspector_Window::defaultTemporaryDirectory() const
559 {
560   // main window creation
561   TCollection_AsciiString aTmpDir;
562 #ifdef _WIN32
563   OSD_Environment anEnvironment ("TEMP");
564   aTmpDir = anEnvironment.Value();
565   if (aTmpDir.IsEmpty() )
566   {
567     anEnvironment.SetName ("TMP");
568     aTmpDir = anEnvironment.Value();
569     if (aTmpDir.IsEmpty())
570       aTmpDir = "C:\\";
571   }
572   if (!aTmpDir.EndsWith ("\\"))
573     aTmpDir += "\\";
574   OSD_Path aTmpPath (aTmpDir);
575   OSD_Directory aTmpDirectory;
576 #else
577   OSD_Directory aTmpDirectory = OSD_Directory::BuildTemporary();
578   OSD_Path aTmpPath;
579   aTmpDirectory.Path (aTmpPath);
580 #endif
581   aTmpPath.DownTrek ("TInspector");
582   aTmpDirectory.SetPath (aTmpPath);
583   if (!aTmpDirectory.Exists())
584     aTmpDirectory.Build (OSD_Protection());
585
586   aTmpDirectory.Path (aTmpPath);
587   TCollection_AsciiString aTmpDirectoryName;
588   aTmpPath.SystemName (aTmpDirectoryName);
589
590   return aTmpDir;
591 }