ctkPluginGenerator.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkPluginGenerator_p.h"
  16. #include "ui_ctkPluginGeneratorMainWindow.h"
  17. #include <ctkPluginFramework.h>
  18. #include <ctkPluginContext.h>
  19. #include <ctkServiceReference.h>
  20. #include <ctkPluginConstants.h>
  21. #include <ctkPluginGeneratorCodeModel.h>
  22. #include <ctkPluginGeneratorConstants.h>
  23. #include <ctkPluginGeneratorOptionsDialog_p.h>
  24. #include <QDebug>
  25. #include <QListWidgetItem>
  26. #include <QDir>
  27. #include <QFileSystemModel>
  28. #include <QTime>
  29. #include <QMessageBox>
  30. #include <QSettings>
  31. #include <stdexcept>
  32. class ctkTemporaryDir
  33. {
  34. public:
  35. static QString create(const QString& path = QString())
  36. {
  37. QString tmpPath = path;
  38. if (tmpPath.isEmpty())
  39. {
  40. tmpPath = "ctkplugingenerator";
  41. }
  42. tmpPath += "." + QTime::currentTime().toString("hhmmsszzz");
  43. QDir tmp = QDir::temp();
  44. if (!tmp.mkdir(tmpPath))
  45. {
  46. QString msg = QString("Creating temporary directory ") + tmpPath + " in "
  47. + QDir::temp().canonicalPath() + " failed.";
  48. throw std::runtime_error(msg.toStdString());
  49. }
  50. tmp.cd(tmpPath);
  51. return tmp.canonicalPath();
  52. }
  53. static bool removeDir(const QString& dirName)
  54. {
  55. bool result = true;
  56. QDir dir(dirName);
  57. if (dir.exists(dirName))
  58. {
  59. foreach (QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst))
  60. {
  61. if (info.isDir()) {
  62. result = removeDir(info.absoluteFilePath());
  63. }
  64. else {
  65. result = QFile::remove(info.absoluteFilePath());
  66. }
  67. if (!result) {
  68. return result;
  69. }
  70. }
  71. result = dir.rmdir(dirName);
  72. }
  73. return result;
  74. }
  75. };
  76. ctkPluginGenerator::ctkPluginGenerator(ctkPluginFramework* framework, QWidget *parent) :
  77. QMainWindow(parent),
  78. framework(framework), ui(new Ui::ctkPluginGeneratorMainWindow),
  79. mode(EDIT), previewModel(0)
  80. {
  81. ui->setupUi(this);
  82. previewModel = new QFileSystemModel(this);
  83. ui->previewTreeView->setModel(previewModel);
  84. ui->previewTreeView->hideColumn(1);
  85. ui->previewTreeView->hideColumn(2);
  86. ui->previewTreeView->hideColumn(3);
  87. this->setStatusBar(0);
  88. connect(ui->actionOptions, SIGNAL(triggered(bool)), this, SLOT(menuOptionsTriggered()));
  89. connect(ui->generateButton, SIGNAL(clicked()), this, SLOT(generateClicked()));
  90. connect(ui->previewButton, SIGNAL(clicked()), this, SLOT(previewClicked()));
  91. connect(ui->cancelButton, SIGNAL(clicked()), qApp, SLOT(quit()));
  92. connect(ui->uiExtensionList, SIGNAL(itemClicked(QListWidgetItem*)),
  93. this, SLOT(extensionItemClicked(QListWidgetItem*)));
  94. connect(ui->previewTreeView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(previewIndexChanged(QModelIndex)));
  95. QList<ctkServiceReference> serviceRefs = framework->getPluginContext()->
  96. getServiceReferences("ctkPluginGeneratorAbstractUiExtension");
  97. QListIterator<ctkServiceReference> it(serviceRefs);
  98. while (it.hasNext())
  99. {
  100. ctkServiceReference serviceRef = it.next();
  101. ctkPluginGeneratorAbstractUiExtension* extension =
  102. qobject_cast<ctkPluginGeneratorAbstractUiExtension*>(framework->getPluginContext()->getService(serviceRef));
  103. qDebug() << "Service reference found";
  104. if (extension)
  105. {
  106. qDebug() << "inserted";
  107. int ranking = serviceRef.getProperty(ctkPluginConstants::SERVICE_RANKING).toInt();
  108. if (ranking > 0)
  109. {
  110. uiExtensionMap.insert(ranking, extension);
  111. }
  112. else
  113. {
  114. uiExtensionMap.insert(-1, extension);
  115. }
  116. }
  117. }
  118. int id = 0;
  119. foreach (ctkPluginGeneratorAbstractUiExtension* extension, uiExtensionMap)
  120. {
  121. idToExtensionMap.insert(id, extension);
  122. ui->extensionStack->addWidget(extension->getWidget());
  123. connect(extension, SIGNAL(errorMessageChanged(QString)), this, SLOT(errorMessageChanged(QString)));
  124. extension->validate();
  125. (new QListWidgetItem(extension->getTitle(), ui->uiExtensionList))->setData(Qt::UserRole, id);
  126. ++id;
  127. }
  128. ui->uiExtensionList->setCurrentRow(0);
  129. extensionClicked(idToExtensionMap[0]);
  130. }
  131. ctkPluginGenerator::~ctkPluginGenerator()
  132. {
  133. delete ui;
  134. if (!previewDir.isEmpty())
  135. {
  136. ctkTemporaryDir::removeDir(previewDir);
  137. }
  138. }
  139. void ctkPluginGenerator::menuOptionsTriggered()
  140. {
  141. ctkPluginGeneratorOptionsDialog optionsDialog;
  142. int result = optionsDialog.exec();
  143. if (result == QDialog::Accepted && mode == PREVIEW)
  144. {
  145. QString selPath;
  146. QString oldPreviewDir = previewDir;
  147. if (!ui->previewTreeView->selectionModel()->selection().isEmpty())
  148. {
  149. QModelIndex index = ui->previewTreeView->selectionModel()->selectedIndexes().front();
  150. selPath = previewModel->data(index, QFileSystemModel::FilePathRole).toString();
  151. }
  152. if (createPreview())
  153. {
  154. ui->modeStack->setCurrentWidget(ui->previewPage);
  155. ui->previewButton->setText(tr("<< Back"));
  156. ui->previewTreeView->expandAll();
  157. if (!selPath.isEmpty())
  158. {
  159. selPath.replace(oldPreviewDir, previewDir);
  160. QModelIndex index = previewModel->index(selPath);
  161. ui->previewTreeView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
  162. previewIndexChanged(index);
  163. }
  164. }
  165. }
  166. }
  167. void ctkPluginGenerator::previewClicked()
  168. {
  169. if (mode == EDIT)
  170. {
  171. if (createPreview())
  172. {
  173. ui->modeStack->setCurrentWidget(ui->previewPage);
  174. ui->previewButton->setText(tr("<< Back"));
  175. ui->previewTreeView->expandAll();
  176. if (!ui->previewTreeView->selectionModel()->selection().isEmpty())
  177. {
  178. previewIndexChanged(ui->previewTreeView->selectionModel()->selectedIndexes().front());
  179. }
  180. mode = PREVIEW;
  181. }
  182. }
  183. else
  184. {
  185. ui->modeStack->setCurrentWidget(ui->editPage);
  186. ui->previewButton->setText(tr("Preview >>"));
  187. mode = EDIT;
  188. ctkTemporaryDir::removeDir(previewDir);
  189. previewDir.clear();
  190. }
  191. }
  192. void ctkPluginGenerator::generateClicked()
  193. {
  194. try
  195. {
  196. createPlugin(ui->outputDirButton->directory());
  197. QMessageBox msgBox;
  198. msgBox.setText(tr("Successfully create plugin"));
  199. msgBox.setStandardButtons(QMessageBox::Ok);
  200. msgBox.setIcon(QMessageBox::Information);
  201. msgBox.exec();
  202. }
  203. catch (const std::runtime_error& error)
  204. {
  205. QMessageBox msgBox;
  206. msgBox.setText(tr("Creating the plugin failed."));
  207. msgBox.setInformativeText(QString::fromLatin1(error.what()));
  208. msgBox.setStandardButtons(QMessageBox::Ok);
  209. msgBox.setIcon(QMessageBox::Critical);
  210. msgBox.exec();
  211. }
  212. }
  213. QString ctkPluginGenerator::createPlugin(const QString& path)
  214. {
  215. ctkServiceReference codeModelRef = framework->getPluginContext()->
  216. getServiceReference("ctkPluginGeneratorCodeModel");
  217. ctkPluginGeneratorCodeModel* codeModel =
  218. qobject_cast<ctkPluginGeneratorCodeModel*>(framework->getPluginContext()->getService(codeModelRef));
  219. codeModel->reset();
  220. // set global code model info from QSettings object
  221. QSettings settings;
  222. codeModel->setLicense(settings.value(ctkPluginGeneratorConstants::PLUGIN_LICENSE_MARKER).toString());
  223. foreach(ctkPluginGeneratorAbstractUiExtension* extension, idToExtensionMap)
  224. {
  225. extension->updateCodeModel();
  226. }
  227. QString pluginDir = path + "/" + codeModel->getSymbolicName(true);
  228. if (!QDir(path).mkdir(codeModel->getSymbolicName(true)))
  229. {
  230. QString msg(tr("Creating directory \"%1\" failed.").arg(pluginDir));
  231. throw std::runtime_error(msg.toStdString());
  232. }
  233. codeModel->create(pluginDir);
  234. return pluginDir;
  235. }
  236. void ctkPluginGenerator::previewIndexChanged(const QModelIndex& index)
  237. {
  238. QString filePath = previewModel->data(index, QFileSystemModel::FilePathRole).toString();
  239. ui->previewTextLabel->setText(QDir(QString(filePath).replace(previewDir, ui->outputDirButton->directory())).absolutePath());
  240. QFile file(filePath);
  241. file.open(QFile::ReadOnly);
  242. QTextStream textStream(&file);
  243. ui->previewTextEdit->setText(textStream.readAll());
  244. }
  245. bool ctkPluginGenerator::createPreview()
  246. {
  247. try
  248. {
  249. previewDir = ctkTemporaryDir::create();
  250. QString tmpPluginDir = createPlugin(previewDir);
  251. previewModel->setRootPath(tmpPluginDir);
  252. ui->previewTreeView->setRootIndex(previewModel->index(previewDir));
  253. }
  254. catch (const std::runtime_error& error)
  255. {
  256. QMessageBox msgBox;
  257. msgBox.setText(tr("Creating the preview failed."));
  258. msgBox.setInformativeText(QString::fromLatin1(error.what()));
  259. msgBox.setStandardButtons(QMessageBox::Ok);
  260. msgBox.setIcon(QMessageBox::Critical);
  261. msgBox.exec();
  262. return false;
  263. }
  264. return true;
  265. }
  266. void ctkPluginGenerator::extensionItemClicked(QListWidgetItem* item)
  267. {
  268. ctkPluginGeneratorAbstractUiExtension* extension = idToExtensionMap[item->data(Qt::UserRole).toInt()];
  269. extensionClicked(extension);
  270. }
  271. void ctkPluginGenerator::extensionClicked(ctkPluginGeneratorAbstractUiExtension* extension)
  272. {
  273. ui->extensionStack->setCurrentWidget(extension->getWidget());
  274. ui->extensionMsgLabel->setText(extension->getTitle());
  275. this->errorMessageChanged(extension->getErrorMessage());
  276. }
  277. void ctkPluginGenerator::errorMessageChanged(const QString& errMsg)
  278. {
  279. ui->extensionErrMsgLabel->setText(errMsg);
  280. bool enableButtons = false;
  281. if (errMsg.isEmpty())
  282. {
  283. enableButtons = true;
  284. }
  285. ui->previewButton->setEnabled(enableButtons);
  286. ui->generateButton->setEnabled(enableButtons);
  287. }