Browse Source

ValueAnnotation integration with example configuration

Neal Wilson 11 years ago
parent
commit
81afd9585f
3 changed files with 129 additions and 38 deletions
  1. 24
    0
      config/Windows/productionroaster.xml
  2. 26
    23
      src/typica.w
  3. 79
    15
      src/valueannotation.w

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

337
 					annotationPanel.addWidget(button);
337
 					annotationPanel.addWidget(button);
338
 					tabControls.push(button);
338
 					tabControls.push(button);
339
 				}
339
 				}
340
+				else if(driverReference.driver == "valueannotation")
341
+				{
342
+					var checker = new ValueAnnotation;
343
+					var valuesSetting = driverReference.measuredValues;
344
+					var notesSetting = driverReference.annotations;
345
+					var valuesList = valuesSetting.slice(2, valuesSetting.length-2).split(",");
346
+					var notesList = notesSetting.slice(2, notesSetting.length-2).split(",");
347
+					if(valuesList.length > 1 && notesList.length == valuesList.length) {
348
+						for(var j = 0; j < valuesList.length; j++) {
349
+							checker.setAnnotation(Number(valueList[j]), notesList[j]);
350
+						}
351
+					}
352
+					if(driverReference.emitOnStart == "true") {
353
+						start.clicked.connect(checker.annotate);
354
+					}
355
+					var colname = driverReference.source;
356
+					for(var j = 0; j < columnNames.length; j++) {
357
+						if(columnNames[j] == colname) {
358
+							channels[j].newData.connect(checker.newMeasurement);
359
+							break;
360
+						}
361
+					}
362
+					annotationButtons.push(checker);
363
+				}
340
 				else if(driverReference.driver == "reconfigurablebutton")
364
 				else if(driverReference.driver == "reconfigurablebutton")
341
 				{
365
 				{
342
 					var button = new AnnotationButton(driverReference.buttontext);
366
 					var button = new AnnotationButton(driverReference.buttontext);

+ 26
- 23
src/typica.w View File

840
 @<GraphSettingsWidget implementation@>@/
840
 @<GraphSettingsWidget implementation@>@/
841
 @<DataqSdkDeviceConfWidget implementation@>@/
841
 @<DataqSdkDeviceConfWidget implementation@>@/
842
 @<SerialScaleConfWidget implementation@>@/
842
 @<SerialScaleConfWidget implementation@>@/
843
+@<ValueAnnotation implementation@>@/
844
+@<ValueAnnotationConfWidget implementation@>@/
843
 
845
 
844
 @ A few headers are required for various parts of \pn{}. These allow the use of
846
 @ A few headers are required for various parts of \pn{}. These allow the use of
845
 various Qt modules.
847
 various Qt modules.
10017
 r = cseconds - oseconds;
10019
 r = cseconds - oseconds;
10018
 
10020
 
10019
 @ The logic for a count down timer is very similar to the logic for a count up
10021
 @ The logic for a count down timer is very similar to the logic for a count up
10020
-timer. A key difference is that we don't want to continue counting down if the
10022
+timer. A key difference is that we don'@q'@>t want to continue counting down if the
10021
 timer has already reached 0.
10023
 timer has already reached 0.
10022
 
10024
 
10023
 @<Check for Timer Decrement@>=
10025
 @<Check for Timer Decrement@>=
10077
 }
10079
 }
10078
 
10080
 
10079
 @ Stopping the timer is a little simpler. Remember to stop the clock so we
10081
 @ Stopping the timer is a little simpler. Remember to stop the clock so we
10080
-aren't updating senselessly.
10082
+aren'@q'@>t updating senselessly.
10081
 
10083
 
10082
 @<TimerDisplay Implementation@>=
10084
 @<TimerDisplay Implementation@>=
10083
 void TimerDisplay::stopTimer()@t\2\2@>@/
10085
 void TimerDisplay::stopTimer()@t\2\2@>@/
11982
 
11984
 
11983
 The end of this function may seem a little strange. Why not simply look up the
11985
 The end of this function may seem a little strange. Why not simply look up the
