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.

manuallogentry.xml 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <window id="manualLogEntry">
  2. <menu name="File">
  3. <plugins id="pluginMenu" title="Import" src="ImportFilters" preRun="pluginContext.preRun();" postRun="pluginContext.postRun();"/>
  4. <separator />
  5. <item id="quitItem" shortcut="ctrl+Q">Quit</item>
  6. </menu>
  7. <menu name="Log">
  8. <item id="clear" shortcut="Ctrl+L">Clear Log</item>
  9. <separator />
  10. <item id="ms">Millisecond View</item>
  11. <item id="1s">1 Second View</item>
  12. <item id="5s">5 Second View</item>
  13. <item id="10s">10 Second View</item>
  14. <item id="15s">15 Second View</item>
  15. <item id="30s">30 Second View</item>
  16. <item id="1m">1 Minute View</item>
  17. </menu>
  18. <layout type="vertical">
  19. <tabbar id="tabs"/>
  20. <layout type="stack" id="pages">
  21. <page>
  22. <layout type="vertical">
  23. <layout type="horizontal">
  24. <label>Batch Type:</label>
  25. <sqldrop id="batchType" />
  26. <label>Machine:</label>
  27. <sqldrop id="machineSelector" />
  28. <stretch />
  29. </layout>
  30. <label>Green Coffee:</label>
  31. <layout type="stack" id="greenInfoLayout">
  32. <page id="sampleGreen">
  33. <layout type="vertical">
  34. <layout type="grid">
  35. <row>
  36. <column><label>Name:</label></column>
  37. <column><line id="sampleGreenName" /></column>
  38. </row>
  39. <row>
  40. <column><label>Weight:</label></column>
  41. <column><line id="sampleGreenWeight" validator="numeric">0.0</line></column>
  42. <column><sqldrop id="sampleGreenUnit" /></column>
  43. </row>
  44. <row>
  45. <column><label>Vendor:</label></column>
  46. <column><line id="sampleGreenVendor" /></column>
  47. </row>
  48. <row>
  49. <column><label>Arrival Date:</label></column>
  50. <column><calendar id="sampleGreenArrivalDate" /></column>
  51. </row>
  52. </layout>
  53. <label>Additional Details:</label>
  54. <sqltablearray columns="2" id="attributes">
  55. <column name="Attribute" />
  56. <column name="Value" />
  57. </sqltablearray>
  58. </layout>
  59. </page>
  60. <page id="productionGreen">
  61. <layout type="vertical">
  62. <layout type="horizontal">
  63. <label>Unit:</label>
  64. <sqldrop id="productionGreenUnit" />
  65. <stretch />
  66. </layout>
  67. <sqltablearray columns="2" id="productionGreenTable">
  68. <column name="Coffee" delegate="sql" showdata="true" null="true" nulltext="Delete" nulldata="delete" data="0" display="1">
  69. <![CDATA[SELECT id, name FROM coffees WHERE quantity <> 0 ORDER BY name]]>
  70. </column>
  71. <column name="Weight" delegate="numeric" />
  72. </sqltablearray>
  73. </layout>
  74. </page>
  75. </layout>
  76. <label>Roasting Details:</label>
  77. <layout type="grid">
  78. <row>
  79. <column><label>Item:</label></column>
  80. <column>
  81. <sqldrop data="0" display="1" showdata="true" id="roastedItem">
  82. <null />
  83. <query>SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id IN (SELECT item FROM current_items) ORDER BY name</query>
  84. </sqldrop>
  85. </column>
  86. </row>
  87. <row>
  88. <column><label>Weight:</label></column>
  89. <column><line id="roastedWeight" validator="numeric">0.0</line></column>
  90. </row>
  91. <row>
  92. <column><label>Time:</label></column>
  93. <column><calendar id="roastTime" time="true"/></column>
  94. </row>
  95. <row>
  96. <column><label>Duration:</label></column>
  97. <column><timeedit id="roastDuration" /></column>
  98. </row>
  99. <row>
  100. <column><label>Notes:</label></column>
  101. <column><textarea id="notes" /></column>
  102. </row>
  103. </layout>
  104. </layout>
  105. </page>
  106. <page>
  107. <layout type="vertical">
  108. <layout type="horizontal">
  109. <label>Time Increment (s):</label>
  110. <line id="timeincrement" validator="numeric">30</line>
  111. <stretch />
  112. <label>Time:</label>
  113. <timeedit id="currenttime" />
  114. <stretch />
  115. <label>Temperature:</label>
  116. <line id="currenttemperature" validator="numeric" />
  117. <label>Note:</label>
  118. <line id="currentnote" />
  119. <button name="Add Measurement" id="addmeasurement" type="push" />
  120. </layout>
  121. <splitter type="horizontal" id="roastdatasplit">
  122. <measurementtable id="log" />
  123. <graph id="graph" />
  124. </splitter>
  125. </layout>
  126. </page>
  127. </layout>
  128. <layout type="horizontal">
  129. <stretch />
  130. <button name="Submit" id="submit" type="push" />
  131. </layout>
  132. </layout>
  133. <program>
  134. <![CDATA[
  135. var window = this;
  136. this.windowTitle = "Typica - Manual Log Entry";
  137. window.windowReady.connect(function() {
  138. if(machineModel.rowCount() == 0) {
  139. displayError(TTR("manualLogEntry", "Configuration Required"),
  140. TTR("manualLogEntry", "Please configure a roaster."));
  141. window.close();
  142. }
  143. });
  144. quitItem = findChildObject(this, 'quitItem');
  145. quitItem.triggered.connect(function() {
  146. Application.quit();
  147. });
  148. pluginContext = {};
  149. pluginContext.table = findChildObject(this, 'log');
  150. pluginContext.table.setHeaderData(1, "Temp");
  151. pluginContext.table.setHeaderData(2, "Note");
  152. pluginContext.graph = findChildObject(this, 'graph');
  153. pluginContext.preRun = function() {
  154. var filename = QFileDialog.getOpenFileName(window, TTR("manualLogEntry", "Import"), QSettings.value('script/lastDir', '') + '/');
  155. var file = new QFile(filename);
  156. if(file.open(1)) {
  157. pluginContext.data = file.readToString();
  158. file.close();
  159. pluginContext.table.clear();
  160. pluginContext.graph.clear();
  161. QSettings.setValue("script/lastDir", dir(filename));
  162. } else {
  163. throw new Error("Failed to open file, aborting import.");
  164. }
  165. };
  166. pluginContext.postRun = function() {
  167. };
  168. pluginContext.newMeasurement = function(m, c) {
  169. pluginContext.table.newMeasurement(m, c);
  170. pluginContext.graph.newMeasurement(m, c);
  171. }
  172. pluginMenu = findChildObject(this, 'pluginMenu');
  173. pluginMenu.setProperty("activationObject", pluginContext);
  174. tabs = findChildObject(this, 'tabs');
  175. tabs.addTab("Batch Data");
  176. tabs.addTab("Roast Data");
  177. pages = findChildObject(this, 'pages');
  178. tabs.currentChanged.connect(function(index) {
  179. pages.setCurrentIndex(index);
  180. });
  181. greenInfoLayout = findChildObject(this, 'greenInfoLayout');
  182. roastedItem = findChildObject(this, 'roastedItem');
  183. batchType = findChildObject(this, 'batchType');
  184. batchType.addItem("Sample");
  185. batchType.addItem("Production");
  186. batchType['currentIndexChanged(int)'].connect(function(batchTypeIndex) {
  187. QSettings.setValue("script/manual_batchType", batchTypeIndex);
  188. greenInfoLayout.setCurrentIndex(batchTypeIndex);
  189. roastedItem.enabled = (batchTypeIndex == 1);
  190. });
  191. batchType.setCurrentIndex(QSettings.value("script/manual_batchType", 1));
  192. var machineSelector = findChildObject(this, 'machineSelector');
  193. var machineModel = new DeviceTreeModel;
  194. machineSelector.setModel(machineModel);
  195. machineSelector.currentIndex = QSettings.value("script/manualMachineSelection", 0);
  196. machineSelector['currentIndexChanged(int)'].connect(function(index) {
  197. QSettings.setValue("script/manualMachineSelection", index);
  198. });
  199. sampleGreenUnit = findChildObject(this, 'sampleGreenUnit');
  200. sampleGreenUnit.addItem("g");
  201. sampleGreenUnit.addItem("Kg");
  202. sampleGreenUnit.addItem("oz");
  203. sampleGreenUnit.addItem("lb");
  204. sampleGreenUnit.currentIndex = (QSettings.value("script/manual_unit", sampleGreenUnit.findText("lb")));
  205. productionGreenUnit = findChildObject(this, 'productionGreenUnit');
  206. productionGreenUnit.addItem("g");
  207. productionGreenUnit.addItem("Kg");
  208. productionGreenUnit.addItem("oz");
  209. productionGreenUnit.addItem("lb");
  210. productionGreenUnit.currentIndex = (QSettings.value("script/manual_unit", productionGreenUnit.findText("lb")));
  211. sampleGreenUnit['currentIndexChanged(int)'].connect(function(greenUnitIndex) {
  212. QSettings.setValue("script/manual_unit", greenUnitIndex);
  213. productionGreenUnit.setCurrentIndex(greenUnitIndex);
  214. });
  215. productionGreenUnit['currentIndexChanged(int)'].connect(function(greenUnitIndex) {
  216. QSettings.setValue("script/manual_unit", greenUnitIndex);
  217. sampleGreenUnit.setCurrentIndex(greenUnitIndex);
  218. });
  219. timeincrement = findChildObject(this, 'timeincrement');
  220. currenttime = findChildObject(this, 'currenttime');
  221. currenttemperature = findChildObject(this, 'currenttemperature');
  222. currentnote = findChildObject(this, 'currentnote');
  223. addmeasurement = findChildObject(this, 'addmeasurement');
  224. addmeasurement.clicked.connect(function() {
  225. pluginContext.newMeasurement(new Measurement(Number(currenttemperature.text), currenttime.time), 1);
  226. if(currentnote.text.length > 0) {
  227. pluginContext.table.newAnnotation(currentnote.text, 1, 2);
  228. }
  229. currentnote.text = "";
  230. var t = QTime();
  231. t = t.fromString(currenttime.time, "hh:mm:ss");
  232. t = t.addSecs(30);
  233. currenttime.time = t;
  234. currenttemperature.text = "";
  235. });
  236. currenttemperature.returnPressed.connect(addmeasurement.clicked);
  237. currentnote.returnPressed.connect(addmeasurement.clicked);
  238. var v1 = findChildObject(this, 'ms');
  239. v1.triggered.connect(pluginContext.table.LOD_ms);
  240. var v2 = findChildObject(this, '1s');
  241. v2.triggered.connect(pluginContext.table.LOD_1s);
  242. var v3 = findChildObject(this, '5s');
  243. v3.triggered.connect(pluginContext.table.LOD_5s);
  244. var v4 = findChildObject(this, '10s');
  245. v4.triggered.connect(pluginContext.table.LOD_10s);
  246. var v5 = findChildObject(this, '15s');
  247. v5.triggered.connect(pluginContext.table.LOD_15s);
  248. var v6 = findChildObject(this, '30s');
  249. v6.triggered.connect(pluginContext.table.LOD_30s);
  250. var v7 = findChildObject(this, '1m');
  251. v7.triggered.connect(pluginContext.table.LOD_1m);
  252. var clear = findChildObject(this, 'clear');
  253. clear.triggered.connect(pluginContext.table.clear);
  254. clear.triggered.connect(pluginContext.graph.clear);
  255. clear.triggered.connect(function() {
  256. currenttime.time = QTime(0, 0, 0, 0);
  257. currenttemperature.text = "";
  258. currentnote.text = "";
  259. });
  260. var sampleGreenName = findChildObject(this, 'sampleGreenName');
  261. var sampleGreenWeight = findChildObject(this, 'sampleGreenWeight');
  262. var productionGreenTable = findChildObject(this, 'productionGreenTable');
  263. var greenModel = productionGreenTable.model();
  264. var greenTotal = 0.0;
  265. var updateGreenTable = function() {
  266. var deleteRow = -1;
  267. while((deleteRow = productionGreenTable.findData("delete", 0)) > -1) {
  268. if(productionGreenTable.data(deleteRow, 0, 0) == "Delete") {
  269. productionGreenTable.removeRow(productionGreenTable.findData("delete", 0));
  270. } else {
  271. break;
  272. }
  273. }
  274. greenTotal = productionGreenTable.columnSum(1, 0);
  275. productionGreenTable.resizeColumnToContents(0);
  276. };
  277. greenModel.dataChanged.connect(updateGreenTable);
  278. var validateInputs = function() {
  279. if(batchType.currentIndex == 0) {
  280. /* Sample batch */
  281. if(sampleGreenName.text.length == 0) {
  282. tabs.setCurrentIndex(0);
  283. displayError(TTR("manualLogEntry", "Data Entry Error"),
  284. TTR("manualLogEntry", "Please enter a green coffee name."));
  285. return false;
  286. }
  287. if(Number(sampleGreenWeight.text) <= 0 || isNaN(sampleGreenWeight.text)) {
  288. tabs.setCurrentIndex(0);
  289. displayError(TTR("manualLogEntry", "Data Entry Error"),
  290. TTR("manualLogEntry", "Green coffee weight must be a number greater than 0."));
  291. return false;
  292. }
  293. } else {
  294. /* Production batch */
  295. var itemArray = productionGreenTable.columnArray(0, 32).split("\\s*,\\s*");
  296. var weightArray = productionGreenTable.columnArray(1, 0).split("\\s*,\\s*");
  297. if((itemArray.length != weightArray.length) || (itemArray.length == 0)) {
  298. tabs.setCurrentIndex(0);
  299. displayError(TTR("manualLogEntry", "Data Entry Error"),
  300. TTR("manualLogEntry", "Please check that at least one green coffee has been selected and each green coffee has a valid weight"));
  301. return false;
  302. }
  303. if(Number(greenTotal) <= 0) {
  304. tabs.setCurrentIndex(0);
  305. displayError(TTR("manualLogEntry", "DataEntryError"),
  306. TTR("manualLogEntry", "Total green coffee weight must be a number greater than 0."));
  307. return false;
  308. }
  309. if(roastedItem.currentIndex == 0) {
  310. tabs.setCurrentIndex(0);
  311. displayError(TTR("manualLogEntry", "DataEntryError"),
  312. TTR("manualLogEntry", "Please select a roasted coffee item."));
  313. return false;
  314. }
  315. }
  316. return true;
  317. };
  318. var roastDataExists = function() {
  319. return (pluginContext.table.rowCount() > 0);
  320. }
  321. var doSubmit = function() {
  322. window.close();
  323. }
  324. var submit = findChildObject(this, 'submit');
  325. submit.clicked.connect(function() {
  326. if(validateInputs()) {
  327. doSubmit();
  328. }
  329. });
  330. ]]>
  331. </program>
  332. </window>