Browse Source

Phidget22 current channel support

Includes configuring current channels, reading current channel data, and allows some additional flexibility in numeric displays.
Neal Wilson 3 years ago
parent
commit
90aff0234c
2 changed files with 470 additions and 194 deletions
  1. 429
    58
      src/phidget22.w
  2. 41
    136
      src/typica.w

+ 429
- 58
src/phidget22.w View File

@@ -7,7 +7,7 @@ provide hardware specimen for testing that requires the new library.
7 7
 
8 8
 API differences are significant enough that it makes more sense to write new
9 9
 code for interacting with phidget22 than attempting to retrofit existing
10
-phidget21 code. By leaving both in, there is no configuration disription for
10
+phidget21 code. By leaving both in, there is no configuration disruption for
11 11
 people already using hardware previously supported and it is possible to use
12 12
 both libraries simultaneously to communicate with different hardware.
13 13
 
@@ -37,6 +37,8 @@ app.registerDeviceConfigurationWidget("phidget22",
37 37
 	PhidgetConfWidget::staticMetaObject);
38 38
 app.registerDeviceConfigurationWidget("phidgetchannel",
39 39
 	PhidgetChannelConfWidget::staticMetaObject);
40
+app.registerDeviceConfigurationWidget("phidgetcurrentchannel",
41
+	PhidgetCurrentChannelConfWidget::staticMetaObject);
40 42
 
41 43
 @ The first configuration widget just serves as a parent to all channels using
42 44
 this library. There does not seem to be a need for the configuration to mirror
@@ -50,13 +52,17 @@ class PhidgetConfWidget : public BasicDeviceConfigurationWidget
50 52
 	public:
51 53
 		Q_INVOKABLE PhidgetConfWidget(DeviceTreeModel *model,
52 54
 		                              const QModelIndex &index);
53
-	private slots:
54
-		void addChannel();
55 55
 };
56 56
 
57 57
 @ The only thing this configuration widget provides is a way to create child
58 58
 nodes.
59 59
 
60
+Originally, this only supported channels that use the TemperatureInput API.
61
+With the addition of support for other input types, the decision was made to
62
+give each channel type its own node type and configuration widget rather than
63
+attempt to cram every configuration option for all supported types into the
64
+same configuration control.
65
+
60 66
 @<Phidget implementation@>=
61 67
 PhidgetConfWidget::PhidgetConfWidget(DeviceTreeModel *model,
62 68
                                      const QModelIndex &index)