11984
 map and insert information directly into the model data? Well, as of this
11986
 map and insert information directly into the model data? Well, as of this
11985
-writing, that doesn't work. There are two ways around that problem. One is to
11987
+writing, that doesn'@q'@>t work. There are two ways around that problem. One is to
11986
 have the lists store references and dereference the real data. The other option
11988
 have the lists store references and dereference the real data. The other option
11987
 is to obtain a copy of the row, then a copy of the cell, update the cell, then
11989
 is to obtain a copy of the row, then a copy of the cell, update the cell, then
11988
 replace the old value of the cell in the copy of the row, then replace the old
11990
 replace the old value of the cell in the copy of the row, then replace the old
12057
 	@<Expand the SaltModel@>@;
12059
 	@<Expand the SaltModel@>@;
12058
 }
12060
 }
12059
 
12061
 
12060
-@ The destructor doesn't need to do anything.
12062
+@ The destructor doesn'@q'@>t need to do anything.
12061
 
12063
 
12062
 @<SaltModel Implementation@>=
12064
 @<SaltModel Implementation@>=
12063
 SaltModel::~SaltModel()
12065
 SaltModel::~SaltModel()
12476
 @ In order to connect to the database, we need five pieces of information: the
12478
 @ In order to connect to the database, we need five pieces of information: the
12477
 name of a database driver (PostgreSQL is recommended for now), the host name of
12479
 name of a database driver (PostgreSQL is recommended for now), the host name of
12478
 the computer running the database, the name of the database, the name of the
12480
 the computer running the database, the name of the database, the name of the
12479
-user connecting to the database, and that user's password. This information will
12481
+user connecting to the database, and that user'@q'@>s password. This information will
12480
 be stored in the user settings for the application so that the database
12482
 be stored in the user settings for the application so that the database
12481
 connection can be established without prompting the user next time. A class is
12483
 connection can be established without prompting the user next time. A class is
12482
 provided to gather this information.
12484
 provided to gather this information.
12669
 				  QVariant(newsize));
12671
 				  QVariant(newsize));
12670
 
12672
 
12671
 @ To determine which window a given table is in, we just follow
12673
 @ To determine which window a given table is in, we just follow
12672
-|parentWidget()| until there isn't one. It is possible that the table view
12674
+|parentWidget()| until there isn'@q'@>t one. It is possible that the table view
12673
 will also be the window, however this is not advised as it is easier for the
12675
 will also be the window, however this is not advised as it is easier for the
12674
 settings key to be non-unique in such a case.
12676
 settings key to be non-unique in such a case.
12675
 
12677
 
12971
 in Qt. This brings several benefits, including making it easy to print reports
12973
 in Qt. This brings several benefits, including making it easy to print reports
12972
 or save reports as plain text or HTML.
12974
 or save reports as plain text or HTML.
12973
 
12975
 
12974
-Reports are specified in the \pn{}'s configuration document and can include both
12976
+Reports are specified in the \pn{}'@q'@>s configuration document and can include both
12975
 static elements and elements that are populated by external data such as the
12977
 static elements and elements that are populated by external data such as the
12976
 result of a SQL query.
12978
 result of a SQL query.
12977
 
12979
 
13223
 @ It is sometimes desirable to add fixed data such as column headers to a table.
13225
 @ It is sometimes desirable to add fixed data such as column headers to a table.
13224
 This is done with the {\tt <row>} element.
13226
 This is done with the {\tt <row>} element.
13225
 
13227
 
13226
-Technically, this isn't needed. The same results can be produced by using a
13228
+Technically, this isn'@q'@>t needed. The same results can be produced by using a
13227
 {\tt <query>} element to select constant data, but this approach saves a trip to
13229
 {\tt <query>} element to select constant data, but this approach saves a trip to
13228
 the database.
13230
 the database.
13229
 
13231
 
14210
 	saveDeviceConfiguration();
14212
 	saveDeviceConfiguration();
14211
 }
14213
 }
14212
 
14214
 
