fw4spl
SDynamicView.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "guiQt/editor/SDynamicView.hpp"
8 
9 #include <fwActivities/IActivityValidator.hpp>
10 #include <fwActivities/IValidator.hpp>
11 
12 #include <fwCom/Signal.hxx>
13 #include <fwCom/Slot.hxx>
14 #include <fwCom/Slots.hxx>
15 
16 #include <fwData/Boolean.hpp>
17 #include <fwData/Composite.hpp>
18 #include <fwData/String.hpp>
19 
20 #include <fwDataCamp/getObject.hpp>
21 
22 #include <fwGui/dialog/MessageDialog.hpp>
23 #include <fwGui/GuiRegistry.hpp>
24 
25 #include <fwRuntime/operations.hpp>
26 
27 #include <fwServices/macros.hpp>
28 #include <fwServices/registry/AppConfig.hpp>
29 
30 #include <fwTools/dateAndTime.hpp>
31 #include <fwTools/UUID.hpp>
32 
33 #include <boost/foreach.hpp>
34 
35 #include <QBoxLayout>
36 #include <QTabWidget>
37 #include <QtGui>
38 
39 namespace guiQt
40 {
41 namespace editor
42 {
43 
44 static const ::fwCom::Slots::SlotKeyType s_CREATE_TAB_SLOT = "createTab";
45 
46 static const ::fwCom::Signals::SignalKeyType s_ACTIVITY_SELECTED_SLOT = "activitySelected";
47 static const ::fwCom::Signals::SignalKeyType s_NOTHING_SELECTED_SLOT = "nothingSelected";
48 
49 fwServicesRegisterMacro( ::fwGui::view::IActivityView, ::guiQt::editor::SDynamicView );
50 
51 //------------------------------------------------------------------------------
52 
53 SDynamicView::SDynamicView() noexcept :
54  m_mainActivityClosable(true)
55 {
56  m_dynamicConfigStartStop = false;
57 
58  newSlot(s_CREATE_TAB_SLOT, &SDynamicView::createTab, this);
59 
60  m_sigActivitySelected = newSignal< ActivitySelectedSignalType >(s_ACTIVITY_SELECTED_SLOT);
61  m_sigNothingSelected = newSignal< NothingSelectedSignalType >(s_NOTHING_SELECTED_SLOT);
62 }
63 
64 //------------------------------------------------------------------------------
65 
67 {
68 }
69 
70 //------------------------------------------------------------------------------
71 
73 {
75 
76  typedef ::fwRuntime::ConfigurationElement::sptr ConfigType;
77 
78  ConfigType activityConfig = m_configuration->findConfigurationElement("mainActivity");
79  if (activityConfig)
80  {
81  const std::string closableStr = activityConfig->getAttributeValue("closable");
82  SLM_ASSERT("main activity 'closable' attribute value must be 'yes', 'true', 'no' or 'false'",
83  closableStr == "yes" || closableStr == "true" ||
84  closableStr == "no" || closableStr == "false");
85  const bool closable = (closableStr == "yes" || closableStr == "true");
86  m_mainActivityClosable = closable;
87  }
88 }
89 
90 //------------------------------------------------------------------------------
91 
93 {
95 
96  ::fwGuiQt::container::QtContainer::sptr parentContainer
97  = ::fwGuiQt::container::QtContainer::dynamicCast( this->getContainer() );
98 
99  m_tabWidget = new QTabWidget();
100  m_tabWidget->setTabsClosable( true );
101  m_tabWidget->setDocumentMode( true );
102  m_tabWidget->setMovable( true );
103 
104  QObject::connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTabSignal(int)));
105  QObject::connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(changedTab(int)));
106 
107  QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
108  layout->addWidget( m_tabWidget );
109 
110  parentContainer->setLayout(layout);
111 
112  m_currentWidget = 0;
113 
114  if (!m_mainActivityId.empty())
115  {
116  this->buildMainActivity();
117  }
118 }
119 
120 //------------------------------------------------------------------------------
121 
123 {
124  SLM_TRACE_FUNC();
125  while(m_tabWidget->count())
126  {
127  this->closeTab(0, true);
128  }
129  m_tabWidget->clear();
130 
131  this->destroy();
132  m_tabWidget = 0;
133 }
134 
135 //------------------------------------------------------------------------------
136 
138 {
139 }
140 
141 //------------------------------------------------------------------------------
142 
144 {
145 }
146 
147 //------------------------------------------------------------------------------
148 
149 void SDynamicView::launchActivity(::fwMedData::ActivitySeries::sptr activitySeries)
150 {
151  if (this->validateActivity(activitySeries))
152  {
153  SDynamicViewInfo viewInfo = this->createViewInfo(activitySeries);
154  viewInfo.closable = true;
155 
156  this->launchTab(viewInfo);
157  }
158 }
159 
160 //------------------------------------------------------------------------------
161 
162 void SDynamicView::createTab( ::fwActivities::registry::ActivityMsg info )
163 {
164  SDynamicViewInfo viewInfo;
165  viewInfo.title = info.getTitle();
166  viewInfo.tabID = info.getTabID();
167  viewInfo.closable = info.isClosable();
168  viewInfo.icon = info.getIconPath();
169  viewInfo.tooltip = info.getToolTip();
170  viewInfo.viewConfigID = info.getAppConfigID();
171  viewInfo.replaceMap = info.getReplaceMap();
172  viewInfo.activitySeries = info.getActivitySeries();
173 
174  this->launchTab(viewInfo);
175 }
176 
177 //------------------------------------------------------------------------------
178 
179 void SDynamicView::launchTab(SDynamicViewInfo& info)
180 {
181  static int count = 0;
182  ActivityIdType::iterator iter = std::find(m_activityIds.begin(), m_activityIds.end(), info.activitySeries->getID());
183 
184  if (iter != m_activityIds.end())
185  {
187  "The current activity is already launched. \n"
188  "It cannot be launched twice.",
189  ::fwGui::dialog::IMessageDialog::WARNING);
190  return;
191  }
192 
193  if ( m_titleToCount.find( info.title ) != m_titleToCount.end() )
194  {
195  m_titleToCount[ info.title ]++;
196  }
197  else
198  {
199  m_titleToCount[ info.title ] = 1;
200  }
201 
202  QString finalTitle = QString("%1 %2").arg( info.title.c_str(), "(%1)" ).arg( m_titleToCount[ info.title ] );
203  info.wid = QString("SDynamicView-%1").arg(count++).toStdString();
204 
205  ::fwGuiQt::container::QtContainer::sptr subContainer = ::fwGuiQt::container::QtContainer::New();
206  QWidget* widget = new QWidget(m_tabWidget);
207  subContainer->setQtContainer(widget);
208  ::fwGui::GuiRegistry::registerWIDContainer(info.wid, subContainer);
209 
210  info.replaceMap[ "WID_PARENT" ] = info.wid;
211  std::string genericUidAdaptor = ::fwServices::registry::AppConfig::getUniqueIdentifier(info.viewConfigID);
212  info.replaceMap["GENERIC_UID"] = genericUidAdaptor;
213 
214  ::fwServices::IAppConfigManager::sptr helper = ::fwServices::IAppConfigManager::New();
215 
216  try
217  {
218  helper->setConfig( info.viewConfigID, info.replaceMap );
219  if (!m_dynamicConfigStartStop)
220  {
221  helper->launch();
222  }
223  else
224  {
225  helper->create();
226  }
227  }
228  catch( std::exception& e )
229  {
230  ::fwGui::dialog::MessageDialog::showMessageDialog("Activity launch failed",
231  e.what(),
232  ::fwGui::dialog::IMessageDialog::CRITICAL);
233  OSLM_ERROR(e.what());
234  return;
235  }
236 
237  info.container = subContainer;
238  info.helper = helper;
239  m_activityIds.insert(info.activitySeries->getID());
240 
241  m_dynamicInfoMap[widget] = info;
242  m_tabIDList.insert(info.tabID);
243 
244  int index = m_tabWidget->addTab(widget, finalTitle );
245  if(!info.tooltip.empty())
246  {
247  m_tabWidget->setTabToolTip(index, QString::fromStdString(info.tooltip));
248  }
249  if(!info.icon.empty())
250  {
251  m_tabWidget->setTabIcon(index, QIcon(QString::fromStdString(info.icon)) );
252  }
253  m_tabWidget->setCurrentWidget(widget);
254 }
255 
256 //------------------------------------------------------------------------------
257 
258 void SDynamicView::info( std::ostream& _sstream )
259 {
260 }
261 
262 //------------------------------------------------------------------------------
263 
265 {
266  closeTab( index, false );
267 }
268 
269 //------------------------------------------------------------------------------
270 
271 void SDynamicView::closeTab( int index, bool forceClose )
272 {
273  QWidget* widget = m_tabWidget->widget(index);
274 
275  SLM_ASSERT("Widget is not in dynamicInfoMap", m_dynamicInfoMap.find(widget) != m_dynamicInfoMap.end());
276  SDynamicViewInfo info = m_dynamicInfoMap[widget];
277  if ( info.closable || forceClose )
278  {
279  m_tabIDList.erase(info.tabID);
280  if (!m_dynamicConfigStartStop)
281  {
282  info.helper->stopAndDestroy();
283  }
284  else
285  {
286  if (info.helper->isStarted())
287  {
288  info.helper->stop();
289  }
290  info.helper->destroy();
291  }
292  info.helper.reset();
293 
294  //Remove tab first, to avoid tab beeing removed by container->destroy
295  m_currentWidget = 0;
296  m_tabWidget->removeTab(index);
297 
299 
300  info.container->destroyContainer();
301  info.container.reset();
302  m_dynamicInfoMap.erase(widget);
303  m_activityIds.erase(info.activitySeries->getID());
304  }
305  else
306  {
308  "The tab " + info.title + " can not be closed.",
309  ::fwGui::dialog::IMessageDialog::INFO);
310  }
311 }
312 
313 //------------------------------------------------------------------------------
314 
315 void SDynamicView::changedTab( int index )
316 {
317  QWidget* widget = m_tabWidget->widget(index);
318 
319  if (m_dynamicConfigStartStop && widget != m_currentWidget)
320  {
321  if (m_currentWidget)
322  {
323  SDynamicViewInfo oldinfo = m_dynamicInfoMap[m_currentWidget];
324  oldinfo.helper->stop();
325  }
326 
327  if (widget)
328  {
329  SDynamicViewInfo newinfo = m_dynamicInfoMap[widget];
330  if (!newinfo.helper->isStarted())
331  {
332  newinfo.helper->start();
333  newinfo.helper->update();
334  }
335  }
336  }
337  m_currentWidget = widget;
338 
339  if (index >= 0)
340  {
341  SDynamicViewInfo info = m_dynamicInfoMap[widget];
342  m_sigActivitySelected->asyncEmit(info.activitySeries);
343  }
344  else
345  {
346  m_sigNothingSelected->asyncEmit();
347  }
348 }
349 
350 //------------------------------------------------------------------------------
351 
352 void SDynamicView::buildMainActivity()
353 {
354  ::fwMedData::ActivitySeries::sptr actSeries = this->createMainActivity();
355 
356  if (actSeries)
357  {
358  SDynamicViewInfo viewInfo;
359  viewInfo = this->createViewInfo(actSeries);
360  viewInfo.closable = m_mainActivityClosable;
361 
362  this->launchTab(viewInfo);
363  }
364 }
365 
366 //------------------------------------------------------------------------------
367 
368 SDynamicView::SDynamicViewInfo SDynamicView::createViewInfo(::fwMedData::ActivitySeries::sptr activitySeries)
369 {
370  ReplaceMapType replaceMap;
371  this->translateParameters(m_parameters, replaceMap);
372 
374  info = ::fwActivities::registry::Activities::getDefault()->getInfo(activitySeries->getActivityConfigId());
375 
376  std::string tabInfo;
377  if(info.tabInfo.empty())
378  {
379  tabInfo = info.title;
380  }
381  else
382  {
383  std::string newTabInfo = info.tabInfo;
384  ::boost::regex e("(!(([[:word:]]+\\.?)+[[:word:]]))");
385  ::boost::smatch what;
386  if(boost::regex_search(newTabInfo, what, e))
387  {
388  std::string submatch(what[1].first, what[1].second);
389 
390  submatch.replace(0, 1, "@");
391 
392  ::fwData::Object::sptr obj = ::fwDataCamp::getObject(activitySeries->getData(), submatch);
393  OSLM_ASSERT("Invalid seshat path : '" << submatch <<"'", obj);
394 
395  ::fwData::String::sptr stringParameter = ::fwData::String::dynamicCast(obj);
396 
397  std::string tabInfoSeshat;
398 
399  if(stringParameter)
400  {
401  tabInfoSeshat = stringParameter->getValue();
402  }
403  else
404  {
405  OSLM_WARN("Seshat path '" << submatch << "' doesn't reference an fwData::String");
406  }
407 
408  submatch.replace(0, 1, "!");
409  ::boost::algorithm::replace_all(newTabInfo, submatch, tabInfoSeshat);
410 
411  }
412  tabInfo = newTabInfo;
413  }
414 
415  this->translateParameters(activitySeries->getData(), info.appConfig.parameters, replaceMap);
416  replaceMap["AS_UID"] = activitySeries->getID();
417 
418  SDynamicViewInfo viewInfo;
419  viewInfo.title = info.title;
420  viewInfo.icon = info.icon;
421  viewInfo.tooltip = tabInfo;
422  viewInfo.viewConfigID = info.appConfig.id;
423  viewInfo.activitySeries = activitySeries;
424  viewInfo.replaceMap = replaceMap;
425 
426  return viewInfo;
427 }
428 
429 //------------------------------------------------------------------------------
430 
431 }// namespace editor
432 }// namespace guiQt
const std::string & getTitle() const
Return activity title.
Definition: ActivityMsg.hpp:49
This editor manages tabs containing activities.
virtual GUIQT_API ~SDynamicView() noexcept
Destructor. Do nothing.
virtual void stopping() override
Destroy the container.
static FWGUI_API void unregisterWIDContainer(std::string wid)
Unregisters container associate with window ID.
Definition: GuiRegistry.cpp:96
const ReplaceMapType & getReplaceMap() const
Return the map of the string association to replace in config.
Definition: ActivityMsg.hpp:91
Holds Activities configuration.
Definition: Activities.hpp:175
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
virtual void configuring() override
Configure the view.
#define SLM_TRACE_FUNC()
Trace contextual function signature.
Definition: spyLog.hpp:329
static FWGUI_API IMessageDialog::Buttons showMessageDialog(const std::string &title, const std::string &message,::fwGui::dialog::IMessageDialog::Icons icon=INFO)
static FWACTIVITIES_API Activities::sptr getDefault()
Return the default global instance of Activities.
Definition: Activities.cpp:226
virtual void starting() override
Install the container.
FWGUI_API void destroy()
Stops sub-views and toobar services. Destroys view, sub-views and toolbar containers.
std::string m_mainActivityId
configuration id of the main activity
virtual void info(std::ostream &_sstream) override
Write information in a stream.
ParametersType m_parameters
parameters given in configuration
void closeTabSignal(int index)
Called when the tab close button is clicked: close the tab if it is "closable".
virtual FWGUI_API bool validateActivity(::fwMedData::ActivitySeries::sptr activitySeries) const
Check if the activity is valid by calling the activity validator.
const std::string & getTabID() const
Return tab identifier.
Definition: ActivityMsg.hpp:55
virtual FWGUI_API::fwMedData::ActivitySeries::sptr createMainActivity() const
Create the activity series given in &#39;mainActivity&#39; configuration.
static FWGUI_API void registerWIDContainer(std::string wid,::fwGui::container::fwContainer::sptr container)
Registers container associate with window ID.
Definition: GuiRegistry.cpp:87
virtual void swapping() override
Swap.
void changedTab(int index)
Called when the current tab selection changed.
Activity information sent by signal to launch new activities in a tab.
Definition: ActivityMsg.hpp:25
const std::string & getAppConfigID() const
Return appConfig identifier.
Definition: ActivityMsg.hpp:61
#define OSLM_ERROR(message)
Definition: spyLog.hpp:274
#define OSLM_WARN(message)
Definition: spyLog.hpp:263
const std::string & getIconPath() const
Return activity icon path.
Definition: ActivityMsg.hpp:73
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
GUIQT_API SDynamicView() noexcept
Constructor. Do nothing.
::fwRuntime::ConfigurationElement::sptr m_configuration
Configuration element used to configure service internal state using a generic XML like structure TOD...
Definition: IService.hpp:670
FWGUI_API void create()
Creates view, sub-views and toolbar containers. Manages sub-views and toobar services.
bool isClosable() const
Return if the activity can be closed.
Definition: ActivityMsg.hpp:43
virtual FWGUI_API void configuring() override
Parse the configuration.
static FWSERVICES_API std::shared_ptr< IAppConfigManager > New()
const ::fwMedData::ActivitySeries::sptr & getActivitySeries() const
Return activity series.
Definition: ActivityMsg.hpp:85
Defines the base class for services displaying activity view.
static FWSERVICES_API std::string getUniqueIdentifier(const std::string &serviceUid="")
Create an unique identifier.
Definition: AppConfig.cpp:269
virtual void updating() override
Update.
const std::string & getToolTip() const
Return tooltip.
Definition: ActivityMsg.hpp:79
The namespace guiQt contains the basic services to build the application IHM with Qt...
Definition: Code.hpp:21
virtual FWGUI_API void translateParameters(::fwData::Object::sptr sourceObj, const ParametersType &parameters, ReplaceMapType &replaceMap)
Translate parameters from source object.