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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <window id="roastspec">
  2. <layout type="horizontal">
  3. <layout type="vertical">
  4. <layout type="horizontal">
  5. <label>Coffee:</label>
  6. <sqldrop data="0" display="1" showdata="false" id="currentitems">
  7. <query>SELECT id, name FROM items WHERE id IN (SELECT item FROM current_items) ORDER BY name</query>
  8. </sqldrop>
  9. </layout>
  10. <tabbar id="tabs" />
  11. <layout type="stack" id="pages">
  12. <page>
  13. <layout type="vertical">
  14. <layout type="horizontal">
  15. <label>Expected % weight loss:</label>
  16. <line validator="numeric" id="expectedloss" />
  17. </layout>
  18. <layout type="horizontal">
  19. <label>Tolerance</label>
  20. <line validator="numeric" id="tolerance" />
  21. </layout>
  22. <stretch />
  23. </layout>
  24. </page>
  25. <page>
  26. <layout type="vertical">
  27. <layout type="horizontal">
  28. <label>Whole color:</label>
  29. <line validator="numeric" id="expectedwhole" />
  30. </layout>
  31. <layout type="horizontal">
  32. <label>Tolerance:</label>
  33. <line validator="numeric" id="wholetolerance" />
  34. </layout>
  35. <layout type="horizontal">
  36. <label>Ground color:</label>
  37. <line validator="numeric" id="expectedground" />
  38. </layout>
  39. <layout type="horizontal">
  40. <label>Tolerance:</label>
  41. <line validator="numeric" id="groundtolerance" />
  42. </layout>
  43. <stretch />
  44. </layout>
  45. </page>
  46. <page>
  47. <layout type="vertical">
  48. <label>Specification Notes:</label>
  49. <textarea id="notes" />
  50. <stretch />
  51. </layout>
  52. </page>
  53. </layout>
  54. <layout type="horizontal">
  55. <stretch />
  56. <button id="save" type="push" name="Save" />
  57. </layout>
  58. </layout>
  59. </layout>
  60. <program>
  61. <![CDATA[
  62. var window = this;
  63. this.windowTitle = TTR("roastspec", "Typica - Edit Roasting Specification");
  64. var tabs = findChildObject(this, 'tabs');
  65. tabs.addTab("Weight Loss");
  66. tabs.addTab("Color");
  67. tabs.addTab("Notes");
  68. var pages = findChildObject(this, 'pages');
  69. tabs.currentChanged.connect(function(index) {
  70. pages.setCurrentIndex(index);
  71. });
  72. var selector = findChildObject(this, 'currentitems');
  73. var expected = findChildObject(this, 'expectedloss');
  74. var tolerance = findChildObject(this, 'tolerance');
  75. var notes = findChildObject(this, 'notes');
  76. var savebutton = findChildObject(this, 'save');
  77. var wholecolor = findChildObject(this, 'expectedwhole');
  78. var groundcolor = findChildObject(this, 'expectedground');
  79. var wholetolerance = findChildObject(this, 'wholetolerance');
  80. var groundtolerance = findChildObject(this, 'groundtolerance');
  81. var updateDisplay = function() {
  82. var query = new QSqlQuery();
  83. query.prepare("SELECT loss, tolerance, notes, spec FROM roasting_specification WHERE item = :id1 AND time = (SELECT max(time) FROM roasting_specification WHERE item = :id2)");
  84. query.bind(":id1", selector.currentData());
  85. query.bind(":id2", selector.currentData());
  86. query.exec();
  87. if(query.next()) {
  88. if(query.value(0).length > 0) {
  89. expected.text = Number(query.value(0)) * 100;
  90. } else {
  91. expected.text = "";
  92. }
  93. if(query.value(1).length > 0) {
  94. tolerance.text = Number(query.value(1)) * 100;
  95. } else {
  96. tolerance.text = "";
  97. }
  98. notes.plainText = query.value(2);
  99. if(query.value(3).length > 0) {
  100. var spec = JSON.parse(query.value(3));
  101. if(spec.color.whole.expected === undefined) {
  102. wholecolor.text = "";
  103. } else {
  104. wholecolor.text = spec.color.whole.expected;
  105. }
  106. if(spec.color.whole.tolerance === undefined) {
  107. wholetolerance.text = "";
  108. } else {
  109. wholetolerance.text = spec.color.whole.tolerance;
  110. }
  111. if(spec.color.ground.expected === undefined) {
  112. groundcolor.text = "";
  113. } else {
  114. groundcolor.text = spec.color.ground.expected;
  115. }
  116. if(spec.color.ground.tolerance === undefined) {
  117. groundtolerance.text = "";
  118. } else {
  119. groundtolerance.text = spec.color.ground.tolerance;
  120. }
  121. }
  122. } else {
  123. expected.text = "";
  124. tolerance.text = "";
  125. notes.plainText = "";
  126. wholecolor.text = "";
  127. wholetolerance.text = "";
  128. groundcolor.text = "";
  129. groundtolerance.text = "";
  130. }
  131. query = query.invalidate();
  132. };
  133. updateDisplay();
  134. selector['currentIndexChanged(int)'].connect(function() {
  135. updateDisplay();
  136. });
  137. savebutton.clicked.connect(function() {
  138. var specobject = new Object;
  139. var query = new QSqlQuery();
  140. var columnspec = "time, item, ";
  141. var valuespec = "'now', :id, ";
  142. if(expected.text.length > 0) {
  143. columnspec += "loss, ";
  144. valuespec += ":loss, ";
  145. var lossspec = new Object;
  146. lossspec.expected = expected.text;
  147. if(tolerance.text.length > 0) {
  148. columnspec += "tolerance, ";
  149. valuespec += ":tolerance, ";
  150. lossspec.tolerance = tolerance.text;
  151. }
  152. specobject.loss = lossspec;
  153. }
  154. colorspec = new Object;
  155. if(wholecolor.text.length > 0) {
  156. wholespec = new Object;
  157. wholespec.expected = wholecolor.text;
  158. if(wholetolerance.text.length > 0) {
  159. wholespec.tolerance = wholetolerance.text;
  160. }
  161. colorspec.whole = wholespec;
  162. }
  163. if(groundcolor.text.length > 0) {
  164. groundspec = new Object;
  165. groundspec.expected = groundcolor.text;
  166. if(groundtolerance.text.length > 0) {
  167. groundspec.tolerance = groundtolerance.text;
  168. }
  169. colorspec.ground = groundspec;
  170. }
  171. if(colorspec.whole || colorspec.ground) {
  172. specobject.color = colorspec;
  173. }
  174. if(notes.plainText.length > 0) {
  175. specobject.notes = notes.plainText;
  176. }
  177. columnspec += "notes, spec";
  178. valuespec += ":notes, :spec";
  179. query.prepare("INSERT INTO roasting_specification (" + columnspec + ") VALUES (" + valuespec + ")");
  180. query.bind(":id", selector.currentData());
  181. if(expected.text.length > 0) {
  182. query.bind(":loss", Number(expected.text) / 100);
  183. }
  184. if(tolerance.text.length > 0) {
  185. query.bind(":tolerance", Number(tolerance.text) / 100);
  186. }
  187. query.bind(":notes", notes.plainText);
  188. query.bind(":spec", JSON.stringify(specobject));
  189. query.exec();
  190. displayInfo(TTR("roastspec", "New Specification Saved"),
  191. TTR("roastspec", "New roasting specification saved"));
  192. });
  193. ]]>
  194. </program>
  195. </window>