14213
-@ There isn't really anything that can be done if the device configuration data
14215
+@ There isn'@q'@>t really anything that can be done if the device configuration data
14214
 is corrupt, but an error message can be produced if the program happens to have
14216
 is corrupt, but an error message can be produced if the program happens to have
14215
 access to a debugging console.
14217
 access to a debugging console.
14216
 
14218
 
14600
 	return QDomElement();
14602
 	return QDomElement();
14601
 }
14603
 }
14602
 
14604
 
14603
-@ We don't want any headers, so |headerData()| is very simple.
14605
+@ We don'@q'@>t want any headers, so |headerData()| is very simple.
14604
 
14606
 
14605
 @<DeviceTreeModel implementation@>=
14607
 @<DeviceTreeModel implementation@>=
14606
 QVariant DeviceTreeModel::headerData(int, Qt::Orientation, int) const
14608
 QVariant DeviceTreeModel::headerData(int, Qt::Orientation, int) const
15228
 	        this, SLOT(insertChildNode(QString, QString)));
15230
 	        this, SLOT(insertChildNode(QString, QString)));
15229
 	connect(freeAnnotationInserter, SIGNAL(triggered(QString, QString)),
15231
 	connect(freeAnnotationInserter, SIGNAL(triggered(QString, QString)),
15230
 	        this, SLOT(insertChildNode(QString, QString)));
15232
 	        this, SLOT(insertChildNode(QString, QString)));
15233
+	@<Add annotation control node inserters@>@;
15231
 	addAnnotationControlButton->setMenu(annotationMenu);
15234
 	addAnnotationControlButton->setMenu(annotationMenu);
15232
 	layout->addWidget(addAnnotationControlButton);
15235
 	layout->addWidget(addAnnotationControlButton);
15233
 	QPushButton *advancedButton = new QPushButton(tr("Advanced Features"));
15236
 	QPushButton *advancedButton = new QPushButton(tr("Advanced Features"));
15816
 A later version of QextSerialPort than is used by \pn{} provides a helper
15819
 A later version of QextSerialPort than is used by \pn{} provides a helper
15817
 class which can be used more conveniently to create this sort of control. As
15820
 class which can be used more conveniently to create this sort of control. As
15818
 this is not yet available to \pn{}, we instead copy the |enum| specifying
15821
 this is not yet available to \pn{}, we instead copy the |enum| specifying
15819
-the appropriate values into the class and use Qt's meta-object system to
15822
+the appropriate values into the class and use Qt'@q'@>s meta-object system to
15820
 populate the combo box based on the values in that |enum|.
15823
 populate the combo box based on the values in that |enum|.
15821
 
15824
 
15822
 @<Class declarations@>=
15825
 @<Class declarations@>=
17304
 }
17307
 }
17305
 
17308
 
17306
 @ There are two ways that we might request measurement data. All of the
17309
 @ There are two ways that we might request measurement data. All of the
17307
-devices I've seen documented provide function 0x4 addresses for PV and SV
17310
+devices I'@q'@>ve seen documented provide function 0x4 addresses for PV and SV
17308
 such that SV can be obtained from the address immediately after the address
17311
 such that SV can be obtained from the address immediately after the address
17309
 from which we obtain PV. In this case we request both values at the same time.
17312
 from which we obtain PV. In this case we request both values at the same time.
17310
 
17313
 
17389
 this buffer will have incomplete data. This means that we must determine when
17392
 this buffer will have incomplete data. This means that we must determine when
17390
 the full response is available before passing the complete response along to
17393
 the full response is available before passing the complete response along to
17391
 the appropriate method. If the response has not been received in full, nothing
17394
 the appropriate method. If the response has not been received in full, nothing
17392
-is done. We'll be notified of more data shortly.
17395
+is done. We'@q'@>ll be notified of more data shortly.
17393
 
17396
 
17394
 When the message we see the response for was queued, a callback was also
17397
 When the message we see the response for was queued, a callback was also
17395
 registered to handle the response. Once we have the complete message, we pass
17398
 registered to handle the response. Once we have the complete message, we pass