@@ -64,16 +70,24 @@ PhidgetConfWidget::PhidgetConfWidget(DeviceTreeModel *model,
64 70
 {
65 71
 	QHBoxLayout *layout = new QHBoxLayout;
66 72
 	QPushButton *addChannelButton = new QPushButton(tr("Add Channel"));
67
-	connect(addChannelButton, SIGNAL(clicked()), this, SLOT(addChannel()));
73
+	QMenu *channelTypeMenu = new QMenu;
74
+	NodeInserter *temperatureChannel =
75
+		new NodeInserter(tr("Temperature Channel"),
76
+		tr("Temperature Channel"), "phidgetchannel");
77
+	connect(temperatureChannel, SIGNAL(triggered(QString, QString)),
78
+	        this, SLOT(insertChildNode(QString, QString)));
79
+	channelTypeMenu->addAction(temperatureChannel);
80
+	NodeInserter *currentChannel =
81
+		new NodeInserter(tr("Current Channel"),
82
+		tr("Current Channel"), "phidgetcurrentchannel");
83
+	connect(currentChannel, SIGNAL(triggered(QString, QString)),
84
+	        this, SLOT(insertChildNode(QString, QString)));
85
+	channelTypeMenu->addAction(currentChannel);
86
+	addChannelButton->setMenu(channelTypeMenu);	
68 87
 	layout->addWidget(addChannelButton);
69 88
 	setLayout(layout);
70 89
 }
71 90
 
72
-void PhidgetConfWidget::addChannel()
73
-{
74
-	insertChildNode(tr("Channel"), "phidgetchannel");
75
-}
76
-
77 91
 @ For this library, \pn{} supports a broader range of hardware. This requires
78 92
 slightly more involved hardware configuration to ensure that a given channel
79 93
 configuration consistently refers to the same sensor.
@@ -85,24 +99,43 @@ thermocouple requires different configuration options than an RTD while the
85 99
 built in ambient temperature sensors on some devices do not require additional
86 100
 configuration.
87 101
 
88
-At present, only temperature sensors are supported, however this code could be
89
-extended to support other options.
90
-
91 102
 To simplify configuration, a combo box is provided which displays all of the
92 103
 currently connected channels that \pn{} supports and allows a configuration
93 104
 widget to obtain relevant channel information when the desired channel is
94 105
 selected.
95 106
 
107
+By passing an optional channel type into the constructor, this will only
108
+display channels matching the specified type. Some potentially interesting
109
+channel types incude:
110
+
111
+\medskip
112
+
113
+\settabs 4 \columns
114
+
115
+\+&2&Current Input\cr
116
+\+&5&Digital Input\cr
117
+\+&6&Digital Output\cr
118
+\+&28&Temperature Input\cr
119
+\+&29&Voltage Input\cr
120
+\+&30&Voltage Output\cr
121
+\+&38&Current Output\cr
122
+\smallskip
123
+
124
+\centerline{Table \secno: A Selection of Phidget Channel Types}
125
+
126
+\medskip
127
+
96 128
 @<Class declarations@>=
97 129
 class PhidgetChannelSelector : public QComboBox
98 130
 {
99 131
 	Q_OBJECT
100
-	public:
101
-		PhidgetChannelSelector();
132
+	public:@/
133
+		PhidgetChannelSelector(int channeltype = 0);
102 134
 		~PhidgetChannelSelector();
103 135
 		void addChannel(void *device);
104 136
 		void removeChannel(void *device);
105
-	private:
137
+	private:@/
138
+		int typefilter;
106 139
 		QLibrary driver;
107 140
 		void *manager;
108 141
 		@<Phidget22 function pointers@>@;
@@ -127,6 +160,7 @@ typedef int (CCONV *PhidgetPointerStringOut)(void *, char **);
127 160
 typedef int (CCONV *PhidgetPointerIntOut)(void *, int *);
128 161
 typedef void (CCONV *PhidgetManagerCallback)(void *, void *, void *);
129 162
 typedef void (CCONV *PhidgetValueCallback)(void *, void *, double);
163
+typedef void (CCONV *PhidgetErrorCallback)(void *, void *, int, const char *);
130 164
 typedef int (CCONV *PhidgetPointerCallbackPointer)(void *,
131 165
                                                    PhidgetManagerCallback,
132 166
                                                    void *);
@@ -134,6 +168,8 @@ typedef int (CCONV *PhidgetPointerVCPointer)(void *,
134 168
                                              PhidgetValueCallback,
135 169
                                              void *);
136 170
 typedef int (CCONV *PhidgetPointerIntIn)(void *, int);
171
+typedef int (CCONV *PhidgetPointerECPointer)(void *, PhidgetErrorCallback,
172
+                                              void *);
137 173
 
138 174
 @ These are used to define function pointers that will be used to
139 175
 communicate with the library.
@@ -177,7 +213,8 @@ if((createManager = (PhidgetPointer) driver.resolve("PhidgetManager_create")) ==
177 213
 the combo box.
178 214
 
179 215
 @<Phidget implementation@>=
180
-PhidgetChannelSelector::PhidgetChannelSelector() : QComboBox(), manager(NULL)
216
+PhidgetChannelSelector::PhidgetChannelSelector(int channeltype) :
217
+	QComboBox(), typefilter(channeltype), manager(NULL)
181 218
 {
182 219
 #if __APPLE__
183 220
 	driver.setFileName("Phidget22.framework/Phidget22");
@@ -244,14 +281,16 @@ void PhidgetChannelSelector::addChannel(void *device)
244 281
 	
245 282
 	QMap<QString,QVariant> itemData;
246 283
 	
247
-	if(channelClass == 28) // Temperature sensor
284
+	if(typefilter != 0 && channelClass == typefilter)
248 285
 	{
249 286
 		itemData.insert("serialNumber", QString("%1").arg(deviceSerialNumber));
250 287
 		itemData.insert("channel", QString("%1").arg(channel));
251 288
 		itemData.insert("class", QString("%1").arg(channelClass));
252
-		itemData.insert("subclass", QString("%1").arg(channelSubclass));
289
+		itemData.insert("subclass", 
290
+		                QString("%1").arg(channelSubclass));
253 291
 		itemData.insert("hubport", QString("%1").arg(hubPort));
254
-		addItem(QString("%1: %2").arg(deviceName).arg(channel), QVariant(itemData));
292
+		addItem(QString("%1: %2").arg(deviceName).arg(channel),
293
+		        QVariant(itemData));
255 294
 	}
256 295
 }
257 296
 
@@ -294,6 +333,11 @@ PhidgetChannelSelector::~PhidgetChannelSelector()
294 333
                                                    
295 334
 @ Channel configuration provides a |PhidgetChannelSelector| for choosing
296 335
 among connected devices but also displays the relevant configuration data.
336
+
337
+This class only deals with temperature channels as that was the only channel
338
+type originally supported. Other configuration classes should be used for
339
+other channel types to allow type specific configuration options to be
340
+presented sensibly.
297 341
                                                    
298 342
 @<Class declarations@>=
299 343
 class PhidgetChannelConfWidget : public BasicDeviceConfigurationWidget
@@ -331,7 +375,7 @@ class PhidgetChannelConfWidget : public BasicDeviceConfigurationWidget
331 375
 PhidgetChannelConfWidget::PhidgetChannelConfWidget(DeviceTreeModel *model,
332 376
                                                    const QModelIndex &index)
333 377
 	: BasicDeviceConfigurationWidget(model, index),
334
-	channelSelector(new PhidgetChannelSelector),
378
+	channelSelector(new PhidgetChannelSelector(28)),
335 379
 	serialNumber(new QLineEdit),
336 380
 	channel(new QLineEdit),
337 381
 	hubPort(new QLineEdit),
@@ -527,6 +571,188 @@ void PhidgetChannelConfWidget::updateHidden(int value)
527 571
 	updateAttribute("hidden", value == 0 ? "false" : "true");
528 572
 }
529 573
 
574
+@ The current input channel is intended for devices that can measure 4-20mA
575
+current signals. The output from such a channel is likely to be hidden and
576
+redirected to something that bring those measurements into whatever scale the
577
+signal represents. For example, the motivating hardware for this feature was a
578
+device that used 4-20mA to represent an approximation of the Agtron Gourmet
579
+Scale in the range of 25-95. Another potential use is measuring gas pressure,
580
+in which case it would be desirable to present this in terms of an appropriate
581
+pressure unit. Longer term it would be nice to add support for custom units and
582
+allow different graphing configurations for different units.
583
+
584
+@<Class declarations@>=
585
+class PhidgetCurrentChannelConfWidget : BasicDeviceConfigurationWidget
586
+{
587
+	Q_OBJECT@;
588
+	public:@/
589
+		Q_INVOKABLE PhidgetCurrentChannelConfWidget(DeviceTreeModel *model,
590
+		                                            const QModelIndex &index);
591
+	public slots:@/
592
+		void changeSelectedChannel(int index);
593
+		void updateSerialNumber(const QString &value);
594
+		void updateChannel(const QString &value);
595
+		void updateHubPort(const QString &value);
596
+		void updateColumnName(const QString &value);
597
+		void updatePowerSupply(int value);
598
+		void updateDataInterval(int value);
599
+		void updateHidden(int value);
600
+	private:@/
601
+		PhidgetChannelSelector *channelSelector;
602
+		QLineEdit *serialNumber;
603
+		QLineEdit *channel;
604
+		QLineEdit *hubPort;
605
+		QComboBox *powerSupply;
606
+};
607
+
608
+@ The constructor is responsible for setting up the interface. This is
609
+slightly simpler than the configuration for temperature inputs as instead of
610
+requiring information about RTD types and wiring or thermocouple types, a
611
+current input only requires selecting the power supply and data interval.
612
+
613
+It might be a good idea to go back to the temperature channels and allow the
614
+data interval to be set there as well instead of relying on the default
615
+sample rate.
616
+
617
+@<Phidget implementation@>=
618
+PhidgetCurrentChannelConfWidget::PhidgetCurrentChannelConfWidget(
619
+	DeviceTreeModel *model, const QModelIndex &index
620
+) :
621
+	BasicDeviceConfigurationWidget(model, index),
622
+	channelSelector(new PhidgetChannelSelector(2)),
623
+	serialNumber(new QLineEdit),
624
+	channel(new QLineEdit),
625
+	hubPort(new QLineEdit),
626
+	powerSupply(new QComboBox)
627
+{
628
+	QFormLayout *layout = new QFormLayout;
629
+	layout->addRow(tr("Channel:"), channelSelector);
630
+	QLineEdit *columnName = new QLineEdit;
631
+	layout->addRow(tr("Column Name:"), columnName);
632
+	powerSupply->addItem(tr("12V"), QVariant(2));
633
+	powerSupply->addItem(tr("24V"), QVariant(3));
634
+	layout->addRow(tr("Power Supply:"), powerSupply);
635
+	QSpinBox *dataInterval = new QSpinBox;
636
+	dataInterval->setMinimum(20);
637
+	dataInterval->setMaximum(1000);
638
+	dataInterval->setValue(250);
639
+	layout->addRow(tr("Data Interval:"), dataInterval);
640
+	QCheckBox *hidden = new QCheckBox(tr("Hide channel"));
641
+	layout->addRow(hidden);
642
+	serialNumber->setEnabled(false);
643
+	channel->setEnabled(false);
644
+	hubPort->setEnabled(false);
645
+	layout->addRow(tr("Serial Number:"), serialNumber);
646
+	layout->addRow(tr("Channel Number:"), channel);
647
+	layout->addRow(tr("Hub Port:"), hubPort);
648
+	@<Get device configuration data for current node@>@;
649
+	for(int i = 0; i < configData.size(); i++)
650
+	{
651
+		node = configData.at(i).toElement();
652
+		if(node.attribute("name") == "serialnumber")
653
+		{
654
+			serialNumber->setText(node.attribute("value"));
655
+		}
656
+		else if(node.attribute("name") == "channel")
657
+		{
658
+			channel->setText(node.attribute("value"));
659
+		}
660
+		else if(node.attribute("name") == "columnname")
661
+		{
662
+			columnName->setText(node.attribute("value"));
663
+		}
664
+		else if(node.attribute("name") == "hidden")
665
+		{
666
+			hidden->setCheckState(node.attribute("value") == "true" ?
667
+				Qt::Checked : Qt::Unchecked);
668
+		}
669
+		else if(node.attribute("name") == "powersupply")
670
+		{
671
+			powerSupply->setCurrentIndex(
672
+				powerSupply->findData(
673
+					QVariant(node.attribute("value").toInt())));
674
+		}
675
+		else if(node.attribute("name") == "datainterval")
676
+		{
677
+			dataInterval->setValue(node.attribute("value").toInt());
678
+		}
679
+	}
680
+	setLayout(layout);
681
+	updateSerialNumber(serialNumber->text());
682
+	updateChannel(channel->text());
683
+	updateColumnName(columnName->text());
684
+	updateHubPort(hubPort->text());
685
+	updateHidden(hidden->checkState());
686
+	updatePowerSupply(powerSupply->currentIndex());
687
+	updateDataInterval(dataInterval->value());
688
+	connect(channelSelector, SIGNAL(currentIndexChanged(int)),
689
+	        this, SLOT(changeSelectedChannel(int)));
690
+	connect(serialNumber, SIGNAL(textChanged(QString)),
691
+	        this, SLOT(updateSerialNumber(QString)));
692
+	connect(channel, SIGNAL(textChanged(QString)),
693
+	        this, SLOT(updateChannel(QString)));
694
+	connect(columnName, SIGNAL(textChanged(QString)),
695
+	        this, SLOT(updateColumnName(QString)));
696
+	connect(hubPort, SIGNAL(textChanged(QString)),
697
+	        this, SLOT(updateHubPort(QString)));
698
+	connect(hidden, SIGNAL(stateChanged(int)),
699
+	        this, SLOT(updateHidden(int)));
700
+	connect(powerSupply, SIGNAL(currentIndexChanged(int)),
701
+	        this, SLOT(updatePowerSupply(int)));
702
+	connect(dataInterval, SIGNAL(valueChanged(int)),
703
+	        this, SLOT(updateDataInterval(int)));
704
+}
705
+
706
+@ The combo box is responsible for setting a variety of required configuration
707
+fields with values the user has no reasonable expectation of knowing.
708
+
709
+@<Phidget implementation@>=
710
+void PhidgetCurrentChannelConfWidget::changeSelectedChannel(int index)
711
+{
712
+	QMap<QString, QVariant> data = channelSelector->itemData(index).toMap();
713
+	serialNumber->setText(data.value("serialNumber").toString());
714
+	channel->setText(data.value("channel").toString());
715
+	hubPort->setText(data.value("hubport").toString());
716
+}
717
+
718
+@ Channel configuration settings are persisted as they are updated as usual.
719
+
720
+@<Phidget implementation@>=
721
+void PhidgetCurrentChannelConfWidget::updateSerialNumber(const QString &value)
722
+{
723
+	updateAttribute("serialnumber", value);
724
+}
725
+
726
+void PhidgetCurrentChannelConfWidget::updateChannel(const QString &value)
727
+{
728
+	updateAttribute("channel", value);
729
+}
730
+
731
+void PhidgetCurrentChannelConfWidget::updateColumnName(const QString &value)
732
+{
733
+	updateAttribute("columnname", value);
734
+}
735
+
736
+void PhidgetCurrentChannelConfWidget::updateHubPort(const QString &value)
737
+{
738
+	updateAttribute("hubport", value);
739
+}
740
+
741
+void PhidgetCurrentChannelConfWidget::updateHidden(int value)
742
+{
743
+	updateAttribute("hidden", value == 0 ? "false" : "true");
744
+}
745
+
746
+void PhidgetCurrentChannelConfWidget::updatePowerSupply(int value)
747
+{
748
+	updateAttribute("powersupply", powerSupply->itemData(value).toString());
749
+}
750
+
751
+void PhidgetCurrentChannelConfWidget::updateDataInterval(int value)
752
+{
753
+	updateAttribute("datainterval", QString("%1").arg(value));
754
+}
755
+
530 756
 @ The hardware communnications code provides a single class that reads the
531 757
 saved configuration data, creates |Channel| objects for the logging view to
532 758
 connect various things to, and pushes data out on those channels. Internally,
@@ -543,11 +769,17 @@ struct PhidgetChannelData
543 769
 	QString indicatorLabel;
544 770
 	int serialNumber;
545 771
 	int channelNumber;
772
+	int majorType;
546 773
 	int channelType;
547 774
 	int hubPort;
775
+	int dataInterval;
776
+	// Set for temperature channels
548 777
 	int tcType;
549 778
 	int rtdType;
550 779
 	int wiring;
780
+	// Set for current channels
781
+	int powerSupply;
782
+	// Non-specialized
551 783
 	bool hidden;
552 784
 	void *device;
553 785
 };
@@ -567,6 +799,7 @@ class Phidget22 : public QObject
567 799
 		Q_INVOKABLE bool isChannelHidden(int channel);
568 800
 		Q_INVOKABLE QString channelColumnName(int channel);
569 801
 		Q_INVOKABLE QString channelIndicatorText(int channel);
802
+		Q_INVOKABLE QString channelType(int channel);
570 803
 	public slots:
571 804
 		void start();
572 805
 		void stop();
@@ -574,16 +807,21 @@ class Phidget22 : public QObject
574 807
 		QList<PhidgetChannelData *> channelConfiguration;
575 808
 		QLibrary driver;
576 809
 		PhidgetPointer p_createTemperatureSensor;
810
+		PhidgetPointer p_createCurrentSensor;
577 811
 		PhidgetPointerIntIn p_setSerialNumber;
578 812
 		PhidgetPointerIntIn p_setChannelNumber;
579 813
 		PhidgetPointerIntIn p_setHubPort;
580 814
 		PhidgetPointerIntIn p_setTCType;
581 815
 		PhidgetPointerIntIn p_setRTDType;
582 816
 		PhidgetPointerIntIn p_setRTDWiring;
817
+		PhidgetPointerIntIn p_setCurrentPowerSupply;
818
+		PhidgetPointerIntIn p_setCurrentDataInterval;
583 819
 		PhidgetPointerVCPointer p_setNewDataCallback;
820
+		PhidgetPointerVCPointer p_setCurrentNewDataCallback;
584 821
 		PhidgetPointerIntIn p_open;
585 822
 		PhidgetPointer p_close;
586 823
 		PhidgetPointer p_delete;
824
+		PhidgetPointerECPointer p_setOnErrorCallback;
587 825
 };
