Fraxinus  2023.01.05-dev+develop.0da12
An IGT application
cxLayoutInteractor.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 #include "cxLayoutInteractor.h"
13 #include "cxLayoutEditorWidget.h"
14 #include <QMenu>
15 #include <QMessageBox>
16 #include <QDialogButtonBox>
17 #include <QMetaMethod>
18 #include "boost/bind.hpp"
19 #include "libQtSignalAdapters/Qt2Func.h"
20 #include "libQtSignalAdapters/ConnectionFactories.h"
21 #include <QVBoxLayout>
22 #include "cxLayoutRepository.h"
23 #include "cxViewService.h"
24 
25 namespace cx
26 {
27 
28 LayoutInteractor::LayoutInteractor(ViewServicePtr viewService, QObject* parent) :
29  QObject(parent),
30  mViewService(viewService)
31 {
32  mSecondaryLayoutActionGroup = NULL;
33  mLayoutActionGroup = NULL;
34  this->createActions();
35  connect(viewService.get(), SIGNAL(activeLayoutChanged()), this, SLOT(layoutChangedSlot()));
36 }
37 
38 LayoutRepositoryPtr LayoutInteractor::getRepo()
39 {
40  return mViewService->getLayoutRepository();
41 }
42 
43 void LayoutInteractor::createActions()
44 {
45  mNewLayoutAction = new QAction(tr("New Layout"), this);
46  mNewLayoutAction->setToolTip("Create a new Custom Layout");
47  connect(mNewLayoutAction, SIGNAL(triggered()), this, SLOT(newCustomLayoutSlot()));
48  mEditLayoutAction = new QAction(tr("Edit Layout"), this);
49  mEditLayoutAction->setToolTip("Edit the current Custom Layout");
50  connect(mEditLayoutAction, SIGNAL(triggered()), this, SLOT(editCustomLayoutSlot()));
51  mDeleteLayoutAction = new QAction(tr("Delete Layout"), this);
52  mDeleteLayoutAction->setToolTip("Delete the current Custom Layout");
53  connect(mDeleteLayoutAction, SIGNAL(triggered()), this, SLOT(deleteCustomLayoutSlot()));
54 }
55 
57 {
58  mMenu = menu;
59 
60  mMenu->addAction(mNewLayoutAction);
61  mMenu->addAction(mEditLayoutAction);
62  mMenu->addAction(mDeleteLayoutAction);
63 
64  mSecondaryLayoutMenu = new QMenu("Secondary Layout", mMenu);
65  mMenu->addMenu(mSecondaryLayoutMenu);
66 
67  mMenu->addSeparator();
68 
69  this->layoutChangedSlot();
70 }
71 
72 
73 void LayoutInteractor::newCustomLayoutSlot()
74 {
75  LayoutData data = this->executeLayoutEditorDialog("New Custom Layout", true);
76  if (data.getUid().isEmpty())
77  return;
78  this->getRepo()->insert(data);
79  mViewService->setActiveLayout(data.getUid());
80 }
81 
82 void LayoutInteractor::editCustomLayoutSlot()
83 {
84  LayoutData data = this->executeLayoutEditorDialog("Edit Current Layout", false);
85  if (data.getUid().isEmpty())
86  return;
87  this->getRepo()->insert(data);
88 }
89 
90 void LayoutInteractor::deleteCustomLayoutSlot()
91 {
92  if (QMessageBox::question(NULL, "Delete current layout", "Do you really want to delete the current layout?",
93  QMessageBox::Cancel | QMessageBox::Ok) != QMessageBox::Ok)
94  return;
95  this->getRepo()->erase(mViewService->getActiveLayout());
96  mViewService->setActiveLayout(this->getRepo()->getAvailable().front()); // revert to existing state
97 }
98 
101 void LayoutInteractor::layoutChangedSlot()
102 {
103  if (!mMenu)
104  return;
105  if (!this->getRepo())
106  return;
107  // reset list of available layouts
108 
109  this->deepDeleteActionGroup(mLayoutActionGroup);
110  mLayoutActionGroup = this->createLayoutActionGroup(0);
111  mMenu->addActions(mLayoutActionGroup->actions());
112 
113  this->deepDeleteActionGroup(mSecondaryLayoutActionGroup);
114  mSecondaryLayoutActionGroup = this->createLayoutActionGroup(1);
115  mSecondaryLayoutMenu->addActions(mSecondaryLayoutActionGroup->actions());
116 
117  bool editable = this->getRepo()->isCustom(mViewService->getActiveLayout());
118  mEditLayoutAction->setEnabled(editable);
119  mDeleteLayoutAction->setEnabled(editable);
120 }
121 
122 void LayoutInteractor::deepDeleteActionGroup(QActionGroup* actionGroup)
123 {
124  //Make sure all actions in the group are deleted - possibly removes a few memory leaks
125  if (actionGroup)
126  {
127  QList<QAction*> actionList = actionGroup->actions();
128  for (int i = 0; i < actionList.size(); i++)
129  delete actionList.at(i);
130  }
131 
132  delete actionGroup;
133 }
134 
138 LayoutData LayoutInteractor::executeLayoutEditorDialog(QString title, bool createNew)
139 {
140  boost::shared_ptr<QDialog> dialog(new QDialog(NULL, Qt::Dialog));
141  dialog->setWindowTitle(title);
142  QVBoxLayout* layout = new QVBoxLayout(dialog.get());
143  layout->setMargin(0);
144 
145  LayoutEditorWidget* editor = new LayoutEditorWidget(mViewService, dialog.get());
146 
147  LayoutData data = this->getRepo()->get(mViewService->getActiveLayout());
148 
149  if (createNew)
150  {
151  data.resetUid(this->getRepo()->generateUid());
152  }
153  editor->setLayoutData(data);
154  layout->addWidget(editor);
155 
156  QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
157  connect(buttonBox, SIGNAL(accepted()), dialog.get(), SLOT(accept()));
158  connect(buttonBox, SIGNAL(rejected()), dialog.get(), SLOT(reject()));
159  layout->addWidget(buttonBox);
160 
161  if (!dialog->exec())
162  return LayoutData();
163 
164  return editor->getLayoutData();
165 }
166 
167 QActionGroup* LayoutInteractor::createLayoutActionGroup(int widgetIndex)
168 {
169  QActionGroup* retval = new QActionGroup(this);
170  retval->setExclusive(true);
171  if (!this->getRepo())
172  return retval;
173 
174 
175  // add default layouts
176  std::vector<QString> layouts = this->getRepo()->getAvailable();
177  int defaultLayouts = 0;
178  for (unsigned i = 0; i < layouts.size(); ++i)
179  {
180  if (!this->getRepo()->isCustom(layouts[i]))
181  {
182  this->addLayoutAction(layouts[i], retval, widgetIndex);
183  defaultLayouts++;
184  }
185  }
186 
187  // add separator
188  QAction* sep = new QAction(retval);
189  sep->setSeparator(true);
190  //retval->addAction(sep);
191 
192  if (defaultLayouts != layouts.size())
193  {
194  QAction* action = new QAction("Custom", retval);
195  action->setEnabled(false);
196  }
197 
198  // add custom layouts
199  for (unsigned i = 0; i < layouts.size(); ++i)
200  {
201  if (this->getRepo()->isCustom(layouts[i]))
202  this->addLayoutAction(layouts[i], retval, widgetIndex);
203  }
204 
205  // set checked status
206  QString type = mViewService->getActiveLayout(widgetIndex);
207  QList<QAction*> actions = retval->actions();
208  for (int i = 0; i < actions.size(); ++i)
209  {
210  if (actions[i]->data().toString() == type)
211  actions[i]->setChecked(true);
212  }
213 
214  return retval;
215 }
216 
219 QAction* LayoutInteractor::addLayoutAction(QString layout, QActionGroup* group, int widgetIndex)
220 {
221  LayoutData data = this->getRepo()->get(layout);
222  if (data.isEmpty())
223  {
224  QAction* sep = new QAction(group);
225  sep->setSeparator(true);
226  }
227  QAction* action = new QAction(data.getName(), group);
228  action->setEnabled(!data.isEmpty());
229  action->setCheckable(!data.isEmpty());
230  action->setData(QVariant(layout));
231 
232 // std::cout << "** " << layout << "-" << widgetIndex << std::endl;
233  QtSignalAdapters::connect0<void()>(
234  action,
235  SIGNAL(triggered()),
236  boost::bind(&LayoutInteractor::setActiveLayout, this, layout, widgetIndex));
237 
238  return action;
239 }
240 
241 void LayoutInteractor::setActiveLayout(QString layout, int widgetIndex)
242 {
243 // std::cout << "*slot* " << layout << "-" << widgetIndex << std::endl;
244  mViewService->setActiveLayout(layout, widgetIndex);
245 }
246 
247 } // namespace cx
248 
boost::shared_ptr< class LayoutRepository > LayoutRepositoryPtr
void connectToMenu(QMenu *menu)
boost::shared_ptr< class ViewService > ViewServicePtr
QString getUid() const
Definition: cxLayoutData.h:88
LayoutData getLayoutData() const
LayoutInteractor(ViewServicePtr viewService, QObject *parent=NULL)
QString getName() const
Definition: cxLayoutData.h:89
void setLayoutData(const LayoutData &data)
bool isEmpty() const
Definition: cxLayoutData.h:102
Namespace for all CustusX production code.