17562
 	queueMessage(message, this, "ignore(QByteArray)");
17565
 	queueMessage(message, this, "ignore(QByteArray)");
17563
 }
17566
 }
17564
 
17567
 
17565
-@ We don't care about the response when sending a new SV.
17568
+@ We don'@q'@>t care about the response when sending a new SV.
17566
 
17569
 
17567
 @<ModbusRTUDevice implementation@>=
17570
 @<ModbusRTUDevice implementation@>=
17568
 void ModbusRTUDevice::ignore(QByteArray)
17571
 void ModbusRTUDevice::ignore(QByteArray)
18183
 		void updateDestinationColumn(const QString &dest);
18186
 		void updateDestinationColumn(const QString &dest);
18184
 		void updateKnots();
18187
 		void updateKnots();
18185
 	private:@/
18188
 	private:@/
18186
-		SaltModel *model;
18189
+		SaltModel *tablemodel;
18187
 };
18190
 };
18188
 
18191
 
18189
 @ This is configured by specifying a source column name, a destination column
18192
 @ This is configured by specifying a source column name, a destination column
18192
 
18195
 
18193
 @<LinearSplineInterpolationConfWidget implementation@>=
18196
 @<LinearSplineInterpolationConfWidget implementation@>=
18194
 LinearSplineInterpolationConfWidget::LinearSplineInterpolationConfWidget(DeviceTreeModel *model, const QModelIndex &index)
18197
 LinearSplineInterpolationConfWidget::LinearSplineInterpolationConfWidget(DeviceTreeModel *model, const QModelIndex &index)
18195
-: BasicDeviceConfigurationWidget(model, index), model(new SaltModel(2))
18198
+: BasicDeviceConfigurationWidget(model, index), tablemodel(new SaltModel(2))
18196
 {
18199
 {
18197
 	QFormLayout *layout = new QFormLayout;
18200
 	QFormLayout *layout = new QFormLayout;
18198
 	QLineEdit *source = new QLineEdit;
18201
 	QLineEdit *source = new QLineEdit;
18199
 	layout->addRow(tr("Source column name:"), source);
18202
 	layout->addRow(tr("Source column name:"), source);
18200
 	QLineEdit *destination = new QLineEdit;
18203
 	QLineEdit *destination = new QLineEdit;
18201
 	layout->addRow(tr("Destination column name:"), destination);
18204
 	layout->addRow(tr("Destination column name:"), destination);
18202
-	model->setHeaderData(0, Qt::Horizontal, "Input");
18203
-	model->setHeaderData(1, Qt::Horizontal, "Output");
18205
+	tablemodel->setHeaderData(0, Qt::Horizontal, "Input");
18206
+	tablemodel->setHeaderData(1, Qt::Horizontal, "Output");
18204
 	QTableView *mappingTable = new QTableView;
18207
 	QTableView *mappingTable = new QTableView;
18205
-	mappingTable->setModel(model);
18208
+	mappingTable->setModel(tablemodel);
18206
 	NumericDelegate *delegate = new NumericDelegate;
18209
 	NumericDelegate *delegate = new NumericDelegate;
18207
 	mappingTable->setItemDelegate(delegate);
18210
 	mappingTable->setItemDelegate(delegate);
18208
 	layout->addRow(tr("Mapping data:"), mappingTable);
18211
 	layout->addRow(tr("Mapping data:"), mappingTable);
18237
 	updateKnots();
18240
 	updateKnots();
18238
 	connect(source, SIGNAL(textEdited(QString)), this, SLOT(updateSourceColumn(QString)));
18241
 	connect(source, SIGNAL(textEdited(QString)), this, SLOT(updateSourceColumn(QString)));
18239
 	connect(destination, SIGNAL(textEdited(QString)), this, SLOT(updateDestinationColumn(QString)));
18242
 	connect(destination, SIGNAL(textEdited(QString)), this, SLOT(updateDestinationColumn(QString)));
18240
-	connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(updateKnots()));
18243
+	connect(tablemodel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(updateKnots()));
18241
 	setLayout(layout);
18244
 	setLayout(layout);
18242
 }