588 826
 
589 827
 @ The constructor reads the previously saved hardware configuration data and
@@ -612,6 +850,17 @@ Phidget22::Phidget22(const QModelIndex &index) : QObject(NULL)
612 850
 				model->data(channelIndex, Qt::DisplayRole).toString();
613 851
 			c->device = NULL;
614 852
 			c->hubPort = -1;
853
+			c->dataInterval = -1;
854
+			c->powerSupply = -1;
855
+			if(channelReferenceElement.attribute("driver") == "phidgetchannel")
856
+			{
857
+				c->majorType = 28; // Temperature Input
858
+			}
859
+			else if(channelReferenceElement.attribute("driver") ==
860
+			        "phidgetcurrentchannel")
861
+			{
862
+				c->majorType = 2; // Current Input
863
+			}
615 864
 			for(int j = 0; j < channelConfigData.size(); j++)
616 865
 			{
617 866
 				QDomElement node = channelConfigData.at(j).toElement();
@@ -639,6 +888,14 @@ Phidget22::Phidget22(const QModelIndex &index) : QObject(NULL)
639 888
 				{
640 889
 					c->wiring = node.attribute("value").toInt();
641 890
 				}
891
+				else if(node.attribute("name") == "powersupply")
892
+				{
893
+					c->powerSupply = node.attribute("value").toInt();
894
+				}
895
+				else if(node.attribute("name") == "datainterval")
896
+				{
897
+					c->dataInterval = node.attribute("value").toInt();
898
+				}
642 899
 				else if(node.attribute("name") == "hidden")
643 900
 				{
644 901
 					c->hidden = (node.attribute("value") == "true");
@@ -690,66 +947,131 @@ QString Phidget22::channelIndicatorText(int channel)
690 947
 	return channelConfiguration.at(channel)->indicatorLabel;
691 948
 }
692 949
 
950
+QString Phidget22::channelType(int channel)
951
+{
952
+	return (channelConfiguration.at(channel)->majorType == 28 ? "T" : "C");
953
+}
954
+
693 955
 @ Once the hardware configuration has been read and the UI has been set up, we
694 956
 can start talking to the hardware and start getting measurements.
695 957
 
958
+Now that multiple channel types are supported which each require slightly
959
+different initialization procedures, it would be nice to see if channel
960
+initialization can be reordered to avoid repeatedly checking the channel type
961
+without duplicating code. Alternately, shared features could be separated into
962
+their own chunks.
963
+
696 964
 @<Phidget implementation@>=
697 965
 void Phidget22::start()
698 966
 {
699
-#if __APPLE__
700
-	driver.setFileName("Phidget22.framework/Phidget22");
701
-#else
702
-	driver.setFileName("phidget22");
703
-#endif
704
-	if(!driver.load())
705
-	{
706
-		QMessageBox::critical(NULL, tr("Typica: Driver not found"),
707
-		                      tr("Failed to find phidget22. Please install it."));
708
-		return;
709
-	}
710
-	if((p_createTemperatureSensor = (PhidgetPointer)driver.resolve("PhidgetTemperatureSensor_create")) == 0 ||
711
-		(p_setSerialNumber = (PhidgetPointerIntIn)driver.resolve("Phidget_setDeviceSerialNumber")) == 0 ||
712
-		(p_setChannelNumber = (PhidgetPointerIntIn)driver.resolve("Phidget_setChannel")) == 0 ||
713
-		(p_setTCType = (PhidgetPointerIntIn)driver.resolve("PhidgetTemperatureSensor_setThermocoupleType")) == 0 ||
714
-		(p_setRTDType = (PhidgetPointerIntIn)driver.resolve("PhidgetTemperatureSensor_setRTDType")) == 0 ||
715
-		(p_setRTDWiring = (PhidgetPointerIntIn)driver.resolve("PhidgetTemperatureSensor_setRTDWireSetup")) == 0 ||
716
-		(p_setNewDataCallback = (PhidgetPointerVCPointer)driver.resolve("PhidgetTemperatureSensor_setOnTemperatureChangeHandler")) == 0 ||
717
-		(p_open = (PhidgetPointerIntIn)driver.resolve("Phidget_openWaitForAttachment")) == 0 ||
718
-		(p_close = (PhidgetPointer)driver.resolve("Phidget_close")) == 0 ||
719
-		(p_delete = (PhidgetPointer)driver.resolve("PhidgetTemperatureSensor_delete")) == 0 ||
720
-		(p_setHubPort = (PhidgetPointerIntIn)driver.resolve("Phidget_setHubPort")) == 0)
721
-	{
722
-		QMessageBox::critical(NULL, tr("Typica: Link error"),
723
-		                      tr("Failed to link a required symbol in phidget22."));
724
-		return;
725
-	}
967
+	@<Load Phidget22 library@>@;
968
+	@<Resolve Phidget22 function pointers@>@;
969
+	
726 970
 	for(int i = 0; i < channelConfiguration.length(); i++)
727 971
 	{
728 972
 		PhidgetChannelData *c = channelConfiguration.at(i);
729
-		p_createTemperatureSensor(&(c->device));
730
-		p_setSerialNumber(c->device, c->serialNumber);
731
-		p_setChannelNumber(c->device, c->channelNumber);
732
-		switch(c->channelType)
973
+		switch(c->majorType)
733 974
 		{
734
-			case 32:
735
-				p_setRTDType(c->device, c->rtdType);
736
-				p_setRTDWiring(c->device, c->wiring);
975
+			case 2:
976
+				p_createCurrentSensor(&(c->device));
977
+				p_setOnErrorCallback(c->device,
978
+				                     Phidget22CurrentErrorCallback,
979
+									 c->channel);
737 980
 				break;
738
-			case 33:
739
-				p_setTCType(c->device, c->tcType);
981
+			case 28:
982
+				p_createTemperatureSensor(&(c->device));
740 983
 				break;
741 984
 			default:
742 985
 				break;
743 986
 		}
987
+		p_setSerialNumber(c->device, c->serialNumber);
988
+		p_setChannelNumber(c->device, c->channelNumber);
989
+		if(c->majorType == 28) //Set up temperature channel
990
+		{
991
+			switch(c->channelType)
992
+			{
993
+				case 32:
994
+					p_setRTDType(c->device, c->rtdType);
995
+					p_setRTDWiring(c->device, c->wiring);
996
+					break;
997
+				case 33:
998
+					p_setTCType(c->device, c->tcType);
999
+					break;
1000
+				default:
1001
+					break;
1002
+			}
1003
+		}
744 1004
 		if(c->hubPort >= 0)
745 1005
 		{
746 1006
 			p_setHubPort(c->device, c->hubPort);
747 1007
 		}
748
-		p_setNewDataCallback(c->device, Phidget22ValueCallback, c->channel);
1008
+		switch(c->majorType)
1009
+		{
1010
+			case 2:
1011
+				p_setCurrentNewDataCallback(c->device,
1012
+				                            Phidget22CurrentValueCallback,
1013
+				                            c->channel);
1014
+				break;
1015
+			case 28:
1016
+				p_setNewDataCallback(c->device, Phidget22ValueCallback, c->channel);
1017
+				break;
1018
+			default:
1019
+				break;
1020
+		}
749 1021
 		p_open(c->device, 5000);
1022
+		/* The data interval must be set after opening the channel, otherwise
1023
+		   the change has no effect. */
1024
+		if(c->majorType == 2)
1025
+		{
1026
+			p_setCurrentPowerSupply(c->device, c->powerSupply);
1027
+			p_setCurrentDataInterval(c->device, c->dataInterval);
1028
+		}
750 1029
 	}
751 1030
 }
752 1031
 
1032
+@ The library we need is slightly different depending on the current platform.
1033
+If the library is not installed, an error is displayed.
1034
+
1035
+@<Load Phidget22 library@>=
1036
+#if __APPLE__
1037
+	driver.setFileName("Phidget22.framework/Phidget22");
1038
+#else
1039
+	driver.setFileName("phidget22");
1040
+#endif
1041
+if(!driver.load())
1042
+{
1043
+	QMessageBox::critical(NULL, tr("Typica: Driver not found"),
1044
+	                      tr("Failed to find phidget22. Please install it."));
1045
+	return;
1046
+}
1047
+
1048
+@ Several function pointers are required to call into the library. If any of
1049
+these fail to resolve, the most likely cause is that an incompatible library
1050
+with the same name has been installed.
1051
+
1052
+@<Resolve Phidget22 function pointers@>=
1053
+if((p_createTemperatureSensor = (PhidgetPointer)driver.resolve("PhidgetTemperatureSensor_create")) == 0 ||
1054
+	(p_createCurrentSensor = (PhidgetPointer)driver.resolve("PhidgetCurrentInput_create")) == 0 ||
1055
+	(p_setSerialNumber = (PhidgetPointerIntIn)driver.resolve("Phidget_setDeviceSerialNumber")) == 0 ||
1056
+	(p_setChannelNumber = (PhidgetPointerIntIn)driver.resolve("Phidget_setChannel")) == 0 ||
1057
+	(p_setTCType = (PhidgetPointerIntIn)driver.resolve("PhidgetTemperatureSensor_setThermocoupleType")) == 0 ||
1058
+	(p_setRTDType = (PhidgetPointerIntIn)driver.resolve("PhidgetTemperatureSensor_setRTDType")) == 0 ||
1059
+	(p_setRTDWiring = (PhidgetPointerIntIn)driver.resolve("PhidgetTemperatureSensor_setRTDWireSetup")) == 0 ||
1060
+	(p_setCurrentPowerSupply = (PhidgetPointerIntIn)driver.resolve("PhidgetCurrentInput_setPowerSupply")) == 0 ||
1061
+	(p_setCurrentDataInterval = (PhidgetPointerIntIn)driver.resolve("PhidgetCurrentInput_setDataInterval")) == 0 ||
1062
+	(p_setNewDataCallback = (PhidgetPointerVCPointer)driver.resolve("PhidgetTemperatureSensor_setOnTemperatureChangeHandler")) == 0 ||
1063
+	(p_setCurrentNewDataCallback = (PhidgetPointerVCPointer)driver.resolve("PhidgetCurrentInput_setOnCurrentChangeHandler")) == 0 ||
1064
+	(p_open = (PhidgetPointerIntIn)driver.resolve("Phidget_openWaitForAttachment")) == 0 ||
1065
+	(p_close = (PhidgetPointer)driver.resolve("Phidget_close")) == 0 ||
1066
+	(p_delete = (PhidgetPointer)driver.resolve("PhidgetTemperatureSensor_delete")) == 0 ||
1067
+	(p_setHubPort = (PhidgetPointerIntIn)driver.resolve("Phidget_setHubPort")) == 0 ||
1068
+	(p_setOnErrorCallback = (PhidgetPointerECPointer)driver.resolve("Phidget_setOnErrorHandler")) == 0)
1069
+{
1070
+	QMessageBox::critical(NULL, tr("Typica: Link error"),
1071
+	                      tr("Failed to link a required symbol in phidget22."));
1072
+	return;
1073
+}
1074
+
753 1075
 @ New values are delivered to a callback function outside of the class, but
754 1076
 with a pointer to the relevant |Channel| object. This means that all the
755 1077
 callback needs to do is perform the unit conversion, assemble the |Measurement|
@@ -759,6 +1081,19 @@ Unfortunately, there can be no guarantee that new measurements will be
759 1081
 available on all channels simultaneously. Hopefully this will not be too
760 1082
 problematic.
761 1083
 
1084
+Temperature values and current values are handled separately with the
1085
+former requiring a conversion into Fahrenheit and the latter providing a
1086
+conversion into mA as the most common use is expected to be reading from
1087
+4-20mA sensors. Additional input types might require their own callbacks. For
1088
+example, a voltage input callback might not perform any conversion.
1089
+
1090
+For current channels, the initial use case potentially uses the entire 0-20mA
1091
+range, which can result in errors being generated instead of measurements. Out
1092
+of range and saturation errors should be converted to 0 and 20 respectively.
1093
+This may be the wrong call if someone wants to use a larger range current
1094
+sensor such as 30A, but until someone provides a concrete use case I'm not
1095
+going to worry about that.
1096
+
762 1097
 @<Additional functions@>=
763 1098
 void CCONV Phidget22ValueCallback(void *, void *context, double value)
764 1099
 {
@@ -768,10 +1103,46 @@ void CCONV Phidget22ValueCallback(void *, void *context, double value)
768 1103
 	channel->input(measure);
769 1104
 }
770 1105
 
771
-@ A function prototype is provided.
1106
+void CCONV Phidget22CurrentValueCallback(void *, void *context, double value)
1107
+{
1108
+	Channel *channel = (Channel*)context;
1109
+	QTime time = QTime::currentTime();
1110
+	Measurement measure(value * 1000.0, time, Units::Unitless);
1111
+	channel->input(measure);
1112
+}
1113
+
1114
+void CCONV Phidget22CurrentErrorCallback(void *, void *context, int error,
1115
+                                         const char *)
1116
+{
1117
+	Channel *channel = (Channel*)context;
1118
+	QTime time = QTime::currentTime();
1119
+	switch(error)
1120
+	{
1121
+		case 4103: // Measurement below valid range
1122
+			{
1123
+				Measurement measure(0.0, time, Units::Unitless);
1124
+				channel->input(measure);
1125
+			}
1126
+			break;
1127
+		case 4105: // Measurement above valid range
1128
+			{
1129
+				Measurement measure(20.0, time, Units::Unitless);
1130
+				channel->input(measure);
1131
+			}
1132
+			break;
1133
+		default:
1134
+			break;
1135
+	}
1136
+}
1137
+
1138
+@ Function prototypes are provided.
772 1139
 
773 1140
 @<Additional function prototypes@>=
774 1141
 void CCONV Phidget22ValueCallback(void *device, void *context, double value);
1142
+void CCONV Phidget22CurrentValueCallback(void *device, void *context,
1143
+                                         double value);
1144
+void CCONV Phidget22CurrentErrorCallback(void *device, void *context,
1145
+                                         int error, const char *description);
775 1146
 
776 1147
 @ When the logging window is closed, it is important to close all open channels
777 1148
 and delete their handles.

+ 41
- 136
src/typica.w View File

@@ -689,12 +689,6 @@ template<> QTime getself(QScriptContext *context)
689 689
     return self;
690 690
 }
