0029748: Samples - Inspector tool - use recently opened files in TInspectorEXE
[occt.git] / tools / TInspectorEXE / TInspectorEXE_OpenFileDialog.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/TInspectorEXE_OpenFileDialog.hxx>
17 #include <inspector/TInspectorEXE_OpenFileViewModel.hxx>
18
19 #include <inspector/TInspector_Communicator.hxx>
20
21 #include <Standard_WarningsDisable.hxx>
22 #include <QApplication>
23 #include <QCompleter>
24 #include <QDir>
25 #include <QFileDialog>
26 #include <QFileSystemModel>
27 #include <QItemSelectionModel>
28 #include <QGroupBox>
29 #include <QHBoxLayout>
30 #include <QHeaderView>
31 #include <QLabel>
32 #include <QLineEdit>
33 #include <QScrollBar>
34 #include <QTableView>
35 #include <QToolButton>
36 #include <QPushButton>
37 #include <QVBoxLayout>
38 #include <QWidget>
39 #include <Standard_WarningsRestore.hxx>
40
41 const int FONT_POINT_SIZE = 18;
42 const int ICON_SIZE = 40;
43
44 const int OPEN_DIALOG_WIDTH = 550;
45 const int OPEN_DIALOG_HEIGHT = 200;
46
47 const int MARGIN_DIALOG = 4;
48 const int SPACING_DIALOG = 2;
49
50 const int RECENT_FILES_CACHE_SIZE = 10;
51
52 TInspector_Communicator* MyCommunicator;
53
54 // =======================================================================
55 // function : StartButton
56 // purpose :
57 // =======================================================================
58 QPushButton* TInspectorEXE_OpenButton::StartButton()
59 {
60   if (!myStartButton)
61   {
62     myStartButton = new QPushButton();
63     myStartButton->setIcon (QIcon (":folder_open.png"));
64     connect (myStartButton, SIGNAL (clicked()), this, SLOT (onStartButtonClicked()));
65   }
66   return myStartButton;
67 }
68
69 // =======================================================================
70 // function : onStartButtonClicked
71 // purpose :
72 // =======================================================================
73 void TInspectorEXE_OpenButton::onStartButtonClicked()
74 {
75   QPushButton* aButton = (QPushButton*)sender();
76   TCollection_AsciiString aPluginName (aButton->objectName().toStdString().c_str());
77   if (aPluginName.IsEmpty())
78     return;
79   
80   QStringList aPluginRecentlyOpenedFiles;
81   if (myRecentlyOpenedFiles.contains(aPluginName))
82   {
83     QStringList aFileNames = myRecentlyOpenedFiles[aPluginName];
84     for (int i = 0; i < aFileNames.size(); i++)
85     {
86       QFileInfo aFileInfo (aFileNames[i]);
87       if (aFileInfo.exists() && aFileInfo.isFile())
88         aPluginRecentlyOpenedFiles.append(aFileInfo.absoluteFilePath());
89     }
90   }
91
92   QString aFileName = TInspectorEXE_OpenFileDialog::OpenFile (0, aPluginRecentlyOpenedFiles);
93   aFileName = QDir().toNativeSeparators (aFileName);
94   if (!aFileName.isEmpty()) {
95     QApplication::setOverrideCursor (Qt::WaitCursor);
96     TInspectorEXE_OpenFileDialog::Communicator()->OpenFile (aPluginName, TCollection_AsciiString (aFileName.toUtf8().data()));
97
98     QFileInfo aFileInfo (aFileName);
99     if (!aPluginRecentlyOpenedFiles.contains (aFileInfo.absoluteFilePath()))
100     {
101       myRecentlyOpenedFiles[aPluginName].append (aFileInfo.absoluteFilePath());
102       for (int i = 0; i < myRecentlyOpenedFiles[aPluginName].size() - RECENT_FILES_CACHE_SIZE; i++)
103         myRecentlyOpenedFiles[aPluginName].removeFirst();
104       TInspectorEXE_OpenFileDialog::SetPluginRecentlyOpenedFiles (aPluginName,
105         TInspectorEXE_OpenFileDialog::Communicator(), myRecentlyOpenedFiles[aPluginName]);
106
107       TInspectorEXE_OpenFileDialog::Communicator()->GetPluginParameters()->StorePreferences();
108     }
109
110     QApplication::restoreOverrideCursor();
111   }
112 }
113
114 // =======================================================================
115 // function : changeMargins
116 // purpose :
117 // =======================================================================
118 void changeMargins (QBoxLayout* theLayout)
119 {
120   theLayout->setContentsMargins (MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG);
121   theLayout->setSpacing (SPACING_DIALOG);
122 }
123
124 // =======================================================================
125 // function : Constructor
126 // purpose :
127 // =======================================================================
128 TInspectorEXE_OpenFileDialog::TInspectorEXE_OpenFileDialog (QWidget* theParent, const QStringList& theRecentlyOpenedFiles)
129 : QDialog (theParent), myRecentlyOpenedFiles (theRecentlyOpenedFiles)
130 {
131   setWindowTitle (tr ("Open File"));
132
133   QVBoxLayout* aDialogLay = new QVBoxLayout (this);
134   changeMargins (aDialogLay);
135
136   // Samples View
137   QGroupBox* aSamplesBox = new QGroupBox (this);
138   aSamplesBox->setTitle (tr ("Recent files"));
139   aDialogLay->addWidget (aSamplesBox);
140   QVBoxLayout* aSampleLay = new QVBoxLayout (aSamplesBox);
141   changeMargins (aSampleLay);
142   mySamplesView = createTableView (theRecentlyOpenedFiles);
143   aSampleLay->addWidget (mySamplesView);
144
145   // Select file
146   QGroupBox* aSelectFileBox = new QGroupBox (this);
147   aSelectFileBox->setTitle (tr ("Select file"));
148   aDialogLay->addWidget (aSelectFileBox);
149   QGridLayout* aSelectFileLay = new QGridLayout (aSelectFileBox);
150   aSelectFileLay->setContentsMargins (MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG, MARGIN_DIALOG);
151
152   mySelectedName = new QLineEdit (aSelectFileBox);
153   QCompleter* aCompleter = new QCompleter();
154   QFileSystemModel* aFileSystemModel = new QFileSystemModel;
155   aFileSystemModel->setRootPath (QDir::rootPath());
156   aCompleter->setModel (aFileSystemModel);
157   mySelectedName->setCompleter (aCompleter);
158   aSelectFileLay->addWidget (mySelectedName, 1, 0);
159
160   QToolButton* aSelectFileBtn = new QToolButton (aSelectFileBox);
161   aSelectFileBtn->setIcon (QIcon (":folder_open.png"));
162   aSelectFileLay->addWidget (aSelectFileBtn, 1, 1);
163
164   connect (aSelectFileBtn, SIGNAL (clicked()), this, SLOT (onSelectClicked()));
165   connect (mySelectedName, SIGNAL (returnPressed()), this, SLOT (onApplySelectClicked()));
166
167   resize (OPEN_DIALOG_WIDTH, OPEN_DIALOG_HEIGHT);
168 }
169
170 // =======================================================================
171 // function : OpenFile
172 // purpose :
173 // =======================================================================
174 QString TInspectorEXE_OpenFileDialog::OpenFile (QWidget* theParent, const QStringList& theRecentlyOpenedFiles)
175 {
176   QString aFileName;
177   TInspectorEXE_OpenFileDialog* aDialog = new TInspectorEXE_OpenFileDialog (theParent, theRecentlyOpenedFiles);
178   if (aDialog->exec() == QDialog::Accepted)
179     aFileName = aDialog->GetFileName();
180
181   return aFileName;
182 }
183
184 // =======================================================================
185 // function : Communicator
186 // purpose :
187 // =======================================================================
188 TInspector_Communicator* TInspectorEXE_OpenFileDialog::Communicator()
189 {
190   if (!MyCommunicator)
191     MyCommunicator = new TInspector_Communicator();
192   return MyCommunicator;
193 }
194
195 // =======================================================================
196 // function : GetPluginRecentlyOpenedFiles
197 // purpose :
198 // =======================================================================
199 void TInspectorEXE_OpenFileDialog::GetPluginRecentlyOpenedFiles (const TCollection_AsciiString& thePluginName,
200                                                                  TInspector_Communicator* theCommunicator,
201                                                                  QStringList& theFileNames)
202 {
203   Handle(TInspectorAPI_PluginParameters) aParameters = theCommunicator->GetPluginParameters();
204   TInspectorAPI_PreferencesDataMap aPreferencesItem;
205   aParameters->GetPreferences (thePluginName, aPreferencesItem);
206
207   for (TInspectorAPI_IteratorOfPreferencesDataMap anItemIt (aPreferencesItem); anItemIt.More(); anItemIt.Next())
208   {
209     if (!anItemIt.Key().IsEqual("recently_opened_files"))
210       continue;
211     theFileNames = QString(anItemIt.Value().ToCString()).split(";", QString::SkipEmptyParts);
212     if (theFileNames.size() > RECENT_FILES_CACHE_SIZE)
213       for (int i = 0; i < theFileNames.size() - RECENT_FILES_CACHE_SIZE; i++)
214         theFileNames.removeFirst();
215     break;
216   }
217 }
218
219 // =======================================================================
220 // function : SetPluginRecentlyOpenedFiles
221 // purpose :
222 // =======================================================================
223 void TInspectorEXE_OpenFileDialog::SetPluginRecentlyOpenedFiles (const TCollection_AsciiString& thePluginName,
224                                                                  TInspector_Communicator* theCommunicator,
225                                                                  QStringList& theFileNames)
226 {
227   Handle(TInspectorAPI_PluginParameters) aParameters = theCommunicator->GetPluginParameters();
228
229   TInspectorAPI_PreferencesDataMap aPreferencesItem;
230   aParameters->GetPreferences (thePluginName, aPreferencesItem);
231   aPreferencesItem.Bind ("recently_opened_files", TCollection_AsciiString (theFileNames.join (";").toUtf8().data()));
232
233   aParameters->SetPreferences (thePluginName, aPreferencesItem);
234 }
235
236 // =======================================================================
237 // function : onSampleSelectionChanged
238 // purpose :
239 // =======================================================================
240 void TInspectorEXE_OpenFileDialog::onSampleSelectionChanged (const QItemSelection& theSelected,
241                                                              const QItemSelection&)
242 {
243   QItemSelectionModel* aSelectionModel = (QItemSelectionModel*)sender();
244   if (!aSelectionModel)
245     return;
246   if (theSelected.isEmpty())
247     return;
248
249   QModelIndex anIndex = theSelected.first().indexes().first();
250   if (!anIndex.isValid())
251     return;
252
253   myFileName = aSelectionModel->model()->data (anIndex, Qt::ToolTipRole).toString();
254   accept();
255 }
256
257 // =======================================================================
258 // function : onSelectClicked
259 // purpose :
260 // =======================================================================
261 void TInspectorEXE_OpenFileDialog::onSelectClicked()
262 {
263   QString anEnteredPath;
264   QString aDirName = mySelectedName->text();
265   if (!aDirName.isEmpty())
266   {
267     QDir aDir (aDirName);
268     if (aDir.exists())
269       anEnteredPath = aDirName;
270   }
271
272   QString aFileName = QFileDialog::getOpenFileName (0, "Open document", anEnteredPath);
273
274   if (aFileName.isEmpty())
275     return; // do nothing, left the previous value
276
277
278   myFileName = aFileName;
279   accept();
280 }
281
282 // =======================================================================
283 // function : onApplySelectClicked
284 // purpose :
285 // =======================================================================
286 void TInspectorEXE_OpenFileDialog::onApplySelectClicked()
287 {
288   QString aFileName = mySelectedName->text();
289
290   QFileInfo aFileInfo (aFileName);
291   if (!aFileInfo.exists() || !aFileInfo.isFile())
292     return;
293
294   myFileName = mySelectedName->text();
295   accept();
296 }
297
298 // =======================================================================
299 // function : createTableView
300 // purpose :
301 // =======================================================================
302 QTableView* TInspectorEXE_OpenFileDialog::createTableView (const QStringList& theFileNames)
303 {
304   QTableView* aTableView = new QTableView (this);
305   aTableView->setFrameStyle (QFrame::NoFrame);
306   QPalette aPalette = aTableView->viewport()->palette();
307   QColor aWindowColor = aPalette.color (QPalette::Window);
308   aPalette.setBrush (QPalette::Base, aWindowColor);
309   aTableView->viewport()->setPalette (aPalette);
310
311   aTableView->horizontalHeader()->setVisible (false);
312   aTableView->verticalHeader()->setVisible (false);
313   aTableView->setGridStyle (Qt::NoPen);
314   aTableView->setModel (createModel (theFileNames));
315   aTableView->setItemDelegateForRow (0, new TInspectorEXE_OpenFileItemDelegate (aTableView,
316                                                           aPalette.color (QPalette::Highlight)));
317   aTableView->viewport()->setAttribute (Qt::WA_Hover);
318   int aCellHeight = ICON_SIZE + aTableView->verticalHeader()->defaultSectionSize();
319   aTableView->setRowHeight (0, aCellHeight);
320   int aScrollHeight = aTableView->horizontalScrollBar()->sizeHint().height();
321   aTableView->setMinimumHeight (aCellHeight + aScrollHeight);
322   QItemSelectionModel* aSelectionModel = new QItemSelectionModel (aTableView->model());
323   connect (aSelectionModel, SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)),
324            this, SLOT (onSampleSelectionChanged (const QItemSelection&, const QItemSelection&)));
325   aTableView->setSelectionModel (aSelectionModel);
326
327   return aTableView;
328 }
329
330 // =======================================================================
331 // function : createModel
332 // purpose :
333 // =======================================================================
334 QAbstractItemModel* TInspectorEXE_OpenFileDialog::createModel (const QStringList& theFileNames)
335 {
336   TInspectorEXE_OpenFileViewModel* aModel = new TInspectorEXE_OpenFileViewModel (this);
337   aModel->Init (theFileNames);
338   return aModel;
339 }