18245
 }
18243
 
18246
 
18260
 @<Populate model column from list@>=
18263
 @<Populate model column from list@>=
18261
 for(int i = 0; i < itemList.size(); i++)
18264
 for(int i = 0; i < itemList.size(); i++)
18262
 {
18265
 {
18263
-	model->setData(model->index(i, column),
18266
+	tablemodel->setData(tablemodel->index(i, column),
18264
 	               QVariant(itemList.at(i).toDouble()),
18267
 	               QVariant(itemList.at(i).toDouble()),
18265
                    Qt::DisplayRole);
18268
                    Qt::DisplayRole);
18266
 }
18269
 }
18271
 @<LinearSplineInterpolationConfWidget implementation@>=
18274
 @<LinearSplineInterpolationConfWidget implementation@>=
18272
 void LinearSplineInterpolationConfWidget::updateKnots()
18275
 void LinearSplineInterpolationConfWidget::updateKnots()
18273
 {
18276
 {
18274
-	updateAttribute("sourcevalues", model->arrayLiteral(0, Qt::DisplayRole));
18275
-	updateAttribute("destinationvalues", model->arrayLiteral(1, Qt::DisplayRole));
18277
+	updateAttribute("sourcevalues", tablemodel->arrayLiteral(0, Qt::DisplayRole));
18278
+	updateAttribute("destinationvalues", tablemodel->arrayLiteral(1, Qt::DisplayRole));
18276
 }
18279
 }
18277
 
18280
 
18278
 void LinearSplineInterpolationConfWidget::updateSourceColumn(const QString &source)
18281
 void LinearSplineInterpolationConfWidget::updateSourceColumn(const QString &source)

+ 79
- 15
src/valueannotation.w View File

11
 to identify which data series should be monitored and what annotations should
11
 to identify which data series should be monitored and what annotations should
12
 be produced for what values.
12
 be produced for what values.
13
 
13
 
14
-@<Class declrations@>=
14
+@<Class declarations@>=
15
 class ValueAnnotationConfWidget : public BasicDeviceConfigurationWidget
15
 class ValueAnnotationConfWidget : public BasicDeviceConfigurationWidget
16
 {
16
 {
17
 	Q_OBJECT
17
 	Q_OBJECT
23
 		void updateAnnotations();
23
 		void updateAnnotations();
24
 		void updateStart(bool noteOnStart);
24
 		void updateStart(bool noteOnStart);
25
 	private:
25
 	private:
26
-		SaltModel *model;
26
+		SaltModel *tablemodel;
27
 };
27
 };
28
 
28
 
29
 @ The constructor sets up the configuration interface requesting a source
29
 @ The constructor sets up the configuration interface requesting a source
34
 ValueAnnotationConfWidget::ValueAnnotationConfWidget(DeviceTreeModel *model,
34
 ValueAnnotationConfWidget::ValueAnnotationConfWidget(DeviceTreeModel *model,
35
                                                      const QModelIndex &index)
35
                                                      const QModelIndex &index)
36
 : BasicDeviceConfigurationWidget(model, index),
36
 : BasicDeviceConfigurationWidget(model, index),
