Browse Source

Merge branch 'release-1.6.2'

Neal Wilson 11 years ago
parent
commit
b386790a8d

+ 19
- 4
config/Reports/auco.xml View File

@@ -65,7 +65,7 @@
65 65
                 output.writeStartElement("thead");
66 66
                 output.writeStartElement("tr");
67 67
                 output.writeStartElement("th");
68
-                output.writeAttribute("colspan", "5");
68
+                output.writeAttribute("colspan", "8");
69 69
                 output.writeCharacters("Regular Coffees");
70 70
                 output.writeEndElement();
71 71
                 output.writeEndElement();
@@ -75,6 +75,9 @@
75 75
                 output.writeTextElement("th", "Avg. Cost");
76 76
 				output.writeTextElement("th", "Last Cost");
77 77
 				output.writeTextElement("th", "Last Purchase Date");
78
+				output.writeTextElement("th", "Bag Size (min)");
79
+				output.writeTextElement("th", "Bag Size (max)");
80
+				output.writeTextElement("th", "Bag Size (mean)");
78 81
                 output.writeEndElement();
79 82
                 output.writeEndElement();
80 83
                 output.writeStartElement("tbody");
@@ -105,10 +108,13 @@
105 108
 						orderClause = "cost DESC";
106 109
 						break;
107 110
 				}
108
-				query.prepare("SELECT DISTINCT origin, (avg(rate)/:conversion)::numeric(10,2) AS rate, (SELECT avg(cost)*:conversion2 FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost, (SELECT avg(cost)*:conversion3 FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin) AND time = (SELECT max(time) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))), (SELECT max(time)::date FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin)) FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY " + orderClause);
111
+				query.prepare("SELECT DISTINCT origin, (avg(rate)/:conversion)::numeric(10,2) AS rate, (SELECT avg(cost)*:conversion2 FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost, (SELECT avg(cost)*:conversion3 FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin) AND time = (SELECT max(time) FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))), (SELECT max(time)::date FROM purchase WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin)), (SELECT min(conversion)/:conversion4 FROM lb_bag_conversion WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS minbag, (SELECT max(conversion)/:conversion5 FROM lb_bag_conversion WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS maxbag, (SELECT avg(conversion)/:conversion6 FROM lb_bag_conversion WHERE item IN (SELECT id FROM regular_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS meanbag FROM coffee_history WHERE id IN (SELECT id FROM regular_coffees) GROUP BY origin ORDER BY " + orderClause);
109 112
 				query.bind(":conversion", conversion);
110 113
 				query.bind(":conversion2", conversion);
111 114
 				query.bind(":conversion3", conversion);
115
+				query.bind(":conversion4", conversion);
116
+				query.bind(":conversion5", conversion);
117
+				query.bind(":conversion6", conversion);
112 118
 				query.exec();
113 119
                 while(query.next())
114 120
                 {
@@ -118,18 +124,24 @@
118 124
                     output.writeTextElement("td", query.value(2));
119 125
 					output.writeTextElement("td", query.value(3));
120 126
 					output.writeTextElement("td", query.value(4));
127
+					output.writeTextElement("td", query.value(5));
128
+					output.writeTextElement("td", query.value(6));
129
+					output.writeTextElement("td", query.value(7));
121 130
                     output.writeEndElement();
122 131
                 }
123 132
                 output.writeStartElement("tr");
124 133
                 output.writeStartElement("th");
125
-                output.writeAttribute("colspan", "5");
134
+                output.writeAttribute("colspan", "8");
126 135
                 output.writeCharacters("Decaffeinated Coffees");
127 136
                 output.writeEndElement();
128 137
                 output.writeEndElement();
129
-				query.prepare("SELECT DISTINCT origin, (avg(rate)/:conversion)::numeric(10,2) AS rate, (SELECT avg(cost)*:conversion2 FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost, (SELECT avg(cost)*:conversion3 FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin) AND time = (SELECT max(time) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))), (SELECT max(time)::date FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin)) FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY " + orderClause);
138
+				query.prepare("SELECT DISTINCT origin, (avg(rate)/:conversion)::numeric(10,2) AS rate, (SELECT avg(cost)*:conversion2 FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS cost, (SELECT avg(cost)*:conversion3 FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin) AND time = (SELECT max(time) FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))), (SELECT max(time)::date FROM purchase WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin)), (SELECT min(conversion)/:conversion4 FROM lb_bag_conversion WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS minbag, (SELECT max(conversion)/:conversion5 FROM lb_bag_conversion WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS maxbag, (SELECT avg(conversion)/:conversion6 FROM lb_bag_conversion WHERE item IN (SELECT id FROM decaf_coffees WHERE origin = coffee_history.origin))::numeric(10,2) AS meanbag FROM coffee_history WHERE id IN (SELECT id FROM decaf_coffees) GROUP BY origin ORDER BY " + orderClause);
130 139
 				query.bind(":conversion", conversion);
131 140
 				query.bind(":conversion2", conversion);
132 141
 				query.bind(":conversion3", conversion);
142
+				query.bind(":conversion4", conversion);
143
+				query.bind(":conversion5", conversion);
144
+				query.bind(":conversion6", conversion);
133 145
 				query.exec();
134 146
                 while(query.next())
135 147
                 {
@@ -139,6 +151,9 @@
139 151
                     output.writeTextElement("td", query.value(2));
140 152
 					output.writeTextElement("td", query.value(3));
141 153
 					output.writeTextElement("td", query.value(4));
154
+					output.writeTextElement("td", query.value(5));
155
+					output.writeTextElement("td", query.value(6));
156
+					output.writeTextElement("td", query.value(7));
142 157
                     output.writeEndElement();
143 158
                 }
144 159
 				query = query.invalidate();

+ 12
- 17
config/Reports/chart.xml View File

@@ -2,10 +2,7 @@
2 2
 	<reporttitle>Production:->Previous Year Production Comparison</reporttitle>
3 3
     <layout type="vertical">
4 4
         <layout type="horizontal">
5
-            <label>Start Date:</label>
6
-            <calendar id="startdate" />
7
-            <label>End Date:</label>
8
-            <calendar id="enddate" />
5
+			<daterange id="dates" initial="19" /><!-- Current Year to Date -->
9 6
             <label>Days to Average</label>
10 7
             <line validator="integer" id="days">7</line>
11 8
 			<label>Weight Unit:</label>
@@ -20,9 +17,8 @@
20 17
     <program>