691 691
 
692
-template<> QModelIndex getself(QScriptContext *context)
693
-{
694
-    QModelIndex self = context->thisObject().toVariant().value<QModelIndex>();
695
-    return self;
696
-}
697
-
698 692
 template<> QByteArray getself(QScriptContext *context)
699 693
 {
700 694
     QByteArray self = context->thisObject().toVariant().toByteArray();
@@ -3516,19 +3510,11 @@ QScriptValue constructQTime(QScriptContext *context,
3516 3510
         {@t\1@>@/
3517 3511
             case 4:@/
3518 3512
                 arg4 = argument<int>(3, context);
3519
-                arg3 = argument<int>(2, context);
3520
-                arg2 = argument<int>(1, context);
3521
-                arg1 = argument<int>(0, context);
3522
-                break;
3523 3513
             case 3:@/
3524 3514
                 arg3 = argument<int>(2, context);
3525
-                arg2 = argument<int>(1, context);
3526
-                arg1 = argument<int>(0, context);
3527
-                break;
3528 3515
             case 2:@/
3529 3516
                 arg2 = argument<int>(1, context);
3530 3517
                 arg1 = argument<int>(0, context);
3531
-                break;
3532 3518
             default:@/
3533 3519
                 break;@t\2@>@/
3534 3520
         }
@@ -3867,15 +3853,10 @@ QScriptValue QTime_setHMS(QScriptContext *context, QScriptEngine *engine)
3867 3853
         {@t\1@>@/
3868 3854
             case 4:@/
3869 3855
                 arg4 = argument<int>(3, context);
3870
-                arg3 = argument<int>(2, context);
3871
-                arg2 = argument<int>(1, context);
3872
-                arg1 = argument<int>(0, context);
3873
-                break;
3874 3856
             case 3:@/
3875 3857
                 arg3 = argument<int>(2, context);
3876 3858
                 arg2 = argument<int>(1, context);
3877 3859
                 arg1 = argument<int>(0, context);
3878
-                break;
3879 3860
             default:@/
3880 3861
                 break;@t\2@>@/
3881 3862
         }
@@ -4695,8 +4676,6 @@ void populateWidget(QDomElement element, QStack<QWidget *> *widgetStack,@|
4695 4676
                     QStack<QLayout *> *layoutStack);
4696 4677
 void populateStackedLayout(QDomElement element, QStack<QWidget *> *widgetStack,
4697 4678
                            QStack<QLayout *> *layoutStack);
4698
-void populateFormLayout(QDomElement element, QStack<QWidget *> *widgetStack,@|
4699
-                        QStack<QLayout *> *layoutStack);
4700 4679
 void addTemperatureDisplayToSplitter(QDomElement element,@|
4701 4680
                                      QStack<QWidget *> *widgetStack,
4702 4681
                                      QStack<QLayout *> *layoutStack);
@@ -5041,12 +5020,6 @@ else if(layoutType == "stack")
5041 5020
     layoutStack->push(layout);
5042 5021
     populateStackedLayout(element, widgetStack, layoutStack);
5043 5022
 }
5044
-else if(layoutType == "form")
5045
-{
5046
-    layout = new QFormLayout;
5047
-    layoutStack->push(layout);
5048
-    populateFormLayout(element, widgetStack, layoutStack);
5049
-}
5050 5023
 if(element.hasAttribute("id"))
5051 5024
 {
5052 5025
     layout->setObjectName(element.attribute("id"));
@@ -5061,47 +5034,6 @@ if(element.hasAttribute("margin"))
5061 5034
     layout->setContentsMargins(m, m, m, m);
5062 5035
 }
5063 5036
 
5064
-@ Any direct child of a form layout must be a {\tt <row>} element to specify
5065
-the label for the given row. The field for the given row will always be a
5066
-|QVBoxLayout| containing whatever is specified by children of the {\tt <row>}.
5067
-
5068
-@<Functions for scripting@>=
5069
-void populateFormLayout(QDomElement element, QStack<QWidget *> *widgetStack,
5070
-                        QStack<QLayout *> *layoutStack)
5071
-{
5072
-    QDomNodeList children = element.childNodes();
5073
-    QFormLayout *layout = qobject_cast<QFormLayout *>(layoutStack->top());
5074
-    for(int i = 0; i < children.count(); i++)
5075
-    {
5076
-        QDomNode current;
5077
-        QDomElement currentElement;
5078
-        current = children.at(i);
5079
-        if(current.isElement())
5080
-        {
5081
-            currentElement = current.toElement();
5082
-            if(currentElement.tagName() == "row")
5083
-            {
5084
-                QString label = QString();
5085
-                if(currentElement.hasAttribute("label"))
5086
-                {
5087
-                    label = currentElement.attribute("label");
5088
-                }
5089
-                QVBoxLayout *childLayout = new QVBoxLayout;
5090
-                layoutStack->push(childLayout);
5091
-                populateBoxLayout(currentElement, widgetStack, layoutStack);
5092
-                if(label.isEmpty())
5093
-                {
5094
-                    layout->addRow(childLayout);
5095
-                }
5096
-                else
5097
-                {
5098
-                    layout->addRow(label, childLayout);
5099
-                }
5100
-            }
5101
-        }
5102
-    }
5103
-}
5104
-
5105 5037
 @ Stacked layouts are a bit different from the other types. A stacked layout has
5106 5038
 an arbitrary number of {\tt <page>} children which are just a |QWidget| which
5107 5039
 can have the same child elements as {\tt <widget>} elements elsewhere. Only the
@@ -5728,7 +5660,7 @@ is an example of such a layout.
5728 5660
 
5729 5661
 When splitters are used as a way to hide optional features it sometimes has the
5730 5662
 effect of forcing a window to stay larger than should be required. To fix this,
5731
-it is possible to set the \tt{ignoreSizePolicy} attribute to true. While this
5663
+it is possible to set the {\tt ignoreSizePolicy} attribute to true. While this
5732 5664
 does solve the window size issue, this technique is inconsistent with generally
5733 5665
 expected behavior and its use should generally be discouraged.
5734 5666
 
@@ -6051,28 +5983,6 @@ void addSaltToLayout(QDomElement element, QStack<QWidget *> *,@|
6051 5983
     {
6052 5984
         view->setObjectName(element.attribute("id"));
6053 5985
     }
6054
-    if(element.hasAttribute("editable"))
6055
-    {
6056
-        if(element.attribute("editable") == "false")
6057
-        {
6058
-            view->setEditTriggers(QAbstractItemView::NoEditTriggers);
6059
-        }
6060
-    }
6061
-    if(element.hasAttribute("selectionBehavior"))
6062
-    {
6063
-        if(element.attribute("selectionBehavior") == "items")
6064
-        {
6065
-            view->setSelectionBehavior(QAbstractItemView::SelectItems);
6066
-        }
6067
-        else if(element.attribute("selectionBehavior") == "rows")
6068
-        {
6069
-            view->setSelectionBehavior(QAbstractItemView::SelectRows);
6070
-        }
6071
-        else if(element.attribute("selectionBehavior") == "columns")
6072
-        {
6073
-            view->setSelectionBehavior(QAbstractItemView::SelectColumns);
6074
-        }
6075
-    }
6076 5986
     if(element.hasChildNodes())
6077 5987
     {
6078 5988
         QDomNodeList children = element.childNodes();
@@ -6166,13 +6076,6 @@ if(currentElement.hasAttribute("display"))
6166 6076
 {
6167 6077
     widget->setDisplayColumn(currentElement.attribute("display").toInt());
6168 6078
 }
6169
-if(currentElement.hasAttribute("editable"))
6170
-{
6171
-    if(currentElement.attribute("editable") == "true")
6172
-    {
6173
-        widget->setEditable(true);
6174
-    }
6175
-}
6176 6079
 widget->addSqlOptions(currentElement.text());
6177 6080
 delegate->setWidget(widget);
6178 6081
 view->setItemDelegateForColumn(currentColumn, delegate);
@@ -8283,12 +8186,19 @@ measured temperature.
8283 8186
 
8284 8187
 This is a specialization of |QLCDNumber|.
8285 8188
 
8189
+With the addition of 4-20mA current channels, it no longer makes sense to
8190
+restrict non-temperature measurements to whole number values. The default
8191
+behavior is kept the same to avoid breaking old configurations, however new
8192
+uses should explicitly set a desired number of decimal places for each
8193
+indicator.
8194
+
8286 8195
 @<Class declarations@>=
8287 8196
 class TemperatureDisplay : public QLCDNumber@/
8288 8197
 {@t\1@>@/
8289 8198
     Q_OBJECT@;
8290 8199
     int unit;
8291 8200
     bool r;
8201
+	int decimalPlaces;
8292 8202
     public:@/
8293 8203
         TemperatureDisplay(QWidget *parent = NULL);
8294 8204
         ~TemperatureDisplay();@/
@@ -8296,7 +8206,8 @@ class TemperatureDisplay : public QLCDNumber@/
8296 8206
         void setValue(Measurement temperature);
8297 8207
         void invalidate();
8298 8208
         void setDisplayUnits(Units::Unit scale);
8299
-        void setRelativeMode(bool relative);@t\2@>@/
8209
+        void setRelativeMode(bool relative);
8210
+		void setDecimalPlaces(int value);@t\2@>@/
8300 8211
 };
8301 8212
 
8302 8213
 @ Starting in version 1.6 this widget is also used for displaying a relative
@@ -8310,6 +8221,16 @@ void TemperatureDisplay::setRelativeMode(bool relative)
8310 8221
     r = relative;
8311 8222
 }
8312 8223
 
8224
+@ Starting in version 1.10 it is possible to override the default number of
8225
+decimal places for different units on a per indicator basis. This allows more
8226
+sensible handling of raw non-temperature measurements.
8227
+
8228
+@<TemperatureDisplay Implementation@>=
8229
+void TemperatureDisplay::setDecimalPlaces(int value)
8230
+{
8231
+	decimalPlaces = value;
8232
+}
8233
+
8313 8234
 @ Displaying a temperature is a simple matter of taking the temperature
8314 8235
 component from the measurement and converting it to a string. Presently, this
8315 8236
 code assumes that the measurements are in degrees Fahrenheit. If the code
@@ -8330,15 +8251,15 @@ void TemperatureDisplay::setValue(Measurement temperature)
8330 8251
         case Units::Fahrenheit:
8331 8252
             display(QString("%1'F").
8332 8253
                 arg(number.setNum(temperature.toFahrenheit().temperature(), 'f',
8333
-                                  2)));
8254
+                                  (decimalPlaces == -1 ? 2 : decimalPlaces))));
8334 8255
             break;
