VPTissue Reference Manual
WorkspaceView.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2011-2016 Universiteit Antwerpen
3  *
4  * Licensed under the EUPL, Version 1.1 or as soon they will be approved by
5  * the European Commission - subsequent versions of the EUPL (the "Licence");
6  * You may not use this work except in compliance with the Licence.
7  * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl5
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the Licence is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the Licence for the specific language governing
13  * permissions and limitations under the Licence.
14  */
20 #include "WorkspaceView.h"
21 
23 #include "util/misc/Exception.h"
25 
26 #include <QContextMenuEvent>
27 #include <QHeaderView>
28 #include <QInputDialog>
29 #include <QItemSelectionModel>
30 #include <QMenu>
31 #include <QMessageBox>
32 
33 namespace SimShell {
34 namespace Gui {
35 
36 using namespace SimPT_Sim::Util;
37 using namespace std;
38 
39 WorkspaceView::WorkspaceView(QWidget* parent)
40  : MyTreeView(parent),
41  model(nullptr),
42  project_widget(nullptr)
43 {
44  action_open = new QAction(QIcon::fromTheme("document-open"), "Open", this);
45  action_rename = new QAction("Rename...", this);
46  action_rename->setShortcut(QKeySequence("F2"));
47  action_rename->setShortcutContext(Qt::WidgetShortcut);
48  action_remove = new QAction(QIcon::fromTheme("edit-delete"), "Remove", this);
49  action_remove->setShortcut(QKeySequence("Del"));
50  action_remove->setShortcutContext(Qt::WidgetShortcut);
51  action_close = new QAction("Close", this);
52  action_close->setShortcutContext(Qt::WidgetShortcut);
53 
54  // add actions so they can be triggered by shortcut when widget has focus.
55  addAction(action_open);
56  addAction(action_rename);
57  addAction(action_remove);
58  addAction(action_close);
59 
60  // all actions are disabled until some workspace is opened.
61  action_open->setEnabled(false);
62  action_rename->setEnabled(false);
63  action_remove->setEnabled(false);
64  action_close->setEnabled(false);
65 
66  connect(action_open, SIGNAL(triggered()), this, SLOT(SLOT_Open()));
67  connect(action_rename, SIGNAL(triggered()), this, SLOT(SLOT_RenameDialog()));
68  connect(action_remove, SIGNAL(triggered()), this, SLOT(SLOT_Remove()));
69  connect(action_close, SIGNAL(triggered()), this, SLOT(SLOT_Close()));
70 
71  header()->hide();
72  setAnimated(true);
73 }
74 
76 {
77  // disable all actions until a selection is made
78  action_open->setEnabled(false);
79  action_rename->setEnabled(false);
80  action_remove->setEnabled(false);
81  action_close->setEnabled(false);
82 
83  model = dynamic_cast<WorkspaceQtModel*>(m);
84 
85  QTreeView::setModel(model);
86 
87  if (model) {
88  connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection const &, QItemSelection const &)),
89  this, SLOT(SLOT_SelectionChanged(QItemSelection const &, QItemSelection const &)));
90  }
91 }
92 
94 {
95  return action_open;
96 }
97 
99 {
100  return action_rename;
101 }
102 
104 {
105  return action_remove;
106 }
107 
108 void WorkspaceView::SLOT_Close()
109 {
110  QModelIndexList list = selectedIndexes();
111  if (list.empty()) {
112  return;
113  }
114  QModelIndex const& index = list.first();
115  model->Close(index);
116  action_rename->setEnabled(true);
117 }
118 
119 void WorkspaceView::SLOT_Open()
120 {
121  QModelIndexList list = selectedIndexes();
122  if (list.empty()) {
123  return;
124  }
125  QModelIndex const& index = list.first();
126  try {
127  model->Open(index);
128  // if project was opened we can't rename it
129  action_rename->setEnabled(false);
130  } catch (exception& e) {
131  QMessageBox::warning(this, "Could not open file", e.what());
132  }
133 }
134 
135 void WorkspaceView::SLOT_RenameDialog()
136 {
137  QModelIndexList list = selectedIndexes();
138  if (list.empty()) {
139  return;
140  }
141  QModelIndex index = list.first();
142  if (model->GetType(index) == WorkspaceQtModel::FileType) {
143  index = model->parent(index);
144  }
145  string const old_name = model->GetName(index);
146  bool ok;
147  string const new_name = QInputDialog::getText(this, "Rename project", "Please enter a new name:",
148  QLineEdit::Normal, QString::fromStdString(old_name), &ok).toStdString();
149  if (ok && (new_name != old_name)) {
150  try {
151  model->Workspace()->Rename(old_name, new_name);
152  // Remove project widget if there is one
153  if (project_widget_project_name == old_name) {
154  project_widget.reset();
155  project_widget_project_name.clear();
156  }
157  emit ProjectRenamed(old_name, new_name);
158  } catch (Exception& e) {
159  QMessageBox::warning(this, "Error", QString("Could not rename project: ") + e.what());
160  }
161  }
162 }
163 
164 void WorkspaceView::SLOT_Remove()
165 {
166  QModelIndexList list = selectedIndexes();
167  if (list.empty()) {
168  return;
169  }
170  QModelIndex index = list.first();
171 
172  if (model->GetType(index) == WorkspaceQtModel::FileType) {
173  if (model->rowCount(model->parent(index)) == 1) {
174  if (QMessageBox::warning(this, "Continue?",
175  "This is the only file in this project.\nRemoving it will remove the project.\nContinue?",
176  QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
177  index = model->parent(index);
178  string project_name = model->GetName(index);
179  try {
180  model->Close(index);
181  model->Workspace()->Remove(project_name); // may throw
182  // Remove project widget if there is one
183  if (project_widget_project_name == project_name) {
184  project_widget.reset();
185  project_widget_project_name.clear();
186  }
187  emit ProjectRemoved(project_name);
188  } catch (Exception& e) {
189  QMessageBox::warning(this, "Error", QString("Could not remove project: ") + e.what());
190  }
191  }
192  } else {
193  if (QMessageBox::warning(this, "Warning", "Remove file?\nThis cannot be undone.",
194  QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
195  string project_name = model->GetName(model->parent(index));
196  string file_name = model->GetName(index);
197  try {
198  auto project = model->Workspace()->Get(project_name);
199  project->Remove(file_name);
200  } catch (Exception& e) {
201  QMessageBox::warning(this, "Error", QString("Could not remove file:") + e.what());
202  }
203  }
204  }
205 
206  } else if (model->GetType(index) == WorkspaceQtModel::ProjectType) {
207  if (QMessageBox::warning(this, "Warning", "Remove project?\nThis cannot be undone.",
208  QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) {
209  string project_name = model->GetName(index);
210  try {
211  model->Close(index);
212  model->Workspace()->Remove(project_name);
213  // Remove project widget if there is one
214  if (project_widget_project_name == project_name) {
215  project_widget.reset();
216  project_widget_project_name.clear();
217  }
218  emit ProjectRemoved(project_name);
219 
220  } catch (Exception& e) {
221  QMessageBox::warning(this, "Error", QString("Could not remove project.") + e.what());
222  }
223  }
224  }
225 }
226 
227 void WorkspaceView::SLOT_SelectionChanged(QItemSelection const &, QItemSelection const &)
228 {
229  if (QItemSelectionModel* s_model = selectionModel()) {
230  QModelIndexList indexes = s_model->selection().indexes();
231  if (indexes.empty()) {
232  // no selection -> disable most actions
233  action_open->setEnabled(false);
234  action_rename->setEnabled(false);
235  action_remove->setEnabled(false);
236  action_close->setEnabled(false);
237  } else {
238  action_remove->setEnabled(true);
239 
240  QModelIndex index = indexes.first(); // only one item can be selected at the same time.
241 
242  action_close->setEnabled(model->IsOpened(index));
243 
244  if (model->GetType(index) == WorkspaceQtModel::ProjectType) {
245  action_open->setEnabled(true);
246  action_rename->setEnabled(!model->IsOpened(index));
247  } else if (model->GetType(index) == WorkspaceQtModel::FileType) {
248  action_open->setEnabled(true);
249  action_rename->setEnabled(false);
250  }
251  }
252  } else {
253  // no model -> disable all actions
254  action_open->setEnabled(false);
255  action_rename->setEnabled(false);
256  action_remove->setEnabled(false);
257  action_close->setEnabled(false);
258  }
259 }
260 
261 void WorkspaceView::SLOT_ProjectWidgetAction()
262 {
263  auto& entry = object_to_callback_map[sender()];
264  auto prefs = Ws::MergedPreferences::Create(
265  model->Workspace(),
266  model->Workspace()->Get(entry.project_name));
267  project_widget = entry.callback(prefs, this);
268  //project_widget->setWindowModality(Qt::ApplicationModal);
269  project_widget_project_name = entry.project_name;
270 }
271 
272 void WorkspaceView::contextMenuEvent(QContextMenuEvent* event)
273 {
274  QMenu menu(this);
275 
276  QModelIndexList list = selectedIndexes();
277  if (!list.empty()) {
278  QModelIndex const & index = list.first();
279  menu.addAction(action_open);
280  menu.addSeparator();
281  if (model->GetType(index) == WorkspaceQtModel::ProjectType) {
282  object_to_callback_map.clear();
283  auto project = model->Workspace()->Get(model->GetName(index));
284  bool project_is_opened = model->IsOpened(index);
285  for (auto widget : project->GetWidgets()) {
286  auto a = menu.addAction(QString::fromStdString(widget.name));
287  if (project_is_opened)
288  a->setEnabled(false);
289  object_to_callback_map[a] = {widget.callback, model->GetName(index)};
290  // TODO: In Qt5, we can connect signals to C++11 lambda functions,
291  // this would make this whole thing much easier...
292  connect(a, SIGNAL(triggered()), this, SLOT(SLOT_ProjectWidgetAction()));
293  }
294  }
295  for (auto& action : model->GetContextMenuActions(index)) {
296  menu.addAction(action);
297  }
298  if (model->GetType(index) == WorkspaceQtModel::ProjectType) {
299  menu.addAction(action_rename);
300  }
301  menu.addAction(action_remove);
302  menu.addSeparator();
303  action_close->setEnabled(model->IsOpened(index));
304  menu.addAction(action_close);
305  }
306  menu.exec(event->globalPos());
307 }
308 
310 {
311  auto const& list = selectedIndexes();
312  if (!list.empty()) {
313  auto const& index = list.first();
314  WorkspaceQtModel::ItemType type = model->GetType(index);
315  if (type == WorkspaceQtModel::FileType) {
316  return (void) SLOT_Open();
317  }
318  }
319 
320  // don't override other events
321  return (void) QTreeView::mouseDoubleClickEvent(e);
322 }
323 
324 } // end of namespace Gui
325 } // end of namespace SimShell
virtual void mouseDoubleClickEvent(QMouseEvent *)
Reimplemented from QTreeView.
STL namespace.
QAction * GetOpenAction() const
Get 'open' action object.
see the online Qt documentation
Namespace for miscellaneous utilities.
Definition: PTreeFile.cpp:44
QAction * GetRemoveAction() const
Get 'remove' action object.
virtual const char * what() const noexcept
Return error message.
Definition: Exception.h:38
Interface for WorkspaceQtModel.
Extremely simple Exception root class.
Definition: Exception.h:28
see the online Qt documentation
Interface for MergedPreferences.
virtual void contextMenuEvent(QContextMenuEvent *)
Reimplemented from QWidget.
QAction * GetRenameAction() const
Get 'rename' action object.
Interface for WorkspaceView.
see the online Qt documentation
Header file for Exception class.
virtual void setModel(QAbstractItemModel *)
Set the model.
Namespace for generic graphical shell for simulators.
Definition: SimSession.h:32
Abstraction of workspace on the filesystem.