37
-  model(new SaltModel(2))
37
+  tablemodel(new SaltModel(2))
38
 {
38
 {
39
 	QFormLayout *layout = new QFormLayout;
39
 	QFormLayout *layout = new QFormLayout;
40
 	QLineEdit *source = new QLineEdit;
40
 	QLineEdit *source = new QLineEdit;
42
 	QCheckBox *noteOnStart = new QCheckBox(tr("Produce Start State Annotation"));
42
 	QCheckBox *noteOnStart = new QCheckBox(tr("Produce Start State Annotation"));
43
 	noteOnStart->setChecked(true);
43
 	noteOnStart->setChecked(true);
44
 	layout->addRow(noteOnStart);
44
 	layout->addRow(noteOnStart);
45
-	model->setHeaderData(0, Qt::Horizontal, "Value");
46
-	model->setHeaderData(1, Qt::Horizontal, "Annotation");
45
+	tablemodel->setHeaderData(0, Qt::Horizontal, "Value");
46
+	tablemodel->setHeaderData(1, Qt::Horizontal, "Annotation");
47
 	QTableView *annotationTable = new QTableView;
47
 	QTableView *annotationTable = new QTableView;
48
-	annotationTable->setModel(model);
48
+	annotationTable->setModel(tablemodel);
49
 	NumericDelegate *delegate = new NumericDelegate;
49
 	NumericDelegate *delegate = new NumericDelegate;
50
 	annotationTable->setItemDelegateForColumn(0, delegate);
50
 	annotationTable->setItemDelegateForColumn(0, delegate);
51
 	layout->addRow(tr("Annotations for values:"), annotationTable);
51
 	layout->addRow(tr("Annotations for values:"), annotationTable);
52
-	@<Get device configuration data for current node@>=
52
+	@<Get device configuration data for current node@>@;
53
 	for(int i = 0; i < configData.size(); i++)
53
 	for(int i = 0; i < configData.size(); i++)
54
 	{
54
 	{
55
 		node = configData.at(i).toElement();
55
 		node = configData.at(i).toElement();
69
 		}
69
 		}
70
 		else if(node.attribute("name") == "annotations")
70
 		else if(node.attribute("name") == "annotations")
71
 		{
71
 		{
72
-			@<Convert numeric array literal to list@>@;
72
+			@<Convert string array literal to list@>@;
73
 			int column = 1;
73
 			int column = 1;
74
-			@<Populate model column from list@>@;
74
+			@<Populate model column from string list@>@;
75
 		}
75
 		}
76
 	}
76
 	}
77
 	updateSourceColumn(source->text());
77
 	updateSourceColumn(source->text());
79
 	updateAnnotations();
79
 	updateAnnotations();
80
 	connect(source, SIGNAL(textEdited(QString)), this, SLOT(updateSourceColumn(QString)));
80
 	connect(source, SIGNAL(textEdited(QString)), this, SLOT(updateSourceColumn(QString)));
81
 	connect(noteOnStart, SIGNAL(toggled(bool)), this, SLOT(updateStart(bool)));
81
 	connect(noteOnStart, SIGNAL(toggled(bool)), this, SLOT(updateStart(bool)));
82
-	connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(updateAnnotations()));
82
+	connect(tablemodel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(updateAnnotations()));
83
 	setLayout(layout);
83
 	setLayout(layout);
84
 }
84
 }
85
 
85
 
86
+@ While we can re-use code for handling numeric array literals, string array
87
+literals need to be handled a little differently.
88
+
89
+@<Convert string array literal to list@>=
90
+QString data = node.attribute("value");
91
+if(data.length() > 3)
92
+{
93
+	data.chop(2);
94
+	data = data.remove(0, 2);
95
+}
96
+QStringList itemList = data.split(",");
97
+for(int i = 0; i < itemList.size(); i++)
98
+{
99
+	itemList[i] = itemList[i].simplified();
100
+}
101
+
102
+@ Populating the model must also be done a little differently.
103
+
104
+@<Populate model column from string list@>=
105
+for(int i = 0; i < itemList.size(); i++)
106
+{
107
+	tablemodel->setData(tablemodel->index(i, column),
108
+	                    QVariant(itemList.at(i)),
109
+	                    Qt::DisplayRole);
110
+}
111
+
86
 @ To update the table data, the measued values and annotations are saved in
112
 @ To update the table data, the measued values and annotations are saved in
87
 separate lists.
113
 separate lists.
88
 
114
 
89
 @<ValueAnnotationConfWidget implementation@>=
115
 @<ValueAnnotationConfWidget implementation@>=
90
 void ValueAnnotationConfWidget::updateAnnotations()
116
 void ValueAnnotationConfWidget::updateAnnotations()