8335 8256
         case Units::Celsius:
8336 8257
             if(!r) {
8337 8258
                 display(QString("%1'C").
8338 8259
                     arg(number.setNum(temperature.toCelsius().temperature(), 'f',
8339
-                                    2)));
8260
+                                    (decimalPlaces == -1 ? 2 : decimalPlaces))));
8340 8261
             } else {
8341
-                number.setNum(temperature.temperature() * (5.0/9.0), 'f', 2);
8262
+                number.setNum(temperature.temperature() * (5.0/9.0), 'f', (decimalPlaces == -1 ? 2 : decimalPlaces));
8342 8263
                 display(QString("%1'C").arg(number));
8343 8264
             }
8344 8265
             break;
@@ -8346,41 +8267,41 @@ void TemperatureDisplay::setValue(Measurement temperature)
8346 8267
             if(!r) {
8347 8268
                 display(QString("%1").
8348 8269
                     arg(number.setNum(temperature.toKelvin().temperature(), 'f',
8349
-                                    2)));
8270
+                                    (decimalPlaces == -1 ? 2 : decimalPlaces))));
8350 8271
             } else {
8351
-                number.setNum(temperature.temperature() * (5.0/9.0), 'f', 2);
8272
+                number.setNum(temperature.temperature() * (5.0/9.0), 'f', (decimalPlaces == -1 ? 2 : decimalPlaces));
8352 8273
                 display(QString("%1").arg(number));
8353 8274
             }
