Fraxinus  16.5.0-fx-rc5
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include "cxLayoutInteractor.h"
34 #include "cxLayoutEditorWidget.h"
35 #include <QMenu>
36 #include <QMessageBox>
37 #include <QDialogButtonBox>
38 #include <QMetaMethod>
39 #include "boost/bind.hpp"
40 #include "libQtSignalAdapters/Qt2Func.h"
41 #include "libQtSignalAdapters/ConnectionFactories.h"
42 #include <QVBoxLayout>
43 #include "cxLayoutRepository.h"
44 #include "cxViewService.h"
45 
46 namespace cx
47 {
48 
49 LayoutInteractor::LayoutInteractor(QObject* parent) : QObject(parent)
50 {
51  mSecondaryLayoutActionGroup = NULL;
52  mLayoutActionGroup = NULL;
53  this->createActions();
54  connect(viewService().get(), SIGNAL(activeLayoutChanged()), this, SLOT(layoutChangedSlot()));
55 }
56 
57 LayoutRepositoryPtr LayoutInteractor::getRepo()
58 {
59  return viewService()->getLayoutRepository();
60 }
61 
62 void LayoutInteractor::createActions()
63 {
64  mNewLayoutAction = new QAction(tr("New Layout"), this);
65  mNewLayoutAction->setToolTip("Create a new Custom Layout");
66  connect(mNewLayoutAction, SIGNAL(triggered()), this, SLOT(newCustomLayoutSlot()));
67  mEditLayoutAction = new QAction(tr("Edit Layout"), this);
68  mEditLayoutAction->setToolTip("Edit the current Custom Layout");
69  connect(mEditLayoutAction, SIGNAL(triggered()), this, SLOT(editCustomLayoutSlot()));
70  mDeleteLayoutAction = new QAction(tr("Delete Layout"), this);
71  mDeleteLayoutAction->setToolTip("Delete the current Custom Layout");
72  connect(mDeleteLayoutAction, SIGNAL(triggered()), this, SLOT(deleteCustomLayoutSlot()));
73 }
74 
76 {
77  mMenu = menu;
78 
79  mMenu->addAction(mNewLayoutAction);
80  mMenu->addAction(mEditLayoutAction);
81  mMenu->addAction(mDeleteLayoutAction);
82 
83  mSecondaryLayoutMenu = new QMenu("Secondary Layout", mMenu);
84  mMenu->addMenu(mSecondaryLayoutMenu);
85 
86  mMenu->addSeparator();
87 
88  this->layoutChangedSlot();
89 }
90 
91 
92 void LayoutInteractor::newCustomLayoutSlot()
93 {
94  LayoutData data = this->executeLayoutEditorDialog("New Custom Layout", true);
95  if (data.getUid().isEmpty())
96  return;
97  this->getRepo()->insert(data);
98  viewService()->setActiveLayout(data.getUid());
99 }
100 
101 void LayoutInteractor::editCustomLayoutSlot()
102 {
103  LayoutData data = this->executeLayoutEditorDialog("Edit Current Layout", false);
104  if (data.getUid().isEmpty())
105  return;
106  this->getRepo()->insert(data);
107 }
108 
109 void LayoutInteractor::deleteCustomLayoutSlot()
110 {
111  if (QMessageBox::question(NULL, "Delete current layout", "Do you really want to delete the current layout?",
112  QMessageBox::Cancel | QMessageBox::Ok) != QMessageBox::Ok)
113  return;
114  this->getRepo()->erase(viewService()->getActiveLayout());
115  viewService()->setActiveLayout(this->getRepo()->getAvailable().front()); // revert to existing state
116 }
117 
120 void LayoutInteractor::layoutChangedSlot()
121 {
122  if (!mMenu)
123  return;
124  if (!this->getRepo())
125  return;
126  // reset list of available layouts
127 
128  this->deepDeleteActionGroup(mLayoutActionGroup);
129  mLayoutActionGroup = this->createLayoutActionGroup(0);
130  mMenu->addActions(mLayoutActionGroup->actions());
131 
132  this->deepDeleteActionGroup(mSecondaryLayoutActionGroup);
133  mSecondaryLayoutActionGroup = this->createLayoutActionGroup(1);
134  mSecondaryLayoutMenu->addActions(mSecondaryLayoutActionGroup->actions());
135 
136  bool editable = this->getRepo()->isCustom(viewService()->getActiveLayout());
137  mEditLayoutAction->setEnabled(editable);
138  mDeleteLayoutAction->setEnabled(editable);
139 }
140 
141 void LayoutInteractor::deepDeleteActionGroup(QActionGroup* actionGroup)
142 {
143  //Make sure all actions in the group are deleted - possibly removes a few memory leaks
144  if (actionGroup)
145  {
146  QList<QAction*> actionList = actionGroup->actions();
147  for (int i = 0; i < actionList.size(); i++)
148  delete actionList.at(i);
149  }
150 
151  delete actionGroup;
152 }
153 
157 LayoutData LayoutInteractor::executeLayoutEditorDialog(QString title, bool createNew)
158 {
159  boost::shared_ptr<QDialog> dialog(new QDialog(NULL, Qt::Dialog));
160  dialog->setWindowTitle(title);
161  QVBoxLayout* layout = new QVBoxLayout(dialog.get());
162  layout->setMargin(0);
163 
164  LayoutEditorWidget* editor = new LayoutEditorWidget(dialog.get());
165 
166  LayoutData data = this->getRepo()->get(viewService()->getActiveLayout());
167 
168  if (createNew)
169  {
170  data.resetUid(this->getRepo()->generateUid());
171  }
172  editor->setLayoutData(data);
173  layout->addWidget(editor);
174 
175  QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
176  connect(buttonBox, SIGNAL(accepted()), dialog.get(), SLOT(accept()));
177  connect(buttonBox, SIGNAL(rejected()), dialog.get(), SLOT(reject()));
178  layout->addWidget(buttonBox);
179 
180  if (!dialog->exec())
181  return LayoutData();
182 
183  return editor->getLayoutData();
184 }
185 
186 QActionGroup* LayoutInteractor::createLayoutActionGroup(int widgetIndex)
187 {
188  QActionGroup* retval = new QActionGroup(this);
189  retval->setExclusive(true);
190  if (!this->getRepo())
191  return retval;
192 
193 
194  // add default layouts
195  std::vector<QString> layouts = this->getRepo()->getAvailable();
196  int defaultLayouts = 0;
197  for (unsigned i = 0; i < layouts.size(); ++i)
198  {
199  if (!this->getRepo()->isCustom(layouts[i]))
200  {
201  this->addLayoutAction(layouts[i], retval, widgetIndex);
202  defaultLayouts++;
203  }
204  }
205 
206  // add separator
207  QAction* sep = new QAction(retval);
208  sep->setSeparator(true);
209  //retval->addAction(sep);
210 
211  if (defaultLayouts != layouts.size())
212  {
213  QAction* action = new QAction("Custom", retval);
214  action->setEnabled(false);
215  }
216 
217  // add custom layouts
218  for (unsigned i = 0; i < layouts.size(); ++i)
219  {
220  if (this->getRepo()->isCustom(layouts[i]))
221  this->addLayoutAction(layouts[i], retval, widgetIndex);
222  }
223 
224  // set checked status
225  QString type = viewService()->getActiveLayout(widgetIndex);
226  QList<QAction*> actions = retval->actions();
227  for (int i = 0; i < actions.size(); ++i)
228  {
229  if (actions[i]->data().toString() == type)
230  actions[i]->setChecked(true);
231  }
232 
233  return retval;
234 }
235 
238 QAction* LayoutInteractor::addLayoutAction(QString layout, QActionGroup* group, int widgetIndex)
239 {
240  LayoutData data = this->getRepo()->get(layout);
241  if (data.isEmpty())
242  {
243  QAction* sep = new QAction(group);
244  sep->setSeparator(true);
245  }
246  QAction* action = new QAction(data.getName(), group);
247  action->setEnabled(!data.isEmpty());
248  action->setCheckable(!data.isEmpty());
249  action->setData(QVariant(layout));
250 
251 // std::cout << "** " << layout << "-" << widgetIndex << std::endl;
252  QtSignalAdapters::connect0<void()>(
253  action,
254  SIGNAL(triggered()),
255  boost::bind(&LayoutInteractor::setActiveLayout, this, layout, widgetIndex));
256 
257  return action;
258 }
259 
260 void LayoutInteractor::setActiveLayout(QString layout, int widgetIndex)
261 {
262 // std::cout << "*slot* " << layout << "-" << widgetIndex << std::endl;
263  viewService()->setActiveLayout(layout, widgetIndex);
264 }
265 
266 } // namespace cx
267 
boost::shared_ptr< class LayoutRepository > LayoutRepositoryPtr
void connectToMenu(QMenu *menu)
QString getUid() const
Definition: cxLayoutData.h:108
cxLogicManager_EXPORT ViewServicePtr viewService()
LayoutInteractor(QObject *parent=NULL)