91
 {
117
 {
92
-	updateAttribute("measuredValues", model->arrayLiteral(0, Qt::DisplayRole));
93
-	updateAttribute("annotations", model->arrayLiteral(1, Qt::DisplayRole));
118
+	updateAttribute("measuredValues", tablemodel->arrayLiteral(0, Qt::DisplayRole));
119
+	updateAttribute("annotations", tablemodel->arrayLiteral(1, Qt::DisplayRole));
94
 }
120
 }
95
 
121
 
96
 @ The other settings are updated based on values passed through the parameter
122
 @ The other settings are updated based on values passed through the parameter
104
 
130
 
105
 void ValueAnnotationConfWidget::updateStart(bool noteOnStart)
131
 void ValueAnnotationConfWidget::updateStart(bool noteOnStart)
106
 {
132
 {
107
-	updateAttribute("emitOnStart", noteOnStart);
133
+	updateAttribute("emitOnStart", noteOnStart ? "true" : "false");
108
 }
134
 }
109
 
135
 
110
 @ The widget is registered with the configuration system.
136
 @ The widget is registered with the configuration system.
111
 
137
 
112
 @<Register device configuration widgets@>=
138
 @<Register device configuration widgets@>=
113
 app.registerDeviceConfigurationWidget("valueannotation",
139
 app.registerDeviceConfigurationWidget("valueannotation",
114
-	ValueAnnotationConfWidget::staticMetaObjet);
140
+	ValueAnnotationConfWidget::staticMetaObject);
141
+
142
+@ A NodeInserter is needed to make this widget available.
143
+
144
+@<Add annotation control node inserters@>=
145
+NodeInserter *valueAnnotationInserter = new NodeInserter(tr("Value Annotation"),
146
+                                                         tr("Value Annotation"),
147
+                                                         "valueannotation");
148
+annotationMenu->addAction(valueAnnotationInserter);
149
+connect(valueAnnotationInserter, SIGNAL(triggered(QString, QString)),
150
+        this, SLOT(insertChildNode(QString, QString)));
115
 
151
 
116
 @ While it is possible to implement this feature with |ThresholdDetector|
152
 @ While it is possible to implement this feature with |ThresholdDetector|
117
 objects, the code to handle these would be difficult to understand and there
153
 objects, the code to handle these would be difficult to understand and there
148
 		QList<double> values;
184
 		QList<double> values;
149
 		QStringList annotations;
185
 		QStringList annotations;
150
 		double tolerance;
186
 		double tolerance;
151
-}
187
+};
152
 
188
 
153
 @ Most of the work of this class happens in the |newMeasurement| method. This
189
 @ Most of the work of this class happens in the |newMeasurement| method. This
154
 compares the latest measurement with every value that has an associated
190
 compares the latest measurement with every value that has an associated
223
 	/* Nothing needs to be done here. */
259
 	/* Nothing needs to be done here. */
224
 }
260
 }
225
 
261
 
262
+@ This class is exposed to the host environment in the usual way. First with
263
+function prototypes.
264
+
265
+@<Function prototypes for scripting@>=
266
+QScriptValue constructValueAnnotation(QScriptContext *context, QScriptEngine *engine);
267
+void setValueAnnotationProperties(QScriptValue value, QScriptEngine *engine);
268
+
269
+@ Then setting up a new property of the global object.
270
+
271
+@<Set up the scripting engine@>=
272
+constructor = engine->newFunction(constructValueAnnotation);
273
+value = engine->newQMetaObject(&ValueAnnotation::staticMetaObject, constructor);
274
+engine->globalObject().setProperty("ValueAnnotation", value);
275
+
276
+@ The implementation of the functions also proceeds as usual.
277
+
278
+@<Functions for scripting@>=
279
+QScriptValue constructValueAnnotation(QScriptContext *context, QScriptEngine *engine)
280
+{
281
+	QScriptValue object = engine->newQObject(new ValueAnnotation);
282
+	setValueAnnotationProperties(object, engine);
283
+	return object;
284
+}
285
+
286
+void setValueAnnotationProperties(QScriptValue value, QScriptEngine *engine)
287
+{
288
+	setQObjectProperties(value, engine);
289
+}

Loading…
Cancel
Save