8354 8275
             break;
8355 8276
         case Units::Rankine:
8356 8277
             display(QString("%1'r").
8357 8278
                 arg(number.setNum(temperature.toRankine().temperature(), 'f',
8358
-                                  2)));
8279
+                                  (decimalPlaces == -1 ? 2 : decimalPlaces))));
8359 8280
             break;
8360 8281
         case Units::Unitless:
8361
-            display(QString("%1").arg(number.setNum(temperature.temperature(), 'f', 0)));
8282
+            display(QString("%1").arg(number.setNum(temperature.temperature(), 'f', (decimalPlaces == -1 ? 0 : decimalPlaces))));
8362 8283
             break;
8363 8284
         default:
8364 8285
             switch(temperature.scale())
8365 8286
             {
8366 8287
                 case Units::Fahrenheit:
8367 8288
                     display(QString("%1'F").
8368
-                        arg(number.setNum(temperature.temperature(), 'f', 2)));
8289
+                        arg(number.setNum(temperature.temperature(), 'f', (decimalPlaces == -1 ? 2 : decimalPlaces))));
8369 8290
                     break;
8370 8291
                 case Units::Celsius:
8371 8292
                     display(QString("%1'C").
8372
-                        arg(number.setNum(temperature.temperature(), 'f', 2)));
8293
+                        arg(number.setNum(temperature.temperature(), 'f', (decimalPlaces == -1 ? 2 : decimalPlaces))));
8373 8294
                     break;