21 18
         <![CDATA[
22 19
             this.windowTitle = "Typica - Previous Year Production Comparison";
23
-            var startDateField = findChildObject(this, 'startdate');
24
-            startDateField.setDate(startDateField.year(), 1, 1);
25
-            var endDateField = findChildObject(this, 'enddate');
20
+			var dateSelect = findChildObject(this, 'dates');
21
+			dateSelect.removeIndex(23); // Remove Lifetime range
26 22
             var view = findChildObject(this, 'report');
27 23
             var printMenu = findChildObject(this, 'print');
28 24
             printMenu.triggered.connect(function() {
@@ -79,10 +75,12 @@
79 75
                 output.writeStartElement("tbody");
80 76
                 var query = new QSqlQuery();
81 77
                 query.exec("START TRANSACTION");
82
-                var curStartDate = "'"+startDateField.year()+"-"+startDateField.month()+"-"+startDateField.day()+"'";
83
-                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'");
84
-                query.next();
85
-                var curEndDate = "'"+query.value(2)+"'";
78
+				var dateRange = dateSelect.currentRange();
79
+				var curStartDate = "'"+dateRange[0]+"'";
80
+				var curEndDate = "'"+dateRange[dateRange.length - 1]+"'";
81
+                query.exec("SELECT "+curStartDate+"::date - interval '1 year', "+curEndDate+"::date - interval '1 year' + interval '1 day', "+curEndDate+"::date + interval '1 day'");
82
+				query.next();
83
+                curEndDate = "'"+query.value(2)+"'";
86 84
                 var prevStartDate = "'"+query.value(0)+"'";
87 85
                 var prevEndDate = "'"+query.value(1)+"'";
88 86
                 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";
@@ -501,12 +499,9 @@
501 499
                 buffer.close();
502 500
             }
503 501
             refresh();
504
-            startDateField.dateChanged.connect(function() {
505
-                refresh();
506
-            });
507
-            endDateField.dateChanged.connect(function() {
508
-                refresh();
509
-            });
502
+			dateSelect.rangeUpdated.connect(function() {
503
+				refresh();
504
+			});
510 505
 			avgField.editingFinished.connect(function() {
511 506
 				refresh();
512 507
 			});

+ 13
- 16
config/Reports/fypurchase.xml View File

@@ -2,10 +2,7 @@
2 2
 	<reporttitle>Purchase:->Coffee Purchase Previous Years Comparison</reporttitle>
3 3
 	<layout type="vertical">
4 4
 		<layout type="horizontal">
5
-			<label>Start Date:</label>
6
-			<calendar id="startdate" />
7
-			<label>End Date:</label>
8
-			<calendar id="enddate" />
5
+			<daterange id = "dates" initial="23" /><!--Lifetime-->
9 6
 			<label>Weight Unit:</label>
10 7
 			<sqldrop id="unit" />
11 8
 			<stretch />
@@ -18,16 +15,16 @@
18 15
 	<program>
19 16
 		<![CDATA[
20 17
 			this.windowTitle = "Typica - Coffee Purchase Previous Years Comparison";
21
-			/* Set starting year to the first year on record. */
22
-			var startDateField = findChildObject(this, 'startdate');
18
+			/* Set Lifetime range. */
19
+			var dateSelect = findChildObject(this, 'dates');
23 20
 			var query = new QSqlQuery();
24
-			query.exec("SELECT EXTRACT(YEAR FROM time) FROM purchase WHERE time = (SELECT min(time) FROM purchase)");
21
+			query.exec("SELECT concat(EXTRACT(YEAR FROM time::date), '-01-01') FROM purchase WHERE time = (SELECT min(time) FROM purchase) UNION SELECT concat(EXTRACT(YEAR FROM 'now'::date), '-12-31')");
25 22
 			query.next();
26
-			startDateField.setDate(query.value(0), 1, 1);
23
+			var lifetimeStartDate = query.value(0);
24
+			query.next();
25
+			var lifetimeEndDate = query.value(0);
26
+			dateSelect.setLifetimeRange(lifetimeStartDate, lifetimeEndDate);
27 27
 			query = query.invalidate();
28
-			/* Set ending year to the current year. */
29
-			var endDateField = findChildObject(this, 'enddate');
30
-			endDateField.setDate(endDateField.year(), 12, 31);
31 28
 			/* Enable printing */
32 29
 			var view = findChildObject(this, 'report');
33 30
 			var printMenu = findChildObject(this, 'print');
@@ -81,7 +78,10 @@
81 78
 				var unittotal = 0;
82 79
 				var costtotal = 0;
83 80
 				var query = new QSqlQuery();
84
-				for(var i = startDateField.year(); i <= endDateField.year(); i++)
81
+				var dateRange = dateSelect.currentRange();
82
+				var startYear = Number(dateRange[0].substr(0, 4));
83
+				var endYear = Number(dateRange[dateRange.length - 1].substr(0, 4));
84
+				for(var i = startYear; i <= endYear; i++)
85 85
 				{
86 86
 					output.writeStartElement("tr");
87 87
 					output.writeAttribute("id", "y"+i);
@@ -121,10 +121,7 @@
121 121
 			}
122 122
 			refresh();
123 123
 			/* Update report as needed. */
124
-			startDateField.dateChanged.connect(function() {
125
-				refresh();
126
-			});
127
-			endDateField.dateChanged.connect(function() {
124
+			dateSelect.rangeUpdated.connect(function() {
128 125
 				refresh();
129 126
 			});
130 127
 			/* Expand year data */

+ 43
- 20
config/Reports/invchange.xml View File

@@ -2,10 +2,7 @@
2 2
 	<reporttitle>Inventory:->Inventory Change Summary</reporttitle>
3 3
 	<layout type="vertical">
4 4
 		<layout type="horizontal">
5
-			<label>Start Date:</label>
6
-			<calendar id="startdate" />
7
-			<label>End Date:</label>
8
-			<calendar id="enddate" />
5
+			<daterange id="dates" initial="19" /><!-- Current Year to Date-->
9 6
 			<label>Weight Unit:</label>
10 7
 			<sqldrop id="unit" />
11 8
 			<stretch />
@@ -18,9 +15,19 @@
18 15
 	<program>
19 16
 		<![CDATA[
20 17
 			this.windowTitle = "Typica - Inventory Change Summary";
21
-			var startDateField = findChildObject(this, 'startdate');
22
-			startDateField.setDate(startDateField.year(), 1, 1);
23
-			var endDateField = findChildObject(this, 'enddate');
18
+			var dateSelect = findChildObject(this, 'dates');
19
+			var dateQuery = new QSqlQuery();
20
+			dateQuery.exec("SELECT time::date FROM transactions WHERE time = (SELECT min(time) FROM transactions) OR time = (SELECT max(time) FROM transactions) ORDER BY time ASC");
21
+			dateQuery.next();
22
+			var lifetimeStartDate = dateQuery.value(0);
23
+			var lifetimeEndDate;
24
+			if(dateQuery.next()) {
25
+				lifetimeEndDate = dateQuery.value(0);
26
+			} else {
27
+				lifetimeEndDate = lifetimeStartDate;
28
+			}
29
+			dateSelect.setLifetimeRange(lifetimeStartDate, lifetimeEndDate);
30
+			dateQuery = dateQuery.invalidate();
24 31
 			var unitBox = findChildObject(this, 'unit');
25 32
 			unitBox.addItem("Kg");
26 33
 			unitBox.addItem("Lb");
@@ -46,8 +53,9 @@
46 53
 				output.writeTextElement("title", "Inventory Change Summary");
47 54
 				output.writeEndElement();
48 55
 				output.writeStartElement("body");
49
-				var startDate = "" + startDateField.year() + "-" + startDateField.month() + "-" + startDateField.day();
50
-				var endDate = "" + endDateField.year() + "-" + endDateField.month() + "-" + endDateField.day();
56
+				var dateRange = dateSelect.currentRange();
57
+				var startDate = dateRange[0];
58
+				var endDate = dateRange[dateRange.length - 1];
51 59
 				output.writeTextElement("h1", "Inventory Change Summary: " + startDate + " – " + endDate);
52 60
 				var conversion = 1;
53 61
 				if(unitBox.currentIndex == 0) {
@@ -58,7 +66,7 @@
58 66
 					unitText = "Kg";
59 67
 				}
60 68
 				var query = new QSqlQuery();
61
-					var q = "WITH q AS (SELECT id, name, reference, COALESCE((SELECT balance FROM item_history(id) WHERE time = (SELECT max(time) FROM item_history(id) WHERE time < :sd1)), 0)/:c1 AS starting_balance, COALESCE((SELECT sum(quantity) FROM purchase WHERE item = id AND time >= :sd2 AND time < :ed1 ::date + interval '1 day'), 0)/:c2 AS purchase, COALESCE((SELECT sum(quantity) FROM use WHERE item = id AND time >= :sd3 AND time < :ed2 ::date + interval '1 day'), 0)/:c3 AS use, COALESCE((SELECT sum(quantity) FROM sale WHERE item = id AND time >= :sd4 AND time < :ed3 ::date + interval '1 day'), 0)/:c4 AS sale, (SElECT balance FROM item_history(id) WHERE time = (SELECT max(time) FROM item_history(id) WHERE time < :ed4 ::date + interval '1 day'))/:c5 AS quantity, (SELECT sum(cost * quantity) / sum(quantity) FROM purchase WHERE item = id)*:c6 AS unit_cost FROM coffees WHERE id IN (SELECT item FROM purchase WHERE time >= :sd6 AND time < :ed5 ::date + interval '1 day') OR id IN (SELECT id FROM items WHERE (SELECT balance FROM item_history(id) WHERE time = (SELECT max(time) FROM item_history(id) WHERE time < :ed6 ::date + interval '1 day')) > 0) OR id IN (SELECT DISTINCT item FROM all_transactions WHERE time > :sd7 AND time < :ed7 ::date + interval '1 day')) SELECT *, (starting_balance + purchase - use - sale - quantity)/:c7 AS adjustment, starting_balance * unit_cost * :c8 AS starting_cost, purchase * unit_cost * :c9 AS purchase_cost, use * unit_cost * :c10 AS use_cost, sale * unit_cost * :c11 AS sale_cost, quantity * unit_cost * :c12 AS quantity_cost, (starting_balance + purchase - use - sale - quantity) * unit_cost * :c13 AS adjustment_cost FROM q ORDER BY name";
69
+					var q = "WITH q AS (SELECT id, name, reference, COALESCE((SELECT balance FROM item_history(id) WHERE time = (SELECT max(time) FROM item_history(id) WHERE time < :sd1)), 0)/:c1 AS starting_balance, COALESCE((SELECT sum(quantity) FROM purchase WHERE item = id AND time >= :sd2 AND time < :ed1 ::date + interval '1 day'), 0)/:c2 AS purchase, COALESCE((SELECT sum(quantity) FROM use WHERE item = id AND time >= :sd3 AND time < :ed2 ::date + interval '1 day'), 0)/:c3 AS use, COALESCE((SELECT sum(quantity) FROM sale WHERE item = id AND time >= :sd4 AND time < :ed3 ::date + interval '1 day'), 0)/:c4 AS sale, (SElECT balance FROM item_history(id) WHERE time = (SELECT max(time) FROM item_history(id) WHERE time < :ed4 ::date + interval '1 day'))/:c5 AS quantity, (SELECT sum(cost * quantity) / sum(quantity) FROM purchase WHERE item = id) AS unit_cost FROM coffees WHERE id IN (SELECT item FROM purchase WHERE time >= :sd6 AND time < :ed5 ::date + interval '1 day') OR id IN (SELECT id FROM items WHERE (SELECT balance FROM item_history(id) WHERE time = (SELECT max(time) FROM item_history(id) WHERE time < :ed6 ::date + interval '1 day')) > 0) OR id IN (SELECT DISTINCT item FROM all_transactions WHERE time > :sd7 AND time < :ed7 ::date + interval '1 day')) SELECT *, (starting_balance + purchase - use - sale - quantity)/:c7 AS adjustment, starting_balance * unit_cost * :c8 AS starting_cost, purchase * unit_cost * :c9 AS purchase_cost, use * unit_cost * :c10 AS use_cost, sale * unit_cost * :c11 AS sale_cost, quantity * unit_cost * :c12 AS quantity_cost, (starting_balance + purchase - use - sale - quantity) * unit_cost * :c13 AS adjustment_cost, (SELECT sum(quantity)/:c6 FROM purchase WHERE item = id) AS total_purchase FROM q ORDER BY name";
62 70
 				query.prepare(q);
63 71
 				query.bind(":sd1", startDate);
64 72
 				query.bind(":sd2", startDate);
@@ -133,17 +141,35 @@
133 141
 					output.writeEndElement();
134 142
 					output.writeTextElement("td", query.value(1)); //Coffee
135 143
 					output.writeTextElement("td", query.value(2)); //Reference
136
-					output.writeTextElement("td", parseFloat(query.value(3)).toFixed(2)); //Starting Wt
144
+					output.writeStartElement("td"); //Starting Wt
145
+					output.writeAttribute("title", (parseFloat(query.value(3))/parseFloat(query.value(16)) * 100).toFixed(0) + "%");
146
+					output.writeCDATA(parseFloat(query.value(3)).toFixed(2));
147
+					output.writeEndElement(); //End of Starting Wt.
137 148
 					output.writeTextElement("td", parseFloat(query.value(10)).toFixed(2)); //Starting Cost
138
-					output.writeTextElement("td", parseFloat(query.value(4)).toFixed(2)); //Purchase Wt
149
+					output.writeStartElement("td"); //Purchase Wt
150
+					output.writeAttribute("title", (parseFloat(query.value(4))/parseFloat(query.value(16)) * 100).toFixed(0) + "%");
151
+					output.writeCDATA(parseFloat(query.value(4)).toFixed(2));
152
+					output.writeEndElement(); //End of Purchase Wt
139 153
 					output.writeTextElement("td", parseFloat(query.value(11)).toFixed(2)); //Purchase Cost
140
-					output.writeTextElement("td", parseFloat(query.value(5)).toFixed(2)); //Use Wt
154
+					output.writeStartElement("td"); //Use Wt
155
+					output.writeAttribute("title", (parseFloat(query.value(5))/parseFloat(query.value(16)) * 100).toFixed(0) + "%");
156
+					output.writeCDATA(parseFloat(query.value(5)).toFixed(2));
157
+					output.writeEndElement(); //End of Use Wt
141 158
 					output.writeTextElement("td", parseFloat(query.value(12)).toFixed(2)); //Use Cost
142
-					output.writeTextElement("td", parseFloat(query.value(6)).toFixed(2)); //Sale Wt
159
+					output.writeStartElement("td"); //Sale Wt
160
+					output.writeAttribute("title", (parseFloat(query.value(6))/parseFloat(query.value(16)) * 100).toFixed(0) + "%");
161
+					output.writeCDATA(parseFloat(query.value(6)).toFixed(2));
162
+					output.writeEndElement(); //End of Sale Wt
143 163
 					output.writeTextElement("td", parseFloat(query.value(13)).toFixed(2)); //Sale Cost
144
-					output.writeTextElement("td", parseFloat(query.value(9)).toFixed(2)); //Adjustment Wt
164
+					output.writeStartElement("td"); //Adjustment Wt
165
+					output.writeAttribute("title", (parseFloat(query.value(9))/parseFloat(query.value(16)) * 100).toFixed(0) + "%");
166
+					output.writeCDATA(parseFloat(query.value(9)).toFixed(2));
167
+					output.writeEndElement(); //Adjustment Wt
145 168
 					output.writeTextElement("td", parseFloat(query.value(15)).toFixed(2)); //Adjustment Cost
146
-					output.writeTextElement("td", parseFloat(query.value(7)).toFixed(2)); //Ending Wt
169
+					output.writeStartElement("td"); //Ending Wt
170
+					output.writeAttribute("title", (parseFloat(query.value(7))/parseFloat(query.value(16)) * 100).toFixed(0) + "%");
171
+					output.writeCDATA(parseFloat(query.value(7)).toFixed(2));
172
+					output.writeEndElement(); //End of Ending Wt
147 173
 					output.writeTextElement("td", parseFloat(query.value(14)).toFixed(2)); //Ending Cost
148 174
 					output.writeEndElement();
149 175
 					sum3 += parseFloat(query.value(3));
@@ -188,10 +214,7 @@
188 214
 				query = query.invalidate();
189 215
 			}
190 216
 			refresh();
191
-			startDateField.dateChanged.connect(function() {
192
-				refresh();
193
-			});
194
-			endDateField.dateChanged.connect(function() {
217
+			dateSelect.rangeUpdated.connect(function() {
195 218
 				refresh();
196 219
 			});
197 220
 			view.scriptLinkClicked.connect(function(url) {

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

@@ -27,6 +27,10 @@
27 27
 			unitBox.addItem("Kg");
28 28
 			unitBox.addItem("oz");
29 29
 			unitBox.addItem("lb");
30
+			unitBox.currentIndex = (QSettings.value("script/greensales_unit", unitBox.findText("lb")));
31
+			unitBox['currentIndexChanged(int)'].connect(function() {
32
+				QSettings.setValue("script/greensales_unit", unitBox.currentIndex);
33
+			});
30 34
 			var convertToPounds = function(w, u) {
31 35
 				switch(u)
32 36
 				{

+ 4
- 2
src/Typica.pro View File

@@ -23,7 +23,8 @@ HEADERS += moc_typica.cpp \
23 23
     webview.h \
24 24
     webelement.h \
25 25
     scale.h \
26
-    draglabel.h
26
+    draglabel.h \
27
+    daterangeselector.h
27 28
 SOURCES += typica.cpp \
28 29
     helpmenu.cpp \
29 30
     abouttypica.cpp \
@@ -31,7 +32,8 @@ SOURCES += typica.cpp \
31 32
     webview.cpp \
32 33
     webelement.cpp \
33 34
     scale.cpp \
34
-    draglabel.cpp
35
+    draglabel.cpp \
36
+    daterangeselector.cpp
35 37
 
36 38
 RESOURCES += \
37 39
     resources.qrc

+ 1
- 1
src/abouttypica.cpp View File

@@ -17,7 +17,7 @@ aboutFile.close();
17 17
 setCentralWidget(banner);
18 18
 }
19 19
 
20
-#line 5640 "./typica.w"
20
+#line 5641 "./typica.w"
21 21
 
22 22
 /*:223*/
23 23
 #line 36 "./abouttypica.w"

+ 43
- 0
src/clock.cpp View File

@@ -0,0 +1,43 @@
1
+/*244:*/
2
+#line 52 "./clock.w"
3
+
4
+#include "clock.h"
5
+
6
+/*245:*/
7
+#line 61 "./clock.w"
8
+
9
+Clock::Clock():QObject(NULL)
10
+{
11
+reference.start();
12
+}
13
+
14
+Clock::~Clock()
15
+{
16
+
17
+}
18
+
19
+/*:245*//*246:*/
20
+#line 79 "./clock.w"
21
+
22
+qint64 Clock::timestamp()
23
+{
24
+guard.lock();
25
+qint64 retval= reference.elapsed();
26
+guard.unlock();
27
+emit newTime(retval);
28
+return retval;
29
+}
30
+
31
+void Clock::setEpoch()
32
+{
33
+guard.lock();
34
+reference.restart();
35
+guard.unlock();
36
+emit newTime(0);
37
+}
38
+
39
+/*:246*/
40
+#line 55 "./clock.w"
41
+
42
+
43
+/*:244*/

+ 29
- 0
src/clock.h View File

@@ -0,0 +1,29 @@
1
+/*243:*/
2
+#line 24 "./clock.w"
3
+
4
+#include <QElapsedTimer> 
5
+#include <QMutex> 
6
+#include <QObject> 
7
+
8
+#ifndef ClockHeader
9
+#define ClockHeader
10
+
11
+class Clock:public QObject
12
+{
13
+Q_OBJECT
14
+public:
15
+Clock();
16
+~Clock();
17
+qint64 timestamp();
18
+public slots:
19
+void setEpoch();
20
+signals:
21
+void newTime(qint64 time);
22
+private:
23
+QElapsedTimer reference;
24
+QMutex guard;
25
+};
26
+
27
+#endif
28
+
29
+/*:243*/

+ 3
- 3
src/dataqsdk.w View File

@@ -496,7 +496,7 @@ DataqSdkDevice::DataqSdkDevice(QString device) : imp(new DataqSdkDeviceImplement
496 496
 	int rstart = finalizedPort.indexOf("COM");
497 497
 	finalizedPort.remove(0, rstart + 3);
498 498
 	bool chopFinished = false;
499
-	int finalizedPortNumber;
499
+	int finalizedPortNumber = 0;
500 500
 	while(finalizedPort.size() > 0 && !chopFinished)
501 501
 	{
502 502
 		finalizedPortNumber = finalizedPort.toInt(&chopFinished);
@@ -1098,7 +1098,7 @@ in.
1098 1098
 @<DATAQ SDK device settings@>=
1099 1099
 bool autoSelect;
1100 1100
 QString deviceID;
1101
-int channelOfInterest;
1101
+unsigned int channelOfInterest;
1102 1102
 
1103 1103
 @ This information is accessed through the reference element associated with
1104 1104
 the parent node of the current configuration and from the row number of the
@@ -1141,7 +1141,7 @@ void DataqSdkChannelConfWidget::startCalibration()
1141 1141
 	resetButton->setEnabled(true);
1142 1142
 	calibrationDevice = new DataqSdkDevice(deviceID);
1143 1143
 	Channel *channel;
1144
-	for(int i = 0; i <= channelOfInterest; i++)
1144
+	for(unsigned int i = 0; i <= channelOfInterest; i++)
1145 1145
 	{
1146 1146
 		channel = calibrationDevice->newChannel(Units::Unitless);
1147 1147
 	}

+ 346
- 0
src/daterangeselector.cpp View File

@@ -0,0 +1,346 @@
1
+/*603:*/
2
+#line 66 "./daterangeselector.w"
3
+
4
+#include <QCalendarWidget> 
5
+#include <QPushButton> 
6
+#include <QBoxLayout> 
7
+#include <QLabel> 
8
+#include <QToolButton> 
9
+#include <QApplication> 
10
+#include <QDesktopWidget> 
11
+
12
+#include "daterangeselector.h"
13
+
14
+/*604:*/
15
+#line 86 "./daterangeselector.w"
16
+
17
+class CustomDateRangePopup:public QWidget
18
+{
19
+Q_OBJECT
20
+public:
21
+CustomDateRangePopup(QWidget*parent= NULL);
22
+public slots:
23
+void applyRange();
24
+signals:
25
+void hidingPopup();
26
+protected:
27
+virtual void hideEvent(QHideEvent*event);
28
+private slots:
29
+void validateRange();
30
+private:
31
+QCalendarWidget*startDateSelector;
32
+QCalendarWidget*endDateSelector;
33
+QPushButton*applyButton;
34
+};
35
+
36
+/*:604*/
37
+#line 77 "./daterangeselector.w"
38
+
39
+/*605:*/
40
+#line 110 "./daterangeselector.w"
41
+
42
+CustomDateRangePopup::CustomDateRangePopup(QWidget*parent):
43
+QWidget(parent,Qt::Popup),startDateSelector(new QCalendarWidget),
44
+endDateSelector(new QCalendarWidget),applyButton(new QPushButton(tr("Apply")))
45
+{
46
+setAttribute(Qt::WA_WindowPropagation);
47
+
48
+QVBoxLayout*outerLayout= new QVBoxLayout;
49
+QHBoxLayout*calendarsLayout= new QHBoxLayout;
50
+QVBoxLayout*startDateLayout= new QVBoxLayout;
51
+QVBoxLayout*endDateLayout= new QVBoxLayout;
52
+QHBoxLayout*buttonLayout= new QHBoxLayout;
53
+QLabel*startDateLabel= new QLabel(tr("From"));
54
+QLabel*endDateLabel= new QLabel(tr("To"));
55
+startDateSelector->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
56
+endDateSelector->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
57
+DateRangeSelector*selector= qobject_cast<DateRangeSelector*> (parent);
58
+if(parent){
59
+QStringList range= selector->currentRange().toStringList();
60
+startDateSelector->setSelectedDate(QDate::fromString(range.first(),Qt::ISODate));
61
+endDateSelector->setSelectedDate(QDate::fromString(range.last(),Qt::ISODate));
62
+}
63
+connect(startDateSelector,SIGNAL(selectionChanged()),this,SLOT(validateRange()));
64
+connect(endDateSelector,SIGNAL(selectionChanged()),this,SLOT(validateRange()));
65
+
66
+startDateLayout->addWidget(startDateLabel);
67
+startDateLayout->addWidget(startDateSelector);
68
+endDateLayout->addWidget(endDateLabel);
69
+endDateLayout->addWidget(endDateSelector);
70
+
71
+connect(applyButton,SIGNAL(clicked()),this,SLOT(applyRange()));
72
+
73
+buttonLayout->addStretch();
74
+buttonLayout->addWidget(applyButton);
75
+
76
+calendarsLayout->addLayout(startDateLayout);
77
+calendarsLayout->addLayout(endDateLayout);
78
+outerLayout->addLayout(calendarsLayout);
79
+outerLayout->addLayout(buttonLayout);
80
+setLayout(outerLayout);
81
+}
82
+
83
+/*:605*//*606:*/
84
+#line 158 "./daterangeselector.w"
85
+
86
+void CustomDateRangePopup::hideEvent(QHideEvent*)
87
+{
88
+emit hidingPopup();
89
+}
90
+
91
+/*:606*//*607:*/
92
+#line 167 "./daterangeselector.w"
93
+
94
+void CustomDateRangePopup::applyRange()
95
+{
96
+DateRangeSelector*selector= qobject_cast<DateRangeSelector*> (parentWidget());
97
+if(selector)
98
+{
99
+selector->setCustomRange(QVariant(QStringList()<<
100
+startDateSelector->selectedDate().toString(Qt::ISODate)<<
101
+endDateSelector->selectedDate().toString(Qt::ISODate)));
102
+}
103
+hide();
104
+}
105
+
106
+/*:607*//*608:*/
107
+#line 184 "./daterangeselector.w"
108
+
109
+void CustomDateRangePopup::validateRange()
110
+{
111
+if(startDateSelector->selectedDate()> endDateSelector->selectedDate())
112
+{
113
+applyButton->setEnabled(false);
114
+}
115
+else
116
+{
117
+applyButton->setEnabled(true);
118
+}
119
+}
120
+
121
+/*:608*/
122
+#line 78 "./daterangeselector.w"
123
+
124
+/*609:*/
125
+#line 202 "./daterangeselector.w"
126
+
127
+DateRangeSelector::DateRangeSelector(QWidget*parent):
128
+QWidget(parent),quickSelector(new QComboBox(this)),
129
+customRangeSelector(NULL),lastIndex(0)
130
+{
131
+connect(quickSelector,SIGNAL(currentIndexChanged(int)),this,SLOT(updateRange(int)));
132
+
133
+QDate currentDate= QDate::currentDate();
134
+
135
+QHBoxLayout*layout= new QHBoxLayout;
136
+/*610:*/
137
+#line 231 "./daterangeselector.w"
138
+
139
+quickSelector->addItem("Yesterday",QVariant(QStringList()<<
140
+currentDate.addDays(-1).toString(Qt::ISODate)));
141
+quickSelector->addItem("Today",QVariant(QStringList()<<
142
+currentDate.toString(Qt::ISODate)));
143
+quickSelector->insertSeparator(quickSelector->count());
144
+quickSelector->addItem("This Week",QVariant(QStringList()<<
145
+(currentDate.dayOfWeek()%7?
146
+currentDate.addDays(-currentDate.dayOfWeek()).toString(Qt::ISODate):
147
+currentDate.toString(Qt::ISODate))<<
148
+currentDate.addDays(6-(currentDate.dayOfWeek()%7)).toString(Qt::ISODate)));
149
+quickSelector->addItem("This Week to Date",currentDate.dayOfWeek()%7?
150
+QVariant(QStringList()<<
151
+currentDate.addDays(-currentDate.dayOfWeek()).toString(Qt::ISODate)<<
152
+currentDate.toString(Qt::ISODate)):
153
+QVariant(QStringList()<<currentDate.toString(Qt::ISODate)));
154
+quickSelector->addItem("Last Week",QVariant(QStringList()<<
155
+currentDate.addDays(-(currentDate.dayOfWeek()%7)-7).toString(Qt::ISODate)<<
156
+currentDate.addDays(-(currentDate.dayOfWeek()%7)-1).toString(Qt::ISODate)));
157
+quickSelector->addItem("Last 7 Days",QVariant(QStringList()<<
158
+currentDate.addDays(-6).toString(Qt::ISODate)<<
159
+currentDate.toString(Qt::ISODate)));
160
+quickSelector->insertSeparator(quickSelector->count());
161
+quickSelector->addItem("This Month",QVariant(QStringList()<<
162
+QDate(currentDate.year(),currentDate.month(),1).toString(Qt::ISODate)<<
163
+QDate(currentDate.year(),currentDate.month(),
164
+currentDate.daysInMonth()).toString(Qt::ISODate)));
165
+quickSelector->addItem("This Month to Date",(currentDate.day()==1?
166
+(QVariant(QStringList()<<currentDate.toString(Qt::ISODate))):
167
+(QVariant(QStringList()<<
168
+QDate(currentDate.year(),currentDate.month(),1).toString(Qt::ISODate)<<
169
+currentDate.toString(Qt::ISODate)))));
170
+quickSelector->addItem("Last Four Weeks",QVariant(QStringList()<<
171
+currentDate.addDays(-27).toString(Qt::ISODate)<<
172
+currentDate.toString(Qt::ISODate)));
173
+quickSelector->addItem("Last 30 Days",QVariant(QStringList()<<
174
+currentDate.addDays(-29).toString(Qt::ISODate)<<
175
+currentDate.toString(Qt::ISODate)));
176
+quickSelector->insertSeparator(quickSelector->count());
177
+quickSelector->addItem("This Quarter",QVariant(QStringList()<<
178
+QDate(currentDate.year(),currentDate.month()-((currentDate.month()-1)%3),1).toString(Qt::ISODate)<<
179
+(currentDate.month()> 9?
180
+QDate(currentDate.year(),12,31).toString(Qt::ISODate):
181
+QDate(currentDate.year(),currentDate.month()-((currentDate.month()-1)%3)+3,1).addDays(-1).toString(Qt::ISODate))));
182
+quickSelector->addItem("This Quarter to Date",
183
+(currentDate.day()==1&&(currentDate.month()-1)%3==0)?
184
+QVariant(QStringList()<<currentDate.toString(Qt::ISODate)):
185
+QVariant(QStringList()<<
186
+QDate(currentDate.year(),currentDate.month()-((currentDate.month()-1)%3),1).toString(Qt::ISODate)<<
187
+currentDate.toString(Qt::ISODate)));
188
+quickSelector->addItem("Last Quarter",currentDate.month()<4?
189
+QVariant(QStringList()<<
190
+QDate(currentDate.year()-1,10,1).toString(Qt::ISODate)<<
191
+QDate(currentDate.year()-1,12,31).toString(Qt::ISODate)):
192
+QVariant(QStringList()<<
193
+QDate(currentDate.year(),currentDate.month()-((currentDate.month()-1)%3)-3,1).toString(Qt::ISODate)<<
194
+QDate(currentDate.year(),currentDate.month()-((currentDate.month()-1)%3),1).addDays(-1).toString(Qt::ISODate)));
195
+quickSelector->addItem("Last 90 Days",QVariant(QStringList()<<
196
+currentDate.addDays(-89).toString(Qt::ISODate)<<
197
+currentDate.toString(Qt::ISODate)));
198
+quickSelector->insertSeparator(quickSelector->count());
199
+quickSelector->addItem("This Year",QVariant(QStringList()<<
200
+QDate(currentDate.year(),1,1).toString(Qt::ISODate)<<
201
+QDate(currentDate.year(),12,31).toString(Qt::ISODate)));
202
+quickSelector->addItem("This Year to Date",(currentDate.dayOfYear()==1)?
203
+QVariant(QStringList()<<currentDate.toString(Qt::ISODate)):
204
+QVariant(QStringList()<<QDate(currentDate.year(),1,1).toString(Qt::ISODate)<<
205
+currentDate.toString(Qt::ISODate)));
206
+quickSelector->addItem("Last Year",QVariant(QStringList()<<
207
+QDate(currentDate.year()-1,1,1).toString(Qt::ISODate)<<
208
+QDate(currentDate.year()-1,12,31).toString(Qt::ISODate)));
209
+quickSelector->addItem("Last 365 Days",QVariant(QStringList()<<
210
+currentDate.addDays(-364).toString(Qt::ISODate)<<
211
+currentDate.toString(Qt::ISODate)));
212
+quickSelector->insertSeparator(quickSelector->count());
213
+quickSelector->addItem("Lifetime");
214
+quickSelector->addItem("Custom");
215
+
216
+/*:610*/
217
+#line 212 "./daterangeselector.w"
218
+
219
+QToolButton*customButton= new QToolButton;
220
+customButton->setIcon(QIcon::fromTheme("office-calendar",
221
+QIcon(":/resources/icons/tango/scalable/apps/office-calendar.svg")));
222
+layout->addWidget(quickSelector);
223
+layout->addWidget(customButton);
224
+setLayout(layout);
225
+
226
+connect(customButton,SIGNAL(clicked()),this,SLOT(toggleCustom()));
227
+}
228
+
229
+/*:609*//*611:*/
230
+#line 314 "./daterangeselector.w"
231
+
232
+void DateRangeSelector::updateRange(int index)
233
+{
234
+if(index!=lastIndex&&index==quickSelector->count()-1)
235
+{
236
+toggleCustom();
237
+}
238
+else
239
+{
240
+lastIndex= index;
241
+emit rangeUpdated(quickSelector->itemData(quickSelector->currentIndex()));
242
+}
243
+}
244
+
245
+/*:611*//*612:*/
246
+#line 331 "./daterangeselector.w"
247
+
248
+void DateRangeSelector::popupHidden()
249
+{
250
+customRangeSelector->deleteLater();
251
+customRangeSelector= NULL;
252
+quickSelector->setCurrentIndex(lastIndex);
253
+}
254
+
255
+/*:612*//*613:*/
256
+#line 342 "./daterangeselector.w"
257
+
258
+void DateRangeSelector::setCustomRange(QVariant range)
259
+{
260
+quickSelector->setItemData(quickSelector->count()-1,range);
261
+emit rangeUpdated(range);
262
+lastIndex= quickSelector->count()-1;
263
+quickSelector->setCurrentIndex(lastIndex);
264
+}
265
+
266
+/*:613*//*614:*/
267
+#line 357 "./daterangeselector.w"
268
+
269
+void DateRangeSelector::toggleCustom()
270
+{
271
+if(!customRangeSelector){
272
+customRangeSelector= new CustomDateRangePopup(this);
273
+QPoint pos= rect().bottomLeft();
274
+QPoint pos2= rect().topLeft();
275
+pos= mapToGlobal(pos);
276
+pos2= mapToGlobal(pos2);
277
+QSize size= customRangeSelector->sizeHint();
278
+QRect screen= QApplication::desktop()->availableGeometry(pos);
279
+if(pos.x()+size.width()> screen.right()){
280
+pos.setX(screen.right()-size.width());
281
+}
282
+pos.setX(qMax(pos.x(),screen.left()));
283
+if(pos.y()+size.height()> screen.bottom()){
284
+pos.setY(pos2.y()-size.height());
285
+}else if(pos.y()<screen.top()){
286
+pos.setY(screen.top());
287
+}
288
+if(pos.y()<screen.top()){
289
+pos.setY(screen.top());
290
+}
291
+if(pos.y()+size.height()> screen.bottom()){
292
+pos.setY(screen.bottom()-size.height());
293
+}
294
+customRangeSelector->move(pos);
295
+customRangeSelector->show();
296
+connect(customRangeSelector,SIGNAL(hidingPopup()),
297
+this,SLOT(popupHidden()));
298
+}
299
+else
300
+{
301
+customRangeSelector->close();
302
+customRangeSelector->deleteLater();
303
+customRangeSelector= NULL;
304
+}
305
+}
306
+
307
+/*:614*//*615:*/
308
+#line 399 "./daterangeselector.w"
309
+
310
+QVariant DateRangeSelector::currentRange()
311
+{
312
+return quickSelector->itemData(lastIndex);
313
+}
314
+
315
+/*:615*//*616:*/
316
+#line 407 "./daterangeselector.w"
317
+
318
+void DateRangeSelector::setCurrentIndex(int index)
319
+{
320
+quickSelector->setCurrentIndex(index);
321
+}
322
+
323
+/*:616*//*617:*/
324
+#line 422 "./daterangeselector.w"
325
+
326
+void DateRangeSelector::setLifetimeRange(QString startDate,QString endDate)
327
+{
328
+quickSelector->setItemData(quickSelector->count()-2,
329
+QVariant(QStringList()<<startDate<<endDate));
330
+}
331
+
332
+/*:617*//*618:*/
333
+#line 432 "./daterangeselector.w"
334
+
335
+void DateRangeSelector::removeIndex(int index)
336
+{
337
+quickSelector->removeItem(index);
338
+}
339
+
340
+/*:618*/
341
+#line 79 "./daterangeselector.w"
342
+
343
+
344
+#include "moc_daterangeselector.cpp"
345
+
346
+/*:603*/

+ 37
- 0
src/daterangeselector.h View File

@@ -0,0 +1,37 @@
1
+/*602:*/
2
+#line 30 "./daterangeselector.w"
3
+
4
+
5
+#include <QComboBox> 
6
+
7
+#ifndef TypicaDateRangeSelectorHeader
8
+#define TypicaDateRangeSelectorHeader
9
+
10
+class CustomDateRangePopup;
11
+
12
+class DateRangeSelector:public QWidget
13
+{
14
+Q_OBJECT
15
+public:
16
+DateRangeSelector(QWidget*parent= NULL);
17
+void setCustomRange(QVariant range);
18
+Q_INVOKABLE QVariant currentRange();
19
+public slots:
20
+void setCurrentIndex(int index);
21
+void setLifetimeRange(QString startDate,QString endDate);
22
+void removeIndex(int index);
23
+signals:
24
+void rangeUpdated(QVariant);
25
+private slots:
26
+void toggleCustom();
27
+void popupHidden();
28
+void updateRange(int index);
29
+private:
30
+QComboBox*quickSelector;
31
+CustomDateRangePopup*customRangeSelector;
32
+int lastIndex;
33
+};
34
+
35
+#endif
36
+
37
+/*:602*/

+ 478
- 0
src/daterangeselector.w View File

@@ -0,0 +1,478 @@
1
+@** A Widget for Selecting Date Ranges.
2
+
3
+\noindent Many of the reports in Typica operate over a range of dates. In these
4
+cases it should generally be possible to set that range to any arbitrary start
5
+or end, however there are some ranges that are commonly useful where it may be
6
+convenient to provide easy access to that range. While Qt provides a widget
7
+for selecting a single date, it does not provide a widget that allows two dates
8
+to be conveniently selected. One approach which Typica has previously taken is
9
+to simply use two |QDateEdit| widgets. This works, however validation that the
10
+range is valid must then be performed in every report that uses such an
11
+approach. Another down side to this is that changing either side of the date
12
+range is either going to result in a database query to obtain results in the
13
+new range or another button must be introduced to make setting a new range
14
+explicit. One typically wants to adjust both sides of the range at the same
15
+time and only have one trip to the database for the new data and increasing the
16
+number of controls required for each filter quickly creates a mess.
17
+
18
+The solution to this is the introduction of a new composite widget for
19
+selecting date ranges. The main widget consists of two parts. First there is a
20
+|QComboBox| which contains many common date ranges. A |QToolButton| is also
21
+provided for convenient one click access to the Custom range. Whether selected
22
+from the |QComboBox| or the |QToolButton|, selecting Custom creates a new pop
23
+up widget containing two |QCalendarWidget|s and a button to explicitly set the
24
+range. This button will not be available unless the selected ending date is not
25
+before the selected starting date.
26
+
27
+As the common use for the selected date is database operations, convenient
28
+access to the ISO 8601 string representation of these dates is provided.
29
+
30
+@(daterangeselector.h@>=
31
+
32
+#include <QComboBox>
33
+
34
+#ifndef TypicaDateRangeSelectorHeader
35
+#define TypicaDateRangeSelectorHeader
36
+
37
+class CustomDateRangePopup;
38
+
39
+class DateRangeSelector : public QWidget
40
+{
41
+	@[Q_OBJECT@]@;
42
+	public:@/
43
+		DateRangeSelector(QWidget *parent = NULL);
44
+		void setCustomRange(QVariant range);
45
+		Q_INVOKABLE QVariant currentRange();@/
46
+	@[public slots@]:@/
47
+		void setCurrentIndex(int index);
48
+		void setLifetimeRange(QString startDate, QString endDate);
49
+		void removeIndex(int index);@/
50
+	@[signals@]:@/
51
+		void rangeUpdated(QVariant);
52
+	@[private slots@]:@/
53
+		void toggleCustom();
54
+		void popupHidden();
55
+		void updateRange(int index);@/
56
+	private:@/
57
+		QComboBox *quickSelector;
58
+		CustomDateRangePopup *customRangeSelector;
59
+		int lastIndex;
60
+};
61
+
62
+#endif
63
+
64
+@ Implementation details are in a different file.
65
+
66
+@(daterangeselector.cpp@>=
67
+#include <QCalendarWidget>
68
+#include <QPushButton>
69
+#include <QBoxLayout>
70
+#include <QLabel>
71
+#include <QToolButton>
72
+#include <QApplication>
73
+#include <QDesktopWidget>
74
+
75
+#include "daterangeselector.h"
76
+
77
+@<CustomDateRangePopup declaration@>
78
+@<CustomDateRangePopup implementation@>
79
+@<DateRangeSelector implementation@>
80
+
81
+#include "moc_daterangeselector.cpp"
82
+
83
+@ The custom range pop up is represented as a separate class which is not to be
84
+instantiated except by |DateRangeSelector|.
85
+
86
+@<CustomDateRangePopup declaration@>=
87
+class CustomDateRangePopup : public QWidget
88
+{
89
+	@[Q_OBJECT@]@;
90
+	public:@/
91
+		CustomDateRangePopup(QWidget *parent = NULL);@/
92
+	@[public slots@]:@/
93
+		void applyRange();@/
94
+	@[signals@]:@/
95
+		void hidingPopup();@/
96
+	protected:@/
97
+		virtual void hideEvent(QHideEvent *event);@/
98
+	@[private slots@]:@/
99
+		void validateRange();@/
100
+	private:@/
101
+		QCalendarWidget *startDateSelector;
102
+		QCalendarWidget *endDateSelector;
103
+		QPushButton *applyButton;
104
+};
105
+
106
+@ The pop up constructor is responsible for laying out the component widgets,
107
+setting the dates selected in each calendar to match the currently selected
108
+range, and connecting the appropriate signal handlers.
109
+
110
+@<CustomDateRangePopup implementation@>=
111
+CustomDateRangePopup::CustomDateRangePopup(QWidget *parent) :
112
+	QWidget(parent, Qt::Popup), startDateSelector(new QCalendarWidget),
113
+	endDateSelector(new QCalendarWidget), applyButton(new QPushButton(tr("Apply")))
114
+{
115
+	setAttribute(Qt::WA_WindowPropagation);
116
+
117
+	QVBoxLayout *outerLayout = new QVBoxLayout;
118
+	QHBoxLayout *calendarsLayout = new QHBoxLayout;
119
+	QVBoxLayout *startDateLayout = new QVBoxLayout;
120
+	QVBoxLayout *endDateLayout = new QVBoxLayout;
121
+	QHBoxLayout *buttonLayout = new QHBoxLayout;
122
+	QLabel *startDateLabel = new QLabel(tr("From"));
123
+	QLabel *endDateLabel = new QLabel(tr("To"));
124
+	startDateSelector->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
125
+	endDateSelector->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
126
+	DateRangeSelector *selector = qobject_cast<DateRangeSelector *>(parent);
127
+	if(parent) {
128
+		QStringList range = selector->currentRange().toStringList();
129
+		startDateSelector->setSelectedDate(QDate::fromString(range.first(), Qt::ISODate));
130
+		endDateSelector->setSelectedDate(QDate::fromString(range.last(), Qt::ISODate));
131
+	}
132
+	connect(startDateSelector, SIGNAL(selectionChanged()), this, SLOT(validateRange()));
133
+	connect(endDateSelector, SIGNAL(selectionChanged()), this, SLOT(validateRange()));
134
+
135
+	startDateLayout->addWidget(startDateLabel);
136
+	startDateLayout->addWidget(startDateSelector);
137
+	endDateLayout->addWidget(endDateLabel);
138
+	endDateLayout->addWidget(endDateSelector);
139
+
140
+	connect(applyButton, SIGNAL(clicked()), this, SLOT(applyRange()));
141
+
142
+	buttonLayout->addStretch();
143
+	buttonLayout->addWidget(applyButton);
144
+
145
+	calendarsLayout->addLayout(startDateLayout);
146
+	calendarsLayout->addLayout(endDateLayout);
147
+	outerLayout->addLayout(calendarsLayout);
148
+	outerLayout->addLayout(buttonLayout);
149
+	setLayout(outerLayout);
150
+}
151
+
152
+@ The pop up can be hidden in two ways. Clicking anywhere outside of the widget
153
+will hide the pop up. Clicking the Apply button will also hide the pop up. In
154
+the former case, we must inform the parent widget that it is fine to destroy
155
+the pop up widget, which we do by emitting a signal. Note that clicking outside
156
+of the widget will cause the |QHideEvent| to be posted automatically.
157
+
158
+@<CustomDateRangePopup implementation@>=
159
+void CustomDateRangePopup::hideEvent(QHideEvent *)
160
+{
161
+	emit hidingPopup();
162
+}
163
+
164
+@ Clicking the Apply button requires setting the Custom date range to the
165
+currently selected range and then hiding the pop up manually.
166
+
167
+@<CustomDateRangePopup implementation@>=
168
+void CustomDateRangePopup::applyRange()
169
+{
170
+	DateRangeSelector *selector = qobject_cast<DateRangeSelector *>(parentWidget());
171
+	if(selector)
172
+	{
173
+		selector->setCustomRange(QVariant(QStringList() <<
174
+			startDateSelector->selectedDate().toString(Qt::ISODate) <<
175
+			endDateSelector->selectedDate().toString(Qt::ISODate)));
176
+	}
177
+	hide();
178
+}
179
+
180
+@ The Apply button is enabled or disabled depending on if the currently
181
+selected dates form a valid range in which the end date does not occur before
182
+the start date.
183
+
184
+@<CustomDateRangePopup implementation@>=
185
+void CustomDateRangePopup::validateRange()
186
+{
187
+	if(startDateSelector->selectedDate() > endDateSelector->selectedDate())
188
+	{
189
+		applyButton->setEnabled(false);
190
+	}
191
+	else
192
+	{
193
+		applyButton->setEnabled(true);
194
+	}
195
+}
196
+
197
+@ The |DateRangeSelector| constructor is responsible for setting up the layout
198
+of the |QComboBox| and the |QToolButton|, adding appropriate items to the
199
+|QComboBox|, and connecting the signals required to handle the pop up
200
+correctly.
201
+
202
+@<DateRangeSelector implementation@>=
203
+DateRangeSelector::DateRangeSelector(QWidget *parent) :
204
+	QWidget(parent), quickSelector(new QComboBox(this)),
205
+	customRangeSelector(NULL), lastIndex(0)
206
+{
207
+	connect(quickSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateRange(int)));
208
+
209
+	QDate currentDate = QDate::currentDate();
210
+
211
+	QHBoxLayout *layout = new QHBoxLayout;
212
+	@<Set common date ranges to quick selector@>@;
213
+	QToolButton *customButton = new QToolButton;
214
+	customButton->setIcon(QIcon::fromTheme("office-calendar",
215
+		QIcon(":/resources/icons/tango/scalable/apps/office-calendar.svg")));
216
+	layout->addWidget(quickSelector);
217
+	layout->addWidget(customButton);
218
+	setLayout(layout);
219
+
220
+	connect(customButton, SIGNAL(clicked()), this, SLOT(toggleCustom()));
221
+}
222
+
223
+@ The |QComboBox| provides a mechanism for associating additional data with an
224
+item. Several possible representations were considered, but what was ultimately
225
+selected was a |QVariant| containing a |QStringList| in which the first entry
226
+in the list is the starting date of the range and the last entry in the list is
227
+the ending date of the range. Note that the list may contain only one item in
228
+cases where the range only covers a single date, however one should not assume
229
+that a range covering a single date will only have a single list entry.
230
+
231
+@<Set common date ranges to quick selector@>=
232
+quickSelector->addItem("Yesterday", QVariant(QStringList() <<
233
+	currentDate.addDays(-1).toString(Qt::ISODate)));
234
+quickSelector->addItem("Today", QVariant(QStringList() <<
235
+	currentDate.toString(Qt::ISODate)));
236
+quickSelector->insertSeparator(quickSelector->count());
237
+quickSelector->addItem("This Week", QVariant(QStringList() <<
238
+	(currentDate.dayOfWeek() % 7 ?
239
+		currentDate.addDays(-currentDate.dayOfWeek()).toString(Qt::ISODate) :
240
+		currentDate.toString(Qt::ISODate)) <<
241
+			currentDate.addDays(6 - (currentDate.dayOfWeek() % 7)).toString(Qt::ISODate)));
242
+quickSelector->addItem("This Week to Date", currentDate.dayOfWeek() % 7 ?
243
+	QVariant(QStringList() <<
244
+	currentDate.addDays(-currentDate.dayOfWeek()).toString(Qt::ISODate) <<
245
+	currentDate.toString(Qt::ISODate)) :
246
+	QVariant(QStringList() << currentDate.toString(Qt::ISODate)));
247
+quickSelector->addItem("Last Week", QVariant(QStringList() <<
248
+	currentDate.addDays(-(currentDate.dayOfWeek() % 7) - 7).toString(Qt::ISODate) <<
249
+	currentDate.addDays(-(currentDate.dayOfWeek() % 7) - 1).toString(Qt::ISODate)));
250
+quickSelector->addItem("Last 7 Days", QVariant(QStringList() <<
251
+	currentDate.addDays(-6).toString(Qt::ISODate) <<
252
+	currentDate.toString(Qt::ISODate)));
253
+quickSelector->insertSeparator(quickSelector->count());
254
+quickSelector->addItem("This Month", QVariant(QStringList() <<
255
+	QDate(currentDate.year(), currentDate.month(), 1).toString(Qt::ISODate) <<
256
+	QDate(currentDate.year(), currentDate.month(),
257
+		currentDate.daysInMonth()).toString(Qt::ISODate)));
258
+quickSelector->addItem("This Month to Date", (currentDate.day() == 1 ?
259
+	(QVariant(QStringList() << currentDate.toString(Qt::ISODate))) :
260
+	(QVariant(QStringList() <<
261
+	QDate(currentDate.year(), currentDate.month(), 1).toString(Qt::ISODate) <<
262
+	currentDate.toString(Qt::ISODate)))));
263
+quickSelector->addItem("Last Four Weeks", QVariant(QStringList() <<
264
+	currentDate.addDays(-27).toString(Qt::ISODate) <<
265
+	currentDate.toString(Qt::ISODate)));
266
+quickSelector->addItem("Last 30 Days", QVariant(QStringList() <<
267
+	currentDate.addDays(-29).toString(Qt::ISODate) <<
268
+	currentDate.toString(Qt::ISODate)));
269
+quickSelector->insertSeparator(quickSelector->count());
270
+quickSelector->addItem("This Quarter", QVariant(QStringList() <<
271
+	QDate(currentDate.year(), currentDate.month() - ((currentDate.month() - 1) % 3), 1).toString(Qt::ISODate) <<
272
+	(currentDate.month() > 9 ?
273
+		QDate(currentDate.year(), 12, 31).toString(Qt::ISODate) :
274
+		QDate(currentDate.year(), currentDate.month() - ((currentDate.month() - 1) % 3) + 3, 1).addDays(-1).toString(Qt::ISODate))));
275
+quickSelector->addItem("This Quarter to Date",
276
+	(currentDate.day() == 1 && (currentDate.month() - 1) % 3 == 0) ?
277
+		QVariant(QStringList() << currentDate.toString(Qt::ISODate)) :
278
+		QVariant(QStringList() <<
279
+		QDate(currentDate.year(), currentDate.month() - ((currentDate.month() - 1) % 3), 1).toString(Qt::ISODate) <<
280
+		currentDate.toString(Qt::ISODate)));
281
+quickSelector->addItem("Last Quarter", currentDate.month() < 4 ?
282
+	QVariant(QStringList() <<
283
+		QDate(currentDate.year() - 1, 10, 1).toString(Qt::ISODate) <<
284
+		QDate(currentDate.year() - 1, 12, 31).toString(Qt::ISODate)) :
285
+	QVariant(QStringList() <<
286
+		QDate(currentDate.year(), currentDate.month() - ((currentDate.month() - 1) % 3) - 3, 1).toString(Qt::ISODate) <<
287
+		QDate(currentDate.year(), currentDate.month() - ((currentDate.month() - 1) % 3), 1).addDays(-1).toString(Qt::ISODate)));
288
+quickSelector->addItem("Last 90 Days", QVariant(QStringList() <<
289
+	currentDate.addDays(-89).toString(Qt::ISODate) <<
290
+	currentDate.toString(Qt::ISODate)));
291
+quickSelector->insertSeparator(quickSelector->count());
292
+quickSelector->addItem("This Year", QVariant(QStringList() <<
293
+	QDate(currentDate.year(), 1, 1).toString(Qt::ISODate) <<
294
+	QDate(currentDate.year(), 12, 31).toString(Qt::ISODate)));
295
+quickSelector->addItem("This Year to Date", (currentDate.dayOfYear() == 1) ?
296
+	QVariant(QStringList() << currentDate.toString(Qt::ISODate)) :
297
+	QVariant(QStringList() << QDate(currentDate.year(), 1, 1).toString(Qt::ISODate) <<
298
+	currentDate.toString(Qt::ISODate)));
299
+quickSelector->addItem("Last Year", QVariant(QStringList() <<
300
+	QDate(currentDate.year() - 1, 1, 1).toString(Qt::ISODate) <<
301
+	QDate(currentDate.year() - 1, 12, 31).toString(Qt::ISODate)));
302
+quickSelector->addItem("Last 365 Days", QVariant(QStringList() <<
303
+	currentDate.addDays(-364).toString(Qt::ISODate) <<
304
+	currentDate.toString(Qt::ISODate)));
305
+quickSelector->insertSeparator(quickSelector->count());
306
+quickSelector->addItem("Lifetime");
307
+quickSelector->addItem("Custom");
308
+
309
+@ Special handling of the Custom range is required because it is possible to
310
+select this from the |QComboBox| and then not set a range. This should result
311
+in the selection changing back to the most recent valid selection. Creating the
312
+pop up in this way is handled in |updateRange()|.
313
+
314
+@<DateRangeSelector implementation@>=
315
+void DateRangeSelector::updateRange(int index)
316
+{
317
+	if(index != lastIndex && index == quickSelector->count() - 1)
318
+	{
319
+		toggleCustom();
320
+	}
321
+	else
322
+	{
323
+		lastIndex = index;
324
+		emit rangeUpdated(quickSelector->itemData(quickSelector->currentIndex()));
325
+	}
326
+}
327
+
328
+@ Resetting the range to the most recent valid selection is handled in
329
+|popupHidden()|.
330
+
331
+@<DateRangeSelector implementation@>=
332
+void DateRangeSelector::popupHidden()
333
+{
334
+	customRangeSelector->deleteLater();
335
+	customRangeSelector = NULL;
336
+	quickSelector->setCurrentIndex(lastIndex);
337
+}
338
+
339
+@ If Custom is set to a new valid range, |lastIndex| will have been set to
340
+point to the appropriate item by a call to |setCustomRange()|.
341
+
342
+@<DateRangeSelector implementation@>=
343
+void DateRangeSelector::setCustomRange(QVariant range)
344
+{
345
+	quickSelector->setItemData(quickSelector->count() - 1, range);
346
+	emit rangeUpdated(range);
347
+	lastIndex = quickSelector->count() - 1;
348
+	quickSelector->setCurrentIndex(lastIndex);
349
+}
350
+
351
+@ When creating the pop up, it should ideally be placed such that the left of
352
+the pop up is aligned with the left of the widget that is normally shown and
353
+immediately under it, however if this would result in part of the pop up not
354
+fitting on the same screen, it should be moved to make a best effort at full
355
+visibility.
356
+
357
+@<DateRangeSelector implementation@>=
358
+void DateRangeSelector::toggleCustom()
359
+{
360
+	if(!customRangeSelector) {
361
+		customRangeSelector = new CustomDateRangePopup(this);
362
+		QPoint pos = rect().bottomLeft();
363
+		QPoint pos2 = rect().topLeft();
364
+		pos = mapToGlobal(pos);
365
+		pos2 = mapToGlobal(pos2);
366
+		QSize size = customRangeSelector->sizeHint();
367
+		QRect screen = QApplication::desktop()->availableGeometry(pos);
368
+		if(pos.x()+size.width() > screen.right()) {
369
+			pos.setX(screen.right()-size.width());
370
+		}
371
+		pos.setX(qMax(pos.x(), screen.left()));
372
+		if(pos.y() + size.height() > screen.bottom()) {
373
+			pos.setY(pos2.y() - size.height());
374
+		} else if (pos.y() < screen.top()){
375
+			pos.setY(screen.top());
376
+		}
377
+		if(pos.y() < screen.top()) {
378
+			pos.setY(screen.top());
379
+		}
380
+		if(pos.y()+size.height() > screen.bottom()) {
381
+			pos.setY(screen.bottom()-size.height());
382
+		}
383
+		customRangeSelector->move(pos);
384
+		customRangeSelector->show();
385
+		connect(customRangeSelector, SIGNAL(hidingPopup()),
386
+				this, SLOT(popupHidden()));
387
+    }
388
+	else
389
+	{
390
+		customRangeSelector->close();
391
+		customRangeSelector->deleteLater();
392
+		customRangeSelector = NULL;
393
+	}
394
+}
395
+
396
+@ While a signal is emitted when the selected range changes, it is frequently
397
+convenient to have a way to request the currently selected range at any time.
398
+
399
+@<DateRangeSelector implementation@>=
400
+QVariant DateRangeSelector::currentRange()
401
+{
402
+	return quickSelector->itemData(lastIndex);
403
+}
404
+
405
+@ Similarly, a method is provided to set the current index of the combo box.
406
+
407
+@<DateRangeSelector implementation@>=
408
+void DateRangeSelector::setCurrentIndex(int index)
409
+{
410
+	quickSelector->setCurrentIndex(index);
411
+}
412
+
413
+@ The Lifetime range is handled somewhat differently from other ranges as there
414
+is no general way to know what that range should be without making unsafe
415
+assumptions. As such, reports are expected to remove the option, provide a
416
+sensible range for it, or handle this selection in a special case. The expected
417
+source of the lifetime date range is the result of a database query so a method
418
+is provided that accepts string representations of the dates. Note that this
419
+method must not be called if the Lifetime option is no longer the second to
420
+last option in the combo box.
421
+
422
+@<DateRangeSelector implementation@>=
423
+void DateRangeSelector::setLifetimeRange(QString startDate, QString endDate)
424
+{
425
+	quickSelector->setItemData(quickSelector->count() - 2,
426
+		QVariant(QStringList() << startDate << endDate));
427
+}
428
+
429
+@ The |removeIndex()| method is intended for removing the Lifetime option in
430
+cases where this is not supported. Use of this method is strongly discouraged.
431
+
432
+@<DateRangeSelector implementation@>=
433
+void DateRangeSelector::removeIndex(int index)
434
+{
435
+	quickSelector->removeItem(index);
436
+}
437
+
438
+@ To use this new control in Typica, we should provide a way to create it from
439
+the XML description of a window.
440
+
441
+@<Additional box layout elements@>=
442
+else if(currentElement.tagName() == "daterange")
443
+{
444
+	addDateRangeToLayout(currentElement, widgetStack, layoutStack);
445
+}
446
+
447
+@ The method for adding a date range selector to a layout is currently trivial.
448
+The |"id"| attribute is supported as usual, as is an |"initial"| attribute for
449
+setting the combo box index.
450
+
451
+@<Functions for scripting@>=
452
+void addDateRangeToLayout(QDomElement element, QStack<QWidget *> *,@|
453
+                          QStack<QLayout *> *layoutStack)
454
+{
455
+	DateRangeSelector *widget = new DateRangeSelector;
456
+	if(element.hasAttribute("id"))
457
+	{
458
+		widget->setObjectName(element.attribute("id"));
459
+	}
460
+	if(element.hasAttribute("initial"))
461
+	{
462
+		widget->setCurrentIndex(element.attribute("initial").toInt());
463
+	}
464
+	QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
465
+	layout->addWidget(widget);
466
+}
467
+
468
+@ The prototype needs to be specified.
469
+
470
+@<Function prototypes for scripting@>=
471
+void addDateRangeToLayout(QDomElement element,
472
+                          QStack<QWidget *> *widgetStack,
473
+                          QStack<QLayout *> *layoutStack);
474
+
475
+@ Our header is also required.
476
+
477
+@<Header files to include@>=
478
+#include "daterangeselector.h"

+ 2
- 2
src/draglabel.cpp View File

@@ -1,4 +1,4 @@
1
-/*842:*/
1
+/*863:*/
2 2
 #line 33 "./scales.w"
3 3
 
4 4
 #include "draglabel.h"
@@ -26,4 +26,4 @@ drag->exec();
26 26
 }
27 27
 }
28 28
 
29
-/*:842*/
29
+/*:863*/

+ 2
- 2
src/draglabel.h View File

@@ -1,4 +1,4 @@
1
-/*841:*/
1
+/*862:*/
2 2
 #line 13 "./scales.w"
3 3
 
4 4
 #ifndef TypicaDragLabelInclude
@@ -17,4 +17,4 @@ void mousePressEvent(QMouseEvent*event);
17 17
 
18 18
 #endif
19 19
 
20
-/*:841*/
20
+/*:862*/

+ 19
- 38
src/rate.w View File

@@ -29,7 +29,6 @@ class RateOfChange : public QObject
29 29
 		int ct;
30 30
 		int st;
31 31
 		QList<Measurement> cache;
32
-		QMap<double,double> smoothCache;
33 32
 };
34 33
 
35 34
 @ The interesting part of this class is in the |newMeasurement()| method. This
@@ -88,51 +87,33 @@ if(cache.size() > 2)
88 87
 	}
89 88
 }
90 89
 
91
-@ The calculation method here is subject to change as this is still noisier
92
-than I would like. What we are doing here is calculating the rate of change
93
-between each pair of adjacent measurements in the cache and averaging them to
94
-produce something that is a little less noisy than just using the first and
95
-last measurements in the cache. Other techniques may be useful for reducing the
96
-noise further.
90
+@ Rather than work directly with changes from one measurement to the next and
91
+attempting to filter out the noise, we instead calculate the slope of a simple
92
+linear regression on the current window of data.
97 93
 
98 94
 The measurement will carry the fact that it is a relative measurement.
99 95
 
100 96
 @<Calculate rate of change@>=
101
-QList<double> rates;
102
-for(int i = 1; i < cache.size(); i++)
97
+int N = cache.size();
98
+double SXY = 0;
99
+double SX = 0;
100
+double SXX = 0;
101
+double SY = 0;
102
+double y;
103
+double x;
104
+for(int i = 0; i < N; i++)
103 105
 {
104
-	double mdiff = cache.at(i).temperature() - cache.at(i-1).temperature();
105
-	double tdiff = (double)(cache.at(i-1).time().msecsTo(cache.at(i).time())) / 1000.0;
106
-	rates.append(mdiff/tdiff);
106
+	y = cache.at(i).temperature();
107
+	SY += y;
108
+	x = cache.at(0).time().msecsTo(cache.at(i).time()) / 1000.0;
109
+	SX += x;
110
+	SXX += (x*x);
111
+	SXY += (x*y);
107 112
 }
108
-double acc = 0.0;
109
-for(int i = 0; i < rates.size(); i++)
110
-{
111
-	acc += rates.at(i);
112
-}
113
-double pavg = acc /= rates.size();
114
-double v2 = pavg * st;
115
-double refm = cache.back().temperature() - cache.front().temperature();
116
-double reft = (double)(cache.front().time().msecsTo(cache.back().time())) / 1000.0;
117
-double ref = refm/reft;
118
-Measurement value(v2, cache.back().time(), cache.back().scale());
113
+double M = ((N * SXY) - (SX * SY)) / ((N * SXX) - (SX * SX));
114
+Measurement value(M * st, cache.back().time(), cache.back().scale());
119 115
 value.insert("relative", true);
120 116
 emit newData(value);
121
-double calcdiff = ref - pavg;
122
-if(calcdiff < 0)
123
-{
124
-	calcdiff = -calcdiff;
125
-}
126
-if(pavg < 0)
127
-{
128
-	pavg = -pavg;
129
-}
130
-if(calcdiff > (pavg * 0.2))
131
-{
132
-	Measurement save = cache.back();
133
-	cache.clear();
134
-	cache.append(save);
135
-}
136 117
 
137 118
 @ The rest of the class implementation is trivial.
138 119
 

+ 4
- 0
src/resources.qrc View File

@@ -23,5 +23,9 @@
23 23
         <file>resources/icons/tango/22x22/categories/applications-graphics.png</file>
24 24
         <file>resources/icons/tango/32x32/categories/applications-graphics.png</file>
25 25
         <file>resources/icons/tango/scalable/categories/applications-graphics.svg</file>
26
+        <file>resources/icons/tango/16x16/apps/office-calendar.png</file>
27
+        <file>resources/icons/tango/22x22/apps/office-calendar.png</file>
28
+        <file>resources/icons/tango/32x32/apps/office-calendar.png</file>
29
+        <file>resources/icons/tango/scalable/apps/office-calendar.svg</file>
26 30
     </qresource>
27 31
 </RCC>

+ 4
- 4
src/resources/Info.plist View File

@@ -7,7 +7,7 @@
7 7
 	<key>CFBundlePackageType</key>
8 8
 	<string>APPL</string>
9 9
 	<key>CFBundleGetInfoString</key>
10
-	<string>Typica 1.6.1</string>
10
+	<string>Typica 1.6.2</string>
11 11
 	<key>CFBundleSignature</key>
12 12
 	<string>@TYPEINFO@</string>
13 13
 	<key>CFBundleExecutable</key>
@@ -17,10 +17,10 @@
17 17
 	<key>CFBundleDisplayName</key>
18 18
 	<string>Typica</string>
19 19
 	<key>CFBundleShortVersionString</key>
20
-	<string>1.6.1</string>
20
+	<string>1.6.2</string>
21 21
 	<key>CFBundleVersion</key>
22
-	<string>1.6.1</string>
22
+	<string>1.6.2</string>
23 23
 	<key>NSHumanReadableCopyright</key>
24
-	<string>© 2007–2013 Neal Wilson</string>
24
+	<string>© 2007–2014 Neal Wilson</string>
25 25
 </dict>
26 26
 </plist>

+ 2
- 3
src/resources/html/about.html View File

@@ -10,10 +10,10 @@
10 10
 				<div id="topbanner">
11 11
 					<a href="http://www.randomfield.com/programs/typica/"><img src="../icons/appicons/logo96.png" height="96px" width="96px" alt="Typica logo" /></a>
12 12
 					<h1><a href="http://www.randomfield.com/programs/typica/">Typica</a></h1>
13
-					<h2>Version 1.6.1</h2>
13
+					<h2>Version 1.6.2</h2>
14 14
 				</div>
15 15
 			<div id="maintext">
16
-				<p>Copyright &copy; 2007&ndash;2013 Neal Evan Wilson
16
+				<p>Copyright &copy; 2007&ndash;2014 Neal Evan Wilson
17 17
 					<span class="icons">
18 18
 						<a href="mailto:roaster@wilsonscoffee.com?subject=Thanks%20for%20Typica&amp;body=Message%20initiated%20from%20Typica.">&#9993;</a>
19 19
 						<a href="https://twitter.com/N3Roaster">&#62217;</a>
@@ -26,7 +26,6 @@
26 26
 				<p>Ongoing development of Typica is made possible through the
27 27
 				generous financial contributions from the following:</p>
28 28
 
29
-				<p>Pinnacle Coffee Roasting</p>
30 29
 				<p>Anonymous Funders Through
31 30
 				<a href="https://www.gittip.com/N3Roaster/">Gittip</a></p>
32 31
 

+ 6
- 6
src/scale.cpp View File

@@ -1,4 +1,4 @@
1
-/*848:*/
1
+/*869:*/
2 2
 #line 131 "./scales.w"
3 3
 
4 4
 #include "scale.h"
@@ -10,7 +10,7 @@ QextSerialPort(port,QextSerialPort::EventDriven)
10 10
 connect(this,SIGNAL(readyRead()),this,SLOT(dataAvailable()));
11 11
 }
12 12
 
13
-/*:848*//*849:*/
13
+/*:869*//*870:*/
14 14
 #line 149 "./scales.w"
15 15
 
16 16
 void SerialScale::dataAvailable()
@@ -24,7 +24,7 @@ responseBuffer.clear();
24 24
 }
25 25
 else
26 26
 {
27
-/*850:*/
27
+/*871:*/
28 28
 #line 189 "./scales.w"
29 29
 
30 30
 QStringList responseParts= QString(responseBuffer.simplified()).split(' ');
@@ -53,7 +53,7 @@ unit= Units::Ounce;
53 53
 }
54 54
 emit newMeasurement(weight,unit);
55 55
 
56
-/*:850*/
56
+/*:871*/
57 57
 #line 161 "./scales.w"
58 58
 
59 59
 responseBuffer.clear();
@@ -61,7 +61,7 @@ responseBuffer.clear();
61 61
 }
62 62
 }
63 63
 
64
-/*:849*//*851:*/
64
+/*:870*//*872:*/
65 65
 #line 220 "./scales.w"
66 66
 
67 67
 void SerialScale::tare()
@@ -74,4 +74,4 @@ void SerialScale::weigh()
74 74
 write("!KP\x0D");
75 75
 }
76 76
 
77
-/*:851*/
77
+/*:872*/

+ 2
- 2
src/scale.h View File

@@ -1,4 +1,4 @@
1
-/*847:*/
1
+/*868:*/
2 2
 #line 103 "./scales.w"
3 3
 
4 4
 #ifndef TypicaScaleInclude
@@ -25,4 +25,4 @@ QByteArray responseBuffer;
25 25
 
26 26
 #endif
27 27
 
28
-/*:847*/
28
+/*:868*/

+ 1297
- 1269
src/typica.cpp
File diff suppressed because it is too large
View File


+ 6
- 6
src/typica.rc View File

@@ -1,7 +1,7 @@
1 1
 #include <winver.h>
2 2
 VS_VERSION_INFO	VERSIONINFO
3
-FILEVERSION 	1,6,1,0
4
-PRODUCTVERSION 	1,6,1,0
3
+FILEVERSION 	1,6,2,0
4
+PRODUCTVERSION 	1,6,2,0
5 5
 FILEFLAGSMASK	0x3fL
6 6
 #ifdef _DEBUG
7 7
 	FILEFLAGS	VS_FF_DEBUG
@@ -16,13 +16,13 @@ BEGIN
16 16
 		BLOCK "040904b0"
17 17
 		BEGIN
18 18
 			VALUE "CompanyName", "Wilson's Coffee & Tea\0"
19
-			VALUE "FileDescription", "Typica 1.6.1\0"
20
-			VALUE "FileVersion", "1.6.1\0"
19
+			VALUE "FileDescription", "Typica 1.6.2\0"
20
+			VALUE "FileVersion", "1.6.2\0"
21 21
 			VALUE "InternalName", "Typica\0"
22
-			VALUE "LegalCopyright", "Copyright 2007-2013 Neal Evan Wilson\0"
22
+			VALUE "LegalCopyright", "Copyright 2007-2014 Neal Evan Wilson\0"
23 23
 			VALUE "OriginalFilename", "Typica.exe\0"
24 24
 			VALUE "ProductName", "Typica\0"
25
-			VALUE "ProductVersion", "1.6.1\0"
25
+			VALUE "ProductVersion", "1.6.2\0"
26 26
 		END
27 27
 	END
28 28
 	BLOCK "VarFileInfo"

+ 5
- 2
src/typica.w View File

@@ -22,8 +22,8 @@
22 22
 \mark{\noexpand\nullsec0{A Note on Notation}}
23 23
 \def\pn{Typica}
24 24
 \def\filebase{typica}
25
-\def\version{1.6.1 \number\year-\number\month-\number\day}
26
-\def\years{2007--2013}
25
+\def\version{1.6.2 \number\year-\number\month-\number\day}
26
+\def\years{2007--2014}
27 27
 \def\title{\pn{} (Version \version)}
28 28
 \newskip\dangerskipb
29 29
 \newskip\dangerskip
@@ -4263,6 +4263,7 @@ void populateBoxLayout(QDomElement element, QStack<QWidget *> *widgetStack,
4263 4263
 				QBoxLayout *layout = qobject_cast<QBoxLayout *>(layoutStack->top());
4264 4264
 				layout->addStretch();
4265 4265
 			}
4266
+			@<Additional box layout elements@>@;
4266 4267
 		}
4267 4268
 	}
4268 4269
 }
@@ -13268,6 +13269,8 @@ void setQTextEditProperties(QScriptValue value, QScriptEngine *engine)
13268 13269
 	value.setProperty("print", engine->newFunction(QTextEdit_print));
13269 13270
 }
13270 13271
 
13272
+@i daterangeselector.w
13273
+
13271 13274
 @** An area for repeated user interface elements.
13272 13275
 
13273 13276
 \noindent There are multiple use cases in which it is useful to specify a

+ 5
- 5
src/units.w View File

@@ -386,7 +386,7 @@ engine->globalObject().setProperty("Units", value);
386 386
 @ The implementation of these functions is trivial.
387 387
 
388 388
 @<Functions for scripting@>=
389
-QScriptValue Units_convertTemperature(QScriptContext *context, QScriptEngine *engine)
389
+QScriptValue Units_convertTemperature(QScriptContext *context, QScriptEngine *)
390 390
 {
391 391
 	return QScriptValue(Units::convertTemperature(argument<double>(0, context),
392 392
 	                                              argument<Units::Unit>(1, context),
@@ -394,7 +394,7 @@ QScriptValue Units_convertTemperature(QScriptContext *context, QScriptEngine *en
394 394
 }
395 395
 
396 396
 QScriptValue Units_convertRelativeTemperature(QScriptContext *context,
397
-                                              QScriptEngine *engine)
397
+                                              QScriptEngine *)
398 398
 {
399 399
 	return QScriptValue(Units::convertRelativeTemperature(
400 400
 	                         argument<double>(0, context),
@@ -402,19 +402,19 @@ QScriptValue Units_convertRelativeTemperature(QScriptContext *context,
402 402
 	                         argument<Units::Unit>(2, context)));
403 403
 }
404 404
 
405
-QScriptValue Units_isTemperatureUnit(QScriptContext *context, QScriptEngine *engine)
405
+QScriptValue Units_isTemperatureUnit(QScriptContext *context, QScriptEngine *)
406 406
 {
407 407
 	return QScriptValue(Units::isTemperatureUnit(argument<Units::Unit>(0, context)));
408 408
 }
409 409
 
410
-QScriptValue Units_convertWeight(QScriptContext *context, QScriptEngine *engine)
410
+QScriptValue Units_convertWeight(QScriptContext *context, QScriptEngine *)
411 411
 {
412 412
 	return QScriptValue(Units::convertWeight(argument<double>(0, context),
413 413
 	                                         argument<Units::Unit>(1, context),
414 414
 	                                         argument<Units::Unit>(2, context)));
415 415
 }
416 416
 
417
-QScriptValue Units_isWeightUnit(QScriptContext *context, QScriptEngine *engine)
417
+QScriptValue Units_isWeightUnit(QScriptContext *context, QScriptEngine *)
418 418
 {
419 419
 	return QScriptValue(Units::isWeightUnit(argument<Units::Unit>(0, context)));
420 420
 }

+ 1
- 1
src/valueannotation.w View File

@@ -276,7 +276,7 @@ engine->globalObject().setProperty("ValueAnnotation", value);
276 276
 @ The implementation of the functions also proceeds as usual.
277 277
 
278 278
 @<Functions for scripting@>=
279
-QScriptValue constructValueAnnotation(QScriptContext *context, QScriptEngine *engine)
279
+QScriptValue constructValueAnnotation(QScriptContext *, QScriptEngine *engine)
280 280
 {
281 281
 	QScriptValue object = engine->newQObject(new ValueAnnotation);
282 282
 	setValueAnnotationProperties(object, engine);

Loading…
Cancel
Save