|
@@ -22,7 +22,7 @@
|
22
|
22
|
\mark{\noexpand\nullsec0{A Note on Notation}}
|
23
|
23
|
\def\pn{Typica}
|
24
|
24
|
\def\filebase{typica}
|
25
|
|
-\def\version{1.4.3 \number\year-\number\month-\number\day}
|
|
25
|
+\def\version{1.5 \number\year-\number\month-\number\day}
|
26
|
26
|
\def\years{2007--2013}
|
27
|
27
|
\def\title{\pn{} (Version \version)}
|
28
|
28
|
\newskip\dangerskipb
|
|
@@ -60,10 +60,10 @@
|
60
|
60
|
distribute, sublicense, and/or sell copies of the Software, and to permit
|
61
|
61
|
persons to whom the Software is furnished to do so, subject to the following
|
62
|
62
|
conditions:\medskip
|
63
|
|
-
|
|
63
|
+
|
64
|
64
|
The above copyright notice and this permission notice shall be included in
|
65
|
65
|
all copies or substantial portions of the Software.\medskip
|
66
|
|
-
|
|
66
|
+
|
67
|
67
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
68
|
68
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
69
|
69
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
@@ -71,24 +71,24 @@
|
71
|
71
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
72
|
72
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
73
|
73
|
IN THE SOFTWARE.
|
74
|
|
-
|
|
74
|
+
|
75
|
75
|
\bigskip\noindent Parts of \pn{} are from QextSerialPort which is used under the
|
76
|
76
|
MIT license as follows:
|
77
|
|
-
|
|
77
|
+
|
78
|
78
|
\bigskip\noindent Copyright \copyright\ 2000--2003 Wayne Roth
|
79
|
|
-
|
|
79
|
+
|
80
|
80
|
\noindent Copyright \copyright\ 2004--2007 Stefan Sander
|
81
|
|
-
|
|
81
|
+
|
82
|
82
|
\noindent Copyright \copyright\ 2007 Michal Policht
|
83
|
|
-
|
|
83
|
+
|
84
|
84
|
\noindent Copyright \copyright\ 2008 Brandon Fosdick
|
85
|
|
-
|
|
85
|
+
|
86
|
86
|
\noindent Copyright \copyright\ 2009--2010 Liam Staskawicz
|
87
|
|
-
|
|
87
|
+
|
88
|
88
|
\noindent Copyright \copyright\ 2011 Debao Zhang
|
89
|
|
-
|
|
89
|
+
|
90
|
90
|
\bigskip\noindent Web: http://code.google.com/p/qextserialport/
|
91
|
|
-
|
|
91
|
+
|
92
|
92
|
\bigskip\noindent Permission is hereby granted, free of charge, to any person obtaining
|
93
|
93
|
a copy of this software and associated documentation files (the
|
94
|
94
|
``Software''), to deal in the Software without restriction, including
|
|
@@ -96,10 +96,10 @@
|
96
|
96
|
distribute, sublicense, and/or sell copies of the Software, and to
|
97
|
97
|
permit persons to whom the Software is furnished to do so, subject to
|
98
|
98
|
the following conditions:
|
99
|
|
-
|
|
99
|
+
|
100
|
100
|
The above copyright notice and this permission notice shall be
|
101
|
101
|
included in all copies or substantial portions of the Software.
|
102
|
|
-
|
|
102
|
+
|
103
|
103
|
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
104
|
104
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
105
|
105
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
@@ -833,6 +833,7 @@ generated file empty.
|
833
|
833
|
@<LinearSplineInterpolator Implementation@>@/
|
834
|
834
|
@<LinearSplineInterpolationConfWidget implementation@>@/
|
835
|
835
|
@<TranslationConfWidget implementation@>@/
|
|
836
|
+@<FreeAnnotationConfWidget implementation@>@/
|
836
|
837
|
|
837
|
838
|
@ A few headers are required for various parts of \pn{}. These allow the use of
|
838
|
839
|
various Qt modules.
|
|
@@ -1141,7 +1142,7 @@ settings and restoring the window geometry from these settings.
|
1141
|
1142
|
|
1142
|
1143
|
As of version 1.4 window geometry management is provided for all windows. The
|
1143
|
1144
|
|restoreSizeAndPosition()| and |saveSizeAndPosition()| methods should be
|
1144
|
|
-considered depreciated.
|
|
1145
|
+considered depreciated.
|
1145
|
1146
|
|
1146
|
1147
|
@<Class declarations@>=
|
1147
|
1148
|
class ScriptQMainWindow : public QMainWindow@/
|
|
@@ -1709,7 +1710,7 @@ QScriptValue constructQBoxLayout(QScriptContext *context,
|
1709
|
1710
|
void setQBoxLayoutProperties(QScriptValue value, QScriptEngine *engine);
|
1710
|
1711
|
QScriptValue QBoxLayout_addLayout(QScriptContext *context, QScriptEngine *engine);
|
1711
|
1712
|
QScriptValue QBoxLayout_addWidget(QScriptContext *context, QScriptEngine *engine);
|
1712
|
|
-
|
|
1713
|
+
|
1713
|
1714
|
@ The script constructor must be passed to the scripting engine.
|
1714
|
1715
|
|
1715
|
1716
|
@<Set up the scripting engine@>=
|
|
@@ -1815,7 +1816,7 @@ QScriptValue QBoxLayout_addWidget(QScriptContext *context, QScriptEngine *)
|
1815
|
1816
|
\noindent The |QAction| class is used in \pn{} to create menu items and respond
|
1816
|
1817
|
to the selection of these items. Three functions are required for our scripting
|
1817
|
1818
|
needs with regard to this class.
|
1818
|
|
-
|
|
1819
|
+
|
1819
|
1820
|
@<Function prototypes for scripting@>=
|
1820
|
1821
|
QScriptValue constructQAction(QScriptContext *context, QScriptEngine *engine);
|
1821
|
1822
|
QScriptValue QAction_setShortcut(QScriptContext *context,
|
|
@@ -1945,7 +1946,7 @@ QScriptValue QFileDialog_getSaveFileName(QScriptContext *context,
|
1945
|
1946
|
retval = QScriptValue(engine,
|
1946
|
1947
|
QFileDialog::getSaveFileName(widget, caption,
|
1947
|
1948
|
dir, "", 0, 0));
|
1948
|
|
-
|
|
1949
|
+
|
1949
|
1950
|
setQFileDialogProperties(retval, engine);
|
1950
|
1951
|
}
|
1951
|
1952
|
else
|
|
@@ -3168,7 +3169,7 @@ are not created directly.
|
3168
|
3169
|
@<Function prototypes for scripting@>=
|
3169
|
3170
|
void setQAbstractScrollAreaProperties(QScriptValue value,
|
3170
|
3171
|
QScriptEngine *engine);
|
3171
|
|
-
|
|
3172
|
+
|
3172
|
3173
|
@ The implementation of this is simple.
|
3173
|
3174
|
|
3174
|
3175
|
@<Functions for scripting@>=
|
|
@@ -3494,7 +3495,7 @@ QScriptValue setFont(QScriptContext *context, QScriptEngine *engine);
|
3494
|
3495
|
QScriptValue annotationFromRecord(QScriptContext *context,
|
3495
|
3496
|
QScriptEngine *engine);
|
3496
|
3497
|
QScriptValue setTabOrder(QScriptContext *context, QScriptEngine *engine);
|
3497
|
|
-
|
|
3498
|
+
|
3498
|
3499
|
@ These functions are passed to the scripting engine.
|
3499
|
3500
|
|
3500
|
3501
|
@<Set up the scripting engine@>=
|
|
@@ -3771,7 +3772,7 @@ and reorganized.\endanger
|
3771
|
3772
|
|
3772
|
3773
|
@<Function prototypes for scripting@>=
|
3773
|
3774
|
QScriptValue createWindow(QScriptContext *context, QScriptEngine *engine);
|
3774
|
|
-void addLayoutToWidget(QDomElement element, QStack<QWidget*> *widgetStack,
|
|
3775
|
+void addLayoutToWidget(QDomElement element, QStack<QWidget*> *widgetStack,
|
3775
|
3776
|
QStack<QLayout*> *layoutStack);
|
3776
|
3777
|
void addLayoutToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
|
3777
|
3778
|
QStack<QLayout *> *layoutStack);
|
|
@@ -4046,7 +4047,7 @@ are supported. The first two resolve to |QBoxLayout| layouts, {\tt grid}
|
4046
|
4047
|
resolves to a |QGridLayout|, and {\tt stack} resolves to a |QStackedLayout|.
|
4047
|
4048
|
|
4048
|
4049
|
@<Functions for scripting@>=
|
4049
|
|
-void addLayoutToWidget(QDomElement element, QStack<QWidget*> *widgetStack,
|
|
4050
|
+void addLayoutToWidget(QDomElement element, QStack<QWidget*> *widgetStack,
|
4050
|
4051
|
QStack<QLayout*> *layoutStack)
|
4051
|
4052
|
{
|
4052
|
4053
|
if(element.hasAttribute("type"))
|
|
@@ -7413,7 +7414,7 @@ QScriptValue constructMeasurementTimeOffset(QScriptContext *context,@|
|
7413
|
7414
|
QScriptEngine *engine);
|
7414
|
7415
|
void setMeasurementTimeOffsetProperties(QScriptValue value,
|
7415
|
7416
|
QScriptEngine *engine);
|
7416
|
|
-
|
|
7417
|
+
|
7417
|
7418
|
@ The scripting engine must be informed of the constructor.
|
7418
|
7419
|
|
7419
|
7420
|
@<Set up the scripting engine@>=
|
|
@@ -8782,7 +8783,7 @@ QScriptValue ZoomLog_lastTime(QScriptContext *context, QScriptEngine *engine)
|
8782
|
8783
|
ZoomLog *self = getself<@[ZoomLog *@]>(context);
|
8783
|
8784
|
return QScriptValue(engine, self->lastTime(argument<int>(0, context)));
|
8784
|
8785
|
}
|
8785
|
|
-
|
|
8786
|
+
|
8786
|
8787
|
@* A model for roasting data.
|
8787
|
8788
|
|
8788
|
8789
|
\noindent Qt provides a tool called the model view architecture. This provides a
|
|
@@ -8914,7 +8915,7 @@ void MeasurementModel::newMeasurement(Measurement measure, int tempcolumn)
|
8914
|
8915
|
emit rowChanged(insertion);
|
8915
|
8916
|
delete temp;
|
8916
|
8917
|
}
|
8917
|
|
-
|
|
8918
|
+
|
8918
|
8919
|
@ To find the insertion point for new measurements we use a binary search of the
|
8919
|
8920
|
existing data. The code below is a direct adaptation of Program B\nfnote{%
|
8920
|
8921
|
\underbar{The Art of Computer Programming} Volume 3 Sorting and Searching 2nd
|
|
@@ -9404,7 +9405,7 @@ QVariant MeasurementModel::data(const QModelIndex &index, int role) const@/
|
9404
|
9405
|
default:
|
9405
|
9406
|
break;
|
9406
|
9407
|
}
|
9407
|
|
- }
|
|
9408
|
+ }
|
9408
|
9409
|
return QVariant(row->at(index.column()).toString());
|
9409
|
9410
|
}
|
9410
|
9411
|
}
|
|
@@ -9757,7 +9758,7 @@ because there were no shops in Racine that could sell a simple dual digital
|
9757
|
9758
|
count up timer at a time when my first timer was malfunctioning. After
|
9758
|
9759
|
attempting to purchase a replacement device at several stores that have sold
|
9759
|
9760
|
such devices in the past, I decided to spend a couple hours writing my own
|
9760
|
|
-timer.
|
|
9761
|
+timer.
|
9761
|
9762
|
|
9762
|
9763
|
For historical reasons, the |TimerDisplay| class is considerably more functional
|
9763
|
9764
|
than \pn{} requires. Those needing only a digital timer can extract the code for
|
|
@@ -10207,7 +10208,7 @@ class PackLayout : public QLayout@/
|
10207
|
10208
|
};
|
10208
|
10209
|
|
10209
|
10210
|
@ The interesting portion of this class is in |doLayout()|. This function goes
|
10210
|
|
-over the items in the layout and sets the geometry appropriately.
|
|
10211
|
+over the items in the layout and sets the geometry appropriately.
|
10211
|
10212
|
|
10212
|
10213
|
The seemingly odd choice of returning |y| at the end of this function (indeed of
|
10213
|
10214
|
having a return value at all) is to allow this function to provide the return
|
|
@@ -10536,7 +10537,7 @@ WidgetDecorator::WidgetDecorator(QWidget *widget, const QString &labeltext,
|
10536
|
10537
|
@<Adjust the decoration width@>@;
|
10537
|
10538
|
@<Pack widgets into the layout@>@;
|
10538
|
10539
|
}
|
10539
|
|
-
|
|
10540
|
+
|
10540
|
10541
|
@ The decoration is a |QGraphicsView|. To get this to look right, we need to
|
10541
|
10542
|
make sure there aren't any scroll bars and there shouldn't be a frame
|
10542
|
10543
|
surrounding it. While we're at it, we allow it to accept clicks, though this
|
|
@@ -12368,16 +12369,16 @@ int main(int argc, char **argv)@/
|
12368
|
12369
|
Application app(*c, argv);
|
12369
|
12370
|
@<Set up icons@>@;
|
12370
|
12371
|
@<Set up fonts@>@;
|
12371
|
|
-
|
|
12372
|
+
|
12372
|
12373
|
QSettings settings;
|
12373
|
|
-
|
|
12374
|
+
|
12374
|
12375
|
@<Register device configuration widgets@>@;
|
12375
|
12376
|
@<Prepare the database connection@>@;
|
12376
|
12377
|
@<Load the application configuration@>@;
|
12377
|
12378
|
@<Set up the scripting engine@>@;
|
12378
|
12379
|
app.engine = engine;
|
12379
|
12380
|
@<Find and evaluate starting script@>@;
|
12380
|
|
-
|
|
12381
|
+
|
12381
|
12382
|
int retval = app.exec();
|
12382
|
12383
|
delete engine;
|
12383
|
12384
|
return retval;@/
|
|
@@ -13216,7 +13217,7 @@ QScriptValue QTextEdit_print(QScriptContext *context, QScriptEngine *)
|
13216
|
13217
|
QTextEdit *self = getself<QTextEdit *>(context);
|
13217
|
13218
|
QTextDocument *document = self->document();
|
13218
|
13219
|
QPrinter printer;
|
13219
|
|
-
|
|
13220
|
+
|
13220
|
13221
|
QPrintDialog printwindow(&printer, self);
|
13221
|
13222
|
if(printwindow.exec() != QDialog::Accepted)
|
13222
|
13223
|
{
|
|
@@ -14580,7 +14581,7 @@ QScriptValue QAbstractItemModel_data(QScriptContext *context, QScriptEngine *eng
|
14580
|
14581
|
QScriptValue QAbstractItemModel_index(QScriptContext *context, QScriptEngine *engine);
|
14581
|
14582
|
QScriptValue QAbstractItemModel_rowCount(QScriptContext *context, QScriptEngine *engine);
|
14582
|
14583
|
QScriptValue QAbstractItemModel_hasChildren(QScriptContext *context, QScriptEngine *engine);
|
14583
|
|
-
|
|
14584
|
+
|
14584
|
14585
|
@ The constructor is trivial.
|
14585
|
14586
|
|
14586
|
14587
|
@<Functions for scripting@>=
|
|
@@ -15149,15 +15150,21 @@ RoasterConfWidget::RoasterConfWidget(DeviceTreeModel *model, const QModelIndex &
|
15149
|
15150
|
NodeInserter *basicButtonInserter = new NodeInserter(tr("Annotation Button"), tr("Annotation Button"), "annotationbutton");
|
15150
|
15151
|
NodeInserter *countingButtonInserter = new NodeInserter(tr("Counting Button"), tr("Counting Button"), "reconfigurablebutton");
|
15151
|
15152
|
NodeInserter *spinBoxInserter = new NodeInserter(tr("Numeric Entry"), tr("Numeric Entry"), "annotationspinbox");
|
|
15153
|
+ NodeInserter *freeAnnotationInserter = new NodeInserter(tr("Free Text"),
|
|
15154
|
+ tr("Free Text"),
|
|
15155
|
+ "freeannotation");
|
15152
|
15156
|
annotationMenu->addAction(basicButtonInserter);
|
15153
|
15157
|
annotationMenu->addAction(countingButtonInserter);
|
15154
|
15158
|
annotationMenu->addAction(spinBoxInserter);
|
|
15159
|
+ annotationMenu->addAction(freeAnnotationInserter);
|
15155
|
15160
|
connect(basicButtonInserter, SIGNAL(triggered(QString, QString)),
|
15156
|
15161
|
this, SLOT(insertChildNode(QString, QString)));
|
15157
|
15162
|
connect(countingButtonInserter, SIGNAL(triggered(QString, QString)),
|
15158
|
15163
|
this, SLOT(insertChildNode(QString, QString)));
|
15159
|
15164
|
connect(spinBoxInserter, SIGNAL(triggered(QString, QString)),
|
15160
|
15165
|
this, SLOT(insertChildNode(QString, QString)));
|
|
15166
|
+ connect(freeAnnotationInserter, SIGNAL(triggered(QString, QString)),
|
|
15167
|
+ this, SLOT(insertChildNode(QString, QString)));
|
15161
|
15168
|
addAnnotationControlButton->setMenu(annotationMenu);
|
15162
|
15169
|
layout->addWidget(addAnnotationControlButton);
|
15163
|
15170
|
QPushButton *advancedButton = new QPushButton(tr("Advanced Features"));
|
|
@@ -15190,7 +15197,7 @@ RoasterConfWidget::RoasterConfWidget(DeviceTreeModel *model, const QModelIndex &
|
15190
|
15197
|
connect(id, SIGNAL(valueChanged(int)), this, SLOT(updateRoasterId(int)));
|
15191
|
15198
|
setLayout(layout);
|
15192
|
15199
|
}
|
15193
|
|
-
|
|
15200
|
+
|
15194
|
15201
|
@ Iterating over the configuration data associated with the current node is
|
15195
|
15202
|
required in nearly every configuration widget. The specifics of the loop
|
15196
|
15203
|
vary, but there is likely a better way to generalize that. Until then,
|
|
@@ -15452,7 +15459,7 @@ app.registerDeviceConfigurationWidget("nidaqmxbase9211series",
|
15452
|
15459
|
NiDaqMxBase9211ConfWidget::staticMetaObject);
|
15453
|
15460
|
app.registerDeviceConfigurationWidget("ni9211seriestc",
|
15454
|
15461
|
Ni9211TcConfWidget::staticMetaObject);
|
15455
|
|
-
|
|
15462
|
+
|
15456
|
15463
|
@ Furthermore, we should create the NodeInserter objects for adding top level
|
15457
|
15464
|
nodes to the configuration. Preferably we would only allow top level nodes to
|
15458
|
15465
|
be inserted when all prerequisite software is available.
|
|
@@ -16639,7 +16646,7 @@ inserter = new NodeInserter(tr("Modbus RTU Port"), tr("Modbus RTU Port"), "modbu
|
16639
|
16646
|
topLevelNodeInserters.append(inserter);
|
16640
|
16647
|
#endif
|
16641
|
16648
|
|
16642
|
|
-@* Configuration of Annotation Controls.
|
|
16649
|
+@** Configuration of Annotation Controls.
|
16643
|
16650
|
|
16644
|
16651
|
\noindent Aside from the details of hardware devices, the logging view must
|
16645
|
16652
|
also be able to set up log annotation controls. A few different control types
|
|
@@ -16908,6 +16915,8 @@ void NoteSpinConfWidget::updatePosttext(const QString &text)
|
16908
|
16915
|
@<Register device configuration widgets@>=
|
16909
|
16916
|
app.registerDeviceConfigurationWidget("annotationspinbox", NoteSpinConfWidget::staticMetaObject);
|
16910
|
16917
|
|
|
16918
|
+@i freeannotation.w
|
|
16919
|
+
|
16911
|
16920
|
@** Communicating with a Device through Modbus RTU.
|
16912
|
16921
|
|
16913
|
16922
|
\noindent The classes described here need to be further generalized to support
|
|
@@ -17362,7 +17371,7 @@ Messages with a function number of 0x03 or 0x04 will be at least 7 bytes in
|
17362
|
17371
|
length with the total length determined by the sum of 5 and the value in the
|
17363
|
17372
|
fifth byte. Messages with a function number of 0x05, 0x06, or 0x10 will be 8
|
17364
|
17373
|
bytes in length. Messages with a function number greater than 0x80 will be five
|
17365
|
|
-bytes in length.
|
|
17374
|
+bytes in length.
|
17366
|
17375
|
|
17367
|
17376
|
@<Check Modbus RTU message size@>=
|
17368
|
17377
|
if(responseBuffer.size() < 5)
|
|
@@ -17480,7 +17489,7 @@ void ModbusRTUDevice::outputSV(double value)
|
17480
|
17489
|
char *valBytes = (char*)&outval;
|
17481
|
17490
|
message.append(valBytes[1]);
|
17482
|
17491
|
message.append(valBytes[0]);
|
17483
|
|
- queueMessage(message, this, "ignore(QByteArray)");
|
|
17492
|
+ queueMessage(message, this, "ignore(QByteArray)");
|
17484
|
17493
|
}
|
17485
|
17494
|
|
17486
|
17495
|
@ We don't care about the response when sending a new SV.
|
|
@@ -18144,7 +18153,7 @@ LinearSplineInterpolationConfWidget::LinearSplineInterpolationConfWidget(DeviceT
|
18144
|
18153
|
@<Convert numeric array literal to list@>@;
|
18145
|
18154
|
int column = 0;
|
18146
|
18155
|
@<Populate model column from list@>@;
|
18147
|
|
-
|
|
18156
|
+
|
18148
|
18157
|
}
|
18149
|
18158
|
else if(node.attribute("name") == "destinationvalues")
|
18150
|
18159
|
{
|
|
@@ -18183,7 +18192,7 @@ for(int i = 0; i < itemList.size(); i++)
|
18183
|
18192
|
{
|
18184
|
18193
|
knotmodel->setData(knotmodel->index(i, column),
|
18185
|
18194
|
QVariant(itemList.at(i).toDouble()),
|
18186
|
|
- Qt::DisplayRole);
|
|
18195
|
+ Qt::DisplayRole);
|
18187
|
18196
|
}
|
18188
|
18197
|
|
18189
|
18198
|
@ When data in the table is changed we simply overwrite any previously saved
|