8374 8295
                 case Units::Kelvin:
8375 8296
                     display(QString("%1").
8376
-                        arg(number.setNum(temperature.temperature(), 'f', 2)));
8297
+                        arg(number.setNum(temperature.temperature(), 'f', (decimalPlaces == -1 ? 2 : decimalPlaces))));
8377 8298
                     break;
8378 8299
                 case Units::Rankine:
8379 8300
                     display(QString("%1'r").
8380
-                        arg(number.setNum(temperature.temperature(), 'f', 2)));
8301
+                        arg(number.setNum(temperature.temperature(), 'f', (decimalPlaces == -1 ? 2 : decimalPlaces))));
8381 8302
                     break;
8382 8303
                 case Units::Unitless:
8383
-                    display(QString("%1").arg(number.setNum(temperature.temperature(), 'f', 0)));
8304
+                    display(QString("%1").arg(number.setNum(temperature.temperature(), 'f', (decimalPlaces == -1 ? 0 : decimalPlaces))));
8384 8305
                     break;
8385 8306
                 default:
8386 8307
 					qDebug() << "Warning: Attempting to convert a non-temperature unit to a temperature unit";
@@ -8400,9 +8321,13 @@ the usual |QLCDNumber| methods.
8400 8321
 \centerline{Figure \secno: Outline (Qt default) and Filled |QLCDNumber| Example}
