Browse Source

Typica 1.4.3

Neal Wilson 11 years ago
commit
7e531f2ad0
100 changed files with 14355 additions and 0 deletions
  1. 141
    0
      config/Reports/auco.xml
  2. 462
    0
      config/Reports/chart.xml
  3. 204
    0
      config/Reports/dailyproduction.xml
  4. 120
    0
      config/Reports/fypurchase.xml
  5. 197
    0
      config/Reports/inventory.xml
  6. 163
    0
      config/Reports/monthcompare.xml
  7. 136
    0
      config/Reports/rwacp.xml
  8. 178
    0
      config/Windows/batchdetails.xml
  9. 313
    0
      config/Windows/batchdetailsnew.xml
  10. 470
    0
      config/Windows/cuppingform.xml
  11. 8
    0
      config/Windows/cuppingformsbysession.xml
  12. 61
    0
      config/Windows/cuppingitemselection.xml
  13. 16
    0
      config/Windows/cuppingsamplepoints.xml
  14. 9
    0
      config/Windows/cuppingsampleselection.xml
  15. 246
    0
      config/Windows/cuppingsession.xml
  16. 263
    0
      config/Windows/cuppingsessionlist.xml
  17. 64
    0
      config/Windows/cuppingsessionsummary.xml
  18. 29
    0
      config/Windows/cuppingsummary.xml
  19. 40
    0
      config/Windows/editfee.xml
  20. 32
    0
      config/Windows/editinvoice.xml
  21. 109
    0
      config/Windows/editinvoiceitem.xml
  22. 760
    0
      config/Windows/export.xml
  23. 276
    0
      config/Windows/externalroaster.xml
  24. 101
    0
      config/Windows/greeninventory.xml
  25. 79
    0
      config/Windows/greensales.xml
  26. 45
    0
      config/Windows/history.xml
  27. 36
    0
      config/Windows/importprofiles.xml
  28. 51
    0
      config/Windows/invoiceinfo.xml
  29. 28
    0
      config/Windows/invoicelist.xml
  30. 229
    0
      config/Windows/navigation.xml
  31. 322
    0
      config/Windows/newbatch.xml
  32. 32
    0
      config/Windows/newroaster.xml
  33. 118
    0
      config/Windows/offline.xml
  34. 78
    0
      config/Windows/optime.xml
  35. 758
    0
      config/Windows/print.xml
  36. 708
    0
      config/Windows/productionroaster.xml
  37. 396
    0
      config/Windows/purchase.xml
  38. 83
    0
      config/Windows/roastmanager.xml
  39. 30
    0
      config/Windows/setsampleparameters.xml
  40. 10
    0
      config/Windows/success.xml
  41. 44
    0
      config/config.xml
  42. 41
    0
      src/3rdparty/qextserialport/.hgignore
  43. 4
    0
      src/3rdparty/qextserialport/.hgtags
  44. 251
    0
      src/3rdparty/qextserialport/ChangeLog
  45. 88
    0
      src/3rdparty/qextserialport/LICENSE
  46. 131
    0
      src/3rdparty/qextserialport/README
  47. 17
    0
      src/3rdparty/qextserialport/buildlib/buildlib.pro
  48. 17
    0
      src/3rdparty/qextserialport/common.pri
  49. 11
    0
      src/3rdparty/qextserialport/config_example.pri
  50. 12
    0
      src/3rdparty/qextserialport/doc/doc.pri
  51. 16
    0
      src/3rdparty/qextserialport/doc/examples/enumerator.qdoc
  52. BIN
      src/3rdparty/qextserialport/doc/examples/images/uartassistant.png
  53. 7
    0
      src/3rdparty/qextserialport/doc/examples/qespta.qdoc
  54. 24
    0
      src/3rdparty/qextserialport/doc/examples/uartassistant.qdoc
  55. 127
    0
      src/3rdparty/qextserialport/doc/index.qdoc
  56. 53
    0
      src/3rdparty/qextserialport/doc/qextserialport.qdocconf
  57. 35
    0
      src/3rdparty/qextserialport/doc/readme.txt
  58. 137
    0
      src/3rdparty/qextserialport/doc/style/style.css
  59. 6
    0
      src/3rdparty/qextserialport/examples/enumerator/enumerator.pro
  60. 31
    0
      src/3rdparty/qextserialport/examples/enumerator/main.cpp
  61. 43
    0
      src/3rdparty/qextserialport/examples/event/PortListener.cpp
  62. 26
    0
      src/3rdparty/qextserialport/examples/event/PortListener.h
  63. 7
    0
      src/3rdparty/qextserialport/examples/event/event.pro
  64. 19
    0
      src/3rdparty/qextserialport/examples/event/main.cpp
  65. 5
    0
      src/3rdparty/qextserialport/examples/examples.pro
  66. 61
    0
      src/3rdparty/qextserialport/examples/qespta/MainWindow.cpp
  67. 38
    0
      src/3rdparty/qextserialport/examples/qespta/MainWindow.h
  68. 95
    0
      src/3rdparty/qextserialport/examples/qespta/MessageWindow.cpp
  69. 82
    0
      src/3rdparty/qextserialport/examples/qespta/MessageWindow.h
  70. 129
    0
      src/3rdparty/qextserialport/examples/qespta/QespTest.cpp
  71. 36
    0
      src/3rdparty/qextserialport/examples/qespta/QespTest.h
  72. 4
    0
      src/3rdparty/qextserialport/examples/qespta/README
  73. 26
    0
      src/3rdparty/qextserialport/examples/qespta/main.cpp
  74. 14
    0
      src/3rdparty/qextserialport/examples/qespta/qespta.pro
  75. 159
    0
      src/3rdparty/qextserialport/examples/uartassistant/dialog.cpp
  76. 41
    0
      src/3rdparty/qextserialport/examples/uartassistant/dialog.h
  77. 191
    0
      src/3rdparty/qextserialport/examples/uartassistant/dialog.ui
  78. 133
    0
      src/3rdparty/qextserialport/examples/uartassistant/hled.cpp
  79. 34
    0
      src/3rdparty/qextserialport/examples/uartassistant/hled.h
  80. 11
    0
      src/3rdparty/qextserialport/examples/uartassistant/main.cpp
  81. 22
    0
      src/3rdparty/qextserialport/examples/uartassistant/uartassistant.pro
  82. 7
    0
      src/3rdparty/qextserialport/qextserialport.pro
  83. 427
    0
      src/3rdparty/qextserialport/src/extserialport/qextserialport_win.cpp
  84. 414
    0
      src/3rdparty/qextserialport/src/extserialport/qextserialport_win.cpp.orig
  85. 167
    0
      src/3rdparty/qextserialport/src/qextserialenumerator.cpp
  86. 69
    0
      src/3rdparty/qextserialport/src/qextserialenumerator.h
  87. 313
    0
      src/3rdparty/qextserialport/src/qextserialenumerator_osx.cpp
  88. 103
    0
      src/3rdparty/qextserialport/src/qextserialenumerator_p.h
  89. 100
    0
      src/3rdparty/qextserialport/src/qextserialenumerator_unix.cpp
  90. 302
    0
      src/3rdparty/qextserialport/src/qextserialenumerator_win.cpp
  91. 1006
    0
      src/3rdparty/qextserialport/src/qextserialport.cpp
  92. 240
    0
      src/3rdparty/qextserialport/src/qextserialport.h
  93. 47
    0
      src/3rdparty/qextserialport/src/qextserialport.pri
  94. 72
    0
      src/3rdparty/qextserialport/src/qextserialport_global.h
  95. 257
    0
      src/3rdparty/qextserialport/src/qextserialport_p.h
  96. 448
    0
      src/3rdparty/qextserialport/src/qextserialport_unix.cpp
  97. 427
    0
      src/3rdparty/qextserialport/src/qextserialport_win.cpp
  98. 247
    0
      src/3rdparty/qextserialport/src/qextwineventnotifier_p.cpp
  99. 80
    0
      src/3rdparty/qextserialport/src/qextwineventnotifier_p.h
  100. 0
    0
      src/3rdparty/qextserialport/tests/qextwineventnotifier/qextwineventnotifier.pro

+ 141
- 0
config/Reports/auco.xml View File

@@ -0,0 +1,141 @@
1
+<window id="useandcostreport">
2
+	<reporttitle>Production:->Average Use and Cost by Origin</reporttitle>
3
+    <layout type="vertical">
4
+        <layout type="horizontal">
5
+            <label>Sort Order:</label>
6
+            <sqldrop id="sort" />
7
+            <stretch />
8
+        </layout>
9
+        <webview id="report" />
10
+    </layout>
11
+    <menu name="File">
12
+        <item id="print" shortcut="Ctrl+P">Print</item>
13
+    </menu>
14
+    <program>
15
+        <![CDATA[
16
+            this.windowTitle = "Typica - Average Use and Cost by Origin";
17
+            var report = findChildObject(this, 'report');
18
+            var printMenu = findChildObject(this, 'print');
19
+            printMenu.triggered.connect(function() {
20
+                report.print();
21
+            });
22
+            var sortBox = findChildObject(this, 'sort');
23
+            sortBox.addItem("Origin A-Z");
24
+            sortBox.addItem("Origin Z-A");
25
+            sortBox.addItem("Avg. Rate Ascending");
26
+            sortBox.addItem("Avg. Rate Descending");
27
+            sortBox.addItem("Avg. Cost Ascending");
28
+            sortBox.addItem("Avg. Cost Descending");
29
+            sortBox.currentIndex = QSettings.value("auco_sort", 0);
30
+            function refresh() {
31
+                var buffer = new QBuffer;
32
+                buffer.open(3);
33
+                var output = new XmlWriter(buffer);
34
+                output.writeStartDocument("1.0");
35
+                output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
36
+                output.writeStartElement("html");
37
+                output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
38
+                output.writeStartElement("head");
39
+                output.writeTextElement("title", "Recent Use and Cost by Origin");
40
+                output.writeEndElement();
41
+                output.writeStartElement("body");
42
+                output.writeTextElement("h1", "Average Use and Cost by Origin");
43
+                output.writeTextElement("p", "This is a report of average rate of use in pounds per day and cost of unroasted coffee.");
44
+                output.writeStartElement("table");
45
+                output.writeAttribute("rules", "groups");
46
+                output.writeAttribute("cellpadding", "3px");
47
+                output.writeStartElement("thead");
48
+                output.writeStartElement("tr");
49
+                output.writeStartElement("th");
50
+                output.writeAttribute("colspan", "3");
51
+                output.writeCharacters("Regular Coffees");
52
+                output.writeEndElement();
53
+                output.writeEndElement();
54
+                output.writeStartElement("tr");
55
+                output.writeTextElement("th", "Origin");
56
+                output.writeTextElement("th", "Avg. Rate");
57
+                output.writeTextElement("th", "Avg. Cost");
58
+                output.writeEndElement();
59
+                output.writeEndElement();
60
+                output.writeStartElement("tbody");
61
+                var query = new QSqlQuery();
62
+                switch(sortBox.currentIndex)
63
+                {
64
+                    case 0:
65
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY origin ASC");
66
+                        break;
67
+                    case 1:
68
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY origin DESC");
69
+                        break;
70
+                    case 2:
71
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY rate ASC");
72
+                        break;
73
+                    case 3:
74
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY rate DESC");
75
+                        break;
76
+                    case 4:
77
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY cost ASC");
78
+                        break;
79
+                    case 5:
80
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY cost DESC");
81
+                        break;
82
+                }
83
+                while(query.next())
84
+                {
85
+                    output.writeStartElement("tr");
86
+                    output.writeTextElement("td", query.value(0));
87
+                    output.writeTextElement("td", query.value(1));
88
+                    output.writeTextElement("td", query.value(2));
89
+                    output.writeEndElement();
90
+                }
91
+                output.writeStartElement("tr");
92
+                output.writeStartElement("th");
93
+                output.writeAttribute("colspan", "3");
94
+                output.writeCharacters("Decaffeinated Coffees");
95
+                output.writeEndElement();
96
+                output.writeEndElement();
97
+                switch(sortBox.currentIndex)
98
+                {
99
+                    case 0:
100
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY origin ASC");
101
+                        break;
102
+                    case 1:
103
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY origin DESC");
104
+                        break;
105
+                    case 2:
106
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY rate ASC");
107
+                        break;
108
+                    case 3:
109
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY rate DESC");
110
+                        break;
111
+                    case 4:
112
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY cost ASC");
113
+                        break;
114
+                    case 5:
115
+                        query.exec("SELECT DISTINCT origin, avg(rate)::numeric(10,2) AS rate, (SELECT avg(cost) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY cost DESC");
116
+                        break;
117
+                }
118
+                while(query.next())
119
+                {
120
+                    output.writeStartElement("tr");
121
+                    output.writeTextElement("td", query.value(0));
122
+                    output.writeTextElement("td", query.value(1));
123
+                    output.writeTextElement("td", query.value(2));
124
+                    output.writeEndElement();
125
+                }
126
+                output.writeEndElement();
127
+                output.writeEndElement();
128
+                output.writeEndElement();
129
+                output.writeEndElement();
130
+                output.writeEndDocument();
131
+                report.setContent(buffer);
132
+                buffer.close();
133
+            }
134
+            refresh();
135
+            sortBox['currentIndexChanged(int)'].connect(function() {
136
+                QSettings.setValue("auco_sort", sortBox.currentIndex);
137
+                refresh();
138
+            });
139
+        ]]>
140
+    </program>
141
+</window>

+ 462
- 0
config/Reports/chart.xml View File

@@ -0,0 +1,462 @@
1
+<window id="pytdprodcomp">
2
+	<reporttitle>Production:->Previous Year Production Comparison</reporttitle>
3
+    <layout type="vertical">
4
+        <layout type="horizontal">
5
+            <label>Start Date:</label>
6
+            <calendar id="startdate" />
7
+            <label>End Date:</label>
8
+            <calendar id="enddate" />
9
+            <label>Days to Average</label>
10
+            <line validator="integer" id="days">7</line>
11
+            <stretch />
12
+        </layout>
13
+        <webview id="report" />
14
+    </layout>
15
+    <menu name="File">
16
+        <item id="print" shortcut="Ctrl+P">Print</item>
17
+    </menu>
18
+    <program>
19
+        <![CDATA[
20
+            this.windowTitle = "Typica - Previous Year Production Comparison";
21
+            var startDateField = findChildObject(this, 'startdate');
22
+            startDateField.setDate(startDateField.year(), 1, 1);
23
+            var endDateField = findChildObject(this, 'enddate');
24
+            var view = findChildObject(this, 'report');
25
+            var printMenu = findChildObject(this, 'print');
26
+            printMenu.triggered.connect(function() {
27
+                view.print();
28
+            });
29
+            var avgField = findChildObject(this, 'days');
30
+            function refresh() {
31
+                var buffer = new QBuffer;
32
+                buffer.open(3);
33
+                var output = new XmlWriter(buffer);
34
+                output.writeStartDocument("1.0");
35
+                output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
36
+                output.writeStartElement("html");
37
+                output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
38
+                output.writeStartElement("head");
39
+                output.writeTextElement("title", "Previous Year Production Comparison");
40
+                output.writeEndElement();
41
+                output.writeStartElement("body");
42
+                output.writeTextElement("h1", "Previous Year Production Comparison");
43
+                output.writeTextElement("p", "This report provides an itemized and overall comparison of roasted coffee production for the dates specified with those dates in the previous year. A chart of this data along with percent change and rolling average of the percent change is also produced.");
44
+                output.writeStartElement("table");
45
+                output.writeAttribute("style", "page-break-after:auto;");
46
+                output.writeAttribute("rules", "groups");
47
+                output.writeAttribute("cellpadding", "3px");
48
+                output.writeStartElement("thead");
49
+                output.writeStartElement("tr");
50
+                output.writeTextElement("th", "Coffee");
51
+                output.writeTextElement("th", "Previous");
52
+                output.writeTextElement("th", "Current");
53
+                output.writeTextElement("th", "Change");
54
+                output.writeEndElement();
55
+                output.writeEndElement();
56
+                output.writeStartElement("tbody");
57
+                var query = new QSqlQuery();
58
+                query.exec("START TRANSACTION");
59
+                print(query.executedQuery());
60
+                var curStartDate = "'"+startDateField.year()+"-"+startDateField.month()+"-"+startDateField.day()+"'";
61
+                query.exec("SELECT "+curStartDate+"::date - interval '1 year', '"+endDateField.year()+"-"+endDateField.month()+"-"+endDateField.day()+"'::date - interval '1 year' + interval '1 day', '"+endDateField.year()+"-"+endDateField.month()+"-"+endDateField.day()+"'::date + interval '1 day'");
62
+                print(query.executedQuery());
63
+                query.next();
64
+                var curEndDate = "'"+query.value(2)+"'";
65
+                var prevStartDate = "'"+query.value(0)+"'";
66
+                var prevEndDate = "'"+query.value(1)+"'";
67
+                var q = "CREATE TEMPORARY TABLE previous ON COMMIT DROP AS SELECT roasted_id, sum(roasted_quantity) AS p FROM roasting_log WHERE time > "+prevStartDate+" AND time < "+prevEndDate+" AND roasted_id IS NOT NULL GROUP BY roasted_id";
68
+                query.exec(q);
69
+                print(query.executedQuery());
70
+                q = "CREATE TEMPORARY TABLE current ON COMMIT DROP AS SELECT roasted_id, sum(roasted_quantity) AS c FROM roasting_log WHERE time > "+curStartDate+" AND time < "+curEndDate+" AND roasted_id IS NOT NULL GROUP BY roasted_id";
71
+                query.exec(q);
72
+                print(query.executedQuery());
73
+                query.exec("INSERT INTO previous SELECT roasted_id, 0 FROM current WHERE roasted_id NOT IN (SELECT roasted_id FROM previous)");
74
+                print(query.executedQuery());
75
+                query.exec("INSERT INTO current SELECT roasted_id, 0 FROM previous WHERE roasted_id NOT IN (SELECT roasted_id FROM current)");
76
+                print(query.executedQuery());
77
+                query.exec("CREATE TEMPORARY TABLE comp ON COMMIT DROP AS SELECT previous.roasted_id, p, c FROM previous LEFT OUTER JOIN current ON previous.roasted_id = current.roasted_id");
78
+                print(query.executedQuery());
79
+                query.exec("SELECT (SELECT name FROM items WHERE id = roasted_id) AS name, p, c, (c-p) FROM comp WHERE p > 0 OR c > 0 ORDER BY name");
80
+                print(query.executedQuery());
81
+                while(query.next())
82
+                {
83
+                    output.writeStartElement("tr");
84
+                    output.writeTextElement("td", query.value(0));
85
+                    output.writeTextElement("td", query.value(1));
86
+                    output.writeTextElement("td", query.value(2));
87
+                    output.writeTextElement("td", query.value(3));
88
+                    output.writeEndElement();
89
+                }
90
+                output.writeEndElement();
91
+                output.writeStartElement("tfoot");
92
+                output.writeTextElement("th", "Totals");
93
+                query.exec("SELECT sum(p), sum(c), sum(c-p) FROM comp");
94
+                print(query.executedQuery());
95
+                query.next();
96
+                output.writeTextElement("td", query.value(0));
97
+                output.writeTextElement("td", query.value(1));
98
+                output.writeTextElement("td", query.value(2));
99
+                output.writeEndElement();
100
+                query.exec("ABORT");
101
+                print(query.executedQuery());
102
+                output.writeEndElement();
103
+                output.writeStartElement("svg");
104
+                output.writeAttribute("xmlns", "http://www.w3.org/2000/svg");
105
+                output.writeAttribute("width", "7.5in");
106
+                output.writeAttribute("height", "6.3in");
107
+                output.writeStartElement("g");
108
+                output.writeAttribute("transform", "translate(0,470)");
109
+                output.writeStartElement("g");
110
+                output.writeAttribute("transform", "scale(1,-1)");
111
+                output.writeStartElement("line");
112
+                output.writeAttribute("x1", "40");
113
+                output.writeAttribute("x2", "40");
114
+                output.writeAttribute("y1", "0");
115
+                output.writeAttribute("y2", "450");
116
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
117
+                output.writeEndElement();
118
+                output.writeStartElement("line");
119
+                output.writeAttribute("x1", "50");
120
+                output.writeAttribute("x2", "650");
121
+                output.writeAttribute("y1", "-10");
122
+                output.writeAttribute("y2", "-10");
123
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
124
+                output.writeEndElement();
125
+                output.writeStartElement("line");
126
+                output.writeAttribute("x1", "660");
127
+                output.writeAttribute("x2", "660");
128
+                output.writeAttribute("y1", "0");
129
+                output.writeAttribute("y2", "450");
130
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
131
+                output.writeEndElement();
132
+                var query = new QSqlQuery();
133
+                var q = "SELECT "+curEndDate+"::date - "+curStartDate+"::date";
134
+                query.exec(q);
135
+                query.next();
136
+                var days = query.value(0);
137
+                var dates = new Array();
138
+                var curpounds = new Array();
139
+                var prevpounds = new Array();
140
+                var change = new Array();
141
+                var avgchange = new Array();
142
+                var i;
143
+                for(i = 0; i < days; i++)
144
+                {
145
+                    q = "SELECT "+curStartDate+"::date + "+(i+1);
146
+                    query.exec(q);
147
+                    query.next();
148
+                    dates[i] = query.value(0);
149
+                    q = "SELECT sum(roasted_quantity) FROM roasting_log WHERE time > "+curStartDate+" AND time < '"+dates[i]+"'";
150
+                    query.exec(q);
151
+                    if(query.next())
152
+                    {
153
+                        curpounds[i] = query.value(0);
154
+                    }
155
+                    else
156
+                    {
157
+                        curpounds[i] = 0;
158
+                    }
159
+                    q = "SELECT sum(roasted_quantity) FROM roasting_log WHERE time > "+curStartDate+"::date - '1 year'::interval AND time < '"+dates[i]+"'::date - '1 year'::interval";
160
+                    query.exec(q);
161
+                    if(query.next())
162
+                    {
163
+                        prevpounds[i] = query.value(0);
164
+                    }
165
+                    else
166
+                    {
167
+                        prevpounds[i] = 0;
168
+                    }
169
+                    if(curpounds[i] > 0)
170
+                    {
171
+                        change[i] = (curpounds[i] - prevpounds[i])/curpounds[i];
172
+                    }
173
+                    else
174
+                    {
175
+                        if(prevpounds[i] > 0)
176
+                        {
177
+                            change[i] = -1;
178
+                        }
179
+                        else
180
+                        {
181
+                            change[i] = 0;
182
+                        }
183
+                    }
184
+                    if(i > (parseInt(avgField.text)-2))
185
+                    {
186
+                        var sum = 0;
187
+                        var j;
188
+                        for(j = 0; j < parseInt(avgField.text); j++)
189
+                        {
190
+                            sum += change[i-j];
191
+                        }
192
+                        avgchange[i] = sum / parseInt(avgField.text);
193
+                    }
194
+                }
195
+                var maxy1 = 0;
196
+                while(maxy1 < Math.max(curpounds[days - 1], prevpounds[days - 1]))
197
+                {
198
+                    maxy1 += 100;
199
+                }
200
+                var pos = 0;
201
+                while(pos <= maxy1)
202
+                {
203
+                    output.writeStartElement("line");
204
+                    output.writeAttribute("x1", "35");
205
+                    output.writeAttribute("x2", "45");
206
+                    output.writeAttribute("y1", (450/maxy1)*pos);
207
+                    output.writeAttribute("y2", (450/maxy1)*pos);
208
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
209
+                    output.writeEndElement();
210
+                    pos += 100;
211
+                }
212
+                var n = Math.min.apply(Math, change);
213
+                var m = Math.max.apply(Math, change);
214
+                var miny2 = 0;
215
+                var maxy2;
216
+                if(n < 0)
217
+                {
218
+                    while(miny2 > n)
219
+                    {
220
+                        miny2 -= 0.1;
221
+                    }
222
+                    maxy2 = miny2;
223
+                }
224
+                else
225
+                {
226
+                    while(miny2 < n)
227
+                    {
228
+                        miny2 += 0.1;
229
+                    }
230
+                    miny2 -= 0.1;
231
+                    maxy2 = miny2;
232
+                }
233
+                while(maxy2 < m)
234
+                {
235
+                    maxy2 += 0.1;
236
+                }
237
+                var range = maxy2 - miny2;
238
+                pos = miny2;
239
+                while(pos <= maxy2)
240
+                {
241
+                    output.writeStartElement("line");
242
+                    output.writeAttribute("x1", "655");
243
+                    output.writeAttribute("x2", "665");
244
+                    output.writeAttribute("y1", (pos-miny2)*(4.5/(range*100))*10000);
245
+                    output.writeAttribute("y2", (pos-miny2)*(4.5/(range*100))*10000);
246
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
247
+                    output.writeEndElement();
248
+                    pos += 0.1;
249
+                }
250
+                pos = 0;
251
+                while(pos < days)
252
+                {
253
+                    output.writeStartElement("line");
254
+                    output.writeAttribute("x1", 50+((600/(days-1))*pos));
255
+                    output.writeAttribute("x2", 50+((600/(days-1))*pos));
256
+                    output.writeAttribute("y1", "-5");
257
+                    output.writeAttribute("y2", "-15");
258
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
259
+                    output.writeEndElement();
260
+                    pos += 7;
261
+                }
262
+                output.writeStartElement("line");
263
+                output.writeAttribute("x1", 50+((600/(days-1))*(days-1)));
264
+                output.writeAttribute("x2", 50+((600/(days-1))*(days-1)));
265
+                output.writeAttribute("y1", "-5");
266
+                output.writeAttribute("y2", "-15");
267
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
268
+                output.writeEndElement();
269
+                pos = 1;
270
+                while(pos < days)
271
+                {
272
+                    output.writeStartElement("line");
273
+                    output.writeAttribute("x1", 50+((600/(days-1))*(pos - 1)));
274
+                    output.writeAttribute("x2", 50+((600/(days-1))*pos));
275
+                    output.writeAttribute("y1", (prevpounds[pos-1]/maxy1)*450);
276
+                    output.writeAttribute("y2", (prevpounds[pos]/maxy1)*450);
277
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1;");
278
+                    output.writeEndElement();
279
+                    output.writeStartElement("line");
280
+                    output.writeAttribute("x1", 50+((600/(days-1))*(pos - 1)));
281
+                    output.writeAttribute("x2", 50+((600/(days-1))*pos));
282
+                    output.writeAttribute("y1", (curpounds[pos-1]/maxy1)*450);
283
+                    output.writeAttribute("y2", (curpounds[pos]/maxy1)*450);
284
+                    output.writeAttribute("style", "stroke:rgb(255,0,0);stroke-width:1;");
285
+                    output.writeEndElement();
286
+                    output.writeStartElement("line");
287
+                    output.writeAttribute("x1", 50+((600/(days-1))*(pos-1)));
288
+                    output.writeAttribute("x2", 50+((600/(days-1))*pos));
289
+                    output.writeAttribute("y1", (change[pos-1]-miny2)*(4.5/(range*100))*10000);
290
+                    output.writeAttribute("y2", (change[pos]-miny2)*(4.5/(range*100))*10000);
291
+                    output.writeAttribute("style", "stroke:rgb(0,255,0);stroke-width:1;");
292
+                    output.writeEndElement();
293
+                    if(pos > (parseInt(avgField.text)-1))
294
+                    {
295
+                        output.writeStartElement("line");
296
+                        output.writeAttribute("x1", 50+((600/(days-1))*(pos-1)));
297
+                        output.writeAttribute("x2", 50+((600/(days-1))*pos));
298
+                        output.writeAttribute("y1", (avgchange[pos-1]-miny2)*(4.5/(range*100))*10000);
299
+                        output.writeAttribute("y2", (avgchange[pos]-miny2)*(4.5/(range*100))*10000);
300
+                        output.writeAttribute("style", "stroke:rgb(0,0,255);stroke-width:1;");
301
+                        output.writeEndElement();
302
+                    }
303
+                    pos++;
304
+                }            
305
+                output.writeEndElement();
306
+                i = 0;
307
+                while(i <= maxy1)
308
+                {
309
+                    output.writeStartElement("text");
310
+                    output.writeAttribute("x", "0");
311
+                    output.writeAttribute("y", -((450/maxy1)*i)+5);
312
+                    output.writeAttribute("font-size", "12");
313
+                    output.writeCharacters(i);
314
+                    output.writeEndElement();
315
+                    i += 100;
316
+                }
317
+                i = miny2;
318
+                while(i <= maxy2)
319
+                {
320
+                    output.writeStartElement("text");
321
+                    output.writeAttribute("x", "670");
322
+                    output.writeAttribute("y", -((i-miny2)*(4.5/(range*100))*10000)+5);
323
+                    output.writeAttribute("font-size", "12");
324
+                    output.writeCharacters(Number(i*100).toFixed(0)+"%");
325
+                    output.writeEndElement();
326
+                    i += 0.1;
327
+                }
328
+                i = 0;
329
+                while(i <= days-1)
330
+                {
331
+                    output.writeStartElement("text");
332
+                    output.writeAttribute("x", 45+((600/(days-1))*i));
333
+                    output.writeAttribute("y", "20");
334
+                    output.writeAttribute("font-size", "12");
335
+                    output.writeAttribute("transform", "rotate(90 "+(45+((600/(days-1))*i))+",20)");
336
+                    q = "SELECT ('"+dates[i]+"'::date - '1 day'::interval)::date";
337
+                    query.exec(q);
338
+                    query.next();
339
+                    var ds = query.value(0);
340
+                    var parts = ds.split("-");
341
+                    switch(parts[1])
342
+                    {
343
+                        case '01':
344
+                            ds = "January ";
345
+                            break;
346
+                        case '02':
347
+                            ds = "February ";
348
+                            break;
349
+                        case '03':
350
+                            ds = "March ";
351
+                            break;
352
+                        case '04':
353
+                            ds = "April ";
354
+                            break;
355
+                        case '05':
356
+                            ds = "May ";
357
+                            break;
358
+                        case '06':
359
+                            ds = "June ";
360
+                            break;
361
+                        case '07':
362
+                            ds = "July ";
363
+                            break;
364
+                        case '08':
365
+                            ds = "August ";
366
+                            break;
367
+                        case '09':
368
+                            ds = "September ";
369
+                            break;
370
+                        case '10':
371
+                            ds = "October ";
372
+                            break;
373
+                        case '11':
374
+                            ds = "November ";
375
+                            break;
376
+                        case '12':
377
+                            ds = "December ";
378
+                            break;
379
+                    }
380
+                    ds = ds + Number(parts[2]);
381
+                    output.writeCharacters(ds);
382
+                    output.writeEndElement();
383
+                    if(i == days-1)
384
+                    {
385
+                        break;
386
+                    }
387
+                    i += 7;
388
+                    if(i > days-1)
389
+                    {
390
+                        i = days - 1;
391
+                    }
392
+                }            
393
+                output.writeStartElement("rect");
394
+                output.writeAttribute("fill", "rgb(0,0,0)");
395
+                output.writeAttribute("x", "45");
396
+                output.writeAttribute("y", "110");
397
+                output.writeAttribute("width", "24");
398
+                output.writeAttribute("height", "12");
399
+                output.writeEndElement();
400
+                output.writeStartElement("text");
401
+                output.writeAttribute("x", "75");
402
+                output.writeAttribute("y", "120");
403
+                output.writeAttribute("font-size", "12");
404
+                output.writeCharacters("Previous Year Pounds");
405
+                output.writeEndElement();
406
+                output.writeStartElement("rect");
407
+                output.writeAttribute("fill", "rgb(255,0,0)");
408
+                output.writeAttribute("x", "195");
409
+                output.writeAttribute("y", "110");
410
+                output.writeAttribute("width", "24");
411
+                output.writeAttribute("height", "12");
412
+                output.writeEndElement();
413
+                output.writeStartElement("text");
414
+                output.writeAttribute("x", "225");
415
+                output.writeAttribute("y", "120");
416
+                output.writeAttribute("font-size", "12");
417
+                output.writeCharacters("Current Year Pounds");
418
+                output.writeEndElement();
419
+                output.writeStartElement("rect");
420
+                output.writeAttribute("fill", "rgb(0,255,0)");
421
+                output.writeAttribute("x", "345");
422
+                output.writeAttribute("y", "110");
423
+                output.writeAttribute("width", "24");
424
+                output.writeAttribute("height", "12");
425
+                output.writeEndElement();
426
+                output.writeStartElement("text");
427
+                output.writeAttribute("x", "375");
428
+                output.writeAttribute("y", "120");
429
+                output.writeAttribute("font-size", "12");
430
+                output.writeCharacters("% Change");
431
+                output.writeEndElement();
432
+                output.writeStartElement("rect");
433
+                output.writeAttribute("fill", "rgb(0,0,255)");
434
+                output.writeAttribute("x", "495");
435
+                output.writeAttribute("y", "110");
436
+                output.writeAttribute("width", "24");
437
+                output.writeAttribute("height", "12");
438
+                output.writeEndElement();
439
+                output.writeStartElement("text");
440
+                output.writeAttribute("x", "525");
441
+                output.writeAttribute("y", "120");
442
+                output.writeAttribute("font-size", "12");
443
+                output.writeCharacters("Average % Change");
444
+                output.writeEndElement();
445
+                output.writeEndElement();
446
+                output.writeEndElement();
447
+                output.writeEndElement();
448
+                output.writeEndElement();
449
+                output.writeEndDocument();
450
+                view.setContent(buffer);
451
+                buffer.close();
452
+            }
453
+            refresh();
454
+            startDateField.dateChanged.connect(function() {
455
+                refresh();
456
+            });
457
+            endDateField.dateChanged.connect(function() {
458
+                refresh();
459
+            });
460
+        ]]>
461
+    </program>
462
+</window>

+ 204
- 0
config/Reports/dailyproduction.xml View File

@@ -0,0 +1,204 @@
1
+<window id="dailyproduction">
2
+	<reporttitle>Production:->Daily Production Report</reporttitle>
3
+	<layout type="vertical">
4
+		<layout type="horizontal">
5
+			<label>Date:</label>
6
+			<calendar id="reportdate" />
7
+			<stretch />
8
+		</layout>
9
+		<webview id="report" />
10
+	</layout>
11
+	<menu name="File">
12
+		<item id="print" shortcut="Ctrl+P">Print</item>
13
+	</menu>
14
+	<program>
15
+		<![CDATA[
16
+			this.windowTitle = "Typica - Daily Production Report";
17
+			var dateField = findChildObject(this, 'reportdate');
18
+			var view = findChildObject(this, 'report');
19
+			var printMenu = findChildObject(this, 'print');
20
+			printMenu.triggered.connect(function() {
21
+				view.print();
22
+			});
23
+			function refresh() {
24
+				var buffer = new QBuffer;
25
+				buffer.open(3);
26
+				var output = new XmlWriter(buffer);
27
+				output.writeStartDocument("1.0");
28
+				output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
29
+				output.writeStartElement("html");
30
+				output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
31
+				output.writeStartElement("head");
32
+				output.writeTextElement("title", "Daily Production Report");
33
+				output.writeEndElement();
34
+				output.writeStartElement("body");
35
+				var dateString = "" + dateField.year() + "-" + dateField.month() + "-" + dateField.day();
36
+				output.writeTextElement("h1", "Daily Production Report: " + dateString);
37
+				output.writeTextElement("h2", "Batches Roasted");
38
+				var query = new QSqlQuery();
39
+				var q = "SELECT time, machine, (SELECT name FROM machine WHERE id = machine), (SELECT name FROM items WHERE id = roasted_id), unroasted_id, unroasted_quantity, unroasted_total_quantity, roasted_id, roasted_quantity, annotation, duration, files FROM roasting_log WHERE time > '" + dateString + "' AND time < ('" + dateString + "'::date + integer '1') ORDER BY time";
40
+				query.exec(q);
41
+				var times = new Array();
42
+				var machines = new Array();
43
+				output.writeStartElement("table");
44
+				output.writeAttribute("rules", "groups");
45
+				output.writeAttribute("cellpadding", "3px");
46
+				output.writeStartElement("thead");
47
+				output.writeStartElement("tr");
48
+				output.writeTextElement("th", "Time");
49
+				output.writeTextElement("th", "Machine");
50
+				output.writeTextElement("th", "Green Weights");
51
+				output.writeTextElement("th", "Green Coffees");
52
+				output.writeTextElement("th", "Roasted Weight");
53
+				output.writeTextElement("th", "Roasted Coffee");
54
+				output.writeTextElement("th", "% Weight Loss");
55
+				output.writeTextElement("th", "Duration");
56
+				output.writeEndElement();
57
+				output.writeEndElement();
58
+				output.writeStartElement("tbody");
59
+				while(query.next())
60
+				{
61
+					times.push(query.value(0));
62
+					machines.push(query.value(1));
63
+					output.writeStartElement("tr");
64
+					output.writeTextElement("td", String(query.value(0)).split("T")[1]);
65
+					output.writeTextElement("td", query.value(2));
66
+					var unroastedWeightsList = sqlToArray(query.value(5));
67
+					output.writeStartElement("td");
68
+					for(var i = 0; i < unroastedWeightsList.length; i++)
69
+					{
70
+						if(i != 0)
71
+						{
72
+							output.writeEmptyElement("br");
73
+						}
74
+						output.writeCDATA(unroastedWeightsList[i]);
75
+					}
76
+					if(unroastedWeightsList.length > 1)
77
+					{
78
+						output.writeCDATA("Total: ");
79
+						output.writeCDATA(query.value(6));
80
+					}
81
+					output.writeEndElement();
82
+					var unroastedList = sqlToArray(query.value(4));
83
+					output.writeStartElement("td");
84
+					for(var i = 0;  i < unroastedList.length; i++)
85
+					{
86
+						var greensQuery = new QSqlQuery();
87
+						greensQuery.prepare("SELECT name FROM items WHERE id = :id");
88
+						greensQuery.bind(":id", Number(unroastedList[i]));
89
+						greensQuery.exec();
90
+						if(i != 0)
91
+						{
92
+							output.writeEmptyElement("br");
93
+						}
94
+						greensQuery.next();
95
+						output.writeCDATA(greensQuery.value(0));
96
+					}
97
+					output.writeEndElement();
98
+					output.writeTextElement("td", query.value(8));
99
+					output.writeTextElement("td", query.value(3));
100
+					var loss = (Number(query.value(6)) - Number(query.value(8)))/Number(query.value(6));
101
+					loss *= 100;
102
+					output.writeTextElement("td", loss.toFixed(2)+"%");
103
+					output.writeTextElement("td", query.value(10));
104
+					output.writeEndElement();
105
+					if(query.value(9) != "")
106
+					{
107
+						output.writeStartElement("tr");
108
+						output.writeEmptyElement("td");
109
+						output.writeStartElement("td");
110
+						output.writeAttribute("colspan", "7");
111
+						output.writeTextElement("em", query.value(9));
112
+						output.writeEndElement();
113
+						output.writeEndElement();
114
+					}
115
+				}
116
+				output.writeEndElement();
117
+				output.writeStartElement("tfoot");
118
+				output.writeStartElement("tr");
119
+				output.writeEmptyElement("td");
120
+				output.writeStartElement("td");
121
+				output.writeTextElement("strong", "Totals:");
122
+				output.writeEndElement();
123
+				q = "SELECT sum(unroasted_total_quantity), sum(roasted_quantity), sum(duration) FROM roasting_log WHERE time > '" + dateString + "' AND time < ('" + dateString + "'::date + integer '1')";
124
+				query.exec(q);
125
+				query.next();
126
+				output.writeTextElement("td", query.value(0));
127
+				output.writeEmptyElement("td");
128
+				output.writeTextElement("td", query.value(1));
129
+				output.writeEmptyElement("td");
130
+				output.writeEmptyElement("td"); 
131
+				output.writeTextElement("td", query.value(2));
132
+				output.writeEndElement();
133
+				output.writeEndElement(); //tfoot
134
+				output.writeEndElement(); //table
135
+				output.writeTextElement("h2", "Inventory");
136
+				output.writeStartElement("table");
137
+				output.writeAttribute("rules", "groups");
138
+				output.writeAttribute("cellpadding", "3px");
139
+				output.writeStartElement("thead");
140
+				output.writeStartElement("tr");
141
+				output.writeTextElement("th", "Green Coffee");
142
+				output.writeTextElement("th", "Starting Inventory");
143
+				output.writeTextElement("th", "Ending Inventory");
144
+				output.writeTextElement("th", "Change");
145
+				output.writeTextElement("th", "Availability");
146
+				output.writeEndElement();
147
+				output.writeEndElement();
148
+				output.writeStartElement("tbody");
149
+				q = "SELECT DISTINCT item, (SELECT name FROM items WHERE id = item) AS name, (SELECT out FROM coffee_history WHERE id = item) FROM all_transactions WHERE time > '" + dateString + "' AND time < '" + dateString + "'::date + integer '1' ORDER BY name ASC";
150
+				query.exec(q)
151
+				var subQuery = new QSqlQuery();
152
+				var qq;
153
+				while(query.next())
154
+				{
155
+					output.writeStartElement("tr");
156
+					output.writeTextElement("td", query.value(1));
157
+					qq = "SELECT balance FROM item_history(" + query.value(0) + ") WHERE time = (SELECT max(time) FROM all_transactions WHERE time < '" + dateString + "' AND item = " + query.value(0) + ") OR time = (SELECT max(time) FROM all_transactions WHERE time < '" + dateString + "'::date + integer '1' AND item = " + query.value(0) + ") ORDER BY time ASC";
158
+					subQuery.exec(qq);
159
+					var startValue = 0;
160
+					var endValue = 0;
161
+					if(subQuery.next())
162
+					{
163
+						output.writeTextElement("td", subQuery.value(0));
164
+						startValue = subQuery.value(0);
165
+					}
166
+					else
167
+					{
168
+						output.writeEmptyElement("td");
169
+					}
170
+					if(subQuery.next())
171
+					{
172
+						output.writeTextElement("td", subQuery.value(0));
173
+						endValue = subQuery.value(0);
174
+					}
175
+					else
176
+					{
177
+						output.writeEmptyElement("td");
178
+					}
179
+					var startPrec = startValue.split('.').length > 1 ? startValue.split('.')[1].length : 0;
180
+					var endPrec = endValue.split('.').length > 1 ? endValue.split('.')[1].length : 0;
181
+					output.writeTextElement("td", (Number(endValue) - Number(startValue)).toFixed(Math.max(startPrec, endPrec)));
182
+					output.writeTextElement("td", query.value(2));
183
+					output.writeEndElement();
184
+				}
185
+				output.writeEndElement();
186
+				output.writeStartElement("tfoot");
187
+				
188
+				output.writeEndElement();
189
+				output.writeEndElement();//End of inventory table
190
+				
191
+				
192
+				output.writeEndElement();
193
+				output.writeEndElement();
194
+				output.writeEndDocument();
195
+				view.setContent(buffer);
196
+				buffer.close();
197
+			}
198
+			refresh();
199
+			dateField.dateChanged.connect(function() {
200
+				refresh();
201
+			});
202
+		]]>
203
+	</program>
204
+</window>

+ 120
- 0
config/Reports/fypurchase.xml View File

@@ -0,0 +1,120 @@
1
+<window id="fypurchase">
2
+	<reporttitle>Purchase:->Coffee Purchase Previous Years Comparison</reporttitle>
3
+	<layout type="vertical">
4
+		<layout type="horizontal">
5
+			<label>Start Date:</label>
6
+			<calendar id="startdate" />
7
+			<label>End Date:</label>
8
+			<calendar id="enddate" />
9
+			<stretch />
10
+		</layout>
11
+		<webview id="report" />
12
+	</layout>
13
+	<menu name="File">
14
+		<item id="print" shortcut="Ctrl+P">Print</item>
15
+	</menu>
16
+	<program>
17
+		<![CDATA[
18
+			this.windowTitle = "Typica - Coffee Purchase Previous Years Comparison";
19
+			var startDateField = findChildObject(this, 'startdate');
20
+			var query = new QSqlQuery();
21
+			query.exec("SELECT EXTRACT(YEAR FROM time) FROM purchase WHERE time = (SELECT min(time) FROM purchase)");
22
+			query.next();
23
+			startDateField.setDate(query.value(0), 1, 1);
24
+			var endDateField = findChildObject(this, 'enddate');
25
+			endDateField.setDate(endDateField.year(), 12, 31);
26
+			var view = findChildObject(this, 'report');
27
+			var printMenu = findChildObject(this, 'print');
28
+			printMenu.triggered.connect(function() {
29
+				view.print();
30
+			});
31
+			function refresh() {
32
+				var buffer = new QBuffer;
33
+				buffer.open(3);
34
+				var output = new XmlWriter(buffer);
35
+				output.writeStartDocument("1.0");
36
+				output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
37
+                output.writeStartElement("html");
38
+                output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
39
+                output.writeStartElement("head");
40
+				output.writeTextElement("title", "Coffee Purchase Previous Years Comparison");
41
+				output.writeEndElement();
42
+				output.writeStartElement("body");
43
+				output.writeTextElement("h1", "Coffee Purchase Previous Years Comparison");
44
+				output.writeStartElement("table");
45
+				output.writeAttribute("style", "page-break-after:auto;");
46
+                output.writeAttribute("rules", "groups");
47
+                output.writeAttribute("cellpadding", "3px");
48
+                output.writeStartElement("thead");
49
+                output.writeStartElement("tr");
50
+				output.writeEmptyElement("th");
51
+				for(var i = startDateField.year(); i <= endDateField.year(); i++)
52
+				{
53
+					output.writeTextElement("th", i);
54
+				}
55
+				output.writeEndElement();
56
+				output.writeEndElement();
57
+				output.writeStartElement("tbody");
58
+				output.writeStartElement("tr");
59
+				output.writeTextElement("th", "Sacks Purchased");
60
+				var j = 0;
61
+				var sacks = new Array;
62
+				for(var i = startDateField.year(); i <= endDateField.year(); i++)
63
+				{
64
+					var q = "SELECT sum(quantity/(SELECT conversion FROM lb_bag_conversion WHERE item = purchase.item)) FROM purchase WHERE time >= '" + i + "-01-01' AND time < '" + (i+1) + "-01-01'";
65
+					query.exec(q);
66
+					query.next();
67
+					output.writeTextElement("td", query.value(0));
68
+					sacks[j] = query.value(0);
69
+					j++;
70
+				}
71
+				output.writeEndElement();
72
+				output.writeStartElement("tr");
73
+				output.writeTextElement("th", "Pounds Purchased");
74
+				j = 0;
75
+				var pounds = new Array;
76
+				for(var i = startDateField.year(); i <= endDateField.year(); i++)
77
+				{
78
+					var q = "SELECT sum(quantity) FROM purchase WHERE time >= '" + i + "-01-01' AND time < '" + (i+1) + "-01-01'";
79
+					query.exec(q);
80
+					query.next();
81
+					output.writeTextElement("td", query.value(0));
82
+					pounds[j] = query.value(0);
83
+					j++;
84
+				}
85
+				output.writeEndElement();
86
+				output.writeStartElement("tr");
87
+				output.writeTextElement("th", "Cost");
88
+				j = 0;
89
+				var cost = new Array;
90
+				for(var i = startDateField.year(); i <= endDateField.year(); i++)
91
+				{
92
+					var q = "SELECT sum(cost*quantity)::numeric(12,2) FROM purchase WHERE time >= '" + i + "-01-01' AND time < '" + (i+1) + "-01-01'";
93
+					query.exec(q);
94
+					query.next();
95
+					output.writeTextElement("td", query.value(0));
96
+					cost[j] = query.value(0);
97
+					j++;
98
+				}
99
+				output.writeEndElement();
100
+				output.writeEndElement();
101
+				output.writeStartElement("tfoot");
102
+				output.writeEndElement();
103
+				output.writeEndElement();
104
+				output.writeEndElement();
105
+				output.writeEndElement();
106
+				output.writeEndDocument();
107
+				view.setContent(buffer);
108
+				buffer.close();
109
+			}
110
+			refresh();
111
+			startDateField.dateChanged.connect(function() {
112
+				refresh();
113
+			});
114
+			endDateField.dateChanged.connect(function() {
115
+				refresh();
116
+			});
117
+		]]>
118
+	</program>
119
+</window>
120
+

+ 197
- 0
config/Reports/inventory.xml View File

@@ -0,0 +1,197 @@
1
+<window id="inventoryreport">
2
+	<reporttitle>Inventory:->Current Inventory and Availability Projection</reporttitle>
3
+    <layout type="vertical">
4
+        <layout type="horizontal">
5
+            <label>Sort Order:</label>
6
+            <sqldrop id="sort" />
7
+			<label>Weight Unit:</label>
8
+			<sqldrop id="unit" />
9
+            <stretch />
10
+        </layout>
11
+        <webview id="report" />
12
+    </layout>
13
+    <menu name="File">
14
+        <item id="print" shortcut="Ctrl+P">Print</item>
15
+    </menu>
16
+    <program>
17
+        <![CDATA[
18
+            this.windowTitle = "Typica - Current Inventory and Availability Projection";
19
+            var report = findChildObject(this, 'report');
20
+            var printMenu = findChildObject(this, 'print');
21
+            printMenu.triggered.connect(function() {
22
+                report.print();
23
+            });
24
+            var sortBox = findChildObject(this, 'sort');
25
+            sortBox.addItem("Coffee A-Z");
26
+            sortBox.addItem("Coffee Z-A");
27
+            sortBox.addItem("Stock Ascending");
28
+            sortBox.addItem("Stock Descending");
29
+            sortBox.addItem("Sacks Ascending");
30
+            sortBox.addItem("Sacks Descending");
31
+            sortBox.addItem("Unit Cost Ascending");
32
+            sortBox.addItem("Unit Cost Descending");
33
+            sortBox.addItem("Stock Cost Ascending");
34
+            sortBox.addItem("Stock Cost Descending");
35
+            sortBox.addItem("Use Rate Ascending");
36
+            sortBox.addItem("Use Rate Descending");
37
+            sortBox.addItem("Availability Shortest-Longest");
38
+            sortBox.addItem("Availability Longest-Shortest");
39
+            sortBox.currentIndex = QSettings.value("inventory_sort", 0);
40
+			var unitBox = findChildObject(this, 'unit');
41
+			unitBox.addItem("Kg");
42
+			unitBox.addItem("Lb");
43
+			unitBox.currentIndex = QSettings.value("script/report_unit", 1);
44
+            function refresh() {
45
+                var buffer = new QBuffer;
46
+                buffer.open(3);
47
+                var output = new XmlWriter(buffer);
48
+                output.writeStartDocument("1.0");
49
+                output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
50
+                output.writeStartElement("html");
51
+                output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
52
+                output.writeStartElement("head");
53
+                output.writeTextElement("title", "Current Inventory and Availability Projection");
54
+                output.writeEndElement();
55
+                output.writeStartElement("body");
56
+                output.writeTextElement("h1", "Current Inventory and Availability Projection");
57
+                output.writeTextElement("p", "This is a report showing how much of each coffee is available, the cost of that coffee, the daily rate of use for that coffee, and the date the coffee will be gone if use continues at the current rate.");
58
+                output.writeStartElement("table");
59
+                output.writeAttribute("rules", "groups");
60
+                output.writeAttribute("cellpadding", "3px");
61
+                output.writeStartElement("thead");
62
+                output.writeStartElement("tr");
63
+                output.writeTextElement("th", "Coffee");
64
+				switch(unitBox.currentIndex)
65
+				{
66
+					case 0:
67
+						output.writeTextElement("th", "Stock (Kg)");
68
+						break;
69
+					case 1:
70
+						output.writeTextElement("th", "Stock (Lb)");
71
+						break;
72
+				}
73
+                output.writeTextElement("th", "Sacks");
74
+                output.writeTextElement("th", "Unit Cost");
75
+                output.writeTextElement("th", "Stock Cost");
76
+                output.writeTextElement("th", "Use Rate");
77
+                output.writeTextElement("th", "Availability");
78
+                output.writeEndElement();
79
+                output.writeEndElement();
80
+                output.writeStartElement("tbody");
81
+                var query = new QSqlQuery();
82
+                var q = "SELECT name, (quantity / :conversion)::numeric(12,2) AS quantity, (quantity / (SELECT conversion FROM lb_bag_conversion WHERE item = id))::numeric(12,2) AS sacks, (SELECT cost * :conversion2 FROM purchase WHERE item = id)::numeric(12,2) AS cost, (quantity * (SELECT cost FROM purchase WHERE item = id))::numeric(12,2) AS stock_cost, (SELECT rate / :conversion3 FROM coffee_history WHERE coffee_history.id = items.id)::numeric(12,2) AS rate, (SELECT out FROM coffee_history WHERE coffee_history.id = items.id) AS out FROM items WHERE quantity > 0 ";
83
+                switch(sortBox.currentIndex)
84
+                {
85
+                    case 0:
86
+                        q = q + "ORDER BY name ASC";
87
+                        break;
88
+                    case 1:
89
+                        q = q + "ORDER BY name DESC";
90
+                        break;
91
+                    case 2:
92
+                        q = q + "ORDER BY quantity ASC";
93
+                        break;
94
+                    case 3:
95
+                        q = q + "ORDER BY quantity DESC";
96
+                        break;
97
+                    case 4:
98
+                        q = q + "ORDER BY sacks ASC";
99
+                        break;
100
+                    case 5:
101
+                        q = q + "ORDER BY sacks DESC";
102
+                        break;
103
+                    case 6:
104
+                        q = q + "ORDER BY cost ASC";
105
+                        break;
106
+                    case 7:
107
+                        q = q + "ORDER BY cost DESC";
108
+                        break;
109
+                    case 8:
110
+                        q = q + "ORDER BY stock_cost ASC";
111
+                        break;
112
+                    case 9:
113
+                        q = q + "ORDER BY stock_cost DESC";
114
+                        break;
115
+                    case 10:
116
+                        q = q + "ORDER BY rate ASC";
117
+                        break;
118
+                    case 11:
119
+                        q = q + "ORDER BY rate DESC";
120
+                        break;
121
+                    case 12:
122
+                        q = q + "ORDER BY out ASC";
123
+                        break;
124
+                    case 13:
125
+                        q = q + "ORDER BY out DESC";
126
+                        break;
127
+                }
128
+                query.prepare(q);
129
+				switch(unitBox.currentIndex)
130
+				{
131
+					case 0:
132
+						query.bind(":conversion", 2.2);
133
+						query.bind(":conversion2", 2.2);
134
+						query.bind(":conversion3", 2.2);
135
+						break;
136
+					case 1:
137
+						query.bind(":conversion", 1);
138
+						query.bind(":conversion2", 1);
139
+						query.bind(":conversion3", 1);
140
+						break;
141
+				}
142
+				query.exec();
143
+                while(query.next())
144
+                {
145
+                    output.writeStartElement("tr");
146
+                    output.writeTextElement("td", query.value(0));
147
+                    output.writeTextElement("td", query.value(1));
148
+                    output.writeTextElement("td", query.value(2));
149
+                    output.writeTextElement("td", query.value(3));
150
+                    output.writeTextElement("td", query.value(4));
151
+                    output.writeTextElement("td", query.value(5));
152
+                    output.writeTextElement("td", query.value(6));
153
+                    output.writeEndElement();
154
+                }
155
+                output.writeEndElement();
156
+                output.writeStartElement("tfoot");
157
+                output.writeStartElement("tr");
158
+                output.writeTextElement("th", "Totals");
159
+                query.prepare("SELECT (sum(quantity) / :conversion)::numeric(12,2), sum(quantity * (SELECT cost FROM purchase WHERE item = id))::numeric(12,2) FROM items WHERE quantity > 0");
160
+				switch(unitBox.currentIndex)
161
+				{
162
+					case 0:
163
+						query.bind(":conversion", 2.2);
164
+						break;
165
+					case 1:
166
+						query.bind(":conversion", 1);
167
+						break;
168
+				}
169
+				query.exec();
170
+                query.next();
171
+                output.writeTextElement("td", query.value(0));
172
+                output.writeTextElement("td", "");
173
+                output.writeTextElement("td", "");
174
+                output.writeTextElement("td", query.value(1));
175
+                output.writeTextElement("td", "");
176
+                output.writeTextElement("td", "");
177
+                output.writeEndElement();
178
+                output.writeEndElement();
179
+                output.writeEndElement();
180
+                output.writeEndElement();
181
+                output.writeEndElement();
182
+                output.writeEndDocument();
183
+                report.setContent(buffer);
184
+                buffer.close();
185
+            }
186
+            refresh();
187
+            sortBox['currentIndexChanged(int)'].connect(function() {
188
+                QSettings.setValue("inventory_sort", sortBox.currentIndex);
189
+                refresh();
190
+            });
191
+			unitBox['currentIndexChanged(int)'].connect(function() {
192
+				QSettings.setValue("script/report_unit", unitBox.currentIndex);
193
+				refresh();
194
+			});
195
+        ]]>
196
+    </program>
197
+</window>

+ 163
- 0
config/Reports/monthcompare.xml View File

@@ -0,0 +1,163 @@
1
+<window id="pytdprodcomp">
2
+	<reporttitle>Production:->Previous Year Production Comparison By Month</reporttitle>
3
+    <layout type="vertical">
4
+		<layout type="horizontal">
5
+			<label>Weight Unit:</label>
6
+			<sqldrop id="unit" />
7
+            <stretch />
8
+        </layout>
9
+        <webview id="report" />
10
+    </layout>
11
+    <menu name="File">
12
+        <item id="print" shortcut="Ctrl+P">Print</item>
13
+    </menu>
14
+    <program>
15
+        <![CDATA[
16
+            this.windowTitle = "Typica - Previous Year Production Comparison By Month";
17
+            var view = findChildObject(this, 'report');
18
+            var printMenu = findChildObject(this, 'print');
19
+            printMenu.triggered.connect(function() {
20
+                view.print();
21
+            });
22
+			var unitBox = findChildObject(this, 'unit');
23
+			unitBox.addItem("Kg");
24
+			unitBox.addItem("Lb");
25
+			unitBox.currentIndex = QSettings.value("script/report_unit", 1);
26
+			unitBox['currentIndexChanged(int)'].connect(function() {
27
+				QSettings.setValue("script/report_unit", unitBox.currentIndex);
28
+				refresh();
29
+			});
30
+            function refresh() {
31
+                var buffer = new QBuffer;
32
+                buffer.open(3);
33
+                var output = new XmlWriter(buffer);
34
+                output.writeStartDocument("1.0");
35
+                output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
36
+                output.writeStartElement("html");
37
+                output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
38
+                output.writeStartElement("head");
39
+                output.writeTextElement("title", "Previous Year Production Comparison By Month");
40
+                output.writeEndElement();
41
+                output.writeStartElement("body");
42
+                output.writeTextElement("h1", "Previous Year Production Comparison By Month");
43
+				switch(unitBox.currentIndex)
44
+				{
45
+					case 0:
46
+						output.writeTextElement("p", "This report compares total roasted coffee production in kilograms with the previous year on a monthly basis.");
47
+						break;
48
+					case 1:
49
+						output.writeTextElement("p", "This report compares total roasted coffee production in pounds with the previous year on a monthly basis.");
50
+						break;
51
+				}
52
+                output.writeStartElement("table");
53
+                output.writeAttribute("style", "page-break-after:auto;");
54
+                output.writeAttribute("rules", "groups");
55
+                output.writeAttribute("cellpadding", "3px");
56
+                output.writeStartElement("thead");
57
+                output.writeStartElement("tr");
58
+                output.writeTextElement("th", "Month");
59
+				var query = new QSqlQuery();
60
+				query.exec("SELECT EXTRACT(YEAR FROM 'now'::date) AS current_year");
61
+				query.next();
62
+				var current_year = query.value(0);
63
+                output.writeTextElement("th", current_year-1);
64
+                output.writeTextElement("th", current_year);
65
+                output.writeTextElement("th", "Change");
66
+                output.writeEndElement();
67
+                output.writeEndElement();
68
+                output.writeStartElement("tbody");
69
+				var month_names = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
70
+				var current_data = new Array();
71
+				var previous_data = new Array();
72
+				for(var i = 0; i < 12; i++) {
73
+					var q = "SELECT SUM(roasted_quantity) FROM roasting_log WHERE roasted_id IS NOT NULL AND time > '"
74
+					q += current_year;
75
+					q += "-";
76
+					q += 1+i;
77
+					q += "-01' AND time < '";
78
+					if(i == 11) {
79
+						q += 1+current_year;
80
+					} else {
81
+						q += current_year;
82
+					}
83
+					q += "-";
84
+					if(i == 11) {
85
+						q += "01"
86
+					} else {
87
+						q += 2+i;
88
+					}
89
+					q += "-01'";
90
+					query.exec(q);
91
+					query.next();
92
+					current_data.push(query.value(0));
93
+				}
94
+				for(var i = 0; i < 12; i++) {
95
+					var q = "SELECT SUM(roasted_quantity) FROM roasting_log WHERE roasted_id IS NOT NULL AND time > '"
96
+					q += current_year-1;
97
+					q += "-";
98
+					q += 1+i;
99
+					q += "-01' AND time < '";
100
+					if(i == 11) {
101
+						q += current_year;
102
+					} else {
103
+						q += current_year-1;
104
+					}
105
+					q += "-";
106
+					if(i == 11) {
107
+						q += "01"
108
+					} else {
109
+						q += 2+i;
110
+					}
111
+					q += "-01'";
112
+					query.exec(q);
113
+					query.next();
114
+					previous_data.push(query.value(0));
115
+				}
116
+				query = query.invalidate();
117
+				for(var i = 0; i < 12; i++) {
118
+					output.writeStartElement("tr");
119
+					output.writeTextElement("td", month_names[i]);
120
+					switch(unitBox.currentIndex)
121
+					{
122
+						case 0:
123
+							output.writeTextElement("td", Number(previous_data[i] / 2.2).toFixed(2));
124
+							output.writeTextElement("td", Number(current_data[i] / 2.2).toFixed(2));
125
+							output.writeTextElement("td", Number((current_data[i] - previous_data[i]) / 2.2).toFixed(2));
126
+							break;
127
+						case 1:
128
+							output.writeTextElement("td", Number(previous_data[i]).toFixed(2));
129
+							output.writeTextElement("td", Number(current_data[i]).toFixed(2));
130
+							output.writeTextElement("td", Number(current_data[i]-previous_data[i]).toFixed(2));
131
+							break;
132
+					}
133
+					output.writeEndElement();
134
+				}
135
+                output.writeEndElement();
136
+                output.writeStartElement("tfoot");
137
+                output.writeTextElement("th", "Totals");
138
+				var current_total = current_data.reduce(function(a,b) {return Number(a) + Number(b);}, 0);
139
+				var previous_total = previous_data.reduce(function(a,b) {return Number(a) + Number(b);}, 0);
140
+				switch(unitBox.currentIndex)
141
+				{
142
+					case 0:
143
+						output.writeTextElement("td", (previous_total/2.2).toFixed(2));
144
+						output.writeTextElement("td", (current_total/2.2).toFixed(2));
145
+						output.writeTextElement("td", ((current_total-previous_total)/2.2).toFixed(2));
146
+						break;
147
+					case 1:
148
+						output.writeTextElement("td", previous_total.toFixed(2));
149
+						output.writeTextElement("td", current_total.toFixed(2));
150
+						output.writeTextElement("td", (current_total-previous_total).toFixed(2));
151
+						break;
152
+				}
153
+                output.writeEndElement();
154
+                output.writeEndElement();
155
+                output.writeEndElement();
156
+                output.writeEndDocument();
157
+                view.setContent(buffer);
158
+                buffer.close();
159
+            }
160
+            refresh();
161
+        ]]>
162
+    </program>
163
+</window>

+ 136
- 0
config/Reports/rwacp.xml View File

@@ -0,0 +1,136 @@
1
+<window id="productionreport">
2
+	<reporttitle>Production:->Recent Average Weekly Coffee Production</reporttitle>
3
+    <layout type="vertical">
4
+        <layout type="horizontal">
5
+            <label>Sort Order:</label>
6
+            <sqldrop id="sort" />
7
+			<label>Weight Unit:</label>
8
+			<sqldrop id="unit" />
9
+            <stretch />
10
+        </layout>
11
+        <webview id="report" />
12
+    </layout>
13
+    <menu name="File">
14
+        <item id="print" shortcut="Ctrl+P">Print</item>
15
+    </menu>
16
+    <program>
17
+        <![CDATA[
18
+            this.windowTitle = "Typica - Recent Average Weekly Coffee Production";
19
+            var report = findChildObject(this, 'report');
20
+            var printMenu = findChildObject(this, 'print');
21
+            printMenu.triggered.connect(function() {
22
+                report.print();
23
+            });
24
+            var sortBox = findChildObject(this, 'sort');
25
+            sortBox.addItem("Roasted Coffee A-Z");
26
+            sortBox.addItem("Roasted Coffee Z-A");
27
+            sortBox.addItem("Weekly Use Ascending");
28
+            sortBox.addItem("Weekly Use Descending");
29
+            sortBox.currentIndex = QSettings.value("rwacp_sort", 3);
30
+			var unitBox = findChildObject(this, 'unit');
31
+			unitBox.addItem("Kg");
32
+			unitBox.addItem("Lb");
33
+			unitBox.currentIndex = QSettings.value("script/report_unit", 1);
34
+            function refresh() {
35
+                var buffer = new QBuffer;
36
+                buffer.open(3);
37
+                var output = new XmlWriter(buffer);
38
+                output.writeStartDocument("1.0");
39
+                output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
40
+                output.writeStartElement("html");
41
+                output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
42
+                output.writeStartElement("head");
43
+                output.writeTextElement("title", "Recent Average Weekly Coffee Production");
44
+                output.writeEndElement();
45
+                output.writeStartElement("body");
46
+                output.writeTextElement("h1", "Recent Average Weekly Coffee Production");
47
+				switch(unitBox.currentIndex)
48
+				{
49
+					case 0:
50
+						output.writeTextElement("p", "This is a report of average weekly coffee production in kilograms over the past 28 days.");
51
+						break;
52
+					case 1:
53
+						output.writeTextElement("p", "This is a report of average weekly coffee production in pounds over the past 28 days.");
54
+						break;
55
+				}
56
+                output.writeStartElement("table");
57
+                output.writeAttribute("rules", "groups");
58
+                output.writeAttribute("cellpadding", "3px");
59
+                output.writeStartElement("thead");
60
+                output.writeStartElement("tr");
61
+                output.writeTextElement("th", "Roasted Coffee");
62
+                output.writeTextElement("th", "Weekly Use");
63
+                output.writeEndElement();
64
+                output.writeEndElement();
65
+                output.writeStartElement("tbody");
66
+				var q = "SELECT (SELECT name FROM items WHERE id = roasted_id) AS name, ((sum(roasted_quantity) / 4) / :conversion)::numeric(18,2) AS weekly FROM roasting_log WHERE time > current_date - integer '28' AND roasted_quantity > 0 GROUP BY roasted_id ORDER BY "
67
+                switch(sortBox.currentIndex)
68
+                {
69
+                    case 0:
70
+						q += "name ASC";
71
+                        break;
72
+                    case 1:
73
+						q += "name DESC";
74
+						break;
75
+                    case 2:
76
+						q += "weekly ASC";
77
+						break;
78
+                    case 3:
79
+						q += "weekly DESC";
80
+						break;
81
+                }
82
+				var query = new QSqlQuery();
83
+				query.prepare(q);
84
+				switch(unitBox.currentIndex)
85
+				{
86
+					case 0:
87
+						query.bind(":conversion", 2.2);
88
+						break;
89
+					case 1:
90
+						query.bind(":conversion", 1);
91
+						break;
92
+				}
93
+                query.exec();
94
+                while(query.next())
95
+                {
96
+                    output.writeStartElement("tr");
97
+                    output.writeTextElement("td", query.value(0));
98
+                    output.writeTextElement("td", query.value(1));
99
+                    output.writeEndElement();
100
+                }
101
+                output.writeEndElement();
102
+                output.writeStartElement("tfoot")
103
+                output.writeTextElement("th", "Total");
104
+                query.prepare("SELECT (sum(roasted_quantity) / 4 / :conversion)::numeric(18,2) FROM roasting_log WHERE time > current_date - integer '28' AND roasted_quantity > 0");
105
+                switch(unitBox.currentIndex)
106
+				{
107
+					case 0:
108
+						query.bind(":conversion", 2.2);
109
+						break;
110
+					case 1:
111
+						query.bind(":conversion", 1);
112
+						break;
113
+				}
114
+				query.exec();
115
+				query.next();
116
+                output.writeTextElement("td", query.value(0));
117
+                output.writeEndElement();
118
+                output.writeEndElement();
119
+                output.writeEndElement();
120
+                output.writeEndElement();
121
+                output.writeEndDocument();
122
+                report.setContent(buffer);
123
+                buffer.close();
124
+            }
125
+            refresh();
126
+            sortBox['currentIndexChanged(int)'].connect(function() {
127
+                QSettings.setValue("rwacp_sort", sortBox.currentIndex);
128
+                refresh();
129
+            });
130
+			unitBox['currentIndexChanged(int)'].connect(function() {
131
+				QSettings.setValue("script/report_unit", unitBox.currentIndex);
132
+				refresh();
133
+			});
134
+        ]]>
135
+    </program>
136
+</window>

+ 178
- 0
config/Windows/batchdetails.xml View File

@@ -0,0 +1,178 @@
1
+<window id="batchDetails">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Time:</label>
5
+            <line editable="false" id="time" />
6
+        </layout>
7
+        <layout type="horizontal">
8
+            <label>Name:</label>
9
+            <line editable="false" id="name" />
10
+        </layout>
11
+        <layout type="horizontal">
12
+            <label>Green:</label>
13
+            <line editable="false" id="green" />
14
+        </layout>
15
+        <layout type="horizontal">
16
+            <label>Roasted:</label>
17
+            <line editable="false" id="roasted" />
18
+        </layout>
19
+        <layout type="horizontal">
20
+            <label>Duration:</label>
21
+            <line editable="false" id="duration" />
22
+        </layout>
23
+        <layout type="horizontal">
24
+            <label>Approval:</label>
25
+            <line editable="false" id="approval" />
26
+        </layout>
27
+        <layout type="horizontal">
28
+            <label>Files:</label>
29
+			<line id="files" />
30
+		</layout>
31
+        <layout type="vertical">
32
+            <button type="push" id="target" name="Load profile as target" />
33
+            <button type="push" id="view" name="View profile" />
34
+            <button type="push" id="compare" name="Compare profile" />
35
+        </layout>
36
+    </layout>
37
+    <program>
38
+        <![CDATA[
39
+			var widget = this;
40
+			var target = findChildObject(this, 'target');
41
+			var batchTime = findChildObject(this, 'time');
42
+			var filesfield = findChildObject(this, 'files');
43
+            var compare = findChildObject(this, 'compare');
44
+			if(typeof(navigationwindow.loggingWindow) == "undefined")
45
+			{
46
+				compare.enabled = false;
47
+				target.enabled = false;
48
+			}
49
+            compare.clicked.connect(function() {
50
+                files = filesfield.text;
51
+                files = files.replace("{", "(");
52
+                files = files.replace("}", ")");
53
+                var q = "SELECT file, name FROM files WHERE id IN ";
54
+                q = q + files;
55
+                q = q + " AND type = 'profile'";
56
+                query = new QSqlQuery();
57
+                query.exec(q);
58
+                query.next();
59
+                var buffer = new QBuffer(query.value(0));
60
+                var pname = query.value(1);
61
+                query = query.invalidate();
62
+                var startSeries = Number(QSettings.value('cseries', 3));
63
+                var nextSeries = startSeries + 2;
64
+                QSettings.setValue('cseries', nextSeries);
65
+                var input = new XMLInput(buffer, startSeries);
66
+                var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
67
+                input.measure.connect(graph.newMeasurement);
68
+                input.input();
69
+            });
70
+			target.clicked.connect(function() {
71
+				files = filesfield.text;
72
+				files = files.replace("{", "(");
73
+				files = files.replace("}", ")");
74
+				var q = "SELECT file, name FROM files WHERE id IN ";
75
+				q = q + files;
76
+				q = q + " AND type = 'profile'";
77
+				query = new QSqlQuery();
78
+				query.exec(q);
79
+				query.next();
80
+				var targetseries = -1;
81
+				var buffer = new QBuffer(query.value(0));
82
+				var pname = query.value(1);
83
+                query = query.invalidate();
84
+				var input = new XMLInput(buffer, 1);
85
+				var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
86
+				var log = findChildObject(navigationwindow.loggingWindow, 'log');
87
+				log.clear();
88
+				graph.clear();
89
+				input.newTemperatureColumn.connect(log.setHeaderData);
90
+				input.newTemperatureColumn.connect(function(col, text) {
91
+					if(text == navigationwindow.loggingWindow.targetcolumnname)
92
+					{
93
+						targetseries = col;
94
+					}
95
+				});
96
+				input.newAnnotationColumn.connect(log.setHeaderData);
97
+				input.measure.connect(graph.newMeasurement);
98
+				input.measure.connect(log.newMeasurement);
99
+				input.measure.connect(function(data, series) {
100
+					if(series == targetseries)
101
+					{
102
+						targetDetector.newMeasurement(data);
103
+					}
104
+				});
105
+				var lc;
106
+				input.lastColumn.connect(function(c) {
107
+					lc = c;
108
+					QSettings.setValue("liveColumn", c + 1);
109
+					navigationwindow.loggingWindow.postLoadColumnSetup(c);
110
+				});
111
+				input.annotation.connect(log.newAnnotation);
112
+				input.annotation.connect(function(note, tcol, ncol) {
113
+					for(var i = tcol; i < ncol; i++) {
114
+						log.newAnnotation(note, i, ncol);
115
+					}
116
+				});
117
+				navigationwindow.loggingWindow.windowTitle = "Typica - " + pname;
118
+				navigationwindow.loggingWindow.raise();
119
+				navigationwindow.loggingWindow.activateWindow();
120
+				input.input();
121
+				log.newAnnotation("End", 1, lc);
122
+			});
123
+			var viewbutton = findChildObject(this, 'view');
124
+			viewbutton.clicked.connect(function() {
125
+				files = filesfield.text;
126
+				files = files.replace("{", "(");
127
+				files = files.replace("}", ")");
128
+				var q = "SELECT file, name FROM files WHERE id IN ";
129
+				q = q + files;
130
+				q = q + " AND type = 'profile'";
131
+				query = new QSqlQuery();
132
+				query.exec(q);
133
+				if(query.next()) {
134
+					var viewer = createWindow('offline');
135
+					var buffer = new QBuffer(query.value(0));
136
+					var pname = query.value(1);
137
+					query = query.invalidate();
138
+					var input = new XMLInput(buffer, 1);
139
+					var graph = findChildObject(viewer, 'graph');
140
+					var log = findChildObject(viewer, 'log');
141
+					input.newTemperatureColumn.connect(log.setHeaderData);
142
+					input.newTemperatureColumn.connect(function(column) {
143
+						viewer.saveTemperatureColumns.push(column);
144
+					});
145
+					input.newAnnotationColumn.connect(log.setHeaderData);
146
+					input.newAnnotationColumn.connect(function(column) {
147
+						viewer.saveAnnotationColumns.push(column);
148
+					});
149
+					input.measure.connect(graph.newMeasurement);
150
+					input.measure.connect(log.newMeasurement);
151
+					input.annotation.connect(log.newAnnotation);
152
+					var lc;
153
+					input.lastColumn.connect(function(c) {
154
+						lc = c;
155
+						if(c < 3)
156
+						{
157
+							log.setHeaderData(3, "");
158
+						}
159
+					});
160
+					input.annotation.connect(function(note, tcol, ncol) {
161
+						for(var i = tcol; i < ncol; i++) {
162
+							log.newAnnotation(note, i, ncol);
163
+						}
164
+					});
165
+					viewer.windowTitle = "Typica - " + pname;
166
+					viewer.raise();
167
+					viewer.activateWindow();
168
+					input.input();
169
+					log.newAnnotation("End", 1, lc);
170
+				}
171
+				else {
172
+					print("Query returned no results");
173
+				}
174
+				query = query.invalidate();
175
+            });
176
+        ]]>
177
+    </program>
178
+</window>

+ 313
- 0
config/Windows/batchdetailsnew.xml View File

@@ -0,0 +1,313 @@
1
+<window id="batchDetails">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <button type="push" id="target" name="Load profile as target" />
5
+			<button type="push" id="viewprofile" name="View profile" />
6
+			<button type="push" id="compare" name="Compare profile" />
7
+        </layout>
8
+        <webview id="view" />
9
+    </layout>
10
+    <program>
11
+        <![CDATA[
12
+			var window = this;
13
+			dataView = findChildObject(this, 'view');
14
+			var fileID;
15
+			var target = findChildObject(this, 'target');
16
+			var compare = findChildObject(this, 'compare');
17
+			if(typeof(navigationwindow.loggingWindow) == "undefined") {
18
+				compare.enabled = false;
19
+				target.enabled = false;
20
+			}
21
+			compare.clicked.connect(function() {
22
+				var query = new QSqlQuery;
23
+				query.prepare("SELECT file, name FROM files WHERE id = :id");
24
+				query.bind(":id", Number(fileID));
25
+				query.exec();
26
+				query.next();
27
+				var buffer = new QBuffer(query.value(0));
28
+                var pname = query.value(1);
29
+                query = query.invalidate();
30
+                var startSeries = Number(QSettings.value('cseries', 3));
31
+                var nextSeries = startSeries + 2;
32
+                QSettings.setValue('cseries', nextSeries);
33
+                var input = new XMLInput(buffer, startSeries);
34
+                var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
35
+                input.measure.connect(graph.newMeasurement);
36
+                input.input();
37
+				query = query.invalidate();
38
+			});
39
+			target.clicked.connect(function() {
40
+				var query = new QSqlQuery;
41
+				query.prepare("SELECT file, name FROM files WHERE id = :id");
42
+				query.bind(":id", Number(fileID));
43
+				query.exec();
44
+				query.next();
45
+				var buffer = new QBuffer(query.value(0));
46
+				var pname = query.value(1);
47
+                query = query.invalidate();
48
+				var input = new XMLInput(buffer, 1);
49
+				var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
50
+				var log = findChildObject(navigationwindow.loggingWindow, 'log');
51
+				log.clear();
52
+				graph.clear();
53
+				input.newTemperatureColumn.connect(log.setHeaderData);
54
+				input.newTemperatureColumn.connect(function(col, text) {
55
+					if(text == navigationwindow.loggingWindow.targetcolumnname)
56
+					{
57
+						targetseries = col;
58
+					}
59
+				});
60
+				input.newAnnotationColumn.connect(log.setHeaderData);
61
+				input.measure.connect(graph.newMeasurement);
62
+				input.measure.connect(log.newMeasurement);
63
+				input.measure.connect(function(data, series) {
64
+					if(series == targetseries)
65
+					{
66
+						targetDetector.newMeasurement(data);
67
+					}
68
+				});
69
+				var lc;
70
+				input.lastColumn.connect(function(c) {
71
+					lc = c;
72
+					QSettings.setValue("liveColumn", c + 1);
73
+					navigationwindow.loggingWindow.postLoadColumnSetup(c);
74
+				});
75
+				input.annotation.connect(log.newAnnotation);
76
+				input.annotation.connect(function(note, tcol, ncol) {
77
+					for(var i = tcol; i < ncol; i++) {
78
+						log.newAnnotation(note, i, ncol);
79
+					}
80
+				});
81
+				navigationwindow.loggingWindow.windowTitle = "Typica - " + pname;
82
+				navigationwindow.loggingWindow.raise();
83
+				navigationwindow.loggingWindow.activateWindow();
84
+				input.input();
85
+				log.newAnnotation("End", 1, lc);
86
+				query = query.invalidate();
87
+			});
88
+			var viewbutton = findChildObject(this, 'viewprofile');
89
+			viewbutton.clicked.connect(function() {
90
+				var query = new QSqlQuery;
91
+				query.prepare("SELECT file, name FROM files WHERE id = :id");
92
+				query.bind(":id", Number(fileID));
93
+				query.exec();
94
+				if(query.next()) {
95
+					var viewer = createWindow('offline');
96
+					var buffer = new QBuffer(query.value(0));
97
+					var pname = query.value(1);
98
+					query = query.invalidate();
99
+					var input = new XMLInput(buffer, 1);
100
+					var graph = findChildObject(viewer, 'graph');
101
+					var log = findChildObject(viewer, 'log');
102
+					input.newTemperatureColumn.connect(log.setHeaderData);
103
+					input.newTemperatureColumn.connect(function(column) {
104
+						viewer.saveTemperatureColumns.push(column);
105
+					});
106
+					input.newAnnotationColumn.connect(log.setHeaderData);
107
+					input.newAnnotationColumn.connect(function(column) {
108
+						viewer.saveAnnotationColumns.push(column);
109
+					});
110
+					input.measure.connect(graph.newMeasurement);
111
+					input.measure.connect(log.newMeasurement);
112
+					input.annotation.connect(log.newAnnotation);
113
+					var lc;
114
+					input.lastColumn.connect(function(c) {
115
+						lc = c;
116
+						if(c < 3)
117
+						{
118
+							log.setHeaderData(3, "");
119
+						}
120
+					});
121
+					input.annotation.connect(function(note, tcol, ncol) {
122
+						for(var i = tcol; i < ncol; i++) {
123
+							log.newAnnotation(note, i, ncol);
124
+						}
125
+					});
126
+					viewer.windowTitle = "Typica - " + pname;
127
+					viewer.raise();
128
+					viewer.activateWindow();
129
+					input.input();
130
+					log.newAnnotation("End", 1, lc);
131
+				}
132
+				else {
133
+					print("Query returned no results");
134
+				}
135
+				query = query.invalidate();
136
+			});
137
+			window.loadData = function(table, row) {
138
+				var buffer = new QBuffer;
139
+				buffer.open(3);
140
+				var output = new XmlWriter(buffer);
141
+				output.writeStartDocument("1.0");
142
+				output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
143
+				output.writeStartElement("html");
144
+				output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
145
+				output.writeStartElement("head");
146
+				output.writeTextElement("title", "Batch Details");
147
+				output.writeEndElement();
148
+				output.writeStartElement("body");
149
+				output.writeStartElement("div");
150
+				output.writeAttribute("style", "float: left; padding-right: 10px");
151
+				output.writeStartElement("p");
152
+				output.writeTextElement("strong", "Roasted Coffee: ");
153
+				output.writeTextElement("span", table.data(row, 2));
154
+				output.writeEndElement();
155
+				output.writeEndElement();
156
+				output.writeStartElement("div");
157
+				output.writeAttribute("style", "float: left");
158
+				output.writeStartElement("p");
159
+				output.writeTextElement("strong", "Roasted On: ");
160
+				output.writeTextElement("span", table.data(row, 0));
161
+				output.writeEndElement();
162
+				output.writeStartElement("p");
163
+				output.writeTextElement("strong", "Batch Duration: ");
164
+				output.writeTextElement("span", table.data(row, 6));
165
+				output.writeEndElement();
166
+				output.writeEndElement();
167
+				output.writeStartElement("div");
168
+				output.writeAttribute("style", "clear: both");
169
+				output.writeEndElement();
170
+				output.writeStartElement("table");
171
+				output.writeStartElement("thead");
172
+				output.writeStartElement("tr");
173
+				output.writeTextElement("th", "Green Coffee");
174
+				output.writeTextElement("th", "Weight (lb)");
175
+				output.writeEndElement();
176
+				output.writeEndElement();
177
+				output.writeStartElement("tbody");
178
+				var query = new QSqlQuery();
179
+				query.prepare("SELECT unroasted_id, unroasted_quantity, approval, files, annotation FROM roasting_log WHERE time = :time AND machine = :machine");
180
+				query.bind(":time", table.data(row, 0));
181
+				query.bind(":machine", table.data(row, 1));
182
+				query.exec();
183
+				query.next();
184
+				var items = sqlToArray(query.value(0));
185
+				var quantities = sqlToArray(query.value(1));
186
+				var nameQuery = new QSqlQuery();
187
+				nameQuery.prepare("SELECT name FROM items WHERE id = :id");
188
+				for(var i = 0; i < items.length; i++) {
189
+					output.writeStartElement("tr");
190
+					nameQuery.bind(":id", items[i]);
191
+					nameQuery.exec();
192
+					nameQuery.next();
193
+					output.writeTextElement("td", nameQuery.value(0));
194
+					output.writeStartElement("td");
195
+					output.writeAttribute("align", "center");
196
+					output.writeCharacters(quantities[i]);
197
+					output.writeEndElement();
198
+					output.writeEndElement();
199
+				}
200
+				nameQuery = nameQuery.invalidate();
201
+				output.writeEndElement();
202
+				output.writeStartElement("tfoot");
203
+				output.writeStartElement("tr");
204
+				output.writeStartElement("td");
205
+				output.writeAttribute("align", "right");
206
+				output.writeTextElement("strong", "Green Total:");
207
+				output.writeEndElement();
208
+				output.writeStartElement("td");
209
+				output.writeAttribute("align", "center");
210
+				output.writeCharacters(table.data(row, 3));
211
+				output.writeEndElement();
212
+				output.writeEndElement();
213
+				output.writeStartElement("tr");
214
+				output.writeStartElement("td");
215
+				output.writeAttribute("align", "right");
216
+				output.writeTextElement("strong", "Roasted Weight:");
217
+				output.writeEndElement();
218
+				output.writeStartElement("td");
219
+				output.writeAttribute("align", "center");
220
+				output.writeCharacters(table.data(row, 4));
221
+				output.writeEndElement();
222
+				output.writeEndElement();
223
+				output.writeStartElement("tr");
224
+				output.writeStartElement("td");
225
+				output.writeAttribute("align", "right");
226
+				output.writeTextElement("strong", "Weight Loss:");
227
+				output.writeEndElement();
228
+				output.writeStartElement("td");
229
+				output.writeAttribute("align", "center");
230
+				output.writeCharacters(table.data(row, 5));
231
+				output.writeCharacters("%");
232
+				output.writeEndElement();
233
+				output.writeEndElement();
234
+				output.writeEndElement();
235
+				output.writeEndElement();
236
+				output.writeStartElement("p");
237
+				output.writeTextElement("strong", "Approved: ");
238
+				output.writeCharacters(query.value(2));
239
+				output.writeEndElement();
240
+				output.writeStartElement("p");
241
+				output.writeTextElement("strong", "Files: ");
242
+				output.writeCharacters(query.value(3));				output.writeEndElement();
243
+				output.writeStartElement("p");
244
+				output.writeTextElement("strong", "Annotations:");
245
+				var files = sqlToArray(query.value(3));
246
+				var annotations = annotationFromRecord(files[0]);
247
+				fileID = files[0];
248
+				var buffer2 = new QBuffer("<points>"+annotations+"</points>");
249
+				buffer2.open(1);
250
+				var colQuery = new XQuery;
251
+				colQuery.bind("profile", buffer2);
252
+				colQuery.setQuery('for $i in doc($profile)//tuple[1]/temperature/@series return (string($i), ";")');
253
+				var result = colQuery.exec();
254
+				buffer2.close();
255
+				var seriesHeaders = new Array();
256
+				seriesHeaders.push("Time");
257
+				var records = result.split(";");
258
+				for(var i = 0; i < records.length - 1; i++) {
259
+					seriesHeaders.push(records[i].replace(/^\s+|\s+$/g,""));
260
+				}
261
+				seriesHeaders.push("Note");
262
+				output.writeStartElement("table");
263
+				output.writeStartElement("thead");
264
+				output.writeStartElement("tr");
265
+				for(var i = 0; i < seriesHeaders.length; i++) {
266
+					output.writeTextElement("th", seriesHeaders[i]);
267
+				}
268
+				output.writeEndElement();
269
+				output.writeEndElement();
270
+				buffer2.open(1);
271
+				var rq = 'for $t in doc($profile) //tuple return (string($t/time), ";", ';
272
+				for(var i = 0; i < seriesHeaders.length - 2; i++) {
273
+					rq = rq + 'string($t/temperature[' + Number(i+1) + ']), ";", ';
274
+				}
275
+				rq = rq + 'string($t/annotation), "~")';
276
+				colQuery.setQuery(rq);
277
+				var annotationData = colQuery.exec();
278
+				buffer2.close();
279
+				output.writeStartElement("tbody");
280
+				var annotationRecords = annotationData.split("~");
281
+				for(var i = 0; i < annotationRecords.length - 1; i++) {
282
+					output.writeStartElement("tr");
283
+					var annotationRow = annotationRecords[i].split(";");
284
+					for(var j = 0; j < annotationRow.length; j++) {
285
+						output.writeStartElement("td");
286
+						output.writeAttribute("style", "border-left: 1px solid #000000");
287
+						if(j > 0) {
288
+							output.writeAttribute("align", "center");
289
+						}
290
+						if(j > 0 && j < annotationRow.length - 1) {
291
+							output.writeCharacters(Number(annotationRow[j].replace(/^\s+|\s+$/g,"")).toFixed(2));
292
+						}
293
+						else {
294
+							output.writeCharacters(annotationRow[j].replace(/^\s+|\s+$/g,""));
295
+						}
296
+						output.writeEndElement();
297
+					}
298
+					output.writeEndElement();
299
+				}
300
+				output.writeEndElement();
301
+				output.writeEndElement();
302
+				output.writeCharacters(query.value(4));
303
+				output.writeEndElement();
304
+				output.writeEndElement();
305
+				output.writeEndElement();
306
+				output.writeEndDocument();
307
+				dataView.setContent(buffer);
308
+				buffer.close();
309
+				query = query.invalidate();
310
+			};
311
+        ]]>
312
+    </program>
313
+</window>

+ 470
- 0
config/Windows/cuppingform.xml View File

@@ -0,0 +1,470 @@
1
+<window id="cuppingform">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Grader:</label>
5
+            <line id="grader" />
6
+            <label>Session:</label>
7
+            <line id="session" writable="false" />
8
+            <label>Event:</label>
9
+            <line id="event" writable="false" />
10
+        </layout>
11
+        <formarray id="form">
12
+            <layout type="grid">
13
+                <row>
14
+                    <column><label>Sample ID</label></column>
15
+                    <column><label>Notes</label></column>
16
+                    <column rowspan="5">
17
+                        <layout type="stack" id="attributes">
18
+                            <page>
19
+                                <layout type="grid">
20
+                                    <row>
21
+                                        <column>
22
+                                            <layout type="vertical">
23
+                                                <label>Aroma</label>
24
+                                                <layout type="horizontal">
25
+                                                    <hscale id="aroma" />
26
+                                                    <spinbox min="0" max="10" decimals="2" step="0.01" id="aromabox" />
27
+                                                </layout>
28
+                                                <layout type="horizontal">
29
+                                                    <layout type="vertical">
30
+                                                        <label>Dry</label>
31
+                                                        <vscale id="dry" />
32
+                                                    </layout>
33
+                                                    <layout type="vertical">
34
+                                                        <label>Break</label>
35
+                                                        <vscale id="break" />
36
+                                                    </layout>
37
+                                                    <layout type="vertical">
38
+                                                        <label>Aroma Notes</label>
39
+                                                        <textarea id="aromanotes" />
40
+                                                    </layout>
41
+                                                </layout>
42
+                                            </layout>
43
+                                        </column>
44
+                                        <column stretch="100">
45
+                                            <label></label>
46
+                                        </column>
47
+                                    </row>
48
+                                </layout>
49
+                            </page>
50
+                            <page>
51
+                                <layout type="grid">
52
+                                    <row>
53
+                                        <column><label>Flavor</label></column>
54
+                                        <column><label>Acidity</label></column>
55
+                                        <column><label>Body</label></column>
56
+                                    </row>
57
+                                    <row>
58
+                                        <column>
59
+                                            <layout type="horizontal">
60
+                                                <hscale id="flavor" />
61
+                                                <spinbox min="0" max="10" decimals="2" step="0.01" id="flavorbox" />
62
+                                            </layout>
63
+                                        </column>
64
+                                        <column>
65
+                                            <layout type="horizontal">
66
+                                                <hscale id="acidity" />
67
+                                                <spinbox min="0" max="10" decimals="2" step="0.01" id="aciditybox" />
68
+                                            </layout>
69
+                                        </column>
70
+                                        <column>
71
+                                            <layout type="horizontal">
72
+                                                <hscale id="body" />
73
+                                                <spinbox min="0" max="10" decimals="2" step="0.01" id="bodybox" />
74
+                                            </layout>
75
+                                        </column>
76
+                                    </row>
77
+                                    <row>
78
+                                        <column column="1">
79
+                                            <layout type="vertical">
80
+                                                <label>Intensity</label>
81
+                                                <layout type="horizontal">
82
+                                                    <vscale id="acidityintensity" />
83
+                                                    <layout type="vertical">
84
+                                                        <label>Acidity Notes</label>
85
+                                                        <textarea id="aciditynotes" />
86
+                                                    </layout>
87
+                                                </layout>
88
+                                            </layout>
89
+                                        </column>
90
+                                        <column>
91
+                                            <layout type="vertical">
92
+                                                <label>Level</label>
93
+                                                <layout type="horizontal">
94
+                                                    <vscale id="bodylevel" />
95
+                                                    <layout type="vertical">
96
+                                                        <label>Body Notes</label>
97
+                                                        <textarea id="bodynotes" />
98
+                                                    </layout>
99
+                                                </layout>
100
+                                            </layout>
101
+                                        </column>
102
+                                    </row>
103
+                                </layout>
104
+                            </page>
105
+                            <page>
106
+                                <layout type="grid">
107
+                                    <row>
108
+                                        <column><label>Balance</label></column>
109
+                                        <column><label>Aftertaste</label></column>
110
+                                        <column><label>Overall</label></column>
111
+                                    </row>
112
+                                    <row>
113
+                                        <column>
114
+                                            <layout type="horizontal">
115
+                                                <hscale id="balance" />
116
+                                                <spinbox min="0" max="10" decimals="2" step="0.01" id="balancebox" />
117
+                                            </layout>
118
+                                        </column>
119
+                                        <column>
120
+                                            <layout type="horizontal">
121
+                                                <hscale id="aftertaste" />
122
+                                                <spinbox min="0" max="10" decimals="2" step="0.01" id="aftertastebox" />
123
+                                            </layout>
124
+                                        </column>
125
+                                        <column>
126
+                                            <layout type="horizontal">
127
+                                                <hscale id="overall" />
128
+                                                <spinbox min="0" max="10" decimals="2" step = "0.01" id="overallbox" />
129
+                                            </layout>
130
+                                        </column>
131
+                                    </row>
132
+                                    <row>
133
+                                        <column>
134
+                                            <textarea id="balancenotes" />
135
+                                        </column>
136
+                                        <column>
137
+                                            <textarea id="aftertastenotes" />
138
+                                        </column>
139
+                                    </row>
140
+                                </layout>
141
+                            </page>
142
+                            <page>
143
+                                <layout type="grid">
144
+                                    <row>
145
+                                        <column><label>Uniformity</label></column>
146
+                                        <column><label>Clean Cup</label></column>
147
+                                        <column><label>Sweetness</label></column>
148
+                                    </row>
149
+                                    <row>
150
+                                        <column>
151
+                                            <layout type="horizontal">
152
+                                                <button type="check" id="u1" name="" />
153
+                                                <button type="check" id="u2" name="" />
154
+                                                <button type="check" id="u3" name="" />
155
+                                                <button type="check" id="u4" name="" />
156
+                                                <button type="check" id="u5" name="" />
157
+                                                <spinbox min="0" max="10" decimals="2" step="0.1" id="uniformity" />
158
+                                            </layout>
159
+                                        </column>
160
+                                        <column>
161
+                                            <layout type="horizontal">
162
+                                                <button type="check" id="c1" name="" />
163
+                                                <button type="check" id="c2" name="" />
164
+                                                <button type="check" id="c3" name="" />
165
+                                                <button type="check" id="c4" name="" />
166
+                                                <button type="check" id="c5" name="" />
167
+                                                <spinbox min="0" max="10" decimals="2" step="0.1" id="cleancup" />
168
+                                            </layout>
169
+                                        </column>
170
+                                        <column>
171
+                                            <layout type="horizontal">
172
+                                                <button type="check" id="s1" name="" />
173
+                                                <button type="check" id="s2" name="" />
174
+                                                <button type="check" id="s3" name="" />
175
+                                                <button type="check" id="s4" name="" />
176
+                                                <button type="check" id="s5" name="" />
177
+                                                <spinbox min="0" max="10" decimals="2" step="0.1" id="sweetness" />
178
+                                            </layout>
179
+                                        </column>
180
+                                    </row>
181
+                                    <row>
182
+                                        <column>
183
+                                            <textarea id="uniformityNotes" />
184
+                                        </column>
185
+                                    </row>
186
+                                </layout>
187
+                            </page>
188
+                        </layout>
189
+                    </column>
190
+                    <column><label>Total Score</label></column>
191
+                    <column>
192
+                        <spinbox decimals="2" step="0.01" min="0" max="100" id="totalscore" />
193
+                    </column>
194
+                </row>
195
+                <row>
196
+                    <column><line id="sampleID" writable="false" /></column>
197
+                    <column rowspan="4"><textarea id="notes" /></column>
198
+                    <column column="3"><label>Taints</label></column>
199
+                    <column>
200
+                        <spinbox decimals="0" step="1" id="taints" />
201
+                    </column>
202
+                </row>
203
+                <row>
204
+                    <column column="3"><label>Faults</label></column>
205
+                    <column>
206
+                        <spinbox decimals="0" step="1" id="faults" />
207
+                    </column>
208
+                </row>
209
+                <row>
210
+                    <column column="3"><label>Final Score</label></column>
211
+                    <column>
212
+                        <spinbox decimals="2" step="0.01" min="-20" max="100" id="finalscore" />
213
+                    </column>
214
+                </row>
215
+            </layout>
216
+        </formarray>
217
+        <button type="push" id="submit" name="Submit" />
218
+    </layout>
219
+    <menu name="File">
220
+        <item id="quit" shortcut="Ctrl+Q">Quit</item>
221
+    </menu>
222
+    <menu name="Sections">
223
+        <item id="p1" shortcut="Ctrl+1">Aroma</item>
224
+        <item id="p2" shortcut="Ctrl+2">Flavor, Acidity, Body</item>
225
+        <item id="p3" shortcut="Ctrl+3">Balance, Aftertaste, Overall</item>
226
+        <item id="p4" shortcut="Ctrl+4">Uniformity, Clean Cup, Sweetness</item>
227
+        <item id="next" shortcut="Ctrl+=">Next Section</item>
228
+        <item id="prev" shortcut="Ctrl+-">Previous Section</item>
229
+    </menu>
230
+    <program>
231
+        <![CDATA[
232
+            var window = this;
233
+            var form = findChildObject(this, 'form')
234
+            var m1 = findChildObject(this, 'p1');
235
+            var m2 = findChildObject(this, 'p2');
236
+            var m3 = findChildObject(this, 'p3');
237
+            var m4 = findChildObject(this, 'p4');
238
+            var mnext = findChildObject(this, 'next');
239
+            var mprev = findChildObject(this, 'prev');
240
+            m1.triggered.connect(function() {
241
+                for(var i = 0; i < form.elements(); i++)
242
+                {
243
+                    var section = findChildObject(form.elementAt(i), 'attributes');
244
+                    section.setCurrentIndex(0);
245
+                }
246
+            });
247
+            m2.triggered.connect(function() {
248
+                for(var i = 0; i < form.elements(); i++)
249
+                {
250
+                    var section = findChildObject(form.elementAt(i), 'attributes');
251
+                    section.setCurrentIndex(1);
252
+                }
253
+            });
254
+            m3.triggered.connect(function() {
255
+                for(var i = 0; i < form.elements(); i++)
256
+                {
257
+                    var section = findChildObject(form.elementAt(i), 'attributes');
258
+                    section.setCurrentIndex(2);
259
+                }
260
+            });
261
+            m4.triggered.connect(function() {
262
+                for(var i = 0; i < form.elements(); i++)
263
+                {
264
+                    var section = findChildObject(form.elementAt(i), 'attributes');
265
+                    section.setCurrentIndex(3);
266
+                }
267
+            });
268
+            mnext.triggered.connect(function() {
269
+                for(var i = 0; i < form.elements(); i++)
270
+                {
271
+                    var section = findChildObject(form.elementAt(i), 'attributes');
272
+                    section.setCurrentIndex((section.currentIndex + 1) % 4);
273
+                }
274
+            });
275
+            mprev.triggered.connect(function() {
276
+                for(var i = 0; i < form.elements(); i++)
277
+                {
278
+                    var section = findChildObject(form.elementAt(i), 'attributes');
279
+                    section.setCurrentIndex((section.currentIndex + 3) % 4);
280
+                }
281
+            });
282
+            var quitMenu = findChildObject(this, 'quit');
283
+            quitMenu.triggered.connect(function() {
284
+                window.close();
285
+                Application.quit();
286
+            });
287
+            var submit = findChildObject(this, 'submit');
288
+            var grader = findChildObject(this, 'grader');
289
+            var session = findChildObject(this, 'session');
290
+            submit.clicked.connect(function() {
291
+                for(var i = 0; i < form.elements(); i++)
292
+                {
293
+                    var sampleBox = findChildObject(form.elementAt(i), 'sampleID');
294
+                    var outfile = new QBuffer("");
295
+                    outfile.open(3);
296
+                    var output = new XmlWriter(outfile);
297
+                    output.writeStartDocument("1.0");
298
+                    output.writeDTD("<!DOCTYPE cuppingsession>");
299
+                    output.writeStartElement("session");
300
+                    output.writeAttribute("samples", "1");
301
+                    output.writeAttribute("formtype", "T1");
302
+                    output.writeStartElement("grader");
303
+                    output.writeCDATA(grader.text);
304
+                    output.writeEndElement();
305
+                    output.writeStartElement("form");
306
+                    var aromaScale = findChildObject(form.elementAt(i), 'aroma');
307
+                    output.writeStartElement("attribute");
308
+                    output.writeAttribute("name", "aroma");
309
+                    output.writeAttribute("initial", aromaScale.initialValue);
310
+                    var aromaBox = findChildObject(form.elementAt(i), 'aromabox');
311
+                    output.writeAttribute("value", aromaBox.cleanText);
312
+                    output.writeEmptyElement("qualifier");
313
+                    output.writeAttribute("name", "dry");
314
+                    var dryScale = findChildObject(form.elementAt(i), 'dry');
315
+                    output.writeAttribute("value", dryScale.value);
316
+                    output.writeEmptyElement("qualifier");
317
+                    var breakScale = findChildObject(form.elementAt(i), 'break');
318
+                    output.writeAttribute("name", "break");
319
+                    output.writeAttribute("value", breakScale.value);
320
+                    output.writeStartElement("notes");
321
+                    var aromaNotes = findChildObject(form.elementAt(i), 'aromanotes');
322
+                    output.writeCDATA(aromaNotes.plainText);
323
+                    output.writeEndElement();
324
+                    output.writeEndElement();
325
+                    output.writeStartElement("attribute");
326
+                    output.writeAttribute("name", "flavor");
327
+                    var flavorScale = findChildObject(form.elementAt(i), 'flavor');
328
+                    output.writeAttribute("initial", flavorScale.initialValue);
329
+                    var flavorBox = findChildObject(form.elementAt(i), 'flavorbox');
330
+                    output.writeAttribute("value", flavorBox.cleanText);
331
+                    output.writeEndElement();
332
+                    output.writeStartElement("attribute");
333
+                    output.writeAttribute("name", "acidity");
334
+                    var acidityScale = findChildObject(form.elementAt(i), 'acidity');
335
+                    output.writeAttribute("initial", acidityScale.initialValue);
336
+                    var acidityBox = findChildObject(form.elementAt(i), 'aciditybox');
337
+                    output.writeAttribute("value", acidityBox.cleanText);
338
+                    output.writeStartElement("qualifier");
339
+                    output.writeAttribute("name", "intensity");
340
+                    var intensityScale = findChildObject(form.elementAt(i), 'acidityintensity');
341
+                    output.writeAttribute("value", intensityScale.value);
342
+                    output.writeEndElement();
343
+                    output.writeStartElement("notes");
344
+                    var acidityNotes = findChildObject(form.elementAt(i), 'aciditynotes');
345
+                    output.writeCDATA(acidityNotes.plainText);
346
+                    output.writeEndElement();
347
+                    output.writeEndElement();
348
+                    output.writeStartElement("attribute");
349
+                    output.writeAttribute("name", "body");
350
+                    var bodyScale = findChildObject(form.elementAt(i), 'body');
351
+                    output.writeAttribute("initial", bodyScale.initialValue);
352
+                    var bodyBox = findChildObject(form.elementAt(i), 'bodybox');
353
+                    output.writeAttribute("value", bodyBox.cleanText);
354
+                    output.writeStartElement("qualifier");
355
+                    output.writeAttribute("name", "level");
356
+                    var levelScale = findChildObject(form.elementAt(i), 'bodylevel');
357
+                    output.writeAttribute("value", levelScale.value);
358
+                    output.writeEndElement();
359
+                    output.writeStartElement("notes");
360
+                    var bodyNotes = findChildObject(form.elementAt(i), 'bodynotes');
361
+                    output.writeCDATA(bodyNotes.plainText);
362
+                    output.writeEndElement();
363
+                    output.writeEndElement();
364
+                    output.writeStartElement("attribute");
365
+                    output.writeAttribute("name", "balance");
366
+                    var balanceScale = findChildObject(form.elementAt(i), 'balance');
367
+                    output.writeAttribute("initial", balanceScale.initialValue);
368
+                    var balanceBox = findChildObject(form.elementAt(i), 'balancebox');
369
+                    output.writeAttribute("value", balanceBox.cleanText);
370
+                    output.writeStartElement("notes")
371
+                    var balanceNotes = findChildObject(form.elementAt(i), 'balancenotes');
372
+                    output.writeCDATA(balanceNotes.plainText);
373
+                    output.writeEndElement();
374
+                    output.writeEndElement();
375
+                    output.writeStartElement("attribute");
376
+                    output.writeAttribute("name", "aftertaste");
377
+                    var aftertasteScale = findChildObject(form.elementAt(i), 'aftertaste');
378
+                    output.writeAttribute("initial", aftertasteScale.initialValue);
379
+                    var aftertasteBox = findChildObject(form.elementAt(i), 'aftertastebox');
380
+                    output.writeAttribute("value", aftertasteBox.cleanText);
381
+                    output.writeStartElement("notes");
382
+                    var aftertasteNotes = findChildObject(form.elementAt(i), 'aftertastenotes');
383
+                    output.writeCDATA(aftertasteNotes.plainText);
384
+                    output.writeEndElement();
385
+                    output.writeEndElement();
386
+                    output.writeStartElement("attribute");
387
+                    output.writeAttribute("name", "overall");
388
+                    var overallScale = findChildObject(form.elementAt(i), 'overall');
389
+                    output.writeAttribute("initial", overallScale.initialValue);
390
+                    var overallBox = findChildObject(form.elementAt(i), 'overallbox');
391
+                    output.writeAttribute("value", overallBox.cleanText);
392
+                    output.writeEndElement();
393
+                    output.writeStartElement("attribute");
394
+                    output.writeAttribute("name", "uniformity");
395
+                    var uniformityBox = findChildObject(form.elementAt(i), 'uniformity');
396
+                    output.writeAttribute("value", uniformityBox.cleanText);
397
+                    output.writeStartElement("notes");
398
+                    var uniformityNotes = findChildObject(form.elementAt(i), 'uniformityNotes');
399
+                    output.writeCDATA(uniformityNotes.plainText);
400
+                    output.writeEndElement();
401
+                    output.writeEndElement();
402
+                    output.writeStartElement("attribute");
403
+                    output.writeAttribute("name", "cleancup");
404
+                    var cleancupBox = findChildObject(form.elementAt(i), 'cleancup');
405
+                    output.writeAttribute("value", cleancupBox.cleanText);
406
+                    output.writeEndElement();
407
+                    output.writeStartElement("attribute");
408
+                    output.writeAttribute("name", "sweetness");
409
+                    var sweetnessBox = findChildObject(form.elementAt(i), 'sweetness');
410
+                    output.writeAttribute("value", sweetnessBox.cleanText);
411
+                    output.writeEndElement();
412
+                    output.writeStartElement("attribute");
413
+                    output.writeAttribute("name", "total");
414
+                    var totalBox = findChildObject(form.elementAt(i), 'totalscore');
415
+                    output.writeAttribute("value", totalBox.cleanText);
416
+                    output.writeEndElement();
417
+                    output.writeStartElement("attribute");
418
+                    output.writeAttribute("name", "taints");
419
+                    var taintBox = findChildObject(form.elementAt(i), 'taints');
420
+                    output.writeAttribute("value", taintBox.cleanText);
421
+                    output.writeEndElement();
422
+                    output.writeStartElement("attribute");
423
+                    output.writeAttribute("name", "faults");
424
+                    var faultBox = findChildObject(form.elementAt(i), 'faults');
425
+                    output.writeAttribute("value", faultBox.cleanText);
426
+                    output.writeEndElement();
427
+                    output.writeStartElement("attribute");
428
+                    output.writeAttribute("name", "final");
429
+                    var finalBox = findChildObject(form.elementAt(i), 'finalscore');
430
+                    output.writeAttribute("value", finalBox.cleanText);
431
+                    output.writeEndElement();
432
+                    output.writeStartElement("attribute");
433
+                    output.writeAttribute("name", "sample");
434
+                    output.writeAttribute("value", sampleBox.text);
435
+                    output.writeEndElement();
436
+                    output.writeStartElement("notes");
437
+                    var sampleNotes = findChildObject(form.elementAt(i), 'notes');
438
+                    output.writeCDATA(sampleNotes.plainText);
439
+                    output.writeEndElement();
440
+                    output.writeEndElement();
441
+                    output.writeEndElement();
442
+                    output.writeEndDocument();
443
+                    var q = "INSERT INTO cuppingform_t1 VALUES(:session, :sample, :position, :grader, :finalscore, :notes, :serialization, :aroma, :flavor, :aftertaste, :acidity, :body, :uniformity, :balance, :cleancup, :sweetness, :overall, :total)";
444
+                    var query = new QSqlQuery;
445
+                    query.prepare(q);
446
+                    query.bind(":session", Number(session.text));
447
+                    query.bind(":sample", sampleBox.text);
448
+                    query.bind(":position", i + 1);
449
+                    query.bind(":grader", grader.text);
450
+                    query.bind(":finalscore", Number(finalBox.cleanText));
451
+                    query.bind(":notes", sampleNotes.plainText);
452
+                    query.bindDeviceData(":serialization", outfile);
453
+                    query.bind(":aroma", Number(aromaBox.cleanText));
454
+                    query.bind(":flavor", Number(flavorBox.cleanText));
455
+                    query.bind(":aftertaste", Number(aftertasteBox.cleanText));
456
+                    query.bind(":acidity", Number(acidityBox.cleanText));
457
+                    query.bind(":body", Number(bodyBox.cleanText));
458
+                    query.bind(":uniformity", Number(uniformityBox.cleanText));
459
+                    query.bind(":balance", Number(balanceBox.cleanText));
460
+                    query.bind(":cleancup", Number(cleancupBox.cleanText));
461
+                    query.bind(":sweetness", Number(sweetnessBox.cleanText));
462
+                    query.bind(":overall", Number(overallBox.cleanText));
463
+                    query.bind(":total", Number(totalBox.cleanText));
464
+                    query.exec();
465
+                }
466
+                window.close();
467
+            });
468
+        ]]>
469
+    </program>
470
+</window>

+ 8
- 0
config/Windows/cuppingformsbysession.xml View File

@@ -0,0 +1,8 @@
1
+<window id="allforms">
2
+    <layout type="vertical">
3
+        <label>All forms in session:</label>
4
+        <sqlview id="data" />
5
+        <label>Average scores by sample:</label>
6
+        <sqlview id="averages" />
7
+    </layout>
8
+</window>

+ 61
- 0
config/Windows/cuppingitemselection.xml View File

@@ -0,0 +1,61 @@
1
+<window id="sampleitemselection">
2
+    <layout type="grid">
3
+        <row>
4
+            <column colspan="5">
5
+                <label>Add Existing Item to Cupping Session</label>
6
+            </column>
7
+        </row>
8
+        <row>
9
+            <column>
10
+                <label>Category:</label>
11
+            </column>
12
+            <column>
13
+                <sqldrop data="0" display="0" showdata="false" id="category">
14
+                    <query>SELECT DISTINCT category FROM items WHERE category LIKE 'Coffee:%'</query>
15
+                </sqldrop>
16
+            </column>
17
+            <column>
18
+                <label>Item:</label>
19
+            </column>
20
+            <column>
21
+                <sqldrop data="0" display="1" showdata="true" id="item" />
22
+            </column>
23
+            <column>
24
+                <button type="push" name="Add Item" id="additem" />
25
+            </column>
26
+        </row>
27
+        <row>
28
+            <column colspan="5">
29
+                <label>Add New Item to Cupping Session</label>
30
+            </column>
31
+        </row>
32
+        <row>
33
+            <column>
34
+                <label>Item:</label>
35
+            </column>
36
+            <column colspan="3">
37
+                <line id="itemname" />
38
+            </column>
39
+            <column column="4">
40
+                <button type="push" name="New Item" id="newitem" />
41
+            </column>
42
+        </row>
43
+    </layout>
44
+    <program>
45
+        <![CDATA[
46
+            var categorydrop = findChildObject(this, 'category');
47
+            var itemdrop = findChildObject(this, 'item');
48
+            var q = "SELECT id, name FROM items WHERE category = '";
49
+            q = q + categorydrop.currentText;
50
+            q = q + "' ORDER BY name";
51
+            itemdrop.addSqlOptions(q);
52
+            categorydrop['currentIndexChanged(QString)'].connect(function(arg) {
53
+                itemdrop.clear();
54
+                q = "SELECT id, name FROM items WHERE category = '";
55
+                q = q + arg;
56
+                q = q + "' ORDER BY name";
57
+                itemdrop.addSqlOptions(q);
58
+            });
59
+        ]]>
60
+    </program>
61
+</window>

+ 16
- 0
config/Windows/cuppingsamplepoints.xml View File

@@ -0,0 +1,16 @@
1
+<window id="selectsamples">
2
+    <layout type="vertical">
3
+        <formarray id="form">
4
+            <layout type="horizontal">
5
+                <button type="check" name="Cup:" id="include" />
6
+                <label>Time:</label>
7
+                <line id="time" writable="false" />
8
+                <label>Bean Temperature:</label>
9
+                <line id="temp" writable="false" />
10
+                <label>Annotation:</label>
11
+                <line id="note" writable="false" />
12
+            </layout>
13
+        </formarray>
14
+        <button id="select" name="Add to Session" type="push" />
15
+    </layout>
16
+</window>

+ 9
- 0
config/Windows/cuppingsampleselection.xml View File

@@ -0,0 +1,9 @@
1
+<window id="sampleselection">
2
+    <layout type="vertical">
3
+        <sqlview id="table" />
4
+    </layout>
5
+    <program>
6
+        var table = findChildObject(this, 'table');
7
+        table.setQuery("SELECT time, name, unroasted_total_quantity AS green, roasted_quantity AS roasted, weight_loss AS loss, duration FROM short_log ORDER BY time DESC");
8
+    </program>
9
+</window>

+ 246
- 0
config/Windows/cuppingsession.xml View File

@@ -0,0 +1,246 @@
1
+<window id="session">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Event:</label>
5
+            <line id="event" />
6
+            <label>Session:</label>
7
+            <line id="session" />
8
+            <label>Date:</label>
9
+            <calendar id="date" />
10
+            <button name="Blind" id="blind" type="check" />
11
+            <button name="Add Sample" id="sample" type="push" />
12
+            <button name="Add Item" id="additem" type="push" />
13
+        </layout>
14
+        <formarray id="form">
15
+            <layout type="vertical">
16
+                <layout type="horizontal">
17
+                    <label>Sample ID:</label>
18
+                    <line id="sample" />
19
+                    <label>Roasted At:</label>
20
+                    <line id="time" writable="false" />
21
+                    <label>On:</label>
22
+                    <line id="machine" writable="false" />
23
+                </layout>
24
+                <layout type="horizontal">
25
+                    <label>Time:</label>
26
+                    <line id="duration" writable="false" />
27
+                    <label>Bean Temperature:</label>
28
+                    <line id="temp" writable="false" />
29
+                    <label>Annotation:</label>
30
+                    <line id="note" writable="false" />
31
+                </layout>
32
+                <layout type="horizontal">
33
+                    <label>Item:</label>
34
+                    <line id="item" writable="false" />
35
+                    <label>Table Position:</label>
36
+                    <line id="position" />
37
+                </layout>
38
+            </layout>
39
+        </formarray>
40
+        <button type="push" name="Create Session" id="submit" />
41
+    </layout>
42
+    <program>
43
+        <![CDATA[
44
+            var window = this;
45
+            this.showMaximized();
46
+            var samples = findChildObject(this, 'form');
47
+            var addSampleButton = findChildObject(this, 'sample');
48
+            var addItemButton = findChildObject(this, 'additem');
49
+            var submitButton = findChildObject(this, 'submit');
50
+            addItemButton.clicked.connect(function() {
51
+                var selectWindow = createWindow("sampleitemselection");
52
+                var itemdrop = findChildObject(selectWindow, 'item');
53
+                var button1 = findChildObject(selectWindow, 'additem');
54
+                button1.clicked.connect(function() {
55
+                    samples.addElements(1);
56
+                    sampleID = findChildObject(samples.elementAt(samples.elements() - 1), 'sample');
57
+                    sampleID.text = itemdrop.currentText;
58
+                    position = findChildObject(samples.elementAt(samples.elements() - 1), 'position');
59
+                    position.text = samples.elements();
60
+                    itemID = findChildObject(samples.elementAt(samples.elements() - 1), 'item');
61
+                    itemID.text = itemdrop.currentData();
62
+                    selectWindow.close();
63
+                });
64
+                var itemname = findChildObject(selectWindow, 'itemname');
65
+                var button2 = findChildObject(selectWindow, 'newitem');
66
+                button2.clicked.connect(function() {
67
+                    samples.addElements(1);
68
+                    sampleID = findChildObject(samples.elementAt(samples.elements() - 1), 'sample');
69
+                    sampleID.text = itemname.text;
70
+                    position = findChildObject(samples.elementAt(samples.elements() - 1), 'position');
71
+                    position.text = samples.elements();
72
+                    var q = "INSERT INTO items VALUES(default, :name, NULL, 'lb', 0, 'Coffee: Sample') RETURNING id";
73
+                    var query = new QSqlQuery;
74
+                    query.prepare(q);
75
+                    query.bind(":name", itemname.text);
76
+                    query.exec();
77
+                    query.next();
78
+                    itemID = findChildObject(samples.elementAt(samples.elements() - 1), 'item');
79
+                    itemID.text = query.value(0);
80
+                    selectWindow.close();
81
+                });
82
+            });
83
+            addSampleButton.clicked.connect(function() {
84
+                var selectWindow = createWindow("sampleselection");
85
+                var sampleTable = findChildObject(selectWindow, 'table');
86
+                sampleTable.openEntry.connect(function(arg) {
87
+                    var q = "SELECT files FROM roasting_log WHERE time = :time";
88
+                    var query = new QSqlQuery;
89
+                    query.prepare(q);
90
+                    query.bind(":time", arg);
91
+                    var batchTime = arg;
92
+                    query.exec();
93
+                    var file = null;
94
+                    while(query.next())
95
+                    {
96
+                        var files = sqlToArray(query.value(0));
97
+                        for(var i = 0; i < files.length; i++)
98
+                        {
99
+                            q = "SELECT type FROM files WHERE id = :id";
100
+                            query.prepare(q);
101
+                            query.bind(":id", files[i]);
102
+                            query.exec();
103
+                            query.next();
104
+                            if(query.value(0) == "profile")
105
+                            {
106
+                                q = "SELECT file FROM files WHERE id = :id";
107
+                                query.prepare(q);
108
+                                query.bind(":id", files[i]);
109
+                                query.exec();
110
+                                query.next();
111
+                                file = query.value(0);
112
+                                break;
113
+                            }
114
+                        }
115
+                        if(file)
116
+                        {
117
+                            break;
118
+                        }
119
+                    }
120
+                    if(file)
121
+                    {
122
+                        var pointwindow = createWindow("selectsamples");
123
+                        var selectButton = findChildObject(pointwindow, 'select');
124
+                        selectButton.clicked.connect(function() {
125
+                            var checkbox;
126
+                            var sampleID;
127
+                            var roastTime;
128
+                            var machineID;
129
+                            var sampleDuration;
130
+                            var sampleBeanTemperature;
131
+                            var sampleAnnotation;
132
+                            var position;
133
+                            for(var i = 0; i < selectform.elements(); i++)
134
+                            {
135
+                                checkbox = findChildObject(selectform.elementAt(i), 'include');
136
+                                if(checkbox.checked)
137
+                                {
138
+                                    samples.addElements(1);
139
+                                    sampleID = findChildObject(samples.elementAt(samples.elements() - 1), 'sample');
140
+                                    roastTime = findChildObject(samples.elementAt(samples.elements() - 1), 'time');
141
+                                    machineID = findChildObject(samples.elementAt(samples.elements() - 1), 'machine');
142
+                                    sampleDuration = findChildObject(samples.elementAt(samples.elements() - 1), 'duration');
143
+                                    sampleBeanTemperature = findChildObject(samples.elementAt(samples.elements() - 1), 'temp');
144
+                                    sampleAnnotation = findChildObject(samples.elementAt(samples.elements() - 1), 'note');
145
+                                    position = findChildObject(samples.elementAt(samples.elements() - 1), 'position');
146
+                                    sampleDuration.text = findChildObject(selectform.elementAt(i), 'time').text;
147
+                                    sampleBeanTemperature.text = findChildObject(selectform.elementAt(i), 'temp').text;
148
+                                    sampleAnnotation.text = findChildObject(selectform.elementAt(i), 'note').text;
149
+                                    sampleID.text = sampleAnnotation.text;
150
+                                    roastTime.text = batchTime;
151
+                                    var q2 = "SELECT machine FROM roasting_log WHERE time = :time";
152
+                                    var query2 = new QSqlQuery;
153
+                                    query2.prepare(q2);
154
+                                    query2.bind(":time", batchTime);
155
+                                    query2.exec();
156
+                                    query2.next();
157
+                                    machineID.text = query2.value(0);
158
+                                    position.text = samples.elements();
159
+                                }
160
+                            }
161
+                            pointwindow.close();
162
+                        });
163
+                        pointwindow.hide();
164
+                        var buffer = new QBuffer(file);
165
+                        buffer.open(1);
166
+                        var xq = new XQuery;
167
+                        xq.bind("profile", buffer);
168
+                        xq.setQuery('for $t in doc($profile) //tuple where exists ($t/annotation) return (string($t/time), ";", string($t/temperature[1]), ";", string($t/annotation), "~")');
169
+                        var result = xq.exec();
170
+                        buffer.close();
171
+                        var records = result.split("~");
172
+                        var selectform = findChildObject(pointwindow, 'form');
173
+                        var time;
174
+                        var temp;
175
+                        var note;
176
+                        for(var i = 0; i < records.length - 1; i++)
177
+                        {
178
+                            selectform.addElements(1);
179
+                            var record = records[i];
180
+                            var fields = record.split(";");
181
+                            time = findChildObject(selectform.elementAt(i), 'time');
182
+                            time.text = fields[0].replace(/^\s+|\s+$/g,"");
183
+                            temp = findChildObject(selectform.elementAt(i), 'temp');
184
+                            temp.text = fields[1].replace(/^\s+|\s+$/g,"");
185
+                            note = findChildObject(selectform.elementAt(i), 'note');
186
+                            note.text = fields[2].replace(/^\s+|\s+$/g,"");
187
+                        }
188
+                        pointwindow.showMaximized();
189
+                    }
190
+                });
191
+            });
192
+            submitButton.clicked.connect(function() {
193
+                var q = "INSERT INTO cupping_sessions VALUES (default, :event, :name, :time, :blind, true, NULL) RETURNING id";
194
+                var query = new QSqlQuery;
195
+                query.prepare(q);
196
+                var eventField = findChildObject(window, 'event');
197
+                if(eventField.text == "")
198
+                {
199
+                    query.bind(":event", null);
200
+                }
201
+                else
202
+                {
203
+                    query.bind(":event", eventField.text);
204
+                }
205
+                var nameField = findChildObject(window, 'session');
206
+                query.bind(":name", nameField.text);
207
+                var timeField = findChildObject(window, 'date');
208
+                query.bind(":time", timeField.date);
209
+                var blindBox = findChildObject(window, 'blind');
210
+                query.bind(":blind", blindBox.checked);
211
+                query.exec();
212
+                query.next();
213
+                var newSessionID = query.value(0);
214
+                q = "INSERT INTO cupping_samples VALUES(:session, :sample, :position, :type, :time, :machine, :point, :item)";
215
+                query.prepare(q);
216
+                query.bind(":session", newSessionID);
217
+                var element;
218
+                for(var i = 0; i < samples.elements(); i++)
219
+                {
220
+                    element = samples.elementAt(i);
221
+                    query.bind(":sample", findChildObject(element, 'sample').text);
222
+                    query.bind(":position", Number(findChildObject(element, 'position').text));
223
+                    var elementItem = findChildObject(element, 'item');
224
+                    if(elementItem.text == "")
225
+                    {
226
+                        query.bind(":type", "SAMPLE");
227
+                        query.bind(":time", findChildObject(element, 'time').text);
228
+                        query.bind(":machine", Number(findChildObject(element, 'machine').text));
229
+                        query.bind(":point", findChildObject(element, 'duration').text);
230
+                        query.bind(":item", null);
231
+                    }
232
+                    else
233
+                    {
234
+                        query.bind(":type", "ITEM");
235
+                        query.bind(":time", null);
236
+                        query.bind(":machine", null);
237
+                        query.bind(":point", null);
238
+                        query.bind(":item", elementItem.text);
239
+                    }
240
+                    query.exec();
241
+                }
242
+                window.close();
243
+            });
244
+        ]]>
245
+    </program>
246
+</window>

+ 263
- 0
config/Windows/cuppingsessionlist.xml View File

@@ -0,0 +1,263 @@
1
+<window id="sessionlist">
2
+    <layout type="vertical">
3
+        <sqlview id="table" />
4
+    </layout>
5
+    <program>
6
+        <![CDATA[
7
+            var table = findChildObject(this, 'table');
8
+            table.setQuery("SELECT id, name, time FROM cupping_sessions WHERE open = true ORDER BY time DESC");
9
+            table.openEntry.connect(function(arg) {
10
+                var q = "SELECT event FROM cupping_sessions WHERE id = :id";
11
+                var query = new QSqlQuery;
12
+                query.prepare(q);
13
+                query.bind(":id", arg);
14
+                query.exec();
15
+                query.next();
16
+                var formwindow = createWindow("cuppingform");
17
+                formwindow.windowTitle = "Typica - Cupping";
18
+                var sessionfield = findChildObject(formwindow, 'session');
19
+                sessionfield.text = arg;
20
+                var eventfield = findChildObject(formwindow, 'event');
21
+                eventfield.text = query.value(0);
22
+                q = "SELECT sample FROM cupping_samples WHERE session = :id ORDER BY position ASC";
23
+                query.prepare(q);
24
+                query.bind(":id", Number(arg));
25
+                query.exec();
26
+                var view = findChildObject(formwindow, 'form');
27
+                view.setMaximumElementHeight(300);
28
+                view.setMaximumElementWidth(1100);
29
+                while(query.next())
30
+                {
31
+                    view.addElements(1);
32
+                    var element = view.elementAt(view.elements() - 1)
33
+                    var sampleBox = findChildObject(element, 'sampleID');
34
+                    sampleBox.text = query.value(0);
35
+                    var aromaScale = findChildObject(element, 'aroma');
36
+                    var aromaBox = findChildObject(element, 'aromabox');
37
+                    aromaScale.finalChanged.connect(aromaBox.setValue);
38
+                    aromaBox['valueChanged(double)'].connect(aromaScale.setFinalValue);
39
+                    var flavorScale = findChildObject(element, 'flavor');
40
+                    var flavorBox = findChildObject(element, 'flavorbox');
41
+                    flavorScale.finalChanged.connect(flavorBox.setValue);
42
+                    flavorBox['valueChanged(double)'].connect(flavorScale.setFinalValue);
43
+                    var acidityScale = findChildObject(element, 'acidity');
44
+                    var acidityBox = findChildObject(element, 'aciditybox');
45
+                    acidityScale.finalChanged.connect(acidityBox.setValue);
46
+                    acidityBox['valueChanged(double)'].connect(acidityScale.setFinalValue);
47
+                    var bodyScale = findChildObject(element, 'body');
48
+                    var bodyBox = findChildObject(element, 'bodybox');
49
+                    bodyScale.finalChanged.connect(bodyBox.setValue);
50
+                    bodyBox['valueChanged(double)'].connect(bodyScale.setFinalValue);
51
+                    var balanceScale = findChildObject(element, 'balance');
52
+                    var balanceBox = findChildObject(element, 'balancebox');
53
+                    balanceScale.finalChanged.connect(balanceBox.setValue);
54
+                    balanceBox['valueChanged(double)'].connect(balanceScale.setFinalValue);
55
+                    var aftertasteScale = findChildObject(element, 'aftertaste');
56
+                    var aftertasteBox = findChildObject(element, 'aftertastebox');
57
+                    aftertasteScale.finalChanged.connect(aftertasteBox.setValue);
58
+                    aftertasteBox['valueChanged(double)'].connect(aftertasteScale.setFinalValue);
59
+                    var overallScale = findChildObject(element, 'overall');
60
+                    var overallBox = findChildObject(element, 'overallbox');
61
+                    overallScale.finalChanged.connect(overallBox.setValue);
62
+                    overallBox['valueChanged(double)'].connect(overallScale.setFinalValue);
63
+                    var uc1 = findChildObject(element, 'u1');
64
+                    var uc2 = findChildObject(element, 'u2');
65
+                    var uc3 = findChildObject(element, 'u3');
66
+                    var uc4 = findChildObject(element, 'u4');
67
+                    var uc5 = findChildObject(element, 'u5');
68
+                    var cc1 = findChildObject(element, 'c1');
69
+                    var cc2 = findChildObject(element, 'c2');
70
+                    var cc3 = findChildObject(element, 'c3');
71
+                    var cc4 = findChildObject(element, 'c4');
72
+                    var cc5 = findChildObject(element, 'c5');
73
+                    var sc1 = findChildObject(element, 's1');
74
+                    var sc2 = findChildObject(element, 's2');
75
+                    var sc3 = findChildObject(element, 's3');
76
+                    var sc4 = findChildObject(element, 's4');
77
+                    var sc5 = findChildObject(element, 's5');
78
+                    var uniformityBox = findChildObject(element, 'uniformity');
79
+                    var cleancupBox = findChildObject(element, 'cleancup');
80
+                    var sweetnessBox = findChildObject(element, 'sweetness');
81
+                    uc1.checked = true;
82
+                    uc2.checked = true;
83
+                    uc3.checked = true;
84
+                    uc4.checked = true;
85
+                    uc5.checked = true;
86
+                    cc1.checked = true;
87
+                    cc2.checked = true;
88
+                    cc3.checked = true;
89
+                    cc4.checked = true;
90
+                    cc5.checked = true;
91
+                    sc1.checked = true;
92
+                    sc2.checked = true;
93
+                    sc3.checked = true;
94
+                    sc4.checked = true;
95
+                    sc5.checked = true;
96
+                    uniformityBox.value = 10;
97
+                    cleancupBox.value = 10;
98
+                    sweetnessBox.value = 10;
99
+                    var recalculateUniformity = function() {
100
+                        for(var i = 0; i < view.elements(); i++)
101
+                        {
102
+                            var u = 0;
103
+                            uc1 = findChildObject(view.elementAt(i), 'u1');
104
+                            uc2 = findChildObject(view.elementAt(i), 'u2');
105
+                            uc3 = findChildObject(view.elementAt(i), 'u3');
106
+                            uc4 = findChildObject(view.elementAt(i), 'u4');
107
+                            uc5 = findChildObject(view.elementAt(i), 'u5');
108
+                            uniformityBox = findChildObject(view.elementAt(i), 'uniformity');
109
+                            if(uc1.checked)
110
+                            {
111
+                                u += 2;
112
+                            }
113
+                            if(uc2.checked)
114
+                            {
115
+                                u += 2;
116
+                            }
117
+                            if(uc3.checked)
118
+                            {
119
+                                u += 2;
120
+                            }
121
+                            if(uc4.checked)
122
+                            {
123
+                                u += 2;
124
+                            }
125
+                            if(uc5.checked)
126
+                            {
127
+                                u += 2;
128
+                            }
129
+                            uniformityBox.value = u;
130
+                        }
131
+                    };
132
+                    uc1.clicked.connect(recalculateUniformity);
133
+                    uc2.clicked.connect(recalculateUniformity);
134
+                    uc3.clicked.connect(recalculateUniformity);
135
+                    uc4.clicked.connect(recalculateUniformity);
136
+                    uc5.clicked.connect(recalculateUniformity);
137
+                    var recalculateCleancup = function()
138
+                    {
139
+                        for(var i = 0; i < view.elements(); i++)
140
+                        {
141
+                            var c = 0;
142
+                            cc1 = findChildObject(view.elementAt(i), 'c1');
143
+                            cc2 = findChildObject(view.elementAt(i), 'c2');
144
+                            cc3 = findChildObject(view.elementAt(i), 'c3');
145
+                            cc4 = findChildObject(view.elementAt(i), 'c4');
146
+                            cc5 = findChildObject(view.elementAt(i), 'c5');
147
+                            cleancupBox = findChildObject(view.elementAt(i), 'cleancup');
148
+                            if(cc1.checked)
149
+                            {
150
+                                c += 2;
151
+                            }
152
+                            if(cc2.checked)
153
+                            {
154
+                                c += 2;
155
+                            }
156
+                            if(cc3.checked)
157
+                            {
158
+                                c += 2;
159
+                            }
160
+                            if(cc4.checked)
161
+                            {
162
+                                c += 2;
163
+                            }
164
+                            if(cc5.checked)
165
+                            {
166
+                                c += 2;
167
+                            }
168
+                            cleancupBox.value = c;
169
+                        }
170
+                    };
171
+                    cc1.clicked.connect(recalculateCleancup);
172
+                    cc2.clicked.connect(recalculateCleancup);
173
+                    cc3.clicked.connect(recalculateCleancup);
174
+                    cc4.clicked.connect(recalculateCleancup);
175
+                    cc5.clicked.connect(recalculateCleancup);
176
+                    var recalculateSweetness = function() {
177
+                        for(var i = 0; i < view.elements(); i++)
178
+                        {
179
+                            sc1 = findChildObject(view.elementAt(i), 's1');
180
+                            sc2 = findChildObject(view.elementAt(i), 's2');
181
+                            sc3 = findChildObject(view.elementAt(i), 's3');
182
+                            sc4 = findChildObject(view.elementAt(i), 's4');
183
+                            sc5 = findChildObject(view.elementAt(i), 's5');
184
+                            sweetnessBox = findChildObject(view.elementAt(i), 'sweetness');
185
+                            var s = 0;
186
+                            if(sc1.checked)
187
+                            {
188
+                                s += 2;
189
+                            }
190
+                            if(sc2.checked)
191
+                            {
192
+                                s += 2;
193
+                            }
194
+                            if(sc3.checked)
195
+                            {
196
+                                s += 2;
197
+                            }
198
+                            if(sc4.checked)
199
+                            {
200
+                                s += 2;
201
+                            }
202
+                            if(sc5.checked)
203
+                            {
204
+                                s += 2;
205
+                            }
206
+                            sweetnessBox.value = s;
207
+                        }
208
+                    };
209
+                    sc1.clicked.connect(recalculateSweetness);
210
+                    sc2.clicked.connect(recalculateSweetness);
211
+                    sc3.clicked.connect(recalculateSweetness);
212
+                    sc4.clicked.connect(recalculateSweetness);
213
+                    sc5.clicked.connect(recalculateSweetness);
214
+                    var totalBox = findChildObject(element, 'totalscore');
215
+                    var finalBox = findChildObject(element, 'finalscore');
216
+                    var taintBox = findChildObject(element, 'taints');
217
+                    var faultBox = findChildObject(element, 'faults');
218
+                    totalBox.enabled = false;
219
+                    finalBox.enabled = false;
220
+                    var recalculateTotals = function() {
221
+                        for(var i = 0; i < view.elements(); i++)
222
+                        {
223
+                            aromaBox = findChildObject(view.elementAt(i), 'aromabox');
224
+                            flavorBox = findChildObject(view.elementAt(i), 'flavorbox');
225
+                            acidityBox = findChildObject(view.elementAt(i), 'aciditybox');
226
+                            bodyBox = findChildObject(view.elementAt(i), 'bodybox');
227
+                            balanceBox = findChildObject(view.elementAt(i), 'balancebox');
228
+                            aftertasteBox = findChildObject(view.elementAt(i), 'aftertastebox');
229
+                            overallBox = findChildObject(view.elementAt(i), 'overallbox');
230
+                            uniformityBox = findChildObject(view.elementAt(i), 'uniformity');
231
+                            cleancupBox = findChildObject(view.elementAt(i), 'cleancup');
232
+                            sweetnessBox = findChildObject(view.elementAt(i), 'sweetness');
233
+                            taintBox = findChildObject(view.elementAt(i), 'taints');
234
+                            faultBox = findChildObject(view.elementAt(i), 'faults');
235
+                            totalBox = findChildObject(view.elementAt(i), 'totalscore');
236
+                            finalBox = findChildObject(view.elementAt(i), 'finalscore');
237
+                            var total = aromaBox.value + flavorBox.value + acidityBox.value + bodyBox.value + balanceBox.value + aftertasteBox.value + overallBox.value + uniformityBox.value + cleancupBox.value + sweetnessBox.value;
238
+                            var taints = -(taintBox.value * 2);
239
+                            var faults = -(faultBox.value * 4);
240
+                            var final = total + taints + faults;
241
+                            totalBox.value = total;
242
+                            finalBox.value = final;
243
+                        }
244
+                    };
245
+                    aromaBox['valueChanged(double)'].connect(recalculateTotals);
246
+                    taintBox['valueChanged(double)'].connect(recalculateTotals);
247
+                    faultBox['valueChanged(double)'].connect(recalculateTotals);
248
+                    flavorBox['valueChanged(double)'].connect(recalculateTotals);
249
+                    acidityBox['valueChanged(double)'].connect(recalculateTotals);
250
+                    bodyBox['valueChanged(double)'].connect(recalculateTotals);
251
+                    balanceBox['valueChanged(double)'].connect(recalculateTotals);
252
+                    aftertasteBox['valueChanged(double)'].connect(recalculateTotals);
253
+                    overallBox['valueChanged(double)'].connect(recalculateTotals);
254
+                    uniformityBox['valueChanged(double)'].connect(recalculateTotals);
255
+                    cleancupBox['valueChanged(double)'].connect(recalculateTotals);
256
+                    sweetnessBox['valueChanged(double)'].connect(recalculateTotals);
257
+                    recalculateTotals();
258
+                }
259
+                formwindow.showMaximized();
260
+            });
261
+        ]]>
262
+    </program>
263
+</window>

+ 64
- 0
config/Windows/cuppingsessionsummary.xml View File

@@ -0,0 +1,64 @@
1
+<window id="cuppingsessionsummary">
2
+    <layout type="vertical">
3
+        <layout type="grid">
4
+            <row>
5
+                <column><label>Session ID:</label></column>
6
+                <column><line id="session" writable="false" /></column>
7
+            </row>
8
+            <row>
9
+                <column><label>Event:</label></column>
10
+                <column><line id="event" writable="false" /></column>
11
+            </row>
12
+            <row>
13
+                <column><label>Session Name:</label></column>
14
+                <column><line id="name" writable="false" /></column>
15
+            </row>
16
+            <row>
17
+                <column><label>Session Date:</label></column>
18
+                <column><calendar id="date" /></column>
19
+            </row>
20
+        </layout>
21
+        <button type="check" name="Session is open" id="open" />
22
+        <label>Session Notes</label>
23
+        <textarea id="notes" />
24
+        <layout type="horizontal">
25
+            <button name="View Session Data" id="data" type="push" />
26
+            <button name="Submit" id="submit" type="push" />
27
+        </layout>
28
+    </layout>
29
+    <program>
30
+        <![CDATA[
31
+            var window = this;
32
+            var dateWidget = findChildObject(this, 'date');
33
+            dateWidget.enabled = false;
34
+            var viewbutton = findChildObject(this, 'data');
35
+            var idField = findChildObject(this, 'session');
36
+            viewbutton.clicked.connect(function() {
37
+                var datascreen = createWindow("allforms");
38
+                var datatable = findChildObject(datascreen, 'data');
39
+                var averagetable = findChildObject(datascreen, 'averages');
40
+                var q1 = "SELECT sample, grader, finalscore, aroma, flavor, aftertaste, acidity, body, uniformity, balance, cleancup, sweetness, overall, total FROM cuppingform_t1 WHERE session = ";
41
+                q1 = q1 + idField.text;
42
+                q1 = q1 + " ORDER BY sample";
43
+                datatable.setQuery(q1);
44
+                var q2 = "SELECT sample, avg(finalscore)::numeric(4,2) AS finalscore, avg(aroma)::numeric(4,2) AS aroma, avg(flavor)::numeric(4,2) AS flavor, avg(aftertaste)::numeric(4,2) AS aftertaste, avg(acidity)::numeric(4,2) AS acidity, avg(body)::numeric(4,2) AS body, avg(uniformity)::numeric(4,2) AS uniformity, avg(balance)::numeric(4,2) AS balance, avg(cleancup)::numeric(4,2) AS cleancup, avg(sweetness)::numeric(4,2) AS sweetness, avg(overall)::numeric(4,2) AS overall, avg(total)::numeric(4,2) AS total FROM cuppingform_t1 WHERE session = ";
45
+                q2 = q2 + idField.text;
46
+                q2 = q2 + " GROUP BY sample, position ORDER BY position";
47
+                averagetable.setQuery(q2);
48
+            });
49
+            var submit = findChildObject(this, 'submit');
50
+            var openBox = findChildObject(this, 'open');
51
+            var notes = findChildObject(this, 'notes');
52
+            submit.clicked.connect(function() {
53
+                var query = new QSqlQuery;
54
+                query.prepare("UPDATE cupping_sessions SET open = :open, note = :note WHERE id = :id");
55
+                query.bind(":id", Number(idField.text));
56
+                query.bind(":open", openBox.checked);
57
+                query.bind(":note", notes.plainText);
58
+                query.exec();
59
+                window.close();
60
+            });
61
+        ]]>
62
+    </program>
63
+</window>
64
+

+ 29
- 0
config/Windows/cuppingsummary.xml View File

@@ -0,0 +1,29 @@
1
+<window id="finsessionlist">
2
+    <layout type="vertical">
3
+        <sqlview id="table" />
4
+    </layout>
5
+    <program>
6
+        var table = findChildObject(this, 'table');
7
+        table.setQuery("SELECT id, open, event, name, time FROM cupping_sessions ORDER BY time DESC");
8
+        table.openEntry.connect(function(arg) {
9
+            var summarywindow = createWindow("cuppingsessionsummary");
10
+            var idfield = findChildObject(summarywindow, 'session');
11
+            idfield.text = arg.toString();
12
+            var query = new QSqlQuery;
13
+            query.prepare("SELECT event, name, time, open, note FROM cupping_sessions WHERE id = :sessionID");
14
+            query.bind(":sessionID", Number(arg));
15
+            query.exec();
16
+            query.next();
17
+            var eventfield = findChildObject(summarywindow, 'event');
18
+            eventfield.text = query.value(0);
19
+            var sessionfield = findChildObject(summarywindow, 'name');
20
+            sessionfield.text = query.value(1);
21
+            var datefield = findChildObject(summarywindow, 'date');
22
+            datefield.date = query.value(2);
23
+            var openbox = findChildObject(summarywindow, 'open');
24
+            openbox.checked = query.value(3);
25
+            var notes = findChildObject(summarywindow, 'notes');
26
+            notes.plainText = query.value(4);
27
+        });
28
+    </program>
29
+</window>

+ 40
- 0
config/Windows/editfee.xml View File

@@ -0,0 +1,40 @@
1
+<window id="invoicefeedetail">
2
+	<layout type="vertical">
3
+		<layout type="grid">
4
+			<row>
5
+				<column><label>Description</label></column>
6
+				<column><line id="description" /></column>
7
+			</row>
8
+			<row>
9
+				<column><label>Cost</label></column>
10
+				<column><line id="cost" validator="numeric"/></column>
11
+			</row>
12
+		</layout>
13
+		<button name="submit" type="push" id="submit" />
14
+	</layout>
15
+	<program>
16
+		<![CDATA[
17
+			window = this;
18
+			this.windowTitle = 'Typica - Fee Detail';
19
+			var descField = findChildObject(this, 'description');
20
+			var costField = findChildObject(this, 'cost');
21
+			this.dataSet = function() {
22
+				descField.text = window.rowData[2];
23
+				costField.text = window.rowData[4];
24
+			};
25
+			button = findChildObject(this, 'submit');
26
+			button.clicked.connect(function() {
27
+				var query = new QSqlQuery();
28
+				query.prepare("UPDATE invoice_items SET description = :name, cost = :cost WHERE invoice_id = :id AND record_type = 'FEE' AND item_id = NULL AND description = :oldname AND cost = :oldcost");
29
+				query.bind(":name", descField.text);
30
+				query.bind(":cost", Number(costField.text));
31
+				query.bind(":id", Number(window.rowData[1]);
32
+				query.bind(":oldname", window.rowData[2]);
33
+				query.bind(":oldcost", window.rowData[4]);
34
+				query.exec();
35
+				query = query.invalidate();
36
+				window.close();
37
+			});
38
+		]]>
39
+	</program>
40
+</window>

+ 32
- 0
config/Windows/editinvoice.xml View File

@@ -0,0 +1,32 @@
1
+<window id="editinvoice">
2
+	<layout type="vertical">
3
+		<layout type="horizontal">
4
+			<label>Invoice:</label>
5
+			<line id="invoice" />
6
+		</layout>
7
+		<layout type="horizontal">
8
+			<button type="push" id="cancel" name="Cancel" />
9
+			<button type="push" id="submit" name="Submit" />
10
+		</layout>
11
+	</layout>
12
+	<program>
13
+		<![CDATA[
14
+			var window = this;
15
+			var submit = findChildObject(this, 'submit');
16
+			var invoiceLine = findChildObject(this, 'invoice');
17
+			submit.clicked.connect(function() {
18
+				var query = new QSqlQuery();
19
+				query.prepare("UPDATE invoices SET invoice = :invoice WHERE id = :id");
20
+				query.bind(":invoice", invoiceLine.text);
21
+				query.bind(":id", window.invoiceID);
22
+				query.exec();
23
+				query = query.invalidate;
24
+				window.close();
25
+			});
26
+			var cancel = findChildObject(this, 'cancel');
27
+			cancel.clicked.connect(function() {
28
+				window.close();
29
+			});
30
+		]]>
31
+	</program>
32
+</window>

+ 109
- 0
config/Windows/editinvoiceitem.xml View File

@@ -0,0 +1,109 @@
1
+<window id="invoiceitemdetail">
2
+	<layout type="vertical">
3
+		<layout type="grid">
4
+			<row>
5
+				<column><label>Name</label></column>
6
+				<column><line id="name" /></column>
7
+			</row>
8
+			<row>
9
+				<column><label>Reference</label></column>
10
+				<column><line id="reference" /></column>
11
+			</row>
12
+			<row>
13
+				<column><label>Unit Cost</label></column>
14
+				<column><line validator="numeric" id="cost" /></column>
15
+			</row>
16
+			<row>
17
+				<column><label>Quantity</label></column>
18
+				<column><line validator="numeric" id="quantity" /></column>
19
+			</row>
20
+			<row>
21
+				<column><label>Bags</label></column>
22
+				<column><line validator="numeric" id="bags" /></column>
23
+			</row>
24
+		</layout>
25
+		<button name="Submit" type="push" id="submit" />
26
+	</layout>
27
+	<program>
28
+		<![CDATA[
29
+			window = this;
30
+			this.windowTitle = 'Typica - Item Detail';
31
+			var nameField = findChildObject(this, 'name');
32
+			var referenceField = findChildObject(this, 'reference');
33
+			var costField = findChildObject(this, 'cost');
34
+			var quantityField = findChildObject(this, 'quantity');
35
+			var bagsField = findChildObject(this, 'bags');
36
+			this.dataSet = function() {
37
+				nameField.text = window.rowData[2];
38
+				referenceField.text = window.rowData[3];
39
+				costField.text = window.rowData[4];
40
+				quantityField.text = window.rowData[5];
41
+				bagsField.text = window.rowData[6];
42
+			};
43
+			button = findChildObject(this, 'submit');
44
+			button.clicked.connect(function() {
45
+				var query = new QSqlQuery();
46
+				if(nameField.text != window.rowData[2]) {
47
+					query.prepare("UPDATE items SET name = :name WHERE id = :id");
48
+					query.bind(":name", nameField.text);
49
+					query.bind(":id", Number(window.rowData[1]));
50
+					query.exec();
51
+					query.prepare("UPDATE invoice_items SET description = :name WHERE item_id = :id");
52
+					query.bind(":name", nameField.text);
53
+					query.bind(":id", Number(window.rowData[1]));
54
+					query.exec();
55
+					window.rowData[2] = nameField.text;
56
+				}
57
+				if(referenceField.text != window.rowData[3]) {
58
+					query.prepare("UPDATE items SET reference = :ref WHERE id = :id");
59
+					query.bind(":ref", referenceField.text);
60
+					query.bind(":id", Number(window.rowData[1]));
61
+					query.exec();
62
+					window.rowData[3] = referenceField.text;
63
+				}
64
+				var cqupdated = false;
65
+				var qbupdated = false;
66
+				if(costField.text != window.rowData[4]) {
67
+					cqupdated = true;
68
+					query.prepare("UPDATE purchase SET cost = :cost WHERE item = :id");
69
+					query.bind(":cost", Number(costField.text));
70
+					query.bind(":id", Number(window.rowData[1]));
71
+					query.exec();
72
+					window.rowData[4] = costField.text;
73
+				}
74
+				if(quantityField.text != window.rowData[5]) {
75
+					cqupdated = true;
76
+					qbupdated = true;
77
+					query.prepare("UPDATE purchase SET quantity = :qty WHERE item = :id");
78
+					query.bind(":qty", Number(quantityField.text));
79
+					query.bind(":id", Number(window.rowData[1]));
80
+					query.exec();
81
+					window.rowData[5] = quantityField.text;
82
+					query.prepare("UPDATE items SET quantity = (SELECT balance FROM item_history(:id) WHERE time = (SELECT max(time) FROM item_history(:id2))) WHERE id = :id3");
83
+					query.bind(":id", Number(window.rowData[1]));
84
+					query.bind(":id2", Number(window.rowData[1]));
85
+					query.bind(":id3", Number(window.rowData[1]));
86
+					query.exec();
87
+				}
88
+				if(bagsField.text != window.rowData[6]) {
89
+					qbupdated = true;
90
+					window.rowData[6] = bagsField.text;
91
+				}
92
+				if(cqupdated) {
93
+					query.prepare("UPDATE invoice_items SET cost = :total WHERE item_id = :id");
94
+					query.bind(":total", Number(window.rowData[5]) * Number(window.rowData[4]));
95
+					query.bind(":id", Number(window.rowData[1]));
96
+					query.exec();
97
+				}
98
+				if(qbupdated) {
99
+					query.prepare("UPDATE lb_bag_conversion SET conversion = :conv WHERE item = :id");
100
+					query.bind(":conv", Number(window.rowData[5]) / Number(window.rowData[6]));
101
+					query.bind(":id", Number(window.rowData[1]));
102
+					query.exec();
103
+				}
104
+				query = query.invalidate();
105
+				window.close();
106
+			});
107
+		]]>
108
+	</program>
109
+</window>

+ 760
- 0
config/Windows/export.xml View File

@@ -0,0 +1,760 @@
1
+<window id="exportWindow">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Title:</label>
5
+            <line id="title" />
6
+        </layout>
7
+        <layout type="horizontal">
8
+            <label>Subtitle:</label>
9
+            <line id="subtitle" />
10
+        </layout>
11
+        <layout type="horizontal">
12
+            <label>% weight loss:</label>
13
+            <line id="loss" validator="numeric" />
14
+            <label>Tolerance:</label>
15
+            <line id="tolerance" validator="numeric" />
16
+        </layout>
17
+        <layout type="horizontal">
18
+            <label>Additional notes:</label>
19
+            <line id="notes" />
20
+        </layout>
21
+        <layout type="horizontal">
22
+            <label>Measurement column:</label>
23
+            <line id="addmeasurement" validator="integer" />
24
+            <button name="Add column" type="push" id="ambutton" />
25
+            <line id="mcols" writable="false" />
26
+        </layout>
27
+        <layout type="horizontal">
28
+            <label>Annotation column:</label>
29
+            <line id="addnote" validator="integer" />
30
+            <button name="Add column" type="push" id="anbutton" />
31
+            <line id="ncols" writable="false" />
32
+        </layout>
33
+        <button name="Export" type="push" id="export" />
34
+    </layout>
35
+    <program>
36
+        <![CDATA[
37
+            var window = this;
38
+            var exportButton = findChildObject(this, 'export');
39
+            exportButton.enable = false;
40
+            var mcoldisp = findChildObject(this, 'mcols');
41
+            mcoldisp.enable = false;
42
+            var ncoldisp = findChildObject(this, 'ncols');
43
+            ncoldisp.enable = false;
44
+            var mbutton = findChildObject(this, 'ambutton');
45
+            var msource = findChildObject(this, 'addmeasurement');
46
+            var mdest = findChildObject(this, 'mcols');
47
+            mbutton.clicked.connect(function() {
48
+                if(window.marray === undefined)
49
+                {
50
+                    window.marray = new Array();
51
+                }
52
+                window.marray.push(Number(msource.text));
53
+                mdest.text = window.marray.toString();
54
+                msource.text = '';
55
+                if(window.narray === undefined)
56
+                {} else { exportButton.enable = true;}
57
+            });
58
+            var abutton = findChildObject(window, 'anbutton');
59
+            var asource = findChildObject(window, 'addnote');
60
+            var adest = findChildObject(window, 'ncols');
61
+            abutton.clicked.connect(function() {
62
+                if(window.narray === undefined)
63
+                {
64
+                    window.narray = new Array();
65
+                }
66
+                window.narray.push(Number(asource.text));
67
+                adest.text = window.narray.toString();
68
+                asource.text = '';
69
+                if(window.marray === undefined)
70
+                { } else { exportButton.enable = true;}
71
+            });
72
+            var titleField = findChildObject(window, 'title');
73
+            var subTitleField = findChildObject(window, 'subtitle');
74
+            exportButton.clicked.connect(function() {
75
+                var filename = QFileDialog.getSaveFileName(window, "Export XHTML+SVG As...", QSettings.value("script/lastDir", "") + "/");
76
+                if(filename != "")
77
+                {
78
+                    window.log.clearOutputColumns();
79
+                    for(var i = 0; i < window.marray.length; i++)
80
+                    {
81
+                        window.log.addOutputTemperatureColumn(window.marray[i]);
82
+                    }
83
+                    for(var i = 0; i < window.narray.length; i++)
84
+                    {
85
+                        window.log.addOutputAnnotationColumn(window.narray[i]);
86
+                    }
87
+                    var unitdesc = log.displayUnits();
88
+                    if(unitdesc != 10144)
89
+                    {
90
+                        log.setDisplayUnits(10144);
91
+                    }
92
+                    var tempFilename = log.saveTemporary();
93
+                    log.setDisplayUnits(unitdesc);
94
+                    var sourceFile = new QFile(tempFilename);
95
+                    sourceFile.open(3);
96
+                    var destFile = new QFile(filename);
97
+                    destFile.remove();
98
+                    destFile.open(3);
99
+                    var input = new XmlReader(sourceFile);
100
+                    var output = new XmlWriter(destFile);
101
+                    output.writeStartDocument("1.0");
102
+                    output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
103
+                    output.writeStartElement("html");
104
+                    output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
105
+                    output.writeStartElement("head");
106
+                    output.writeStartElement("title");
107
+                    output.writeCDATA(titleField.text);
108
+                    output.writeEndElement();
109
+                    output.writeEndElement();
110
+                    output.writeStartElement("body");
111
+                    output.writeStartElement("h1");
112
+                    output.writeAttribute("style", "font-size:100%;font-weight:bold");
113
+                    output.writeCDATA(titleField.text);
114
+                    output.writeEndElement();
115
+                    output.writeStartElement("h2");
116
+                    output.writeAttribute("style", "font-size:100%;font-weight:normal");
117
+                    output.writeCDATA(subTitleField.text);
118
+                    output.writeEndElement();
119
+                    output.writeStartElement("div");
120
+                    output.writeAttribute("style", "width:7.5in");
121
+                    output.writeStartElement("div");
122
+                    output.writeAttribute("style", "float:left;width:2.5in");
123
+                    output.writeStartElement("table");
124
+                    output.writeStartElement("tr");
125
+                    output.writeStartElement("th");
126
+                    output.writeCDATA("Time");
127
+                    output.writeEndElement();
128
+                    input.readNext();
129
+                    var colMap = new Array();
130
+                    var tempMap = new Array();
131
+                    while(input.name() != "roast")
132
+                    {
133
+                        if(input.isStartElement())
134
+                        {
135
+                            if(input.name() == "tempseries")
136
+                            {
137
+                                colMap.push(input.attribute("name"));
138
+                                tempMap.push(input.attribute("name"));
139
+                            }
140
+                            if(input.name() == "noteseries")
141
+                            {
142
+                                colMap.push(input.attribute("name"));
143
+                            }
144
+                        }
145
+                        input.readNext();
146
+                    }
147
+print("Column definitions read");
148
+                    for(var i = 0; i < colMap.length; i++)
149
+                    {
150
+                        output.writeStartElement("th");
151
+                        output.writeCDATA(colMap[i]);
152
+                        output.writeEndElement();
153
+                    }
154
+print("Column headers output");
155
+                    output.writeEndElement();
156
+                    var rowBuffer = new Array();
157
+                    var nextTime = 0;
158
+                    input.readNext();
159
+                    var inputReady = false;
160
+                    var annotationRead = false;
161
+                    var tm = 0;
162
+                    var ts = 0;
163
+                    while(!input.atEnd())
164
+                    {
165
+                        if(input.isStartElement())
166
+                        {
167
+                            if(input.name() == "time")
168
+                            {
169
+                                rowBuffer[0] = input.readElementText();
170
+                                inputReady = true;
171
+                            }
172
+                            if(input.name() == "temperature")
173
+                            {
174
+                                for (var i = 0; i < colMap.length; i++)
175
+                                {
176
+                                    if(colMap[i] == input.attribute("series"))
177
+                                    {
178
+                                        if(log.displayUnits() == 10143)
179
+                                        {
180
+                                            rowBuffer[i + 1] = Math.floor((input.readElementText() - 32) * 5 / 9);
181
+                                        }
182
+                                        else
183
+                                        {
184
+                                            rowBuffer[i + 1] = Math.floor(input.readElementText());
185
+                                        }
186
+                                        break;
187
+                                    }
188
+                                }
189
+                            }
190
+                            if(input.name() == "annotation")
191
+                            {
192
+                                for (var i = 0; i < colMap.length; i++)
193
+                                {
194
+                                    if(colMap[i] == input.attribute("series"))
195
+                                    {
196
+                                        rowBuffer[i + 1] = input.readElementText();
197
+                                        break;
198
+                                    }
199
+                                }
200
+                                annotationRead = true;
201
+                            }
202
+                            if(input.name() == "tuple")
203
+                            {
204
+                                if(inputReady)
205
+                                {
206
+                                    var ta1 = rowBuffer[0].split(":");
207
+                                    var ta2 = ta1[1].split(".");
208
+                                    if(Number(ta1[0]) == tm)
209
+                                    {
210
+                                        if(Number(ta2[0]) == ts)
211
+                                        {
212
+                                            annotationRead = false;
213
+                                            output.writeStartElement("tr");
214
+                                            for(var i = 0; i < rowBuffer.length; i++)
215
+                                            {
216
+                                                output.writeStartElement("td");
217
+                                                output.writeAttribute("align", "center");
218
+                                                output.writeAttribute("style", "font-size: 80%");
219
+                                                if(i == 0)
220
+                                                {
221
+                                                    output.writeCDATA(rowBuffer[i].split(".")[0]);
222
+                                                }
223
+                                                else
224
+                                                {
225
+                                                    output.writeCDATA(rowBuffer[i]);
226
+                                                }
227
+                                                output.writeEndElement();
228
+                                            }
229
+                                            output.writeEndElement();
230
+                                            nextTime += 30;
231
+                                            tm = Math.floor(nextTime / 60);
232
+                                            ts = nextTime % 60;
233
+                                        }
234
+                                    }
235
+                                    if(annotationRead)
236
+                                    {
237
+                                        output.writeStartElement("tr");
238
+                                        for(var i = 0; i < rowBuffer.length; i++)
239
+                                        {
240
+                                            output.writeStartElement("td");
241
+                                            output.writeAttribute("align", "center");
242
+                                            output.writeAttribute("style", "font-size: 80%");
243
+                                            output.writeCDATA(rowBuffer[i]);
244
+                                            output.writeEndElement();
245
+                                        }
246
+                                        output.writeEndElement();
247
+                                        annotationRead = false;
248
+                                    }
249
+                                }
250
+                                rowBuffer = new Array();
251
+                            }
252
+                        }
253
+                        input.readNext();
254
+                    }
255
+                    output.writeStartElement("tr");
256
+                    for(var i = 0; i < rowBuffer.length; i++)
257
+                    {
258
+                        output.writeStartElement("td");
259
+                        output.writeAttribute("align", "center");
260
+                        output.writeAttribute("style", "font-size: 80%");
261
+                        output.writeCDATA(rowBuffer[i]);
262
+                        output.writeEndElement();
263
+                    }
264
+                    output.writeEndElement();
265
+                    output.writeEndElement();
266
+                    output.writeEndElement();
267
+                    output.writeStartElement("div");
268
+                    output.writeAttribute("style", "width=4.5in;float=right");
269
+                    output.writeStartElement("svg");
270
+                    output.writeAttribute("xmlns", "http://www.w3.org/2000/svg");
271
+                    output.writeAttribute("version", "1.1");
272
+                    output.writeAttribute("width", "4.5in");
273
+                    output.writeAttribute("height", "3.4in");
274
+                    output.writeAttribute("viewbox", "0 0 400 400");
275
+                    output.writeStartElement("rect");
276
+                    output.writeAttribute("width", "4.5in");
277
+                    output.writeAttribute("height", "3.4in");
278
+                    output.writeAttribute("style", "fill:none;stroke-width:3;stroke:rgb(64,64,64)");
279
+                    output.writeEndElement();
280
+                    output.writeStartElement("text");
281
+                    output.writeAttribute("x", "0.1in");
282
+                    output.writeAttribute("y", "1.3in");
283
+                    output.writeAttribute("font-size", "12");
284
+                    output.writeAttribute("transform", "rotate(-90 40,150)");
285
+                    if(log.displayUnits() == 10143)
286
+                    {
287
+                        output.writeCDATA("Temperature (°C)");
288
+                    }
289
+                    else
290
+                    {
291
+                        output.writeCDATA("Temperature (°F)");
292
+                    }
293
+                    output.writeEndElement();
294
+                    output.writeStartElement("text");
295
+                    output.writeAttribute("x", "1.9in");
296
+                    output.writeAttribute("y", "3.3in");
297
+                    output.writeAttribute("font-size", "12");
298
+                    output.writeCDATA("Time (minutes)");
299
+                    output.writeEndElement();
300
+                    output.writeStartElement("line");
301
+                    output.writeAttribute("x1", "0.4in");
302
+                    output.writeAttribute("x2", "0.4in");
303
+                    output.writeAttribute("y1", "0.1in");
304
+                    output.writeAttribute("y2", "2.9in");
305
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
306
+                    output.writeEndElement();
307
+                    output.writeStartElement("line");
308
+                    output.writeAttribute("x1", "0.5in");
309
+                    output.writeAttribute("x2", "4.4in");
310
+                    output.writeAttribute("y1", "3in");
311
+                    output.writeAttribute("y2", "3in");
312
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
313
+                    output.writeEndElement();
314
+                    output.writeStartElement("line");
315
+                    output.writeAttribute("x1", "0.4in");
316
+                    output.writeAttribute("x2", "4.4in");
317
+                    output.writeAttribute("y1", "2.9in");
318
+                    output.writeAttribute("y2", "2.9in");
319
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
320
+                    output.writeEndElement();
321
+                    if(log.displayUnits() != 10143)
322
+                    {
323
+                        output.writeStartElement("text");
324
+                        output.writeAttribute("x", "0.3in");
325
+                        output.writeAttribute("y", "2.95in");
326
+                        output.writeAttribute("font-size", "12");
327
+                        output.writeCDATA("0");
328
+                        output.writeEndElement();
329
+                    }
330
+                    if(log.displayUnits() == 10143)
331
+                    {
332
+                        output.writeStartElement("line");
333
+                        output.writeAttribute("x1", "0.4in");
334
+                        output.writeAttribute("x2", "4.4in");
335
+                        output.writeAttribute("y1", "2.22in");
336
+                        output.writeAttribute("y2", "2.22in");
337
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
338
+                        output.writeEndElement();
339
+                        output.writeStartElement("text");
340
+                        output.writeAttribute("x", "0.18in");
341
+                        output.writeAttribute("y", "2.27in");
342
+                        output.writeAttribute("font-size", "12");
343
+                        output.writeCDATA("50");
344
+                        output.writeEndElement();
345
+                        output.writeStartElement("line");
346
+                        output.writeAttribute("x1", "0.4in");
347
+                        output.writeAttribute("x2", "4.4in");
348
+                        output.writeAttribute("y1", "1.71in");
349
+                        output.writeAttribute("y2", "1.71in");
350
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
351
+                        output.writeEndElement();
352
+                        output.writeStartElement("text");
353
+                        output.writeAttribute("x", "0.18in");
354
+                        output.writeAttribute("y", "1.76in");
355
+                        output.writeAttribute("font-size", "12");
356
+                        output.writeCDATA("100");
357
+                        output.writeEndElement();
358
+                        output.writeStartElement("line");
359
+                        output.writeAttribute("x1", "0.4in");
360
+                        output.writeAttribute("x2", "4.4in");
361
+                        output.writeAttribute("y1", "1.21in");
362
+                        output.writeAttribute("y2", "1.21in");
363
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
364
+                        output.writeEndElement();
365
+                        output.writeStartElement("text");
366
+                        output.writeAttribute("x", "0.18in");
367
+                        output.writeAttribute("y", "1.26in");
368
+                        output.writeAttribute("font-size", "12");
369
+                        output.writeCDATA("150");
370
+                        output.writeEndElement();
371
+                        output.writeStartElement("line");
372
+                        output.writeAttribute("x1", "0.4in");
373
+                        output.writeAttribute("x2", "4.4in");
374
+                        output.writeAttribute("y1", "0.7in");
375
+                        output.writeAttribute("y2", "0.7in");
376
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
377
+                        output.writeEndElement();
378
+                        output.writeStartElement("text");
379
+                        output.writeAttribute("x", "0.18in");
380
+                        output.writeAttribute("y", "0.75in");
381
+                        output.writeAttribute("font-size", "12");
382
+                        output.writeCDATA("200");
383
+                        output.writeEndElement();
384
+                        output.writeStartElement("line");
385
+                        output.writeAttribute("x1", "0.4in");
386
+                        output.writeAttribute("x2", "4.4in");
387
+                        output.writeAttribute("y1", "0.2in");
388
+                        output.writeAttribute("y2", "0.2in");
389
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
390
+                        output.writeEndElement();
391
+                        output.writeStartElement("text");
392
+                        output.writeAttribute("x", "0.18in");
393
+                        output.writeAttribute("y", "0.25in");
394
+                        output.writeAttribute("font-size", "12");
395
+                        output.writeCDATA("250");
396
+                        output.writeEndElement();
397
+                    }
398
+                    else
399
+                    {
400
+                        output.writeStartElement("line");
401
+                        output.writeAttribute("x1", "0.4in");
402
+                        output.writeAttribute("x2", "4.4in");
403
+                        output.writeAttribute("y1", "2.34in");
404
+                        output.writeAttribute("y2", "2.34in");
405
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
406
+                        output.writeEndElement();
407
+                        output.writeStartElement("text");
408
+                        output.writeAttribute("x", "0.18in");
409
+                        output.writeAttribute("y", "2.39in");
410
+                        output.writeAttribute("font-size", "12");
411
+                        output.writeCDATA("100");
412
+                        output.writeEndElement();
413
+                        output.writeStartElement("line");
414
+                        output.writeAttribute("x1", "0.4in");
415
+                        output.writeAttribute("x2", "4.4in");
416
+                        output.writeAttribute("y1", "1.78in");
417
+                        output.writeAttribute("y2", "1.78in");
418
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
419
+                        output.writeEndElement();
420
+                        output.writeStartElement("text");
421
+                        output.writeAttribute("x", "0.18in");
422
+                        output.writeAttribute("y", "1.83in");
423
+                        output.writeAttribute("font-size", "12");
424
+                        output.writeCDATA("200");
425
+                        output.writeEndElement();
426
+                        output.writeStartElement("line");
427
+                        output.writeAttribute("x1", "0.4in");
428
+                        output.writeAttribute("x2", "4.4in");
429
+                        output.writeAttribute("y1", "1.22in");
430
+                        output.writeAttribute("y2", "1.22in");
431
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
432
+                        output.writeEndElement();
433
+                        output.writeStartElement("text");
434
+                        output.writeAttribute("x", "0.18in");
435
+                        output.writeAttribute("y", "1.27in");
436
+                        output.writeAttribute("font-size", "12");
437
+                        output.writeCDATA("300");
438
+                        output.writeEndElement();
439
+                        output.writeStartElement("line");
440
+                        output.writeAttribute("x1", "0.4in");
441
+                        output.writeAttribute("x2", "4.4in");
442
+                        output.writeAttribute("y1", "0.66in");
443
+                        output.writeAttribute("y2", "0.66in");
444
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
445
+                        output.writeEndElement();
446
+                        output.writeStartElement("text");
447
+                        output.writeAttribute("x", "0.18in");
448
+                        output.writeAttribute("y", "0.71in");
449
+                        output.writeAttribute("font-size", "12");
450
+                        output.writeCDATA("400");
451
+                        output.writeEndElement();
452
+                        output.writeStartElement("line");
453
+                        output.writeAttribute("x1", "0.4in");
454
+                        output.writeAttribute("x2", "4.4in");
455
+                        output.writeAttribute("y1", "0.1in");
456
+                        output.writeAttribute("y2", "0.1in");
457
+                        output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
458
+                        output.writeEndElement();
459
+                        output.writeStartElement("text");
460
+                        output.writeAttribute("x", "0.18in");
461
+                        output.writeAttribute("y", "0.15in");
462
+                        output.writeAttribute("font-size", "12");
463
+                        output.writeCDATA("500");
464
+                        output.writeEndElement();
465
+                    }
466
+                    output.writeStartElement("line");
467
+                    output.writeAttribute("x1", "0.5in");
468
+                    output.writeAttribute("x2", "0.5in");
469
+                    output.writeAttribute("y1", "2.95in");
470
+                    output.writeAttribute("y2", "3.05in");
471
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
472
+                    output.writeEndElement();
473
+                    output.writeStartElement("text");
474
+                    output.writeAttribute("x", "0.47in");
475
+                    output.writeAttribute("y", "3.16in");
476
+                    output.writeAttribute("font-size", "12");
477
+                    output.writeCDATA("0");
478
+                    output.writeEndElement();
479
+                    output.writeStartElement("line");
480
+                    output.writeAttribute("x1", "0.89in");
481
+                    output.writeAttribute("x2", "0.89in");
482
+                    output.writeAttribute("y1", "2.95in");
483
+                    output.writeAttribute("y2", "3.05in");
484
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
485
+                    output.writeEndElement();
486
+                    output.writeStartElement("text");
487
+                    output.writeAttribute("x", "0.86in");
488
+                    output.writeAttribute("y", "3.16in");
489
+                    output.writeAttribute("font-size", "12");
490
+                    output.writeCDATA("2");
491
+                    output.writeEndElement();
492
+                    output.writeStartElement("line");
493
+                    output.writeAttribute("x1", "1.28in");
494
+                    output.writeAttribute("x2", "1.28in");
495
+                    output.writeAttribute("y1", "2.95in");
496
+                    output.writeAttribute("y2", "3.05in");
497
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
498
+                    output.writeEndElement();
499
+                    output.writeStartElement("text");
500
+                    output.writeAttribute("x", "1.25in");
501
+                    output.writeAttribute("y", "3.16in");
502
+                    output.writeAttribute("font-size", "12");
503
+                    output.writeCDATA("4");
504
+                    output.writeEndElement();
505
+                    output.writeStartElement("line");
506
+                    output.writeAttribute("x1", "1.67in");
507
+                    output.writeAttribute("x2", "1.67in");
508
+                    output.writeAttribute("y1", "2.95in");
509
+                    output.writeAttribute("y2", "3.05in");
510
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
511
+                    output.writeEndElement();
512
+                    output.writeStartElement("text");
513
+                    output.writeAttribute("x", "1.64in");
514
+                    output.writeAttribute("y", "3.16in");
515
+                    output.writeAttribute("font-size", "12");
516
+                    output.writeCDATA("6");
517
+                    output.writeEndElement();
518
+                    output.writeStartElement("line");
519
+                    output.writeAttribute("x1", "2.06in");
520
+                    output.writeAttribute("x2", "2.06in");
521
+                    output.writeAttribute("y1", "2.95in");
522
+                    output.writeAttribute("y2", "3.05in");
523
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
524
+                    output.writeEndElement();
525
+                    output.writeStartElement("text");
526
+                    output.writeAttribute("x", "2.03in");
527
+                    output.writeAttribute("y", "3.16in");
528
+                    output.writeAttribute("font-size", "12");
529
+                    output.writeCDATA("8");
530
+                    output.writeEndElement();
531
+                    output.writeStartElement("line");
532
+                    output.writeAttribute("x1", "2.45in");
533
+                    output.writeAttribute("x2", "2.45in");
534
+                    output.writeAttribute("y1", "2.95in");
535
+                    output.writeAttribute("y2", "3.05in");
536
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
537
+                    output.writeEndElement();
538
+                    output.writeStartElement("text");
539
+                    output.writeAttribute("x", "2.39in");
540
+                    output.writeAttribute("y", "3.16in");
541
+                    output.writeAttribute("font-size", "12");
542
+                    output.writeCDATA("10");
543
+                    output.writeEndElement();
544
+                    output.writeStartElement("line");
545
+                    output.writeAttribute("x1", "2.84in");
546
+                    output.writeAttribute("x2", "2.84in");
547
+                    output.writeAttribute("y1", "2.95in");
548
+                    output.writeAttribute("y2", "3.05in");
549
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
550
+                    output.writeEndElement();
551
+                    output.writeStartElement("text");
552
+                    output.writeAttribute("x", "2.78in");
553
+                    output.writeAttribute("y", "3.16in");
554
+                    output.writeAttribute("font-size", "12");
555
+                    output.writeCDATA("12");
556
+                    output.writeEndElement();
557
+                    output.writeStartElement("line");
558
+                    output.writeAttribute("x1", "3.23in");
559
+                    output.writeAttribute("x2", "3.23in");
560
+                    output.writeAttribute("y1", "2.95in");
561
+                    output.writeAttribute("y2", "3.05in");
562
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
563
+                    output.writeEndElement();
564
+                    output.writeStartElement("text");
565
+                    output.writeAttribute("x", "3.17in");
566
+                    output.writeAttribute("y", "3.16in");
567
+                    output.writeAttribute("font-size", "12");
568
+                    output.writeCDATA("14");
569
+                    output.writeEndElement();
570
+                    output.writeStartElement("line");
571
+                    output.writeAttribute("x1", "3.62in");
572
+                    output.writeAttribute("x2", "3.62in");
573
+                    output.writeAttribute("y1", "2.95in");
574
+                    output.writeAttribute("y2", "3.05in");
575
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
576
+                    output.writeEndElement();
577
+                    output.writeStartElement("text");
578
+                    output.writeAttribute("x", "3.56in");
579
+                    output.writeAttribute("y", "3.16in");
580
+                    output.writeAttribute("font-size", "12");
581
+                    output.writeCDATA("16");
582
+                    output.writeEndElement();
583
+                    output.writeStartElement("line");
584
+                    output.writeAttribute("x1", "4.01in");
585
+                    output.writeAttribute("x2", "4.01in");
586
+                    output.writeAttribute("y1", "2.95in");
587
+                    output.writeAttribute("y2", "3.05in");
588
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
589
+                    output.writeEndElement();
590
+                    output.writeStartElement("text");
591
+                    output.writeAttribute("x", "3.95in");
592
+                    output.writeAttribute("y", "3.16in");
593
+                    output.writeAttribute("font-size", "12");
594
+                    output.writeCDATA("18");
595
+                    output.writeEndElement();
596
+                    output.writeStartElement("line");
597
+                    output.writeAttribute("x1", "4.4in");
598
+                    output.writeAttribute("x2", "4.4in");
599
+                    output.writeAttribute("y1", "2.95in");
600
+                    output.writeAttribute("y2", "3.05in");
601
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
602
+                    output.writeEndElement();
603
+                    output.writeStartElement("text");
604
+                    output.writeAttribute("x", "4.34in");
605
+                    output.writeAttribute("y", "3.16in");
606
+                    output.writeAttribute("font-size", "12");
607
+                    output.writeCDATA("20");
608
+                    output.writeEndElement();
609
+                    sourceFile.close();
610
+                    sourceFile.open(3);
611
+                    input = new XmlReader(sourceFile);
612
+                    var lineStyles = new Array();
613
+                    lineStyles.push("stroke:rgb(255,0,0);stroke-width:1");
614
+                    lineStyles.push("stroke:rgb(0,255,0);stroke-width:1");
615
+                    lineStyles.push("stroke:rgb(0,0,255);stroke-width:1");
616
+                    lineStyles.push("stroke:rgb(255,255,0);stroke-width:1");
617
+                    lineStyles.push("stroke:rgb(255,0,255);stroke-width:1");
618
+                    lineStyles.push("stroke:rgb(0,255,255);stroke-width:1");
619
+                    var check1 = false;
620
+                    var drawable = false;
621
+                    var previousX;
622
+                    var currentX;
623
+                    var previousY = new Array();
624
+                    input.readNext();
625
+                    while(!input.atEnd())
626
+                    {
627
+                        if(input.isStartElement())
628
+                        {
629
+                            if(input.name() == "time")
630
+                            {
631
+                                if(check1)
632
+                                {
633
+                                    previousX = currentX;
634
+                                }
635
+                                var tstring = input.readElementText();
636
+                                var tsplit1 = tstring.split(":");
637
+                                var tsplit2 = tsplit1[1].split(".");
638
+                                currentX = 0.5 + (Number(tsplit1[0])*0.195) + (Number(tsplit2[0])*0.00325);// + (Number(tsplit2[1]) * 0.00000325);
639
+                                if(check1)
640
+                                {
641
+                                    drawable = true;
642
+                                }
643
+                                check1 = true;
644
+                            }
645
+                            if(input.name() == "temperature")
646
+                            {
647
+                                var series;
648
+                                for(var i = 0; i < tempMap.length; i++)
649
+                                {
650
+                                    if(tempMap[i] == input.attribute("series"))
651
+                                    {
652
+                                        series = i;
653
+                                        break;
654
+                                    }
655
+                                }
656
+                                var currentY = 2.9 - Number(input.readElementText()) * 0.0056;
657
+                                if(drawable)
658
+                                {
659
+                                    output.writeStartElement("line");
660
+                                    output.writeAttribute("style", lineStyles[series % 6]);
661
+                                    output.writeAttribute("x1", String(previousX)+"in");
662
+                                    output.writeAttribute("x2", String(currentX)+"in");
663
+                                    output.writeAttribute("y1", String(previousY[series])+"in");
664
+                                    output.writeAttribute("y2", String(currentY)+"in");
665
+                                    output.writeEndElement();
666
+                                }
667
+                                previousY[series] = currentY;
668
+                            }
669
+                        }
670
+                        input.readNext();
671
+                    }
672
+                    sourceFile.remove();
673
+                    sourceFile.close();
674
+                    output.writeEndElement();
675
+                    output.writeStartElement("div");
676
+                    output.writeAttribute("style", "margin-left:3in;margin-top:0.5in");
677
+                    var lossField = findChildObject(window, 'loss');
678
+                    var tolField = findChildObject(window, 'tolerance');
679
+                    if(lossField.text != "")
680
+                    {
681
+                        output.writeStartElement("p");
682
+                        output.writeCDATA("Weight loss: ");
683
+                        output.writeCDATA(lossField.text);
684
+                        if(tolField.text != "")
685
+                        {
686
+                            output.writeCDATA("±");
687
+                            output.writeCDATA(tolField.text);
688
+                        }
689
+                        output.writeCDATA("%");
690
+                        output.writeEndElement();
691
+                        output.writeStartElement("table");
692
+                        output.writeStartElement("tr");
693
+                        output.writeStartElement("th");
694
+                        output.writeCDATA("Roasted");
695
+                        output.writeEndElement();
696
+                        output.writeStartElement("th");
697
+                        output.writeCDATA("Green");
698
+                        output.writeEndElement();
699
+                        output.writeEndElement();
700
+                        var green;
701
+                        var roasted;
702
+                        var loss = (Number(lossField.text) + Number(tolField.text)) / 100;
703
+                        for(roasted = 1; roasted < 30; roasted++)
704
+                        {
705
+                            green = (1/-(loss-1)) * roasted;
706
+                            if(green > 30)
707
+                            {
708
+                                break;
709
+                            }
710
+                            if(roasted % 5 == 0)
711
+                            {
712
+                                output.writeStartElement("tr");
713
+                                output.writeStartElement("td");
714
+                                output.writeAttribute("align", "center");
715
+                                output.writeCDATA(roasted);
716
+                                output.writeEndElement();
717
+                                output.writeStartElement("td");
718
+                                output.writeAttribute("align", "center");
719
+                                output.writeCDATA(green.toFixed(2));
720
+                                output.writeEndElement();
721
+                                output.writeEndElement();
722
+                            }
723
+                        }
724
+                        roasted--;
725
+                        if(roasted % 5 > 0)
726
+                        {
727
+                            green = (1/-(loss-1)) * roasted;
728
+                            output.writeStartElement("tr");
729
+                            output.writeStartElement("td");
730
+                            output.writeAttribute("align", "center");
731
+                            output.writeCDATA(roasted);
732
+                            output.writeEndElement();
733
+                            output.writeStartElement("td");
734
+                            output.writeAttribute("align", "center");
735
+                            output.writeCDATA(green.toFixed(2));
736
+                            output.writeEndElement();
737
+                            output.writeEndElement();
738
+                        }
739
+                        output.writeEndElement();
740
+                    }
741
+                    var noteField = findChildObject(window, 'notes');
742
+                    if(noteField.text != "")
743
+                    {
744
+                        output.writeStartElement("p");
745
+                        output.writeCDATA(noteField.text);
746
+                        output.writeEndElement();
747
+                    }
748
+                    output.writeEndElement();
749
+                    output.writeEndElement();
750
+                    output.writeEndElement();
751
+                    output.writeEndElement();
752
+                    output.writeEndDocument();
753
+                    destFile.close();
754
+                    QSettings.setValue("script/lastDir", dir(filename));
755
+                    window.close();
756
+                }
757
+            });
758
+        ]]>
759
+    </program>
760
+</window>

+ 276
- 0
config/Windows/externalroaster.xml View File

@@ -0,0 +1,276 @@
1
+<window id="basicWindow">
2
+    <layout type="vertical">
3
+        <splitter type = "vertical" id = "main">
4
+            <splitter type = "horizontal" id = "indicators">
5
+                <decoration name="Bean Temperature" type="vertical">
6
+                    <lcdtemperature id = "beans" />
7
+                </decoration>
8
+                <decoration name="Air Temperature" type="vertical">
9
+                    <lcdtemperature id = "environment" />
10
+                </decoration>
11
+                <decoration name="Batch Timer" type="vertical">
12
+                    <lcdtimer format="mm:ss" id="batch" />
13
+                </decoration>
14
+            </splitter>
15
+            <widget id="widget">
16
+                <layout type="horizontal">
17
+                    <button name="Start Batch" type="push" id="startbutton" />
18
+                    <button name="Stop Batch" type="annotation" id="stopbutton" series="1" column="3" annotation="End" />
19
+                    <spinbox id="manometer" series="1" column="3" min="0" max="10" step="0.1" decimals="1" />
20
+                    <button name="New Sample" type="annotation" id="sample" series="1" column="3" annotation="Sample %1" />
21
+                </layout>
22
+            </widget>
23
+            <splitter type="horizontal" id="logsplit">
24
+                <measurementtable id="log">
25
+                    <column>Time</column>
26
+                    <column>Bean</column>
27
+                    <column>Air</column>
28
+                    <column>Note</column>
29
+                    <column>.</column>
30
+                    <column>.</column>
31
+                    <column>.</column>
32
+                </measurementtable>
33
+                <graph id="graph" />
34
+            </splitter>
35
+        </splitter>
36
+    </layout>
37
+    <menu name="File">
38
+        <item id="open" shortcut="Ctrl+O">Open…</item>
39
+        <item id="save" shortcut="Ctrl+S">Save…</item>
40
+        <item id="export">Export CSV…</item>
41
+        <item id="quit" shortcut="Ctrl+Q">Quit</item>
42
+    </menu>
43
+    <menu name="Batch">
44
+        <item id="new" shortcut="Ctrl+N">New Batch…</item>
45
+    </menu>
46
+    <menu name="Log">
47
+        <item id="clear" shortcut="Ctrl+L">Clear Log</item>
48
+        <separator />
49
+        <item id="ms">Millisecond View</item>
50
+        <item id="1s">1 Second View</item>
51
+        <item id="5s">5 Second View</item>
52
+        <item id="10s">10 Second View</item>
53
+        <item id="15s">15 Second View</item>
54
+        <item id="30s">30 Second View</item>
55
+        <item id="1m">1 Minute View</item>
56
+        <separator />
57
+        <item id="manual" shortcut="Ctrl+E">Manual Entry</item>
58
+    </menu>
59
+    <program>
60
+        lc = 1;
61
+        this.restoreSizeAndPosition('window');
62
+        var vsplit = findChildObject(this, 'main');
63
+        vsplit.restoreState("script/mainSplitter");
64
+        var isplit = findChildObject(this, 'indicators');
65
+        isplit.restoreState("script/instrumentSplitter");
66
+        var lsplit = findChildObject(this, 'logsplit');
67
+        lsplit.restoreState("script/logSplitter");
68
+        var log = findChildObject(this, 'log');
69
+        this.show();
70
+        log.restoreState("script/log", 7);
71
+        var window = this;
72
+        this.aboutToClose.connect(function() {
73
+            window.saveSizeAndPosition("window");
74
+            vsplit.saveState("script/mainSplitter");
75
+            isplit.saveState("script/instrumentSplitter");
76
+            lsplit.saveState("script/logSplitter");
77
+            log.saveState("script/log", 7);
78
+            loggingWindow = undefined;
79
+        });
80
+        vsplit.restoreState("script/mainSplitter");
81
+        isplit.restoreState("script/instrumentSplitter");
82
+        lsplit.restoreState("script/logSplitter");
83
+        var device = new DAQ('Dev1');
84
+        var bchannel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeJ);
85
+        var achannel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeJ);
86
+        device.setClockRate(2.0);
87
+        device.start();
88
+        beanDisplay = findChildObject(this, 'beans');
89
+        envDisplay = findChildObject(this, 'environment');
90
+        bchannel.newData.connect(beanDisplay.setValue);
91
+        achannel.newData.connect(envDisplay.setValue);
92
+        var epoch = new QTime;
93
+        epoch = epoch.currentTime;
94
+        var boffset = new MeasurementTimeOffset(epoch);
95
+        var aoffset = new MeasurementTimeOffset(epoch);
96
+        badapt = new MeasurementAdapter(1);
97
+        aadapt = new MeasurementAdapter(2);
98
+        bzero = new ZeroEmitter(1);
99
+        azero = new ZeroEmitter(2);
100
+        bchannel.newData.connect(boffset.newMeasurement);
101
+        achannel.newData.connect(aoffset.newMeasurement);
102
+        boffset.measurement.connect(badapt.newMeasurement);
103
+        aoffset.measurement.connect(aadapt.newMeasurement);
104
+        bchannel.newData.connect(bzero.newMeasurement);
105
+        achannel.newData.connect(azero.newMeasurement);
106
+        var graph = findChildObject(this, 'graph');
107
+        bzero.measurement.connect(log.newMeasurement);
108
+        bzero.measurement.connect(graph.newMeasurement);
109
+        azero.measurement.connect(log.newMeasurement);
110
+        azero.measurement.connect(graph.newMeasurement);
111
+        var timer = findChildObject(this, 'batch');
112
+        timer.autoReset = true;
113
+        var start = findChildObject(this, 'startbutton');
114
+        start.clicked.connect(function() {
115
+            var epoch = new QTime();
116
+            epoch = epoch.currentTime();
117
+            timer.startTimer();
118
+            boffset.setZeroTime(epoch);
119
+            aoffset.setZeroTime(epoch);
120
+            bzero.emitZero();
121
+            azero.emitZero();
122
+            aadapt.measurement.connect(log.newMeasurement);
123
+            aadapt.measurement.connect(graph.newMeasurement);
124
+            badapt.measurement.connect(log.newMeasurement);
125
+            badapt.measurement.connect(graph.newMeasurement);
126
+            if(typeof(currentBatchInfo) == 'undefined') { } else {
127
+                var query = new QSqlQuery();
128
+                query.exec("SELECT now()::timestamp without time zone");
129
+                query.next();
130
+                var result = query.value(0);
131
+                var timefield = findChildObject(currentBatchInfo, 'time');
132
+                timefield.text = result.replace('T', ' ');
133
+            }
134
+        });
135
+        start.setFocus();
136
+        var spin = findChildObject(this, 'manometer');
137
+        spin.annotation.connect(log.newAnnotation);
138
+        var stop = findChildObject(this, 'stopbutton');
139
+        stop.annotation.connect(log.newAnnotation);
140
+        stop.clicked.connect(timer.stopTimer);
141
+        stop.clicked.connect(function() {
142
+            badapt.measurement.disconnect(log.newMeasurement);
143
+            badapt.measurement.disconnect(graph.newMeasurement);
144
+            aadapt.measurement.disconnect(log.newMeasurement);
145
+            aadapt.measurement.disconnect(graph.newMeasurement);
146
+            spin.resetChange();
147
+            if(typeof(currentBatchInfo) == 'undefined') { } else {
148
+                var duration = log.lastTime(lc);
149
+                var durfield = findChildObject(currentBatchInfo, 'duration');
150
+                durfield.text = duration;
151
+                log.clearOutputColumns();
152
+                log.addOutputTemperatureColumn(lc);
153
+                log.addOutputTemperatureColumn(lc + 1);
154
+                log.addOutputAnnotationColumn(lc + 2);
155
+                var filename = log.saveTemporary();
156
+                currentBatchInfo.tempData = filename;
157
+                currentBatchInfo.raise();
158
+                currentBatchInfo.activateWindow();
159
+            }
160
+        });
161
+        var sample = findChildObject(this, 'sample');
162
+        sample.annotation.connect(log.newAnnotation);
163
+        var openMenu = findChildObject(this, 'open');
164
+        var window = this;
165
+        openMenu.triggered.connect(function() {
166
+            var filename = QFileDialog.getOpenFileName(window, 'Open Log…', QSettings.value('script/lastDir', '') + '/');
167
+            if(filename != '') {
168
+                var file = new QFile(filename);
169
+                var input = new XMLInput(file, 1);
170
+                input.newTemperatureColumn.connect(log.setHeaderData);
171
+                input.newAnnotationColumn.connect(log.setHeaderData);
172
+                input.measure.connect(graph.newMeasurement);
173
+                input.measure.connect(log.newMeasurement);
174
+                input.annotation.connect(log.newAnnotation);
175
+                input.lastColumn.connect(function(c) {
176
+                    lc = c + 1;
177
+                    badapt.setColumn(c + 1);
178
+                    aadapt.setColumn(c + 2);
179
+                    bzero.setColumn(c + 1);
180
+                    azero.setColumn(c + 2);
181
+                    stop.setTemperatureColumn(c + 1);
182
+                    stop.setAnnotationColumn(c + 3);
183
+                    sample.setTemperatureColumn(c + 1);
184
+                    sample.setAnnotationColumn(c + 3);
185
+                    spin.setTemperatureColumn(c + 1);
186
+                    spin.setAnnotationColumn(c + 3);
187
+                    log.setHeaderData(c + 1, "Bean");
188
+                    log.setHeaderData(c + 2, "Air");
189
+                    log.setHeaderData(c + 3, "Note");
190
+                });
191
+                input.input();
192
+                window.windowTitle = 'Typica - ' + baseName(filename);
193
+                QSettings.setValue("script/lastDir", dir(filename));
194
+            }
195
+        });
196
+        var quitMenu = findChildObject(this, 'quit');
197
+        quitMenu.triggered.connect(function() {
198
+            window.close();
199
+            Application.quit();
200
+        });
201
+        var saveMenu = findChildObject(this, 'save');
202
+        saveMenu.triggered.connect(function() {
203
+            var filename = QFileDialog.getSaveFileName(window, "Save Log As…", QSettings.value("script/lastDir", "") + "/");
204
+            if(filename != "") {
205
+                var file = new QFile(filename);
206
+                log.clearOutputColumns();
207
+                log.addOutputTemperatureColumn(lc);
208
+                log.addOutputTemperatureColumn(lc + 1);
209
+                log.addOutputAnnotationColumn(lc + 2);
210
+                log.saveXML(file);
211
+                QSettings.setValue("script/lastDir", dir(filename));
212
+            }
213
+        });
214
+        var exportMenu = findChildObject(this, 'export');
215
+        exportMenu.triggered.connect(function() {
216
+            var filename = QFileDialog.getSaveFileName(window, "Export CSV As…", QSettings.value("script/lastDir", "") + "/");
217
+            if(filename != "") {
218
+                var file = new QFile(filename);
219
+                log.clearOutputColumns();
220
+                log.addOutputTemperatureColumn(lc);
221
+                log.addOutputTemperatureColumn(lc + 1);
222
+                log.addOutputAnnotationColumn(lc + 2);
223
+                log.saveCSV(file);
224
+                QSettings.setValue("script/lastDir", dir(filename));
225
+            }
226
+        });
227
+        var clear = findChildObject(this, 'clear');
228
+        clear.triggered.connect(log.clear);
229
+        clear.triggered.connect(graph.clear);
230
+        clear.triggered.connect(function() {
231
+            window.windowTitle = "Typica";
232
+            log.setHeaderData(0, "Time");
233
+            log.setHeaderData(1, "Bean");
234
+            log.setHeaderData(2, "Air");
235
+            log.setHeaderData(3, "Note");
236
+            log.setHeaderData(4, "");
237
+            log.setHeaderData(5, "");
238
+            log.setHeaderData(6, "");
239
+            lc = 1;
240
+            badapt.setColumn(1);
241
+            aadapt.setColumn(2);
242
+            bzero.setColumn(1);
243
+            azero.setColumn(2);
244
+            stop.setTemperatureColumn(1);
245
+            stop.setAnnotationColumn(3);
246
+            sample.setTemperatureColumn(1);
247
+            sample.setAnnotationColumn(3);
248
+            spin.setTemperatureColumn(1);
249
+            spin.setAnnotationColumn(3);
250
+        });
251
+        var v1 = findChildObject(this, 'ms');
252
+        v1.triggered.connect(log.LOD_ms);
253
+        var v2 = findChildObject(this, '1s');
254
+        v2.triggered.connect(log.LOD_1s);
255
+        var v3 = findChildObject(this, '5s');
256
+        v3.triggered.connect(log.LOD_5s);
257
+        var v4 = findChildObject(this, '10s');
258
+        v4.triggered.connect(log.LOD_10s);
259
+        var v5 = findChildObject(this, '15s');
260
+        v5.triggered.connect(log.LOD_15s);
261
+        var v6 = findChildObject(this, '30s');
262
+        v6.triggered.connect(log.LOD_30s);
263
+        var v7 = findChildObject(this, '1m');
264
+        v7.triggered.connect(log.LOD_1m);
265
+        var manual = findChildObject(this, 'manual');
266
+        manual.triggered.connect(function() {
267
+            var entry = new LogEditWindow();
268
+            entry.show();
269
+        });
270
+        var newMenu = findChildObject(this, 'new');
271
+        newMenu.triggered.connect(function() {
272
+            var bwindow = createWindow("batchWindow");
273
+            bwindow.windowTitle = "Typica - New Batch";
274
+        });
275
+    </program>
276
+</window>

+ 101
- 0
config/Windows/greeninventory.xml View File

@@ -0,0 +1,101 @@
1
+<window id="inventory">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <sqldrop data="0" display="1" showdata="true" id="item">
5
+                <query><![CDATA[SELECT id, name FROM coffees WHERE quantity <> 0 ORDER BY name ASC]]></query>
6
+            </sqldrop>
7
+            <line id="quantity" />
8
+            <sqldrop id="units" />
9
+            <button type="push" name="Update" id="update" />
10
+        </layout>
11
+        <textarea id="current" />
12
+    </layout>
13
+    <program>
14
+        <![CDATA[
15
+			var units = findChildObject(this, 'units');
16
+			units.addItem("bag");
17
+			units.addItem("lb");
18
+			var items = findChildObject(this, 'item');
19
+			var status = findChildObject(this, 'current');
20
+			var q = "SELECT quantity FROM items WHERE id = ";
21
+			q = q + items.currentData();
22
+			query = new QSqlQuery();
23
+			query.exec(q);
24
+			query.next();
25
+			var text = items.currentText;
26
+			text = text + " Current inventory: ";
27
+			text = text + query.value(0);
28
+			text = text + " pounds (";
29
+			q = "SELECT ";
30
+			q = q + query.value(0);
31
+			q = q + " / (SELECT conversion FROM lb_bag_conversion WHERE item = ";
32
+			q = q + items.currentData();
33
+			q = q + ")";
34
+			query.exec(q);
35
+			query.next();
36
+			text = text + query.value(0);
37
+			text = text + " bags)";
38
+            query = query.invalidate();
39
+			status.plainText = text;
40
+			var button = findChildObject(this, 'update');
41
+			var value = findChildObject(this, 'quantity');
42
+			button.clicked.connect(function() {
43
+				q = "INSERT INTO inventory VALUES ('now', ";
44
+				q = q + items.currentData();
45
+				q = q + ", ";
46
+				if(units.currentText == "lb") {
47
+					q = q + value.text;
48
+				} else {
49
+					q = q + value.text;
50
+					q = q + " * (SELECT conversion FROM lb_bag_conversion WHERE item = ";
51
+					q = q + items.currentData();
52
+					q = q + ")";
53
+				}
54
+				q = q + ")";
55
+                query = new QSqlQuery();
56
+				query.exec(q);
57
+				text = items.currentText;
58
+				q = "SELECT quantity FROM items WHERE id = ";
59
+				q = q + items.currentData();
60
+				query.exec(q);
61
+				query.next();
62
+				text = text + " Current inventory: ";
63
+				text = text + query.value(0);
64
+				text = text + " pounds (";
65
+				q = "SELECT ";
66
+				q = q + query.value(0);
67
+				q = q + " / (SELECT conversion FROM lb_bag_conversion WHERE item = ";
68
+				q = q + items.currentData();
69
+				q = q + ")";
70
+				query.exec(q);
71
+				query.next();
72
+				text = text + query.value(0);
73
+				text = text + " bags)";
74
+				status.plainText = text;
75
+                query = query.invalidate();
76
+			});
77
+			items['currentIndexChanged(int)'].connect(function() {
78
+				q = "SELECT quantity FROM items WHERE id = ";
79
+				q = q + items.currentData();
80
+                query = new QSqlQuery();
81
+				query.exec(q);
82
+				query.next();
83
+				var text = items.currentText;
84
+				text = text + " Current inventory: ";
85
+				text = text + query.value(0);
86
+				text = text + " pounds (";
87
+				q = "SELECT ";
88
+				q = q + query.value(0);
89
+				q = q + " / (SELECT conversion FROM lb_bag_conversion WHERE item = ";
90
+				q = q + items.currentData();
91
+				q = q + ")";
92
+				query.exec(q);
93
+				query.next();
94
+				text = text + query.value(0);
95
+				text = text + " bags)";
96
+				status.plainText = text;
97
+                query = query.invalidate();
98
+			});
99
+        ]]>
100
+    </program>
101
+</window>

+ 79
- 0
config/Windows/greensales.xml View File

@@ -0,0 +1,79 @@
1
+<window id="greensales">
2
+	<layout type="vertical">
3
+		<layout type="horizontal">
4
+			<label>Date:</label>
5
+			<calendar id="date" />
6
+			<label>Customer:</label>
7
+			<line id="customer" />
8
+			<label>Weight Unit:</label>
9
+			<sqldrop data="0" display="0" showdata="false" editable="false" id="units" />
10
+		</layout>
11
+		<sqltablearray columns="2" id="coffees">
12
+			<column name="Coffee" delegate="sql" showdata="true" null="false" data="0" display="1">
13
+				<![CDATA[
14
+					SELECT id, name FROM coffees WHERE quantity <> 0 ORDER BY name
15
+				]]>
16
+			</column>
17
+			<column name="Weight" delegate="numeric" />
18
+		</sqltablearray>
19
+		<button name="Submit" id="submit" type="push" />
20
+	</layout>
21
+	<program>
22
+		<![CDATA[
23
+			var window = this;
24
+			this.windowTitle = 'Typica - Enter Green Coffee Sales';
25
+			var unitBox = findChildObject(this, 'units');
26
+			unitBox.addItem("g");
27
+			unitBox.addItem("Kg");
28
+			unitBox.addItem("oz");
29
+			unitBox.addItem("lb");
30
+			var convertToPounds = function(w, u) {
31
+				switch(u)
32
+				{
33
+					case "g":
34
+						return w * 0.0022;
35
+					case "oz":
36
+						return w * 0.0625;
37
+					case "Kg":
38
+						return w * 2.2;
39
+				}
40
+				return w;
41
+			};
42
+			var dateField = findChildObject(this, 'date');
43
+			var customerField = findChildObject(this, 'customer');
44
+			var items = findChildObject(this, 'coffees');
45
+			var submit = findChildObject(this, 'submit');
46
+			submit.clicked.connect(function() {
47
+				var query = new QSqlQuery();
48
+				query.prepare("INSERT INTO sale VALUES(:time, :item, :quantity, :customer)");
49
+				query.bind(":time", dateField.text);
50
+				if(customerField.text == "") {
51
+					query.bind(":customer", null);
52
+				}
53
+				else {
54
+					query.bind(":customer", customerField.text);
55
+				}
56
+				var coffeesArray = sqlToArray(items.columnArray(0, 32));
57
+				if(coffeesArray.length > 0)
58
+				{
59
+					for(var i = 0; i < coffeesArray.length; i++)
60
+					{
61
+						if(items.data(i, 0, 32).value == '')
62
+						{
63
+							continue;
64
+						}
65
+						if(items.data(i, 1, 0).value == '')
66
+						{
67
+							continue;
68
+						}
69
+						query.bind(":item", items.data(i, 0, 32).value);
70
+						query.bind(":quantity", convertToPounds(items.data(i, 1, 0).value, unitBox.currentText));
71
+						query.exec();
72
+					}
73
+				}
74
+				query = query.invalidate();
75
+				window.close();
76
+			});
77
+		]]>
78
+	</program>
79
+</window>

+ 45
- 0
config/Windows/history.xml View File

@@ -0,0 +1,45 @@
1
+<window id="history">
2
+    <layout type="vertical">
3
+        <sqlview id="table" />
4
+    </layout>
5
+    <program>
6
+        <![CDATA[
7
+			var q = "SELECT time, machine, (SELECT name FROM items WHERE id = roasted_id) AS name, unroasted_total_quantity AS green, roasted_quantity AS roasted, ((unroasted_total_quantity - roasted_quantity) / unroasted_total_quantity * 100::numeric)::numeric(12,2) AS weight_loss, duration FROM roasting_log ORDER BY time DESC";
8
+			//var q = "SELECT time, name, unroasted_total_quantity AS green, roasted_quantity AS roasted, weight_loss AS loss, duration FROM short_log ORDER BY time DESC";
9
+			var table = findChildObject(this, 'table');
10
+			table.setQuery(q);
11
+			table.hideColumn(1);
12
+			table.openEntryRow.connect(function(arg) {
13
+				var details = createWindow("batchDetails");
14
+				details.loadData(table, arg);
15
+			});
16
+			/*
17
+			table.openEntry.connect(function(arg) {
18
+				var details = createWindow("batchDetails");
19
+				details.windowTitle = 'Typica - Batch Details';
20
+				q = "SELECT time, (SELECT name FROM items WHERE id = roasted_id) AS name, unroasted_total_quantity, roasted_quantity, duration, approval, files FROM roasting_log WHERE time = :time";
21
+				query = new QSqlQuery();
22
+                query.prepare(q);
23
+				query.bind(":time", arg);
24
+				query.exec();
25
+				query.next();
26
+				var timefield = findChildObject(details, 'time');
27
+				timefield.text = query.value(0);
28
+				var namefield = findChildObject(details, 'name');
29
+				namefield.text = query.value(1);
30
+				var greenfield = findChildObject(details, 'green');
31
+				greenfield.text = query.value(2);
32
+				var roastedfield = findChildObject(details, 'roasted');
33
+				roastedfield.text = query.value(3);
34
+				var durationfield = findChildObject(details, 'duration');
35
+				durationfield.text = query.value(4);
36
+				var approvalfield = findChildObject(details, 'approval');
37
+				approvalfield.text = query.value(5);
38
+				var filesfield = findChildObject(details, 'files');
39
+				filesfield.text = query.value(6);
40
+                query = query.invalidate();
41
+			});
42
+			*/
43
+        ]]>
44
+    </program>
45
+</window>

+ 36
- 0
config/Windows/importprofiles.xml View File

@@ -0,0 +1,36 @@
1
+<window id="importTargets">
2
+    <layout type="horizontal">
3
+        <sqldrop data="0" display="1" showdata="true" id="roasted">
4
+            <query>SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id IN (SELECT item FROM current_items) ORDER BY name</query>
5
+        </sqldrop>
6
+        <button name="File…" id="file" type="push" />
7
+    </layout>
8
+    <program>
9
+        var button = findChildObject(this, 'file');
10
+        var box = findChildObject(this, 'roasted');
11
+        var win = this;
12
+        button.clicked.connect(function() {
13
+            var filename = QFileDialog.getOpenFileName(win, 'Open Log…', QSettings.value('script/lastDir', '') + '/');
14
+            if(filename != '') {
15
+                QSettings.setValue("script/lastDir", dir(filename));
16
+                var q = "INSERT INTO files VALUES(default, :name, 'profile', NULL, :data) RETURNING id";
17
+                query = new QSqlQuery();
18
+                query.prepare(q);
19
+                query.bind(":name", baseName(filename));
20
+                query.bindFileData(":data", filename);
21
+                query.exec();
22
+                query.next();
23
+                var fileno = query.value(0);
24
+                var id = box.currentData();
25
+                q = "INSERT INTO item_files VALUES('now', ";
26
+                q = q + id;
27
+                q = q + ", '{";
28
+                q = q + fileno;
29
+                q = q + "}')";
30
+                query.exec(q);
31
+                query = query.invalidate();
32
+                var success = createWindow("success");
33
+            }
34
+        });
35
+    </program>
36
+</window>

+ 51
- 0
config/Windows/invoiceinfo.xml View File

@@ -0,0 +1,51 @@
1
+<window id="invoiceinfo">
2
+	<layout type="vertical">
3
+		<layout type="horizontal">
4
+			<label>Date:</label>
5
+			<line id="date" writable="false" />
6
+			<label>Vendor:</label>
7
+			<line id="vendor" writable="false" />
8
+			<label>Invoice:</label>
9
+			<line id="invoice" writable="false" />
10
+			<button id="edit" name="Edit" type="push" />
11
+		</layout>
12
+		<sqlview id="itemtable" />
13
+	</layout>
14
+	<program>
15
+		<![CDATA[
16
+			var window = this;
17
+			var table = findChildObject(this, 'itemtable');
18
+			this.setInvoiceID = function(arg) {
19
+				window.invoiceID = arg;
20
+				window.windowTitle = "Typica - Invoice Details " + arg;
21
+			};
22
+			button = findChildObject(this, 'edit');
23
+			button.clicked.connect(function() {
24
+				var editInvoiceDetails = createWindow("editinvoice");
25
+				editInvoiceDetails.invoiceID = window.invoiceID;
26
+				var invoiceLine = findChildObject(editInvoiceDetails, 'invoice');
27
+				var localInvoiceLine = findChildObject(window, 'invoice');
28
+				invoiceLine.text = localInvoiceLine.text;
29
+				editInvoiceDetails.invoiceID = window.invoiceID;
30
+			});
31
+			table.openEntryRow.connect(function(arg) {
32
+				if(table.data(arg, 0) == 'PURCHASE') {
33
+					var itemWindow = createWindow("invoiceitemdetail");
34
+					itemWindow.rowData = [];
35
+					for(var i = 0; i < 8; i++) {
36
+						itemWindow.rowData[i] = table.data(arg, i);
37
+					}
38
+					itemWindow.dataSet();
39
+				}
40
+				else {
41
+					var feeWindow = createWindow("invoicefeedetail");
42
+					feeWindow.rowData = [];
43
+					for(var i = 0; i < 8; i++) {
44
+						feeWindow.rowData[i] = table.data(arg, i);
45
+					}
46
+					feeWindow.dataSet();
47
+				}
48
+			});
49
+		]]>
50
+	</program>
51
+</window>

+ 28
- 0
config/Windows/invoicelist.xml View File

@@ -0,0 +1,28 @@
1
+<window id="invoicelist">
2
+	<layout type="vertical">
3
+		<sqlview id="table" />
4
+	</layout>
5
+	<program>
6
+		<![CDATA[
7
+			this.windowTitle = "Typica - Invoice List";
8
+			var table = findChildObject(this, 'table');
9
+			table.setQuery("SELECT id, time, invoice, vendor FROM invoices ORDER BY time DESC");
10
+			table.openEntry.connect(function(arg) {
11
+				var info = createWindow("invoiceinfo");
12
+				info.setInvoiceID(arg);
13
+				var query = new QSqlQuery();
14
+				query.exec("SELECT time, invoice, vendor FROM invoices WHERE id = " + arg);
15
+				query.next();
16
+				var timefield = findChildObject(info, 'date');
17
+				timefield.text = query.value(0);
18
+				var vendorfield = findChildObject(info, 'vendor');
19
+				vendorfield.text = query.value(2);
20
+				var invoicefield = findChildObject(info, 'invoice');
21
+				invoicefield.text = query.value(1);
22
+				var itemtable = findChildObject(info, 'itemtable');
23
+				itemtable.setQuery("SELECT record_type, item_id, description, (SELECT reference FROM items WHERE id = item_id) AS reference, (SELECT cost FROM purchase WHERE item = item_id) AS unit_cost, (SELECT quantity FROM purchase WHERE item = item_id) AS quantity, ((SELECT quantity FROM purchase WHERE item = item_id)/(SELECT conversion FROM lb_bag_conversion WHERE item = item_id))::numeric(12,2) AS sacks, cost FROM invoice_items WHERE invoice_id = " + arg + " AND record_type = 'PURCHASE' UNION SELECT record_type, NULL, description, NULL, NULL, NULL, NULL, cost FROM invoice_items WHERE invoice_id = " + arg + " AND record_type = 'FEE' ORDER BY item_id");
24
+				query = query.invalidate();
25
+			});
26
+		]]>
27
+	</program>
28
+</window>

+ 229
- 0
config/Windows/navigation.xml View File

@@ -0,0 +1,229 @@
1
+<window id="navwindow">
2
+	<layout type="grid">
3
+		<row>
4
+			<column>
5
+				<button name="Configure Roasters" id="configure" type="push" />
6
+			</column>
7
+		</row>
8
+		<row>
9
+			<column>
10
+				<sqldrop id="machineselector" />
11
+			</column>
12
+			<column>
13
+				<button name="Roast Coffee" id="roast" type="push" />
14
+			</column>
15
+		</row>
16
+		<row>
17
+			<column>
18
+				<button name="Purchase Green Coffee" id="green" type="push" />
19
+			</column>
20
+		</row>
21
+		<row>
22
+			<column>
23
+				<button name="Manage Roasted Coffee Items" id="newroasted" type="push" />
24
+			</column>
25
+		</row>
26
+		<row>
27
+			<column>
28
+				<button name="Update Inventory" id="inventory" type="push" />
29
+			</column>
30
+		</row>
31
+		<row>
32
+			<column>	
33
+				<button name="Batch Log" id="history" type="push" />
34
+			</column>
35
+		</row>
36
+		<row>
37
+			<column>	
38
+				<button name="New Cupping Session" id="createcupping" type="push" />
39
+			</column>
40
+		</row>
41
+		<row>
42
+			<column>	
43
+				<button name="Join Cupping Session" id="joincupping" type="push" />
44
+			</column>
45
+		</row>
46
+		<row>
47
+			<column>	
48
+				<button name="Summarize Cupping Session" id="sumcupping" type="push" />
49
+			</column>
50
+		</row>
51
+		<row>
52
+			<column>	
53
+				<button name="Import Target Roast Profiles" id="target" type="push" />
54
+			</column>
55
+		</row>
56
+		<row>
57
+			<column>	
58
+				<button name="Invoice List" id="invoicelist" type="push" />
59
+			</column>
60
+		</row>
61
+		<row>
62
+			<column>	
63
+				<button name="Enter Green Coffee Sales" id="greensales" type="push" />
64
+			</column>
65
+		</row>
66
+	</layout>
67
+    <menu name="Reports" type="reports" src="Reports" />
68
+	<menu name="Database">
69
+		<item id="resetconnection">Forget Connection Details</item>
70
+	</menu>
71
+    <program>
72
+		var window = this;
73
+		var navigationwindow = window;
74
+		window.loggingWindow = undefined;
75
+		var roasterlist = findChildObject(this, 'machineselector');
76
+		var model = new DeviceTreeModel;
77
+		roasterlist.setModel(model);
78
+		roasterlist.currentIndex = QSettings.value("machineSelection", 0);
79
+		roasterlist['currentIndexChanged(int)'].connect(function() {
80
+			QSettings.setValue("machineSelection", roasterlist.currentIndex);
81
+		});
82
+		var resetdbconnection = findChildObject(this, 'resetconnection');
83
+		resetdbconnection.triggered.connect(function() {
84
+			QSettings.setValue("database/exists", false);
85
+			QSettings.setValue("database/hostname", "");
86
+			QSettings.setValue("database/dbname", "");
87
+			QSettings.setValue("database/user", "");
88
+			QSettings.setValue("database/password", "");
89
+		});
90
+		var greensalesbutton = findChildObject(this, 'greensales');
91
+		greensalesbutton.clicked.connect(function() {
92
+			createWindow("greensales");
93
+		});
94
+		var invoicesbutton = findChildObject(this, 'invoicelist');
95
+		invoicesbutton.clicked.connect(function() {
96
+			createWindow("invoicelist");
97
+		});
98
+        var sumcup = findChildObject(this, 'sumcupping');
99
+        sumcup.clicked.connect(function() {
100
+            var sessionlist = createWindow("finsessionlist");
101
+            sessionlist.windowTitle = "Typica - Summarize Cupping Session";
102
+        });
103
+        var ncsbutton = findChildObject(this, 'createcupping')
104
+        ncsbutton.clicked.connect(function() {
105
+            var ncswindow = createWindow("session");
106
+            ncswindow.windowTitle = "Typica - New Cupping Session";
107
+        });
108
+        var jcsbutton = findChildObject(this, 'joincupping')
109
+        jcsbutton.clicked.connect(function() {
110
+            var jcswindow = createWindow("sessionlist");
111
+            jcswindow.windowTitle = "Typica - Join Cupping Session";
112
+        });
113
+		/*
114
+        var nrbutton = findChildObject(this, 'newroaster');
115
+        nrbutton.clicked.connect(function() {
116
+            var nrwindow = createWindow("newroaster");
117
+            nrwindow.windowTitle = "Typica - New Roaster";
118
+        });
119
+		*/
120
+        var inventory = findChildObject(this, 'inventory');
121
+        inventory.clicked.connect(function() {
122
+            var invwin = createWindow("inventory");
123
+            invwin.windowTitle = "Typica - Inventory";
124
+        });
125
+        var history = findChildObject(this, 'history');
126
+        history.clicked.connect(function() {
127
+            var histwindow = createWindow("history");
128
+            histwindow.windowTitle = "Typica - Batch Log";
129
+        });
130
+        var gbutton = findChildObject(this, 'green');
131
+        gbutton.clicked.connect(function() {
132
+            var purchasewindow = createWindow("purchase");
133
+        });
134
+        var nrbutton = findChildObject(this, 'newroasted');
135
+        nrbutton.clicked.connect(function() {
136
+            var nrwindow = createWindow("newroasted");
137
+            nrwindow.windowTitle = "New Roasted Coffee Item";
138
+        });
139
+        var importb = findChildObject(this, 'target');
140
+        importb.clicked.connect(function() {
141
+            var importWindow = createWindow("importTargets");
142
+            importWindow.windowTitle = "Typica - Import Target Roast Profiles";
143
+        });
144
+        var roastbutton = findChildObject(this, 'roast');
145
+        roastbutton.clicked.connect(function() {
146
+            if(typeof(window.loggingWindow) == "undefined")
147
+            {
148
+                window.loggingWindow = createWindow("basicWindow");
149
+                window.loggingWindow.windowTitle = "Typica";
150
+				window.loggingWindow.navigationWindow = window;
151
+            }
152
+            else
153
+            {
154
+				print(window.loggingWindow);
155
+                window.loggingWindow.raise();
156
+                window.loggingWindow.activateWindow();
157
+            }
158
+        });
159
+		var configurebutton = findChildObject(this, 'configure');
160
+		configurebutton.clicked.connect(function() {
161
+			var confwindow = new DeviceConfigurationWindow;
162
+			confwindow.show();
163
+		});
164
+        <![CDATA[
165
+				query = new QSqlQuery();
166
+                query.exec("CREATE TABLE certifications (item bigint NOT NULL, certification text NOT NULL)");
167
+                query.exec("CREATE TABLE cupping_samples (session bigint NOT NULL, sample text NOT NULL, position bigint NOT NULL, type text NOT NULL, \"time\" timestamp without time zone, machine bigint, point text, item bigint)");
168
+                query.exec("CREATE TABLE cupping_sessions (id bigserial NOT NULL, event text, name text NOT NULL, \"time\" timestamp without time zone NOT NULL, blind boolean NOT NULL, open boolean NOT NULL, note text)");
169
+                query.exec("CREATE TABLE cuppingforms (session bigint NOT NULL, sample text NOT NULL, position bigint NOT NULL, grader text, finalscore numeric, notes text, serialization text)");
170
+                query.exec("CREATE TABLE cuppingform_t1 (aroma numeric, flavor numeric, aftertaste numeric, acidity numeric, body numeric, uniformity numeric, balance numeric, cleancup numeric, sweetness numeric, overall numeric, total numeric) INHERITS (cuppingforms)");
171
+                query.exec("CREATE TABLE invoices (id bigserial PRIMARY KEY NOT NULL, invoice text, vendor text NOT NULL, \"time\" timestamp without time zone NOT NULL)");
172
+                query.exec("CREATE TABLE invoice_items (invoice_id bigint NOT NULL, record_type text NOT NULL, item_id bigint, description text NOT NULL, cost numeric NOT NULL)");
173
+				query.exec("CREATE TABLE transactions (\"time\" timestamp without time zone NOT NULL, item bigint NOT NULL)");
174
+				query.exec("CREATE TABLE inventory (quantity numeric NOT NULL) INHERITS (transactions)");
175
+				query.exec("CREATE TABLE loss (quantity numeric NOT NULL, reason text) INHERITS (transactions)");
176
+				query.exec("CREATE TABLE make (quantity numeric NOT NULL) INHERITS (transactions)");
177
+				query.exec("CREATE TABLE purchase (quantity numeric NOT NULL, cost numeric NOT NULL, vendor text NOT NULL) INHERITS (transactions)");
178
+				query.exec("CREATE TABLE sale (quantity numeric NOT NULL, customer text) INHERITS (transactions)");
179
+				query.exec("CREATE TABLE use (quantity numeric NOT NULL) INHERITS (transactions)");
180
+				query.exec("CREATE VIEW all_transactions AS ((((SELECT purchase.\"time\", purchase.item, purchase.quantity, purchase.cost, purchase.vendor, NULL::unknown AS reason, NULL::unknown AS customer, 'PURCHASE' AS type FROM purchase UNION SELECT use.\"time\", use.item, use.quantity, NULL::unknown AS cost, NULL::unknown AS vendor, NULL::unknown AS reason, NULL::unknown AS customer, 'USE' AS type FROM use) UNION SELECT inventory.\"time\", inventory.item, inventory.quantity, NULL::unknown AS cost, NULL::unknown AS vendor, NULL::unknown AS reason, NULL::unknown AS customer, 'INVENTORY' AS type FROM inventory) UNION SELECT loss.\"time\", loss.item, loss.quantity, NULL::unknown AS cost, NULL::unknown AS vendor, loss.reason, NULL::unknown AS customer, 'LOSS' AS type FROM loss) UNION SELECT make.\"time\", make.item, make.quantity, NULL::unknown AS cost, NULL::unknown AS vendor, NULL::unknown AS reason, NULL::unknown AS customer, 'MAKE' AS type FROM make) UNION SELECT sale.\"time\", sale.item, sale.quantity, NULL::unknown AS cost, NULL::unknown AS vendor, NULL::unknown AS reason, sale.customer, 'SALE' AS type FROM sale");
181
+				query.exec("CREATE FUNCTION time_range(bigint) RETURNS integer AS $$ BEGIN IF (SELECT quantity FROM items WHERE id = $1) > 0 THEN RETURN (SELECT current_date - min(time)::date + 1 FROM use WHERE item = $1); ELSE RETURN (SELECT max(time)::date - min(time)::date + 1 FROM use WHERE item = $1); END IF; END; $$ LANGUAGE plpgsql STRICT");
182
+				query.exec("CREATE TABLE items(id bigint NOT NULL, name text NOT NULL, reference text, unit text NOT NULL, quantity numeric DEFAULT 0, category text)");
183
+				query.exec("CREATE SEQUENCE items_id_seq INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1");
184
+				query.exec("CREATE TABLE coffees(origin text NOT NULL, region text, producer text, grade text, milling text, drying text) INHERITS (items)");
185
+				query.exec("CREATE VIEW coffee_history AS SELECT coffees.id, coffees.name, coffees.origin, coffees.quantity AS stock, (SELECT sum(use.quantity) AS sum FROM use WHERE (use.item = coffees.id)) AS used, time_range(coffees.id) AS \"interval\", ((SELECT (sum(use.quantity) / (time_range(use.item))::numeric) FROM use WHERE (use.item = coffees.id) GROUP BY use.item))::numeric(10,2) AS rate, (SELECT (('now'::text)::date + ((coffees.quantity / (SELECT (sum(use.quantity) / (time_range(use.item))::numeric) FROM use WHERE (use.item = coffees.id) GROUP BY use.item)))::integer)) AS \"out\" FROM coffees WHERE (coffees.id IN (SELECT use.item FROM use)) ORDER BY coffees.origin");
186
+				query.exec("CREATE TABLE current_items (item bigint NOT NULL)");
187
+				query.exec("CREATE TABLE decaf_coffees (decaf_method text NOT NULL) INHERITS (coffees)");
188
+				query.exec("CREATE TABLE files (id bigint NOT NULL, name text NOT NULL, type text NOT NULL, note text, file bytea NOT NULL)");
189
+				query.exec("CREATE TABLE item_files(\"time\" timestamp without time zone NOT NULL, item bigint NOT NULL, files bigint[] NOT NULL)");
190
+				query.exec("CREATE TYPE item_transaction_with_balance AS (\"time\" timestamp without time zone, item bigint, quantity numeric, cost numeric, vendor text, reason text, customer text, type text, balance numeric)");
191
+				query.exec("CREATE TABLE lb_bag_conversion (item bigint NOT NULL, conversion numeric NOT NULL)");
192
+				query.exec("CREATE TABLE machine (id bigint NOT NULL, name text NOT NULL)");
193
+				query.exec("CREATE VIEW regular_coffees AS SELECT coffees.id, coffees.name, coffees.reference, coffees.unit, coffees.quantity, coffees.category, coffees.origin, coffees.region, coffees.producer, coffees.grade, coffees.milling, coffees.drying FROM coffees WHERE (NOT (coffees.id IN (SELECT decaf_coffees.id FROM decaf_coffees)))");
194
+				query.exec("CREATE TABLE roasting_log (\"time\" timestamp without time zone NOT NULL, unroasted_id bigint[], unroasted_quantity numeric[], unroasted_total_quantity numeric, roasted_id bigint, roasted_quantity numeric, transaction_type text NOT NULL, annotation text, machine bigint NOT NULL, duration interval, approval boolean, humidity numeric, barometric numeric, indoor_air numeric, outdoor_air numeric, files bigint[])");
195
+				query.exec("CREATE VIEW short_log AS SELECT roasting_log.\"time\", (SELECT items.name FROM items WHERE (items.id = roasting_log.roasted_id)) AS name, roasting_log.unroasted_total_quantity, roasting_log.roasted_quantity, ((((roasting_log.unroasted_total_quantity - roasting_log.roasted_quantity) / roasting_log.unroasted_total_quantity) * (100)::numeric))::numeric(12,2) AS weight_loss, roasting_log.duration FROM roasting_log ORDER BY roasting_log.\"time\"");
196
+				query.exec("CREATE FUNCTION add_inventory() RETURNS trigger AS $$ BEGIN UPDATE items SET quantity = quantity + NEW.quantity WHERE id = NEW.item; RETURN NEW; END; $$ LANGUAGE plpgsql");
197
+				query.exec("CREATE FUNCTION bags_in_stock(bigint) RETURNS numeric AS $_$SELECT quantity / (SELECT conversion FROM lb_bag_conversion WHERE item = id) FROM items WHERE id = $1;$_$ LANGUAGE sql IMMUTABLE STRICT");
198
+				query.exec("CREATE FUNCTION calculate_inventory_balance() RETURNS trigger AS $$ DECLARE old_quantity numeric; BEGIN old_quantity := (SELECT balance FROM working WHERE time = (SELECT max(time) FROM working)); IF old_quantity IS NULL THEN old_quantity := 0; END IF; IF NEW.type = 'PURCHASE' OR NEW.type = 'MAKE' THEN NEW.balance := old_quantity + NEW.quantity; ELSE IF NEW.type = 'INVENTORY' THEN NEW.balance := NEW.quantity; ELSE IF NEW.type = 'USE' OR NEW.type = 'SALE' OR NEW.type = 'LOSS' THEN NEW.balance := old_quantity - NEW.quantity; END IF; END IF; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql");
199
+				query.exec("CREATE FUNCTION item_history(bigint) RETURNS SETOF item_transaction_with_balance AS $_$ DECLARE r item_transaction_with_balance; BEGIN CREATE TEMPORARY TABLE working(time timestamp without time zone, item bigint, quantity numeric, cost numeric, vendor text, reason text, customer text, type text, balance numeric) ON COMMIT DROP; CREATE TRIGGER quantity_update BEFORE INSERT ON working FOR EACH ROW EXECUTE PROCEDURE calculate_inventory_balance(); INSERT INTO working SELECT time, item, quantity, cost, vendor, reason, customer, type, NULL AS balance FROM all_transactions WHERE item = $1 ORDER BY time ASC; FOR r IN SELECT time, item, quantity, cost, vendor, reason, customer, type, balance FROM working LOOP RETURN NEXT r; END LOOP; DROP TABLE working; RETURN; END; $_$ LANGUAGE plpgsql");
200
+				query.exec("CREATE FUNCTION log_make() RETURNS trigger AS $$ BEGIN IF NEW.roasted_quantity IS NOT NULL THEN INSERT INTO make VALUES(NEW.time, NEW.roasted_id, NEW.roasted_quantity); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql");
201
+				query.exec("CREATE FUNCTION log_make_update() RETURNS trigger AS $$ BEGIN IF NEW.roasted_quantity <> OLD.roasted_quantity AND NEW.roasted_quantity IS NOT NULL THEN INSERT INTO make VALUES(NEW.time, NEW.roasted_id, NEW.roasted_quantity); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql");
202
+				query.exec("CREATE FUNCTION log_use() RETURNS trigger AS $$ DECLARE i integer := array_lower(NEW.unroasted_id, 1); u integer := array_upper(NEW.unroasted_id, 1); BEGIN WHILE i <= u LOOP INSERT INTO use VALUES(NEW.time, NEW.unroasted_id[i], NEW.unroasted_quantity[i]); i := i + 1; END LOOP; RETURN NEW; END; $$ LANGUAGE plpgsql");
203
+				query.exec("CREATE FUNCTION replace_inventory() RETURNS trigger AS $$ BEGIN UPDATE items SET quantity = NEW.quantity WHERE id = NEW.item; RETURN NEW; END; $$ LANGUAGE plpgsql");
204
+				query.exec("CREATE FUNCTION subtract_inventory() RETURNS trigger AS $$ BEGIN UPDATE items SET quantity = quantity - NEW.quantity WHERE id = NEW.item; RETURN NEW; END; $$ LANGUAGE plpgsql");
205
+				query.exec("CREATE SEQUENCE files_id_seq START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1");
206
+				query.exec("ALTER TABLE files ALTER COLUMN id SET DEFAULT nextval('files_id_seq'::regclass)");
207
+				query.exec("ALTER TABLE items ALTER COLUMN id SET DEFAULT nextval('items_id_seq'::regclass)");
208
+				query.exec("ALTER TABLE ONLY files ADD CONSTRAINT file_pkey PRIMARY KEY (id)");
209
+				query.exec("ALTER TABLE ONLY items ADD CONSTRAINT items_pkey PRIMARY KEY (id)");
210
+				query.exec("ALTER TABLE ONLY lb_bag_conversion ADD CONSTRAINT lb_bag_conversion_item_key UNIQUE (item)");
211
+				query.exec("ALTER TABLE ONLY roasting_log ADD CONSTRAINT roasting_log_pkey PRIMARY KEY (\"time\", machine)");
212
+				query.exec("CREATE INDEX itemcategories ON items USING btree (category)");
213
+				query.exec("CREATE INDEX itemnames ON items USING btree (name)");
214
+				query.exec("CREATE INDEX roasting_log_index ON roasting_log USING btree (\"time\")");
215
+				query.exec("CREATE INDEX transactionitems ON transactions USING btree (item)");
216
+				query.exec("CREATE INDEX transactiontimes ON transactions USING btree (\"time\")");
217
+				query.exec("CREATE TRIGGER add_inventory_trigger AFTER INSERT ON purchase FOR EACH ROW EXECUTE PROCEDURE add_inventory()");
218
+				query.exec("CREATE TRIGGER add_inventory_trigger AFTER INSERT ON make FOR EACH ROW EXECUTE PROCEDURE add_inventory()");
219
+				query.exec("CREATE TRIGGER log_use_trigger AFTER INSERT ON roasting_log FOR EACH ROW EXECUTE PROCEDURE log_use()");
220
+				query.exec("CREATE TRIGGER replace_inventory_trigger AFTER INSERT ON inventory FOR EACH ROW EXECUTE PROCEDURE replace_inventory()");
221
+				query.exec("CREATE TRIGGER subtract_inventory_trigger AFTER INSERT ON loss FOR EACH ROW EXECUTE PROCEDURE subtract_inventory()");
222
+				query.exec("CREATE TRIGGER subtract_inventory_trigger AFTER INSERT ON sale FOR EACH ROW EXECUTE PROCEDURE subtract_inventory()");
223
+				query.exec("CREATE TRIGGER subtract_inventory_trigger AFTER INSERT ON use FOR EACH ROW EXECUTE PROCEDURE subtract_inventory()");
224
+				query.exec("ALTER TABLE ONLY item_files ADD CONSTRAINT item_files_item_fkey FOREIGN KEY (item) REFERENCES items(id)");
225
+				query.exec("ALTER TABLE ONLY transactions ADD CONSTRAINT transactions_item_fkey FOREIGN KEY (item) REFERENCES items(id)");
226
+				query = query.invalidate();
227
+        ]]>
228
+    </program>
229
+</window>

+ 322
- 0
config/Windows/newbatch.xml View File

@@ -0,0 +1,322 @@
1
+<window id="batchWindow">
2
+    <menu name="Batch">
3
+        <item id="new" shortcut="Ctrl+N">New Batch…</item>
4
+    </menu>
5
+    <layout type="vertical">
6
+        <layout type="horizontal">
7
+			<label>Machine:</label>
8
+			<line id="machine" writable="false" />
9
+			<label>Unit:</label>
10
+			<sqldrop id="unit" />
11
+            <stretch />
12
+        </layout>
13
+        <layout type="horizontal">
14
+            <label>Roasted Coffee:</label>
15
+            <sqldrop data="0" display="1" showdata="true" id="roasted">
16
+                <null />
17
+                <query>SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id IN (SELECT item FROM current_items) ORDER BY name</query>
18
+            </sqldrop>
19
+            <stretch />
20
+        </layout>
21
+        <label>Green Coffee:</label>
22
+        <sqltablearray columns="2" id="greens">
23
+            <column name="Coffee" delegate="sql" showdata="true" null="false" data="0" display="1">SELECT id, name FROM coffees WHERE quantity &lt;&gt; 0 ORDER BY name</column>
24
+            <column name="Weight" />
25
+        </sqltablearray>
26
+        <layout type="horizontal">
27
+            <label>Green Weight:</label>
28
+            <line id="green" writable="false">0.0</line>
29
+        </layout>
30
+        <layout type="horizontal">
31
+            <button name="Load Profile" type="push" id="load" />
32
+            <button name="No Profile" type="push" id="noprofile" />
33
+        </layout>
34
+        <layout type="horizontal">
35
+            <label>Time:</label>
36
+            <line id="time" writable="false" />
37
+            <label>Duration:</label>
38
+            <line id="duration" writable="false" />
39
+        </layout>
40
+        <layout type="horizontal">
41
+            <label>Roasted Weight:</label>
42
+            <line id="roast" validator="numeric" />
43
+            <label>Weight Loss:</label>
44
+            <line id="wloss" writable="false" />
45
+            <button type="check" id="approval" name="Approved" />
46
+        </layout>
47
+        <layout type="horizontal">
48
+            <label>Annotation:</label>
49
+            <textarea id="annotation" />
50
+        </layout>
51
+        <layout type="horizontal">
52
+            <button name="Submit" id="submit" type="push" />
53
+            <button name="Save log as target profile" type="check" id="target" />
54
+        </layout>
55
+    </layout>
56
+    <program>
57
+        <![CDATA[
58
+			var unitBox = findChildObject(this, 'unit');
59
+			unitBox.addItem("g");
60
+			unitBox.addItem("Kg");
61
+			unitBox.addItem("oz");
62
+			unitBox.addItem("lb");
63
+			unitBox.currentIndex = (QSettings.value("script/batch_unit", unitBox.findText("lb")));
64
+			var machine = findChildObject(this, "machine");
65
+			machine.setText(selectedRoasterName + " (" + selectedRoasterID + ")");
66
+			var newMenu = findChildObject(this, 'new');
67
+			newMenu.triggered.connect(function() {
68
+				var bwindow = createWindow("batchWindow");
69
+				bwindow.windowTitle = "Typica - New Batch";
70
+			});
71
+			var batch = this;
72
+			var table = findChildObject(this, 'greens');
73
+			var green = findChildObject(this, 'green');
74
+			var model = table.model();
75
+            var lossField = findChildObject(this, 'wloss');
76
+            lossField.maximumWidth = 80;
77
+            var roasted = findChildObject(this, 'roasted');
78
+            var roastwt = findChildObject(this, 'roast');
79
+            roastwt.maximumWidth = 80;
80
+			model.dataChanged.connect(function() {
81
+				green.text = table.columnSum(1, 0);
82
+				table.resizeColumnToContents(0);
83
+                if(parseFloat(green.text) > 0)
84
+                {
85
+                    if(parseFloat(roastwt.text) > 0)
86
+                    {
87
+                        lossField.text = (((parseFloat(green.text) - parseFloat(roastwt.text)) / parseFloat(green.text)) * 100).toFixed(2) + "%";
88
+                    }
89
+                    else
90
+                    {
91
+                        lossField.text = "100%";
92
+                    }
93
+                }
94
+			});
95
+            roastwt.textChanged.connect(function() {
96
+                if(parseFloat(green.text) > 0)
97
+                {
98
+                    if(parseFloat(roastwt.text) > 0)
99
+                    {
100
+                        lossField.text = (((parseFloat(green.text) - parseFloat(roastwt.text)) / parseFloat(green.text)) * 100).toFixed(2) + "%";
101
+                    }
102
+                    else
103
+                    {
104
+                        lossField.text = "100%";
105
+                    }
106
+                }
107
+            });
108
+			var convertToPounds = function(w, u) {
109
+				switch(u) {
110
+					case "g":
111
+						return w * 0.0022;
112
+					case "oz":
113
+						return w * 0.0625;
114
+					case "Kg":
115
+						return w * 2.2;
116
+				}
117
+				return w;
118
+			};
119
+            var profilebutton = findChildObject(this, 'load');
120
+            profilebutton.setEnabled(false);
121
+            roasted['currentIndexChanged(int)'].connect(function() {
122
+                var query = new QSqlQuery();
123
+                var q = "SELECT EXISTS(SELECT 1 FROM item_files WHERE item = ";
124
+                q = q + roasted.currentData();
125
+                q = q + ")";
126
+                query.exec(q);
127
+                if(query.next())
128
+                {
129
+                    if(query.value(0) == 'false')
130
+                    {
131
+                        profilebutton.setEnabled(false);
132
+                    }
133
+                    else
134
+                    {
135
+                        profilebutton.setEnabled(true);
136
+                    }
137
+                }
138
+                else
139
+                {
140
+                    profilebutton.setEnabled(false);
141
+                }
142
+                var title = "Typica - New Batch (";
143
+                title = title + roasted.currentText;
144
+                title = title + ")";
145
+                batch.windowTitle = title;
146
+                q = "SELECT unroasted_id FROM roasting_log WHERE roasted_id = ";
147
+                q = q + roasted.currentData();
148
+                q = q + " AND time = (SELECT max(time) FROM roasting_log WHERE roasted_id = ";
149
+                q = q + roasted.currentData();
150
+                q = q + ")";
151
+                query.exec(q);
152
+                if(query.next())
153
+                {
154
+                    var unroasted_items = sqlToArray(query.value(0));
155
+                    var names = [];
156
+                    q = "SELECT name FROM items WHERE id = :id AND quantity <> 0";
157
+                    query.prepare(q);
158
+                    var allInStock = true;
159
+                    for(var i = 0; i < unroasted_items.length; i++)
160
+                    {
161
+                        query.bind("id", unroasted_items[i]);
162
+                        query.exec();
163
+                        if(query.next())
164
+                        {
165
+                            names[i] = query.value(0);
166
+                        }
167
+                        else
168
+                        {
169
+                            allInStock = false;
170
+                        }
171
+                    }
172
+                    if(allInStock)
173
+                    {
174
+                        for(var i = 0; i < unroasted_items.length; i++)
175
+                        {
176
+                            table.setData(i, 0, names[i], 0);
177
+                            table.setData(i, 0, unroasted_items[i], 32);
178
+                        }
179
+                    }
180
+                }
181
+            });
182
+			profilebutton.clicked.connect(function() {
183
+				currentBatchInfo = batch;
184
+				query = new QSqlQuery();
185
+                var q = "SELECT files FROM item_files WHERE item = :item AND time = (SELECT max(time) FROM item_files WHERE item = :again)";
186
+				query.prepare(q);
187
+                query.bind(":item", Number(roasted.currentData()));
188
+                query.bind(":again", Number(roasted.currentData()));
189
+				query.exec();
190
+				if(query.next())
191
+				{
192
+					var files = query.value(0);
193
+					files = files.replace("{", "(");
194
+					files = files.replace("}", ")");
195
+					q = "SELECT file, name FROM files WHERE id IN ";
196
+					q = q + files;
197
+					q = q + " AND type = 'profile'";
198
+					query.exec(q);
199
+					if(query.next())
200
+					{
201
+						var targetseries = -1;
202
+						var buffer = new QBuffer(query.value(0));
203
+						var pname = query.value(1);
204
+						var input = new XMLInput(buffer, 1);
205
+						var graph = findChildObject(navigationwindow.loggingWindow, 'graph');
206
+						var log = findChildObject(navigationwindow.loggingWindow, 'log');
207
+						log.clear();
208
+						graph.clear();
209
+						input.newTemperatureColumn.connect(log.setHeaderData);
210
+						input.newTemperatureColumn.connect(function(col, text) {
211
+							if(text == navigationwindow.loggingWindow.targetcolumnname)
212
+							{
213
+								targetseries = col;
214
+							}
215
+						});
216
+						input.newAnnotationColumn.connect(log.setHeaderData);
217
+						input.measure.connect(graph.newMeasurement);
218
+						input.measure.connect(log.newMeasurement);
219
+						input.measure.connect(function(data, series) {
220
+							if(series == targetseries)
221
+							{
222
+								targetDetector.newMeasurement(data);
223
+							}
224
+						});
225
+						input.annotation.connect(log.newAnnotation);
226
+						var lc;
227
+						input.lastColumn.connect(function(c) {
228
+							lc = c;
229
+							QSettings.setValue("liveColumn", c + 1);
230
+							navigationwindow.loggingWindow.postLoadColumnSetup(c)
231
+						});
232
+					}
233
+				}
234
+                query = query.invalidate();
235
+				navigationwindow.loggingWindow.windowTitle = "Typica - " + pname;
236
+				navigationwindow.loggingWindow.raise();
237
+				navigationwindow.loggingWindow.activateWindow();
238
+				input.input();
239
+				log.newAnnotation("End", 1, lc);
240
+			});
241
+			var noprofilebutton = findChildObject(this, 'noprofile');
242
+			noprofilebutton.clicked.connect(function() {
243
+				currentBatchInfo = batch;
244
+				navigationwindow.loggingWindow.raise();
245
+				navigationwindow.loggingWindow.activateWindow();
246
+			});
247
+			var submitbutton = findChildObject(this, 'submit');
248
+			var timefield = findChildObject(this, 'time');
249
+			var notes = findChildObject(this, 'annotation');
250
+			/*
251
+			var machine = findChildObject(this, 'machine');
252
+            machine.currentIndex = QSettings.value("batchmachine_last", 0);
253
+            machine['currentIndexChanged(int)'].connect(function() {
254
+                QSettings.setValue("batchmachine_last", machine.currentIndex);
255
+            });
256
+			*/
257
+			var duration = findChildObject(this, 'duration');
258
+			var approval = findChildObject(this, 'approval');
259
+			var target = findChildObject(this, 'target');
260
+			submitbutton.clicked.connect(function() {
261
+				checkQuery = new QSqlQuery();
262
+				checkQuery.exec("SELECT 1 FROM machine WHERE id = " + selectedRoasterID);
263
+				if(!checkQuery.next())
264
+				{
265
+					checkQuery.prepare("INSERT INTO machine VALUES(:id, :name)");
266
+					checkQuery.bind(":id", selectedRoasterID);
267
+					checkQuery.bind(":name", selectedRoasterName);
268
+					checkQuery.exec();
269
+				}
270
+				checkQuery = checkQuery.invalidate();
271
+				var q = "INSERT INTO files VALUES(default, :name, 'profile', NULL, :data) RETURNING id";
272
+				query = new QSqlQuery();
273
+				query.prepare(q);
274
+				query.bind(":name", timefield.text + " " + roasted.currentText);
275
+				query.bindFileData(":data", batch.tempData);
276
+				query.exec();
277
+				query.next();
278
+				var fileno = query.value(0);
279
+				var file = new QFile(batch.tempData);
280
+				file.remove();
281
+				var q2 = "INSERT INTO roasting_log VALUES(:time, ";
282
+				q2 = q2 + table.columnArray(0, 32);
283
+				q2 = q2 + ", ";
284
+				for(var i = 0; table.data(i, 1, 0).value != ""; i++)
285
+				{
286
+					table.setData(i, 1, convertToPounds(parseFloat(table.data(i, 1, 0)), unitBox.currentText) ,32)
287
+				}
288
+				q2 = q2 + table.columnArray(1, 32);
289
+				q2 = q2 + ", ";
290
+				q2 = q2 + convertToPounds(parseFloat(green.text), unitBox.currentText);
291
+				q2 = q2 + ", ";
292
+				q2 = q2 + roasted.currentData();
293
+				q2 = q2 + ", ";
294
+				q2 = q2 + convertToPounds(parseFloat(roastwt.text), unitBox.currentText);
295
+				q2 = q2 + ", 'ROAST', :annotation, ";
296
+				q2 = q2 + selectedRoasterID;
297
+				q2 = q2 + ", :duration, :approval, NULL, NULL, NULL, NULL, '{";
298
+				q2 = q2 + fileno;
299
+				q2 = q2 + "}')";
300
+				query2 = new QSqlQuery();
301
+				query2.prepare(q2);
302
+				query2.bind(":time", timefield.text);
303
+				query2.bind(":annotation", notes.plainText);
304
+				query2.bind(":duration", duration.text);
305
+				query2.bind(":approval", approval.checked);
306
+				query2.exec();
307
+                query2 = query2.invalidate();
308
+				if(target.checked) {
309
+					var q3 = "INSERT INTO item_files VALUES(:time, :item, '{";
310
+					q3 = q3 + fileno;
311
+					q3 = q3 + "}')";
312
+					query.prepare(q3);
313
+					query.bind(":time", timefield.text);
314
+					query.bind(":item", roasted.currentData());
315
+					query.exec();
316
+				}
317
+                query = query.invalidate();
318
+				batch.close();
319
+			});
320
+        ]]>
321
+    </program>
322
+</window>

+ 32
- 0
config/Windows/newroaster.xml View File

@@ -0,0 +1,32 @@
1
+<window id="newroaster">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Roaster Name:</label>
5
+            <line id="name" />
6
+        </layout>
7
+        <layout type="horizontal">
8
+            <label>Roaster Number:</label>
9
+            <line id="id" />
10
+        </layout>
11
+        <button name="Submit" id="submit" type="push" />
12
+    </layout>
13
+    <program>
14
+        <![CDATA[
15
+			var button = findChildObject(this, 'submit');
16
+			var rname = findChildObject(this, 'name');
17
+			var rnumber = findChildObject(this, 'id');
18
+			var nrwindow = this;
19
+			button.clicked.connect(function() {
20
+				var q = "INSERT INTO machine VALUES (";
21
+				q = q + rnumber.text;
22
+				q = q + ", :name)";
23
+				query = new QSqlQuery();
24
+				query.prepare(q);
25
+				query.bind(":name", rname.text);
26
+				query.exec();
27
+                query = query.invalidate();
28
+				nrwindow.close();
29
+			});
30
+        ]]>
31
+    </program>
32
+</window>

+ 118
- 0
config/Windows/offline.xml View File

@@ -0,0 +1,118 @@
1
+<window id="offline">
2
+    <layout type="vertical">
3
+        <splitter type="horizontal" id="logsplit">
4
+            <measurementtable id="log">
5
+                <column>Time</column>
6
+                <column>Bean</column>
7
+                <column>Air</column>
8
+                <column>Note</column>
9
+            </measurementtable>
10
+            <graph id="graph" />
11
+        </splitter>
12
+    </layout>
13
+	<menu name="File">
14
+		<item id="save" shortcut="Ctrl+S">Save…</item>
15
+		<item id="print" shortcut="Ctrl+P">Print…</item>
16
+		<item id="export">Export CSV…</item>
17
+		<item id="svgexport">Export XHTML+SVG…</item>
18
+		<item id="quit" shortcut="Ctrl+Q">Quit</item>
19
+	</menu>
20
+	<menu name="Log">
21
+		<item id="showC">Display Celsius</item>
22
+		<item id="showF">Display Fahrenheit</item>
23
+		<separator />
24
+		<item id="ms">Millisecond View</item>
25
+		<item id="1s">1 Second View</item>
26
+		<item id="5s">5 Second View</item>
27
+		<item id="10s">10 Second View</item>
28
+		<item id="15s">15 Second View</item>
29
+		<item id="30s">30 Second View</item>
30
+		<item id="1m">1 Minute View</item>
31
+	</menu>
32
+	<program>
33
+		<![CDATA[
34
+			var window = this;
35
+			var splitter = findChildObject(this, 'logsplit');
36
+			splitter.restoreState("script/offlineViewSplitter");
37
+			window.saveTemperatureColumns = new Array();
38
+			window.saveAnnotationColumns = new Array();
39
+			this.aboutToClose.connect(function() {
40
+				splitter.saveState("script/offlineViewSplitter");
41
+			});
42
+			var log = findChildObject(this, 'log');
43
+			var graph = findChildObject(this, 'graph');
44
+			var setLogOutputColumns = function() {
45
+				log.clearOutputColumns();
46
+				for(var c = 0; c < window.saveTemperatureColumns.length; c++)
47
+				{
48
+					log.addOutputTemperatureColumn(window.saveTemperatureColumns[c]);
49
+				}
50
+				for(var c = 0; c < window.saveAnnotationColumns.length; c++)
51
+				{
52
+					log.addOutputAnnotationColumn(window.saveAnnotationColumns[c]);
53
+				}
54
+			};
55
+			var saveMenu = findChildObject(this, 'save');
56
+			saveMenu.triggered.connect(function() {
57
+				var filename = QFileDialog.getSaveFileName(window, "Save Log As…", QSettings.value("script/lastDir", "") + "/");
58
+				if(filename != "") {
59
+					var file = new QFile(filename);
60
+					setLogOutputColumns();
61
+					log.saveXML(file);
62
+					QSettings.setValue("script/lastDir", dir(filename));
63
+				}
64
+			});
65
+			var printMenu = findChildObject(this, 'print');			
66
+			printMenu.triggered.connect(function() {
67
+				var exportWindow = createWindow("print");
68
+				exportWindow.windowTitle = "Typica - Print";
69
+				exportWindow.log = log;
70
+			});
71
+			var exportMenu = findChildObject(this, 'export');
72
+			exportMenu.triggered.connect(function() {
73
+				var filename = QFileDialog.getSaveFileName(window, "Export CSV As…", QSettings.value("script/lastDir", "") + "/");
74
+				if(filename != "") {
75
+					var file = new QFile(filename);
76
+					setLogOutputColumns();
77
+					log.saveCSV(file);
78
+					QSettings.setValue("script/lastDir", dir(filename));
79
+				}
80
+			});
81
+			var svgExportMenu = findChildObject(this, 'svgexport');
82
+			svgExportMenu.triggered.connect(function() {
83
+				var exportWindow = createWindow("exportWindow");
84
+				exportWindow.windowTitle = "Typica - Export XHTML+SVG";
85
+				exportWindow.log = log;
86
+			});
87
+			var quitMenu = findChildObject(this, 'quit');
88
+			quitMenu.triggered.connect(function() {
89
+				window.close();
90
+				Application.quit();
91
+			});
92
+			var showC = findChildObject(this, 'showC');
93
+			showC.triggered.connect(function() {
94
+				log.setDisplayUnits(TemperatureDisplay.Celsius);
95
+				graph.showC();
96
+			});
97
+			var showF = findChildObject(this, 'showF');
98
+			showF.triggered.connect(function() {
99
+				log.setDisplayUnits(TemperatureDisplay.Fahrenheit);
100
+				graph.showF();
101
+			});
102
+			var v1 = findChildObject(this, 'ms');
103
+			v1.triggered.connect(log.LOD_ms);
104
+			var v2 = findChildObject(this, '1s');
105
+			v2.triggered.connect(log.LOD_1s);
106
+			var v3 = findChildObject(this, '5s');
107
+			v3.triggered.connect(log.LOD_5s);
108
+			var v4 = findChildObject(this, '10s');
109
+			v4.triggered.connect(log.LOD_10s);
110
+			var v5 = findChildObject(this, '15s');
111
+			v5.triggered.connect(log.LOD_15s);
112
+			var v6 = findChildObject(this, '30s');
113
+			v6.triggered.connect(log.LOD_30s);
114
+			var v7 = findChildObject(this, '1m');
115
+			v7.triggered.connect(log.LOD_1m);
116
+		]]>
117
+	</program>
118
+</window>

+ 78
- 0
config/Windows/optime.xml View File

@@ -0,0 +1,78 @@
1
+<window id="optime">
2
+	<layout type="vertical">
3
+		<layout type="horizontal">
4
+			<label>Machine:</label>
5
+			<sqldrop data="0" display="1" showdata="true" id="machine">
6
+				<query>SELECT id, name FROM machine ORDER BY name</query>
7
+			</sqldrop>
8
+			<stretch />
9
+		</layout>
10
+		<layout type="horizontal">
11
+			<label>Start Time:</label>
12
+			<line id="starttime" writable="false" />
13
+			<button name="Start Roaster" type="push" id="start" />
14
+		</layout>
15
+		<layout type="horizontal">
16
+			<label>Stop Time:</label>
17
+			<line id="stoptime" writable="false" />
18
+			<button name="Stop Roaster" type="push" id="stop" />
19
+		</layout>
20
+		<layout type="horizontal">
21
+			<label>Duration:</label>
22
+			<line id="duration" writable="false" />
23
+			<button name="Submit" type="push" id="submit" />
24
+		</layout>
25
+	</layout>
26
+	<program>
27
+		<![CDATA[
28
+			var window = this;
29
+			var startbutton = findChildObject(this, "start");
30
+			var stopbutton = findChildObject(this, "stop");
31
+			var submitbutton = findChildObject(this, "submit");
32
+			stopbutton.setEnabled(false);
33
+			submitbutton.setEnabled(false);
34
+			var startline = findChildObject(this, "starttime");
35
+			var stopline = findChildObject(this, "stoptime");
36
+			var durationline = findChildObject(this, "duration");
37
+			var machine = findChildObject(this, "machine");
38
+			machine.currentIndex = QSettings.value("lastMachineStarted", 0);
39
+			machine['currentIndexChanged(int)'].connect(function() {
40
+				QSettings.setValue("lastMachineStarted", machine.currentIndex);
41
+			});
42
+			startbutton.clicked.connect(function() {
43
+				query = new QSqlQuery();
44
+				query.exec("SELECT now()::timestamp without time zone");
45
+				query.next();
46
+				var result = query.value(0);
47
+				query = query.invalidate();
48
+				startline.text = result.replace('T', ' ');
49
+				stopbutton.setEnabled(true);
50
+			});
51
+			stopbutton.clicked.connect(function() {
52
+				query = new QSqlQuery();
53
+				query.exec("SELECT now()::timestamp without time zone");
54
+				query.next();
55
+				var result = query.value(0);
56
+				stopline.text = result.replace('T', ' ');
57
+				var q = "SELECT '" + stopline.text + "'::timestamp - '" + startline.text + "'::timestamp";
58
+				query.exec(q);
59
+				query.next();
60
+				durationline.text = query.value(0);
61
+				query = query.invalidate();
62
+				submitbutton.setEnabled(true);
63
+			});
64
+			submitbutton.clicked.connect(function() {
65
+				query = new QSqlQuery();
66
+				var q = "INSERT INTO operational_time VALUES (:machine, :start, :stop, :duration)";
67
+				query.prepare(q);
68
+				query.bind(":machine", machine.currentData());
69
+				query.bind(":start", startline.text);
70
+				query.bind(":stop", stopline.text);
71
+				query.bind(":duration", durationline.text);
72
+				query.exec();
73
+				query = query.invalidate();
74
+				window.close();
75
+			});
76
+		]]>
77
+	</program>
78
+</window>

+ 758
- 0
config/Windows/print.xml View File

@@ -0,0 +1,758 @@
1
+<window id="print">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Title:</label>
5
+            <line id="title" />
6
+        </layout>
7
+        <layout type="horizontal">
8
+            <label>Subtitle:</label>
9
+            <line id="subtitle" />
10
+        </layout>
11
+        <layout type="horizontal">
12
+            <label>% weight loss:</label>
13
+            <line id="loss" validator="numeric" />
14
+            <label>Tolerance:</label>
15
+            <line id="tolerance" validator="numeric" />
16
+        </layout>
17
+        <layout type="horizontal">
18
+            <label>Additional notes:</label>
19
+            <line id="notes" />
20
+        </layout>
21
+        <layout type="horizontal">
22
+            <label>Measurement column:</label>
23
+            <line id="addmeasurement" validator="integer" />
24
+            <button name="Add column" type="push" id="ambutton" />
25
+            <line id="mcols" writable="false" />
26
+        </layout>
27
+        <layout type="horizontal">
28
+            <label>Annotation column:</label>
29
+            <line id="addnote" validator="integer" />
30
+            <button name="Add column" type="push" id="anbutton" />
31
+            <line id="ncols" writable="false" />
32
+        </layout>
33
+        <button name="Print" type="push" id="export" />
34
+    </layout>
35
+    <program>
36
+        <![CDATA[
37
+            var window = this;
38
+            var exportButton = findChildObject(this, 'export');
39
+            exportButton.enable = false;
40
+            var mcoldisp = findChildObject(this, 'mcols');
41
+            mcoldisp.enable = false;
42
+            var ncoldisp = findChildObject(this, 'ncols');
43
+            ncoldisp.enable = false;
44
+            var mbutton = findChildObject(this, 'ambutton');
45
+            var msource = findChildObject(this, 'addmeasurement');
46
+            var mdest = findChildObject(this, 'mcols');
47
+            mbutton.clicked.connect(function() {
48
+                if(window.marray === undefined)
49
+                {
50
+                    window.marray = new Array();
51
+                }
52
+                window.marray.push(Number(msource.text));
53
+                mdest.text = window.marray.toString();
54
+                msource.text = '';
55
+                if(window.narray === undefined)
56
+                {} else { exportButton.enable = true;}
57
+            });
58
+            var abutton = findChildObject(window, 'anbutton');
59
+            var asource = findChildObject(window, 'addnote');
60
+            var adest = findChildObject(window, 'ncols');
61
+            abutton.clicked.connect(function() {
62
+                if(window.narray === undefined)
63
+                {
64
+                    window.narray = new Array();
65
+                }
66
+                window.narray.push(Number(asource.text));
67
+                adest.text = window.narray.toString();
68
+                asource.text = '';
69
+                if(window.marray === undefined)
70
+                { } else { exportButton.enable = true;}
71
+            });
72
+            var titleField = findChildObject(window, 'title');
73
+            var subTitleField = findChildObject(window, 'subtitle');
74
+            exportButton.clicked.connect(function() {
75
+                window.log.clearOutputColumns();
76
+                for(var i = 0; i < window.marray.length; i++)
77
+                {
78
+                    window.log.addOutputTemperatureColumn(window.marray[i]);
79
+                }
80
+                for(var i = 0; i < window.narray.length; i++)
81
+                {
82
+                    window.log.addOutputAnnotationColumn(window.narray[i]);
83
+                }
84
+                var unitdesc = log.displayUnits();
85
+                if(unitdesc != 10144)
86
+                {
87
+                    log.setDisplayUnits(10144);
88
+                }
89
+                var tempFilename = log.saveTemporary();
90
+                log.setDisplayUnits(unitdesc);
91
+                var sourceFile = new QFile(tempFilename);
92
+                sourceFile.open(3);
93
+                var tf2 = tempFilename + ".xml";
94
+                var destFile = new QFile(tf2);
95
+                destFile.open(3);
96
+                var input = new XmlReader(sourceFile);
97
+                var output = new XmlWriter(destFile);
98
+                output.writeStartDocument("1.0");
99
+                output.writeDTD('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg.dtd">');
100
+                output.writeStartElement("html");
101
+                output.writeAttribute("xmlns", "http://www.w3.org/1999/xhtml");
102
+                output.writeStartElement("head");
103
+                output.writeStartElement("title");
104
+                output.writeCDATA(titleField.text);
105
+                output.writeEndElement();
106
+                output.writeEndElement();
107
+                output.writeStartElement("body");
108
+                output.writeStartElement("h1");
109
+                output.writeAttribute("style", "font-size:100%;font-weight:bold");
110
+                output.writeCDATA(titleField.text);
111
+                output.writeEndElement();
112
+                output.writeStartElement("h2");
113
+                output.writeAttribute("style", "font-size:100%;font-weight:normal");
114
+                output.writeCDATA(subTitleField.text);
115
+                output.writeEndElement();
116
+                output.writeStartElement("div");
117
+                output.writeAttribute("style", "width:7.5in");
118
+                output.writeStartElement("div");
119
+                output.writeAttribute("style", "float:left;width:2.5in");
120
+                output.writeStartElement("table");
121
+                output.writeStartElement("tr");
122
+                output.writeStartElement("th");
123
+                output.writeCDATA("Time");
124
+                output.writeEndElement();
125
+                input.readNext();
126
+                var colMap = new Array();
127
+                var tempMap = new Array();
128
+                while(input.name() != "roast")
129
+                {
130
+                    if(input.isStartElement())
131
+                    {
132
+                        if(input.name() == "tempseries")
133
+                        {
134
+                            colMap.push(input.attribute("name"));
135
+                            tempMap.push(input.attribute("name"));
136
+                        }
137
+                        if(input.name() == "noteseries")
138
+                        {
139
+                            colMap.push(input.attribute("name"));
140
+                        }
141
+                    }
142
+                    input.readNext();
143
+                }
144
+                for(var i = 0; i < colMap.length; i++)
145
+                {
146
+                    output.writeStartElement("th");
147
+                    output.writeCDATA(colMap[i]);
148
+                    output.writeEndElement();
149
+                }
150
+                output.writeEndElement();
151
+                var rowBuffer = new Array();
152
+                var nextTime = 0;
153
+                input.readNext();
154
+                var inputReady = false;
155
+                var annotationRead = false;
156
+                var tm = 0;
157
+                var ts = 0;
158
+                while(!input.atEnd())
159
+                {
160
+                    if(input.isStartElement())
161
+                    {
162
+                        if(input.name() == "time")
163
+                        {
164
+                            rowBuffer[0] = input.readElementText();
165
+                            inputReady = true;
166
+                        }
167
+                        if(input.name() == "temperature")
168
+                        {
169
+                            for (var i = 0; i < colMap.length; i++)
170
+                            {
171
+                                if(colMap[i] == input.attribute("series"))
172
+                                {
173
+                                    if(log.displayUnits() == 10143)
174
+                                    {
175
+                                        rowBuffer[i + 1] = Math.floor((input.readElementText() - 32) * 5 / 9);
176
+                                    }
177
+                                    else
178
+                                    {
179
+                                        rowBuffer[i + 1] = Math.floor(input.readElementText());
180
+                                    }
181
+                                    break;
182
+                                }
183
+                            }
184
+                        }
185
+                        if(input.name() == "annotation")
186
+                        {
187
+                            for (var i = 0; i < colMap.length; i++)
188
+                            {
189
+                                if(colMap[i] == input.attribute("series"))
190
+                                {
191
+                                    rowBuffer[i + 1] = input.readElementText();
192
+                                    break;
193
+                                }
194
+                            }
195
+                            annotationRead = true;
196
+                        }
197
+                        if(input.name() == "tuple")
198
+                        {
199
+                            if(inputReady)
200
+                            {
201
+                                var ta1 = rowBuffer[0].split(":");
202
+                                var ta2 = ta1[1].split(".");
203
+                                if(Number(ta1[0]) == tm)
204
+                                {
205
+                                    if(Number(ta2[0]) == ts)
206
+                                    {
207
+                                        annotationRead = false;
208
+                                        output.writeStartElement("tr");
209
+                                        for(var i = 0; i < rowBuffer.length; i++)
210
+                                        {
211
+                                            output.writeStartElement("td");
212
+                                            output.writeAttribute("align", "center");
213
+                                            output.writeAttribute("style", "font-size: 80%");
214
+                                            if(i == 0)
215
+                                            {
216
+                                                output.writeCDATA(rowBuffer[i].split(".")[0]);
217
+                                            }
218
+                                            else
219
+                                            {
220
+                                                output.writeCDATA(rowBuffer[i]);
221
+                                            }
222
+                                            output.writeEndElement();
223
+                                        }
224
+                                        output.writeEndElement();
225
+                                        nextTime += 30;
226
+                                        tm = Math.floor(nextTime / 60);
227
+                                        ts = nextTime % 60;
228
+                                    }
229
+                                }
230
+                                if(annotationRead)
231
+                                {
232
+                                    output.writeStartElement("tr");
233
+                                    for(var i = 0; i < rowBuffer.length; i++)
234
+                                    {
235
+                                        output.writeStartElement("td");
236
+                                        output.writeAttribute("align", "center");
237
+                                        output.writeAttribute("style", "font-size: 80%");
238
+                                        output.writeCDATA(rowBuffer[i]);
239
+                                        output.writeEndElement();
240
+                                    }
241
+                                    output.writeEndElement();
242
+                                    annotationRead = false;
243
+                                }
244
+                            }
245
+                            rowBuffer = new Array();
246
+                        }
247
+                    }
248
+                    input.readNext();
249
+                }
250
+                output.writeStartElement("tr");
251
+                for(var i = 0; i < rowBuffer.length; i++)
252
+                {
253
+                    output.writeStartElement("td");
254
+                    output.writeAttribute("align", "center");
255
+                    output.writeAttribute("style", "font-size: 80%");
256
+                    output.writeCDATA(rowBuffer[i]);
257
+                    output.writeEndElement();
258
+                }
259
+                output.writeEndElement();
260
+                output.writeEndElement();
261
+                output.writeEndElement();
262
+                output.writeStartElement("div");
263
+                output.writeAttribute("style", "width=4.5in;float=right");
264
+                output.writeStartElement("svg");
265
+                output.writeAttribute("xmlns", "http://www.w3.org/2000/svg");
266
+                output.writeAttribute("version", "1.1");
267
+                output.writeAttribute("width", "4.5in");
268
+                output.writeAttribute("height", "3.4in");
269
+                output.writeAttribute("viewbox", "0 0 400 400");
270
+                output.writeStartElement("rect");
271
+                output.writeAttribute("width", "4.5in");
272
+                output.writeAttribute("height", "3.4in");
273
+                output.writeAttribute("style", "fill:none;stroke-width:3;stroke:rgb(64,64,64)");
274
+                output.writeEndElement();
275
+                output.writeStartElement("text");
276
+                output.writeAttribute("x", "0.1in");
277
+                output.writeAttribute("y", "1.3in");
278
+                output.writeAttribute("font-size", "12");
279
+                output.writeAttribute("transform", "rotate(-90 40,150)");
280
+                if(log.displayUnits() == 10143)
281
+                {
282
+                    output.writeCDATA("Temperature (°C)");
283
+                }
284
+                else
285
+                {
286
+                    output.writeCDATA("Temperature (°F)");
287
+                }
288
+                output.writeEndElement();
289
+                output.writeStartElement("text");
290
+                output.writeAttribute("x", "1.9in");
291
+                output.writeAttribute("y", "3.3in");
292
+                output.writeAttribute("font-size", "12");
293
+                output.writeCDATA("Time (minutes)");
294
+                output.writeEndElement();
295
+                output.writeStartElement("line");
296
+                output.writeAttribute("x1", "0.4in");
297
+                output.writeAttribute("x2", "0.4in");
298
+                output.writeAttribute("y1", "0.1in");
299
+                output.writeAttribute("y2", "2.9in");
300
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
301
+                output.writeEndElement();
302
+                output.writeStartElement("line");
303
+                output.writeAttribute("x1", "0.5in");
304
+                output.writeAttribute("x2", "4.4in");
305
+                output.writeAttribute("y1", "3in");
306
+                output.writeAttribute("y2", "3in");
307
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
308
+                output.writeEndElement();
309
+                output.writeStartElement("line");
310
+                output.writeAttribute("x1", "0.4in");
311
+                output.writeAttribute("x2", "4.4in");
312
+                output.writeAttribute("y1", "2.9in");
313
+                output.writeAttribute("y2", "2.9in");
314
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
315
+                output.writeEndElement();
316
+                if(log.displayUnits() != 10143)
317
+                {
318
+                    output.writeStartElement("text");
319
+                    output.writeAttribute("x", "0.3in");
320
+                    output.writeAttribute("y", "2.95in");
321
+                    output.writeAttribute("font-size", "12");
322
+                    output.writeCDATA("0");
323
+                    output.writeEndElement();
324
+                }
325
+                if(log.displayUnits() == 10143)
326
+                {
327
+                    output.writeStartElement("line");
328
+                    output.writeAttribute("x1", "0.4in");
329
+                    output.writeAttribute("x2", "4.4in");
330
+                    output.writeAttribute("y1", "2.22in");
331
+                    output.writeAttribute("y2", "2.22in");
332
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
333
+                    output.writeEndElement();
334
+                    output.writeStartElement("text");
335
+                    output.writeAttribute("x", "0.18in");
336
+                    output.writeAttribute("y", "2.27in");
337
+                    output.writeAttribute("font-size", "12");
338
+                    output.writeCDATA("50");
339
+                    output.writeEndElement();
340
+                    output.writeStartElement("line");
341
+                    output.writeAttribute("x1", "0.4in");
342
+                    output.writeAttribute("x2", "4.4in");
343
+                    output.writeAttribute("y1", "1.71in");
344
+                    output.writeAttribute("y2", "1.71in");
345
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
346
+                    output.writeEndElement();
347
+                    output.writeStartElement("text");
348
+                    output.writeAttribute("x", "0.18in");
349
+                    output.writeAttribute("y", "1.76in");
350
+                    output.writeAttribute("font-size", "12");
351
+                    output.writeCDATA("100");
352
+                    output.writeEndElement();
353
+                    output.writeStartElement("line");
354
+                    output.writeAttribute("x1", "0.4in");
355
+                    output.writeAttribute("x2", "4.4in");
356
+                    output.writeAttribute("y1", "1.21in");
357
+                    output.writeAttribute("y2", "1.21in");
358
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
359
+                    output.writeEndElement();
360
+                    output.writeStartElement("text");
361
+                    output.writeAttribute("x", "0.18in");
362
+                    output.writeAttribute("y", "1.26in");
363
+                    output.writeAttribute("font-size", "12");
364
+                    output.writeCDATA("150");
365
+                    output.writeEndElement();
366
+                    output.writeStartElement("line");
367
+                    output.writeAttribute("x1", "0.4in");
368
+                    output.writeAttribute("x2", "4.4in");
369
+                    output.writeAttribute("y1", "0.7in");
370
+                    output.writeAttribute("y2", "0.7in");
371
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
372
+                    output.writeEndElement();
373
+                    output.writeStartElement("text");
374
+                    output.writeAttribute("x", "0.18in");
375
+                    output.writeAttribute("y", "0.75in");
376
+                    output.writeAttribute("font-size", "12");
377
+                    output.writeCDATA("200");
378
+                    output.writeEndElement();
379
+                    output.writeStartElement("line");
380
+                    output.writeAttribute("x1", "0.4in");
381
+                    output.writeAttribute("x2", "4.4in");
382
+                    output.writeAttribute("y1", "0.2in");
383
+                    output.writeAttribute("y2", "0.2in");
384
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
385
+                    output.writeEndElement();
386
+                    output.writeStartElement("text");
387
+                    output.writeAttribute("x", "0.18in");
388
+                    output.writeAttribute("y", "0.25in");
389
+                    output.writeAttribute("font-size", "12");
390
+                    output.writeCDATA("250");
391
+                    output.writeEndElement();
392
+                }
393
+                else
394
+                {
395
+                    output.writeStartElement("line");
396
+                    output.writeAttribute("x1", "0.4in");
397
+                    output.writeAttribute("x2", "4.4in");
398
+                    output.writeAttribute("y1", "2.34in");
399
+                    output.writeAttribute("y2", "2.34in");
400
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
401
+                    output.writeEndElement();
402
+                    output.writeStartElement("text");
403
+                    output.writeAttribute("x", "0.18in");
404
+                    output.writeAttribute("y", "2.39in");
405
+                    output.writeAttribute("font-size", "12");
406
+                    output.writeCDATA("100");
407
+                    output.writeEndElement();
408
+                    output.writeStartElement("line");
409
+                    output.writeAttribute("x1", "0.4in");
410
+                    output.writeAttribute("x2", "4.4in");
411
+                    output.writeAttribute("y1", "1.78in");
412
+                    output.writeAttribute("y2", "1.78in");
413
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
414
+                    output.writeEndElement();
415
+                    output.writeStartElement("text");
416
+                    output.writeAttribute("x", "0.18in");
417
+                    output.writeAttribute("y", "1.83in");
418
+                    output.writeAttribute("font-size", "12");
419
+                    output.writeCDATA("200");
420
+                    output.writeEndElement();
421
+                    output.writeStartElement("line");
422
+                    output.writeAttribute("x1", "0.4in");
423
+                    output.writeAttribute("x2", "4.4in");
424
+                    output.writeAttribute("y1", "1.22in");
425
+                    output.writeAttribute("y2", "1.22in");
426
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
427
+                    output.writeEndElement();
428
+                    output.writeStartElement("text");
429
+                    output.writeAttribute("x", "0.18in");
430
+                    output.writeAttribute("y", "1.27in");
431
+                    output.writeAttribute("font-size", "12");
432
+                    output.writeCDATA("300");
433
+                    output.writeEndElement();
434
+                    output.writeStartElement("line");
435
+                    output.writeAttribute("x1", "0.4in");
436
+                    output.writeAttribute("x2", "4.4in");
437
+                    output.writeAttribute("y1", "0.66in");
438
+                    output.writeAttribute("y2", "0.66in");
439
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
440
+                    output.writeEndElement();
441
+                    output.writeStartElement("text");
442
+                    output.writeAttribute("x", "0.18in");
443
+                    output.writeAttribute("y", "0.71in");
444
+                    output.writeAttribute("font-size", "12");
445
+                    output.writeCDATA("400");
446
+                    output.writeEndElement();
447
+                    output.writeStartElement("line");
448
+                    output.writeAttribute("x1", "0.4in");
449
+                    output.writeAttribute("x2", "4.4in");
450
+                    output.writeAttribute("y1", "0.1in");
451
+                    output.writeAttribute("y2", "0.1in");
452
+                    output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
453
+                    output.writeEndElement();
454
+                    output.writeStartElement("text");
455
+                    output.writeAttribute("x", "0.18in");
456
+                    output.writeAttribute("y", "0.15in");
457
+                    output.writeAttribute("font-size", "12");
458
+                    output.writeCDATA("500");
459
+                    output.writeEndElement();
460
+                }
461
+                output.writeStartElement("line");
462
+                output.writeAttribute("x1", "0.5in");
463
+                output.writeAttribute("x2", "0.5in");
464
+                output.writeAttribute("y1", "2.95in");
465
+                output.writeAttribute("y2", "3.05in");
466
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
467
+                output.writeEndElement();
468
+                output.writeStartElement("text");
469
+                output.writeAttribute("x", "0.47in");
470
+                output.writeAttribute("y", "3.16in");
471
+                output.writeAttribute("font-size", "12");
472
+                output.writeCDATA("0");
473
+                output.writeEndElement();
474
+                output.writeStartElement("line");
475
+                output.writeAttribute("x1", "0.89in");
476
+                output.writeAttribute("x2", "0.89in");
477
+                output.writeAttribute("y1", "2.95in");
478
+                output.writeAttribute("y2", "3.05in");
479
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
480
+                output.writeEndElement();
481
+                output.writeStartElement("text");
482
+                output.writeAttribute("x", "0.86in");
483
+                output.writeAttribute("y", "3.16in");
484
+                output.writeAttribute("font-size", "12");
485
+                output.writeCDATA("2");
486
+                output.writeEndElement();
487
+                output.writeStartElement("line");
488
+                output.writeAttribute("x1", "1.28in");
489
+                output.writeAttribute("x2", "1.28in");
490
+                output.writeAttribute("y1", "2.95in");
491
+                output.writeAttribute("y2", "3.05in");
492
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
493
+                output.writeEndElement();
494
+                output.writeStartElement("text");
495
+                output.writeAttribute("x", "1.25in");
496
+                output.writeAttribute("y", "3.16in");
497
+                output.writeAttribute("font-size", "12");
498
+                output.writeCDATA("4");
499
+                output.writeEndElement();
500
+                output.writeStartElement("line");
501
+                output.writeAttribute("x1", "1.67in");
502
+                output.writeAttribute("x2", "1.67in");
503
+                output.writeAttribute("y1", "2.95in");
504
+                output.writeAttribute("y2", "3.05in");
505
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
506
+                output.writeEndElement();
507
+                output.writeStartElement("text");
508
+                output.writeAttribute("x", "1.64in");
509
+                output.writeAttribute("y", "3.16in");
510
+                output.writeAttribute("font-size", "12");
511
+                output.writeCDATA("6");
512
+                output.writeEndElement();
513
+                output.writeStartElement("line");
514
+                output.writeAttribute("x1", "2.06in");
515
+                output.writeAttribute("x2", "2.06in");
516
+                output.writeAttribute("y1", "2.95in");
517
+                output.writeAttribute("y2", "3.05in");
518
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
519
+                output.writeEndElement();
520
+                output.writeStartElement("text");
521
+                output.writeAttribute("x", "2.03in");
522
+                output.writeAttribute("y", "3.16in");
523
+                output.writeAttribute("font-size", "12");
524
+                output.writeCDATA("8");
525
+                output.writeEndElement();
526
+                output.writeStartElement("line");
527
+                output.writeAttribute("x1", "2.45in");
528
+                output.writeAttribute("x2", "2.45in");
529
+                output.writeAttribute("y1", "2.95in");
530
+                output.writeAttribute("y2", "3.05in");
531
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
532
+                output.writeEndElement();
533
+                output.writeStartElement("text");
534
+                output.writeAttribute("x", "2.39in");
535
+                output.writeAttribute("y", "3.16in");
536
+                output.writeAttribute("font-size", "12");
537
+                output.writeCDATA("10");
538
+                output.writeEndElement();
539
+                output.writeStartElement("line");
540
+                output.writeAttribute("x1", "2.84in");
541
+                output.writeAttribute("x2", "2.84in");
542
+                output.writeAttribute("y1", "2.95in");
543
+                output.writeAttribute("y2", "3.05in");
544
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
545
+                output.writeEndElement();
546
+                output.writeStartElement("text");
547
+                output.writeAttribute("x", "2.78in");
548
+                output.writeAttribute("y", "3.16in");
549
+                output.writeAttribute("font-size", "12");
550
+                output.writeCDATA("12");
551
+                output.writeEndElement();
552
+                output.writeStartElement("line");
553
+                output.writeAttribute("x1", "3.23in");
554
+                output.writeAttribute("x2", "3.23in");
555
+                output.writeAttribute("y1", "2.95in");
556
+                output.writeAttribute("y2", "3.05in");
557
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
558
+                output.writeEndElement();
559
+                output.writeStartElement("text");
560
+                output.writeAttribute("x", "3.17in");
561
+                output.writeAttribute("y", "3.16in");
562
+                output.writeAttribute("font-size", "12");
563
+                output.writeCDATA("14");
564
+                output.writeEndElement();
565
+                output.writeStartElement("line");
566
+                output.writeAttribute("x1", "3.62in");
567
+                output.writeAttribute("x2", "3.62in");
568
+                output.writeAttribute("y1", "2.95in");
569
+                output.writeAttribute("y2", "3.05in");
570
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
571
+                output.writeEndElement();
572
+                output.writeStartElement("text");
573
+                output.writeAttribute("x", "3.56in");
574
+                output.writeAttribute("y", "3.16in");
575
+                output.writeAttribute("font-size", "12");
576
+                output.writeCDATA("16");
577
+                output.writeEndElement();
578
+                output.writeStartElement("line");
579
+                output.writeAttribute("x1", "4.01in");
580
+                output.writeAttribute("x2", "4.01in");
581
+                output.writeAttribute("y1", "2.95in");
582
+                output.writeAttribute("y2", "3.05in");
583
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
584
+                output.writeEndElement();
585
+                output.writeStartElement("text");
586
+                output.writeAttribute("x", "3.95in");
587
+                output.writeAttribute("y", "3.16in");
588
+                output.writeAttribute("font-size", "12");
589
+                output.writeCDATA("18");
590
+                output.writeEndElement();
591
+                output.writeStartElement("line");
592
+                output.writeAttribute("x1", "4.4in");
593
+                output.writeAttribute("x2", "4.4in");
594
+                output.writeAttribute("y1", "2.95in");
595
+                output.writeAttribute("y2", "3.05in");
596
+                output.writeAttribute("style", "stroke:rgb(0,0,0);stroke-width:1");
597
+                output.writeEndElement();
598
+                output.writeStartElement("text");
599
+                output.writeAttribute("x", "4.34in");
600
+                output.writeAttribute("y", "3.16in");
601
+                output.writeAttribute("font-size", "12");
602
+                output.writeCDATA("20");
603
+                output.writeEndElement();
604
+                sourceFile.close();
605
+                sourceFile.open(3);
606
+                input = new XmlReader(sourceFile);
607
+
608
+                var lineStyles = new Array();
609
+                lineStyles.push("stroke:rgb(255,0,0);stroke-width:1");
610
+                lineStyles.push("stroke:rgb(0,255,0);stroke-width:1");
611
+                lineStyles.push("stroke:rgb(0,0,255);stroke-width:1");
612
+                lineStyles.push("stroke:rgb(255,255,0);stroke-width:1");
613
+                lineStyles.push("stroke:rgb(255,0,255);stroke-width:1");
614
+                lineStyles.push("stroke:rgb(0,255,255);stroke-width:1");
615
+                var check1 = false;
616
+                var drawable = false;
617
+                var previousX;
618
+                var currentX;
619
+                var previousY = new Array();
620
+                input.readNext();
621
+                while(!input.atEnd())
622
+                {
623
+                    if(input.isStartElement())
624
+                    {
625
+                        if(input.name() == "time")
626
+                        {
627
+                            if(check1)
628
+                            {
629
+                                previousX = currentX;
630
+                            }
631
+                            var tstring = input.readElementText();
632
+                            var tsplit1 = tstring.split(":");
633
+                            var tsplit2 = tsplit1[1].split(".");
634
+                            currentX = 0.5 + (Number(tsplit1[0])*0.195) + (Number(tsplit2[0])*0.00325);// + (Number(tsplit2[1]) * 0.00000325);
635
+                            if(check1)
636
+                            {
637
+                                drawable = true;
638
+                            }
639
+                            check1 = true;
640
+                        }
641
+                        if(input.name() == "temperature")
642
+                        {
643
+                            var series;
644
+                            for(var i = 0; i < tempMap.length; i++)
645
+                            {
646
+                                if(tempMap[i] == input.attribute("series"))
647
+                                {
648
+                                    series = i;
649
+                                    break;
650
+                                }
651
+                            }
652
+                            var currentY = 2.9 - Number(input.readElementText()) * 0.0056;
653
+                            if(drawable)
654
+                            {
655
+                                output.writeStartElement("line");
656
+                                output.writeAttribute("style", lineStyles[series % 6]);
657
+                                output.writeAttribute("x1", String(previousX)+"in");
658
+                                output.writeAttribute("x2", String(currentX)+"in");
659
+                                output.writeAttribute("y1", String(previousY[series])+"in");
660
+                                output.writeAttribute("y2", String(currentY)+"in");
661
+                                output.writeEndElement();
662
+                            }
663
+                            previousY[series] = currentY;
664
+                        }
665
+                    }
666
+                    input.readNext();
667
+                }
668
+                sourceFile.remove();
669
+                sourceFile.close();
670
+                output.writeEndElement();
671
+                output.writeStartElement("div");
672
+                output.writeAttribute("style", "margin-left:3in;margin-top:0.5in");
673
+                var lossField = findChildObject(window, 'loss');
674
+                var tolField = findChildObject(window, 'tolerance');
675
+                if(lossField.text != "")
676
+                {
677
+                    output.writeStartElement("p");
678
+                    output.writeCDATA("Weight loss: ");
679
+                    output.writeCDATA(lossField.text);
680
+                    if(tolField.text != "")
681
+                    {
682
+                        output.writeCDATA("±");
683
+                        output.writeCDATA(tolField.text);
684
+                    }
685
+                    output.writeCDATA("%");
686
+                    output.writeEndElement();
687
+                    output.writeStartElement("table");
688
+                    output.writeStartElement("tr");
689
+                    output.writeStartElement("th");
690
+                    output.writeCDATA("Roasted");
691
+                    output.writeEndElement();
692
+                    output.writeStartElement("th");
693
+                    output.writeCDATA("Green");
694
+                    output.writeEndElement();
695
+                    output.writeEndElement();
696
+                    var green;
697
+                    var roasted;
698
+                    var loss = (Number(lossField.text) + Number(tolField.text)) / 100;
699
+                    for(roasted = 1; roasted < 30; roasted++)
700
+                    {
701
+                        green = (1/-(loss-1)) * roasted;
702
+                        if(green > 30)
703
+                        {
704
+                            break;
705
+                        }
706
+                        if(roasted % 5 == 0)
707
+                        {
708
+                            output.writeStartElement("tr");
709
+                            output.writeStartElement("td");
710
+                            output.writeAttribute("align", "center");
711
+                            output.writeCDATA(roasted);
712
+                            output.writeEndElement();
713
+                            output.writeStartElement("td");
714
+                            output.writeAttribute("align", "center");
715
+                            output.writeCDATA(green.toFixed(2));
716
+                            output.writeEndElement();
717
+                            output.writeEndElement();
718
+                        }
719
+                    }
720
+                    roasted--;
721
+                    if(roasted % 5 > 0)
722
+                    {
723
+                        green = (1/-(loss-1)) * roasted;
724
+                        output.writeStartElement("tr");
725
+                        output.writeStartElement("td");
726
+                        output.writeAttribute("align", "center");
727
+                        output.writeCDATA(roasted);
728
+                        output.writeEndElement();
729
+                        output.writeStartElement("td");
730
+                        output.writeAttribute("align", "center");
731
+                        output.writeCDATA(green.toFixed(2));
732
+                        output.writeEndElement();
733
+                        output.writeEndElement();
734
+                    }
735
+                    output.writeEndElement();
736
+                }
737
+                var noteField = findChildObject(window, 'notes');
738
+                if(noteField.text != "")
739
+                {
740
+                    output.writeStartElement("p");
741
+                    output.writeCDATA(noteField.text);
742
+                    output.writeEndElement();
743
+                }
744
+                output.writeEndElement();
745
+                output.writeEndElement();
746
+                output.writeEndElement();
747
+                output.writeEndElement();
748
+                output.writeEndDocument();
749
+                var printView = new WebView;
750
+                destFile.close();
751
+                printView.load(tf2);
752
+                printView.print();
753
+                destFile.remove();
754
+                window.close();
755
+            });
756
+        ]]>
757
+    </program>
758
+</window>

+ 708
- 0
config/Windows/productionroaster.xml View File

@@ -0,0 +1,708 @@
1
+<window id="basicWindow">
2
+    <layout type="vertical">
3
+        <splitter type = "vertical" id = "main">
4
+            <splitter type = "horizontal" id = "indicators" />
5
+            <widget id="widget">
6
+                <layout type="horizontal" id="controlpanel">
7
+                    <button name="Start Batch" type="push" id="startbutton" />
8
+                    <button name="Stop Batch" type="annotation" id="stopbutton" annotation="End" />
9
+                </layout>
10
+            </widget>
11
+            <splitter type="horizontal" id="logsplit">
12
+                <measurementtable id="log" />
13
+                <graph id="graph" />
14
+            </splitter>
15
+        </splitter>
16
+    </layout>
17
+    <menu name="File">
18
+        <item id="open" shortcut="Ctrl+O">Open…</item>
19
+        <item id="save" shortcut="Ctrl+S">Save…</item>
20
+        <item id="print" shortcut="Ctrl+P">Print…</item>
21
+        <item id="export">Export CSV…</item>
22
+        <item id="svgexport">Export XHTML+SVG…</item>
23
+        <item id="quit" shortcut="Ctrl+Q">Quit</item>
24
+    </menu>
25
+    <menu name="Batch">
26
+        <item id="new" shortcut="Ctrl+N">New Batch…</item>
27
+        <item id="compare">Load Additional Profiles...</item>
28
+    </menu>
29
+    <menu name="Log">
30
+        <item id="showC">Display Celsius</item>
31
+        <item id="showF">Display Fahrenheit</item>
32
+        <item id="setSample">New Sample Parameters</item>
33
+        <separator />
34
+        <item id="clear" shortcut="Ctrl+L">Clear Log</item>
35
+        <separator />
36
+        <item id="ms">Millisecond View</item>
37
+        <item id="1s">1 Second View</item>
38
+        <item id="5s">5 Second View</item>
39
+        <item id="10s">10 Second View</item>
40
+        <item id="15s">15 Second View</item>
41
+        <item id="30s">30 Second View</item>
42
+        <item id="1m">1 Minute View</item>
43
+        <separator />
44
+        <item id="manual" shortcut="Ctrl+E">Manual Entry</item>
45
+    </menu>
46
+	<menu name="Graph">
47
+		<item id="unshift">Reset Translation</item>
48
+	</menu>
49
+    <program>
50
+		<![CDATA[
51
+		var window = this;
52
+		var targetOffset = 0;
53
+		var gtrans = 0;
54
+		var targetDetector = new ThresholdDetector;
55
+		window.targetcolumnname = "";
56
+		var currentDetector = new ThresholdDetector;
57
+		var translationChannel = -1;
58
+		targetDetector.timeForValue.connect(function(value) {
59
+			targetOffset = value;
60
+		});
61
+		var epoch = new QTime;
62
+		epoch = epoch.currentTime;
63
+		var translationCurrentColumn = -1;
64
+		var configModel = new DeviceTreeModel;
65
+		var rootIndex = configModel.index(roasterlist.currentIndex, 0);
66
+		var channels = new Array();
67
+		var annotationButtons = new Array();
68
+		var nidevices = new Array();
69
+		var temperatureDisplays = new Array();
70
+		var columnNames = new Array();
71
+		var modbusdevices = new Array();
72
+		var indicatorPanel = findChildObject(this, 'indicators');
73
+		var annotationPanel = findChildObject(this, 'controlpanel');
74
+		var log = findChildObject(this, 'log');
75
+		var tabControls = new Array();
76
+		var start = findChildObject(this, 'startbutton');
77
+		var stop = findChildObject(this, 'stopbutton');
78
+		stop.enabled = false;
79
+		tabControls.push(start);
80
+		tabControls.push(stop);
81
+		var nsparam = findChildObject(this, 'setSample');
82
+		nsparam.enabled = false;
83
+		var graph = findChildObject(this, 'graph');
84
+		var hasTranslated = false;
85
+		var externtrans = undefined;
86
+		window.translateLoadedSeries = function(translation) {
87
+			var lc = Number(QSettings.value("liveColumn"));
88
+			for(var i = 1; i < lc - 1; i++)
89
+			{
90
+				graph.setSeriesTranslation(i, translation);
91
+			}
92
+		};
93
+		window.translateCurrentSeries = function(translation) {
94
+			var lc = Number(QSettings.value("liveColumn"));
95
+			for(var i = 0; i < columnNames.length; i++)
96
+			{
97
+				graph.setSeriesTranslation(lc + i, translation);
98
+			}
99
+		};
100
+		var selectedRoasterName = configModel.data(rootIndex, 0);
101
+		var machineReference = configModel.referenceElement(configModel.data(rootIndex, 32));
102
+		var selectedRoasterID = machineReference.databaseid;
103
+		if(configModel.hasChildren(rootIndex)) {
104
+			for(var i = 0; i < configModel.rowCount(rootIndex); i++) {
105
+				var driverIndex = configModel.index(i, 0, rootIndex);
106
+				var driverReference = configModel.referenceElement(configModel.data(driverIndex, 32));
107
+				if(driverReference.driver == "nidaqmxbase" || driverReference.driver == "nidaqmx") {
108
+				if(configModel.hasChildren(driverIndex)) {
109
+						for(var j = 0; j < configModel.rowCount(driverIndex); j++) {
110
+							var deviceIndex = configModel.index(j, 0, driverIndex);
111
+							var deviceReference = configModel.referenceElement(configModel.data(deviceIndex, 32));
112
+							if(deviceReference.driver == "nidaqmxbase9211series" || deviceReference.driver == "nidaqmx9211series") {								
113
+								var device = new DAQ(deviceReference.deviceID, driverReference.driver);
114
+								nidevices.push(device);
115
+								var DAQChannels = 0;
116
+								if(configModel.hasChildren(deviceIndex)) {
117
+									for(var k = 0; k < configModel.rowCount(deviceIndex); k++) {
118
+										var channelIndex = configModel.index(k, 0, deviceIndex);
119
+										var channelReference = configModel.referenceElement(configModel.data(channelIndex, 32));
120
+										if(channelReference.driver == "ni9211seriestc")	{											
121
+											var channel;
122
+											if(channelReference.type == "J") {
123
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeJ);
124
+											}
125
+											else if(channelReference.type == "K") {
126
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeK);
127
+											}
128
+											else if(channelReference.type == "T") {
129
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeT);
130
+											}
131
+											else if(channelReference.type == "B") {
132
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeB);
133
+											}
134
+											else if(channelReference.type == "E") {
135
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeE);
136
+											}
137
+											else if(channelReference.type == "N") {
138
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeN);
139
+											}
140
+											else if(channelReference.type == "R") {
141
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeR);
142
+											}
143
+											else if(channelReference.type == "S") {
144
+												channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeS);
145
+											}
146
+											channels.push(channel);
147
+											columnNames.push(channelReference.columnname);
148
+											DAQChannels++;
149
+											var indicator = new TemperatureDisplay;
150
+											temperatureDisplays.push(indicator);
151
+											var decorator = new WidgetDecorator(indicator, configModel.data(channelIndex, 0), 2);
152
+											channel.newData.connect(indicator.setValue);
153
+											indicatorPanel.addWidget(decorator);
154
+										}
155
+									}
156
+									switch(DAQChannels) {
157
+										case 1:
158
+											device.setClockRate(4);
159
+											break;
160
+										case 2:
161
+											device.setClockRate(2);
162
+											break;
163
+										case 3:
164
+											device.setClockRate(1.5);
165
+											break;
166
+										case 4:
167
+											device.setClockRate(1);
168
+											break;
169
+									}
170
+									device.start();
171
+								}
172
+							}
173
+							else if(deviceReference.driver == "nidaqmxtc01")
174
+							{						
175
+								var device = new DAQ(deviceReference.deviceID, "nidaqmx");
176
+								var channel;
177
+								if(deviceReference.type == "J")
178
+								{
179
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeJ);
180
+								}
181
+								else if(deviceReference.type == "K")
182
+								{
183
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeK);
184
+								}
185
+								else if(deviceReference.type == "T")
186
+								{
187
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeT);
188
+								}
189
+								else if(deviceReference.type == "B")
190
+								{
191
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeB);
192
+								}
193
+								else if(deviceReference.type == "E")
194
+								{
195
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeE);
196
+								}
197
+								else if(deviceReference.type == "N")
198
+								{
199
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeN);
200
+								}
201
+								else if(deviceReference.type == "R")
202
+								{
203
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeR);
204
+								}
205
+								else if(deviceReference.type == "S")
206
+								{
207
+									channel = device.newChannel(DAQ.Fahrenheit, DAQ.TypeS);
208
+								}
209
+								channels.push(channel);
210
+								columnNames.push(deviceReference.columnname);
211
+								var indicator = new TemperatureDisplay;
212
+								temperatureDisplays.push(indicator);
213
+								var decorator = new WidgetDecorator(indicator, configModel.data(deviceIndex, 0), 2);
214
+								channel.newData.connect(indicator.setValue);
215
+								indicatorPanel.addWidget(decorator);
216
+								device.start();
217
+								nidevices.push(device);
218
+							}
219
+						}
220
+					}
221
+				}
222
+				else if(driverReference.driver == "modbusrtu")
223
+				{
224
+					var device = new ModbusRTUDevice(configModel, driverIndex);
225
+					modbusdevices.push(device);
226
+					var pvchannel = device.pVChannel();
227
+					channels.push(pvchannel);
228
+					columnNames.push(driverReference.pvcolname);
229
+					var indicator = new TemperatureDisplay;
230
+					temperatureDisplays.push(indicator);
231
+					var decorator = new WidgetDecorator(indicator, configModel.data(driverIndex, 0) + " PV", 2);
232
+					pvchannel.newData.connect(indicator.setValue);
233
+					indicatorPanel.addWidget(decorator);
234
+					if(driverReference.sVEnabled == "true")
235
+					{
236
+						var svchannel = device.sVChannel();
237
+						channels.push(svchannel);
238
+						columnNames.push(driverReference.svcolname);
239
+						var indicator = new TemperatureDisplay;
240
+						temperatureDisplays.push(indicator);
241
+						var decorator = new WidgetDecorator(indicator, configModel.data(driverIndex, 0) + " SV", 2);
242
+						svchannel.newData.connect(indicator.setValue);
243
+						indicatorPanel.addWidget(decorator);
244
+					}
245
+					if(driverReference.sVWritable == "true")
246
+					{
247
+						var outputControl = new AnnotationSpinBox;
248
+						device.SVLowerChanged.connect(function(min) {
249
+							outputControl.minimum = min;
250
+						});
251
+						outputControl.minimum = device.SVLower();
252
+						device.SVUpperChanged.connect(function(max) {
253
+							outputControl.maximum = max;
254
+						});
255
+						outputControl.maximum = device.SVUpper();
256
+						device.SVDecimalChanged.connect(function(prec) {
257
+							outputControl.decimals = prec;
258
+						});
259
+						outputControl.decimals = device.decimals();
260
+						outputControl.editingFinished.connect(function() {
261
+							device.outputSV(outputControl.value);
262
+						});
263
+						var layout = new QBoxLayout;
264
+						var label = new QLabel("Change SV");
265
+						layout.addWidget(label, 0, 2);
266
+						layout.addWidget(outputControl, 0, 1);
267
+						annotationPanel.addLayout(layout);
268
+						tabControls.push(outputControl);
269
+					}
270
+				}
271
+				else if(driverReference.driver == "annotationbutton")
272
+				{
273
+					var button = new AnnotationButton(driverReference.buttontext);
274
+					button.setAnnotation(driverReference.annotationtext);
275
+					annotationButtons.push(button);
276
+					annotationPanel.addWidget(button);
277
+					tabControls.push(button);
278
+				}
279
+				else if(driverReference.driver == "reconfigurablebutton")
280
+				{
281
+					var button = new AnnotationButton(driverReference.buttontext);
282
+					button.setAnnotation(driverReference.annotationtext);
283
+					annotationButtons.push(button);
284
+					annotationPanel.addWidget(button);
285
+					tabControls.push(button);
286
+					nsparam.enabled = true;
287
+					nsparam.triggered.connect(function() {
288
+						var setParam = createWindow("sampleParameters");
289
+						setParam.windowTitle = "Typica - Set Sample Parameters";
290
+						setParam.button = button;
291
+					});
292
+				}
293
+				else if(driverReference.driver == "annotationspinbox")
294
+				{
295
+					var layout = new QBoxLayout;
296
+					var label = new QLabel(driverReference.label);
297
+					layout.addWidget(label, 0, 2);
298
+					var spinbox = new AnnotationSpinBox;
299
+					spinbox.setPretext(driverReference.pretext);
300
+					spinbox.setPosttext(driverReference.posttext);
301
+					spinbox.minimum = driverReference.minimum;
302
+					spinbox.maximum = driverReference.maximum;
303
+					spinbox.decimals = driverReference.precision;
304
+					layout.addWidget(spinbox, 0, 1);
305
+					annotationPanel.addLayout(layout);
306
+					annotationButtons.push(spinbox);
307
+					tabControls.push(spinbox);
308
+				}
309
+				else if(driverReference.driver == "linearspline")
310
+				{
311
+					var colname = driverReference.source;
312
+					for(var j = 0; j < columnNames.length; j++)
313
+					{
314
+						if(columnNames[j] == colname)
315
+						{
316
+							var calibrator = new LinearSplineInterpolator;
317
+							var sv = driverReference.sourcevalues;
318
+							var dv = driverReference.destinationvalues;
319
+							var sourcevalues = sv.slice(2, sv.length-2).split(",");
320
+							var destvalues = dv.slice(2, dv.length-2).split(",");
321
+							if(sourcevalues.length > 1 && destvalues.length == sourcevalues.length)
322
+							{
323
+								for(var k = 0; k < sourcevalues.length; k++)
324
+								{
325
+									calibrator.add_pair(Number(sourcevalues[k]),Number(destvalues[k]));
326
+								}
327
+								var indicator = new TemperatureDisplay;
328
+								temperatureDisplays.push(indicator);
329
+								var decorator = new WidgetDecorator(indicator, configModel.data(driverIndex, 0), 2);
330
+								channels[j].newData.connect(calibrator.newMeasurement);
331
+								calibrator.newData.connect(indicator.setValue);
332
+								channels.push(calibrator);
333
+								columnNames.push(driverReference.destination);
334
+								indicatorPanel.addWidget(decorator);
335
+							}
336
+							break;
337
+						}
338
+					}
339
+				}
340
+				else if(driverReference.driver == "translation")
341
+				{
342
+					var colname = driverReference.column;
343
+					window.targetcolumnname = colname;
344
+					for(var j = 0; j < columnNames.length; j++)
345
+					{
346
+						if(columnNames[j] == colname)
347
+						{
348
+							translationChannel = j;
349
+							var indicator = new TemperatureDisplay;
350
+							externtrans = indicator;
351
+							indicator.display(0);
352
+							var decorator = new WidgetDecorator(indicator, configModel.data(driverIndex, 0), 2);
353
+							indicatorPanel.addWidget(decorator);
354
+							currentDetector.timeForValue.connect(function(value) {
355
+								if(!hasTranslated)
356
+								{
357
+									var currentOffset = value;
358
+									if(targetOffset != 0)
359
+									{
360
+										var translation = currentOffset - targetOffset;
361
+										indicator.display(translation);
362
+										gtrans = translation;
363
+										if(translation > 0)
364
+										{
365
+											window.translateLoadedSeries(translation);
366
+										}
367
+										else
368
+										{
369
+											window.translateCurrentSeries(-translation);
370
+										}
371
+									}
372
+								}
373
+								hasTranslated = true;
374
+							});
375
+							var resetTranslation = findChildObject(this, 'unshift');
376
+							resetTranslation.triggered.connect(function() {
377
+								if(gtrans > 0) {
378
+									window.translateLoadedSeries(-gtrans);
379
+								}
380
+								else {
381
+									window.translateCurrentSeries(gtrans);
382
+								}
383
+								gtrans = 0;
384
+								indicator.display(0);
385
+							});
386
+						}
387
+					}
388
+					targetDetector.setThreshold(driverReference.FValue);
389
+					currentDetector.setThreshold(driverReference.FValue);
390
+				}
391
+			}
392
+		}
393
+		for(var i = 1; i < tabControls.length; i++)
394
+		{
395
+			setTabOrder(tabControls[i-1], tabControls[i]);
396
+		}
397
+		log.setHeaderData(0, "Time");
398
+		for(var i = 0; i < columnNames.length; i++) {
399
+			log.setHeaderData(i + 1, columnNames[i]);
400
+		}
401
+		log.setHeaderData(columnNames.length + 1, "Note");
402
+		for(var i = 0; i < channels.length; i++) {
403
+			log.addToCurrentColumnSet(i + 1);
404
+		}
405
+		var timer = new TimerDisplay;
406
+		timer.displayFormat = "mm:ss";
407
+		timer.autoReset = true;
408
+		var btdecorator = new WidgetDecorator(timer, "Batch Timer", 2);
409
+		indicatorPanel.addWidget(btdecorator);
410
+		var vsplit = findChildObject(this, 'main');
411
+		var isplit = findChildObject(this, 'indicators');
412
+		var lsplit = findChildObject(this, 'logsplit');
413
+		window.aboutToClose.connect(function() {
414
+			for(var i = 0; i < nidevices.length; i++)
415
+			{
416
+				nidevices[i].stop();
417
+				nidevices[i].deleteLater();
418
+			}
419
+			for(var i = 0; i < modbusdevices.length; i++)
420
+			{
421
+				modbusdevices[i].deleteLater();
422
+			}
423
+			delete nidevices;
424
+			delete modbusdevices;
425
+            window.saveSizeAndPosition("window");
426
+            vsplit.saveState("script/mainSplitter");
427
+            isplit.saveState("script/instrumentSplitter");
428
+            lsplit.saveState("script/logSplitter");
429
+            log.saveState("script/log", 7);
430
+			window.navigationWindow.loggingWindow = undefined;
431
+        });
432
+		this.restoreSizeAndPosition('window');
433
+        vsplit.restoreState("script/mainSplitter");
434
+        isplit.restoreState("script/instrumentSplitter");
435
+        lsplit.restoreState("script/logSplitter");
436
+		log.restoreState("script/log", 7);
437
+		var offsets = new Array();
438
+		var zeroemitters = new Array();
439
+		var adapters = new Array();
440
+		for(var i = 0; i < channels.length; i++) {
441
+			var offset = new MeasurementTimeOffset(epoch);
442
+			offsets.push(offset);
443
+			channels[i].newData.connect(offset.newMeasurement);
444
+			var adapter = new MeasurementAdapter(i + 1);
445
+			adapters.push(adapter);
446
+			offset.measurement.connect(adapter.newMeasurement);
447
+			var emitter = new ZeroEmitter(i + 1);
448
+			zeroemitters.push(emitter);
449
+			channels[i].newData.connect(emitter.newMeasurement);
450
+			emitter.measurement.connect(log.newMeasurement);
451
+			emitter.measurement.connect(graph.newMeasurement);
452
+		}
453
+        start.clicked.connect(function() {
454
+			start.enabled = false;
455
+			hasTranslated = false;
456
+            var epoch = new QTime();
457
+            epoch = epoch.currentTime();
458
+			for(var i = 0; i < offsets.length; i++)
459
+			{
460
+				offsets[i].setZeroTime(epoch);
461
+				zeroemitters[i].emitZero();
462
+				adapters[i].measurement.connect(log.newMeasurement);
463
+				adapters[i].measurement.connect(graph.newMeasurement);
464
+			}
465
+			timer.startTimer();
466
+            if(typeof(currentBatchInfo) == 'undefined') { } else {
467
+                query = new QSqlQuery();
468
+                query.exec("SELECT now()::timestamp without time zone");
469
+                query.next();
470
+                var result = query.value(0);
471
+                query = query.invalidate();
472
+                var timefield = findChildObject(currentBatchInfo, 'time');
473
+                timefield.text = result.replace('T', ' ');
474
+            }
475
+			if(translationChannel >= 0)
476
+			{
477
+				offsets[translationChannel].measurement.connect(currentDetector.newMeasurement);
478
+			}
479
+			if(typeof(externtrans) != 'undefined') {
480
+				externtrans.display(0);
481
+			}
482
+			stop.enabled = true;
483
+        });
484
+		for(var i = 0; i < annotationButtons.length; i++) {
485
+			if(channels.length > 0)
486
+			{
487
+				annotationButtons[i].annotation.connect(log.newAnnotation);
488
+				annotationButtons[i].setTemperatureColumn(1);
489
+				annotationButtons[i].setAnnotationColumn(channels.length + 1);
490
+				annotationButtons[i].annotation.connect(function(note, tcol, ncol) {
491
+					for(var i = tcol; i < ncol; i++) {
492
+						log.newAnnotation(note, i, ncol);
493
+					}
494
+				});
495
+			}
496
+		}
497
+        start.setFocus();
498
+        stop.annotation.connect(log.newAnnotation);
499
+        stop.clicked.connect(timer.stopTimer);
500
+		stop.setTemperatureColumn(1);
501
+		stop.setAnnotationColumn(channels.length + 1);
502
+		QSettings.setValue("liveColumn", 1);
503
+        var lc = 1;
504
+        stop.clicked.connect(function() {
505
+			stop.enabled = false;
506
+			for(var i = 0; i < adapters.length; i++)
507
+			{
508
+				adapters[i].measurement.disconnect(log.newMeasurement);
509
+				adapters[i].measurement.disconnect(graph.newMeasurement);
510
+			}
511
+            if(typeof(currentBatchInfo) == 'undefined') { } else {
512
+                lc = Number(QSettings.value("liveColumn"));
513
+                var duration = log.lastTime(lc);
514
+                var durfield = findChildObject(currentBatchInfo, 'duration');
515
+                durfield.text = duration;
516
+                log.clearOutputColumns();
517
+				for(var i = 0; i < channels.length; i++)
518
+				{
519
+					log.addOutputTemperatureColumn(lc + i);
520
+				}
521
+				log.addOutputAnnotationColumn(lc + channels.length);
522
+                var filename = log.saveTemporary();
523
+                currentBatchInfo.tempData = filename;
524
+                currentBatchInfo.raise();
525
+                currentBatchInfo.activateWindow();
526
+            }
527
+			if(translationChannel >= 0)
528
+			{
529
+				offsets[translationChannel].measurement.disconnect(currentDetector.newMeasurement);
530
+			}
531
+			start.enabled = true;
532
+        });
533
+		stop.annotation.connect(function(note, tcol, ncol) {
534
+			for(var i = tcol; i < ncol; i++) {
535
+				log.newAnnotation(note, i, ncol);
536
+			}
537
+		});
538
+		var quitMenu = findChildObject(this, 'quit');
539
+        quitMenu.triggered.connect(function() {
540
+            window.close();
541
+            Application.quit();
542
+        });
543
+        var v1 = findChildObject(this, 'ms');
544
+        v1.triggered.connect(log.LOD_ms);
545
+        var v2 = findChildObject(this, '1s');
546
+        v2.triggered.connect(log.LOD_1s);
547
+        var v3 = findChildObject(this, '5s');
548
+        v3.triggered.connect(log.LOD_5s);
549
+        var v4 = findChildObject(this, '10s');
550
+        v4.triggered.connect(log.LOD_10s);
551
+        var v5 = findChildObject(this, '15s');
552
+        v5.triggered.connect(log.LOD_15s);
553
+        var v6 = findChildObject(this, '30s');
554
+        v6.triggered.connect(log.LOD_30s);
555
+        var v7 = findChildObject(this, '1m');
556
+        v7.triggered.connect(log.LOD_1m);
557
+        var showC = findChildObject(this, 'showC');
558
+        showC.triggered.connect(function() {
559
+			for(var i = 0; i < temperatureDisplays.length; i++)
560
+			{
561
+				temperatureDisplays[i].setDisplayUnits(TemperatureDisplay.Celsius);
562
+			}
563
+            log.setDisplayUnits(TemperatureDisplay.Celsius);
564
+            graph.showC();
565
+        });
566
+        var showF = findChildObject(this, 'showF');
567
+        showF.triggered.connect(function() {
568
+			for(var i = 0; i < temperatureDisplays.length; i++)
569
+			{
570
+				temperatureDisplays[i].setDisplayUnits(TemperatureDisplay.Fahrenheit);
571
+			}
572
+            log.setDisplayUnits(TemperatureDisplay.Fahrenheit);
573
+            graph.showF();
574
+        });
575
+		var clear = findChildObject(this, 'clear');
576
+        clear.triggered.connect(log.clear);
577
+        clear.triggered.connect(graph.clear);
578
+        clear.triggered.connect(function() {
579
+            window.windowTitle = "Typica";
580
+			log.setHeaderData(0, "Time");
581
+            QSettings.setValue("liveColumn", 1);
582
+			window.postLoadColumnSetup(0);
583
+			if(typeof(externtrans) != 'undefined') {
584
+				externtrans.display(0);
585
+			}
586
+        });
587
+		var openMenu = findChildObject(this, 'open');
588
+        var compareMenu = findChildObject(this, 'compare');
589
+        compareMenu.triggered.connect(function() {
590
+            QSettings.setValue('cseries', lc+1);
591
+            var history = createWindow("history");
592
+            history.windowTitle = 'Typica - Roasting Log';
593
+        });
594
+        var printMenu = findChildObject(this, 'print');
595
+        printMenu.triggered.connect(function() {
596
+            var exportWindow = createWindow("print");
597
+            exportWindow.windowTitle = "Typica - Print";
598
+            exportWindow.log = log;
599
+        });
600
+        var svgExportMenu = findChildObject(this, 'svgexport');
601
+        svgExportMenu.triggered.connect(function() {
602
+            var exportWindow = createWindow("exportWindow");
603
+            exportWindow.windowTitle = "Typica - Export XHTML+SVG";
604
+            exportWindow.log = log;
605
+        });
606
+        openMenu.triggered.connect(function() {
607
+            var filename = QFileDialog.getOpenFileName(window, 'Open Log…', QSettings.value('script/lastDir', '') + '/');
608
+            if(filename != '') {
609
+                var file = new QFile(filename);
610
+                var input = new XMLInput(file, 1);
611
+				targetseries = -1;
612
+                input.newTemperatureColumn.connect(log.setHeaderData);
613
+				input.newTemperatureColumn.connect(function(col, text) {
614
+					if(text == window.targetcolumnname) {
615
+						targetseries = col;
616
+					}
617
+				});
618
+                input.newAnnotationColumn.connect(log.setHeaderData);
619
+                input.measure.connect(graph.newMeasurement);
620
+                input.measure.connect(log.newMeasurement);
621
+				input.measure.connect(function(data, series) {
622
+					if(series == targetseries) {
623
+						targetDetector.newMeasurement(data);
624
+					}
625
+				});
626
+                input.annotation.connect(log.newAnnotation);
627
+				input.annotation.connect(function(note, tcol, ncol) {
628
+					for(var i = tcol; i < ncol; i++) {
629
+						log.newAnnotation(note, i, ncol);
630
+					}
631
+				});
632
+				var lc;
633
+                input.lastColumn.connect(function(c) {
634
+					lc = c;
635
+                    QSettings.setValue("liveColumn", c + 1);
636
+					window.postLoadColumnSetup(c);
637
+				});
638
+                input.input();
639
+                window.windowTitle = 'Typica - ' + baseName(filename);
640
+                QSettings.setValue("script/lastDir", dir(filename));
641
+				log.newAnnotation("End", 1, lc);
642
+            }
643
+        });
644
+		window.postLoadColumnSetup = function(c) {
645
+			for(var i = 0; i < adapters.length; i++)
646
+			{
647
+				adapters[i].setColumn(c + i + 1);
648
+				zeroemitters[i].setColumn(c + i + 1);
649
+				log.setHeaderData(c + i + 1, columnNames[i]);
650
+			}
651
+			log.setHeaderData(c + columnNames.length + 1, "Note");
652
+            stop.setTemperatureColumn(c + 1);
653
+			stop.setAnnotationColumn(c + columnNames.length + 1);
654
+			for(var i = 0; i < annotationButtons.length; i++)
655
+			{
656
+				annotationButtons[i].setTemperatureColumn(c + 1);
657
+				annotationButtons[i].setAnnotationColumn(c + columnNames.length + 1);
658
+			}
659
+			log.clearCurrentColumnSet();
660
+			for(var i = 0; i < channels.length; i++) {
661
+				log.addToCurrentColumnSet(c + i + 1);
662
+			}
663
+		};
664
+		var saveMenu = findChildObject(this, 'save');
665
+        saveMenu.triggered.connect(function() {
666
+            var filename = QFileDialog.getSaveFileName(window, "Save Log As…", QSettings.value("script/lastDir", "") + "/");
667
+            if(filename != "") {
668
+                var lc = Number(QSettings.value("liveColumn"));
669
+                var file = new QFile(filename);
670
+                log.clearOutputColumns();
671
+				for(var i = 0; i < columnNames.length; i++)
672
+				{
673
+					log.addOutputTemperatureColumn(lc + i);
674
+				}
675
+				log.addOutputAnnotationColumn(lc + columnNames.length);
676
+                log.saveXML(file);
677
+                QSettings.setValue("script/lastDir", dir(filename));
678
+            }
679
+        });
680
+		var exportMenu = findChildObject(this, 'export');
681
+        exportMenu.triggered.connect(function() {
682
+            var filename = QFileDialog.getSaveFileName(window, "Export CSV As…", QSettings.value("script/lastDir", "") + "/");
683
+            if(filename != "") {
684
+                var lc = Number(QSettings.value("liveColumn"));
685
+                var file = new QFile(filename);
686
+                log.clearOutputColumns();
687
+				for(var i = 0; i < columnNames.length; i++)
688
+				{
689
+					log.addOutputTemperatureColumn(lc + i);
690
+				}
691
+				log.addOutputAnnotationColumn(lc + columnNames.length);
692
+                log.saveCSV(file);
693
+                QSettings.setValue("script/lastDir", dir(filename));
694
+            }
695
+        });
696
+        var manual = findChildObject(this, 'manual');
697
+        manual.triggered.connect(function() {
698
+            var entry = new LogEditWindow();
699
+            entry.show();
700
+        });
701
+        var newMenu = findChildObject(this, 'new');
702
+        newMenu.triggered.connect(function() {
703
+            var bwindow = createWindow("batchWindow");
704
+            bwindow.windowTitle = "Typica - New Batch";
705
+        });
706
+		]]>
707
+    </program>
708
+</window>

+ 396
- 0
config/Windows/purchase.xml View File

@@ -0,0 +1,396 @@
1
+<window id="purchase">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <button name="Add Item" type="push" id="newForm" />
5
+            <label>Date:</label>
6
+            <calendar id="date"/>
7
+            <label>Vendor:</label>
8
+            <sqldrop data="0" display="0" showdata="false" editable="true" id="vendor">
9
+                <query>SELECT DISTINCT vendor FROM purchase UNION SELECT '' ORDER BY vendor ASC</query>
10
+            </sqldrop>
11
+            <label>Invoice:</label>
12
+            <line id="invoice" />
13
+        </layout>
14
+        <formarray id="form">
15
+            <layout type="grid">
16
+                <row>
17
+                    <column><label>Item:</label></column>
18
+                    <column>
19
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="name">
20
+                            <query>SELECT DISTINCT name FROM coffees UNION SELECT '' ORDER BY name ASC</query>
21
+                        </sqldrop>
22
+                    </column>
23
+                    <column />
24
+                    <column><label>Reference:</label></column>
25
+                    <column>
26
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="reference">
27
+                            <query>SELECT DISTINCT reference FROM coffees UNION SELECT '' ORDER BY reference ASC</query>
28
+                        </sqldrop>
29
+                    </column>
30
+                </row>
31
+                <row>
32
+                    <column><label>Quantity:</label></column>
33
+                    <column>
34
+                        <line validator="numeric" id="quantity" />
35
+                    </column>
36
+                    <column />
37
+                    <column><label>Unit:</label></column>
38
+                    <column>
39
+                        <sqldrop data="0" display="0" showdata="false" editable="false" id="units">
40
+                            <query>SELECT * FROM (VALUES('Lb'),('Kg')) AS q (unit)</query>
41
+                        </sqldrop>
42
+                    </column>
43
+                </row>
44
+                <row>
45
+                    <column><label>Cost:</label></column>
46
+                    <column>
47
+                        <line validator="numeric" id="cost" />
48
+                    </column>
49
+                    <column>
50
+                        <sqldrop data="0" display="0" showdata="false" editable="false" id="costModifier">
51
+                            <query>SELECT 'per unit' UNION SELECT 'total'</query>
52
+                        </sqldrop>
53
+                    </column>
54
+                </row>
55
+                <row>
56
+                    <column><label>Origin:</label></column>
57
+                    <column>
58
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="origin">
59
+                            <query>SELECT DISTINCT origin FROM coffees UNION SELECT '' ORDER BY origin ASC</query>
60
+                        </sqldrop>
61
+                    </column>
62
+                    <column />
63
+                    <column><label>Region:</label></column>
64
+                    <column>
65
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="region">
66
+                            <query>SELECT DISTINCT region FROM coffees UNION SELECT '' ORDER BY region ASC</query>
67
+                        </sqldrop>
68
+                    </column>
69
+                </row>
70
+                <row>
71
+                    <column><label>Producer</label></column>
72
+                    <column>
73
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="producer">
74
+                            <query>SELECT DISTINCT producer FROM coffees UNION SELECT '' ORDER BY producer ASC</query>
75
+                        </sqldrop>
76
+                    </column>
77
+                    <column />
78
+                    <column><label>Grade:</label></column>
79
+                    <column>
80
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="grade">
81
+                            <query>SELECT DISTINCT grade FROM coffees UNION SELECT '' ORDER BY grade ASC</query>
82
+                        </sqldrop>
83
+                    </column>
84
+                </row>
85
+                <row>
86
+                    <column><label>Milling:</label></column>
87
+                    <column>
88
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="milling">
89
+                            <query>SELECT DISTINCT milling FROM coffees UNION SELECT '' ORDER BY milling ASC</query>
90
+                        </sqldrop>
91
+                    </column>
92
+                    <column />
93
+                    <column><label>Drying:</label></column>
94
+                    <column>
95
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="drying">
96
+                            <query>SELECT DISTINCT drying FROM coffees UNION SELECT '' ORDER BY drying ASC</query>
97
+                        </sqldrop>
98
+                    </column>
99
+                </row>
100
+                <row>
101
+                    <column><label>Bags:</label></column>
102
+                    <column>
103
+                        <line validator="numeric" id="bags" />
104
+                    </column>
105
+                    <column>
106
+                        <button type="check" id="isDecaf" name="Decaffeinated" />
107
+                    </column>
108
+                    <column><label>by method:</label></column>
109
+                    <column>
110
+                        <sqldrop data="0" display="0" showdata="false" editable="true" id="decafMethod">
111
+                            <query>SELECT DISTINCT decaf_method FROM decaf_coffees UNION SELECT '' ORDER BY decaf_method ASC</query>
112
+                        </sqldrop>
113
+                    </column>
114
+                </row>
115
+                <row>
116
+                    <column colspan="2">
117
+                        <line id="certdisplay" writable="false" />
118
+                    </column>
119
+                    <column column="2">
120
+                        <button type="push" name="Add Certification" id="addcert" />
121
+                    </column>
122
+                    <column colspan="2">
123
+                        <line id="certification" />
124
+                    </column>
125
+                </row>
126
+            </layout>
127
+        </formarray>
128
+        <layout type="horizontal">
129
+            <layout type="vertical">
130
+                <label>Fees:</label>
131
+                <sqltablearray columns="2" id="fees">
132
+                    <column name="Fee Description" />
133
+                    <column name="Amount" />
134
+                </sqltablearray>
135
+            </layout>
136
+            <button name="Submit" type="push" id="submit" />
137
+        </layout>
138
+    </layout>
139
+    <program>
140
+        <![CDATA[
141
+            var window = this;
142
+			var convertToPounds = function(w, u) {
143
+				switch(u) {
144
+					case "g":
145
+						return w * 0.0022;
146
+					case "oz":
147
+						return w * 0.0625;
148
+					case "Kg":
149
+						return w * 2.2;
150
+				}
151
+				return w;
152
+			};
153
+			var convertToPerPounds = function(w, u) {
154
+				switch(u) {
155
+					case "g":
156
+						return w / 0.0022;
157
+					case "oz":
158
+						return w / 0.0625;
159
+					case "Kg":
160
+						return w / 2.2;
161
+				}
162
+				return w;
163
+			};
164
+            this.windowTitle = 'Typica - Coffee Purchase';
165
+            var form = findChildObject(this, 'form');
166
+            form.setMaximumElementHeight(320);
167
+            var appendForm = function() {
168
+                form.addElements(1);
169
+                var thisCoffee = form.elementAt(form.elements() - 1);
170
+                var decafButton = findChildObject(thisCoffee, 'isDecaf');
171
+                var methodField = findChildObject(thisCoffee, 'decafMethod');
172
+                methodField.enabled = false;
173
+                decafButton.stateChanged.connect(function(state) {
174
+                    if(state == 0)
175
+                    {
176
+                        methodField.enabled = false;
177
+                    }
178
+                    else
179
+                    {
180
+                        methodField.enabled = true;
181
+                    }
182
+                });
183
+                var certificationButton = findChildObject(thisCoffee, 'addcert');
184
+                var certSource = findChildObject(thisCoffee, 'certification');
185
+                var certTarget = findChildObject(thisCoffee, 'certdisplay');
186
+                certificationButton.clicked.connect(function() {
187
+                    if(thisCoffee.certificationArray === undefined)
188
+                    {
189
+                        thisCoffee.certificationArray = new Array();
190
+                    }
191
+                    thisCoffee.certificationArray.push(certSource.text);
192
+                    certTarget.text = thisCoffee.certificationArray.toString();
193
+                    certSource.text = '';
194
+                });
195
+            };
196
+            appendForm();
197
+            var itemButton = findChildObject(this, 'newForm');
198
+            itemButton.clicked.connect(function() {
199
+                appendForm();
200
+            });
201
+            var invoiceField = findChildObject(this, 'invoice');
202
+            var vendorField = findChildObject(this, 'vendor');
203
+            var feesTable = findChildObject(this, 'fees');
204
+            var submitButton = findChildObject(this, 'submit');
205
+            var dateField = findChildObject(this, 'date');
206
+            submitButton.clicked.connect(function() {
207
+                var query = new QSqlQuery;
208
+                var q = "INSERT INTO invoices VALUES (default, :invoice, :vendor, :date) RETURNING id";
209
+                query.prepare(q);
210
+                query.bind(":invoice", invoiceField.text);
211
+                query.bind(":vendor", vendorField.currentText);
212
+                query.bind(":date", dateField.date);
213
+                query.exec();
214
+                query.next();
215
+                var invoiceNumber = query.value(0);
216
+                for(var i = 0; i < form.elements(); i++)
217
+                {
218
+                    var current = form.elementAt(i);
219
+                    var nameEntry = findChildObject(current, 'name');
220
+                    var quantityEntry = findChildObject(current, 'quantity');
221
+					var unitEntry = findChildObject(current, 'units');
222
+                    var costEntry = findChildObject(current, 'cost');
223
+                    var originEntry = findChildObject(current, 'origin');
224
+                    var decafSelection = findChildObject(current, 'isDecaf');
225
+                    var decafEntry = findChildObject(current, 'decafMethod');
226
+                    if(nameEntry.currentText == '')
227
+                    {
228
+                        continue;
229
+                    }
230
+                    if(quantityEntry.text == '')
231
+                    {
232
+                        continue;
233
+                    }
234
+                    if(costEntry.text == '')
235
+                    {
236
+                        continue;
237
+                    }
238
+                    if(originEntry.currentText == '')
239
+                    {
240
+                        continue;
241
+                    }
242
+                    if(decafSelection.checked)
243
+                    {
244
+                        if(decafEntry.currentText == '')
245
+                        {
246
+                            continue;
247
+                        }
248
+                    }
249
+                    if(decafSelection.checked)
250
+                    {
251
+                        q = "INSERT INTO decaf_coffees VALUES (default, :name, :reference, :unit, 0, 'Coffee: Unroasted', :origin, :region, :producer, :grade, :milling, :drying, :decafMethod) RETURNING id";
252
+                    }
253
+                    else
254
+                    {
255
+                        q = "INSERT INTO coffees VALUES (default, :name, :reference, :unit, 0, 'Coffee: Unroasted', :origin, :region, :producer, :grade, :milling, :drying) RETURNING id";
256
+                    }
257
+                    query.prepare(q);
258
+                    query.bind(":name", nameEntry.currentText);
259
+                    var referenceEntry = findChildObject(current, 'reference');
260
+                    if(referenceEntry.currentText == '')
261
+                    {
262
+                        query.bind(":reference", null);
263
+                    }
264
+                    else
265
+                    {
266
+                        query.bind(":reference", referenceEntry.currentText);
267
+                    }
268
+					query.bind(":unit", 'lb');
269
+                    query.bind(":origin", originEntry.currentText);
270
+                    var regionEntry = findChildObject(current, 'region');
271
+                    if(regionEntry.currentText == '')
272
+                    {
273
+                        query.bind(":region", null);
274
+                    }
275
+                    else
276
+                    {
277
+                        query.bind(":region", regionEntry.currentText);
278
+                    }
279
+                    var producerEntry = findChildObject(current, 'producer');
280
+                    if(producerEntry.currentText == '')
281
+                    {
282
+                        query.bind(":producer", null);
283
+                    }
284
+                    else
285
+                    {
286
+                        query.bind(":producer", producerEntry.currentText);
287
+                    }
288
+                    var gradeEntry = findChildObject(current, 'grade');
289
+                    if(gradeEntry.currentText == '')
290
+                    {
291
+                        query.bind(":grade", null);
292
+                    }
293
+                    else
294
+                    {
295
+                        query.bind(":grade", gradeEntry.currentText);
296
+                    }
297
+                    var millingEntry = findChildObject(current, 'milling');
298
+                    if(millingEntry.currentText == '')
299
+                    {
300
+                        query.bind(":milling", null);
301
+                    }
302
+                    else
303
+                    {
304
+                        query.bind(":milling", millingEntry.currentText);
305
+                    }
306
+                    var dryingEntry = findChildObject(current, 'drying');
307
+                    if(dryingEntry.currentText == '')
308
+                    {
309
+                        query.bind(":drying", null);
310
+                    }
311
+                    else
312
+                    {
313
+                        query.bind(":drying", dryingEntry.currentText);
314
+                    }
315
+                    if(decafSelection.checked)
316
+                    {
317
+                        query.bind(":decafMethod", decafEntry.currentText);
318
+                    }
319
+                    query.exec();
320
+                    query.next();
321
+                    var item_id = query.value(0);
322
+                    q = "INSERT INTO purchase VALUES(:time, :item, :quantity, :cost, :vendor)";
323
+                    query.prepare(q);
324
+                    query.bind(":time", dateField.date);
325
+                    query.bind(":item", item_id);
326
+                    query.bind(":quantity", convertToPounds(parseFloat(quantityEntry.text), unitEntry.currentText));
327
+                    var costModifier = findChildObject(current, 'costModifier');
328
+                    if(costModifier.currentText == 'per unit')
329
+                    {
330
+                        query.bind(":cost", convertToPerPounds(parseFloat(costEntry.text), unitEntry.currentText));
331
+                    }
332
+                    else
333
+                    {
334
+                        query.bind(":cost", Number(costEntry.text) / convertToPounds(parseFloat(quantityEntry.text), unitEntry.currentText));
335
+                    }
336
+                    query.bind(":vendor", vendorField.currentText);
337
+                    query.exec();
338
+                    q = "INSERT INTO lb_bag_conversion VALUES(:item, :conversion)";
339
+                    query.prepare(q);
340
+                    query.bind(":item", item_id);
341
+                    var bagsEntry = findChildObject(current, 'bags');
342
+                    var conversion = convertToPounds(parseFloat(quantityEntry.text), unitEntry.currentText) / Number(bagsEntry.text);
343
+                    query.bind(":conversion", conversion);
344
+                    query.exec();
345
+                    q = "INSERT INTO invoice_items VALUES(:id, 'PURCHASE', :item, :description, :cost)";
346
+                    query.prepare(q);
347
+                    query.bind(":id", invoiceNumber);
348
+                    query.bind(":item", item_id);
349
+                    query.bind(":description", nameEntry.currentText);
350
+                    if(costModifier.currentText == 'per unit')
351
+                    {
352
+                        query.bind(":cost", Number(costEntry.text) * Number(quantityEntry.text));
353
+                    }
354
+                    else
355
+                    {
356
+                        query.bind(":cost", Number(costEntry.text));
357
+                    }
358
+                    query.exec();
359
+                    var certifications = findChildObject(current, 'certdisplay');
360
+                    var certlist = certifications.text.split(",");
361
+                    q = "INSERT INTO certifications VALUES (:item, :certification)";
362
+                    query.prepare(q);
363
+                    query.bind(":item", item_id);
364
+                    for(var j = 0; j < certlist.length; j++)
365
+                    {
366
+                        query.bind(":certification", certlist[j]);
367
+                        query.exec();
368
+                    }
369
+                }
370
+                var descriptionArray = sqlToArray(feesTable.columnArray(0, 0));
371
+                var q = "INSERT INTO invoice_items VALUES (:id, 'FEE', NULL, :description, :cost)";
372
+                query.prepare(q);
373
+                query.bind(":id", invoiceNumber);
374
+                if(descriptionArray.length > 0)
375
+                {
376
+                    for(var i = 0; i < descriptionArray.length; i++)
377
+                    {
378
+                        if(feesTable.data(i, 0, 0).value == '')
379
+                        {
380
+                            continue;
381
+                        }
382
+                        if(feesTable.data(i, 1, 0).value == '')
383
+                        {
384
+                            continue;
385
+                        }
386
+                        query.bind(":description", feesTable.data(i, 0, 0).value);
387
+                        query.bind(":cost", Number(feesTable.data(i, 1, 0).value));
388
+                        query.exec();
389
+                    }
390
+                }
391
+                window.close();
392
+            });
393
+            this.showMaximized();
394
+        ]]>
395
+    </program>
396
+</window>

+ 83
- 0
config/Windows/roastmanager.xml View File

@@ -0,0 +1,83 @@
1
+<window id="newroasted">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>New Roasted Coffee:</label>
5
+            <line id="name" />
6
+            <button id="ok" type="push" name="Add New Coffee" />
7
+        </layout>
8
+        <layout type="horizontal">
9
+            <layout type="vertical">
10
+                <label>Current Items:</label>
11
+                <sqldrop data="0" display="1" showdata="false" id="currentitems">
12
+                    <query>SELECT id, name FROM items WHERE id IN (SELECT item FROM current_items) ORDER BY name</query>
13
+                </sqldrop>
14
+                <button id="remove" type="push" name="Remove Item" />
15
+            </layout>
16
+            <layout type="vertical">
17
+                <label>Discontinued Items:</label>
18
+                <sqldrop data="0" display="1" showdata="false" id="pastitems">
19
+                    <query>SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id NOT IN (SELECT item FROM current_items) ORDER BY name</query>
20
+                </sqldrop>
21
+                <button id="restore" type="push" name="Restore Item" />
22
+            </layout>
23
+        </layout>
24
+    </layout>
25
+    <program>
26
+        <![CDATA[
27
+            this.displayStatus("Ready.");
28
+            var itemname = findChildObject(this, 'name');
29
+            var newItemButton = findChildObject(this, 'ok');
30
+            var window = this;
31
+            var drop1 = findChildObject(this, 'currentitems');
32
+            var drop2 = findChildObject(this, 'pastitems');
33
+            var removeButton = findChildObject(this, 'remove');
34
+            var restoreButton = findChildObject(this, 'restore');
35
+            removeButton.clicked.connect(function() {
36
+                var q = "DELETE FROM current_items WHERE item = :id";
37
+                query = new QSqlQuery();
38
+                query.prepare(q);
39
+                query.bind(":id", drop1.currentData());
40
+                query.exec();
41
+                query = query.invalidate();
42
+                drop1.clear();
43
+                drop2.clear();
44
+                drop1.addSqlOptions("SELECT id, name FROM items WHERE id IN (SELECT item FROM current_items) ORDER BY name");
45
+                drop2.addSqlOptions("SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id NOT IN (SELECT item FROM current_items) ORDER BY name");
46
+                window.displayStatus("Item removed.");
47
+            });
48
+            restoreButton.clicked.connect(function() {
49
+                var q = "INSERT INTO current_items VALUES (:id)";
50
+                query = new QSqlQuery();
51
+                query.prepare(q);
52
+                query.bind(":id", drop2.currentData());
53
+                query.exec();
54
+                query = query.invalidate();
55
+                drop1.clear();
56
+                drop2.clear();
57
+                drop1.addSqlOptions("SELECT id, name FROM items WHERE id IN (SELECT item FROM current_items) ORDER BY name");
58
+                drop2.addSqlOptions("SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id NOT IN (SELECT item FROM current_items) ORDER BY name");
59
+                window.displayStatus("Item restored.");
60
+            });
61
+            newItemButton.clicked.connect(function() {
62
+                var q = "INSERT INTO items VALUES (default, :name, NULL, 'lb', 0, 'Coffee: Roasted') RETURNING id";
63
+                query = new QSqlQuery();
64
+                query.prepare(q);
65
+                query.bind(":name", itemname.text);
66
+                query.exec();
67
+                query.next();
68
+                var i = query.value(0);
69
+                q = "INSERT INTO current_items VALUES(:id)";
70
+                query.prepare(q);
71
+                query.bind(":id", i);
72
+                query.exec();
73
+                query = query.invalidate();
74
+                itemname.text = "";
75
+                drop1.clear();
76
+                drop2.clear();
77
+                drop1.addSqlOptions("SELECT id, name FROM items WHERE id IN (SELECT item FROM current_items) ORDER BY name");
78
+                drop2.addSqlOptions("SELECT id, name FROM items WHERE category = 'Coffee: Roasted' AND id NOT IN (SELECT item FROM current_items) ORDER BY name");
79
+                window.displayStatus("Item added.");
80
+            });
81
+        ]]>
82
+    </program>
83
+</window>

+ 30
- 0
config/Windows/setsampleparameters.xml View File

@@ -0,0 +1,30 @@
1
+<window id="sampleParameters">
2
+    <layout type="vertical">
3
+        <layout type="horizontal">
4
+            <label>Annotation:</label>
5
+            <line id="template">Sample %1</line>
6
+        </layout>
7
+        <textarea id="instructions" />
8
+        <button name="Reset Sample Number" type="push" id="reset" />
9
+        <button name="Okay" type="push" id="ok" />
10
+    </layout>
11
+    <program>
12
+        <![CDATA[
13
+        print("Program loaded");
14
+        var window = this;
15
+        var instructions = findChildObject(this, 'instructions');
16
+        instructions.plainText = "%1 will be replaced with a sample number.";
17
+        instructions.readOnly = true;
18
+        var reset = findChildObject(this, 'reset');
19
+        reset.clicked.connect(function() {
20
+            window.button.resetCount();
21
+        });
22
+        var okay = findChildObject(this, 'ok');
23
+        var template = findChildObject(this, 'template');
24
+        okay.clicked.connect(function() {
25
+            window.button.setAnnotation(template.text);
26
+            window.close();
27
+        });
28
+        ]]>
29
+    </program>
30
+<window>

+ 10
- 0
config/Windows/success.xml View File

@@ -0,0 +1,10 @@
1
+<window id="success">
2
+    <layout type="vertical">
3
+        <label>Success</label>
4
+        <button type="push" id="ok" name="Okay" />
5
+    </layout>
6
+    <program>
7
+        var button = findChildObject(this, 'ok');
8
+        button.clicked.connect(this.close);
9
+    </program>
10
+</window>

+ 44
- 0
config/config.xml View File

@@ -0,0 +1,44 @@
1
+<application>
2
+    <include src="Windows/print.xml" />
3
+    <include src="Windows/export.xml" />
4
+    <include src="Windows/setsampleparameters.xml" />
5
+    <include src="Windows/productionroaster.xml" />
6
+    <include src="Windows/newbatch.xml" />
7
+    <include src="Windows/importprofiles.xml" />
8
+    <include src="Windows/navigation.xml" />
9
+    <include src="Windows/success.xml" />
10
+    <include src="Windows/roastmanager.xml" />
11
+    <include src="Windows/history.xml" />
12
+    <include src="Windows/greeninventory.xml" />
13
+    <include src="Windows/newroaster.xml" />
14
+    <include src="Windows/batchdetailsnew.xml" />
15
+    <include src="Windows/offline.xml" />
16
+    <include src="Windows/cuppingsession.xml" />
17
+    <include src="Windows/cuppingitemselection.xml" />
18
+    <include src="Windows/cuppingsampleselection.xml" />
19
+    <include src="Windows/cuppingsamplepoints.xml" />
20
+    <include src="Windows/cuppingsessionlist.xml" />
21
+    <include src="Windows/cuppingform.xml" />
22
+    <include src="Windows/cuppingformsbysession.xml" />
23
+    <include src="Windows/cuppingsessionsummary.xml" />
24
+    <include src="Windows/cuppingsummary.xml" />
25
+    <include src="Windows/purchase.xml" />
26
+	<include src="Windows/invoicelist.xml" />
27
+	<include src="Windows/invoiceinfo.xml" />
28
+	<include src="Windows/editinvoice.xml" />
29
+	<include src="Windows/editinvoiceitem.xml" />
30
+	<include src="Windows/editfee.xml" />
31
+	<include src="Windows/optime.xml" />
32
+	<include src="Windows/greensales.xml" />
33
+	<program>
34
+		var loggingWindow;
35
+		var currentBatchInfo;
36
+		var navwindow = createWindow("navwindow");
37
+		var aadapt;
38
+		var badapt;
39
+		var azero;
40
+		var bzero;
41
+		navwindow.windowTitle = "Typica - Choose Your Path";
42
+	</program>
43
+</application>
44
+		

+ 41
- 0
src/3rdparty/qextserialport/.hgignore View File

@@ -0,0 +1,41 @@
1
+syntax: glob
2
+*.pro.user*
3
+*.app
4
+*.moc
5
+Makefile*
6
+doc/html/
7
+debug/
8
+release/
9
+qtc-gdbmacros/
10
+*.rej
11
+*.orig
12
+*.obj
13
+*.swp
14
+*.dll
15
+*.exp
16
+*.ilk
17
+*.pdb
18
+*.lib
19
+moc_*.cpp
20
+qrc_*.cpp
21
+*.o
22
+*.so.*
23
+*.so
24
+*.pdb
25
+ui_*.h
26
+*~
27
+.qmake.cache
28
+lib/*
29
+*.orig
30
+*.exe
31
+*.vcproj
32
+*.vcproj.*.user
33
+*.sln
34
+*.idb
35
+*.ncb
36
+*.suo
37
+examples/enumerator/enumerator
38
+examples/event/event
39
+examples/qespta/qespta
40
+examples/uartassistant/uartassistant
41
+object_script.*

+ 4
- 0
src/3rdparty/qextserialport/.hgtags View File

@@ -0,0 +1,4 @@
1
+96e3a424c22cda7bd430736ffe8ec94c02e9d462 REL_0_9
2
+ecdbd5f836603c25941f6ea7659b271767088cb8 REL_1_1
3
+f5c8064caf35b35778bd191a2d8aed9e7b1260f4 REL_0_8
4
+4a0173d282232b56c55962e17aa254917c52c4c0 1.2-beta1

+ 251
- 0
src/3rdparty/qextserialport/ChangeLog View File

@@ -0,0 +1,251 @@
1
+Change history for QextSerialPort (formerly QwSerialPort):
2
+(Lines beginning with + represent new functionality, * represent changed or
3
+fixed functionality, - represent removed or deprecated functionality)
4
+
5
+Version 1.2 beta1 (2012 Debao Zhang)
6
+  * D-pointer and Q_PRIVATE_SLOT are used to moving private members from QextSerialPort to QextSerialPortPrivate
7
+  * qdoc3 instead of doxygen is used for generating documents
8
+  * MIT license header add to all sources files
9
+  + add a helper class QextWinEventNotifier for windows user, when user's SDK doesnot contain Qt's private files, this class will be auto selected.
10
+  + Support platform custom baudrate. Macros such as B230400 / B460800 can be used directly if you OS support it. 
11
+
12
+Version 1.2win-alpha (2007 Michal Policht)
13
+  + Added QextSerialEnumerator pre-alpha. Works under W2k and later versions of Windows.
14
+  + Event driven mechanism (alternative to polling) is now available on Windows.
15
+  - Removed default (=0) parameter from open() functions.
16
+  * Fixed bug #1714917 in Win_QextSerialPort::close() method (by Kurt).
17
+  * Fixed problem with lack of proper blocking in readData() on win32 (by Brandon Fosdick).
18
+  * Removed QT_THREAD_SUPPORT option. Now QextSerialPort must be always compiled with threads support.
19
+  * Mutexes are not static.
20
+  * setTimeout() now accepts only one parameter.
21
+  * bytesAvailable() on POSIX now shows 0 bytes instead of -1 when no bytes are available.
22
+  * bytesAvailable() is const.
23
+  * native POSIX file descriptors instead of QFile->handle() calls
24
+  + POSIX: Save and restore original termios when opening and closing the device
25
+  * POSIX: Only disable special characters on systems that support it
26
+  * POSIX: Use cfmakeraw(3) to get a non-canonical termios
27
+  + POSIX: Call close(2) in close() to actually close the device
28
+
29
+Version 1.1 (official release)
30
+
31
+Version 1.0.1
32
+  * Minor changes (mostly in test application)
33
+
34
+Version 1.0.0e (by Micha? Policht)
35
+  * Fixed bytesAvailable(). Includes buffered bytes to the result.
36
+  + Added isSequential() method.
37
+  + Provided test application
38
+
39
+Version 1.0.0d ( changes by Micha? Policht )
40
+  - Removed isOpen() overriden declaration/implementation from qextserialport's classes. isOpen() relies on QIODevice now.
41
+  - Removed bool portOpen variable. Replaced by internal QIODevice.openMode.
42
+  - Removed getChar(), putChar() overriden declaration/implementation. QIODevice can handle this.
43
+  * Calling open() with specified OpenMode invokes QIODevice::open() which result in proper openMode setting.
44
+  * readData(), writeData() are protected as in QIODevice declaration.
45
+  * QIODevice:: read() and write() function are working now (use them instead of readData() writeData()).
46
+  * readData(), writeData() don't check if port is open any more (read() and write() assures that). The same behaviour can be found in QFile for example.
47
+  * Fixed readLine().
48
+
49
+  * Fixed randomly crash on deletion bug on Windows ( by Stuart Nixon )
50
+  http://lists.trolltech.com/qt-interest/2007-02/thread00340-0.html#msg00351
51
+
52
+Version 0.9 (March 3, 2005) Stefan Sander <stefan-sander@users.sf.net>:
53
+  + Added a new precompiler constant, _TTY_FREEBSD_
54
+    to support FreeBSD port names.
55
+  + Added _TTY_WIN_ constant in qextserialport.pro win32:DEFINES
56
+    to have Windows port names as default when compiling on it.
57
+  - Removed construct() call from QextSerialBase constructors,
58
+    it is called indirectly through Win_QextSerialPort::construct()
59
+    and Posix_QextSerialPort::construct().
60
+  + Added construct() call to Win_QextSerialPort constructors.
61
+  + Added setTimeout(0, 500) call to Win_QextSerialPort::construct().
62
+  - Removed setTimeout(0, 500) call from Win_QextSerialPort(const char* name).
63
+  * Fixed Posix_QextSerialPort::open(int) control flow, now the port settings
64
+    are only applied if the associated file could be opened.
65
+  * Fixed masking CR to NL, in Posix_CommConfig.c_iflag 
66
+
67
+Version 0.8 (, 2003) (Alpha release):
68
+  * Added code to set the port timeouts in Win_QextSerialPort's default 
69
+    constructor.
70
+  * Fixed Posix_QextSerialPort::construct() to set up the port correctly.
71
+  * Fixed syntax errors in 2 ioctl() calls in posix_QextSerialPort.
72
+  * lastError is now initialized to E_NO_ERROR in the QextSerialBase 
73
+    constructor.    
74
+  * The select() call in posix_QextSerialPort::bytesWaiting() is now 
75
+    properly coded.  Previously it would always time out.
76
+  * Fixed runtime errors in the ioctl() calls for 
77
+    Posix_QextSerialPort::setDtr() and Posix_QextSerialPort::setRts().
78
+    Thanks to Marc Pignat.
79
+    
80
+Version 0.7 (June 15, 2002) <Bugfix release>:
81
+  (0.61 - unofficial release)
82
+  * Fixed a small bug in the initializations of the static members when 
83
+    QT_THREAD_SUPPORT was defined.
84
+  * Fixed a  bug that caused Borland's compiler to choke on Windows platforms
85
+    (which perversely actually stemmed from a shortcoming of Visual C++ that 
86
+    Borland doesn't have).
87
+    
88
+  (0.62 - unofficial release)
89
+  * Fixed a bug that gave Q_LONG the wrong typedef for QT versions prior to 
90
+    3.0. 
91
+    
92
+  (0.63 - unofficial release)       
93
+  * Fixed 2 incorrect references to Posix_Comm_Config.
94
+  * Fixed scoping of Posix_QextSerialPort::operator=().
95
+  * Posix_QextSerialPort::construct should now be coded correctly.
96
+  * Fixed return type for Posix_QextSerialPort::size().
97
+  
98
+  (0.64 - unofficial release)
99
+  * Fixed all the port settings functions to work properly when opening the 
100
+    port for the first time - previously none of the settings were being 
101
+    applied when the port was opened.
102
+  * Fixed an oversight in Win_QextSerialPort::open() that caused the setting
103
+    of port parameters to fail on NT and 2000 systems.
104
+    
105
+  (0.7 - official release)
106
+  * Fixed some calls to QextSerialBase constructors that no longer exist on 
107
+    the POSIX side.
108
+  * Fixed the bad memcpy()'s in the POSIX copy constructor.
109
+  * Fixed the Offset scoping problem under gcc 2.95.
110
+  * The CBAUD flag has been deprecated on some POSIX systems.  Fixed 
111
+    Posix_QextSerialPort::setBaudRate() to reflect this.
112
+  * Added construct() calls to all of the Posix_QextSerialPort constructors.
113
+  * Fixed double (and conflicting) typedefs of Offset when using QT versions 
114
+    prior to 3.0
115
+  * Changed the call to CreateFile() to CreateFileA() in 
116
+    Win_QextSerialPort.cpp.  This should get rid of problems for those using
117
+    Unicode or other multibyte character sets for their string literals.
118
+  * A few tweaks to the documentation.
119
+    
120
+  - Removed the protected Posix_Handle variable from Posix_QextSerialPort.
121
+  
122
+Version 0.6 (March 11, 2002) <Bugfix release>:
123
+  + Added a new precompiler constant, QTVER_PRE_30.  QT3 changed the return
124
+    types of some QIODevice functions. Therefore, if compiling on versions
125
+    of QT prior to 3.0, you should always define QTVER_PRE_30 in your project.
126
+    Also had to add some preprocessor blocks to support both 3.0 and earlier 
127
+    versions of QT.
128
+  + Added implementations of 2 of the new constructors added in 0.5 to both 
129
+    Win_QextSerialPort and Posix_QextSerialPort.
130
+
131
+  * The scoping of the enums used in the PortSettings struct has been fixed.
132
+  * QObject inheritance has been removed.  This should not affect the 
133
+    functionality of the classes.
134
+  * Replaced a few stray references to mutex->unlock() with UNLOCK_MUTEX() in 
135
+    the Windows code.
136
+  * Fixed several runtime errors caused by calling nonexistent members of 
137
+    QextSerialBase.
138
+  * Fixed a whole bunch of little things that were causing MSVC to choke when
139
+    compiling for Windows.
140
+
141
+Version 0.5 (February 15, 2002):
142
+  + There are 4 new macros (LOCK_MUTEX, UNLOCK_MUTEX, TTY_WARNING, and 
143
+    TTY_PORTABILITY_WARNING) that replace most of those ugly #ifdef blocks in
144
+    the code.  
145
+  + In place of the old namingConvention stuff, there is a new function, 
146
+    setName().  It is used to set the name of the device to be associated with
147
+    the object.  The new name() function can be used to retrieve the device 
148
+    name, which is stored in the new member variable portName.
149
+  + There is a new version of open() that takes a const char* as a parameter.
150
+    It can be used to specify the name of the device when it is opened rather
151
+    than at construction time.
152
+
153
+  * 3 constructors have been removed and 3 more added.  There is now a copy
154
+    constructor (and operator=()) as well as a constructor that takes a
155
+    PortSettings structure as a parameter, and another that takes both a
156
+    device name and a PortSettings structure.  As a result of these changes
157
+    the PortSettings structure declaration is no longer local to the
158
+    QextSerialBase class.  All of the removed constructors had to do with
159
+    the setNamingConvention() system.
160
+  * The static mutex member should now be reference-counted and only deleted 
161
+    when it is no longer referenced.  
162
+  * Most of the object construction duties have been pushed back into
163
+    QextSerialBase
164
+  * Fixed a couple resource leaks, mostly to do with unlocking the mutex
165
+    properly
166
+
167
+  - Removed the setNamingConvention() nonsense.  
168
+  - Removed all QStrings and calls to sprintf() for thread compatibility.
169
+  - Removed setNumber() functions as well as the portNumber member variable,
170
+    as they were only necessary under the setNamingConvention() system.
171
+
172
+  I am grateful to Jorg Preiss (Preisz?  Sorry, American keyboards don't have
173
+  an ess-tset character ;)) for his invaluable input on most of the changes
174
+  that went into this version.
175
+
176
+Version 0.4 (March 20, 2001):
177
+  + All of the classes now derive from QObject as well as QIODevice.  This
178
+    is pretty much useless at the moment - signals and slots may be used
179
+    to implement asynchronous communications in a future version
180
+  + Added configurable timeouts via the setTimeout() function.  The default
181
+    timeout for read and write operations is now 500 milliseconds
182
+  + There is now a functional .pro file for the library (thanks to
183
+    Gunnstein Lye)
184
+  + The prefixes for all of the classes have changed from Qw to Qext, in
185
+    compliance with the qt-addons project standard
186
+
187
+  * Fixed a bug that caused port settings to be restored incorrectly when
188
+    switching ports with setNumber()
189
+  * Minor changes to QextSerialBase::setNumber().  Functionality should now
190
+    reflect the documentation, which has also been updated to reflect the
191
+    changes that went in on version 0.3.
192
+  * Some fixes to the documentation.  The Posix_QextSerialPort and
193
+    Win_QextSerialPort classes should no longer have any unnecessary
194
+    references to inapplicable platforms, and the documentation for open() has
195
+    been updated.
196
+  * Should now compile without QT_THREAD_SUPPORT defined (ie, in single-
197
+    threaded environments), although it will require slight changes to the
198
+    makefile (tmake "CONFIG-=thread" should work)
199
+  * Fixed a few compilation issues, especially on the POSIX side (should
200
+    compile under Linux now :))
201
+  * POSIX code is a little cleaner and more efficient
202
+  * Various small fixes to the documentation
203
+  * Constants now follow a consistent naming convention, with underscores at
204
+    the beginning and end of each.  For example TTY_POSIX has become
205
+    _TTY_POSIX_
206
+    
207
+Version 0.3 (Feb. 14, 2001):
208
+  + Added a warning that appears when QwSerialPort is compiled on a POSIX
209
+    platform that does not implement 76800 baud operation.  In this situation
210
+    QwSerialPort will also switch to 57600 baud.
211
+  + Major code reorganization - there are now 4 classes instead of 1.  This
212
+    should remove a lot of the #ifdef...#else...#endif constructs and
213
+    hopefully make the code easier to read.  Including the class in your
214
+    project is still done by including QwSerialPort.h and instantiating a
215
+    QwSerialPort object.
216
+
217
+  * The serial port associated with a QwSerialPort object is no longer
218
+    opened on construction, or upon calling the setNumber() function.  You
219
+    must now explicitly call open() to open the port.
220
+
221
+Version 0.2 (Jan. 3, 2001):
222
+  + Added lastError() function with rudimentary error codes
223
+  + Better documentation
224
+  + Added ability to examine the empty/not empty state of a port's input
225
+    buffer with atEnd()
226
+  + Added ability to retrieve the number of bytes in a port's input buffer
227
+    with size() (thanks to Olivier Tubach)
228
+  + Added ability to turn off portability warnings by defining
229
+    TTY_NOWARN_PORT in your project
230
+  + Added ability to turn off all warning messages by defining TTY_NOWARN
231
+    in your project
232
+  + Added ability to select POSIX serial functions in Windows NT/2000 by
233
+    defining TTY_POSIX in your project (untested)
234
+  + Added control over RTS and DTR lines with setRts() and setDtr()
235
+    respectively
236
+  + Added ability to query line status using lineStatus().
237
+  + Added readLine() functionality (thanks to Olivier Tubach)
238
+  + Added bytesWaiting(), a non-const/thread-safe version of size()
239
+  + The class should now be thread-safe through the use of a recursive
240
+    QMutex (untested)
241
+
242
+  * Fixed a bug that could cause hardware flow control not to work on some
243
+    POSIX systems
244
+  * Put in a few missing fileno() calls in the POSIX code
245
+  * Fixed a few syntax errors that caused compilation to fail on POSIX systems
246
+
247
+  - BAUD0 is no longer a valid baud rate setting - to drop the DTR line,
248
+    call setDtr(FALSE)
249
+
250
+Version 0.1 (Dec. 11, 2000):
251
+  Initial public release.

+ 88
- 0
src/3rdparty/qextserialport/LICENSE View File

@@ -0,0 +1,88 @@
1
+From QextSerialPort 1.2-beta on, we use MIT license for QextSerialPort project.
2
+
3
+== License ==
4
+
5
+    Copyright (c) 2000-2003 Wayne Roth
6
+    Copyright (c) 2004-2007 Stefan Sander
7
+    Copyright (c) 2007 Michal Policht
8
+    Copyright (c) 2008 Brandon Fosdick
9
+    Copyright (c) 2009-2010 Liam Staskawicz
10
+    Copyright (c) 2011 Debao Zhang
11
+    
12
+    Web: http://code.google.com/p/qextserialport/
13
+    
14
+    Permission is hereby granted, free of charge, to any person obtaining
15
+    a copy of this software and associated documentation files (the
16
+    "Software"), to deal in the Software without restriction, including
17
+    without limitation the rights to use, copy, modify, merge, publish,
18
+    distribute, sublicense, and/or sell copies of the Software, and to
19
+    permit persons to whom the Software is furnished to do so, subject to
20
+    the following conditions:
21
+    
22
+    The above copyright notice and this permission notice shall be
23
+    included in all copies or substantial portions of the Software.
24
+    
25
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29
+    LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30
+    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
+
33
+== Why license needed? ==
34
+
35
+ Many users complains that, without a proper licence they can not use this library.
36
+
37
+ * http://groups.google.com/group/qextserialport/browse_thread/thread/0e8756920b01da82
38
+
39
+    Hi, 
40
+    we are considering using a modified version of QExtSerialPort in one of our 
41
+    projects (Qt Creator, http://qt.gitorious.org/qt-creator). 
42
+    Would it be possible to add license header information or a license file to the   
43
+    QExtSerialPort code base? - This would make re-use of the code base easier. 
44
+    If that is not  possible, could we redistribute the source code with BSD- 
45
+    license headers manually added? 
46
+
47
+And
48
+
49
+    I am also considering packaging the software for Debian, but I 
50
+    couldn't do it yet just because of the license. 
51
+
52
+ * http://code.google.com/p/qextserialport/issues/detail?id=8
53
+
54
+    Questions:
55
+    Can I use qextserialport in a commercial product?
56
+    If yes, how?
57
+    Compile it in? I guess no.
58
+    If I can use it as a library, how should the README be formulated?
59
+    Is the "MIT license" from 2008 appropriate?
60
+
61
+== Why can we use MIT? ==
62
+
63
+Form the history of [http://lists.trolltech.com/qt-interest/2004-12/msg01022.html qt-interest mail list]
64
+
65
+ * Wayne Roth, the original author of the project, had said that:
66
+
67
+    the code is in the public domain. Do whatever you like with it. Right 
68
+    now I have too many other things to do to put any serious time into
69
+    fixing it.  Trolltech should be aware of this already; they asked 
70
+    about a license when they offered to host the tarball.
71
+
72
+ * Stefan Sander, the maintainer of qextserialport on sourceforge, said that
73
+
74
+    Hello,
75
+    My project registration at !SourceForge have been approved.
76
+    http://www.sf.net/projects/qextserialport
77
+    I thought an initial licence of Public Domain would be best solution.
78
+    Someone wrote: - Because its public domain, some could fork it under different licenses -
79
+
80
+And from [http://groups.google.com/group/qextserialport/browse_thread/thread/fbcddbfb4a0b5a51?pli=1 this thread] on qesp mail list, we can see that, current maintainers and users agree with a MIT licence.
81
+
82
+ * Brandon Fosdick,
83
+
84
+    I would vote for BSD or MIT :) 
85
+
86
+ * Liam Staskawicz,
87
+
88
+    That works for me - let's call it MIT and go for it :) 

+ 131
- 0
src/3rdparty/qextserialport/README View File

@@ -0,0 +1,131 @@
1
+= About QextSerialPort =
2
+
3
+QextSerialPort provides an interface to old fashioned serial ports for Qt-based applications. It currently supports Mac OS X, Windows, Linux, FreeBSD. 
4
+
5
+    http://code.google.com/p/qextserialport/
6
+
7
+== How to use (1) ==
8
+
9
+ * Download the source code.
10
+
11
+ * Put the source code in any directory you like. For example, 3rdparty:
12
+
13
+            |-- project.pro
14
+            |-- ....
15
+            |-- 3rdparty\
16
+            |     |-- qextserialport\
17
+            |     |
18
+
19
+ * Add following line to your qmake project file:
20
+
21
+            include(3rdparty/qextserialport/src/qextserialport.pri)
22
+
23
+ * Using QextSerialPort in your code. Enjoy it!
24
+
25
+            #include "qextserialport.h"
26
+            ....
27
+            QextSerialPort * port = new QextSerialPort();
28
+            ....
29
+            
30
+== How to use (2) ==
31
+
32
+It's very easy to compile QextSerialPort directly into your application
33
+(see above section), however, we would prefer to use it as a static or
34
+ shared library.
35
+
36
+ * Download the source code, and put it in any location you like.
37
+
38
+           |-- yourpath\
39
+           |     |-- qextserialport\
40
+           |     |
41
+
42
+ * Create a config.pri file, and put into qextserialport's directory.
43
+
44
+           |-- yourpath\
45
+           |     |-- qextserialport\
46
+           |     |     |-- config.pri
47
+           
48
+   * Contents of config_example.pri
49
+  
50
+           # uncomment the following line if you want to use qesp as library
51
+           # QEXTSERIALPORT_LIBRARY = yes
52
+
53
+           # uncomment the following line too if you want to use it as static library
54
+           # QEXTSERIALPORT_STATIC = yes
55
+
56
+ * Goto qextserialport/buildlib, and run following command to generate library.
57
+
58
+           qmake
59
+           make (or nmake)
60
+
61
+ * Add following line to your qmake project file. Enjoy it!
62
+
63
+           include(pathToQextserialport/src/qextserialport.pri)
64
+
65
+== How to use (3) ==
66
+
67
+Someone complains that, I want to used !QextSerialPort as a shared libaray, but
68
+I don't want to add the {{{include(***.pri)}}} to my project file. Otherwise,
69
+all the source files of !QextSerialPort will be shown in Qt Creator, which is
70
+very annoying.
71
+
72
+Ok, let's go!
73
+
74
+ * Download the source code, and put it in any location you like.
75
+
76
+ * Goto qextserialport/buildlib, and run following command to generate library. (Yes, config.pri is not needed.)
77
+
78
+          qmake
79
+          make (or nmake)
80
+
81
+ * Add following lines to your .pro file. And you need to specify the path to the lib and headers. Then Enjoy it!
82
+
83
+          # Specify lib and headers path if they are not in standard locations.
84
+          # Otherwise, your can ignore this.
85
+          unix{
86
+             QEXTSERIALPORT_LIBDIR = #path_to_qextserialport_lib
87
+             QEXTSERIALPORT_INCDIR = #path_to_qextserialport_headers
88
+          }else{
89
+             QEXTSERIALPORT_LIBDIR = #path_to_qextserialport_lib
90
+             QEXTSERIALPORT_INCDIR = #path_to_qextserialport_headers
91
+          }
92
+
93
+          SAVE_TEMPLATE = $$TEMPLATE
94
+          TEMPLATE = fakelib
95
+          QEXTSERIALPORT_LIBNAME = $$qtLibraryTarget(qextserialport-1.2)
96
+          TEMPLATE = $$SAVE_TEMPLATE
97
+
98
+          INCLUDEPATH += $$QEXTSERIALPORT_INCDIR
99
+          LIBS += -L$$QEXTSERIALPORT_LIBDIR -l$$QEXTSERIALPORT_LIBNAME
100
+          DEFINES += QEXTSERIALPORT_USING_SHARED
101
+
102
+          unix:QMAKE_RPATHDIR += $$QEXTSERIALPORT_LIBDIR
103
+
104
+ * Oh, this file looks a bit complicated, as we need cross-platform. If you don't care cross-platform. It will be very simple :-) , for example
105
+      
106
+          INCLUDEPATH += /home/xxxx/download/qextserialport/src
107
+          LIBS += /home/xxxx/download/qextserialport/lib/libqextsrialport-1.2.so
108
+          DEFINES += QEXTSERIALPORT_USING_SHARED
109
+
110
+ * Note:
111
+  * If you do not want to add such lines to each of your projects. This is another solution too.
112
+  * Create a new file called *extserialport.prf* , then add above lines to this new file.
113
+  * Put this .prf file to one of feature paths, such as
114
+          
115
+          $QTDIR\mkspecs\features\
116
+          
117
+  * Add the following line to your .pro file. Enjoy it!
118
+
119
+          CONFIG += extserialport
120
+
121
+== Build (optional) ==
122
+
123
+ * Run qmake from the toplevel directory.(If your has create a config.pri file properly, this will generate the library, and then all examples will use the library. Otherwise, qextserialport will be directly compiled into the examples)
124
+
125
+           qmake (or qmake -r)
126
+           make (or nmake)
127
+
128
+ * Run qdoc3 from the doc directory.
129
+
130
+           qdoc3 qextserialport.qdocconf
131
+

+ 17
- 0
src/3rdparty/qextserialport/buildlib/buildlib.pro View File

@@ -0,0 +1,17 @@
1
+TEMPLATE=lib
2
+CONFIG += qt qextserialport-buildlib
3
+# Include .pri file before using "qextserialport-static"
4
+# and after CONFIG += "qextserialport-buildlib"
5
+include(../src/qextserialport.pri)
6
+qextserialport-static:CONFIG += static
7
+else:CONFIG += dll
8
+mac:CONFIG += absolute_library_soname
9
+win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release build_all
10
+TARGET = $$QEXTSERIALPORT_LIBNAME
11
+DESTDIR = $$QEXTSERIALPORT_LIBDIR
12
+win32:!qextserialport-static{
13
+    DLLDESTDIR = $$[QT_INSTALL_BINS]
14
+    QMAKE_DISTCLEAN += $$[QT_INSTALL_BINS]\\$${QEXTSERIALPORT_LIBNAME}.dll
15
+}
16
+target.path = $$DESTDIR
17
+INSTALLS += target

+ 17
- 0
src/3rdparty/qextserialport/common.pri View File

@@ -0,0 +1,17 @@
1
+infile(config.pri, QEXTSERIALPORT_LIBRARY, yes): CONFIG += qextserialport-library
2
+qextserialport-library{
3
+    infile(config.pri, QEXTSERIALPORT_STATIC, yes): CONFIG += qextserialport-static
4
+}
5
+# Though maybe you have been fimiliar with "TEMPLATE += fakelib" and "TEMPLATE -= fakelib",
6
+# but it don't work when you using "qmake -tp XXX". So I use another variable Here.
7
+SAVE_TEMPLATE = $$TEMPLATE
8
+TEMPLATE = fakelib
9
+contains(QT_VERSION, ^5\\..*\\..*) {
10
+    #different name for Qt4 and Qt5
11
+    QEXTSERIALPORT_LIBNAME = $$qtLibraryTarget(QtExtSerialPort-1.2)
12
+} else {
13
+    QEXTSERIALPORT_LIBNAME = $$qtLibraryTarget(qextserialport-1.2)
14
+}
15
+TEMPLATE = $$SAVE_TEMPLATE
16
+QEXTSERIALPORT_LIBDIR = $$PWD/lib
17
+unix:qextserialport-library:!qextserialport-buildlib:QMAKE_RPATHDIR += $$QEXTSERIALPORT_LIBDIR

+ 11
- 0
src/3rdparty/qextserialport/config_example.pri View File

@@ -0,0 +1,11 @@
1
+# This is an example config.pri for building and using qextserialport.
2
+# 
3
+# When using the qextserialport, all you need is to add following line
4
+# in your .pro file:
5
+#    include(pathToQextserialport/src/qextserialport.pri)
6
+#
7
+# uncomment the following line if you want to use qextserialport as library
8
+# QEXTSERIALPORT_LIBRARY = yes
9
+
10
+# uncomment the following line too if you want to use it as static library
11
+# QEXTSERIALPORT_STATIC = yes

+ 12
- 0
src/3rdparty/qextserialport/doc/doc.pri View File

@@ -0,0 +1,12 @@
1
+OTHER_FILES += $$PWD/qextserialport.qdocconf
2
+
3
+#name of qdoc3 has been changed to qdoc under Qt5
4
+QESP_QDOC = qdoc
5
+lessThan(QT_MAJOR_VERSION, 5):QESP_QDOC = qdoc3
6
+
7
+docs_target.target = docs
8
+docs_target.commands = $$QESP_QDOC $$PWD/qextserialport.qdocconf
9
+
10
+QMAKE_EXTRA_TARGETS = docs_target
11
+QMAKE_CLEAN += "-r $$PWD/html"
12
+

+ 16
- 0
src/3rdparty/qextserialport/doc/examples/enumerator.qdoc View File

@@ -0,0 +1,16 @@
1
+/*!
2
+    \example examples/enumerator
3
+    \title enumerator Demo
4
+
5
+    The example demonstrates how to use QextSerialEnumerator.
6
+
7
+    Include the proper header file
8
+    \snippet examples/enumerator/main.cpp 0
9
+
10
+    Get available ports in the system.
11
+    \snippet examples/enumerator/main.cpp 1
12
+
13
+    Output
14
+    \snippet examples/enumerator/main.cpp 2
15
+*/
16
+

BIN
src/3rdparty/qextserialport/doc/examples/images/uartassistant.png View File


+ 7
- 0
src/3rdparty/qextserialport/doc/examples/qespta.qdoc View File

@@ -0,0 +1,7 @@
1
+/*!
2
+    \example examples/qespta
3
+    \title qespta Demo
4
+
5
+    The example demonstrates how to use QextSerialPort.
6
+*/
7
+

+ 24
- 0
src/3rdparty/qextserialport/doc/examples/uartassistant.qdoc View File

@@ -0,0 +1,24 @@
1
+/*!
2
+    \example examples/uartassistant
3
+    \title UartAssistant Demo
4
+
5
+    The example demonstrates how to use QextSerialPort.
6
+
7
+    Initialze UI element.
8
+    \snippet examples/uartassistant/dialog.cpp 0
9
+
10
+    Initialize serial port
11
+    \snippet examples/uartassistant/dialog.cpp 1
12
+
13
+    port Settings
14
+    \snippet examples/uartassistant/dialog.cpp 2
15
+
16
+    Open or Close the port.
17
+    \snippet examples/uartassistant/dialog.cpp 3
18
+
19
+    Read from or Write to the port
20
+    \snippet examples/uartassistant/dialog.cpp 4
21
+
22
+    \image uartassistant.png
23
+*/
24
+

+ 127
- 0
src/3rdparty/qextserialport/doc/index.qdoc View File

@@ -0,0 +1,127 @@
1
+/*!
2
+    \page index.html
3
+    \title QextSerialPort Manual
4
+
5
+    \section1 Overview
6
+      QextSerialPort provides an interface to old fashioned serial ports for
7
+      Qt-based applications. It currently supports Mac OS X, Windows, Linux, FreeBSD. 
8
+
9
+      From QextSerialPort 1.2-beta on, license of the project has been changed to MIT.
10
+
11
+      \list
12
+         \o Revision 0.9.x is Qt 2 & 3 compatible.
13
+         \o Revision 1.x.x is Qt 4 compatible.
14
+         \o From revision 1.2beta1 on, Qt 5 support is added.
15
+      \endlist
16
+
17
+        
18
+    \section1 Classes
19
+      \list
20
+      \o \l QextSerialPort encapsulates a serial port on both POSIX and Windows systems.
21
+      \o \l QextSerialEnumerator enumerates ports currently available in the system.
22
+      \endlist
23
+    
24
+    \section1 Getting Started
25
+      The package contains a qextserialport.pri file that allows you to integrate the 
26
+      component into programs that use qmake for the build step.
27
+
28
+      All you need is adding following line to your qmake's project file:
29
+      \code
30
+      include(pathToPri/qextserialport.pri)
31
+      \endcode
32
+
33
+      Then, using QextSerialPort in your code
34
+      \code
35
+      #include "qextserialport.h"
36
+      ... 
37
+      MyClass::MyClass()
38
+      {
39
+          port = new QextSerialPort("COM1");
40
+          connect(port, SIGNAL(readyRead()), this, SLOT(onDataAvailable()));
41
+          port->open();
42
+      }
43
+  
44
+      void MyClass::onDataAvailable()
45
+      {
46
+          QByteArray data = port->readAll();
47
+          processNewData(usbdata);
48
+      }
49
+      \endcode
50
+
51
+    \section2 Using QexSerialPort as library
52
+      Although QextSerialPort can be directly compiled into your application, You may prefer
53
+      to use QextSerailPort as an library, which is very easy too.
54
+
55
+      1. Write a config.pri file.(read config_example.pri for reference):
56
+
57
+      \list
58
+        \o shared library
59
+        \o static library
60
+      \endlist
61
+
62
+      2. Changed to subdirectory 'buildlib', run
63
+      \code
64
+      qmake
65
+      make
66
+      \endcode
67
+      shared or static library will be generated.
68
+
69
+      3.  Add following line to your qmake project file:
70
+      \code
71
+      include(pathToPri/qextserialport.pri)
72
+      \endcode
73
+
74
+     \section2 Build documents
75
+      Run qdoc3 from the doc directory.
76
+      \code
77
+        qdoc3 qextserialport.qdocconf
78
+      \endcode
79
+      Note: qdoc3 has been renamed to qdoc under Qt5.
80
+
81
+    \section1 Examples
82
+      \list
83
+      \o \l examples/enumerator
84
+      \o \l examples/qespta
85
+      \o \l examples/uartassistant
86
+      \endlist
87
+
88
+     \section2 Build examples
89
+      Run following commands at toplevel directory
90
+      \code
91
+      qmake
92
+      make
93
+      \endcode
94
+
95
+      or simply open the qextserialport.pro using Qt Creator.
96
+
97
+    \section1 Resources
98
+        \section2  Nokia(Trolltech)
99
+        \list
100
+          \o  \l {http://doc.trolltech.com/qq/qq12-iodevice.html} {Writing a Custom I/O Device}
101
+          \o  \l {http://doc.trolltech.com/3.3/qiodevice.html} {Qt 3.3: QIODevice Class Reference}
102
+          \o  \l {http://doc.trolltech.com/4.7/qiodevice.html} {Qt 4.7: QIODevice Class Reference}
103
+        \endlist
104
+        \section2  MSDN
105
+        \list
106
+          \o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/communications_resources.asp} {Communications Resources}
107
+           \o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/about_communications_resources.asp} {About Communications Resources}
108
+           \o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/using_communications_resources.asp}{Using Communications Resources}
109
+           \o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/communications_functions.asp} {Communications Functions}
110
+           \o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/communications_structures.asp} {Communications Structures}
111
+        \endlist
112
+        \section2  TLDP
113
+        \list
114
+           \o \l {http://www.tldp.org/HOWTO/Serial-HOWTO.html}{Serial HOWTO}
115
+           \o \l {http://www.tldp.org/HOWTO/Serial-Programming-HOWTO/}{Serial Programming HOWTO}
116
+        \endlist
117
+        \section2  Other
118
+        \list
119
+           \o \l {http://www.easysw.com/~mike/serial/serial.html} {Serial Programming Guide for POSIX Operating Systems}
120
+        \endlist
121
+
122
+*/
123
+
124
+/*!
125
+  \page classes.html
126
+  \generatelist annotatedclasses
127
+*/

+ 53
- 0
src/3rdparty/qextserialport/doc/qextserialport.qdocconf View File

@@ -0,0 +1,53 @@
1
+# Run qdoc3 from the directory that contains this file.
2
+project = qesp
3
+description = QextSerialPort Reference Documentation
4
+url = http://code.google.com/p/qextserialport
5
+
6
+outputencoding = UTF-8
7
+language = Cpp
8
+
9
+#Paths are relative to the location of this file
10
+headerdirs               = . ../src
11
+sourcedirs               = . ../src
12
+exampledirs              = ../examples ..
13
+imagedirs                = ./examples/images images
14
+
15
+Cpp.ignoretokens         = QEXTSERIALPORT_EXPORT 
16
+
17
+indexes = $QTDIR/doc/html/qt.index
18
+
19
+qhp.projects             = qesp
20
+qhp.qesp.file            = qesp.qhp
21
+qhp.qesp.namespace       = com.google.code.qextserialport.120
22
+qhp.qesp.virtualFolder   = qdoc
23
+qhp.qesp.indexTitle      = QextSerialPort Reference Documentation
24
+qhp.qesp.indexRoot       = 
25
+qhp.qesp.extraFiles      = style/style.css
26
+
27
+
28
+#------------------------------------------------------------------
29
+outputdir = html
30
+outputformats = HTML
31
+
32
+headers.fileextensions = "*.h"
33
+sources.fileextensions = "*.cpp *.qdoc"
34
+
35
+HTML.templatedir        = .
36
+HTML.stylesheets        = style/style.css
37
+
38
+HTML.headerstyles       = "  <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n"
39
+HTML.endheader          = "</head>\n"
40
+
41
+HTML.postheader         = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \
42
+                          "<tr>\n" \
43
+                          "<td class=\"postheader\" valign=\"center\">" \
44
+                          "<a href=\"index.html\">Home</a> &middot;" \
45
+                          " <a href=\"classes.html\">All Classes</a> &middot;" \
46
+                          "</td></tr></table>"
47
+
48
+HTML.footer             = "<p /><address><hr /><div align=\"center\">\n" \
49
+                          "<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \
50
+                          "<td width=\"40%\" align=\"left\">Copyright &copy; 2000-2012</td>\n" \
51
+                          "<td width=\"20%\" align=\"center\"><a href=\"http://code.google.com/p/qextserialport\">QextSerialPort Project</a></td>\n" \
52
+                          "<td width=\"40%\" align=\"right\"><div align=\"right\">QextSerialPort Manual</div></td>\n" \
53
+                          "</tr></table></div></address>"

+ 35
- 0
src/3rdparty/qextserialport/doc/readme.txt View File

@@ -0,0 +1,35 @@
1
+Note: 
2
+
3
+  If you are using qextserialport-XXX.tar.gz, the qesp.qch and
4
+  html files have been provided.
5
+
6
+  Open the file "html/index.html" using your web browser.
7
+  Or integrated the "html/qesp.qch" into your QtCreator.
8
+
9
+
10
+== How to generate help files? ==
11
+
12
+Simply run following commands at toplevel directory.
13
+    qmake
14
+    make docs
15
+
16
+Or run the following command at this directory
17
+    qdoc3 qextserialport.qdocconf
18
+
19
+Then a folder called "html" will be generated. 
20
+Open the file "html/index.html" using your web browser.
21
+
22
+== How to integrated into Qt Creator or Qt Assistant? ==
23
+
24
+Once the html files are generated. run following commands
25
+   cd doc/html
26
+   qhelpgenerator qesp.qhp
27
+
28
+A file called "qesp.qch" will be generated.
29
+
30
+For Qt Assistant: 
31
+   Edit ==> Preferences ==>  Documentations ==> Add...
32
+
33
+For Qt Creator
34
+   Tools ==> Options ==> Help ==> Documentations ==> Add...
35
+ 

+ 137
- 0
src/3rdparty/qextserialport/doc/style/style.css View File

@@ -0,0 +1,137 @@
1
+a:link, a:visited {
2
+    color: #00732F;
3
+    text-decoration: none;
4
+    font-weight: bold;
5
+}
6
+
7
+body {
8
+    font: normal 400 14px/1.2 Arial;
9
+    margin-top: 85px;
10
+}
11
+
12
+h1 {
13
+    margin: 0;
14
+}
15
+
16
+h2 {
17
+    font: 500 20px/1.2 Arial;
18
+}
19
+
20
+h3.fn, span.fn {
21
+    -moz-border-radius: 7px 7px 7px 7px;
22
+    -webkit-border-radius: 7px 7px 7px 7px;
23
+    border-radius: 7px 7px 7px 7px;
24
+    background-color: #F6F6F6;
25
+    border-width: 1px;
26
+    border-style: solid;
27
+    border-color: #E6E6E6;
28
+    word-spacing: 3px;
29
+    padding: 3px 5px;
30
+}
31
+
32
+table, pre {
33
+    -moz-border-radius: 7px 7px 7px 7px;
34
+    -webkit-border-radius: 7px 7px 7px 7px;
35
+    border-radius: 7px 7px 7px 7px;
36
+    background-color: #F6F6F6;
37
+    border: 1px solid #E6E6E6;
38
+    border-collapse: separate;
39
+    font-size: 12px;
40
+    line-height: 1.2;
41
+    margin-bottom: 25px;
42
+    margin-left: 15px;
43
+}
44
+
45
+table td {
46
+    padding: 3px 15px 3px 20px;
47
+}
48
+
49
+table tr.even {
50
+    background-color: white;
51
+    color: #66666E;
52
+}
53
+
54
+table tr.odd {
55
+    background-color: #F6F6F6;
56
+    color: #66666E;
57
+}
58
+
59
+li {
60
+    margin-bottom: 10px;
61
+    padding-left: 12px;
62
+}
63
+
64
+.cpp {
65
+    display: block;
66
+    margin: 10;
67
+    overflow: hidden;
68
+    overflow-x: hidden;
69
+    overflow-y: hidden;
70
+    padding: 20px 0 20px 0;
71
+}
72
+
73
+.footer {
74
+    margin-top: 50px;
75
+}
76
+
77
+.memItemLeft {
78
+    padding-right: 3px;
79
+}
80
+
81
+.memItemRight {
82
+    padding: 3px 15px 3px 0;
83
+}
84
+
85
+.qml {
86
+    display: block;
87
+    margin: 10;
88
+    overflow: hidden;
89
+    overflow-x: hidden;
90
+    overflow-y: hidden;
91
+    padding: 20px 0 20px 0;
92
+}
93
+
94
+.qmldefault {
95
+    padding-left: 5px;
96
+    float: right;
97
+    color: red;
98
+}
99
+
100
+.qmlreadonly {
101
+    padding-left: 5px;
102
+    float: right;
103
+    color: #254117;
104
+}
105
+
106
+.rightAlign {
107
+    padding: 3px 5px 3px 10px;
108
+    text-align: right;
109
+}
110
+
111
+.title {
112
+    background-color: white;
113
+    color: #44A51C;
114
+    font-family: Verdana;
115
+    font-size: 35px;
116
+    font-weight: normal;
117
+    left: 0;
118
+    padding-bottom: 5px;
119
+    padding-left: 16px;
120
+    padding-top: 20px;
121
+    position: absolute;
122
+    right: 0;
123
+    top: 0;
124
+}
125
+
126
+.toc {
127
+    float: right;
128
+    -moz-border-radius: 7px 7px 7px 7px;
129
+    -webkit-border-radius: 7px 7px 7px 7px;
130
+    border-radius: 7px 7px 7px 7px;
131
+    background-color: #F6F6F6;
132
+    border: 1px solid #DDD;
133
+    margin: 0 20px 10px 10px;
134
+    padding: 20px 15px 20px 20px;
135
+    height: auto;
136
+    width: 200px;
137
+}

+ 6
- 0
src/3rdparty/qextserialport/examples/enumerator/enumerator.pro View File

@@ -0,0 +1,6 @@
1
+TEMPLATE = app
2
+DEPENDPATH += .
3
+CONFIG += console
4
+include(../../src/qextserialport.pri)
5
+SOURCES += main.cpp
6
+

+ 31
- 0
src/3rdparty/qextserialport/examples/enumerator/main.cpp View File

@@ -0,0 +1,31 @@
1
+/**
2
+ * @file main.cpp
3
+ * @brief Main file.
4
+ * @author Micha? Policht
5
+ */
6
+//! [0]
7
+#include "qextserialenumerator.h"
8
+//! [0]
9
+#include <QtCore/QList>
10
+#include <QtCore/QDebug>
11
+int main()
12
+{
13
+    //! [1]
14
+    QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();
15
+    //! [1]
16
+    qDebug() << "List of ports:";
17
+    //! [2]
18
+    foreach (QextPortInfo info, ports) {
19
+        qDebug() << "port name:"       << info.portName;
20
+        qDebug() << "friendly name:"   << info.friendName;
21
+        qDebug() << "physical name:"   << info.physName;
22
+        qDebug() << "enumerator name:" << info.enumName;
23
+        qDebug() << "vendor ID:"       << info.vendorID;
24
+        qDebug() << "product ID:"      << info.productID;
25
+
26
+        qDebug() << "===================================";
27
+    }
28
+    //! [2]
29
+    return 0;
30
+}
31
+

+ 43
- 0
src/3rdparty/qextserialport/examples/event/PortListener.cpp View File

@@ -0,0 +1,43 @@
1
+
2
+#include "PortListener.h"
3
+#include <QtDebug>
4
+
5
+PortListener::PortListener(const QString & portName)
6
+{
7
+    qDebug() << "hi there";
8
+    this->port = new QextSerialPort(portName, QextSerialPort::EventDriven);
9
+    port->setBaudRate(BAUD9600);
10
+    port->setFlowControl(FLOW_OFF);
11
+    port->setParity(PAR_NONE);
12
+    port->setDataBits(DATA_8);
13
+    port->setStopBits(STOP_2);
14
+
15
+    if (port->open(QIODevice::ReadWrite) == true) {
16
+        connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
17
+        connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
18
+        if (!(port->lineStatus() & LS_DSR))
19
+            qDebug() << "warning: device is not turned on";
20
+        qDebug() << "listening for data on" << port->portName();
21
+    }
22
+    else {
23
+        qDebug() << "device failed to open:" << port->errorString();
24
+    }
25
+}
26
+
27
+void PortListener::onReadyRead()
28
+{
29
+    QByteArray bytes;
30
+    int a = port->bytesAvailable();
31
+    bytes.resize(a);
32
+    port->read(bytes.data(), bytes.size());
33
+    qDebug() << "bytes read:" << bytes.size();
34
+    qDebug() << "bytes:" << bytes;
35
+}
36
+
37
+void PortListener::onDsrChanged(bool status)
38
+{
39
+    if (status)
40
+        qDebug() << "device was turned on";
41
+    else
42
+        qDebug() << "device was turned off";
43
+}

+ 26
- 0
src/3rdparty/qextserialport/examples/event/PortListener.h View File

@@ -0,0 +1,26 @@
1
+
2
+
3
+
4
+#ifndef PORTLISTENER_H_
5
+#define PORTLISTENER_H_
6
+
7
+#include <QObject>
8
+#include "qextserialport.h"
9
+
10
+class PortListener : public QObject
11
+{
12
+Q_OBJECT
13
+public:
14
+    PortListener(const QString & portName);
15
+
16
+private:
17
+    QextSerialPort *port;
18
+
19
+private slots:
20
+    void onReadyRead();
21
+    void onDsrChanged(bool status);
22
+
23
+};
24
+
25
+
26
+#endif /*PORTLISTENER_H_*/

+ 7
- 0
src/3rdparty/qextserialport/examples/event/event.pro View File

@@ -0,0 +1,7 @@
1
+TEMPLATE = app
2
+DEPENDPATH += .
3
+CONFIG += console
4
+include(../../src/qextserialport.pri)
5
+
6
+SOURCES += main.cpp PortListener.cpp
7
+HEADERS += PortListener.h

+ 19
- 0
src/3rdparty/qextserialport/examples/event/main.cpp View File

@@ -0,0 +1,19 @@
1
+/**
2
+ * @file main.cpp
3
+ * @brief Main file.
4
+ * @author Michal Policht
5
+ */
6
+
7
+#include <QCoreApplication>
8
+#include "PortListener.h"
9
+
10
+int main(int argc, char *argv[])
11
+{
12
+    QCoreApplication app(argc, argv);
13
+
14
+    QString portName = QLatin1String("COM1");              // update this to use your port of choice
15
+    PortListener listener(portName);        // signals get hooked up internally
16
+
17
+    // start the event loop and wait for signals
18
+    return app.exec();
19
+}

+ 5
- 0
src/3rdparty/qextserialport/examples/examples.pro View File

@@ -0,0 +1,5 @@
1
+TEMPLATE = subdirs
2
+SUBDIRS = qespta enumerator \
3
+    uartassistant
4
+win32:SUBDIRS += event
5
+

+ 61
- 0
src/3rdparty/qextserialport/examples/qespta/MainWindow.cpp View File

@@ -0,0 +1,61 @@
1
+/**
2
+ * @file MainWindow.cpp
3
+ * @brief MainWindow Implementation.
4
+ * @see MainWindow.h
5
+ * @author Micha? Policht
6
+ */
7
+
8
+
9
+#include <QMessageBox>
10
+#include <QMenuBar>
11
+#include "MainWindow.h"
12
+#include "MessageWindow.h"
13
+#include "QespTest.h"
14
+
15
+MainWindow::MainWindow()
16
+{
17
+    //central widget
18
+	QespTest* qespTest = new QespTest();
19
+    setCentralWidget(qespTest);
20
+	//bottom dock widget
21
+	MessageWindow* msgWindow = new MessageWindow();
22
+	addDockWidget(Qt::BottomDockWidgetArea, msgWindow);
23
+
24
+	createActions();
25
+	createMenus();
26
+
27
+    setWindowTitle(tr("QextSerialPort Test Application"));
28
+}
29
+
30
+void MainWindow::about()
31
+{
32
+    QMessageBox::about(this, tr("About "),
33
+            tr("<B>""</B><BR>"
34
+				"author: Michal Policht<br>"
35
+                "<a href='mailto:xpolik@users.sourceforge.net'>xpolik@users.sourceforge.net</a>"));
36
+}
37
+
38
+void MainWindow::createActions()
39
+{
40
+	//File actions
41
+	exitAct = new QAction(tr("E&xit"), this);
42
+	exitAct->setShortcut(tr("CTRL+D"));
43
+	exitAct->setStatusTip(tr("Exit the application"));
44
+	connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
45
+	
46
+	//Help actions
47
+	aboutAct = new QAction(tr("&About"), this);
48
+	aboutAct->setShortcut(tr("CTRL+A"));
49
+	aboutAct->setStatusTip(tr("About application"));
50
+	connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
51
+}
52
+
53
+void MainWindow::createMenus()
54
+{
55
+	fileMenu = menuBar()->addMenu(tr("&File"));
56
+	fileMenu->addAction(exitAct);
57
+
58
+	helpMenu = menuBar()->addMenu(tr("&Help"));
59
+	helpMenu->addAction(aboutAct);
60
+}
61
+

+ 38
- 0
src/3rdparty/qextserialport/examples/qespta/MainWindow.h View File

@@ -0,0 +1,38 @@
1
+/**
2
+ * @file MainWindow.h
3
+ * @brief Application's Main Window.
4
+ * @see MainWindow
5
+ * @author Micha? Policht
6
+ */
7
+
8
+#ifndef MAINWINDOW_H_
9
+#define MAINWINDOW_H_
10
+
11
+#include <QMainWindow>
12
+
13
+class QMenu;
14
+class QAction;
15
+
16
+class MainWindow : public QMainWindow
17
+{
18
+	Q_OBJECT
19
+
20
+	QMenu *fileMenu;
21
+    QAction *exitAct;
22
+	QMenu *helpMenu;
23
+    QAction *aboutAct;
24
+	
25
+private:
26
+    void createMenus();
27
+    void createActions();
28
+
29
+private slots:
30
+    void about();
31
+
32
+public:
33
+    MainWindow();
34
+
35
+};
36
+
37
+#endif /*MAINWINDOW_H_*/
38
+

+ 95
- 0
src/3rdparty/qextserialport/examples/qespta/MessageWindow.cpp View File

@@ -0,0 +1,95 @@
1
+/**
2
+ * @file MessageWindow.cpp
3
+ * @brief MessageWindow Implementation.
4
+ * @see MessageWindow.h
5
+ * @author Micha? Policht
6
+ */
7
+
8
+#include <stdio.h>
9
+#include "MessageWindow.h"
10
+#include <QMessageBox>
11
+#include <QCoreApplication>
12
+#include <QMutexLocker>
13
+
14
+const char* MessageWindow::WINDOW_TITLE = "Message Window";
15
+MessageWindow* MessageWindow::MsgHandler = NULL;
16
+
17
+MessageWindow::MessageWindow(QWidget* parent, Qt::WFlags flags) 
18
+	: QDockWidget(parent, flags),
19
+		msgTextEdit(this)
20
+{
21
+	setWindowTitle(tr(WINDOW_TITLE));
22
+	msgTextEdit.setReadOnly(true);
23
+	setWidget(&msgTextEdit);
24
+
25
+	MessageWindow::MsgHandler = this;
26
+}
27
+
28
+//static
29
+QString MessageWindow::QtMsgToQString(QtMsgType type, const char *msg)
30
+{
31
+	switch (type) {
32
+		case QtDebugMsg:
33
+			return QLatin1String("Debug: ")+QLatin1String(msg);
34
+		case QtWarningMsg:
35
+			return QLatin1String("Warning: ")+QLatin1String(msg);
36
+		case QtCriticalMsg:
37
+			return QLatin1String("Critical: ")+QLatin1String(msg);
38
+		case QtFatalMsg:
39
+			return QLatin1String("Fatal: ")+QLatin1String(msg);
40
+		default:
41
+			return QLatin1String("Unrecognized message type: ")+QLatin1String(msg);
42
+	}
43
+}
44
+
45
+//static
46
+void MessageWindow::AppendMsgWrapper(QtMsgType type, const char* msg)
47
+{
48
+	static QMutex mutex;
49
+	QMutexLocker locker(&mutex);
50
+	
51
+	if (MessageWindow::MsgHandler != NULL)
52
+		return MessageWindow::MsgHandler->postMsgEvent(type, msg);
53
+	else
54
+        fprintf(stderr, "%s", MessageWindow::QtMsgToQString(type, msg).toLatin1().data());
55
+}
56
+
57
+void MessageWindow::customEvent(QEvent* event)
58
+{
59
+	if (static_cast<MessageWindow::EventType>(event->type()) == MessageWindow::MessageEventType)
60
+		msgTextEdit.append(dynamic_cast<MessageEvent* >(event)->msg);
61
+}
62
+
63
+void MessageWindow::postMsgEvent(QtMsgType type, const char* msg)
64
+{
65
+	QString qmsg = MessageWindow::QtMsgToQString(type, msg);
66
+	switch (type) {
67
+		case QtDebugMsg:
68
+			break;
69
+		case QtWarningMsg:
70
+			qmsg.prepend(QLatin1String("<FONT color=\"#FF0000\">"));
71
+			qmsg.append(QLatin1String("</FONT>"));
72
+			break;
73
+		case QtCriticalMsg:
74
+			if (QMessageBox::critical(this, QLatin1String("Critical Error"), qmsg,
75
+					QMessageBox::Ignore,
76
+					QMessageBox::Abort,
77
+					QMessageBox::NoButton) == QMessageBox::Abort)
78
+				abort(); // core dump
79
+			qmsg.prepend(QLatin1String("<B><FONT color=\"#FF0000\">"));
80
+			qmsg.append(QLatin1String("</FONT></B>"));
81
+			break;
82
+		case QtFatalMsg:
83
+			QMessageBox::critical(this, QLatin1String("Fatal Error"), qmsg, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
84
+			abort(); // deliberately core dump
85
+	}
86
+	//it's impossible to change GUI directly from thread other than the main thread 
87
+	//so post message encapsulated by MessageEvent to the main thread's event queue
88
+	QCoreApplication::postEvent(this, new MessageEvent(qmsg));
89
+}
90
+
91
+MessageEvent::MessageEvent(QString & msg):
92
+	QEvent(static_cast<QEvent::Type>(MessageWindow::MessageEventType))
93
+{
94
+	this->msg = msg;
95
+}

+ 82
- 0
src/3rdparty/qextserialport/examples/qespta/MessageWindow.h View File

@@ -0,0 +1,82 @@
1
+/**
2
+ * @file MessageWindow.h
3
+ * @brief Message Window.
4
+ * @see MessageWindow
5
+ * @author Micha? Policht
6
+ */
7
+
8
+#ifndef MESSAGEWINDOW_H_
9
+#define MESSAGEWINDOW_H_
10
+
11
+#include <QDockWidget>
12
+#include <QTextEdit>
13
+#include <QEvent>
14
+
15
+/**
16
+ * Message Window. Handling errors and other messages.
17
+ */
18
+class MessageWindow: public QDockWidget
19
+{
20
+	Q_OBJECT
21
+
22
+	QTextEdit msgTextEdit;				///< Main widget.
23
+	static MessageWindow* MsgHandler;	///< Set in constructor.
24
+	static const char* WINDOW_TITLE; 	///< Window title.
25
+
26
+	private:
27
+		static QString QtMsgToQString(QtMsgType type, const char *msg);
28
+	
29
+	protected:
30
+		/**
31
+		 * Handle custom events. MessageWindow hadles custom events listed in
32
+		 * EventType enum.
33
+		 */
34
+		virtual void customEvent(QEvent* event);
35
+		
36
+	public:
37
+        enum EventType {MessageEventType = QEvent::User};	///< Custom event types.
38
+		
39
+		/**
40
+		 * Default constructor.
41
+		 * 	@param parent parent widget.
42
+		 * 	@param flags widget flags.
43
+		 */
44
+		MessageWindow(QWidget* parent = 0, Qt::WFlags flags = 0);
45
+
46
+		/**
47
+		 * Append message wrapper. Since ISO forbids casting member functions
48
+		 * to C functions, wrapper is needed to use this class as QtMsgHandler.
49
+		 * This method is thread-safe but not reentrant.
50
+		 * 	@param type message type.
51
+		 * 	@param msg message string.
52
+		 */
53
+		static void AppendMsgWrapper(QtMsgType type, const char *msg);
54
+		
55
+		/**
56
+		 * Post message event to the main event loop. This function encapsulates
57
+		 * message into MessageEvent object and passes it to the main event loop.
58
+		 * 	@param type message type.
59
+		 * 	@param msg message string.
60
+		 */
61
+		void postMsgEvent(QtMsgType type, const char *msg);
62
+	
63
+};
64
+
65
+
66
+/**
67
+ * Message Event. Custom event used by @ref MessageWindow to provide multi-threaded
68
+ * access. Encapsulates message inside @a msg variable.
69
+ */
70
+class MessageEvent: public QEvent
71
+{
72
+    public:
73
+        QString msg;	///< Message string.
74
+
75
+        /**
76
+         * Contructor.
77
+         * 	@param msg message to post.
78
+         */
79
+        MessageEvent(QString & msg);
80
+};
81
+
82
+#endif /*MESSAGEWINDOW_H_*/

+ 129
- 0
src/3rdparty/qextserialport/examples/qespta/QespTest.cpp View File

@@ -0,0 +1,129 @@
1
+/* QespTest.cpp
2
+**************************************/
3
+#include "QespTest.h"
4
+#include "qextserialport.h"
5
+#include <QLayout>
6
+#include <QLineEdit>
7
+#include <QTextEdit>
8
+#include <QPushButton>
9
+#include <QSpinBox>
10
+
11
+
12
+QespTest::QespTest(QWidget* parent) 
13
+	: QWidget(parent)
14
+
15
+{
16
+	//modify the port settings on your own
17
+    #ifdef Q_OS_UNIX
18
+		port = new QextSerialPort(QLatin1String("/dev/ttyS0"), QextSerialPort::Polling);
19
+	#else
20
+		port = new QextSerialPort(QLatin1String("COM1"), QextSerialPort::Polling);
21
+    #endif /*Q_OS_UNIX*/
22
+	port->setBaudRate(BAUD19200);
23
+	port->setFlowControl(FLOW_OFF);
24
+	port->setParity(PAR_NONE);
25
+	port->setDataBits(DATA_8);
26
+	port->setStopBits(STOP_2);
27
+	//set timeouts to 500 ms
28
+	port->setTimeout(500);
29
+	
30
+	message = new QLineEdit(this);
31
+
32
+	// transmit receive
33
+	QPushButton *transmitButton = new QPushButton(tr("Transmit"));
34
+	connect(transmitButton, SIGNAL(clicked()), SLOT(transmitMsg()));
35
+	QPushButton *receiveButton = new QPushButton(tr("Receive"));
36
+	connect(receiveButton, SIGNAL(clicked()), SLOT(receiveMsg()));
37
+	QHBoxLayout* trLayout = new QHBoxLayout;
38
+	trLayout->addWidget(transmitButton);
39
+	trLayout->addWidget(receiveButton);
40
+	  
41
+	//CR LF
42
+	QPushButton *CRButton = new QPushButton(tr("CR"));
43
+	connect(CRButton, SIGNAL(clicked()), SLOT(appendCR()));
44
+	QPushButton *LFButton = new QPushButton(tr("LF"));
45
+	connect(LFButton, SIGNAL(clicked()), SLOT(appendLF()));
46
+	QHBoxLayout *crlfLayout = new QHBoxLayout;
47
+	crlfLayout->addWidget(CRButton);
48
+	crlfLayout->addWidget(LFButton);
49
+	
50
+	//open close
51
+	QPushButton *openButton = new QPushButton(tr("Open"));
52
+	connect(openButton, SIGNAL(clicked()), SLOT(openPort()));
53
+	QPushButton *closeButton = new QPushButton(tr("Close"));
54
+	connect(closeButton, SIGNAL(clicked()), SLOT(closePort()));
55
+	QHBoxLayout *ocLayout = new QHBoxLayout;
56
+	ocLayout->addWidget(openButton);
57
+	ocLayout->addWidget(closeButton);
58
+	
59
+	received_msg = new QTextEdit();
60
+	  
61
+	QVBoxLayout *myVBox = new QVBoxLayout;
62
+	myVBox->addWidget(message);
63
+	myVBox->addLayout(crlfLayout);
64
+	myVBox->addLayout(trLayout);
65
+	myVBox->addLayout(ocLayout);
66
+	myVBox->addWidget(received_msg);
67
+	setLayout(myVBox);
68
+	
69
+	qDebug("isOpen : %d", port->isOpen());
70
+}
71
+
72
+QespTest::~QespTest()
73
+{
74
+    delete port;
75
+    port = NULL;
76
+}
77
+
78
+void QespTest::transmitMsg()
79
+{
80
+  int i = port->write((message->text()).toAscii(),
81
+                       (message->text()).length());
82
+  qDebug("trasmitted : %d", i);
83
+}
84
+
85
+void QespTest::receiveMsg()
86
+{
87
+	char buff[1024];
88
+  	int numBytes;
89
+  
90
+	numBytes = port->bytesAvailable();
91
+    if(numBytes > 1024) 
92
+    	numBytes = 1024;
93
+
94
+    int i = port->read(buff, numBytes);
95
+    if (i != -1)
96
+		buff[i] = '\0';
97
+	else
98
+		buff[0] = '\0';
99
+	QString msg = QLatin1String(buff);
100
+	
101
+   	received_msg->append(msg);
102
+   	received_msg->ensureCursorVisible();
103
+	qDebug("bytes available: %d", numBytes);
104
+	qDebug("received: %d", i);
105
+}
106
+
107
+
108
+void QespTest::appendCR()
109
+{
110
+	message->insert(QLatin1String("\x0D"));
111
+}
112
+
113
+void QespTest::appendLF()
114
+{
115
+	message->insert(QLatin1String("\x0A"));
116
+}
117
+
118
+void QespTest::closePort()
119
+{
120
+	port->close();
121
+	qDebug("is open: %d", port->isOpen());
122
+}
123
+
124
+void QespTest::openPort()
125
+{
126
+	port->open(QIODevice::ReadWrite | QIODevice::Unbuffered);
127
+	qDebug("is open: %d", port->isOpen());
128
+}
129
+

+ 36
- 0
src/3rdparty/qextserialport/examples/qespta/QespTest.h View File

@@ -0,0 +1,36 @@
1
+/* qesptest.h
2
+**************************************/
3
+#ifndef _QESPTEST_H_
4
+#define _QESPTEST_H_
5
+
6
+#include <QWidget>
7
+
8
+class QLineEdit;
9
+class QTextEdit;
10
+class QextSerialPort;
11
+class QSpinBox;
12
+
13
+class QespTest :  public QWidget
14
+{
15
+  Q_OBJECT
16
+public:
17
+  QespTest(QWidget *parent=0);
18
+
19
+  virtual ~QespTest();
20
+
21
+private:
22
+  QLineEdit *message;
23
+  QSpinBox* delaySpinBox;
24
+  QTextEdit *received_msg;
25
+  QextSerialPort *port;
26
+
27
+private slots:
28
+  void transmitMsg();
29
+  void receiveMsg();
30
+  void appendCR();
31
+  void appendLF();
32
+  void closePort();
33
+  void openPort();
34
+};
35
+
36
+#endif

+ 4
- 0
src/3rdparty/qextserialport/examples/qespta/README View File

@@ -0,0 +1,4 @@
1
+This is simple application using QextSerialPort library.
2
+
3
+Port settings are in QespTest constructor (QespTest.cpp)
4
+

+ 26
- 0
src/3rdparty/qextserialport/examples/qespta/main.cpp View File

@@ -0,0 +1,26 @@
1
+/**
2
+ * @file main.cpp
3
+ * @brief Main file.
4
+ * @author Micha? Policht
5
+ */
6
+
7
+#include <QApplication>
8
+#include "MainWindow.h"
9
+#include "MessageWindow.h"
10
+
11
+
12
+int main(int argc, char *argv[])
13
+{
14
+	QApplication app(argc, argv);
15
+    //! [0]
16
+    //redirect debug messages to the MessageWindow dialog
17
+	qInstallMsgHandler(MessageWindow::AppendMsgWrapper);
18
+    //! [0]
19
+
20
+    MainWindow mainWindow;
21
+	mainWindow.show();
22
+
23
+    return app.exec();
24
+}
25
+
26
+

+ 14
- 0
src/3rdparty/qextserialport/examples/qespta/qespta.pro View File

@@ -0,0 +1,14 @@
1
+TEMPLATE = app
2
+DEPENDPATH += .
3
+QT += core gui
4
+contains(QT_VERSION, ^5\\..*\\..*): QT += widgets
5
+HEADERS += MainWindow.h \
6
+		MessageWindow.h \
7
+        QespTest.h
8
+
9
+SOURCES += main.cpp \
10
+		MainWindow.cpp \
11
+		MessageWindow.cpp \
12
+		QespTest.cpp
13
+
14
+include(../../src/qextserialport.pri)

+ 159
- 0
src/3rdparty/qextserialport/examples/uartassistant/dialog.cpp View File

@@ -0,0 +1,159 @@
1
+#include "qextserialport.h"
2
+#include "dialog.h"
3
+#include "ui_dialog.h"
4
+#include <QtCore>
5
+
6
+Dialog::Dialog(QWidget *parent) :
7
+    QDialog(parent),
8
+    ui(new Ui::Dialog)
9
+{
10
+    ui->setupUi(this);
11
+
12
+    //! [0]
13
+#ifdef Q_OS_WIN
14
+    ui->portBox->addItems(QStringList()<<"COM1"<<"COM2"<<"COM3"<<"COM4");
15
+#else
16
+    ui->portBox->addItems(QStringList()<<"/dev/ttyS0"<<"/dev/ttyS1"<<"/dev/ttyUSB0"<<"/dev/ttyUSB1");
17
+#endif
18
+    //make sure user can input their own port name!
19
+    ui->portBox->setEditable(true);
20
+
21
+    ui->baudRateBox->addItem("1200", BAUD1200);
22
+    ui->baudRateBox->addItem("2400", BAUD2400);
23
+    ui->baudRateBox->addItem("4800", BAUD4800);
24
+    ui->baudRateBox->addItem("9600", BAUD9600);
25
+    ui->baudRateBox->addItem("19200", BAUD19200);
26
+    ui->baudRateBox->setCurrentIndex(3);
27
+
28
+    ui->parityBox->addItem("NONE", PAR_NONE);
29
+    ui->parityBox->addItem("ODD", PAR_ODD);
30
+    ui->parityBox->addItem("EVEN", PAR_EVEN);
31
+
32
+    ui->dataBitsBox->addItem("5", DATA_5);
33
+    ui->dataBitsBox->addItem("6", DATA_6);
34
+    ui->dataBitsBox->addItem("7", DATA_7);
35
+    ui->dataBitsBox->addItem("8", DATA_8);
36
+    ui->dataBitsBox->setCurrentIndex(3);
37
+
38
+    ui->stopBitsBox->addItem("1", STOP_1);
39
+    ui->stopBitsBox->addItem("2", STOP_2);
40
+
41
+    ui->queryModeBox->addItem("Polling", QextSerialPort::Polling);
42
+    ui->queryModeBox->addItem("EventDriven", QextSerialPort::EventDriven);
43
+    //! [0]
44
+
45
+    ui->led->turnOff();
46
+
47
+    timer = new QTimer(this);
48
+    timer->setInterval(40);
49
+    //! [1]
50
+    PortSettings settings = {BAUD9600, DATA_8, PAR_NONE, STOP_1, FLOW_OFF, 10};
51
+    port = new QextSerialPort(ui->portBox->currentText(), settings, QextSerialPort::Polling);
52
+    //! [1]
53
+    connect(ui->baudRateBox, SIGNAL(currentIndexChanged(int)), SLOT(onBaudRateChanged(int)));
54
+    connect(ui->parityBox, SIGNAL(currentIndexChanged(int)), SLOT(onParityChanged(int)));
55
+    connect(ui->dataBitsBox, SIGNAL(currentIndexChanged(int)), SLOT(onDataBitsChanged(int)));
56
+    connect(ui->stopBitsBox, SIGNAL(currentIndexChanged(int)), SLOT(onStopBitsChanged(int)));
57
+    connect(ui->queryModeBox, SIGNAL(currentIndexChanged(int)), SLOT(onQueryModeChanged(int)));
58
+    connect(ui->timeoutBox, SIGNAL(valueChanged(int)), SLOT(onTimeoutChanged(int)));
59
+    connect(ui->portBox, SIGNAL(editTextChanged(QString)), SLOT(onPortNameChanged(QString)));
60
+    connect(ui->openCloseButton, SIGNAL(clicked()), SLOT(onOpenCloseButtonClicked()));
61
+    connect(ui->sendButton, SIGNAL(clicked()), SLOT(onSendButtonClicked()));
62
+    connect(timer, SIGNAL(timeout()), SLOT(onReadyRead()));
63
+    connect(port, SIGNAL(readyRead()), SLOT(onReadyRead()));
64
+
65
+    setWindowTitle(tr("QextSerialPort Demo"));
66
+}
67
+
68
+Dialog::~Dialog()
69
+{
70
+    delete ui;
71
+    delete port;
72
+}
73
+
74
+void Dialog::changeEvent(QEvent *e)
75
+{
76
+    QDialog::changeEvent(e);
77
+    switch (e->type()) {
78
+    case QEvent::LanguageChange:
79
+        ui->retranslateUi(this);
80
+        break;
81
+    default:
82
+        break;
83
+    }
84
+}
85
+
86
+void Dialog::onPortNameChanged(const QString & /*name*/)
87
+{
88
+    if (port->isOpen()) {
89
+        port->close();
90
+        ui->led->turnOff();
91
+    }
92
+}
93
+//! [2]
94
+void Dialog::onBaudRateChanged(int idx)
95
+{
96
+    port->setBaudRate((BaudRateType)ui->baudRateBox->itemData(idx).toInt());
97
+}
98
+
99
+void Dialog::onParityChanged(int idx)
100
+{
101
+    port->setParity((ParityType)ui->parityBox->itemData(idx).toInt());
102
+}
103
+
104
+void Dialog::onDataBitsChanged(int idx)
105
+{
106
+    port->setDataBits((DataBitsType)ui->dataBitsBox->itemData(idx).toInt());
107
+}
108
+
109
+void Dialog::onStopBitsChanged(int idx)
110
+{
111
+    port->setStopBits((StopBitsType)ui->stopBitsBox->itemData(idx).toInt());
112
+}
113
+
114
+void Dialog::onQueryModeChanged(int idx)
115
+{
116
+    port->setQueryMode((QextSerialPort::QueryMode)ui->queryModeBox->itemData(idx).toInt());
117
+}
118
+
119
+void Dialog::onTimeoutChanged(int val)
120
+{
121
+    port->setTimeout(val);
122
+}
123
+//! [2]
124
+//! [3]
125
+void Dialog::onOpenCloseButtonClicked()
126
+{
127
+    if (!port->isOpen()) {
128
+        port->setPortName(ui->portBox->currentText());
129
+        port->open(QIODevice::ReadWrite);
130
+    }
131
+    else {
132
+        port->close();
133
+    }
134
+
135
+    //If using polling mode, we need a QTimer
136
+    if (port->isOpen() && port->queryMode() == QextSerialPort::Polling)
137
+        timer->start();
138
+    else
139
+        timer->stop();
140
+
141
+    //update led's status
142
+    ui->led->turnOn(port->isOpen());
143
+}
144
+//! [3]
145
+//! [4]
146
+void Dialog::onSendButtonClicked()
147
+{
148
+    if (port->isOpen() && !ui->sendEdit->toPlainText().isEmpty())
149
+        port->write(ui->sendEdit->toPlainText().toLatin1());
150
+}
151
+
152
+void Dialog::onReadyRead()
153
+{
154
+    if (port->bytesAvailable()) {
155
+        ui->recvEdit->moveCursor(QTextCursor::End);
156
+        ui->recvEdit->insertPlainText(QString::fromLatin1(port->readAll()));
157
+    }
158
+}
159
+//! [4]

+ 41
- 0
src/3rdparty/qextserialport/examples/uartassistant/dialog.h View File

@@ -0,0 +1,41 @@
1
+#ifndef DIALOG_H
2
+#define DIALOG_H
3
+
4
+#include <QDialog>
5
+
6
+namespace Ui {
7
+    class Dialog;
8
+}
9
+class QTimer;
10
+class QextSerialPort;
11
+
12
+class Dialog : public QDialog
13
+{
14
+    Q_OBJECT
15
+
16
+public:
17
+    explicit Dialog(QWidget *parent = 0);
18
+    ~Dialog();
19
+
20
+protected:
21
+    void changeEvent(QEvent *e);
22
+
23
+private Q_SLOTS:
24
+    void onPortNameChanged(const QString &name);
25
+    void onBaudRateChanged(int idx);
26
+    void onParityChanged(int idx);
27
+    void onDataBitsChanged(int idx);
28
+    void onStopBitsChanged(int idx);
29
+    void onQueryModeChanged(int idx);
30
+    void onTimeoutChanged(int val);
31
+    void onOpenCloseButtonClicked();
32
+    void onSendButtonClicked();
33
+    void onReadyRead();
34
+
35
+private:
36
+    Ui::Dialog *ui;
37
+    QTimer *timer;
38
+    QextSerialPort *port;
39
+};
40
+
41
+#endif // DIALOG_H

+ 191
- 0
src/3rdparty/qextserialport/examples/uartassistant/dialog.ui View File

@@ -0,0 +1,191 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<ui version="4.0">
3
+ <class>Dialog</class>
4
+ <widget class="QDialog" name="Dialog">
5
+  <property name="geometry">
6
+   <rect>
7
+    <x>0</x>
8
+    <y>0</y>
9
+    <width>604</width>
10
+    <height>485</height>
11
+   </rect>
12
+  </property>
13
+  <property name="windowTitle">
14
+   <string>Dialog</string>
15
+  </property>
16
+  <layout class="QHBoxLayout" name="horizontalLayout_2">
17
+   <item>
18
+    <layout class="QVBoxLayout" name="verticalLayout" stretch="3,1">
19
+     <item>
20
+      <widget class="QPlainTextEdit" name="recvEdit">
21
+       <property name="maximumBlockCount">
22
+        <number>800</number>
23
+       </property>
24
+      </widget>
25
+     </item>
26
+     <item>
27
+      <widget class="QPlainTextEdit" name="sendEdit"/>
28
+     </item>
29
+    </layout>
30
+   </item>
31
+   <item>
32
+    <layout class="QVBoxLayout" name="verticalLayout_2">
33
+     <item>
34
+      <layout class="QFormLayout" name="formLayout">
35
+       <item row="0" column="0">
36
+        <widget class="QLabel" name="label">
37
+         <property name="text">
38
+          <string>Port:</string>
39
+         </property>
40
+        </widget>
41
+       </item>
42
+       <item row="0" column="1">
43
+        <widget class="QComboBox" name="portBox"/>
44
+       </item>
45
+       <item row="1" column="0">
46
+        <widget class="QLabel" name="label_2">
47
+         <property name="text">
48
+          <string>BaudRate:</string>
49
+         </property>
50
+        </widget>
51
+       </item>
52
+       <item row="1" column="1">
53
+        <widget class="QComboBox" name="baudRateBox"/>
54
+       </item>
55
+       <item row="2" column="0">
56
+        <widget class="QLabel" name="label_3">
57
+         <property name="text">
58
+          <string>DataBits:</string>
59
+         </property>
60
+        </widget>
61
+       </item>
62
+       <item row="2" column="1">
63
+        <widget class="QComboBox" name="dataBitsBox"/>
64
+       </item>
65
+       <item row="3" column="0">
66
+        <widget class="QLabel" name="label_4">
67
+         <property name="text">
68
+          <string>Parity:</string>
69
+         </property>
70
+        </widget>
71
+       </item>
72
+       <item row="3" column="1">
73
+        <widget class="QComboBox" name="parityBox"/>
74
+       </item>
75
+       <item row="4" column="0">
76
+        <widget class="QLabel" name="label_5">
77
+         <property name="text">
78
+          <string>StopBits:</string>
79
+         </property>
80
+        </widget>
81
+       </item>
82
+       <item row="4" column="1">
83
+        <widget class="QComboBox" name="stopBitsBox"/>
84
+       </item>
85
+       <item row="6" column="0">
86
+        <widget class="QLabel" name="label_6">
87
+         <property name="text">
88
+          <string>QueryMode:</string>
89
+         </property>
90
+        </widget>
91
+       </item>
92
+       <item row="6" column="1">
93
+        <widget class="QComboBox" name="queryModeBox"/>
94
+       </item>
95
+       <item row="5" column="0">
96
+        <widget class="QLabel" name="label_7">
97
+         <property name="text">
98
+          <string>Timeout:</string>
99
+         </property>
100
+        </widget>
101
+       </item>
102
+       <item row="5" column="1">
103
+        <widget class="QSpinBox" name="timeoutBox">
104
+         <property name="suffix">
105
+          <string> ms</string>
106
+         </property>
107
+         <property name="minimum">
108
+          <number>-1</number>
109
+         </property>
110
+         <property name="maximum">
111
+          <number>10000</number>
112
+         </property>
113
+         <property name="singleStep">
114
+          <number>10</number>
115
+         </property>
116
+         <property name="value">
117
+          <number>10</number>
118
+         </property>
119
+        </widget>
120
+       </item>
121
+      </layout>
122
+     </item>
123
+     <item>
124
+      <layout class="QHBoxLayout" name="horizontalLayout">
125
+       <item>
126
+        <widget class="HLed" name="led" native="true">
127
+         <property name="sizePolicy">
128
+          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
129
+           <horstretch>0</horstretch>
130
+           <verstretch>0</verstretch>
131
+          </sizepolicy>
132
+         </property>
133
+         <property name="minimumSize">
134
+          <size>
135
+           <width>20</width>
136
+           <height>20</height>
137
+          </size>
138
+         </property>
139
+         <property name="maximumSize">
140
+          <size>
141
+           <width>25</width>
142
+           <height>25</height>
143
+          </size>
144
+         </property>
145
+        </widget>
146
+       </item>
147
+       <item>
148
+        <widget class="QPushButton" name="openCloseButton">
149
+         <property name="text">
150
+          <string>Open/Close</string>
151
+         </property>
152
+        </widget>
153
+       </item>
154
+      </layout>
155
+     </item>
156
+     <item>
157
+      <spacer name="verticalSpacer">
158
+       <property name="orientation">
159
+        <enum>Qt::Vertical</enum>
160
+       </property>
161
+       <property name="sizeHint" stdset="0">
162
+        <size>
163
+         <width>20</width>
164
+         <height>40</height>
165
+        </size>
166
+       </property>
167
+      </spacer>
168
+     </item>
169
+     <item>
170
+      <widget class="QPushButton" name="sendButton">
171
+       <property name="text">
172
+        <string>Send</string>
173
+       </property>
174
+      </widget>
175
+     </item>
176
+    </layout>
177
+   </item>
178
+  </layout>
179
+ </widget>
180
+ <layoutdefault spacing="6" margin="11"/>
181
+ <customwidgets>
182
+  <customwidget>
183
+   <class>HLed</class>
184
+   <extends>QWidget</extends>
185
+   <header>hled.h</header>
186
+   <container>1</container>
187
+  </customwidget>
188
+ </customwidgets>
189
+ <resources/>
190
+ <connections/>
191
+</ui>

+ 133
- 0
src/3rdparty/qextserialport/examples/uartassistant/hled.cpp View File

@@ -0,0 +1,133 @@
1
+#include <QtGui>
2
+#include "hled.h"
3
+
4
+struct HLed::Private
5
+{
6
+public:
7
+    Private()
8
+        : darkerFactor(300), color(Qt::green), isOn(true)
9
+    { }
10
+
11
+    int darkerFactor;
12
+    QColor color;
13
+    bool isOn;
14
+};
15
+
16
+HLed::HLed(QWidget *parent)
17
+    :QWidget(parent), m_d(new Private)
18
+{
19
+}
20
+
21
+HLed::~HLed()
22
+{
23
+    delete m_d;
24
+}
25
+
26
+QColor HLed::color() const
27
+{
28
+    return m_d->color;
29
+}
30
+
31
+void HLed::setColor(const QColor &color)
32
+{
33
+    if (m_d->color == color)
34
+        return;
35
+    update();
36
+}
37
+
38
+QSize HLed::sizeHint() const
39
+{
40
+    return QSize(20, 20);
41
+}
42
+
43
+QSize HLed::minimumSizeHint() const
44
+{
45
+    return QSize(16, 16);
46
+}
47
+
48
+void HLed::toggle()
49
+{
50
+    m_d->isOn = !m_d->isOn;
51
+    update();
52
+}
53
+
54
+void HLed::turnOn(bool on)
55
+{
56
+    m_d->isOn = on;
57
+    update();
58
+}
59
+
60
+void HLed::turnOff(bool off)
61
+{
62
+    turnOn(!off);
63
+}
64
+
65
+void HLed::paintEvent(QPaintEvent* /* event*/)
66
+{
67
+    int width = ledWidth();
68
+
69
+    QPainter painter(this);
70
+    painter.setRenderHint(QPainter::Antialiasing);
71
+
72
+    QColor color = m_d->isOn ? m_d->color
73
+                             : m_d->color.darker(m_d->darkerFactor);
74
+
75
+    QBrush brush;
76
+    brush.setStyle(Qt::SolidPattern);
77
+    brush.setColor(color);
78
+    painter.setBrush(brush);
79
+    // draw plain
80
+    painter.drawEllipse(1, 1, width-1, width-1);
81
+
82
+    QPen pen;
83
+    pen.setWidth(2);
84
+
85
+    int pos = width / 5 + 1;
86
+    int lightWidth = width * 2 / 3;
87
+    int lightQuote = 130 * 2 / (lightWidth ? lightWidth : 1) + 100;
88
+
89
+    // draw bright spot
90
+    while (lightWidth) {
91
+        color = color.lighter(lightQuote);
92
+        pen.setColor(color);
93
+        painter.setPen(pen);
94
+        painter.drawEllipse(pos, pos, lightWidth, lightWidth);
95
+        lightWidth--;
96
+
97
+        if (!lightWidth)
98
+            break;
99
+
100
+        painter.drawEllipse(pos, pos, lightWidth, lightWidth);
101
+        lightWidth--;
102
+
103
+        if (!lightWidth)
104
+            break;
105
+
106
+        painter.drawEllipse(pos, pos, lightWidth, lightWidth);
107
+        pos++;
108
+        lightWidth--;
109
+    }
110
+
111
+    //draw border
112
+    painter.setBrush(Qt::NoBrush);
113
+
114
+    int angle = -720;
115
+    color = palette().color(QPalette::Light);
116
+
117
+    for (int arc=120; arc<2880; arc+=240) {
118
+        pen.setColor(color);
119
+        painter.setPen(pen);
120
+        int w = width - pen.width()/2;
121
+        painter.drawArc(pen.width()/2, pen.width()/2, w, w, angle+arc, 240);
122
+        painter.drawArc(pen.width()/2, pen.width()/2, w, w, angle-arc, 240);
123
+        color = color.darker(110);
124
+    }
125
+}
126
+
127
+int HLed::ledWidth() const
128
+{
129
+    int width = qMin(this->width(), this->height());
130
+    width -= 2;
131
+    return width > 0 ? width : 0;
132
+}
133
+

+ 34
- 0
src/3rdparty/qextserialport/examples/uartassistant/hled.h View File

@@ -0,0 +1,34 @@
1
+#ifndef HLED_H
2
+#define HLED_H
3
+
4
+#include <QWidget>
5
+
6
+class QColor;
7
+
8
+class HLed : public QWidget
9
+{
10
+    Q_OBJECT
11
+public:
12
+    HLed(QWidget *parent = 0);
13
+    ~HLed();
14
+
15
+    QColor color() const;
16
+    QSize sizeHint() const;
17
+    QSize minimumSizeHint() const;
18
+
19
+public slots:
20
+    void setColor(const QColor &color);
21
+    void toggle();
22
+    void turnOn(bool on=true);
23
+    void turnOff(bool off=true);
24
+
25
+protected:
26
+    void paintEvent(QPaintEvent*);
27
+    int ledWidth() const;
28
+
29
+private:
30
+    struct Private;
31
+    Private * const m_d;
32
+};
33
+
34
+#endif // HLED_H

+ 11
- 0
src/3rdparty/qextserialport/examples/uartassistant/main.cpp View File

@@ -0,0 +1,11 @@
1
+#include <QApplication>
2
+#include "dialog.h"
3
+
4
+int main(int argc, char *argv[])
5
+{
6
+    QApplication a(argc, argv);
7
+    Dialog w;
8
+    w.show();
9
+
10
+    return a.exec();
11
+}

+ 22
- 0
src/3rdparty/qextserialport/examples/uartassistant/uartassistant.pro View File

@@ -0,0 +1,22 @@
1
+#-------------------------------------------------
2
+#
3
+# Project created by QtCreator 2011-11-06T21:37:41
4
+#
5
+#-------------------------------------------------
6
+
7
+QT       += core gui
8
+contains(QT_VERSION, ^5\\..*\\..*): QT += widgets
9
+
10
+TARGET = uartassistant
11
+TEMPLATE = app
12
+
13
+include(../../src/qextserialport.pri)
14
+
15
+SOURCES += main.cpp\
16
+        dialog.cpp\
17
+        hled.cpp
18
+
19
+HEADERS  += dialog.h \
20
+            hled.h
21
+
22
+FORMS    += dialog.ui

+ 7
- 0
src/3rdparty/qextserialport/qextserialport.pro View File

@@ -0,0 +1,7 @@
1
+TEMPLATE=subdirs
2
+CONFIG += ordered
3
+include(common.pri)
4
+qextserialport-library:SUBDIRS=buildlib
5
+SUBDIRS+=examples
6
+
7
+include(doc/doc.pri)

+ 427
- 0
src/3rdparty/qextserialport/src/extserialport/qextserialport_win.cpp View File

@@ -0,0 +1,427 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialport.h"
33
+#include "qextserialport_p.h"
34
+#include <QtCore/QThread>
35
+#include <QtCore/QReadWriteLock>
36
+#include <QtCore/QMutexLocker>
37
+#include <QtCore/QDebug>
38
+#include <QtCore/QRegExp>
39
+#include <QtCore/QMetaType>
40
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
41
+#  include <QtCore/QWinEventNotifier>
42
+#  define WinEventNotifier QWinEventNotifier
43
+#elif !defined(QESP_NO_QT4_PRIVATE)
44
+#  include <QtCore/private/qwineventnotifier_p.h>
45
+#  define WinEventNotifier QWinEventNotifier
46
+#else
47
+#  include "qextwineventnotifier_p.h"
48
+#  define WinEventNotifier QextWinEventNotifier
49
+#endif
50
+void QextSerialPortPrivate::platformSpecificInit()
51
+{
52
+    Win_Handle=INVALID_HANDLE_VALUE;
53
+    ZeroMemory(&overlap, sizeof(OVERLAPPED));
54
+    overlap.hEvent = CreateEvent(NULL, true, false, NULL);
55
+    winEventNotifier = 0;
56
+    bytesToWriteLock = new QReadWriteLock;
57
+    _bytesToWrite = 0;
58
+}
59
+
60
+void QextSerialPortPrivate::platformSpecificDestruct() {
61
+    CloseHandle(overlap.hEvent);
62
+    delete bytesToWriteLock;
63
+}
64
+
65
+
66
+/*!
67
+    \internal
68
+    COM ports greater than 9 need \\.\ prepended
69
+
70
+    This is only need when open the port.
71
+*/
72
+static QString fullPortNameWin(const QString & name)
73
+{
74
+    QRegExp rx(QLatin1String("^COM(\\d+)"));
75
+    QString fullName(name);
76
+    if(fullName.contains(rx))
77
+        fullName.prepend(QLatin1String("\\\\.\\"));
78
+    return fullName;
79
+}
80
+
81
+bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode)
82
+{
83
+    Q_Q(QextSerialPort);
84
+    DWORD confSize = sizeof(COMMCONFIG);
85
+    Win_CommConfig.dwSize = confSize;
86
+    DWORD dwFlagsAndAttributes = 0;
87
+    if (_queryMode == QextSerialPort::EventDriven)
88
+        dwFlagsAndAttributes += FILE_FLAG_OVERLAPPED;
89
+
90
+    /*open the port*/
91
+    Win_Handle=CreateFileW((wchar_t*)fullPortNameWin(port).utf16(), GENERIC_READ|GENERIC_WRITE,
92
+                           0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL);
93
+    if (Win_Handle!=INVALID_HANDLE_VALUE) {
94
+        q->setOpenMode(mode);
95
+        /*configure port settings*/
96
+        GetCommConfig(Win_Handle, &Win_CommConfig, &confSize);
97
+        GetCommState(Win_Handle, &(Win_CommConfig.dcb));
98
+
99
+        /*set up parameters*/
100
+        Win_CommConfig.dcb.fBinary=TRUE;
101
+        Win_CommConfig.dcb.fInX=FALSE;
102
+        Win_CommConfig.dcb.fOutX=FALSE;
103
+        Win_CommConfig.dcb.fAbortOnError=FALSE;
104
+        Win_CommConfig.dcb.fNull=FALSE;
105
+        /* Dtr default to true. See Issue 122*/
106
+        Win_CommConfig.dcb.fDtrControl=TRUE;
107
+        /*flush all settings*/
108
+        settingsDirtyFlags = DFE_ALL;
109
+        updatePortSettings();
110
+
111
+        //init event driven approach
112
+        if (_queryMode == QextSerialPort::EventDriven) {
113
+            if (!SetCommMask( Win_Handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) {
114
+                QESP_WARNING()<<"failed to set Comm Mask. Error code:"<<GetLastError();
115
+                return false;
116
+            }
117
+            winEventNotifier = new WinEventNotifier(overlap.hEvent, q);
118
+            qRegisterMetaType<HANDLE>("HANDLE");
119
+            q->connect(winEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onWinEvent(HANDLE)), Qt::DirectConnection);
120
+            WaitCommEvent(Win_Handle, &eventMask, &overlap);
121
+        }
122
+        return true;
123
+    }
124
+    return false;
125
+}
126
+
127
+bool QextSerialPortPrivate::close_sys()
128
+{
129
+    flush_sys();
130
+    CancelIo(Win_Handle);
131
+    if (CloseHandle(Win_Handle))
132
+        Win_Handle = INVALID_HANDLE_VALUE;
133
+    if (winEventNotifier){
134
+        winEventNotifier->setEnabled(false);
135
+        winEventNotifier->deleteLater();
136
+        winEventNotifier = 0;
137
+    }
138
+    _bytesToWrite = 0;
139
+
140
+    foreach(OVERLAPPED* o, pendingWrites) {
141
+        CloseHandle(o->hEvent);
142
+        delete o;
143
+    }
144
+    pendingWrites.clear();
145
+    return true;
146
+}
147
+
148
+bool QextSerialPortPrivate::flush_sys()
149
+{
150
+    FlushFileBuffers(Win_Handle);
151
+    return true;
152
+}
153
+
154
+qint64 QextSerialPortPrivate::bytesAvailable_sys() const
155
+{
156
+    DWORD Errors;
157
+    COMSTAT Status;
158
+    if (ClearCommError(Win_Handle, &Errors, &Status)) {
159
+        return Status.cbInQue;
160
+    }
161
+    return (qint64)-1;
162
+}
163
+
164
+/*
165
+    Translates a system-specific error code to a QextSerialPort error code.  Used internally.
166
+*/
167
+void QextSerialPortPrivate::translateError(ulong error)
168
+{
169
+    if (error&CE_BREAK) {
170
+        lastErr=E_BREAK_CONDITION;
171
+    }
172
+    else if (error&CE_FRAME) {
173
+        lastErr=E_FRAMING_ERROR;
174
+    }
175
+    else if (error&CE_IOE) {
176
+        lastErr=E_IO_ERROR;
177
+    }
178
+    else if (error&CE_MODE) {
179
+        lastErr=E_INVALID_FD;
180
+    }
181
+    else if (error&CE_OVERRUN) {
182
+        lastErr=E_BUFFER_OVERRUN;
183
+    }
184
+    else if (error&CE_RXPARITY) {
185
+        lastErr=E_RECEIVE_PARITY_ERROR;
186
+    }
187
+    else if (error&CE_RXOVER) {
188
+        lastErr=E_RECEIVE_OVERFLOW;
189
+    }
190
+    else if (error&CE_TXFULL) {
191
+        lastErr=E_TRANSMIT_OVERFLOW;
192
+    }
193
+}
194
+
195
+/*
196
+    Reads a block of data from the serial port.  This function will read at most maxlen bytes from
197
+    the serial port and place them in the buffer pointed to by data.  Return value is the number of
198
+    bytes actually read, or -1 on error.
199
+    
200
+    \warning before calling this function ensure that serial port associated with this class
201
+    is currently open (use isOpen() function to check if port is open).
202
+*/
203
+qint64 QextSerialPortPrivate::readData_sys(char *data, qint64 maxSize)
204
+{
205
+    DWORD bytesRead = 0;
206
+    bool failed = false;
207
+    if (_queryMode == QextSerialPort::EventDriven) {
208
+        OVERLAPPED overlapRead;
209
+        ZeroMemory(&overlapRead, sizeof(OVERLAPPED));
210
+        if (!ReadFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesRead, & overlapRead)) {
211
+            if (GetLastError() == ERROR_IO_PENDING)
212
+                GetOverlappedResult(Win_Handle, & overlapRead, & bytesRead, true);
213
+            else
214
+                failed = true;
215
+        }
216
+    } else if (!ReadFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesRead, NULL)) {
217
+        failed = true;
218
+    }
219
+    if (!failed)
220
+        return (qint64)bytesRead;
221
+
222
+    lastErr = E_READ_FAILED;
223
+    return -1;
224
+}
225
+
226
+/*
227
+    Writes a block of data to the serial port.  This function will write len bytes
228
+    from the buffer pointed to by data to the serial port.  Return value is the number
229
+    of bytes actually written, or -1 on error.
230
+    
231
+    \warning before calling this function ensure that serial port associated with this class
232
+    is currently open (use isOpen() function to check if port is open).
233
+*/
234
+qint64 QextSerialPortPrivate::writeData_sys(const char *data, qint64 maxSize)
235
+{
236
+    DWORD bytesWritten = 0;
237
+    bool failed = false;
238
+    if (_queryMode == QextSerialPort::EventDriven) {
239
+        OVERLAPPED* newOverlapWrite = new OVERLAPPED;
240
+        ZeroMemory(newOverlapWrite, sizeof(OVERLAPPED));
241
+        newOverlapWrite->hEvent = CreateEvent(NULL, true, false, NULL);
242
+        if (WriteFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesWritten, newOverlapWrite)) {
243
+            CloseHandle(newOverlapWrite->hEvent);
244
+            delete newOverlapWrite;
245
+        }
246
+        else if (GetLastError() == ERROR_IO_PENDING) {
247
+            // writing asynchronously...not an error
248
+            QWriteLocker writelocker(bytesToWriteLock);
249
+            _bytesToWrite += maxSize;
250
+            pendingWrites.append(newOverlapWrite);
251
+        }
252
+        else {
253
+            QESP_WARNING()<<"QextSerialPort write error:"<<GetLastError();
254
+            failed = true;
255
+            if(!CancelIo(newOverlapWrite->hEvent))
256
+                QESP_WARNING("QextSerialPort: couldn't cancel IO");
257
+            if(!CloseHandle(newOverlapWrite->hEvent))
258
+                QESP_WARNING("QextSerialPort: couldn't close OVERLAPPED handle");
259
+            delete newOverlapWrite;
260
+        }
261
+    } else if (!WriteFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesWritten, NULL)) {
262
+        failed = true;
263
+    }
264
+
265
+    if (!failed)
266
+        return (qint64)bytesWritten;
267
+
268
+    lastErr = E_WRITE_FAILED;
269
+    return -1;
270
+}
271
+
272
+void QextSerialPortPrivate::setDtr_sys(bool set) {
273
+    EscapeCommFunction(Win_Handle, set ? SETDTR : CLRDTR);
274
+}
275
+
276
+void QextSerialPortPrivate::setRts_sys(bool set) {
277
+    EscapeCommFunction(Win_Handle, set ? SETRTS : CLRRTS);
278
+}
279
+
280
+ulong QextSerialPortPrivate::lineStatus_sys(void) {
281
+    unsigned long Status=0, Temp=0;
282
+    GetCommModemStatus(Win_Handle, &Temp);
283
+    if (Temp & MS_CTS_ON) Status|=LS_CTS;
284
+    if (Temp & MS_DSR_ON) Status|=LS_DSR;
285
+    if (Temp & MS_RING_ON) Status|=LS_RI;
286
+    if (Temp & MS_RLSD_ON) Status|=LS_DCD;
287
+    return Status;
288
+}
289
+
290
+/*
291
+  Triggered when there's activity on our HANDLE.
292
+*/
293
+void QextSerialPortPrivate::_q_onWinEvent(HANDLE h)
294
+{
295
+    Q_Q(QextSerialPort);
296
+    if(h == overlap.hEvent) {
297
+        if (eventMask & EV_RXCHAR) {
298
+            if (q->sender() != q && bytesAvailable_sys() > 0)
299
+                _q_canRead();
300
+        }
301
+        if (eventMask & EV_TXEMPTY) {
302
+            /*
303
+              A write completed.  Run through the list of OVERLAPPED writes, and if
304
+              they completed successfully, take them off the list and delete them.
305
+              Otherwise, leave them on there so they can finish.
306
+            */
307
+            qint64 totalBytesWritten = 0;
308
+            QList<OVERLAPPED*> overlapsToDelete;
309
+            foreach(OVERLAPPED* o, pendingWrites) {
310
+                DWORD numBytes = 0;
311
+                if (GetOverlappedResult(Win_Handle, o, & numBytes, false)) {
312
+                    overlapsToDelete.append(o);
313
+                    totalBytesWritten += numBytes;
314
+                } else if( GetLastError() != ERROR_IO_INCOMPLETE ) {
315
+                    overlapsToDelete.append(o);
316
+                    QESP_WARNING()<<"CommEvent overlapped write error:" << GetLastError();
317
+                }
318
+            }
319
+
320
+            if (q->sender() != q && totalBytesWritten > 0) {
321
+                QWriteLocker writelocker(bytesToWriteLock);
322
+                Q_EMIT q->bytesWritten(totalBytesWritten);
323
+                _bytesToWrite = 0;
324
+            }
325
+
326
+            foreach(OVERLAPPED* o, overlapsToDelete) {
327
+                OVERLAPPED *toDelete = pendingWrites.takeAt(pendingWrites.indexOf(o));
328
+                CloseHandle(toDelete->hEvent);
329
+                delete toDelete;
330
+            }
331
+        }
332
+        if (eventMask & EV_DSR) {
333
+            if (lineStatus_sys() & LS_DSR)
334
+                Q_EMIT q->dsrChanged(true);
335
+            else
336
+                Q_EMIT q->dsrChanged(false);
337
+        }
338
+    }
339
+    WaitCommEvent(Win_Handle, &eventMask, &overlap);
340
+}
341
+
342
+void QextSerialPortPrivate::updatePortSettings()
343
+{
344
+    if (!q_ptr->isOpen() || !settingsDirtyFlags)
345
+        return;
346
+
347
+    //fill struct : COMMCONFIG
348
+    if (settingsDirtyFlags & DFE_BaudRate) {
349
+        Win_CommConfig.dcb.BaudRate = Settings.BaudRate;
350
+    }
351
+    if (settingsDirtyFlags & DFE_Parity) {
352
+        Win_CommConfig.dcb.Parity = (BYTE)Settings.Parity;
353
+        Win_CommConfig.dcb.fParity = (Settings.Parity == PAR_NONE) ? FALSE : TRUE;
354
+    }
355
+    if (settingsDirtyFlags & DFE_DataBits) {
356
+        Win_CommConfig.dcb.ByteSize = (BYTE)Settings.DataBits;
357
+    }
358
+    if (settingsDirtyFlags & DFE_StopBits) {
359
+        switch (Settings.StopBits) {
360
+        case STOP_1:
361
+            Win_CommConfig.dcb.StopBits = ONESTOPBIT;
362
+            break;
363
+        case STOP_1_5:
364
+            Win_CommConfig.dcb.StopBits = ONE5STOPBITS;
365
+            break;
366
+        case STOP_2:
367
+            Win_CommConfig.dcb.StopBits = TWOSTOPBITS;
368
+            break;
369
+        }
370
+    }
371
+    if (settingsDirtyFlags & DFE_Flow) {
372
+        switch(Settings.FlowControl) {
373
+        /*no flow control*/
374
+        case FLOW_OFF:
375
+            Win_CommConfig.dcb.fOutxCtsFlow=FALSE;
376
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE;
377
+            Win_CommConfig.dcb.fInX=FALSE;
378
+            Win_CommConfig.dcb.fOutX=FALSE;
379
+            break;
380
+        /*software (XON/XOFF) flow control*/
381
+        case FLOW_XONXOFF:
382
+            Win_CommConfig.dcb.fOutxCtsFlow=FALSE;
383
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE;
384
+            Win_CommConfig.dcb.fInX=TRUE;
385
+            Win_CommConfig.dcb.fOutX=TRUE;
386
+            break;
387
+        /*hardware flow control*/
388
+        case FLOW_HARDWARE:
389
+            Win_CommConfig.dcb.fOutxCtsFlow=TRUE;
390
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
391
+            Win_CommConfig.dcb.fInX=FALSE;
392
+            Win_CommConfig.dcb.fOutX=FALSE;
393
+            break;
394
+        }
395
+    }
396
+
397
+    //fill struct : COMMTIMEOUTS
398
+    if (settingsDirtyFlags & DFE_TimeOut) {
399
+        if (_queryMode != QextSerialPort::EventDriven) {
400
+            int millisec = Settings.Timeout_Millisec;
401
+            if (millisec == -1) {
402
+                Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD;
403
+                Win_CommTimeouts.ReadTotalTimeoutConstant = 0;
404
+            } else {
405
+                Win_CommTimeouts.ReadIntervalTimeout = millisec;
406
+                Win_CommTimeouts.ReadTotalTimeoutConstant = millisec;
407
+            }
408
+            Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
409
+            Win_CommTimeouts.WriteTotalTimeoutMultiplier = millisec;
410
+            Win_CommTimeouts.WriteTotalTimeoutConstant = 0;
411
+        }
412
+        else {
413
+            Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD;
414
+            Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
415
+            Win_CommTimeouts.ReadTotalTimeoutConstant = 0;
416
+            Win_CommTimeouts.WriteTotalTimeoutMultiplier = 0;
417
+            Win_CommTimeouts.WriteTotalTimeoutConstant = 0;
418
+        }
419
+    }
420
+
421
+
422
+    if (settingsDirtyFlags & DFE_Settings_Mask)
423
+        SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG));
424
+    if ((settingsDirtyFlags & DFE_TimeOut))
425
+        SetCommTimeouts(Win_Handle, &Win_CommTimeouts);
426
+    settingsDirtyFlags = 0;
427
+}

+ 414
- 0
src/3rdparty/qextserialport/src/extserialport/qextserialport_win.cpp.orig View File

@@ -0,0 +1,414 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialport.h"
33
+#include "qextserialport_p.h"
34
+#include <QtCore/QThread>
35
+#include <QtCore/QReadWriteLock>
36
+#include <QtCore/QMutexLocker>
37
+#include <QtCore/QDebug>
38
+#include <QtCore/QRegExp>
39
+#include <QtCore/QMetaType>
40
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
41
+#  include <QtCore/private/qwineventnotifier_p.h>
42
+#else
43
+#  include <QtCore/QWinEventNotifier>
44
+#endif
45
+
46
+void QextSerialPortPrivate::platformSpecificInit()
47
+{
48
+    Win_Handle=INVALID_HANDLE_VALUE;
49
+    ZeroMemory(&overlap, sizeof(OVERLAPPED));
50
+    overlap.hEvent = CreateEvent(NULL, true, false, NULL);
51
+    winEventNotifier = 0;
52
+    bytesToWriteLock = new QReadWriteLock;
53
+    _bytesToWrite = 0;
54
+}
55
+
56
+void QextSerialPortPrivate::platformSpecificDestruct() {
57
+    CloseHandle(overlap.hEvent);
58
+    delete bytesToWriteLock;
59
+}
60
+
61
+
62
+/*!
63
+    \internal
64
+    COM ports greater than 9 need \\.\ prepended
65
+
66
+    This is only need when open the port.
67
+*/
68
+static QString fullPortNameWin(const QString & name)
69
+{
70
+    QRegExp rx(QLatin1String("^COM(\\d+)"));
71
+    QString fullName(name);
72
+    if(fullName.contains(rx))
73
+        fullName.prepend(QLatin1String("\\\\.\\"));
74
+    return fullName;
75
+}
76
+
77
+bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode)
78
+{
79
+    Q_Q(QextSerialPort);
80
+    DWORD confSize = sizeof(COMMCONFIG);
81
+    Win_CommConfig.dwSize = confSize;
82
+    DWORD dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED;
83
+
84
+    /*open the port*/
85
+    Win_Handle=CreateFileW((wchar_t*)fullPortNameWin(port).utf16(), GENERIC_READ|GENERIC_WRITE,
86
+                           0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL);
87
+    if (Win_Handle!=INVALID_HANDLE_VALUE) {
88
+        q->setOpenMode(mode);
89
+        /*configure port settings*/
90
+        GetCommConfig(Win_Handle, &Win_CommConfig, &confSize);
91
+        GetCommState(Win_Handle, &(Win_CommConfig.dcb));
92
+
93
+        /*set up parameters*/
94
+        Win_CommConfig.dcb.fBinary=TRUE;
95
+        Win_CommConfig.dcb.fInX=FALSE;
96
+        Win_CommConfig.dcb.fOutX=FALSE;
97
+        Win_CommConfig.dcb.fAbortOnError=FALSE;
98
+        Win_CommConfig.dcb.fNull=FALSE;
99
+        /* Dtr default to true. See Issue 122*/
100
+        Win_CommConfig.dcb.fDtrControl=TRUE;
101
+        /*flush all settings*/
102
+        settingsDirtyFlags = DFE_ALL;
103
+        updatePortSettings();
104
+
105
+        //init event driven approach
106
+<<<<<<< local
107
+        if (_queryMode == QextSerialPort::EventDriven) {
108
+            if (!SetCommMask( Win_Handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) {
109
+                QESP_WARNING()<<"failed to set Comm Mask. Error code:"<<GetLastError();
110
+                return false;
111
+            }
112
+            winEventNotifier = new WinEventNotifier(overlap.hEvent);
113
+            qRegisterMetaType<HANDLE>("HANDLE");
114
+            q->connect(winEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onWinEvent(HANDLE)), Qt::DirectConnection);
115
+            WaitCommEvent(Win_Handle, &eventMask, &overlap);
116
+=======
117
+        if (!SetCommMask( Win_Handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) {
118
+            QESP_WARNING()<<"failed to set Comm Mask. Error code:"<<GetLastError();
119
+            return false;
120
+>>>>>>> other
121
+        }
122
+        winEventNotifier = new QWinEventNotifier(overlap.hEvent, q);
123
+        qRegisterMetaType<HANDLE>("HANDLE");
124
+        q->connect(winEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onWinEvent(HANDLE)), Qt::DirectConnection);
125
+        WaitCommEvent(Win_Handle, &eventMask, &overlap);
126
+        return true;
127
+    }
128
+    return false;
129
+}
130
+
131
+bool QextSerialPortPrivate::close_sys()
132
+{
133
+    flush_sys();
134
+    CancelIo(Win_Handle);
135
+    if (CloseHandle(Win_Handle))
136
+        Win_Handle = INVALID_HANDLE_VALUE;
137
+    if (winEventNotifier){
138
+        winEventNotifier->setEnabled(false);
139
+        winEventNotifier->deleteLater();
140
+        winEventNotifier = 0;
141
+    }
142
+    _bytesToWrite = 0;
143
+
144
+    foreach(OVERLAPPED* o, pendingWrites) {
145
+        CloseHandle(o->hEvent);
146
+        delete o;
147
+    }
148
+    pendingWrites.clear();
149
+    return true;
150
+}
151
+
152
+bool QextSerialPortPrivate::flush_sys()
153
+{
154
+    FlushFileBuffers(Win_Handle);
155
+    return true;
156
+}
157
+
158
+qint64 QextSerialPortPrivate::bytesAvailable_sys() const
159
+{
160
+    DWORD Errors;
161
+    COMSTAT Status;
162
+    if (ClearCommError(Win_Handle, &Errors, &Status)) {
163
+        return Status.cbInQue;
164
+    }
165
+    return (qint64)-1;
166
+}
167
+
168
+/*
169
+    Translates a system-specific error code to a QextSerialPort error code.  Used internally.
170
+*/
171
+void QextSerialPortPrivate::translateError(ulong error) {
172
+    if (error&CE_BREAK) {
173
+        lastErr=QextSerialPort::E_BREAK_CONDITION;
174
+    }
175
+    else if (error&CE_FRAME) {
176
+        lastErr=QextSerialPort::E_FRAMING_ERROR;
177
+    }
178
+    else if (error&CE_IOE) {
179
+        lastErr=QextSerialPort::E_IO_ERROR;
180
+    }
181
+    else if (error&CE_MODE) {
182
+        lastErr=QextSerialPort::E_INVALID_FD;
183
+    }
184
+    else if (error&CE_OVERRUN) {
185
+        lastErr=QextSerialPort::E_BUFFER_OVERRUN;
186
+    }
187
+    else if (error&CE_RXPARITY) {
188
+        lastErr=QextSerialPort::E_RECEIVE_PARITY_ERROR;
189
+    }
190
+    else if (error&CE_RXOVER) {
191
+        lastErr=QextSerialPort::E_RECEIVE_OVERFLOW;
192
+    }
193
+    else if (error&CE_TXFULL) {
194
+        lastErr=QextSerialPort::E_TRANSMIT_OVERFLOW;
195
+    }
196
+}
197
+
198
+/*
199
+    Reads a block of data from the serial port.  This function will read at most maxlen bytes from
200
+    the serial port and place them in the buffer pointed to by data.  Return value is the number of
201
+    bytes actually read, or -1 on error.
202
+    
203
+    \warning before calling this function ensure that serial port associated with this class
204
+    is currently open (use isOpen() function to check if port is open).
205
+*/
206
+qint64 QextSerialPortPrivate::readData_sys(char *data, qint64 maxSize)
207
+{
208
+    DWORD bytesRead = 0;
209
+    bool failed = false;
210
+    OVERLAPPED overlapRead;
211
+    ZeroMemory(&overlapRead, sizeof(OVERLAPPED));
212
+    if (!ReadFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesRead, & overlapRead)) {
213
+        if (GetLastError() == ERROR_IO_PENDING)
214
+            GetOverlappedResult(Win_Handle, & overlapRead, & bytesRead, true);
215
+        else
216
+            failed = true;
217
+    }
218
+
219
+    if (!failed)
220
+        return (qint64)bytesRead;
221
+
222
+    lastErr = QextSerialPort::E_READ_FAILED;
223
+    return -1;
224
+}
225
+
226
+/*
227
+    Writes a block of data to the serial port.  This function will write len bytes
228
+    from the buffer pointed to by data to the serial port.  Return value is the number
229
+    of bytes actually written, or -1 on error.
230
+    
231
+    \warning before calling this function ensure that serial port associated with this class
232
+    is currently open (use isOpen() function to check if port is open).
233
+*/
234
+qint64 QextSerialPortPrivate::writeData_sys(const char *data, qint64 maxSize)
235
+{
236
+    DWORD bytesWritten = 0;
237
+    bool failed = false;
238
+    OVERLAPPED* newOverlapWrite = new OVERLAPPED;
239
+    ZeroMemory(newOverlapWrite, sizeof(OVERLAPPED));
240
+    newOverlapWrite->hEvent = CreateEvent(NULL, true, false, NULL);
241
+    if (WriteFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesWritten, newOverlapWrite)) {
242
+        CloseHandle(newOverlapWrite->hEvent);
243
+        delete newOverlapWrite;
244
+    }
245
+    else if (GetLastError() == ERROR_IO_PENDING) {
246
+        // writing asynchronously...not an error
247
+        QWriteLocker writelocker(bytesToWriteLock);
248
+        _bytesToWrite += maxSize;
249
+        pendingWrites.append(newOverlapWrite);
250
+    }
251
+    else {
252
+        QESP_WARNING()<<"QextSerialPort write error:"<<GetLastError();
253
+        failed = true;
254
+        if(!CancelIo(newOverlapWrite->hEvent))
255
+            QESP_WARNING("QextSerialPort: couldn't cancel IO");
256
+        if(!CloseHandle(newOverlapWrite->hEvent))
257
+            QESP_WARNING("QextSerialPort: couldn't close OVERLAPPED handle");
258
+        delete newOverlapWrite;
259
+    }
260
+
261
+    if (!failed)
262
+        return (qint64)bytesWritten;
263
+
264
+    lastErr = QextSerialPort::E_WRITE_FAILED;
265
+    return -1;
266
+}
267
+
268
+void QextSerialPortPrivate::setDtr_sys(bool set) {
269
+    EscapeCommFunction(Win_Handle, set ? SETDTR : CLRDTR);
270
+}
271
+
272
+void QextSerialPortPrivate::setRts_sys(bool set) {
273
+    EscapeCommFunction(Win_Handle, set ? SETRTS : CLRRTS);
274
+}
275
+
276
+ulong QextSerialPortPrivate::lineStatus_sys(void) {
277
+    unsigned long Status=0, Temp=0;
278
+    GetCommModemStatus(Win_Handle, &Temp);
279
+    if (Temp & MS_CTS_ON) Status|=QextSerialPort::LS_CTS;
280
+    if (Temp & MS_DSR_ON) Status|=QextSerialPort::LS_DSR;
281
+    if (Temp & MS_RING_ON) Status|=QextSerialPort::LS_RI;
282
+    if (Temp & MS_RLSD_ON) Status|=QextSerialPort::LS_DCD;
283
+    return Status;
284
+}
285
+
286
+/*
287
+  Triggered when there's activity on our HANDLE.
288
+*/
289
+void QextSerialPortPrivate::_q_onWinEvent(HANDLE h)
290
+{
291
+    Q_Q(QextSerialPort);
292
+    if(h == overlap.hEvent) {
293
+        if (eventMask & EV_RXCHAR) {
294
+            if (q->sender() != q && bytesAvailable_sys() > 0)
295
+                _q_canRead();
296
+        }
297
+        if (eventMask & EV_TXEMPTY) {
298
+            /*
299
+              A write completed.  Run through the list of OVERLAPPED writes, and if
300
+              they completed successfully, take them off the list and delete them.
301
+              Otherwise, leave them on there so they can finish.
302
+            */
303
+            qint64 totalBytesWritten = 0;
304
+            QList<OVERLAPPED*> overlapsToDelete;
305
+            foreach(OVERLAPPED* o, pendingWrites) {
306
+                DWORD numBytes = 0;
307
+                if (GetOverlappedResult(Win_Handle, o, & numBytes, false)) {
308
+                    overlapsToDelete.append(o);
309
+                    totalBytesWritten += numBytes;
310
+                } else if( GetLastError() != ERROR_IO_INCOMPLETE ) {
311
+                    overlapsToDelete.append(o);
312
+                    QESP_WARNING()<<"CommEvent overlapped write error:" << GetLastError();
313
+                }
314
+            }
315
+
316
+            if (q->sender() != q && totalBytesWritten > 0) {
317
+                QWriteLocker writelocker(bytesToWriteLock);
318
+                Q_EMIT q->bytesWritten(totalBytesWritten);
319
+                _bytesToWrite = 0;
320
+            }
321
+
322
+            foreach(OVERLAPPED* o, overlapsToDelete) {
323
+                OVERLAPPED *toDelete = pendingWrites.takeAt(pendingWrites.indexOf(o));
324
+                CloseHandle(toDelete->hEvent);
325
+                delete toDelete;
326
+            }
327
+        }
328
+        if (eventMask & EV_DSR) {
329
+            if (lineStatus_sys() & QextSerialPort::LS_DSR)
330
+                Q_EMIT q->dsrChanged(true);
331
+            else
332
+                Q_EMIT q->dsrChanged(false);
333
+        }
334
+    }
335
+    WaitCommEvent(Win_Handle, &eventMask, &overlap);
336
+}
337
+
338
+void QextSerialPortPrivate::updatePortSettings()
339
+{
340
+    if (!q_ptr->isOpen() || !settingsDirtyFlags)
341
+        return;
342
+
343
+    //fill struct : COMMCONFIG
344
+    if (settingsDirtyFlags & DFE_BaudRate) {
345
+        Win_CommConfig.dcb.BaudRate = Settings.BaudRate;
346
+    }
347
+    if (settingsDirtyFlags & DFE_Parity) {
348
+        Win_CommConfig.dcb.Parity = (BYTE)Settings.Parity;
349
+        Win_CommConfig.dcb.fParity = (Settings.Parity == QextSerialPort::PAR_NONE) ? FALSE : TRUE;
350
+    }
351
+    if (settingsDirtyFlags & DFE_DataBits) {
352
+        Win_CommConfig.dcb.ByteSize = (BYTE)Settings.DataBits;
353
+    }
354
+    if (settingsDirtyFlags & DFE_StopBits) {
355
+        switch (Settings.StopBits) {
356
+        case QextSerialPort::STOP_1:
357
+            Win_CommConfig.dcb.StopBits = ONESTOPBIT;
358
+            break;
359
+        case QextSerialPort::STOP_1_5:
360
+            Win_CommConfig.dcb.StopBits = ONE5STOPBITS;
361
+            break;
362
+        case QextSerialPort::STOP_2:
363
+            Win_CommConfig.dcb.StopBits = TWOSTOPBITS;
364
+            break;
365
+        }
366
+    }
367
+    if (settingsDirtyFlags & DFE_Flow) {
368
+        switch(Settings.FlowControl) {
369
+        /*no flow control*/
370
+        case QextSerialPort::FLOW_OFF:
371
+            Win_CommConfig.dcb.fOutxCtsFlow=FALSE;
372
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE;
373
+            Win_CommConfig.dcb.fInX=FALSE;
374
+            Win_CommConfig.dcb.fOutX=FALSE;
375
+            break;
376
+        /*software (XON/XOFF) flow control*/
377
+        case QextSerialPort::FLOW_XONXOFF:
378
+            Win_CommConfig.dcb.fOutxCtsFlow=FALSE;
379
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE;
380
+            Win_CommConfig.dcb.fInX=TRUE;
381
+            Win_CommConfig.dcb.fOutX=TRUE;
382
+            break;
383
+        /*hardware flow control*/
384
+        case QextSerialPort::FLOW_HARDWARE:
385
+            Win_CommConfig.dcb.fOutxCtsFlow=TRUE;
386
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
387
+            Win_CommConfig.dcb.fInX=FALSE;
388
+            Win_CommConfig.dcb.fOutX=FALSE;
389
+            break;
390
+        }
391
+    }
392
+
393
+    //fill struct : COMMTIMEOUTS
394
+    if (settingsDirtyFlags & DFE_TimeOut) {
395
+        int millisec = Settings.Timeout_Millisec;
396
+        if (millisec == -1) {
397
+            Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD;
398
+            Win_CommTimeouts.ReadTotalTimeoutConstant = 0;
399
+        } else {
400
+            Win_CommTimeouts.ReadIntervalTimeout = millisec;
401
+            Win_CommTimeouts.ReadTotalTimeoutConstant = millisec;
402
+        }
403
+        Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
404
+        Win_CommTimeouts.WriteTotalTimeoutMultiplier = millisec;
405
+        Win_CommTimeouts.WriteTotalTimeoutConstant = 0;
406
+    }
407
+
408
+
409
+    if (settingsDirtyFlags & DFE_Settings_Mask)
410
+        SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG));
411
+    if ((settingsDirtyFlags & DFE_TimeOut))
412
+        SetCommTimeouts(Win_Handle, &Win_CommTimeouts);
413
+    settingsDirtyFlags = 0;
414
+}

+ 167
- 0
src/3rdparty/qextserialport/src/qextserialenumerator.cpp View File

@@ -0,0 +1,167 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialenumerator.h"
33
+#include "qextserialenumerator_p.h"
34
+
35
+#include <QtCore/QDebug>
36
+#include <QtCore/QMetaType>
37
+#include <QtCore/QRegExp>
38
+
39
+QextSerialEnumeratorPrivate::QextSerialEnumeratorPrivate(QextSerialEnumerator *enumrator)
40
+    :q_ptr(enumrator)
41
+{
42
+    platformSpecificInit();
43
+}
44
+
45
+QextSerialEnumeratorPrivate::~QextSerialEnumeratorPrivate()
46
+{
47
+    platformSpecificDestruct();
48
+}
49
+
50
+/*!
51
+  \class QextPortInfo
52
+
53
+  \brief The QextPortInfo class containing port information.
54
+
55
+  Structure containing port information.
56
+
57
+  \code
58
+  QString portName;   ///< Port name.
59
+  QString physName;   ///< Physical name.
60
+  QString friendName; ///< Friendly name.
61
+  QString enumName;   ///< Enumerator name.
62
+  int vendorID;       ///< Vendor ID.
63
+  int productID;      ///< Product ID
64
+  \endcode
65
+ */
66
+
67
+/*! \class QextSerialEnumerator
68
+
69
+    \brief The QextSerialEnumerator class provides list of ports available in the system.
70
+  
71
+    \section1 Usage
72
+    To poll the system for a list of connected devices, simply use getPorts().  Each
73
+    QextPortInfo structure will populated with information about the corresponding device.
74
+  
75
+    \bold Example
76
+    \code
77
+    QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();
78
+    foreach( QextPortInfo port, ports ) {
79
+        // inspect port...
80
+    }
81
+    \endcode
82
+  
83
+    To enable event-driven notification of device connection events, first call
84
+    setUpNotifications() and then connect to the deviceDiscovered() and deviceRemoved()
85
+    signals.  Event-driven behavior is currently available only on Windows and OS X.
86
+  
87
+    \bold Example
88
+    \code
89
+    QextSerialEnumerator* enumerator = new QextSerialEnumerator();
90
+    connect(enumerator, SIGNAL(deviceDiscovered(const QextPortInfo &)),
91
+               myClass, SLOT(onDeviceDiscovered(const QextPortInfo &)));
92
+    connect(enumerator, SIGNAL(deviceRemoved(const QextPortInfo &)),
93
+               myClass, SLOT(onDeviceRemoved(const QextPortInfo &)));
94
+    \endcode
95
+  
96
+    \section1 Credits
97
+    Windows implementation is based on Zach Gorman's work from
98
+    \l {http://www.codeproject.com}{The Code Project} (\l http://www.codeproject.com/system/setupdi.asp).
99
+  
100
+    OS X implementation, see \l http://developer.apple.com/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Finding_Devices/chapter_4_section_2.html
101
+  
102
+    \bold author Michal Policht, Liam Staskawicz
103
+*/
104
+
105
+/*!
106
+    \fn void QextSerialEnumerator::deviceDiscovered( const QextPortInfo & info )
107
+    A new device has been connected to the system.
108
+  
109
+    setUpNotifications() must be called first to enable event-driven device notifications.
110
+    Currently only implemented on Windows and OS X.
111
+  
112
+    \a info The device that has been discovered.
113
+*/
114
+
115
+/*!
116
+   \fn void QextSerialEnumerator::deviceRemoved( const QextPortInfo & info );
117
+    A device has been disconnected from the system.
118
+  
119
+    setUpNotifications() must be called first to enable event-driven device notifications.
120
+    Currently only implemented on Windows and OS X.
121
+  
122
+    \a info The device that was disconnected.
123
+*/
124
+
125
+/*!
126
+   Constructs a QextSerialEnumerator object with the given \a parent.
127
+*/
128
+QextSerialEnumerator::QextSerialEnumerator(QObject *parent)
129
+    :QObject(parent), d_ptr(new QextSerialEnumeratorPrivate(this))
130
+{
131
+    if( !QMetaType::isRegistered( QMetaType::type("QextPortInfo") ) )
132
+        qRegisterMetaType<QextPortInfo>("QextPortInfo");
133
+}
134
+
135
+/*!
136
+   Destructs the QextSerialEnumerator object.
137
+*/
138
+QextSerialEnumerator::~QextSerialEnumerator( )
139
+{
140
+    delete d_ptr;
141
+}
142
+
143
+/*!
144
+    Get list of ports.
145
+
146
+    return list of ports currently available in the system.
147
+*/
148
+QList<QextPortInfo> QextSerialEnumerator::getPorts()
149
+{
150
+#if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_MAC)
151
+    qCritical("Enumeration for POSIX systems (except Linux) is not implemented yet.");
152
+#endif
153
+    return QextSerialEnumeratorPrivate::getPorts_sys();
154
+}
155
+
156
+/*!
157
+    Enable event-driven notifications of board discovery/removal.
158
+*/
159
+void QextSerialEnumerator::setUpNotifications()
160
+{
161
+#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
162
+    qCritical("Notifications for *Nix/FreeBSD are not implemented yet");
163
+#endif
164
+    Q_D(QextSerialEnumerator);
165
+    if (!d->setUpNotifications_sys(true))
166
+        QESP_WARNING("Setup Notification Failed...");
167
+}

+ 69
- 0
src/3rdparty/qextserialport/src/qextserialenumerator.h View File

@@ -0,0 +1,69 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#ifndef _QEXTSERIALENUMERATOR_H_
33
+#define _QEXTSERIALENUMERATOR_H_
34
+
35
+#include <QtCore/QList>
36
+#include <QtCore/QObject>
37
+#include "qextserialport_global.h"
38
+
39
+struct QextPortInfo {
40
+    QString portName;   ///< Port name.
41
+    QString physName;   ///< Physical name.
42
+    QString friendName; ///< Friendly name.
43
+    QString enumName;   ///< Enumerator name.
44
+    int vendorID;       ///< Vendor ID.
45
+    int productID;      ///< Product ID
46
+};
47
+
48
+class QextSerialEnumeratorPrivate;
49
+class QEXTSERIALPORT_EXPORT QextSerialEnumerator : public QObject
50
+{
51
+    Q_OBJECT
52
+    Q_DECLARE_PRIVATE(QextSerialEnumerator)
53
+public:
54
+    QextSerialEnumerator(QObject * parent=0);
55
+    ~QextSerialEnumerator();
56
+
57
+    static QList<QextPortInfo> getPorts();
58
+    void setUpNotifications();
59
+
60
+Q_SIGNALS:
61
+    void deviceDiscovered(const QextPortInfo & info);
62
+    void deviceRemoved(const QextPortInfo & info);
63
+
64
+private:
65
+    Q_DISABLE_COPY(QextSerialEnumerator)
66
+    QextSerialEnumeratorPrivate *d_ptr;
67
+};
68
+
69
+#endif /*_QEXTSERIALENUMERATOR_H_*/

+ 313
- 0
src/3rdparty/qextserialport/src/qextserialenumerator_osx.cpp View File

@@ -0,0 +1,313 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialenumerator.h"
33
+#include "qextserialenumerator_p.h"
34
+#include <QtCore/QDebug>
35
+#include <IOKit/serial/IOSerialKeys.h>
36
+#include <CoreFoundation/CFNumber.h>
37
+#include <sys/param.h>
38
+
39
+void QextSerialEnumeratorPrivate::platformSpecificInit()
40
+{
41
+}
42
+
43
+void QextSerialEnumeratorPrivate::platformSpecificDestruct()
44
+{
45
+    IONotificationPortDestroy( notificationPortRef );
46
+}
47
+
48
+// static
49
+QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
50
+{
51
+    QList<QextPortInfo> infoList;
52
+    io_iterator_t serialPortIterator = 0;
53
+    kern_return_t kernResult = KERN_FAILURE;
54
+    CFMutableDictionaryRef matchingDictionary;
55
+
56
+    // first try to get any serialbsd devices, then try any USBCDC devices
57
+    if( !(matchingDictionary = IOServiceMatching(kIOSerialBSDServiceValue) ) ) {
58
+        QESP_WARNING("IOServiceMatching returned a NULL dictionary.");
59
+        return infoList;
60
+    }
61
+    CFDictionaryAddValue(matchingDictionary, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
62
+
63
+    // then create the iterator with all the matching devices
64
+    if( IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &serialPortIterator) != KERN_SUCCESS ) {
65
+        qCritical() << "IOServiceGetMatchingServices failed, returned" << kernResult;
66
+        return infoList;
67
+    }
68
+    iterateServicesOSX(serialPortIterator, infoList);
69
+    IOObjectRelease(serialPortIterator);
70
+    serialPortIterator = 0;
71
+
72
+    if( !(matchingDictionary = IOServiceNameMatching("AppleUSBCDC")) ) {
73
+        QESP_WARNING("IOServiceNameMatching returned a NULL dictionary.");
74
+        return infoList;
75
+    }
76
+
77
+    if( IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &serialPortIterator) != KERN_SUCCESS ) {
78
+        qCritical() << "IOServiceGetMatchingServices failed, returned" << kernResult;
79
+        return infoList;
80
+    }
81
+    iterateServicesOSX(serialPortIterator, infoList);
82
+    IOObjectRelease(serialPortIterator);
83
+
84
+    return infoList;
85
+}
86
+
87
+void QextSerialEnumeratorPrivate::iterateServicesOSX(io_object_t service, QList<QextPortInfo> & infoList)
88
+{
89
+    // Iterate through all modems found.
90
+    io_object_t usbService;
91
+    while( ( usbService = IOIteratorNext(service) ) )
92
+    {
93
+        QextPortInfo info;
94
+        info.vendorID = 0;
95
+        info.productID = 0;
96
+        getServiceDetailsOSX( usbService, &info );
97
+        infoList.append(info);
98
+    }
99
+}
100
+
101
+bool QextSerialEnumeratorPrivate::getServiceDetailsOSX( io_object_t service, QextPortInfo* portInfo )
102
+{
103
+    bool retval = true;
104
+    CFTypeRef bsdPathAsCFString = NULL;
105
+    CFTypeRef productNameAsCFString = NULL;
106
+    CFTypeRef vendorIdAsCFNumber = NULL;
107
+    CFTypeRef productIdAsCFNumber = NULL;
108
+    // check the name of the modem's callout device
109
+    bsdPathAsCFString = IORegistryEntryCreateCFProperty(service, CFSTR(kIOCalloutDeviceKey),
110
+                                                        kCFAllocatorDefault, 0);
111
+
112
+    // wander up the hierarchy until we find the level that can give us the
113
+    // vendor/product IDs and the product name, if available
114
+    io_registry_entry_t parent;
115
+    kern_return_t kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
116
+    while( kernResult == KERN_SUCCESS && !vendorIdAsCFNumber && !productIdAsCFNumber )
117
+    {
118
+        if(!productNameAsCFString)
119
+            productNameAsCFString = IORegistryEntrySearchCFProperty(parent,
120
+                                                                    kIOServicePlane,
121
+                                                                    CFSTR("Product Name"),
122
+                                                                    kCFAllocatorDefault, 0);
123
+        vendorIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
124
+                                                             kIOServicePlane,
125
+                                                             CFSTR(kUSBVendorID),
126
+                                                             kCFAllocatorDefault, 0);
127
+        productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
128
+                                                              kIOServicePlane,
129
+                                                              CFSTR(kUSBProductID),
130
+                                                              kCFAllocatorDefault, 0);
131
+        io_registry_entry_t oldparent = parent;
132
+        kernResult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent);
133
+        IOObjectRelease(oldparent);
134
+    }
135
+
136
+    io_string_t ioPathName;
137
+    IORegistryEntryGetPath( service, kIOServicePlane, ioPathName );
138
+    portInfo->physName = ioPathName;
139
+
140
+    if( bsdPathAsCFString )
141
+    {
142
+        char path[MAXPATHLEN];
143
+        if( CFStringGetCString((CFStringRef)bsdPathAsCFString, path,
144
+                               PATH_MAX, kCFStringEncodingUTF8) )
145
+            portInfo->portName = path;
146
+        CFRelease(bsdPathAsCFString);
147
+    }
148
+
149
+    if(productNameAsCFString)
150
+    {
151
+        char productName[MAXPATHLEN];
152
+        if( CFStringGetCString((CFStringRef)productNameAsCFString, productName,
153
+                               PATH_MAX, kCFStringEncodingUTF8) )
154
+            portInfo->friendName = productName;
155
+        CFRelease(productNameAsCFString);
156
+    }
157
+
158
+    if(vendorIdAsCFNumber)
159
+    {
160
+        SInt32 vID;
161
+        if(CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberSInt32Type, &vID))
162
+            portInfo->vendorID = vID;
163
+        CFRelease(vendorIdAsCFNumber);
164
+    }
165
+
166
+    if(productIdAsCFNumber)
167
+    {
168
+        SInt32 pID;
169
+        if(CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberSInt32Type, &pID))
170
+            portInfo->productID = pID;
171
+        CFRelease(productIdAsCFNumber);
172
+    }
173
+    IOObjectRelease(service);
174
+    return retval;
175
+}
176
+
177
+// IOKit callbacks registered via setupNotifications()
178
+void deviceDiscoveredCallbackOSX( void *ctxt, io_iterator_t serialPortIterator )
179
+{
180
+    QextSerialEnumeratorPrivate* d = (QextSerialEnumeratorPrivate*)ctxt;
181
+    io_object_t serialService;
182
+    while ((serialService = IOIteratorNext(serialPortIterator)))
183
+        d->onDeviceDiscoveredOSX(serialService);
184
+}
185
+
186
+void deviceTerminatedCallbackOSX( void *ctxt, io_iterator_t serialPortIterator )
187
+{
188
+    QextSerialEnumeratorPrivate* d = (QextSerialEnumeratorPrivate*)ctxt;
189
+    io_object_t serialService;
190
+    while ((serialService = IOIteratorNext(serialPortIterator)))
191
+        d->onDeviceTerminatedOSX(serialService);
192
+}
193
+
194
+/*
195
+  A device has been discovered via IOKit.
196
+  Create a QextPortInfo if possible, and emit the signal indicating that we've found it.
197
+*/
198
+void QextSerialEnumeratorPrivate::onDeviceDiscoveredOSX( io_object_t service )
199
+{
200
+    Q_Q(QextSerialEnumerator);
201
+    QextPortInfo info;
202
+    info.vendorID = 0;
203
+    info.productID = 0;
204
+    if( getServiceDetailsOSX( service, &info ) )
205
+        Q_EMIT q->deviceDiscovered( info );
206
+}
207
+
208
+/*
209
+  Notification via IOKit that a device has been removed.
210
+  Create a QextPortInfo if possible, and emit the signal indicating that it's gone.
211
+*/
212
+void QextSerialEnumeratorPrivate::onDeviceTerminatedOSX( io_object_t service )
213
+{
214
+    Q_Q(QextSerialEnumerator);
215
+    QextPortInfo info;
216
+    info.vendorID = 0;
217
+    info.productID = 0;
218
+    if( getServiceDetailsOSX( service, &info ) )
219
+        Q_EMIT q->deviceRemoved( info );
220
+}
221
+
222
+/*
223
+  Create matching dictionaries for the devices we want to get notifications for,
224
+  and add them to the current run loop.  Invoke the callbacks that will be responding
225
+  to these notifications once to arm them, and discover any devices that
226
+  are currently connected at the time notifications are setup.
227
+*/
228
+bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
229
+{
230
+    kern_return_t kernResult;
231
+    mach_port_t masterPort;
232
+    CFRunLoopSourceRef notificationRunLoopSource;
233
+    CFMutableDictionaryRef classesToMatch;
234
+    CFMutableDictionaryRef cdcClassesToMatch;
235
+    io_iterator_t portIterator;
236
+
237
+    kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
238
+    if (KERN_SUCCESS != kernResult) {
239
+        qDebug() << "IOMasterPort returned:" << kernResult;
240
+        return false;
241
+    }
242
+
243
+    classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
244
+    if (classesToMatch == NULL)
245
+        qDebug("IOServiceMatching returned a NULL dictionary.");
246
+    else
247
+        CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
248
+
249
+    if( !(cdcClassesToMatch = IOServiceNameMatching("AppleUSBCDC") ) ) {
250
+        QESP_WARNING("couldn't create cdc matching dict");
251
+        return false;
252
+    }
253
+
254
+    // Retain an additional reference since each call to IOServiceAddMatchingNotification consumes one.
255
+    classesToMatch = (CFMutableDictionaryRef) CFRetain(classesToMatch);
256
+    cdcClassesToMatch = (CFMutableDictionaryRef) CFRetain(cdcClassesToMatch);
257
+
258
+    notificationPortRef = IONotificationPortCreate(masterPort);
259
+    if(notificationPortRef == NULL) {
260
+        qDebug("IONotificationPortCreate return a NULL IONotificationPortRef.");
261
+        return false;
262
+    }
263
+
264
+    notificationRunLoopSource = IONotificationPortGetRunLoopSource(notificationPortRef);
265
+    if (notificationRunLoopSource == NULL) {
266
+        qDebug("IONotificationPortGetRunLoopSource returned NULL CFRunLoopSourceRef.");
267
+        return false;
268
+    }
269
+
270
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), notificationRunLoopSource, kCFRunLoopDefaultMode);
271
+
272
+    kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOMatchedNotification, classesToMatch,
273
+                                                  deviceDiscoveredCallbackOSX, this, &portIterator);
274
+    if (kernResult != KERN_SUCCESS) {
275
+        qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
276
+        return false;
277
+    }
278
+
279
+    // arm the callback, and grab any devices that are already connected
280
+    deviceDiscoveredCallbackOSX( this, portIterator );
281
+
282
+    kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOMatchedNotification, cdcClassesToMatch,
283
+                                                  deviceDiscoveredCallbackOSX, this, &portIterator);
284
+    if (kernResult != KERN_SUCCESS) {
285
+        qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
286
+        return false;
287
+    }
288
+
289
+    // arm the callback, and grab any devices that are already connected
290
+    deviceDiscoveredCallbackOSX( this, portIterator );
291
+
292
+    kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOTerminatedNotification, classesToMatch,
293
+                                                  deviceTerminatedCallbackOSX, this, &portIterator);
294
+    if (kernResult != KERN_SUCCESS) {
295
+        qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
296
+        return false;
297
+    }
298
+
299
+    // arm the callback, and clear any devices that are terminated
300
+    deviceTerminatedCallbackOSX( this, portIterator );
301
+
302
+    kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOTerminatedNotification, cdcClassesToMatch,
303
+                                                  deviceTerminatedCallbackOSX, this, &portIterator);
304
+    if (kernResult != KERN_SUCCESS) {
305
+        qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
306
+        return false;
307
+    }
308
+
309
+    // arm the callback, and clear any devices that are terminated
310
+    deviceTerminatedCallbackOSX( this, portIterator );
311
+    return true;
312
+}
313
+

+ 103
- 0
src/3rdparty/qextserialport/src/qextserialenumerator_p.h View File

@@ -0,0 +1,103 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+#ifndef _QEXTSERIALENUMERATOR_P_H_
32
+#define _QEXTSERIALENUMERATOR_P_H_
33
+
34
+//
35
+//  W A R N I N G
36
+//  -------------
37
+//
38
+// This file is not part of the QESP API.  It exists for the convenience
39
+// of other QESP classes.  This header file may change from version to
40
+// version without notice, or even be removed.
41
+//
42
+// We mean it.
43
+//
44
+
45
+#include "qextserialenumerator.h"
46
+
47
+#ifdef Q_OS_WIN
48
+// needed for mingw to pull in appropriate dbt business...
49
+// probably a better way to do this
50
+// http://mingw-users.1079350.n2.nabble.com/DEV-BROADCAST-DEVICEINTERFACE-was-not-declared-in-this-scope-td3552762.html
51
+#  ifdef  __MINGW32__
52
+#    define _WIN32_WINNT 0x0500
53
+#    define _WIN32_WINDOWS 0x0500
54
+#    define WINVER 0x0500
55
+#  endif
56
+#  include <QtCore/qt_windows.h>
57
+#endif /*Q_OS_WIN*/
58
+
59
+#ifdef Q_OS_MAC
60
+#  include <IOKit/usb/IOUSBLib.h>
61
+#endif /*Q_OS_MAC*/
62
+
63
+class QextSerialRegistrationWidget;
64
+class QextSerialEnumeratorPrivate
65
+{
66
+    Q_DECLARE_PUBLIC(QextSerialEnumerator)
67
+public:
68
+    QextSerialEnumeratorPrivate(QextSerialEnumerator * enumrator);
69
+    ~QextSerialEnumeratorPrivate();
70
+    void platformSpecificInit();
71
+    void platformSpecificDestruct();
72
+
73
+    static QList<QextPortInfo> getPorts_sys();
74
+    bool setUpNotifications_sys(bool setup);
75
+
76
+#ifdef Q_OS_WIN
77
+    LRESULT onDeviceChanged( WPARAM wParam, LPARAM lParam );
78
+    bool matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam);
79
+#  ifdef QT_GUI_LIB
80
+    QextSerialRegistrationWidget* notificationWidget;
81
+#  endif
82
+#endif /*Q_OS_WIN*/
83
+
84
+#ifdef Q_OS_MAC
85
+    /*!
86
+     * Search for serial ports using IOKit.
87
+     *    \param infoList list with result.
88
+     */
89
+    static void iterateServicesOSX(io_object_t service, QList<QextPortInfo> & infoList);
90
+    static bool getServiceDetailsOSX( io_object_t service, QextPortInfo* portInfo );
91
+    void onDeviceDiscoveredOSX( io_object_t service );
92
+    void onDeviceTerminatedOSX( io_object_t service );
93
+    friend void deviceDiscoveredCallbackOSX( void *ctxt, io_iterator_t serialPortIterator );
94
+    friend void deviceTerminatedCallbackOSX( void *ctxt, io_iterator_t serialPortIterator );
95
+
96
+    IONotificationPortRef notificationPortRef;
97
+#endif // Q_OS_MAC
98
+
99
+private:
100
+    QextSerialEnumerator * q_ptr;
101
+};
102
+
103
+#endif //_QEXTSERIALENUMERATOR_P_H_

+ 100
- 0
src/3rdparty/qextserialport/src/qextserialenumerator_unix.cpp View File

@@ -0,0 +1,100 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialenumerator.h"
33
+#include "qextserialenumerator_p.h"
34
+#include <QtCore/QDebug>
35
+#include <QtCore/QStringList>
36
+#include <QtCore/QDir>
37
+
38
+void QextSerialEnumeratorPrivate::platformSpecificInit()
39
+{
40
+}
41
+
42
+void QextSerialEnumeratorPrivate::platformSpecificDestruct()
43
+{
44
+}
45
+
46
+QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
47
+{
48
+    QList<QextPortInfo> infoList;
49
+#ifdef Q_OS_LINUX
50
+    QStringList portNamePrefixes, portNameList;
51
+    portNamePrefixes << QLatin1String("ttyS*"); // list normal serial ports first
52
+
53
+    QDir dir(QLatin1String("/dev"));
54
+    portNameList = dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);
55
+
56
+    // remove the values which are not serial ports for e.g.  /dev/ttysa
57
+    for (int i = 0; i < portNameList.size(); i++) {
58
+        bool ok;
59
+        QString current = portNameList.at(i);
60
+        // remove the ttyS part, and check, if the other part is a number
61
+        current.remove(0,4).toInt(&ok, 10);
62
+        if (!ok) {
63
+            portNameList.removeAt(i);
64
+            i--;
65
+        }
66
+    }
67
+
68
+    // get the non standard serial ports names
69
+    // (USB-serial, bluetooth-serial, 18F PICs, and so on)
70
+    // if you know an other name prefix for serial ports please let us know
71
+    portNamePrefixes.clear();
72
+    portNamePrefixes << QLatin1String("ttyACM*") << QLatin1String("ttyUSB*") << QLatin1String("rfcomm*");
73
+    portNameList += dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);
74
+
75
+    foreach (QString str , portNameList) {
76
+        QextPortInfo inf;
77
+        inf.physName = QLatin1String("/dev/")+str;
78
+        inf.portName = str;
79
+
80
+        if (str.contains(QLatin1String("ttyS"))) {
81
+            inf.friendName = QLatin1String("Serial port ")+str.remove(0, 4);
82
+        }
83
+        else if (str.contains(QLatin1String("ttyUSB"))) {
84
+            inf.friendName = QLatin1String("USB-serial adapter ")+str.remove(0, 6);
85
+        }
86
+        else if (str.contains(QLatin1String("rfcomm"))) {
87
+            inf.friendName = QLatin1String("Bluetooth-serial adapter ")+str.remove(0, 6);
88
+        }
89
+        inf.enumName = QLatin1String("/dev"); // is there a more helpful name for this?
90
+        infoList.append(inf);
91
+    }
92
+#endif
93
+    return infoList;
94
+}
95
+
96
+bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
97
+{
98
+    Q_UNUSED(setup)
99
+    return false;
100
+}

+ 302
- 0
src/3rdparty/qextserialport/src/qextserialenumerator_win.cpp View File

@@ -0,0 +1,302 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialenumerator.h"
33
+#include "qextserialenumerator_p.h"
34
+#include <QtCore/QDebug>
35
+#include <QtCore/QMetaType>
36
+#include <QtCore/QRegExp>
37
+#include <objbase.h>
38
+#include <initguid.h>
39
+#include <setupapi.h>
40
+#include <dbt.h>
41
+#include "qextserialport.h"
42
+
43
+#ifdef QT_GUI_LIB
44
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
45
+#include <QtGui/QWidget>
46
+class QextSerialRegistrationWidget : public QWidget
47
+#else
48
+#include <QtGui/QWindow>
49
+class QextSerialRegistrationWidget : public QWindow
50
+#endif
51
+{
52
+public:
53
+    QextSerialRegistrationWidget(QextSerialEnumeratorPrivate* qese) {
54
+        this->qese = qese;
55
+    }
56
+    ~QextSerialRegistrationWidget() {}
57
+
58
+protected:
59
+
60
+#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
61
+    bool winEvent( MSG* message, long* result ) {
62
+#else
63
+    bool nativeEvent(const QByteArray & /*eventType*/, void *msg, long *result) {
64
+        MSG *message = static_cast<MSG*>(msg);
65
+#endif
66
+        if ( message->message == WM_DEVICECHANGE ) {
67
+            qese->onDeviceChanged(message->wParam, message->lParam );
68
+            *result = 1;
69
+            return true;
70
+        }
71
+        return false;
72
+    }
73
+private:
74
+    QextSerialEnumeratorPrivate* qese;
75
+};
76
+
77
+#endif // QT_GUI_LIB
78
+
79
+void QextSerialEnumeratorPrivate::platformSpecificInit()
80
+{
81
+#ifdef QT_GUI_LIB
82
+    notificationWidget = 0;
83
+#endif // QT_GUI_LIB
84
+}
85
+
86
+/*!
87
+  default
88
+*/
89
+void QextSerialEnumeratorPrivate::platformSpecificDestruct()
90
+{
91
+#ifdef QT_GUI_LIB
92
+    if( notificationWidget )
93
+        delete notificationWidget;
94
+#endif
95
+}
96
+
97
+// see http://msdn.microsoft.com/en-us/library/windows/hardware/ff553426(v=vs.85).aspx
98
+// for list of GUID classes
99
+#ifndef GUID_DEVCLASS_PORTS
100
+    DEFINE_GUID(GUID_DEVCLASS_PORTS, 0x4D36E978, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 );
101
+#endif
102
+
103
+/* Gordon Schumacher's macros for TCHAR -> QString conversions and vice versa */
104
+#ifdef UNICODE
105
+    #define QStringToTCHAR(x)     (wchar_t*) x.utf16()
106
+    #define PQStringToTCHAR(x)    (wchar_t*) x->utf16()
107
+    #define TCHARToQString(x)     QString::fromUtf16((ushort*)(x))
108
+    #define TCHARToQStringN(x,y)  QString::fromUtf16((ushort*)(x),(y))
109
+#else
110
+    #define QStringToTCHAR(x)     x.local8Bit().constData()
111
+    #define PQStringToTCHAR(x)    x->local8Bit().constData()
112
+    #define TCHARToQString(x)     QString::fromLocal8Bit((char*)(x))
113
+    #define TCHARToQStringN(x,y)  QString::fromLocal8Bit((char*)(x),(y))
114
+#endif /*UNICODE*/
115
+
116
+/*!
117
+    \internal
118
+    Get value of specified property from the registry.
119
+        \a key handle to an open key.
120
+        \a property property name.
121
+
122
+        return property value.
123
+*/
124
+static QString getRegKeyValue(HKEY key, LPCTSTR property)
125
+{
126
+    DWORD size = 0;
127
+    DWORD type;
128
+    ::RegQueryValueEx(key, property, NULL, NULL, NULL, & size);
129
+    BYTE* buff = new BYTE[size];
130
+    QString result;
131
+    if(::RegQueryValueEx(key, property, NULL, &type, buff, & size) == ERROR_SUCCESS )
132
+        result = TCHARToQString(buff);
133
+    ::RegCloseKey(key);
134
+    delete [] buff;
135
+    return result;
136
+}
137
+
138
+/*!
139
+     \internal
140
+     Get specific property from registry.
141
+     \a devInfo pointer to the device information set that contains the interface
142
+        and its underlying device. Returned by SetupDiGetClassDevs() function.
143
+     \a devData pointer to an SP_DEVINFO_DATA structure that defines the device instance.
144
+        this is returned by SetupDiGetDeviceInterfaceDetail() function.
145
+     \a property registry property. One of defined SPDRP_* constants.
146
+
147
+     return property string.
148
+ */
149
+static QString getDeviceProperty(HDEVINFO devInfo, PSP_DEVINFO_DATA devData, DWORD property)
150
+{
151
+    DWORD buffSize = 0;
152
+    ::SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, NULL, 0, & buffSize);
153
+    BYTE* buff = new BYTE[buffSize];
154
+    ::SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, buff, buffSize, NULL);
155
+    QString result = TCHARToQString(buff);
156
+    delete [] buff;
157
+    return result;
158
+}
159
+
160
+/*!
161
+     \internal
162
+*/
163
+static bool getDeviceDetailsWin( QextPortInfo* portInfo, HDEVINFO devInfo, PSP_DEVINFO_DATA devData
164
+                                 , WPARAM wParam = DBT_DEVICEARRIVAL)
165
+{
166
+    portInfo->friendName = getDeviceProperty(devInfo, devData, SPDRP_FRIENDLYNAME);
167
+    if( wParam == DBT_DEVICEARRIVAL)
168
+        portInfo->physName = getDeviceProperty(devInfo, devData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME);
169
+    portInfo->enumName = getDeviceProperty(devInfo, devData, SPDRP_ENUMERATOR_NAME);
170
+    QString hardwareIDs = getDeviceProperty(devInfo, devData, SPDRP_HARDWAREID);
171
+    HKEY devKey = ::SetupDiOpenDevRegKey(devInfo, devData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
172
+    portInfo->portName = getRegKeyValue(devKey, TEXT("PortName"));
173
+    QRegExp idRx(QLatin1String("VID_(\\w+)&PID_(\\w+)"));
174
+    if(hardwareIDs.toUpper().contains(idRx)) {
175
+        bool dummy;
176
+        portInfo->vendorID = idRx.cap(1).toInt(&dummy, 16);
177
+        portInfo->productID = idRx.cap(2).toInt(&dummy, 16);
178
+        //qDebug() << "got vid:" << vid << "pid:" << pid;
179
+    }
180
+    return true;
181
+}
182
+
183
+/*!
184
+     \internal
185
+*/
186
+static void enumerateDevicesWin( const GUID & guid, QList<QextPortInfo>* infoList )
187
+{
188
+    HDEVINFO devInfo;
189
+    if( (devInfo = ::SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT)) != INVALID_HANDLE_VALUE) {
190
+        SP_DEVINFO_DATA devInfoData;
191
+        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
192
+        for(int i = 0; ::SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) {
193
+            QextPortInfo info;
194
+            info.productID = info.vendorID = 0;
195
+            getDeviceDetailsWin( &info, devInfo, &devInfoData );
196
+            infoList->append(info);
197
+        }
198
+        ::SetupDiDestroyDeviceInfoList(devInfo);
199
+    }
200
+}
201
+
202
+
203
+static bool lessThan(const QextPortInfo &s1, const QextPortInfo &s2)
204
+{
205
+    if (s1.portName.startsWith(QLatin1String("COM"))
206
+            && s2.portName.startsWith(QLatin1String("COM"))) {
207
+        return s1.portName.mid(3).toInt()<s2.portName.mid(3).toInt();
208
+    }
209
+    return s1.portName < s2.portName;
210
+}
211
+
212
+
213
+/*!
214
+    Get list of ports.
215
+
216
+    return list of ports currently available in the system.
217
+*/
218
+QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
219
+{
220
+    QList<QextPortInfo> ports;
221
+    enumerateDevicesWin(GUID_DEVCLASS_PORTS, &ports);
222
+    qSort(ports.begin(), ports.end(), lessThan);
223
+    return ports;
224
+}
225
+
226
+
227
+/*
228
+    Enable event-driven notifications of board discovery/removal.
229
+*/
230
+bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
231
+{
232
+#ifndef QT_GUI_LIB
233
+    Q_UNUSED(setup)
234
+    QESP_WARNING("QextSerialEnumerator: GUI not enabled - can't register for device notifications.");
235
+    return false;
236
+#else
237
+    Q_Q(QextSerialEnumerator);
238
+    if(setup && notificationWidget) //already setup
239
+        return true;
240
+    notificationWidget = new QextSerialRegistrationWidget(this);
241
+
242
+    DEV_BROADCAST_DEVICEINTERFACE dbh;
243
+    ::ZeroMemory(&dbh, sizeof(dbh));
244
+    dbh.dbcc_size = sizeof(dbh);
245
+    dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
246
+    ::CopyMemory(&dbh.dbcc_classguid, &GUID_DEVCLASS_PORTS, sizeof(GUID));
247
+    if(::RegisterDeviceNotification((HWND)notificationWidget->winId(), &dbh, DEVICE_NOTIFY_WINDOW_HANDLE ) == NULL) {
248
+        QESP_WARNING() << "RegisterDeviceNotification failed:" << GetLastError();
249
+        return false;
250
+    }
251
+    // setting up notifications doesn't tell us about devices already connected
252
+    // so get those manually
253
+    foreach(QextPortInfo port, getPorts_sys())
254
+      Q_EMIT q->deviceDiscovered(port);
255
+    return true;
256
+#endif // QT_GUI_LIB
257
+}
258
+
259
+LRESULT QextSerialEnumeratorPrivate::onDeviceChanged( WPARAM wParam, LPARAM lParam )
260
+{
261
+    if (DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam ) {
262
+        PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
263
+        if(pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE ) {
264
+            PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
265
+             // delimiters are different across APIs...change to backslash.  ugh.
266
+            QString deviceID = TCHARToQString(pDevInf->dbcc_name).toUpper().replace(QLatin1String("#"), QLatin1String("\\"));
267
+
268
+            matchAndDispatchChangedDevice(deviceID, GUID_DEVCLASS_PORTS, wParam);
269
+        }
270
+    }
271
+    return 0;
272
+}
273
+
274
+bool QextSerialEnumeratorPrivate::matchAndDispatchChangedDevice(const QString & deviceID, const GUID & guid, WPARAM wParam)
275
+{
276
+    Q_Q(QextSerialEnumerator);
277
+    bool rv = false;
278
+    DWORD dwFlag = (DBT_DEVICEARRIVAL == wParam) ? DIGCF_PRESENT : DIGCF_ALLCLASSES;
279
+    HDEVINFO devInfo;
280
+    if( (devInfo = SetupDiGetClassDevs(&guid,NULL,NULL,dwFlag)) != INVALID_HANDLE_VALUE ) {
281
+        SP_DEVINFO_DATA spDevInfoData;
282
+        spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
283
+        for(int i=0; SetupDiEnumDeviceInfo(devInfo, i, &spDevInfoData); i++) {
284
+            DWORD nSize=0 ;
285
+            TCHAR buf[MAX_PATH];
286
+            if ( SetupDiGetDeviceInstanceId(devInfo, &spDevInfoData, buf, MAX_PATH, &nSize) &&
287
+                    deviceID.contains(TCHARToQString(buf))) { // we found a match
288
+                rv = true;
289
+                QextPortInfo info;
290
+                info.productID = info.vendorID = 0;
291
+                getDeviceDetailsWin( &info, devInfo, &spDevInfoData, wParam );
292
+                if( wParam == DBT_DEVICEARRIVAL )
293
+                    Q_EMIT q->deviceDiscovered(info);
294
+                else if( wParam == DBT_DEVICEREMOVECOMPLETE )
295
+                    Q_EMIT q->deviceRemoved(info);
296
+                break;
297
+            }
298
+        }
299
+        SetupDiDestroyDeviceInfoList(devInfo);
300
+    }
301
+    return rv;
302
+}

+ 1006
- 0
src/3rdparty/qextserialport/src/qextserialport.cpp
File diff suppressed because it is too large
View File


+ 240
- 0
src/3rdparty/qextserialport/src/qextserialport.h View File

@@ -0,0 +1,240 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#ifndef _QEXTSERIALPORT_H_
33
+#define _QEXTSERIALPORT_H_
34
+
35
+#include <QtCore/QIODevice>
36
+#include "qextserialport_global.h"
37
+#ifdef Q_OS_UNIX
38
+#include <termios.h>
39
+#endif
40
+/*line status constants*/
41
+// ### QESP2.0 move to enum
42
+#define LS_CTS  0x01
43
+#define LS_DSR  0x02
44
+#define LS_DCD  0x04
45
+#define LS_RI   0x08
46
+#define LS_RTS  0x10
47
+#define LS_DTR  0x20
48
+#define LS_ST   0x40
49
+#define LS_SR   0x80
50
+
51
+/*error constants*/
52
+// ### QESP2.0 move to enum
53
+#define E_NO_ERROR                   0
54
+#define E_INVALID_FD                 1
55
+#define E_NO_MEMORY                  2
56
+#define E_CAUGHT_NON_BLOCKED_SIGNAL  3
57
+#define E_PORT_TIMEOUT               4
58
+#define E_INVALID_DEVICE             5
59
+#define E_BREAK_CONDITION            6
60
+#define E_FRAMING_ERROR              7
61
+#define E_IO_ERROR                   8
62
+#define E_BUFFER_OVERRUN             9
63
+#define E_RECEIVE_OVERFLOW          10
64
+#define E_RECEIVE_PARITY_ERROR      11
65
+#define E_TRANSMIT_OVERFLOW         12
66
+#define E_READ_FAILED               13
67
+#define E_WRITE_FAILED              14
68
+#define E_FILE_NOT_FOUND            15
69
+#define E_PERMISSION_DENIED         16
70
+#define E_AGAIN                     17
71
+
72
+enum BaudRateType
73
+{
74
+#if defined(Q_OS_UNIX) || defined(qdoc)
75
+    BAUD50 = 50,                //POSIX ONLY
76
+    BAUD75 = 75,                //POSIX ONLY
77
+    BAUD134 = 134,              //POSIX ONLY
78
+    BAUD150 = 150,              //POSIX ONLY
79
+    BAUD200 = 200,              //POSIX ONLY
80
+    BAUD1800 = 1800,            //POSIX ONLY
81
+#  if defined(B76800) || defined(qdoc)
82
+    BAUD76800 = 76800,          //POSIX ONLY
83
+#  endif
84
+#  if (defined(B230400) && defined(B4000000)) || defined(qdoc)
85
+    BAUD230400 = 230400,        //POSIX ONLY
86
+    BAUD460800 = 460800,        //POSIX ONLY
87
+    BAUD500000 = 500000,        //POSIX ONLY
88
+    BAUD576000 = 576000,        //POSIX ONLY
89
+    BAUD921600 = 921600,        //POSIX ONLY
90
+    BAUD1000000 = 1000000,      //POSIX ONLY
91
+    BAUD1152000 = 1152000,      //POSIX ONLY
92
+    BAUD1500000 = 1500000,      //POSIX ONLY
93
+    BAUD2000000 = 2000000,      //POSIX ONLY
94
+    BAUD2500000 = 2500000,      //POSIX ONLY
95
+    BAUD3000000 = 3000000,      //POSIX ONLY
96
+    BAUD3500000 = 3500000,      //POSIX ONLY
97
+    BAUD4000000 = 4000000,      //POSIX ONLY
98
+#  endif
99
+#endif //Q_OS_UNIX
100
+#if defined(Q_OS_WIN) || defined(qdoc)
101
+    BAUD14400 = 14400,          //WINDOWS ONLY
102
+    BAUD56000 = 56000,          //WINDOWS ONLY
103
+    BAUD128000 = 128000,        //WINDOWS ONLY
104
+    BAUD256000 = 256000,        //WINDOWS ONLY
105
+#endif  //Q_OS_WIN
106
+    BAUD110 = 110,
107
+    BAUD300 = 300,
108
+    BAUD600 = 600,
109
+    BAUD1200 = 1200,
110
+    BAUD2400 = 2400,
111
+    BAUD4800 = 4800,
112
+    BAUD9600 = 9600,
113
+    BAUD19200 = 19200,
114
+    BAUD38400 = 38400,
115
+    BAUD57600 = 57600,
116
+    BAUD115200 = 115200
117
+};
118
+
119
+enum DataBitsType
120
+{
121
+    DATA_5 = 5,
122
+    DATA_6 = 6,
123
+    DATA_7 = 7,
124
+    DATA_8 = 8
125
+};
126
+
127
+enum ParityType
128
+{
129
+    PAR_NONE,
130
+    PAR_ODD,
131
+    PAR_EVEN,
132
+#if defined(Q_OS_WIN) || defined(qdoc)
133
+    PAR_MARK,               //WINDOWS ONLY
134
+#endif
135
+    PAR_SPACE
136
+};
137
+
138
+enum StopBitsType
139
+{
140
+    STOP_1,
141
+#if defined(Q_OS_WIN) || defined(qdoc)
142
+    STOP_1_5,               //WINDOWS ONLY
143
+#endif
144
+    STOP_2
145
+};
146
+
147
+enum FlowType
148
+{
149
+    FLOW_OFF,
150
+    FLOW_HARDWARE,
151
+    FLOW_XONXOFF
152
+};
153
+
154
+/**
155
+ * structure to contain port settings
156
+ */
157
+struct PortSettings
158
+{
159
+    BaudRateType BaudRate;
160
+    DataBitsType DataBits;
161
+    ParityType Parity;
162
+    StopBitsType StopBits;
163
+    FlowType FlowControl;
164
+    long Timeout_Millisec;
165
+};
166
+
167
+class QextSerialPortPrivate;
168
+class QEXTSERIALPORT_EXPORT QextSerialPort: public QIODevice
169
+{
170
+    Q_OBJECT
171
+    Q_DECLARE_PRIVATE(QextSerialPort)
172
+    Q_ENUMS(QueryMode)
173
+    Q_PROPERTY(QString portName READ portName WRITE setPortName)
174
+    Q_PROPERTY(QueryMode queryMode READ queryMode WRITE setQueryMode)
175
+public:
176
+    enum QueryMode {
177
+        Polling,
178
+        EventDriven
179
+    };
180
+
181
+    explicit QextSerialPort(QueryMode mode = EventDriven, QObject* parent = 0);
182
+    explicit QextSerialPort(const QString & name, QueryMode mode = EventDriven, QObject * parent = 0);
183
+    explicit QextSerialPort(const PortSettings & s, QueryMode mode = EventDriven, QObject * parent = 0);
184
+    QextSerialPort(const QString & name, const PortSettings& s, QueryMode mode = EventDriven, QObject *parent=0);
185
+
186
+    ~QextSerialPort();
187
+
188
+    QString portName() const;
189
+    QueryMode queryMode() const;
190
+    BaudRateType baudRate() const;
191
+    DataBitsType dataBits() const;
192
+    ParityType parity() const;
193
+    StopBitsType stopBits() const;
194
+    FlowType flowControl() const;
195
+
196
+    bool open(OpenMode mode);
197
+    bool isSequential() const;
198
+    void close();
199
+    void flush();
200
+    qint64 bytesAvailable() const;
201
+    bool canReadLine() const;
202
+    QByteArray readAll();
203
+
204
+    ulong lastError() const;
205
+
206
+    ulong lineStatus();
207
+    QString errorString();
208
+
209
+public Q_SLOTS:
210
+    void setPortName(const QString & name);
211
+    void setQueryMode(QueryMode mode);
212
+    void setBaudRate(BaudRateType);
213
+    void setDataBits(DataBitsType);
214
+    void setParity(ParityType);
215
+    void setStopBits(StopBitsType);
216
+    void setFlowControl(FlowType);
217
+    void setTimeout(long);
218
+
219
+    void setDtr(bool set=true);
220
+    void setRts(bool set=true);
221
+
222
+Q_SIGNALS:
223
+    void dsrChanged(bool status);
224
+
225
+protected:
226
+    qint64 readData(char * data, qint64 maxSize);
227
+    qint64 writeData(const char * data, qint64 maxSize);
228
+
229
+private:
230
+    Q_DISABLE_COPY(QextSerialPort)
231
+
232
+#ifdef Q_OS_WIN
233
+    Q_PRIVATE_SLOT(d_func(), void _q_onWinEvent(HANDLE))
234
+#endif
235
+    Q_PRIVATE_SLOT(d_func(), void _q_canRead())
236
+
237
+    QextSerialPortPrivate * const d_ptr;
238
+};
239
+
240
+#endif

+ 47
- 0
src/3rdparty/qextserialport/src/qextserialport.pri View File

@@ -0,0 +1,47 @@
1
+exists(../common.pri) {
2
+    #For case:
3
+    #  someone want to copy all file in the src/ directory
4
+    #  to their project src/ directory and they does not like
5
+    #  the common.pri file.
6
+    #In this case:
7
+    #  they can just include this file (qextserialport.pri) too.
8
+    include(../common.pri)
9
+}
10
+INCLUDEPATH += $$PWD
11
+DEPENDPATH += $$PWD
12
+
13
+qextserialport-library:!qextserialport-buildlib {
14
+    # Using QextSerialPort as shared or static library.
15
+    LIBS += -L$$QEXTSERIALPORT_LIBDIR -l$$QEXTSERIALPORT_LIBNAME
16
+   !qextserialport-static: DEFINES += QEXTSERIALPORT_USING_SHARED
17
+} else {
18
+    # Building library(shared or static)
19
+    # or including source files
20
+    HEADERS                += $$PWD/qextserialport.h \
21
+                              $$PWD/qextserialport_p.h \
22
+                              $$PWD/qextserialenumerator.h \
23
+                              $$PWD/qextserialenumerator_p.h \
24
+                              $$PWD/qextserialport_global.h
25
+    SOURCES                += $$PWD/qextserialport.cpp \
26
+                              $$PWD/qextserialenumerator.cpp
27
+    unix:SOURCES           += $$PWD/qextserialport_unix.cpp
28
+    unix:!macx:SOURCES     += $$PWD/qextserialenumerator_unix.cpp
29
+    macx:SOURCES           += $$PWD/qextserialenumerator_osx.cpp
30
+    win32:SOURCES          += $$PWD/qextserialport_win.cpp \
31
+                              $$PWD/qextserialenumerator_win.cpp
32
+
33
+    # For Windows user who doesn't have Qt4's Private files
34
+    win32:contains(QT_VERSION, ^4\\..*\\..*):!exists($$[QT_INSTALL_HEADERS]/QtCore/private/qwineventnotifier_p.h){
35
+        DEFINES            += QESP_NO_QT4_PRIVATE
36
+        HEADERS            += $$PWD/qextwineventnotifier_p.h
37
+        SOURCES            += $$PWD/qextwineventnotifier_p.cpp
38
+    }
39
+
40
+    # For building shared library only
41
+    qextserialport-buildlib:contains(TEMPLATE, .*lib):contains(CONFIG, shared){
42
+        DEFINES += QEXTSERIALPORT_BUILD_SHARED
43
+    }
44
+}
45
+
46
+macx:LIBS              += -framework IOKit -framework CoreFoundation
47
+win32:LIBS             += -lsetupapi -ladvapi32 -luser32

+ 72
- 0
src/3rdparty/qextserialport/src/qextserialport_global.h View File

@@ -0,0 +1,72 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#ifndef QEXTSERIALPORT_GLOBAL_H
33
+#define QEXTSERIALPORT_GLOBAL_H
34
+
35
+#include <QtCore/QtGlobal>
36
+
37
+#ifdef QEXTSERIALPORT_BUILD_SHARED
38
+#  define QEXTSERIALPORT_EXPORT Q_DECL_EXPORT
39
+#elif defined(QEXTSERIALPORT_USING_SHARED)
40
+#  define QEXTSERIALPORT_EXPORT Q_DECL_IMPORT
41
+#else
42
+#  define QEXTSERIALPORT_EXPORT
43
+#endif
44
+
45
+// ### for compatible with old version. should be removed in QESP 2.0
46
+#ifdef _TTY_NOWARN_
47
+#  define QESP_NO_WARN
48
+#endif
49
+#ifdef _TTY_NOWARN_PORT_
50
+#  define QESP_NO_PORTABILITY_WARN
51
+#endif
52
+
53
+/*if all warning messages are turned off, flag portability warnings to be turned off as well*/
54
+#ifdef QESP_NO_WARN
55
+#  define QESP_NO_PORTABILITY_WARN
56
+#endif
57
+
58
+/*macros for warning and debug messages*/
59
+#ifdef QESP_NO_PORTABILITY_WARN
60
+#  define QESP_PORTABILITY_WARNING  while(false)qWarning
61
+#else
62
+#  define QESP_PORTABILITY_WARNING qWarning
63
+#endif /*QESP_NOWARN_PORT*/
64
+
65
+#ifdef QESP_NO_WARN
66
+#  define QESP_WARNING while(false)qWarning
67
+#else
68
+#  define QESP_WARNING qWarning
69
+#endif /*QESP_NOWARN*/
70
+
71
+#endif // QEXTSERIALPORT_GLOBAL_H
72
+

+ 257
- 0
src/3rdparty/qextserialport/src/qextserialport_p.h View File

@@ -0,0 +1,257 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#ifndef _QEXTSERIALPORT_P_H_
33
+#define _QEXTSERIALPORT_P_H_
34
+
35
+//
36
+//  W A R N I N G
37
+//  -------------
38
+//
39
+// This file is not part of the QESP API.  It exists for the convenience
40
+// of other QESP classes.  This header file may change from version to
41
+// version without notice, or even be removed.
42
+//
43
+// We mean it.
44
+//
45
+
46
+#include "qextserialport.h"
47
+#include <QtCore/QReadWriteLock>
48
+#ifdef Q_OS_UNIX
49
+#  include <termios.h>
50
+#elif (defined Q_OS_WIN)
51
+#  include <QtCore/qt_windows.h>
52
+#endif
53
+#include <stdlib.h>
54
+
55
+// This is QextSerialPort's read buffer, needed by posix system.
56
+// ref: QRingBuffer & QIODevicePrivateLinearBuffer
57
+class QextReadBuffer
58
+{
59
+public:
60
+    inline QextReadBuffer(size_t growth=4096)
61
+        : len(0), first(0), buf(0), capacity(0), basicBlockSize(growth) {
62
+    }
63
+
64
+    ~QextReadBuffer() {
65
+        delete [] buf;
66
+    }
67
+
68
+    inline void clear() {
69
+        first = buf;
70
+        len = 0;
71
+    }
72
+
73
+    inline int size() const {
74
+        return len;
75
+    }
76
+
77
+    inline bool isEmpty() const {
78
+        return len == 0;
79
+    }
80
+
81
+    inline int read(char* target, int size) {
82
+        int r = qMin(size, len);
83
+        if (r == 1) {
84
+            *target = *first;
85
+            --len;
86
+            ++first;
87
+        } else {
88
+            memcpy(target, first, r);
89
+            len -= r;
90
+            first += r;
91
+        }
92
+        return r;
93
+    }
94
+
95
+    inline char* reserve(size_t size) {
96
+        if ((first - buf) + len + size > capacity) {
97
+            size_t newCapacity = qMax(capacity, basicBlockSize);
98
+            while (newCapacity < size)
99
+                newCapacity *= 2;
100
+            if (newCapacity > capacity) {
101
+                // allocate more space
102
+                char* newBuf = new char[newCapacity];
103
+                memmove(newBuf, first, len);
104
+                delete [] buf;
105
+                buf = newBuf;
106
+                capacity = newCapacity;
107
+            } else {
108
+                // shift any existing data to make space
109
+                memmove(buf, first, len);
110
+            }
111
+            first = buf;
112
+        }
113
+        char* writePtr = first + len;
114
+        len += (int)size;
115
+        return writePtr;
116
+    }
117
+
118
+    inline void chop(int size) {
119
+        if (size >= len) {
120
+            clear();
121
+        } else {
122
+            len -= size;
123
+        }
124
+    }
125
+
126
+    inline void squeeze() {
127
+        if (first != buf) {
128
+            memmove(buf, first, len);
129
+            first = buf;
130
+        }
131
+        size_t newCapacity = basicBlockSize;
132
+        while (newCapacity < size_t(len))
133
+            newCapacity *= 2;
134
+        if (newCapacity < capacity) {
135
+            char * tmp = static_cast<char*>(realloc(buf, newCapacity));
136
+            if (tmp) {
137
+                buf = tmp;
138
+                capacity = newCapacity;
139
+            }
140
+        }
141
+    }
142
+
143
+    inline QByteArray readAll() {
144
+        char* f = first;
145
+        int l = len;
146
+        clear();
147
+        return QByteArray(f, l);
148
+    }
149
+
150
+    inline int readLine(char* target, int size) {
151
+        int r = qMin(size, len);
152
+        char* eol = static_cast<char*>(memchr(first, '\n', r));
153
+        if (eol)
154
+            r = 1+(eol-first);
155
+        memcpy(target, first, r);
156
+        len -= r;
157
+        first += r;
158
+        return int(r);
159
+    }
160
+
161
+    inline bool canReadLine() const {
162
+        return memchr(first, '\n', len);
163
+    }
164
+
165
+private:
166
+    int len;
167
+    char* first;
168
+    char* buf;
169
+    size_t capacity;
170
+    size_t basicBlockSize;
171
+};
172
+
173
+class QextWinEventNotifier;
174
+class QWinEventNotifier;
175
+class QReadWriteLock;
176
+class QSocketNotifier;
177
+
178
+class QextSerialPortPrivate
179
+{
180
+    Q_DECLARE_PUBLIC(QextSerialPort)
181
+public:
182
+    QextSerialPortPrivate(QextSerialPort * q);
183
+    ~QextSerialPortPrivate();
184
+    enum DirtyFlagEnum
185
+    {
186
+        DFE_BaudRate = 0x0001,
187
+        DFE_Parity = 0x0002,
188
+        DFE_StopBits = 0x0004,
189
+        DFE_DataBits = 0x0008,
190
+        DFE_Flow = 0x0010,
191
+        DFE_TimeOut = 0x0100,
192
+        DFE_ALL = 0x0fff,
193
+        DFE_Settings_Mask = 0x00ff //without TimeOut
194
+    };
195
+    mutable QReadWriteLock lock;
196
+    QString port;
197
+    PortSettings Settings;
198
+    QextReadBuffer readBuffer;
199
+    int settingsDirtyFlags;
200
+    ulong lastErr;
201
+    QextSerialPort::QueryMode _queryMode;
202
+
203
+    // platform specific members
204
+#ifdef Q_OS_UNIX
205
+    int fd;
206
+    QSocketNotifier *readNotifier;
207
+    struct termios Posix_CommConfig;
208
+    struct termios old_termios;
209
+#elif (defined Q_OS_WIN)
210
+    HANDLE Win_Handle;
211
+    OVERLAPPED overlap;
212
+    COMMCONFIG Win_CommConfig;
213
+    COMMTIMEOUTS Win_CommTimeouts;
214
+#  ifndef QESP_NO_QT4_PRIVATE
215
+    QWinEventNotifier *winEventNotifier;
216
+#  else
217
+    QextWinEventNotifier *winEventNotifier;
218
+#  endif
219
+    DWORD eventMask;
220
+    QList<OVERLAPPED*> pendingWrites;
221
+    QReadWriteLock* bytesToWriteLock;
222
+    qint64 _bytesToWrite;
223
+#endif
224
+
225
+    /*fill PortSettings*/
226
+    void setBaudRate(BaudRateType baudRate, bool update=true);
227
+    void setDataBits(DataBitsType dataBits, bool update=true);
228
+    void setParity(ParityType parity, bool update=true);
229
+    void setStopBits(StopBitsType stopbits, bool update=true);
230
+    void setFlowControl(FlowType flow, bool update=true);
231
+    void setTimeout(long millisec, bool update=true);
232
+    void setPortSettings(const PortSettings& settings, bool update=true);
233
+
234
+    void platformSpecificDestruct();
235
+    void platformSpecificInit();
236
+    void translateError(ulong error);
237
+    void updatePortSettings();
238
+
239
+    qint64 readData_sys(char * data, qint64 maxSize);
240
+    qint64 writeData_sys(const char * data, qint64 maxSize);
241
+    void setDtr_sys(bool set=true);
242
+    void setRts_sys(bool set=true);
243
+    bool open_sys(QIODevice::OpenMode mode);
244
+    bool close_sys();
245
+    bool flush_sys();
246
+    ulong lineStatus_sys();
247
+    qint64 bytesAvailable_sys() const;
248
+
249
+#ifdef Q_OS_WIN
250
+    void _q_onWinEvent(HANDLE h);
251
+#endif
252
+    void _q_canRead();
253
+
254
+    QextSerialPort * q_ptr;
255
+};
256
+
257
+#endif //_QEXTSERIALPORT_P_H_

+ 448
- 0
src/3rdparty/qextserialport/src/qextserialport_unix.cpp View File

@@ -0,0 +1,448 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialport.h"
33
+#include "qextserialport_p.h"
34
+#include <fcntl.h>
35
+#include <stdio.h>
36
+#include <errno.h>
37
+#include <unistd.h>
38
+#include <sys/time.h>
39
+#include <sys/ioctl.h>
40
+#include <sys/select.h>
41
+#include <QtCore/QMutexLocker>
42
+#include <QtCore/QDebug>
43
+#include <QtCore/QSocketNotifier>
44
+
45
+void QextSerialPortPrivate::platformSpecificInit()
46
+{
47
+    fd = 0;
48
+    readNotifier = 0;
49
+}
50
+
51
+/*!
52
+    Standard destructor.
53
+*/
54
+void QextSerialPortPrivate::platformSpecificDestruct()
55
+{
56
+}
57
+
58
+bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode)
59
+{
60
+    Q_Q(QextSerialPort);
61
+    //note: linux 2.6.21 seems to ignore O_NDELAY flag
62
+    if ((fd = ::open(port.toAscii() ,O_RDWR | O_NOCTTY | O_NDELAY)) != -1) {
63
+
64
+        /*In the Private class, We can not call QIODevice::open()*/
65
+        q->setOpenMode(mode);             // Flag the port as opened
66
+        ::tcgetattr(fd, &old_termios);    // Save the old termios
67
+        Posix_CommConfig = old_termios;   // Make a working copy
68
+        ::cfmakeraw(&Posix_CommConfig);   // Enable raw access
69
+
70
+        /*set up other port settings*/
71
+        Posix_CommConfig.c_cflag |= CREAD|CLOCAL;
72
+        Posix_CommConfig.c_lflag &= (~(ICANON|ECHO|ECHOE|ECHOK|ECHONL|ISIG));
73
+        Posix_CommConfig.c_iflag &= (~(INPCK|IGNPAR|PARMRK|ISTRIP|ICRNL|IXANY));
74
+        Posix_CommConfig.c_oflag &= (~OPOST);
75
+        Posix_CommConfig.c_cc[VMIN] = 0;
76
+#ifdef _POSIX_VDISABLE  // Is a disable character available on this system?
77
+        // Some systems allow for per-device disable-characters, so get the
78
+        //  proper value for the configured device
79
+        const long vdisable = ::fpathconf(fd, _PC_VDISABLE);
80
+        Posix_CommConfig.c_cc[VINTR] = vdisable;
81
+        Posix_CommConfig.c_cc[VQUIT] = vdisable;
82
+        Posix_CommConfig.c_cc[VSTART] = vdisable;
83
+        Posix_CommConfig.c_cc[VSTOP] = vdisable;
84
+        Posix_CommConfig.c_cc[VSUSP] = vdisable;
85
+#endif //_POSIX_VDISABLE
86
+        settingsDirtyFlags = DFE_ALL;
87
+        updatePortSettings();
88
+
89
+        if (_queryMode == QextSerialPort::EventDriven) {
90
+            readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, q);
91
+            q->connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_q_canRead()));
92
+        }
93
+        return true;
94
+    } else {
95
+        translateError(errno);
96
+        return false;
97
+    }
98
+}
99
+
100
+bool QextSerialPortPrivate::close_sys()
101
+{
102
+    // Force a flush and then restore the original termios
103
+    flush_sys();
104
+    // Using both TCSAFLUSH and TCSANOW here discards any pending input
105
+    ::tcsetattr(fd, TCSAFLUSH | TCSANOW, &old_termios);   // Restore termios
106
+    ::close(fd);
107
+    if(readNotifier) {
108
+        delete readNotifier;
109
+        readNotifier = 0;
110
+    }
111
+    return true;
112
+}
113
+
114
+bool QextSerialPortPrivate::flush_sys()
115
+{
116
+    ::tcdrain(fd);
117
+    return true;
118
+}
119
+
120
+qint64 QextSerialPortPrivate::bytesAvailable_sys() const
121
+{
122
+    int bytesQueued;
123
+    if (::ioctl(fd, FIONREAD, &bytesQueued) == -1) {
124
+        return (qint64)-1;
125
+    }
126
+    return bytesQueued;
127
+}
128
+
129
+/*!
130
+    Translates a system-specific error code to a QextSerialPort error code.  Used internally.
131
+*/
132
+void QextSerialPortPrivate::translateError(ulong error)
133
+{
134
+    switch (error) {
135
+    case EBADF:
136
+    case ENOTTY:
137
+        lastErr = E_INVALID_FD;
138
+        break;
139
+    case EINTR:
140
+        lastErr = E_CAUGHT_NON_BLOCKED_SIGNAL;
141
+        break;
142
+    case ENOMEM:
143
+        lastErr = E_NO_MEMORY;
144
+        break;
145
+    case EACCES:
146
+        lastErr = E_PERMISSION_DENIED;
147
+        break;
148
+    case EAGAIN:
149
+        lastErr = E_AGAIN;
150
+        break;
151
+    }
152
+}
153
+
154
+void QextSerialPortPrivate::setDtr_sys(bool set)
155
+{
156
+    int status;
157
+    ::ioctl(fd, TIOCMGET, &status);
158
+    if (set)
159
+        status |= TIOCM_DTR;
160
+    else
161
+        status &= ~TIOCM_DTR;
162
+    ::ioctl(fd, TIOCMSET, &status);
163
+}
164
+
165
+void QextSerialPortPrivate::setRts_sys(bool set)
166
+{
167
+    int status;
168
+    ::ioctl(fd, TIOCMGET, &status);
169
+    if (set)
170
+        status |= TIOCM_RTS;
171
+    else
172
+        status &= ~TIOCM_RTS;
173
+    ::ioctl(fd, TIOCMSET, &status);
174
+}
175
+
176
+unsigned long QextSerialPortPrivate::lineStatus_sys()
177
+{
178
+    unsigned long Status=0, Temp=0;
179
+    ::ioctl(fd, TIOCMGET, &Temp);
180
+    if (Temp & TIOCM_CTS) Status |= LS_CTS;
181
+    if (Temp & TIOCM_DSR) Status |= LS_DSR;
182
+    if (Temp & TIOCM_RI ) Status |= LS_RI;
183
+    if (Temp & TIOCM_CD ) Status |= LS_DCD;
184
+    if (Temp & TIOCM_DTR) Status |= LS_DTR;
185
+    if (Temp & TIOCM_RTS) Status |= LS_RTS;
186
+    if (Temp & TIOCM_ST ) Status |= LS_ST;
187
+    if (Temp & TIOCM_SR ) Status |= LS_SR;
188
+    return Status;
189
+}
190
+
191
+/*!
192
+    Reads a block of data from the serial port.  This function will read at most maxSize bytes from
193
+    the serial port and place them in the buffer pointed to by data.  Return value is the number of
194
+    bytes actually read, or -1 on error.
195
+    
196
+    \warning before calling this function ensure that serial port associated with this class
197
+    is currently open (use isOpen() function to check if port is open).
198
+*/
199
+qint64 QextSerialPortPrivate::readData_sys(char * data, qint64 maxSize)
200
+{
201
+    int retVal = ::read(fd, data, maxSize);
202
+    if (retVal == -1)
203
+        lastErr = E_READ_FAILED;
204
+
205
+    return retVal;
206
+}
207
+
208
+/*!
209
+    Writes a block of data to the serial port.  This function will write maxSize bytes
210
+    from the buffer pointed to by data to the serial port.  Return value is the number
211
+    of bytes actually written, or -1 on error.
212
+    
213
+    \warning before calling this function ensure that serial port associated with this class
214
+    is currently open (use isOpen() function to check if port is open).
215
+*/
216
+qint64 QextSerialPortPrivate::writeData_sys(const char * data, qint64 maxSize)
217
+{
218
+    int retVal = ::write(fd, data, maxSize);
219
+    if (retVal == -1)
220
+        lastErr = E_WRITE_FAILED;
221
+
222
+    return (qint64)retVal;
223
+}
224
+
225
+static void setBaudRate2Termios(termios *config, int baudRate)
226
+{
227
+#ifdef CBAUD
228
+    config->c_cflag &= (~CBAUD);
229
+    config->c_cflag |= baudRate;
230
+#else
231
+    ::cfsetispeed(config, baudRate);
232
+    ::cfsetospeed(config, baudRate);
233
+#endif
234
+}
235
+
236
+/*
237
+    All the platform settings was performed in this function.
238
+*/
239
+void QextSerialPortPrivate::updatePortSettings()
240
+{
241
+    if (!q_func()->isOpen() || !settingsDirtyFlags)
242
+        return;
243
+
244
+    if (settingsDirtyFlags & DFE_BaudRate) {
245
+        switch (Settings.BaudRate) {
246
+        case BAUD50:
247
+            setBaudRate2Termios(&Posix_CommConfig, B50);
248
+            break;
249
+        case BAUD75:
250
+            setBaudRate2Termios(&Posix_CommConfig, B75);
251
+            break;
252
+        case BAUD110:
253
+            setBaudRate2Termios(&Posix_CommConfig, B110);
254
+            break;
255
+        case BAUD134:
256
+            setBaudRate2Termios(&Posix_CommConfig, B134);
257
+            break;
258
+        case BAUD150:
259
+            setBaudRate2Termios(&Posix_CommConfig, B150);
260
+            break;
261
+        case BAUD200:
262
+            setBaudRate2Termios(&Posix_CommConfig, B200);
263
+            break;
264
+        case BAUD300:
265
+            setBaudRate2Termios(&Posix_CommConfig, B300);
266
+            break;
267
+        case BAUD600:
268
+            setBaudRate2Termios(&Posix_CommConfig, B600);
269
+            break;
270
+        case BAUD1200:
271
+            setBaudRate2Termios(&Posix_CommConfig, B1200);
272
+            break;
273
+        case BAUD1800:
274
+            setBaudRate2Termios(&Posix_CommConfig, B1800);
275
+            break;
276
+        case BAUD2400:
277
+            setBaudRate2Termios(&Posix_CommConfig, B2400);
278
+            break;
279
+        case BAUD4800:
280
+            setBaudRate2Termios(&Posix_CommConfig, B4800);
281
+            break;
282
+        case BAUD9600:
283
+            setBaudRate2Termios(&Posix_CommConfig, B9600);
284
+            break;
285
+        case BAUD19200:
286
+            setBaudRate2Termios(&Posix_CommConfig, B19200);
287
+            break;
288
+        case BAUD38400:
289
+            setBaudRate2Termios(&Posix_CommConfig, B38400);
290
+            break;
291
+        case BAUD57600:
292
+            setBaudRate2Termios(&Posix_CommConfig, B57600);
293
+            break;
294
+#ifdef B76800
295
+        case BAUD76800:
296
+            setBaudRate2Termios(&Posix_CommConfig, B76800);
297
+            break;
298
+#endif
299
+        case BAUD115200:
300
+            setBaudRate2Termios(&Posix_CommConfig, B115200);
301
+            break;
302
+#if defined(B230400) && defined(B4000000)
303
+        case BAUD230400:
304
+            setBaudRate2Termios(&Posix_CommConfig, B230400);
305
+            break;
306
+        case BAUD460800:
307
+            setBaudRate2Termios(&Posix_CommConfig, B460800);
308
+            break;
309
+        case BAUD500000:
310
+            setBaudRate2Termios(&Posix_CommConfig, B500000);
311
+            break;
312
+        case BAUD576000:
313
+            setBaudRate2Termios(&Posix_CommConfig, B576000);
314
+            break;
315
+        case BAUD921600:
316
+            setBaudRate2Termios(&Posix_CommConfig, B921600);
317
+            break;
318
+        case BAUD1000000:
319
+            setBaudRate2Termios(&Posix_CommConfig, B1000000);
320
+            break;
321
+        case BAUD1152000:
322
+            setBaudRate2Termios(&Posix_CommConfig, B1152000);
323
+            break;
324
+        case BAUD1500000:
325
+            setBaudRate2Termios(&Posix_CommConfig, B1500000);
326
+            break;
327
+        case BAUD2000000:
328
+            setBaudRate2Termios(&Posix_CommConfig, B2000000);
329
+            break;
330
+        case BAUD2500000:
331
+            setBaudRate2Termios(&Posix_CommConfig, B2500000);
332
+            break;
333
+        case BAUD3000000:
334
+            setBaudRate2Termios(&Posix_CommConfig, B3000000);
335
+            break;
336
+        case BAUD3500000:
337
+            setBaudRate2Termios(&Posix_CommConfig, B3500000);
338
+            break;
339
+        case BAUD4000000:
340
+            setBaudRate2Termios(&Posix_CommConfig, B4000000);
341
+            break;
342
+#endif
343
+        }
344
+    }
345
+    if (settingsDirtyFlags & DFE_Parity) {
346
+        switch (Settings.Parity) {
347
+        case PAR_SPACE:
348
+            /*space parity not directly supported - add an extra data bit to simulate it*/
349
+            settingsDirtyFlags |= DFE_DataBits;
350
+            break;
351
+        case PAR_NONE:
352
+            Posix_CommConfig.c_cflag &= (~PARENB);
353
+            break;
354
+        case PAR_EVEN:
355
+            Posix_CommConfig.c_cflag &= (~PARODD);
356
+            Posix_CommConfig.c_cflag |= PARENB;
357
+            break;
358
+        case PAR_ODD:
359
+            Posix_CommConfig.c_cflag |= (PARENB|PARODD);
360
+            break;
361
+        }
362
+    }
363
+    /*must after Parity settings*/
364
+    if (settingsDirtyFlags & DFE_DataBits) {
365
+        if (Settings.Parity != PAR_SPACE) {
366
+            Posix_CommConfig.c_cflag &= (~CSIZE);
367
+            switch(Settings.DataBits) {
368
+            case DATA_5:
369
+                Posix_CommConfig.c_cflag |= CS5;
370
+                break;
371
+            case DATA_6:
372
+                Posix_CommConfig.c_cflag |= CS6;
373
+                break;
374
+            case DATA_7:
375
+                Posix_CommConfig.c_cflag |= CS7;
376
+                break;
377
+            case DATA_8:
378
+                Posix_CommConfig.c_cflag |= CS8;
379
+                break;
380
+            }
381
+        } else {
382
+            /*space parity not directly supported - add an extra data bit to simulate it*/
383
+            Posix_CommConfig.c_cflag &= ~(PARENB|CSIZE);
384
+            switch(Settings.DataBits) {
385
+            case DATA_5:
386
+                Posix_CommConfig.c_cflag |= CS6;
387
+                break;
388
+            case DATA_6:
389
+                Posix_CommConfig.c_cflag |= CS7;
390
+                break;
391
+            case DATA_7:
392
+                Posix_CommConfig.c_cflag |= CS8;
393
+                break;
394
+            case DATA_8:
395
+                /*this will never happen, put here to Suppress an warning*/
396
+                break;
397
+            }
398
+        }
399
+    }
400
+    if (settingsDirtyFlags & DFE_StopBits) {
401
+        switch (Settings.StopBits) {
402
+        case STOP_1:
403
+            Posix_CommConfig.c_cflag &= (~CSTOPB);
404
+            break;
405
+        case STOP_2:
406
+            Posix_CommConfig.c_cflag |= CSTOPB;
407
+            break;
408
+        }
409
+    }
410
+    if (settingsDirtyFlags & DFE_Flow) {
411
+        switch(Settings.FlowControl) {
412
+        case FLOW_OFF:
413
+            Posix_CommConfig.c_cflag &= (~CRTSCTS);
414
+            Posix_CommConfig.c_iflag &= (~(IXON|IXOFF|IXANY));
415
+            break;
416
+        case FLOW_XONXOFF:
417
+            /*software (XON/XOFF) flow control*/
418
+            Posix_CommConfig.c_cflag &= (~CRTSCTS);
419
+            Posix_CommConfig.c_iflag |= (IXON|IXOFF|IXANY);
420
+            break;
421
+        case FLOW_HARDWARE:
422
+            Posix_CommConfig.c_cflag |= CRTSCTS;
423
+            Posix_CommConfig.c_iflag &= (~(IXON|IXOFF|IXANY));
424
+            break;
425
+        }
426
+    }
427
+
428
+    /*if any thing in Posix_CommConfig changed, flush*/
429
+    if (settingsDirtyFlags & DFE_Settings_Mask)
430
+        ::tcsetattr(fd, TCSAFLUSH, &Posix_CommConfig);
431
+
432
+    if (settingsDirtyFlags & DFE_TimeOut) {
433
+        int millisec = Settings.Timeout_Millisec;
434
+        if (millisec == -1) {
435
+            ::fcntl(fd, F_SETFL, O_NDELAY);
436
+        }
437
+        else {
438
+            //O_SYNC should enable blocking ::write()
439
+            //however this seems not working on Linux 2.6.21 (works on OpenBSD 4.2)
440
+            ::fcntl(fd, F_SETFL, O_SYNC);
441
+        }
442
+        ::tcgetattr(fd, & Posix_CommConfig);
443
+        Posix_CommConfig.c_cc[VTIME] = millisec/100;
444
+        ::tcsetattr(fd, TCSAFLUSH, & Posix_CommConfig);
445
+    }
446
+
447
+    settingsDirtyFlags = 0;
448
+}

+ 427
- 0
src/3rdparty/qextserialport/src/qextserialport_win.cpp View File

@@ -0,0 +1,427 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextserialport.h"
33
+#include "qextserialport_p.h"
34
+#include <QtCore/QThread>
35
+#include <QtCore/QReadWriteLock>
36
+#include <QtCore/QMutexLocker>
37
+#include <QtCore/QDebug>
38
+#include <QtCore/QRegExp>
39
+#include <QtCore/QMetaType>
40
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
41
+#  include <QtCore/QWinEventNotifier>
42
+#  define WinEventNotifier QWinEventNotifier
43
+#elif !defined(QESP_NO_QT4_PRIVATE)
44
+#  include <QtCore/private/qwineventnotifier_p.h>
45
+#  define WinEventNotifier QWinEventNotifier
46
+#else
47
+#  include "qextwineventnotifier_p.h"
48
+#  define WinEventNotifier QextWinEventNotifier
49
+#endif
50
+void QextSerialPortPrivate::platformSpecificInit()
51
+{
52
+    Win_Handle=INVALID_HANDLE_VALUE;
53
+    ZeroMemory(&overlap, sizeof(OVERLAPPED));
54
+    overlap.hEvent = CreateEvent(NULL, true, false, NULL);
55
+    winEventNotifier = 0;
56
+    bytesToWriteLock = new QReadWriteLock;
57
+    _bytesToWrite = 0;
58
+}
59
+
60
+void QextSerialPortPrivate::platformSpecificDestruct() {
61
+    CloseHandle(overlap.hEvent);
62
+    delete bytesToWriteLock;
63
+}
64
+
65
+
66
+/*!
67
+    \internal
68
+    COM ports greater than 9 need \\.\ prepended
69
+
70
+    This is only need when open the port.
71
+*/
72
+static QString fullPortNameWin(const QString & name)
73
+{
74
+    QRegExp rx(QLatin1String("^COM(\\d+)"));
75
+    QString fullName(name);
76
+    if(fullName.contains(rx))
77
+        fullName.prepend(QLatin1String("\\\\.\\"));
78
+    return fullName;
79
+}
80
+
81
+bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode)
82
+{
83
+    Q_Q(QextSerialPort);
84
+    DWORD confSize = sizeof(COMMCONFIG);
85
+    Win_CommConfig.dwSize = confSize;
86
+    DWORD dwFlagsAndAttributes = 0;
87
+    if (_queryMode == QextSerialPort::EventDriven)
88
+        dwFlagsAndAttributes += FILE_FLAG_OVERLAPPED;
89
+
90
+    /*open the port*/
91
+    Win_Handle=CreateFileW((wchar_t*)fullPortNameWin(port).utf16(), GENERIC_READ|GENERIC_WRITE,
92
+                           0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL);
93
+    if (Win_Handle!=INVALID_HANDLE_VALUE) {
94
+        q->setOpenMode(mode);
95
+        /*configure port settings*/
96
+        GetCommConfig(Win_Handle, &Win_CommConfig, &confSize);
97
+        GetCommState(Win_Handle, &(Win_CommConfig.dcb));
98
+
99
+        /*set up parameters*/
100
+        Win_CommConfig.dcb.fBinary=TRUE;
101
+        Win_CommConfig.dcb.fInX=FALSE;
102
+        Win_CommConfig.dcb.fOutX=FALSE;
103
+        Win_CommConfig.dcb.fAbortOnError=FALSE;
104
+        Win_CommConfig.dcb.fNull=FALSE;
105
+        /* Dtr default to true. See Issue 122*/
106
+        Win_CommConfig.dcb.fDtrControl=TRUE;
107
+        /*flush all settings*/
108
+        settingsDirtyFlags = DFE_ALL;
109
+        updatePortSettings();
110
+
111
+        //init event driven approach
112
+        if (_queryMode == QextSerialPort::EventDriven) {
113
+            if (!SetCommMask( Win_Handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) {
114
+                QESP_WARNING()<<"failed to set Comm Mask. Error code:"<<GetLastError();
115
+                return false;
116
+            }
117
+            winEventNotifier = new WinEventNotifier(overlap.hEvent, q);
118
+            qRegisterMetaType<HANDLE>("HANDLE");
119
+            q->connect(winEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onWinEvent(HANDLE)), Qt::DirectConnection);
120
+            WaitCommEvent(Win_Handle, &eventMask, &overlap);
121
+        }
122
+        return true;
123
+    }
124
+    return false;
125
+}
126
+
127
+bool QextSerialPortPrivate::close_sys()
128
+{
129
+    flush_sys();
130
+    CancelIo(Win_Handle);
131
+    if (CloseHandle(Win_Handle))
132
+        Win_Handle = INVALID_HANDLE_VALUE;
133
+    if (winEventNotifier){
134
+        winEventNotifier->setEnabled(false);
135
+        winEventNotifier->deleteLater();
136
+        winEventNotifier = 0;
137
+    }
138
+    _bytesToWrite = 0;
139
+
140
+    foreach(OVERLAPPED* o, pendingWrites) {
141
+        CloseHandle(o->hEvent);
142
+        delete o;
143
+    }
144
+    pendingWrites.clear();
145
+    return true;
146
+}
147
+
148
+bool QextSerialPortPrivate::flush_sys()
149
+{
150
+    FlushFileBuffers(Win_Handle);
151
+    return true;
152
+}
153
+
154
+qint64 QextSerialPortPrivate::bytesAvailable_sys() const
155
+{
156
+    DWORD Errors;
157
+    COMSTAT Status;
158
+    if (ClearCommError(Win_Handle, &Errors, &Status)) {
159
+        return Status.cbInQue;
160
+    }
161
+    return (qint64)-1;
162
+}
163
+
164
+/*
165
+    Translates a system-specific error code to a QextSerialPort error code.  Used internally.
166
+*/
167
+void QextSerialPortPrivate::translateError(ulong error)
168
+{
169
+    if (error&CE_BREAK) {
170
+        lastErr=E_BREAK_CONDITION;
171
+    }
172
+    else if (error&CE_FRAME) {
173
+        lastErr=E_FRAMING_ERROR;
174
+    }
175
+    else if (error&CE_IOE) {
176
+        lastErr=E_IO_ERROR;
177
+    }
178
+    else if (error&CE_MODE) {
179
+        lastErr=E_INVALID_FD;
180
+    }
181
+    else if (error&CE_OVERRUN) {
182
+        lastErr=E_BUFFER_OVERRUN;
183
+    }
184
+    else if (error&CE_RXPARITY) {
185
+        lastErr=E_RECEIVE_PARITY_ERROR;
186
+    }
187
+    else if (error&CE_RXOVER) {
188
+        lastErr=E_RECEIVE_OVERFLOW;
189
+    }
190
+    else if (error&CE_TXFULL) {
191
+        lastErr=E_TRANSMIT_OVERFLOW;
192
+    }
193
+}
194
+
195
+/*
196
+    Reads a block of data from the serial port.  This function will read at most maxlen bytes from
197
+    the serial port and place them in the buffer pointed to by data.  Return value is the number of
198
+    bytes actually read, or -1 on error.
199
+    
200
+    \warning before calling this function ensure that serial port associated with this class
201
+    is currently open (use isOpen() function to check if port is open).
202
+*/
203
+qint64 QextSerialPortPrivate::readData_sys(char *data, qint64 maxSize)
204
+{
205
+    DWORD bytesRead = 0;
206
+    bool failed = false;
207
+    if (_queryMode == QextSerialPort::EventDriven) {
208
+        OVERLAPPED overlapRead;
209
+        ZeroMemory(&overlapRead, sizeof(OVERLAPPED));
210
+        if (!ReadFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesRead, & overlapRead)) {
211
+            if (GetLastError() == ERROR_IO_PENDING)
212
+                GetOverlappedResult(Win_Handle, & overlapRead, & bytesRead, true);
213
+            else
214
+                failed = true;
215
+        }
216
+    } else if (!ReadFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesRead, NULL)) {
217
+        failed = true;
218
+    }
219
+    if (!failed)
220
+        return (qint64)bytesRead;
221
+
222
+    lastErr = E_READ_FAILED;
223
+    return -1;
224
+}
225
+
226
+/*
227
+    Writes a block of data to the serial port.  This function will write len bytes
228
+    from the buffer pointed to by data to the serial port.  Return value is the number
229
+    of bytes actually written, or -1 on error.
230
+    
231
+    \warning before calling this function ensure that serial port associated with this class
232
+    is currently open (use isOpen() function to check if port is open).
233
+*/
234
+qint64 QextSerialPortPrivate::writeData_sys(const char *data, qint64 maxSize)
235
+{
236
+    DWORD bytesWritten = 0;
237
+    bool failed = false;
238
+    if (_queryMode == QextSerialPort::EventDriven) {
239
+        OVERLAPPED* newOverlapWrite = new OVERLAPPED;
240
+        ZeroMemory(newOverlapWrite, sizeof(OVERLAPPED));
241
+        newOverlapWrite->hEvent = CreateEvent(NULL, true, false, NULL);
242
+        if (WriteFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesWritten, newOverlapWrite)) {
243
+            CloseHandle(newOverlapWrite->hEvent);
244
+            delete newOverlapWrite;
245
+        }
246
+        else if (GetLastError() == ERROR_IO_PENDING) {
247
+            // writing asynchronously...not an error
248
+            QWriteLocker writelocker(bytesToWriteLock);
249
+            _bytesToWrite += maxSize;
250
+            pendingWrites.append(newOverlapWrite);
251
+        }
252
+        else {
253
+            QESP_WARNING()<<"QextSerialPort write error:"<<GetLastError();
254
+            failed = true;
255
+            if(!CancelIo(newOverlapWrite->hEvent))
256
+                QESP_WARNING("QextSerialPort: couldn't cancel IO");
257
+            if(!CloseHandle(newOverlapWrite->hEvent))
258
+                QESP_WARNING("QextSerialPort: couldn't close OVERLAPPED handle");
259
+            delete newOverlapWrite;
260
+        }
261
+    } else if (!WriteFile(Win_Handle, (void*)data, (DWORD)maxSize, & bytesWritten, NULL)) {
262
+        failed = true;
263
+    }
264
+
265
+    if (!failed)
266
+        return (qint64)bytesWritten;
267
+
268
+    lastErr = E_WRITE_FAILED;
269
+    return -1;
270
+}
271
+
272
+void QextSerialPortPrivate::setDtr_sys(bool set) {
273
+    EscapeCommFunction(Win_Handle, set ? SETDTR : CLRDTR);
274
+}
275
+
276
+void QextSerialPortPrivate::setRts_sys(bool set) {
277
+    EscapeCommFunction(Win_Handle, set ? SETRTS : CLRRTS);
278
+}
279
+
280
+ulong QextSerialPortPrivate::lineStatus_sys(void) {
281
+    unsigned long Status=0, Temp=0;
282
+    GetCommModemStatus(Win_Handle, &Temp);
283
+    if (Temp & MS_CTS_ON) Status|=LS_CTS;
284
+    if (Temp & MS_DSR_ON) Status|=LS_DSR;
285
+    if (Temp & MS_RING_ON) Status|=LS_RI;
286
+    if (Temp & MS_RLSD_ON) Status|=LS_DCD;
287
+    return Status;
288
+}
289
+
290
+/*
291
+  Triggered when there's activity on our HANDLE.
292
+*/
293
+void QextSerialPortPrivate::_q_onWinEvent(HANDLE h)
294
+{
295
+    Q_Q(QextSerialPort);
296
+    if(h == overlap.hEvent) {
297
+        if (eventMask & EV_RXCHAR) {
298
+            if (q->sender() != q && bytesAvailable_sys() > 0)
299
+                _q_canRead();
300
+        }
301
+        if (eventMask & EV_TXEMPTY) {
302
+            /*
303
+              A write completed.  Run through the list of OVERLAPPED writes, and if
304
+              they completed successfully, take them off the list and delete them.
305
+              Otherwise, leave them on there so they can finish.
306
+            */
307
+            qint64 totalBytesWritten = 0;
308
+            QList<OVERLAPPED*> overlapsToDelete;
309
+            foreach(OVERLAPPED* o, pendingWrites) {
310
+                DWORD numBytes = 0;
311
+                if (GetOverlappedResult(Win_Handle, o, & numBytes, false)) {
312
+                    overlapsToDelete.append(o);
313
+                    totalBytesWritten += numBytes;
314
+                } else if( GetLastError() != ERROR_IO_INCOMPLETE ) {
315
+                    overlapsToDelete.append(o);
316
+                    QESP_WARNING()<<"CommEvent overlapped write error:" << GetLastError();
317
+                }
318
+            }
319
+
320
+            if (q->sender() != q && totalBytesWritten > 0) {
321
+                QWriteLocker writelocker(bytesToWriteLock);
322
+                Q_EMIT q->bytesWritten(totalBytesWritten);
323
+                _bytesToWrite = 0;
324
+            }
325
+
326
+            foreach(OVERLAPPED* o, overlapsToDelete) {
327
+                OVERLAPPED *toDelete = pendingWrites.takeAt(pendingWrites.indexOf(o));
328
+                CloseHandle(toDelete->hEvent);
329
+                delete toDelete;
330
+            }
331
+        }
332
+        if (eventMask & EV_DSR) {
333
+            if (lineStatus_sys() & LS_DSR)
334
+                Q_EMIT q->dsrChanged(true);
335
+            else
336
+                Q_EMIT q->dsrChanged(false);
337
+        }
338
+    }
339
+    WaitCommEvent(Win_Handle, &eventMask, &overlap);
340
+}
341
+
342
+void QextSerialPortPrivate::updatePortSettings()
343
+{
344
+    if (!q_ptr->isOpen() || !settingsDirtyFlags)
345
+        return;
346
+
347
+    //fill struct : COMMCONFIG
348
+    if (settingsDirtyFlags & DFE_BaudRate) {
349
+        Win_CommConfig.dcb.BaudRate = Settings.BaudRate;
350
+    }
351
+    if (settingsDirtyFlags & DFE_Parity) {
352
+        Win_CommConfig.dcb.Parity = (BYTE)Settings.Parity;
353
+        Win_CommConfig.dcb.fParity = (Settings.Parity == PAR_NONE) ? FALSE : TRUE;
354
+    }
355
+    if (settingsDirtyFlags & DFE_DataBits) {
356
+        Win_CommConfig.dcb.ByteSize = (BYTE)Settings.DataBits;
357
+    }
358
+    if (settingsDirtyFlags & DFE_StopBits) {
359
+        switch (Settings.StopBits) {
360
+        case STOP_1:
361
+            Win_CommConfig.dcb.StopBits = ONESTOPBIT;
362
+            break;
363
+        case STOP_1_5:
364
+            Win_CommConfig.dcb.StopBits = ONE5STOPBITS;
365
+            break;
366
+        case STOP_2:
367
+            Win_CommConfig.dcb.StopBits = TWOSTOPBITS;
368
+            break;
369
+        }
370
+    }
371
+    if (settingsDirtyFlags & DFE_Flow) {
372
+        switch(Settings.FlowControl) {
373
+        /*no flow control*/
374
+        case FLOW_OFF:
375
+            Win_CommConfig.dcb.fOutxCtsFlow=FALSE;
376
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE;
377
+            Win_CommConfig.dcb.fInX=FALSE;
378
+            Win_CommConfig.dcb.fOutX=FALSE;
379
+            break;
380
+        /*software (XON/XOFF) flow control*/
381
+        case FLOW_XONXOFF:
382
+            Win_CommConfig.dcb.fOutxCtsFlow=FALSE;
383
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE;
384
+            Win_CommConfig.dcb.fInX=TRUE;
385
+            Win_CommConfig.dcb.fOutX=TRUE;
386
+            break;
387
+        /*hardware flow control*/
388
+        case FLOW_HARDWARE:
389
+            Win_CommConfig.dcb.fOutxCtsFlow=TRUE;
390
+            Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
391
+            Win_CommConfig.dcb.fInX=FALSE;
392
+            Win_CommConfig.dcb.fOutX=FALSE;
393
+            break;
394
+        }
395
+    }
396
+
397
+    //fill struct : COMMTIMEOUTS
398
+    if (settingsDirtyFlags & DFE_TimeOut) {
399
+        if (_queryMode != QextSerialPort::EventDriven) {
400
+            int millisec = Settings.Timeout_Millisec;
401
+            if (millisec == -1) {
402
+                Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD;
403
+                Win_CommTimeouts.ReadTotalTimeoutConstant = 0;
404
+            } else {
405
+                Win_CommTimeouts.ReadIntervalTimeout = millisec;
406
+                Win_CommTimeouts.ReadTotalTimeoutConstant = millisec;
407
+            }
408
+            Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
409
+            Win_CommTimeouts.WriteTotalTimeoutMultiplier = millisec;
410
+            Win_CommTimeouts.WriteTotalTimeoutConstant = 0;
411
+        }
412
+        else {
413
+            Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD;
414
+            Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
415
+            Win_CommTimeouts.ReadTotalTimeoutConstant = 0;
416
+            Win_CommTimeouts.WriteTotalTimeoutMultiplier = 0;
417
+            Win_CommTimeouts.WriteTotalTimeoutConstant = 0;
418
+        }
419
+    }
420
+
421
+
422
+    if (settingsDirtyFlags & DFE_Settings_Mask)
423
+        SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG));
424
+    if ((settingsDirtyFlags & DFE_TimeOut))
425
+        SetCommTimeouts(Win_Handle, &Win_CommTimeouts);
426
+    settingsDirtyFlags = 0;
427
+}

+ 247
- 0
src/3rdparty/qextserialport/src/qextwineventnotifier_p.cpp View File

@@ -0,0 +1,247 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#include "qextwineventnotifier_p.h"
33
+#include <QtCore/QThread>
34
+#include <QtCore/QList>
35
+#include <QtCore/QMutex>
36
+#include <QtCore/QMutexLocker>
37
+#include <QtCore/QEvent>
38
+#include <QtCore/QDebug>
39
+#include <QtCore/QCoreApplication>
40
+
41
+class QextWinEventNotifierPrivate
42
+{
43
+    Q_DECLARE_PUBLIC(QextWinEventNotifier)
44
+public:
45
+    QextWinEventNotifierPrivate(HANDLE hEvent, QextWinEventNotifier * q)
46
+        :handleToEvent(hEvent), enabled(false), q_ptr(q)
47
+    {}
48
+
49
+    HANDLE handleToEvent;
50
+    bool enabled;
51
+private:
52
+    QextWinEventNotifier * q_ptr;
53
+};
54
+
55
+/*
56
+  \internal
57
+
58
+  \class QextWinEventNotifierThread
59
+
60
+  This class works more or less like an EventDispatcher.
61
+
62
+  The api function WaitForMultipleObjects() is used in the new thread
63
+  to wait for the  registered handle.
64
+*/
65
+class QextWinEventNotifierThread:public QThread
66
+{
67
+public:
68
+    explicit QextWinEventNotifierThread(QObject * parent=0);
69
+    ~QextWinEventNotifierThread();
70
+    void stop();
71
+    bool registerEventNotifier(QextWinEventNotifier * notifier);
72
+    void unregisterEventNotifier(QextWinEventNotifier * notifier);
73
+protected:
74
+    void run();
75
+private:
76
+    HANDLE hStopEvent; //stop thread when this event signaled.
77
+    HANDLE hUpdateEvent; //make sure eventlist updated.
78
+    QMutex mutex;
79
+    QList<QextWinEventNotifier *> winEventNotifierList;
80
+};
81
+
82
+Q_GLOBAL_STATIC(QextWinEventNotifierThread, notifierThread)
83
+
84
+QextWinEventNotifierThread::QextWinEventNotifierThread(QObject * parent)
85
+    :QThread(parent)
86
+{
87
+    hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
88
+    hUpdateEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
89
+    start();
90
+}
91
+
92
+QextWinEventNotifierThread::~QextWinEventNotifierThread()
93
+{
94
+    if (isRunning())
95
+        stop();
96
+    CloseHandle(hStopEvent);
97
+    CloseHandle(hUpdateEvent);
98
+}
99
+
100
+void QextWinEventNotifierThread::stop()
101
+{
102
+    {
103
+        QMutexLocker locker(&mutex);
104
+        SetEvent(hStopEvent);
105
+    }
106
+    wait();    /// Is this an good idea?
107
+}
108
+
109
+bool QextWinEventNotifierThread::registerEventNotifier(QextWinEventNotifier *notifier)
110
+{
111
+    QMutexLocker locker(&mutex);
112
+    if (!notifier) {
113
+        QESP_WARNING("QextWinEventNotifier: Internal error");
114
+        return false;
115
+    }
116
+    if (winEventNotifierList.contains(notifier))
117
+        return true;
118
+    if (winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 3) {
119
+        QESP_WARNING("QextWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 3);
120
+        return false;
121
+    }
122
+    winEventNotifierList.append(notifier);
123
+    SetEvent(hUpdateEvent);
124
+    return true;
125
+}
126
+
127
+void QextWinEventNotifierThread::unregisterEventNotifier(QextWinEventNotifier *notifier)
128
+{
129
+    QMutexLocker locker(&mutex);
130
+    if (!notifier) {
131
+        QESP_WARNING("QextWinEventNotifier: Internal error");
132
+        return;
133
+    }
134
+
135
+    int idx = winEventNotifierList.indexOf(notifier);
136
+    if (idx != -1) {
137
+        winEventNotifierList.takeAt(idx);
138
+        SetEvent(hUpdateEvent);
139
+    }
140
+}
141
+
142
+void QextWinEventNotifierThread::run()
143
+{
144
+    forever{
145
+        HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
146
+        DWORD nCount = 0;
147
+        {
148
+            QMutexLocker locker(&mutex);
149
+            nCount = winEventNotifierList.count();
150
+            for (int i=0; i<(int)nCount; ++i)
151
+                pHandles[i] = winEventNotifierList.at(i)->handle();
152
+            pHandles[nCount] = hUpdateEvent;
153
+            pHandles[nCount+1] = hStopEvent;
154
+        }
155
+        DWORD ret = WaitForMultipleObjects(nCount+2, pHandles, FALSE, INFINITE);
156
+        if (ret >= WAIT_OBJECT_0 && ret < WAIT_OBJECT_0 + nCount) {
157
+            QEvent *evt = new QEvent(QEvent::User);
158
+            QMutexLocker locker(&mutex);
159
+            ResetEvent(pHandles[ret-WAIT_OBJECT_0]);
160
+            QObject * notifier = winEventNotifierList[ret - WAIT_OBJECT_0];
161
+            QCoreApplication::postEvent(notifier, evt);
162
+        }
163
+        else if (ret == WAIT_OBJECT_0 + nCount) {
164
+            //ResetEvent(hUpdateEvent);
165
+        }
166
+        else if (ret == WAIT_OBJECT_0 + nCount + 1) {
167
+            //qDebug()<<"quit...";
168
+            return;
169
+        }
170
+    }
171
+}
172
+
173
+/*!
174
+    \internal
175
+    \class QextWinEventNotifier
176
+    \brief The QextWinEventNotifier class provides support for the Windows Wait functions.
177
+
178
+    The QextWinEventNotifier class makes it possible to use the wait
179
+    functions on windows in a asynchronous manner. With this class
180
+    you can register a HANDLE to an event and get notification when
181
+    that event becomes signalled.
182
+
183
+    \bold Note: If it is a manual reset event ,it will be reset before
184
+    the notification. This is different from QWinEventNotifier.
185
+
186
+    \bold Note: All the registered handles will be waited under a new thread.
187
+    This is different from QWinEventNotifier whose event handle will be waited
188
+    in its affinal thread.
189
+*/
190
+
191
+QextWinEventNotifier::QextWinEventNotifier(QObject *parent)
192
+    : QObject(parent), d_ptr(new QextWinEventNotifierPrivate(0, this))
193
+{}
194
+
195
+QextWinEventNotifier::QextWinEventNotifier(HANDLE hEvent, QObject *parent)
196
+ : QObject(parent), d_ptr(new QextWinEventNotifierPrivate(hEvent, this))
197
+{
198
+    setEnabled(true);
199
+}
200
+
201
+QextWinEventNotifier::~QextWinEventNotifier()
202
+{
203
+    setEnabled(false);
204
+}
205
+
206
+void QextWinEventNotifier::setHandle(HANDLE hEvent)
207
+{
208
+    setEnabled(false);
209
+    Q_D(QextWinEventNotifier);
210
+    d->handleToEvent = hEvent;
211
+}
212
+
213
+HANDLE  QextWinEventNotifier::handle() const
214
+{
215
+    return d_func()->handleToEvent;
216
+}
217
+
218
+bool QextWinEventNotifier::isEnabled() const
219
+{
220
+    return d_func()->enabled;
221
+}
222
+
223
+void QextWinEventNotifier::setEnabled(bool enable)
224
+{
225
+    Q_D(QextWinEventNotifier);
226
+
227
+    if (d->enabled == enable)
228
+        return;
229
+    d->enabled = enable;
230
+
231
+    if (d->enabled)
232
+        notifierThread()->registerEventNotifier(this);
233
+    else
234
+        notifierThread()->unregisterEventNotifier(this);
235
+}
236
+
237
+bool QextWinEventNotifier::event(QEvent * e)
238
+{
239
+    Q_D(QextWinEventNotifier);
240
+    QObject::event(e);
241
+    if (e->type() == QEvent::User) {
242
+        emit activated(d->handleToEvent);
243
+        return true;
244
+    }
245
+    return false;
246
+}
247
+

+ 80
- 0
src/3rdparty/qextserialport/src/qextwineventnotifier_p.h View File

@@ -0,0 +1,80 @@
1
+/****************************************************************************
2
+** Copyright (c) 2000-2003 Wayne Roth
3
+** Copyright (c) 2004-2007 Stefan Sander
4
+** Copyright (c) 2007 Michal Policht
5
+** Copyright (c) 2008 Brandon Fosdick
6
+** Copyright (c) 2009-2010 Liam Staskawicz
7
+** Copyright (c) 2011 Debao Zhang
8
+** All right reserved.
9
+** Web: http://code.google.com/p/qextserialport/
10
+**
11
+** Permission is hereby granted, free of charge, to any person obtaining
12
+** a copy of this software and associated documentation files (the
13
+** "Software"), to deal in the Software without restriction, including
14
+** without limitation the rights to use, copy, modify, merge, publish,
15
+** distribute, sublicense, and/or sell copies of the Software, and to
16
+** permit persons to whom the Software is furnished to do so, subject to
17
+** the following conditions:
18
+**
19
+** The above copyright notice and this permission notice shall be
20
+** included in all copies or substantial portions of the Software.
21
+**
22
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
+** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
+** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
+** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
+**
30
+****************************************************************************/
31
+
32
+#ifndef QEXTWINEVENTNOTIFIER_P_H_
33
+#define QEXTWINEVENTNOTIFIER_P_H_
34
+
35
+//
36
+//  W A R N I N G
37
+//  -------------
38
+//
39
+// This file is not part of the QESP API.  It exists for the convenience
40
+// of other QESP classes.  This header file may change from version to
41
+// version without notice, or even be removed.
42
+//
43
+// We mean it.
44
+//
45
+
46
+#include <QtCore/QObject>
47
+#include <QtCore/qt_windows.h>
48
+#include "qextserialport_global.h"
49
+
50
+class QextWinEventNotifierPrivate;
51
+class QEXTSERIALPORT_EXPORT QextWinEventNotifier : public QObject
52
+{
53
+    Q_OBJECT
54
+    Q_DECLARE_PRIVATE(QextWinEventNotifier)
55
+
56
+public:
57
+    explicit QextWinEventNotifier(QObject *parent = 0);
58
+    explicit QextWinEventNotifier(HANDLE hEvent, QObject *parent = 0);
59
+    ~QextWinEventNotifier();
60
+
61
+    void setHandle(HANDLE hEvent);
62
+    HANDLE handle() const;
63
+
64
+    bool isEnabled() const;
65
+
66
+public Q_SLOTS:
67
+    void setEnabled(bool enable);
68
+
69
+Q_SIGNALS:
70
+    void activated(HANDLE hEvent);
71
+
72
+protected:
73
+    bool event(QEvent * e);
74
+
75
+private:
76
+    Q_DISABLE_COPY(QextWinEventNotifier)
77
+    QextWinEventNotifierPrivate * d_ptr;
78
+};
79
+
80
+#endif // QEXTWINEVENTNOTIFIER_P_H_

+ 0
- 0
src/3rdparty/qextserialport/tests/qextwineventnotifier/qextwineventnotifier.pro View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save