Typica is a free program for professional coffee roasters. https://typica.us
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

plugins.w 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. @** Simple Plugins.
  2. \noindent The original motivation for this feature is to provide a simple way
  3. to allow importing data from other data logging applications. The problem is
  4. that there are huge differences in the data formats exported by different
  5. applications, sometimes there are differences that depend on how the other
  6. application was configured which cannot be reliably determined in an automated
  7. fashion, and if a substantial number of import plugins were created, any given
  8. person using Typica would be unlikely to ever use most of them.
  9. Based on these concerns, I wanted something that would make it easy to create
  10. new import plugins without the need to create a new build of Typica every time,
  11. I wanted it to be relatively easy for people to modify example import plugins
  12. to suit the data they wanted to import, and I wanted it to be easy for people
  13. to hide plugins that they were not required.
  14. This is handled in a way similar to reports. A new directory is provided with
  15. the \pn{} configuration which contains files with script code. A menu item is
  16. available that will examine the files in that folder to populate its sub-menu.
  17. @<Process plugin item@>=
  18. QMenu *pluginMenu = new QMenu(menu);
  19. if(itemElement.hasAttribute("id"))
  20. {
  21. pluginMenu->setObjectName(itemElement.attribute("id"));
  22. }
  23. if(itemElement.hasAttribute("title"))
  24. {
  25. pluginMenu->setTitle(itemElement.attribute("title"));
  26. }
  27. if(itemElement.hasAttribute("src"))
  28. {
  29. QSettings settings;
  30. QString pluginDirectory = QString("%1/%2").
  31. arg(settings.value("config").toString()).
  32. arg(itemElement.attribute("src"));
  33. QDir directory(pluginDirectory);
  34. directory.setFilter(QDir::Files);
  35. directory.setSorting(QDir::Name);
  36. QStringList nameFilter;
  37. nameFilter << "*.js";
  38. directory.setNameFilters(nameFilter);
  39. QFileInfoList pluginFiles = directory.entryInfoList();
  40. for(int k = 0; k < pluginFiles.size(); k++)
  41. {
  42. PluginAction *pa = new PluginAction(pluginFiles.at(k), pluginMenu);
  43. if(itemElement.hasAttribute("preRun"))
  44. {
  45. pa->setPreRun(itemElement.attribute("preRun"));
  46. }
  47. if(itemElement.hasAttribute("postRun"))
  48. {
  49. pa->setPostRun(itemElement.attribute("postRun"));
  50. }
  51. pluginMenu->addAction(pa);
  52. }
  53. }
  54. menu->addMenu(pluginMenu);
  55. @ The sub-menu items are a subclass of |QAction| which holds all of the
  56. information needed to respond to its activation.
  57. @<Class declarations@>=
  58. class PluginAction : public QAction
  59. {
  60. Q_OBJECT
  61. Q_PROPERTY(QString preRun READ preRun WRITE setPreRun);
  62. Q_PROPERTY(QString postRun READ postRun WRITE setPostRun);
  63. public:
  64. PluginAction(const QFileInfo &info, QObject *parent);
  65. QString preRun();
  66. QString postRun();
  67. public slots:
  68. void setPreRun(const QString &script);
  69. void setPostRun(const QString &script);
  70. private slots:
  71. void runScript();
  72. private:
  73. QString pluginFile;
  74. QString preRunScript;
  75. QString postRunScript;
  76. };
  77. @ The constructor takes a |QFileInfo| and uses that to extract the path of the
  78. file used to respond to the action activation as well as the text that should
  79. be used in the menu text. It also takes a |QObject*| parent which should be the
  80. |QMenu| the |PluginAction| will be placed in.
  81. Everything interesting happens in |runScript()| which is called when the action
  82. is triggered.
  83. @<PluginAction implementation@>=
  84. PluginAction::PluginAction(const QFileInfo &info, QObject *parent) :
  85. QAction(parent), preRunScript(""), postRunScript("")
  86. {
  87. pluginFile = info.absoluteFilePath();
  88. setText(info.baseName());
  89. connect(this, SIGNAL(triggered()), this, SLOT(runScript()));
  90. }
  91. void PluginAction::runScript()
  92. {
  93. QFile file(pluginFile);
  94. if(file.open(QIODevice::ReadOnly))
  95. {
  96. QScriptEngine *engine = AppInstance->engine;
  97. QScriptContext *context = engine->pushContext();
  98. if(parent()->dynamicPropertyNames().contains("activationObject"))
  99. {
  100. QScriptValue activationObject =
  101. parent()->property("activationObject").value<QScriptValue>();
  102. context->setActivationObject(activationObject);
  103. }
  104. QString script(file.readAll());
  105. QScriptValue retval = engine->evaluate(preRunScript + script + postRunScript, pluginFile);
  106. if(engine->hasUncaughtException())
  107. {
  108. qDebug() << "Uncaught exception: " <<
  109. engine->uncaughtException().toString() <<
  110. " in " << pluginFile << " line: " <<
  111. engine->uncaughtExceptionLineNumber();
  112. }
  113. engine->popContext();
  114. file.close();
  115. }
  116. }
  117. @ Pre-run and post-run scripts can be set to handle boilerplate that would
  118. otherwise need to be included in all plugins.
  119. @<PluginAction implementation@>=
  120. QString PluginAction::preRun()
  121. {
  122. return preRunScript;
  123. }
  124. QString PluginAction::postRun()
  125. {
  126. return postRunScript;
  127. }
  128. void PluginAction::setPreRun(const QString &script)
  129. {
  130. preRunScript = script;
  131. }
  132. void PluginAction::setPostRun(const QString &script)
  133. {
  134. postRunScript = script;
  135. }
  136. @ In order to get the activation object in this way, we need to allow a
  137. |QScriptValue| to be stored in a |QVariant|.
  138. @<Class declarations@>=
  139. Q_DECLARE_METATYPE(QScriptValue)
  140. @ This is added to the list of class implementations.
  141. @<Class implementations@>=
  142. @<PluginAction implementation@>