8401 8322
 \medskip
8402 8323
 
8324
+The default initialization of decimalPlaces to -1 is used to preserve unit
8325
+specific defaults as seen above.
8326
+
8403 8327
 @<TemperatureDisplay Implementation@>=
8404 8328
 TemperatureDisplay::TemperatureDisplay(QWidget *parent) :
8405
-    QLCDNumber(8, parent), unit(Units::Fahrenheit), r(false)@/
8329
+    QLCDNumber(8, parent), unit(Units::Fahrenheit), r(false),
8330
+	decimalPlaces(-1)@/
8406 8331
 {
8407 8332
     setSegmentStyle(Filled);
8408 8333
     display("---.--'F");
@@ -13392,7 +13317,7 @@ class SaltModel : public QAbstractItemModel@/
13392 13317
     public:@/
13393 13318
         SaltModel(int columns);
13394 13319
         ~SaltModel();
13395
-        Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const;
13320
+        int rowCount(const QModelIndex &parent = QModelIndex()) const;
13396 13321
         int columnCount(const QModelIndex &parent = QModelIndex()) const;
13397 13322
         bool setHeaderData(int section, Qt::Orientation@, orientation,
13398 13323
                            const QVariant &value, int role = Qt::DisplayRole);
@@ -13904,7 +13829,6 @@ SqlComboBox::SqlComboBox() :
13904 13829
     specialNullText(tr("Unknown")), specialNullData(QVariant::String)
13905 13830
 {
13906 13831
     view()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
13907
-    setMinimumContentsLength(20);
13908 13832
 }
13909 13833
 
13910 13834
 SqlComboBox::~SqlComboBox()
@@ -13952,12 +13876,7 @@ QWidget* SqlComboBoxDelegate::createEditor(QWidget *parent,@|
13952 13876
                                            const QStyleOptionViewItem &,
13953 13877
                                            const QModelIndex &) const
13954 13878
 {
13955
-    SqlComboBox *retval = delegate->clone(parent);
13956
-    if(delegate->isEditable())
13957
-    {
13958
-        retval->setEditable(true);
13959
-    }
13960
-    return retval;
13879
+    return delegate->clone(parent);
13961 13880
 }
13962 13881
 
13963 13882
 @ To set the appropriate editor data, we check the value in the model and
@@ -13982,9 +13901,9 @@ void SqlComboBoxDelegate::setModelData(QWidget *editor,@|
13982 13901
                                        const QModelIndex &index) const
13983 13902
 {
13984 13903
     SqlComboBox *self = qobject_cast<SqlComboBox *>(editor);
13985
-    model->setData(index, self->currentText(), Qt::DisplayRole);
13986 13904
     model->setData(index, self->itemData(self->currentIndex(), Qt::UserRole),
13987 13905
                    Qt::UserRole);
13906
+    model->setData(index, self->currentText(), Qt::DisplayRole);
13988 13907
 }
13989 13908
 
13990 13909
 @ This is needed to play nicely with the model view architecture.
@@ -16466,13 +16385,11 @@ we declare that as a metatype.
16466 16385
 Q_DECLARE_METATYPE(QModelIndex)
16467 16386
 
16468 16387
 @ Next we need a pair of functions to convert |QModelIndex| to and from script
16469
-values. Some |QModelIndex| methods are also exposed to the host environment.
16388
+values.
16470 16389
 
16471 16390
 @<Function prototypes for scripting@>=
16472 16391
 QScriptValue QModelIndex_toScriptValue(QScriptEngine *engine, const QModelIndex &index);
16473 16392
 void QModelIndex_fromScriptValue(const QScriptValue &value, QModelIndex &index);
16474
-void setQModelIndexProperties(QScriptValue value, QScriptEngine *engine);
16475
-QScriptValue QModelIndex_row(QScriptContext *context, QScriptEngine *engine);
16476 16393
 
16477 16394
 @ These are implemented thusly.
16478 16395
 
@@ -16482,7 +16399,6 @@ QScriptValue QModelIndex_toScriptValue(QScriptEngine *engine, const QModelIndex
16482 16399
     QVariant var;
16483 16400
     var.setValue(index);
16484 16401
     QScriptValue object = engine->newVariant(var);
16485
-    setQModelIndexProperties(object, engine);
16486 16402
     return object;
16487 16403
 }
16488 16404
 
@@ -16491,17 +16407,6 @@ void QModelIndex_fromScriptValue(const QScriptValue &value, QModelIndex &index)
16491 16407
     index = value.toVariant().value<QModelIndex>();
16492 16408
 }
16493 16409
 
16494
-void setQModelIndexProperties(QScriptValue value, QScriptEngine *engine)
16495
-{
16496
-    value.setProperty("row", engine->newFunction(QModelIndex_row));
16497
-}
16498
-
16499
-QScriptValue QModelIndex_row(QScriptContext *context, QScriptEngine *engine)
16500
-{
16501
-    QModelIndex self = getself<QModelIndex>(context);
16502
-    return QScriptValue(engine, self.row());
16503
-}
16504
-
16505 16410
 @ Finally we register this with the engine.
16506 16411
 
16507 16412
 @<Set up the scripting engine@>=

Loading…
Cancel
Save