瀏覽代碼

Hosted app encapsulating CommandLineModules

Ivo Wolf 12 年之前
父節點
當前提交
621271eb71

+ 4 - 0
CMakeLists.txt

@@ -583,6 +583,10 @@ ctk_plugin_option(org.commontk.dah.exampleapp
                   "Build the org.commontk.dah.exampleapp plugin." OFF
                   CTK_APP_ctkExampleHostedApp)
                   
+ctk_plugin_option(org.commontk.dah.cmdlinemoduleapp
+                  "Build the org.commontk.dah.cmdlinemoduleapp plugin." OFF
+                  CTK_APP_ctkCommandLineModuleApp)
+                  
 ctk_plugin_option(org.commontk.dah.examplehost
                   "Build the org.commontk.dah.examplehost plugin." OFF
                   CTK_APP_ctkExampleHost)

+ 39 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/CMakeLists.txt

@@ -0,0 +1,39 @@
+project(org_commontk_dah_cmdlinemoduleapp)
+
+set(PLUGIN_export_directive "org_commontk_dah_cmdlinemoduleapp_EXPORT")
+
+set(PLUGIN_SRCS
+  ctkCommandLineModuleAppLogic_p.h
+  ctkCommandLineModuleAppPlugin_p.h
+  ctkCommandLineModuleAppLogic.cpp
+  ctkCommandLineModuleAppPlugin.cpp
+)
+
+# Files which should be processed by Qts moc
+set(PLUGIN_MOC_SRCS
+  ctkCommandLineModuleAppLogic_p.h
+  ctkCommandLineModuleAppPlugin_p.h
+)
+
+# Qt Designer files which should be processed by Qts uic
+set(PLUGIN_UI_FORMS
+  ctkCommandLineModuleAppWidget.ui
+)
+
+# QRC Files which should be compiled into the plugin
+set(PLUGIN_resources
+#  resources/ctkCommandLineModuleApp.qrc
+)
+
+#Compute the plugin dependencies
+ctkFunctionGetTargetLibraries(PLUGIN_target_libraries)
+
+ctkMacroBuildPlugin(
+  NAME ${PROJECT_NAME}
+  EXPORT_DIRECTIVE ${PLUGIN_export_directive}
+  SRCS ${PLUGIN_SRCS}
+  MOC_SRCS ${PLUGIN_MOC_SRCS}
+  UI_FORMS ${PLUGIN_UI_FORMS}
+  RESOURCES ${PLUGIN_resources}
+  TARGET_LIBRARIES ${PLUGIN_target_libraries}
+)

+ 330 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/ctkCommandLineModuleAppLogic.cpp

