NorMIT-nav  16.5
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxPluginBrowser.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 // Based on a class from CTK:
34 
35 /*=============================================================================
36 
37  Library: CTK
38 
39  Copyright (c) German Cancer Research Center,
40  Division of Medical and Biological Informatics
41 
42  Licensed under the Apache License, Version 2.0 (the "License");
43  you may not use this file except in compliance with the License.
44  You may obtain a copy of the License at
45 
46  http://www.apache.org/licenses/LICENSE-2.0
47 
48  Unless required by applicable law or agreed to in writing, software
49  distributed under the License is distributed on an "AS IS" BASIS,
50  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
51  See the License for the specific language governing permissions and
52  limitations under the License.
53 
54 =============================================================================*/
55 
56 #include "cxPluginBrowser.h"
57 #include <QtWidgets>
58 
59 #include "cxPluginTableModel.h"
60 #include "ctkServiceReference.h"
61 #include "ctkServiceException.h"
62 #include "ctkPluginConstants.h"
63 
64 #include <ctkConfig.h>
65 #include <ctkPluginException.h>
66 #include <ctkPluginFramework.h>
67 #include <ctkPluginContext.h>
68 #include <iostream>
69 
70 #include <QApplication>
71 #include <QMainWindow>
72 #include <QStringList>
73 #include <QDirIterator>
74 #include <QUrl>
75 #include <QSettings>
76 #include <QCloseEvent>
77 #include "cxSettings.h"
78 
79 //#define SETTINGS_WND_GEOM "mainwindow.geom"
80 //#define SETTINGS_WND_STATE "mainwindow.state"
81 
82 namespace cx
83 {
84 
86 : framework(framework)
87 {
88  mSettingsMainWindowStateTag = "pluginbrowser/state";
89  mSettingsMainWindowGeometryTag = "pluginbrowser/geometry";
90 
91  pluginEventTypeToString[ctkPluginEvent::INSTALLED] = "Installed";
92  pluginEventTypeToString[ctkPluginEvent::LAZY_ACTIVATION] = "Lazy Activation";
93  pluginEventTypeToString[ctkPluginEvent::RESOLVED] = "Resolved";
94  pluginEventTypeToString[ctkPluginEvent::STARTED] = "Started";
95  pluginEventTypeToString[ctkPluginEvent::STARTING] = "Starting";
96  pluginEventTypeToString[ctkPluginEvent::STOPPED] = "Stopped";
97  pluginEventTypeToString[ctkPluginEvent::STOPPING] = "Stopping";
98  pluginEventTypeToString[ctkPluginEvent::UNINSTALLED] = "Uninstalled";
99  pluginEventTypeToString[ctkPluginEvent::UNRESOLVED] = "Unresolved";
100  pluginEventTypeToString[ctkPluginEvent::UPDATED] = "Updated";
101 
102 // qDebug() << "ctkPluginBrowser::ctkPluginBrowser 1";
103 // qDebug() << "ctkPluginBrowser::ctkPluginBrowser fw is null: " << (framework.get() == NULL);
104 // qDebug() << "ctkPluginBrowser::ctkPluginBrowser" << framework->getPluginContext();
105  framework->getPluginContext()->connectFrameworkListener(this, SLOT(frameworkEvent(ctkPluginFrameworkEvent)));
106  framework->getPluginContext()->connectPluginListener(this, SLOT(pluginEvent(ctkPluginEvent)));
107  framework->getPluginContext()->connectServiceListener(this, "serviceEvent");
108 // qDebug() << "ctkPluginBrowser::ctkPluginBrowser 2";
109 
110  this->setupUi();
111 
112  mPluginTableModel = new ctkPluginTableModel(framework, this);
113  pluginsTableView->setModel(mPluginTableModel);
114 
115  connect(pluginsTableView->selectionModel(),
116  &QItemSelectionModel::currentChanged,
117  this,
118  &ctkPluginBrowser::pluginSelected);
119 
120  startPluginNowAction = new QAction(QIcon(":/icons/open_icon_library/arrow-right-double-3.png"), "Start Plugin (ignore activation policy)", this);
121  startPluginAction = new QAction(QIcon(":/icons/open_icon_library/arrow-right-3.png"), "Start Plugin", this);
122  stopPluginAction = new QAction(QIcon(":/icons/open_icon_library/media-record-3.png"), "Stop Plugin", this);
123  toggleInstallPluginAction = new QAction(QIcon(":/icons/preset_reset.png"), "Toggle Install", this);
124 
125  connect(startPluginNowAction, SIGNAL(triggered()), this, SLOT(startPluginNow()));
126  connect(startPluginAction, SIGNAL(triggered()), this, SLOT(startPlugin()));
127  connect(stopPluginAction, SIGNAL(triggered()), this, SLOT(stopPlugin()));
128  connect(toggleInstallPluginAction, SIGNAL(triggered()), this, SLOT(toggleInstallPlugin()));
129 
130  startPluginNowAction->setEnabled(false);
131  startPluginAction->setEnabled(false);
132  stopPluginAction->setEnabled(false);
133 
134  pluginToolBar->addAction(startPluginNowAction);
135  pluginToolBar->addAction(startPluginAction);
136  pluginToolBar->addAction(stopPluginAction);
137  pluginToolBar->addAction(toggleInstallPluginAction);
138 
139  if(settings()->contains(mSettingsMainWindowGeometryTag))
140  {
141  this->restoreGeometry(settings()->value(mSettingsMainWindowGeometryTag).toByteArray());
142  }
143  if (settings()->contains(mSettingsMainWindowStateTag))
144  {
145  this->restoreState(settings()->value(mSettingsMainWindowStateTag).toByteArray());
146  }
147 
148  QTimer::singleShot(0, this, SLOT(resizePluginsTableView()));
149 }
150 
152 {
153  settings()->setValue(mSettingsMainWindowGeometryTag, this->saveGeometry());
154  settings()->setValue(mSettingsMainWindowStateTag, this->saveState());
155 }
156 
157 void ctkPluginBrowser::resizePluginsTableView()
158 {
159  pluginsTableView->resizeColumnToContents(0);
160 }
161 
162 void ctkPluginBrowser::setupUi()
163 {
164  pluginsTableView = new QTableView(this);
165  pluginsTableView->setObjectName(QString::fromUtf8("pluginsTableView"));
166  pluginsTableView->setWindowTitle("Plugins");
167  pluginsTableView->setAutoScroll(false);
168  pluginsTableView->setSelectionMode(QAbstractItemView::SingleSelection);
169  pluginsTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
170  pluginsTableView->setShowGrid(false);
171  pluginsTableView->setSortingEnabled(true);
172  pluginsTableView->horizontalHeader()->setCascadingSectionResizes(true);
173  pluginsTableView->horizontalHeader()->setHighlightSections(false);
174  pluginsTableView->horizontalHeader()->setProperty("showSortIndicator", QVariant(true));
175  pluginsTableView->horizontalHeader()->setStretchLastSection(true);
176  pluginsTableView->verticalHeader()->setVisible(false);
177 
178  this->wrapInDockWidget(pluginsTableView);
179 
180  pluginToolBar = new QToolBar(this);
181  pluginToolBar->setObjectName(QString::fromUtf8("pluginToolBar"));
182  this->addToolBar(Qt::TopToolBarArea, pluginToolBar);
183 
184  searchPathSelectWidget = new cx::MultiFileInputWidget(this);
185  searchPathSelectWidget->setDescription("Search Paths");
186  searchPathSelectWidget->setWindowTitle("Search Paths");
187 
188  searchPathSelectWidget->setHelp("Select where to look for plugins");
189  searchPathSelectWidget->setBrowseHelp("Browse for a search path");
190  searchPathSelectWidget->setUseRelativePath(true);
191  searchPathSelectWidget->setBasePath(qApp->applicationDirPath());
192 
193  searchPathSelectWidget->setFilenames(framework->getSearchPaths());
194  connect(searchPathSelectWidget, SIGNAL(fileChanged()), this, SLOT(searchPathChanged()));
195 
196  this->wrapInDockWidget(searchPathSelectWidget);
197 
198  mPluginInfoWidget = new QTextEdit(this);
199  mPluginInfoWidget->setObjectName("PluginInfoWidget");
200  mPluginInfoWidget->setWindowTitle("Plugin Info");
201  this->wrapInDockWidget(mPluginInfoWidget);
202 
203 }
204 
205 void ctkPluginBrowser::wrapInDockWidget(QWidget* widget)
206 {
207  QDockWidget* dockWidget = new QDockWidget(widget->windowTitle(), this);
208  dockWidget->setObjectName(widget->objectName()+"_dockwidget");
209  dockWidget->setFeatures(QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable);
210  dockWidget->setWidget(widget);
211  this->addDockWidget(static_cast<Qt::DockWidgetArea>(1), dockWidget);
212 }
213 
214 void ctkPluginBrowser::searchPathChanged()
215 {
216  QStringList files = searchPathSelectWidget->getAbsoluteFilenames();
217  QStringList validFiles;
218  for (int i=0; i<files.size(); ++i)
219  if (QFileInfo(files[i]).exists())
220  validFiles << files[i];
221 
222  framework->setSearchPaths(validFiles);
223 }
224 
225 void ctkPluginBrowser::pluginSelected(const QModelIndex &index)
226 {
227  this->updatePluginToolbar();
228  this->updatePluginInfo();
229 }
230 
231 void ctkPluginBrowser::updatePluginToolbar()
232 {
233  startPluginNowAction->setEnabled(false);
234  startPluginAction->setEnabled(false);
235  stopPluginAction->setEnabled(false);
236 
237  PluginData plugin = this->getSelectedPlugin();
238 
239  if (!plugin.second)
240  {
241  toggleInstallPluginAction->setText("Install");
242  return;
243  }
244  toggleInstallPluginAction->setText("Uninstall");
245 
246  const ctkPlugin::States startStates = ctkPlugin::INSTALLED | ctkPlugin::RESOLVED | ctkPlugin::STOPPING;
247  const ctkPlugin::States stopStates = ctkPlugin::STARTING | ctkPlugin::ACTIVE;
248  if (startStates.testFlag(plugin.second->getState()))
249  {
250  startPluginNowAction->setEnabled(true);
251  startPluginAction->setEnabled(true);
252  }
253 
254  if (stopStates.testFlag(plugin.second->getState()))
255  {
256  stopPluginAction->setEnabled(true);
257  }
258 }
259 
260 void ctkPluginBrowser::updatePluginInfo()
261 {
262  PluginData plugin = this->getSelectedPlugin();
263 
264  QString text;
265 
266  if (plugin.second)
267  {
268  QString manifest("/META-INF/MANIFEST.MF");
269  text += QString("%1").arg(manifest);
270  text += QString("<hr>");
271  QByteArray mfContent = plugin.second->getResource(manifest);
272  QString rawText("<div style=\"white-space: pre-wrap;\">%1</div>");
273  text += rawText.arg(QString(mfContent));
274  text += QString("<hr>");
275  text += QString("<p><b>Location:</b> %1</p>").arg(plugin.second->getLocation());
276  }
277 
278  if (!plugin.second.isNull() && plugin.second->getPluginContext())
279  {
280  QStringList serviceTexts;
281  QList<ctkServiceReference> serviceRefs = plugin.second->getPluginContext()->getServiceReferences("");
282  QListIterator<ctkServiceReference> it(serviceRefs);
283  while (it.hasNext())
284  {
285  ctkServiceReference ref(it.next());
286 
287  if (ref.getPlugin()->getSymbolicName() != plugin.first)
288  continue;
289 
290  serviceTexts += QString("<tr><td><b>Service</td></tr>");
291  QStringList propKeys = ref.getPropertyKeys();
292  for (int i=0; i<propKeys.size(); ++i)
293  {
294  QString val = ref.getProperty(propKeys[i]).toString();
295  QString bblue("<b><font color=\"blue\">%1</font></b>");
296  QString green("<b><font color=\"green\">%1</font></b>");
297  QString formattedKey = green.arg(propKeys[i]);
298  QString formattedVal = bblue.arg(val);
299  serviceTexts += QString("<tr> <td></td> <td>%1</td> <td>%2</td> </tr>").arg(formattedKey).arg(formattedVal);
300  }
301  }
302 
303  text += QString("<table>%1</table>").arg(serviceTexts.join("\n"));
304  }
305  else
306  {
307  text += QString("<p>Service info not available</p>");
308  }
309 
310  mPluginInfoWidget->setHtml(text);
311 }
312 
313 void ctkPluginBrowser::frameworkEvent(const ctkPluginFrameworkEvent& event)
314 {
315  qDebug() << "FrameworkEvent: [" << event.getPlugin()->getSymbolicName() << "]" << event.getErrorString();
316 }
317 
318 void ctkPluginBrowser::pluginEvent(const ctkPluginEvent& event)
319 {
320  qDebug() << "PluginEvent: [" << event.getPlugin()->getSymbolicName() << "]" << pluginEventTypeToString[event.getType()];
321 
322  updatePluginToolbar();
323 }
324 
325 void ctkPluginBrowser::serviceEvent(const ctkServiceEvent &event)
326 {
327  ctkServiceReference ref = event.getServiceReference();
328  qDebug() << "ServiceEvent: [" << event.getType() << "]" << event.getServiceReference().getUsingPlugins();
329  qDebug() << " keys: " << ref.getPropertyKeys();
330  qDebug() << " objectclass: " << ref.getProperty("objectclass");
331 }
332 
333 PluginData ctkPluginBrowser::getSelectedPlugin()
334 {
335  QModelIndex selection = pluginsTableView->selectionModel()->currentIndex();
336  QVariant v = selection.data(Qt::UserRole);
337  QString name = v.toString();
338  ctkPluginPtr plugin = framework->getInstalledPluginFromSymbolicName(name);
339  return std::make_pair(name, plugin);
340 }
341 
342 void ctkPluginBrowser::toggleInstallPlugin()
343 {
344  PluginData plugin = this->getSelectedPlugin();
345  if (plugin.second)
346  {
347  framework->uninstall(plugin.first);
348  }
349  else
350  {
351  framework->install(plugin.first);
352  }
353 }
354 
355 void ctkPluginBrowser::startPlugin()
356 {
357  startPlugin(ctkPlugin::START_TRANSIENT | ctkPlugin::START_ACTIVATION_POLICY);
358 }
359 
360 void ctkPluginBrowser::startPluginNow()
361 {
362  startPlugin(ctkPlugin::START_TRANSIENT);
363 }
364 
365 void ctkPluginBrowser::startPlugin(ctkPlugin::StartOptions options)
366 {
367  PluginData plugin = this->getSelectedPlugin();
368  framework->start(plugin.first, options);
369 }
370 
371 void ctkPluginBrowser::stopPlugin()
372 {
373  PluginData plugin = this->getSelectedPlugin();
374  framework->stop(plugin.first);
375 }
376 
377 }
QSharedPointer< ctkPlugin > ctkPluginPtr
QStringList getAbsoluteFilenames() const
void setValue(const QString &key, const QVariant &value)
Definition: cxSettings.cpp:79
std::pair< QString, ctkPluginPtr > PluginData
ctkPluginBrowser(PluginFrameworkManagerPtr framework)
Settings * settings()
Shortcut for accessing the settings instance.
Definition: cxSettings.cpp:42
boost::shared_ptr< class PluginFrameworkManager > PluginFrameworkManagerPtr
void setFilenames(QStringList text)