@@ -0,0 +1,330 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+// Qt includes
+#include <QtPlugin>
+#include <QRect>
+#include <QDebug>
+#include <QPushButton>
+#include <QApplication>
+#include <QLabel>
+#include <QRect>
+#include <QStringList>
+#include <QDir>
+#include <QTemporaryFile>
+#include <QPainter>
+
+// CTK includes
+#include "ctkDICOMImage.h"
+#include "ctkCommandLineModuleAppLogic_p.h"
+#include "ctkCommandLineModuleAppPlugin_p.h"
+#include "ctkDicomAvailableDataHelper.h"
+#include "ctkCmdLineModuleInstanceFactoryQtGui.h"
+#include "ctkCmdLineModuleReference.h"
+#include "ctkCmdLineModuleInstance.h"
+
+// DCMTK includes
+#include <dcmimage.h>
+
+//----------------------------------------------------------------------------
+ctkCommandLineModuleAppLogic::ctkCommandLineModuleAppLogic(const QString & modulelocation):
+ctkDicomAbstractApp(ctkCommandLineModuleAppPlugin::getPluginContext()), AppWidget(0),
+ModuleLocation(modulelocation), ModuleManager(new ctkCmdLineModuleInstanceFactoryQtGui())
+{
+  connect(this, SIGNAL(startProgress()), this, SLOT(onStartProgress()), Qt::QueuedConnection);
+  connect(this, SIGNAL(resumeProgress()), this, SLOT(onResumeProgress()), Qt::QueuedConnection);
+  connect(this, SIGNAL(suspendProgress()), this, SLOT(onSuspendProgress()), Qt::QueuedConnection);
+  connect(this, SIGNAL(cancelProgress()), this, SLOT(onCancelProgress()), Qt::QueuedConnection);
+  connect(this, SIGNAL(exitHostedApp()), this, SLOT(onExitHostedApp()), Qt::QueuedConnection);
+  connect(this, SIGNAL(dataAvailable()), this, SLOT(onDataAvailable()));
+
+  //notify Host we are ready.
+  try {
+    getHostInterface()->notifyStateChanged(ctkDicomAppHosting::IDLE);
+  }
+  catch(...)
+  {
+    qDebug() << "ctkDicomAbstractApp: Could not getHostInterface()";
+  }
+
+  ResultData = new ctkDicomAppHosting::AvailableData;
+}
+
+//----------------------------------------------------------------------------
+ctkCommandLineModuleAppLogic::~ctkCommandLineModuleAppLogic()
+{
+  ctkPluginContext* context = ctkCommandLineModuleAppPlugin::getPluginContext();
+  QList <QSharedPointer<ctkPlugin> > plugins = context->getPlugins();
+  for (int i = 0; i < plugins.size(); ++i)
+  {
+    qDebug() << plugins.at(i)->getSymbolicName ();
+  }
+
+  delete ResultData;
+}
+
+//----------------------------------------------------------------------------
+bool ctkCommandLineModuleAppLogic::bringToFront(const QRect& requestedScreenArea)
+{
+  if(this->AppWidget!=NULL)
+  {
+    this->AppWidget->move(requestedScreenArea.topLeft());
+    this->AppWidget->resize(requestedScreenArea.size());
+    this->AppWidget->activateWindow();
+    this->AppWidget->raise();
+  }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::do_something()
+{
+  AppWidget = new QWidget;
+  ui.setupUi(AppWidget);
+
+  QVBoxLayout *verticalLayout = new QVBoxLayout(ui.PlaceHolder);
+  verticalLayout->setObjectName(QString::fromUtf8("cmdlineparentverticalLayout"));
+
+  ui.CLModuleName->setText(ModuleLocation);
+
+  ctkCmdLineModuleReference moduleRef = ModuleManager.registerModule(ModuleLocation);
+  ctkCmdLineModuleInstance* moduleInstance = ModuleManager.createModuleInstance(moduleRef);
+  QObject* guiHandle = moduleInstance->guiHandle();
+  QWidget* widget = qobject_cast<QWidget*>(guiHandle);
+  widget->setParent(ui.PlaceHolder);
+  verticalLayout->addWidget(widget);
+
+  connect(ui.LoadDataButton, SIGNAL(clicked()), this, SLOT(onLoadDataClicked()));
+  connect(ui.CreateSecondaryCaptureButton, SIGNAL(clicked()), this, SLOT(onCreateSecondaryCapture()));
+  try
+    {
+    QRect preferred(50,50,100,100);
+    qDebug() << "  Asking:getAvailableScreen";
+    QRect rect = getHostInterface()->getAvailableScreen(preferred);
+    qDebug() << "  got sth:" << rect.top();
+    this->AppWidget->move(rect.topLeft());
+    this->AppWidget->resize(rect.size());
+    }
+  catch (const ctkRuntimeException& e)
+    {
+    qCritical() << e.what();
+    return;
+    }
+  this->AppWidget->show();
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::onStartProgress()
+{
+  setInternalState(ctkDicomAppHosting::INPROGRESS);
+
+  // we need to create the button before we receive data from
+  // the host, which happens immediately after calling
+  // getHostInterface()->notifyStateChanged
+  do_something(); 
+
+  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::INPROGRESS);
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::onResumeProgress()
+{
+  //reclame all resources.
+
+  //notify state changed
+  setInternalState(ctkDicomAppHosting::INPROGRESS);
+  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::INPROGRESS);
+  //we're rolling
+  //do something else normally, but this is an example
+  ui.LoadDataButton->setEnabled(true);
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::onSuspendProgress()
+{
+  //release resources it can reclame later to resume work
+  ui.LoadDataButton->setEnabled(false);
+  //notify state changed
+  setInternalState(ctkDicomAppHosting::SUSPENDED);
+  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::SUSPENDED);
+  //we're rolling
+  //do something else normally, but this is an example
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::onCancelProgress()
+{
+  //release all resources
+  onReleaseResources();
+  //update state
+  setInternalState(ctkDicomAppHosting::IDLE);
+  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::IDLE);
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::onExitHostedApp()
+{
+  //useless move, but correct:
+  setInternalState(ctkDicomAppHosting::EXIT);
+  getHostInterface()->notifyStateChanged(ctkDicomAppHosting::EXIT);
+  qDebug() << "Exiting";
+  //die
+  qApp->exit(0);
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::onReleaseResources()
+{
+  this->AppWidget->hide();
+  delete (this->AppWidget);
+  this->AppWidget = 0 ;
+}
+
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppLogic::onDataAvailable()
+{
+  QString s;
+  const ctkDicomAppHosting::AvailableData& data = getIncomingAvailableData();
+  if(this->AppWidget == 0)
+    {
+    qCritical() << "Button is null!";
+    return;
+    }
+  s = "Received notifyDataAvailable with patients.count()= " + QString().setNum(data.patients.count());
+  if(data.patients.count()>0)
+    {
+    s=s+" name:"+data.patients.begin()->name+" studies.count(): "+QString().setNum(data.patients.begin()->studies.count());
+    if(data.patients.begin()->studies.count()>0)
+    {
+      s=s+" series.count():" + QString().setNum(data.patients.begin()->studies.begin()->series.count());
+      if(data.patients.begin()->studies.begin()->series.count()>0)
+      {
+        s=s+" uid:" + data.patients.begin()->studies.begin()->series.begin()->seriesUID;
+//        QUuid uuid("93097dc1-caf9-43a3-a814-51a57f8d861d");//data.patients.begin()->studies.begin()->series.begin()->seriesUID);
+        QUuid uuid = data.patients.begin()->studies.begin()->series.begin()->objectDescriptors.begin()->descriptorUUID;
+        s=s+" uuid:"+uuid.toString();
+      }
+    }
+  }
+  ui.ReceivedDataInformation->setText(s);
+  ui.LoadDataButton->setEnabled(true);
+}
+
+
+void ctkCommandLineModuleAppLogic::onLoadDataClicked()
+{
+  const ctkDicomAppHosting::AvailableData& data = getIncomingAvailableData();
+  if(data.patients.count()==0)
+    return;
+  const ctkDicomAppHosting::Patient& firstpatient = *data.patients.begin();
+  QList<QUuid> uuidlist = ctkDicomAvailableDataHelper::getAllUuids(firstpatient);
+  
+  QString transfersyntax("1.2.840.10008.1.2.1");
+  QList<QUuid> transfersyntaxlist;
+  transfersyntaxlist.append(transfersyntax);
+  QList<ctkDicomAppHosting::ObjectLocator> locators;
+  locators = getHostInterface()->getData(uuidlist, transfersyntaxlist, false);
+  qDebug() << "got locators! " << QString().setNum(locators.count());
+
+  QString s;
+  s=s+" loc.count:"+QString().setNum(locators.count());
+  if(locators.count()>0)
+  {
+    s=s+" URI: "+locators.begin()->URI +" locatorUUID: "+locators.begin()->locator+" sourceUUID: "+locators.begin()->source;
+    qDebug() << "URI: " << locators.begin()->URI;
+    QString filename = locators.begin()->URI;
+    if(filename.startsWith("file:/",Qt::CaseInsensitive))
+      filename=filename.remove(0,8);
+    qDebug()<<filename;
+    if(QFileInfo(filename).exists())
+    {
+      try {
+        DicomImage dcmtkImage(filename.toLatin1().data());
+        ctkDICOMImage ctkImage(&dcmtkImage);
+
+        QPixmap pixmap = QPixmap::fromImage(ctkImage.frame(0),Qt::AvoidDither);
+        if (pixmap.isNull())
+        {
+          qCritical() << "Failed to convert QImage to QPixmap" ;
+        }
+        else
+        {
+          ui.PlaceHolderForImage->setPixmap(pixmap);
+        }
+      }
+      catch(...)
+      {
+        qCritical() << "Caught exception while trying to load file" << filename;
+      }
+    }
+    else
+    {
+      qCritical() << "File does not exist: " << filename;
+    }
+  }
+  ui.ReceivedDataInformation->setText(s);
+}
+
+void ctkCommandLineModuleAppLogic::onCreateSecondaryCapture()
+{
+  const QPixmap* pixmap = ui.PlaceHolderForImage->pixmap();
+  if(pixmap!=NULL)
+  {
+    QStringList preferredProtocols;
+    preferredProtocols.append("file:");
+    QString outputlocation = getHostInterface()->getOutputLocation(preferredProtocols);
+    QString templatefilename = QDir(outputlocation).absolutePath();
+    if(templatefilename.isEmpty()==false) templatefilename.append('/'); 
+    templatefilename.append("ctkdahscXXXXXX.jpg");
+    QTemporaryFile *tempfile = new QTemporaryFile(templatefilename,this->AppWidget);
+
+    if(tempfile->open())
+    {
+      QString filename = QFileInfo(tempfile->fileName()).absoluteFilePath();
+      qDebug() << "Created file: " << filename;
+      tempfile->close();
+      QPixmap tmppixmap(*pixmap);
+      QPainter painter(&tmppixmap);
+      painter.setPen(Qt::white);
+      painter.setFont(QFont("Arial", 15));
+      painter.drawText(tmppixmap.rect(),Qt::AlignBottom|Qt::AlignLeft,"Secondary capture by ctkCommandLineModuleApp");
+     //painter.drawText(rect(), Qt::AlignCenter, "Qt");
+      tmppixmap.save(tempfile->fileName(), "JPEG");
+      qDebug() << "Created Uuid: " << getHostInterface()->generateUID();
+
+      ctkDicomAvailableDataHelper::addToAvailableData(*ResultData, 
+        objectLocatorCache(), 
+        tempfile->fileName());
+
+      bool success = publishData(*ResultData, true);
+      if(!success)
+      {
+        qCritical() << "Failed to publish data";
+      }
+      qDebug() << "  publishData returned: " << success;
+
+    }
+    else
+      qDebug() << "Creating temporary file failed.";
+  }
+
+}

+ 91 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/ctkCommandLineModuleAppLogic_p.h

@@ -0,0 +1,91 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKCOMMANDLINEMODULEAPPLOGIC_P_H
+#define CTKCOMMANDLINEMODULEAPPLOGIC_P_H
+
+// Qt includes
+#include <QUuid>
+
+// CTK includes
+#include <ctkDicomAbstractApp.h>
+#include <ctkDicomHostInterface.h>
+#include <ctkCmdLineModuleManager.h>
+
+#include <ctkServiceTracker.h>
+
+// ui of this application
+#include "ui_ctkCommandLineModuleAppWidget.h"
+
+struct ctkDicomHostInterface;
+
+class QWidget;
+
+class ctkCommandLineModuleAppLogic : public ctkDicomAbstractApp
+{
+  Q_OBJECT
+  Q_INTERFACES(ctkDicomAppInterface)
+
+public:
+
+  ctkCommandLineModuleAppLogic(const QString & modulelocation);
+  virtual ~ctkCommandLineModuleAppLogic();
+
+  // ctkDicomAppInterface
+
+  /**
+   * Method triggered by the host. By calling this method, the Hosting System is asking the Hosted Application to take whatever steps are
+   * needed to make its GUI visible as the topmost window, and to gain focus.
+   * \return TRUE if the Hosted Application received the request and will act on it. Otherwise it returns FALSE
+   */
+  virtual bool bringToFront(const QRect& requestedScreenArea);
+
+  // some logic
+  /** Test function for checking */
+  void do_something();
+
+
+protected Q_SLOTS:
+
+  void onStartProgress();
+  void onResumeProgress();
+  void onSuspendProgress();
+  void onCancelProgress();
+  void onExitHostedApp();
+  void onReleaseResources();
+
+  void onLoadDataClicked();
+  void onCreateSecondaryCapture();
+
+  void onDataAvailable();
+private:
+  QWidget * AppWidget;
+  Ui::ctkCommandLineModuleAppWidget ui;
+
+  QString ModuleLocation;
+
+  ctkCmdLineModuleManager ModuleManager;
+
+  ctkDicomAppHosting::AvailableData* ResultData;
+}; // ctkCommandLineModuleAppLogic
+
+#endif // CTKCOMMANDLINEMODULEAPPLOGIC_P_H

+ 98 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/ctkCommandLineModuleAppPlugin.cpp

@@ -0,0 +1,98 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+// Qt includes
+#include <QtPlugin>
+#include <QStringList>
+#include <QString>
+
+// CTK includes
+#include "ctkCommandLineModuleAppPlugin_p.h"
+#include "ctkCommandLineModuleAppLogic_p.h"
+#include <ctkCommandLineParser.h>
+
+ctkPluginContext* ctkCommandLineModuleAppPlugin::Context = 0;
+
+//----------------------------------------------------------------------------
+ctkCommandLineModuleAppPlugin::ctkCommandLineModuleAppPlugin()
+  : AppLogic(0)
+{
+}
+
+//----------------------------------------------------------------------------
+ctkCommandLineModuleAppPlugin::~ctkCommandLineModuleAppPlugin()
+{
+  qDebug()<< "delete applogic";
+  delete this->AppLogic;
+  this->AppLogic = 0;
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppPlugin::start(ctkPluginContext* context)
+{
+  ctkCommandLineModuleAppPlugin::Context = context;
+
+  delete this->AppLogic;
+
+  ctkCommandLineParser cmdLineParser;
+  cmdLineParser.setArgumentPrefix("--", "-");
+  cmdLineParser.setStrictModeEnabled(true);
+
+  cmdLineParser.addArgument("module", "", QVariant::String, "Path to a CLI module (executable)", "CLIModuleBlur2dImage");
+
+  QString argsstring("pluginname ");
+  argsstring.append(context->getProperty("dah.args").toString());
+  
+  QStringList argslist = argsstring.split(" ");
+
+  bool parseOkay = false;
+  QHash<QString, QVariant> args = cmdLineParser.parseArguments(argslist, &parseOkay);
+
+  bool canStart = true;
+  if(!args.contains("module"))
+  {
+    qDebug() << "ctkCommandLineModuleAppPlugin: The plugin framework does not contain a valid \"dah.args\" property that specifies a CLModule as \"--module <modulename>\".";
+    canStart = false;
+  }
+
+  if(canStart)
+  {
+    this->AppLogic = new ctkCommandLineModuleAppLogic(args["module"].toString());
+    context->registerService<ctkDicomAppInterface>(this->AppLogic);
+  }
+}
+
+//----------------------------------------------------------------------------
+void ctkCommandLineModuleAppPlugin::stop(ctkPluginContext* context)
+{
+  Q_UNUSED(context)
+  ctkCommandLineModuleAppPlugin::Context = 0;
+}
+
+//----------------------------------------------------------------------------
+ctkPluginContext* ctkCommandLineModuleAppPlugin::getPluginContext()
+{
+  return ctkCommandLineModuleAppPlugin::Context;
+}
+
+Q_EXPORT_PLUGIN2(org_commontk_dah_cmdlinemoduleapp, ctkCommandLineModuleAppPlugin)
+
+

+ 54 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/ctkCommandLineModuleAppPlugin_p.h

@@ -0,0 +1,54 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=============================================================================*/
+
+
+#ifndef CTKCOMMANDLINEMODULEAPPPLUGIN_P_H
+#define CTKCOMMANDLINEMODULEAPPPLUGIN_P_H
+
+#include <ctkPluginActivator.h>
+
+class ctkCommandLineModuleAppLogic;
+
+class ctkCommandLineModuleAppPlugin :
+  public QObject, public ctkPluginActivator
+{
+  Q_OBJECT
+  Q_INTERFACES(ctkPluginActivator)
+
+public:
+
+  ctkCommandLineModuleAppPlugin();
+  virtual ~ctkCommandLineModuleAppPlugin();
+
+  virtual void start(ctkPluginContext* context);
+  virtual void stop(ctkPluginContext* context);
+
+  static ctkPluginContext* getPluginContext();
+
+private:
+
+  static ctkPluginContext* Context;
+
+  QObject* AppLogic;
+
+}; // ctkCommandLineModuleAppPlugin
+
+#endif // CTKCOMMANDLINEMODULEAPPPLUGIN_P_H

+ 84 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/ctkCommandLineModuleAppWidget.ui

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ctkCommandLineModuleAppWidget</class>
+ <widget class="QWidget" name="ctkCommandLineModuleAppWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>322</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>DICOM Part 19 Hosted App</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="CLModuleName">
+     <property name="text">
+      <string>CLModule not set.</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="LoadDataButton">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="text">
+      <string>Run!</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="ReceivedDataInformation">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>No data received</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="PlaceHolder" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>2</verstretch>
+      </sizepolicy>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="PlaceHolderForImage">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>1</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="CreateSecondaryCaptureButton">
+     <property name="text">
+      <string>Create Secondary Capture</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 2 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/manifest_headers.cmake

@@ -0,0 +1,2 @@
+set(Require-Plugin org.commontk.dah.hostedapp)
+set(Plugin-ActivationPolicy "eager")

+ 11 - 0
Plugins/org.commontk.dah.cmdlinemoduleapp/target_libraries.cmake

@@ -0,0 +1,11 @@
+#
+# See CMake/ctkMacroGetTargetLibraries.cmake
+# 
+# This file should list the libraries required to build the current CTK libraries
+# 
+
+set(target_libraries
+  CTKDICOMCore
+  CTKDICOMWidgets
+  CTKCommandLineModulesQtGui
+  )