Browse Source

Merge branch 'extratimers' into release-1.6.4

Neal Wilson 9 years ago
parent
commit
32fa8fed94
2 changed files with 634 additions and 3 deletions
  1. 151
    0
      config/Windows/productionroaster.xml
  2. 483
    3
      src/typica.w

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

@@ -67,6 +67,7 @@
67 67
 		var roasterIndex = roasterlist.currentIndex;
68 68
 		var channels = new Array();
69 69
 		var annotationButtons = new Array();
70
+                var rangetimers = new Array();
70 71
 		var nidevices = new Array();
71 72
 		var dataqsdkdevices = new Array();
72 73
 		var jsdevices = new Array();
@@ -612,6 +613,151 @@
612 613
 					scale.open(3);
613 614
 					window.scales.push(scale);
614 615
 				}
616
+                                else if(driverReference.driver == "coolingtimer")
617
+                                {
618
+                                    var coolingTimer = new TimerDisplay();
619
+                                    coolingTimer.setDisplayFormat("mm:ss");
620
+                                    var decorator = new WidgetDecorator(coolingTimer, configModel.data(driverIndex, 0), 2);
621
+                                    indicatorPanel.addWidget(decorator);
622
+                                    coolingTimer.setTimerMode(1);
623
+                                    coolingTimer.setAutoReset(true);
624
+                                    var timeValue = new QTime();
625
+                                    timeValue = timeValue.fromString(driverReference.reset, "mm:ss");
626
+                                    coolingTimer.setResetValue(timeValue);
627
+                                    stop.clicked.connect(coolingTimer.startTimer);
628
+                                }
629
+                                else if(driverReference.driver == "rangetimer")
630
+                                {
631
+                                    rangetimers.push(new TimerDisplay());
632
+                                    var rangeTimer = rangetimers[rangetimers.length - 1];
633
+                                    rangeTimer.setDisplayFormat("mm:ss");
634
+                                    var decorator = new WidgetDecorator(rangeTimer, configModel.data(driverIndex, 0), 2);
635
+                                    indicatorPanel.addWidget(decorator);
636
+                                    stop.clicked.connect(rangeTimer.stopTimer);
637
+                                    start.clicked.connect(rangeTimer.reset);
638
+                                    if(driverReference.starttrigger == "batch")
639
+                                    {
640
+                                        start.clicked.connect(rangeTimer.startTimer);
641
+                                    }
642
+                                    else if(driverReference.starttrigger == "manual")
643
+                                    {
644
+                                        var startButton = new AnnotationButton(driverReference.startbuttontext);
645
+                                        startButton.clicked.connect(rangeTimer.startTimer);
646
+                                        annotationPanel.addWidget(startButton);
647
+                                        tabControls.push(button);
648
+                                    }
649
+                                    else if(driverReference.starttrigger == "value")
650
+                                    {
651
+                                        var startTrigger = new ThresholdDetector();
652
+                                        startTrigger.setThreshold(Number(driverReference.startvalue));
653
+                                        var scope = new Object;
654
+                                        scope.invoke = function() {
655
+                                            if(timer.running && !(arguments.callee.rangeTimer.running))
656
+                                            {
657
+                                                arguments.callee.rangeTimer.startTimer();
658
+                                            }
659
+                                        };
660
+                                        scope.invoke.rangeTimer = rangeTimer;
661
+                                        startTrigger.timeForValue.connect(scope.invoke);
662
+                                        for(var j = 0; j < columnNames.length; j++)
663
+                                        {
664
+                                            if(columnNames[j] == driverReference.startcolumnname)
665
+                                            {
666
+                                                channels[j].newData.connect(startTrigger.newMeasurement);
667
+                                            }
668
+                                        }
669
+                                    }
670
+                                    stop.clicked.connect(rangeTimer.stopTimer)
671
+                                    if(driverReference.stoptrigger == "manual")
672
+                                    {
673
+                                        var stopButton = new AnnotationButton(driverReference.stopbuttontext);
674
+                                        stopButton.clicked.connect(rangeTimer.stopTimer);
675
+                                        annotationPanel.addWidget(stopButton);
676
+                                        tabControls.push(button);
677
+                                    }
678
+                                    else if(driverReference.stoptrigger == "value")
679
+                                    {
680
+                                        var stopTrigger = new ThresholdDetector();
681
+                                        stopTrigger.setThreshold(Number(driverReference.stopvalue));
682
+                                        stopTrigger.timeForValue.connect(rangeTimer.stopTimer);
683
+                                        for(var j = 0; j < columnNames.length; j++)
684
+                                        {
685
+                                            if(columnNames[j] == driverReference.stopcolumnname)
686
+                                            {
687
+                                                channels[j].newData.connect(stopTrigger.newMeasurement);
688
+                                            }
689
+                                        }
690
+                                    }
691
+                                    rangeTimer.reportingName = configModel.data(driverIndex, 0);
692
+                                    rangeTimer.report = function() {
693
+                                        return "" + this.reportingName + ": " + this.value;
694
+                                    };
695
+                                }
696
+                                else if(driverReference.driver = "multirangetimer")
697
+                                {
698
+                                    var rangeTimer = new TimerDisplay();
699
+                                    rangeTimer.setDisplayFormat("mm:ss");
700
+                                    var decorator = new WidgetDecorator(rangeTimer, configModel.data(driverIndex, 0), 2);
701
+                                    indicatorPanel.addWidget(decorator);
702
+                                    var rangenames = driverReference.rangenames;
703
+                                    var endtemps = driverReference.endtemps;
704
+                                    var names = rangenames.slice(2, rangenames.length - 2).split(", ");
705
+                                    rangeTimer.rangeNames = new Array();
706
+                                    for(var j = 0; j < names.length; j++)
707
+                                    {
708
+                                        var name = names[j].slice(1, names[j].length - 1);
709
+                                        rangeTimer.rangeNames.push(name);
710
+                                    }
711
+                                    rangeTimer.rangeEnds = new Array();
712
+                                    var ends = endtemps.slice(2, endtemps.length - 2).split(", ");
713
+                                    for(var j = 0; j < ends.length; j++)
714
+                                    {
715
+                                        rangeTimer.rangeEnds.push(Number(ends[j]));
716
+                                    }
717
+                                    rangeTimer.currentRange = 0;
718
+                                    rangeTimer.results = new Array();
719
+                                    rangeTimer.trigger = new ThresholdDetector();
720
+                                    for(var j = 0; j < columnNames.length; j++)
721
+                                    {
722
+                                        if(columnNames[j] == driverReference.trigger)
723
+                                        {
724
+                                            channels[j].newData.connect(rangeTimer.trigger.newMeasurement);
725
+                                        }
726
+                                    }
727
+                                    rangeTimer.startRanges = function() {
728
+                                        arguments.callee.timer.currentRange = 0;
729
+                                        arguments.callee.timer.results.splice(0, arguments.callee.timer.results.length);
730
+                                        arguments.callee.timer.trigger.setThreshold(arguments.callee.timer.rangeEnds[0]);
731
+                                    };
732
+                                    rangeTimer.startRanges.timer = rangeTimer;
733
+                                    start.clicked.connect(rangeTimer.startTimer);
734
+                                    start.clicked.connect(rangeTimer.startRanges);
735
+                                    rangeTimer.transition = function() {
736
+                                        arguments.callee.timer.stopTimer();
737
+                                        arguments.callee.timer.results.push(arguments.callee.timer.value);
738
+                                        arguments.callee.timer.reset();
739
+                                        arguments.callee.timer.startTimer();
740
+                                        arguments.callee.timer.currentRange++;
741
+                                        if(arguments.callee.timer.currentRange <= arguments.callee.timer.rangeEnds.length)
742
+                                        {
743
+                                            arguments.callee.timer.trigger.setThreshold(arguments.callee.timer.rangeEnds[arguments.callee.timer.currentRange]);
744
+                                        }
745
+                                    };
746
+                                    rangeTimer.transition.timer = rangeTimer;
747
+                                    rangeTimer.trigger.timeForValue.connect(rangeTimer.transition);
748
+                                    stop.clicked.connect(rangeTimer.transition);
749
+                                    stop.clicked.connect(rangeTimer.stopTimer);
750
+                                    rangeTimer.report = function() {
751
+                                        var retval = "";
752
+                                        for(var j = 0; j < arguments.callee.timer.results.length; j++)
753
+                                        {
754
+                                            retval += arguments.callee.timer.rangeNames[j] + ": " + arguments.callee.timer.results[j] + "\n";
755
+                                        }
756
+                                        return retval;
757
+                                    };
758
+                                    rangeTimer.report.timer = rangeTimer;
759
+                                    rangetimers.push(rangeTimer);
760
+                                }
615 761
 			}
616 762
 		}
617 763
 		for(var i = 1; i < tabControls.length; i++)
@@ -805,6 +951,11 @@
805 951
 				log.addOutputAnnotationColumn(lc + channels.length - channelSkip);
806 952
                 var filename = log.saveTemporary();
807 953
                 currentBatchInfo.tempData = filename;
954
+                var notes = findChildObject(currentBatchInfo, 'annotation');
955
+                for(var i = 0; i < rangetimers.length; i++)
956
+                {
957
+                    notes.append(rangetimers[i].report());
958
+                }
808 959
                 currentBatchInfo.raise();
809 960
                 currentBatchInfo.activateWindow();
810 961
             }

+ 483
- 3
src/typica.w View File

@@ -4155,6 +4155,7 @@ QScriptValue setTabOrder(QScriptContext *context, QScriptEngine *)
4155 4155
     return QScriptValue();
4156 4156
 }
4157 4157
 
4158
+
4158 4159
 @** Application Configuration.
4159 4160
 
4160 4161
 \noindent While \pn{} is intended as a data logging application, the diversity
@@ -10554,6 +10555,7 @@ Q_PROPERTY(bool running READ isRunning)@/
10554 10555
 Q_PROPERTY(QTime resetValue READ resetValue WRITE setResetValue)@/
10555 10556
 Q_PROPERTY(QString displayFormat READ displayFormat WRITE setDisplayFormat)@/
10556 10557
 Q_PROPERTY(bool autoReset READ autoReset WRITE setAutoReset)@/
10558
+Q_PROPERTY(QString value READ value)@/
10557 10559
 
10558 10560
 @ A number of private variables are used to implement this class.
10559 10561
 
@@ -10673,6 +10675,8 @@ if(s > QTime(0, 0, 0))@/
10673 10675
         s = nt;
10674 10676
         emit valueChanged(s);
10675 10677
     }
10678
+} else {
10679
+    stopTimer();
10676 10680
 }
10677 10681
 
10678 10682
 @ The clock mode is the simplest case as it just needs to find out if the time
@@ -10867,6 +10871,7 @@ void TimerDisplay::updateDisplay()
10867 10871
 QScriptValue constructTimerDisplay(QScriptContext *context,
10868 10872
                                    QScriptEngine *engine);
10869 10873
 void setTimerDisplayProperties(QScriptValue value, QScriptEngine *engine);
10874
+QScriptValue TimerDisplay_setTimerMode(QScriptContext *context, QScriptEngine *engine);
10870 10875
 
10871 10876
 @ The engine must be informed of the script constructor.
10872 10877
 
@@ -10888,6 +10893,36 @@ QScriptValue constructTimerDisplay(QScriptContext *, QScriptEngine *engine)
10888 10893
 void setTimerDisplayProperties(QScriptValue value, QScriptEngine *engine)
10889 10894
 {
10890 10895
     setQLCDNumberProperties(value, engine);
10896
+    value.setProperty("setTimerMode", engine->newFunction(TimerDisplay_setTimerMode));
10897
+}
10898
+
10899
+@ A new feature in \pn{} 1.6.4 benefits from having the ability to set the
10900
+timer mode from a script. Rather than exposing the |enum| responsible for this
10901
+to the host environment, a new function is provided to allow integer based
10902
+setting.
10903
+
10904
+@<Functions for scripting@>=
10905
+QScriptValue TimerDisplay_setTimerMode(QScriptContext *context, QScriptEngine *)
10906
+{
10907
+    TimerDisplay *self = getself<TimerDisplay *>(context);
10908
+    if(self)
10909
+    {
10910
+        switch(argument<int>(0, context))
10911
+        {
10912
+            case 0:
10913
+                self->setMode(TimerDisplay::CountUp);
10914
+                break;
10915
+            case 1:
10916
+                self->setMode(TimerDisplay::CountDown);
10917
+                break;
10918
+            case 2:
10919
+                self->setMode(TimerDisplay::Clock);
10920
+                break;
10921
+            default:
10922
+                break;
10923
+        }
10924
+    }
10925
+    return QScriptValue();
10891 10926
 }
10892 10927
 
10893 10928
 
@@ -16004,6 +16039,24 @@ RoasterConfWidget::RoasterConfWidget(DeviceTreeModel *model, const QModelIndex &
16004 16039
     @<Add annotation control node inserters@>@;
16005 16040
     addAnnotationControlButton->setMenu(annotationMenu);
16006 16041
     layout->addWidget(addAnnotationControlButton);
16042
+    
16043
+    QPushButton *timersButton = new QPushButton(tr("Extra Timers"));
16044
+    QMenu *timersMenu = new QMenu;
16045
+    NodeInserter *coolingTimerInserter = new NodeInserter(tr("Cooling Timer"), tr("Cooling Timer"), "coolingtimer");
16046
+    NodeInserter *rangeTimerInserter = new NodeInserter(tr("Range Timer"), tr("Range Timer"), "rangetimer");
16047
+    NodeInserter *multirangeTimerInserter = new NodeInserter(tr("Multi-Range Timer"), tr("Multi-Range Timer"), "multirangetimer");
16048
+    timersMenu->addAction(coolingTimerInserter);
16049
+    timersMenu->addAction(rangeTimerInserter);
16050
+    timersMenu->addAction(multirangeTimerInserter);
16051
+    connect(coolingTimerInserter, SIGNAL(triggered(QString, QString)),
16052
+            this, SLOT(insertChildNode(QString, QString)));
16053
+    connect(rangeTimerInserter, SIGNAL(triggered(QString, QString)),
16054
+            this, SLOT(insertChildNode(QString, QString)));
16055
+    connect(multirangeTimerInserter, SIGNAL(triggered(QString, QString)),
16056
+            this, SLOT(insertChildNode(QString, QString)));
16057
+    timersButton->setMenu(timersMenu);
16058
+    layout->addWidget(timersButton);
16059
+    
16007 16060
     QPushButton *advancedButton = new QPushButton(tr("Advanced Features"));
16008 16061
     QMenu *advancedMenu = new QMenu;
16009 16062
     NodeInserter *linearsplineinserter = new NodeInserter(tr("Linear Spline Interpolated Series"), tr("Linear Spline Interpolated Series"), "linearspline");
@@ -16015,6 +16068,7 @@ RoasterConfWidget::RoasterConfWidget(DeviceTreeModel *model, const QModelIndex &
16015 16068
     @<Add node inserters to advanced features menu@>@;
16016 16069
     advancedButton->setMenu(advancedMenu);
16017 16070
     layout->addWidget(advancedButton);
16071
+    
16018 16072
     QHBoxLayout *idLayout = new QHBoxLayout;
16019 16073
     QLabel *idLabel = new QLabel(tr("Machine ID for database:"));
16020 16074
     idLayout->addWidget(idLabel);
@@ -19123,10 +19177,10 @@ QStringList itemList = data.split(",");
19123 19177
 model.
19124 19178
 
19125 19179
 @<Populate model column from list@>=
19126
-for(int i = 0; i < itemList.size(); i++)
19180
+for(int j = 0; j < itemList.size(); j++)
19127 19181
 {
19128
-    tablemodel->setData(tablemodel->index(i, column),
19129
-                   QVariant(itemList.at(i).toDouble()),
19182
+    tablemodel->setData(tablemodel->index(j, column),
19183
+                   QVariant(itemList.at(j).toDouble()),
19130 19184
                    Qt::DisplayRole);
19131 19185
 }
19132 19186
 
@@ -19155,6 +19209,432 @@ void LinearSplineInterpolationConfWidget::updateDestinationColumn(const QString
19155 19209
 @<Register device configuration widgets@>=
19156 19210
 app.registerDeviceConfigurationWidget("linearspline", LinearSplineInterpolationConfWidget::staticMetaObject);
19157 19211
 
19212
+@* Additional Timers.
19213
+
19214
+\noindent \pn{} 1.6.4 adds support for more timer indicators than just the
19215
+default batch timer. Three new timer types are supported. The first is a
19216
+cooling timer. This is a timer that is initially set to 0, but at the end of a
19217
+batch this is set to a configured time and starts counting down. There are no
19218
+data logging requirements and this is purely a convenience feature, but one
19219
+that supports product and personnel safety best practices as it helps to
19220
+eliminate the practice of a person reaching into the cooling tray as it
19221
+agitates to test if the coffee has cooled.
19222
+
19223
+@<Class declarations@>=
19224
+class CoolingTimerConfWidget : public BasicDeviceConfigurationWidget
19225
+{
19226
+    @[Q_OBJECT@]@/
19227
+    public:@/
19228
+        @[Q_INVOKABLE@]@, CoolingTimerConfWidget(DeviceTreeModel *model,
19229
+                                                 const QModelIndex &index);
19230
+    @[private slots@]:@/
19231
+        void updateResetTime(QTime time);
19232
+};
19233
+
19234
+@ The only configurable detail is the vaue the timer should reset to. For this
19235
+a |QTimeEdit| is fine.
19236
+
19237
+@<CoolingTimerConfWidget implementation@>=
19238
+CoolingTimerConfWidget::CoolingTimerConfWidget(DeviceTreeModel *model,
19239
+                                               const QModelIndex &index)
19240
+: BasicDeviceConfigurationWidget(model, index)
19241
+{
19242
+    QHBoxLayout *layout = new QHBoxLayout;
19243
+    QLabel *label = new QLabel(tr("Cooling Time: "));
19244
+    QTimeEdit *editor = new QTimeEdit;
19245
+    editor->setDisplayFormat("mm:ss");
19246
+    @<Get device configuration data for current node@>@;
19247
+    for(int i = 0; i < configData.size(); i++)
19248
+    {
19249
+        node = configData.at(i).toElement();
19250
+        if(node.attribute("name") == "reset")
19251
+        {
19252
+            editor->setTime(QTime::fromString(node.attribute("value"), "mm:ss"));
19253
+        }
19254
+    }
19255
+    updateResetTime(editor->time());
19256
+    connect(editor, SIGNAL(timeChanged(QTime)),
19257
+            this, SLOT(updateResetTime(QTime)));
19258
+    layout->addWidget(label);
19259
+    layout->addWidget(editor);
19260
+    setLayout(layout);
19261
+}
19262
+
19263
+void CoolingTimerConfWidget::updateResetTime(QTime time)
19264
+{
19265
+    updateAttribute("reset", time.toString("mm:ss"));
19266
+}
19267
+
19268
+@ The widget is registered with the configuration system.
19269
+@<Register device configuration widgets@>=
19270
+app.registerDeviceConfigurationWidget("coolingtimer",
19271
+CoolingTimerConfWidget::staticMetaObject);
19272
+
19273
+@ The implementation chunk for now is in the main source file.
19274
+
19275
+@<Class implementations@>=
19276
+@<CoolingTimerConfWidget implementation@>
19277
+
19278
+@ The other two timer types are intended for measuring ranges of interest
19279
+within a batch. These have more configuration options. First is the range
19280
+timer. Someone setting this up needs to decide how the timer is started.
19281
+Sensible options include starting the timer at the start of the batch,
19282
+starting the timer when a button is pressed, or starting the timer when a set
19283
+point is reached on the ascent of a named data series. Stopping the timer is
19284
+also a configurable concern. This will be stopped at the end of the batch,
19285
+but it might be stopped sooner on reaching some threshold or when a button is
19286
+pressed. There are also questions of how the information is persisted with the
19287
+roasting records.
19288
+
19289
+@<Class declarations@>=
19290
+class RangeTimerConfWidget : public BasicDeviceConfigurationWidget
19291
+{
19292
+    @[Q_OBJECT@]@;
19293
+    public:@/
19294
+        @[Q_INVOKABLE@]@, RangeTimerConfWidget(DeviceTreeModel *model, const QModelIndex &index);
19295
+    @[private slots@]:@/
19296
+        void updateStartButtonText(const QString &text);
19297
+        void updateStopButtonText(const QString &text);
19298
+        void updateStartColumnName(const QString &text);
19299
+        void updateStopColumnName(const QString &text);
19300
+        void updateStartValue(const QString &text);
19301
+        void updateStopValue(const QString &text);
19302
+        void updateStartTrigger(int option);
19303
+        void updateStopTrigger(int option);
19304
+};
19305
+
19306
+@ The constructor sets up controls for configuring these details.
19307
+
19308
+@<RangeTimerConfWidget implementation@>=
19309
+RangeTimerConfWidget::RangeTimerConfWidget(DeviceTreeModel *model, const QModelIndex &index)
19310
+: BasicDeviceConfigurationWidget(model, index)
19311
+{
19312
+    QVBoxLayout *layout = new QVBoxLayout;
19313
+    
19314
+    QGroupBox *startConfigurationGroup = new QGroupBox(tr("Start trigger"));
19315
+    QRadioButton *startBatchOption = new QRadioButton(tr("Start of batch"));
19316
+    QRadioButton *buttonOption = new QRadioButton(tr("Manual"));
19317
+    QRadioButton *thresholdOption = new QRadioButton(tr("At temperature"));
19318
+    QButtonGroup *startOptionGroup = new QButtonGroup;
19319
+    startOptionGroup->addButton(startBatchOption, 1);
19320
+    startOptionGroup->addButton(buttonOption, 2);
19321
+    startOptionGroup->addButton(thresholdOption, 3);
19322
+    startBatchOption->setChecked(true);
19323
+    QGridLayout *startOptions = new QGridLayout;
19324
+    startOptions->addWidget(startBatchOption, 0, 0);
19325
+    startOptions->addWidget(buttonOption, 1, 0);
19326
+    startOptions->addWidget(thresholdOption, 2, 0);
19327
+    QLabel *buttonTextLabel = new QLabel(tr("Button Text: "));
19328
+    QLineEdit *buttonTextEdit = new QLineEdit;
19329
+    QHBoxLayout *buttonTextOptions = new QHBoxLayout;
19330
+    buttonTextOptions->addWidget(buttonTextLabel);
19331
+    buttonTextOptions->addWidget(buttonTextEdit);
19332
+    startOptions->addLayout(buttonTextOptions, 1, 1);
19333
+    QFormLayout *thresholdOptions = new QFormLayout;
19334
+    QLineEdit *startColumnName = new QLineEdit;
19335
+    QLineEdit *startValue = new QLineEdit;
19336
+    thresholdOptions->addRow(tr("Column Name: "), startColumnName);
19337
+    thresholdOptions->addRow(tr("Value: "), startValue);
19338
+    startOptions->addLayout(thresholdOptions, 2, 1);
19339
+    startConfigurationGroup->setLayout(startOptions);
19340
+    layout->addWidget(startConfigurationGroup);
19341
+    
19342
+    QGroupBox *stopConfigurationGroup = new QGroupBox(tr("Stop trigger"));
19343
+    QRadioButton *stopBatchOption = new QRadioButton(tr("End of batch"));
19344
+    QRadioButton *stopButtonOption = new QRadioButton(tr("Manual"));
19345
+    QRadioButton *stopThresholdOption = new QRadioButton(tr("At temperature"));
19346
+    QButtonGroup *stopOptionGroup = new QButtonGroup;
19347
+    stopOptionGroup->addButton(stopBatchOption, 1);
19348
+    stopOptionGroup->addButton(stopButtonOption, 2);
19349
+    stopOptionGroup->addButton(stopThresholdOption, 3);
19350
+    stopBatchOption->setChecked(true);
19351
+    QGridLayout *stopOptions = new QGridLayout;
19352
+    stopOptions->addWidget(stopBatchOption, 0, 0);
19353
+    stopOptions->addWidget(stopButtonOption, 1, 0);
19354
+    stopOptions->addWidget(stopThresholdOption, 2, 0);
19355
+    QLabel *stopButtonLabel = new QLabel(tr("Button Text: "));
19356
+    QLineEdit *stopButtonEdit = new QLineEdit;
19357
+    QHBoxLayout *stopButtonTextOptions = new QHBoxLayout;
19358
+    stopButtonTextOptions->addWidget(stopButtonLabel);
19359
+    stopButtonTextOptions->addWidget(stopButtonEdit);
19360
+    stopOptions->addLayout(stopButtonTextOptions, 1, 1);
19361
+    QLineEdit *stopColumnName = new QLineEdit;
19362
+    QLineEdit *stopValue = new QLineEdit;
19363
+    QFormLayout *stopThresholdOptions = new QFormLayout;
19364
+    stopThresholdOptions->addRow(tr("Column Name: "), stopColumnName);
19365
+    stopThresholdOptions->addRow(tr("Value: "), stopValue);
19366
+    stopOptions->addLayout(stopThresholdOptions, 2, 1);
19367
+    stopConfigurationGroup->setLayout(stopOptions);
19368
+    layout->addWidget(stopConfigurationGroup);
19369
+    
19370
+    @<Get device configuration data for current node@>@;
19371
+    for(int i = 0; i < configData.size(); i++)
19372
+    {
19373
+        node = configData.at(i).toElement();
19374
+        if(node.attribute("name") == "startbuttontext")
19375
+        {
19376
+            buttonTextEdit->setText(node.attribute("value"));
19377
+        }
19378
+        else if(node.attribute("name") == "stopbuttontext")
19379
+        {
19380
+            stopButtonEdit->setText(node.attribute("value"));
19381
+        }
19382
+        else if(node.attribute("name") == "startcolumnname")
19383
+        {
19384
+            startColumnName->setText(node.attribute("value"));
19385
+        }
19386
+        else if(node.attribute("name") == "stopcolumnname")
19387
+        {
19388
+            stopColumnName->setText(node.attribute("value"));
19389
+        }
19390
+        else if(node.attribute("name") == "startvalue")
19391
+        {
19392
+            startValue->setText(node.attribute("value"));
19393
+        }
19394
+        else if(node.attribute("name") == "stopvalue")
19395
+        {
19396
+            stopValue->setText(node.attribute("value"));
19397
+        }
19398
+        else if(node.attribute("name") == "starttrigger")
19399
+        {
19400
+            if(node.attribute("value") == "batch")
19401
+            {
19402
+                startBatchOption->setChecked(true);
19403
+            }
19404
+            else if(node.attribute("value") == "manual")
19405
+            {
19406
+                buttonOption->setChecked(true);
19407
+            }
19408
+            else if(node.attribute("value") == "value")
19409
+            {
19410
+                thresholdOption->setChecked(true);
19411
+            }
19412
+        }
19413
+        else if(node.attribute("name") == "stoptrigger")
19414
+        {
19415
+            if(node.attribute("value") == "batch")
19416
+            {
19417
+                stopBatchOption->setChecked(true);
19418
+            }
19419
+            else if(node.attribute("value") == "manual")
19420
+            {
19421
+                stopButtonOption->setChecked(true);
19422
+            }
19423
+            else if(node.attribute("value") == "value")
19424
+            {
19425
+                stopThresholdOption->setChecked(true);
19426
+            }
19427
+        }
19428
+    }
19429
+    updateStartButtonText(buttonTextEdit->text());
19430
+    updateStopButtonText(stopButtonEdit->text());
19431
+    updateStartColumnName(startColumnName->text());
19432
+    updateStopColumnName(stopColumnName->text());
19433
+    updateStartValue(startValue->text());
19434
+    updateStopValue(stopValue->text());
19435
+    updateStartTrigger(startOptionGroup->checkedId());
19436
+    updateStopTrigger(stopOptionGroup->checkedId());
19437
+    
19438
+    setLayout(layout);
19439
+    
19440
+    connect(buttonTextEdit, SIGNAL(textChanged(QString)),
19441
+            this, SLOT(updateStartButtonText(QString)));
19442
+    connect(stopButtonEdit, SIGNAL(textChanged(QString)),
19443
+            this, SLOT(updateStopButtonText(QString)));
19444
+    connect(startColumnName, SIGNAL(textChanged(QString)),
19445
+            this, SLOT(updateStartColumnName(QString)));
19446
+    connect(stopColumnName, SIGNAL(textChanged(QString)),
19447
+            this, SLOT(updateStopColumnName(QString)));
19448
+    connect(startValue, SIGNAL(textChanged(QString)),
19449
+            this, SLOT(updateStartValue(QString)));
19450
+    connect(stopValue, SIGNAL(textChanged(QString)),
19451
+            this, SLOT(updateStopValue(QString)));
19452
+    connect(startOptionGroup, SIGNAL(buttonClicked(int)),
19453
+            this, SLOT(updateStartTrigger(int)));
19454
+    connect(stopOptionGroup, SIGNAL(buttonClicked(int)),
19455
+            this, SLOT(updateStopTrigger(int)));
19456
+}
19457
+
19458
+@ Small methods update the configuration as usual.
19459
+
19460
+@<RangeTimerConfWidget implementation@>=
19461
+void RangeTimerConfWidget::updateStartButtonText(const QString &text)
19462
+{
19463
+    updateAttribute("startbuttontext", text);
19464
+}
19465
+
19466
+void RangeTimerConfWidget::updateStopButtonText(const QString &text)
19467
+{
19468
+    updateAttribute("stopbuttontext", text);
19469
+}
19470
+
19471
+void RangeTimerConfWidget::updateStartColumnName(const QString &text)
19472
+{
19473
+    updateAttribute("startcolumnname", text);
19474
+}
19475
+
19476
+void RangeTimerConfWidget::updateStopColumnName(const QString &text)
19477
+{
19478
+    updateAttribute("stopcolumnname", text);
19479
+}
19480
+
19481
+void RangeTimerConfWidget::updateStartValue(const QString &text)
19482
+{
19483
+    updateAttribute("startvalue", text);
19484
+}
19485
+
19486
+void RangeTimerConfWidget::updateStopValue(const QString &text)
19487
+{
19488
+    updateAttribute("stopvalue", text);
19489
+}
19490
+
19491
+void RangeTimerConfWidget::updateStartTrigger(int option)
19492
+{
19493
+    switch(option)
19494
+    {
19495
+        case 1:
19496
+            updateAttribute("starttrigger", "batch");
19497
+            break;
19498
+        case 2:
19499
+            updateAttribute("starttrigger", "manual");
19500
+            break;
19501
+        case 3:
19502
+            updateAttribute("starttrigger", "value");
19503
+            break;
19504
+        default:
19505
+            break;
19506
+    }
19507
+}
19508
+
19509
+void RangeTimerConfWidget::updateStopTrigger(int option)
19510
+{
19511
+    switch(option)
19512
+    {
19513
+        case 1:
19514
+            updateAttribute("stoptrigger", "batch");
19515
+            break;
19516
+        case 2:
19517
+            updateAttribute("stoptrigger", "manual");
19518
+            break;
19519
+        case 3:
19520
+            updateAttribute("stoptrigger", "value");
19521
+            break;
19522
+        default:
19523
+            break;
19524
+    }
19525
+}
19526
+
19527
+@ The widget is registered with the configuration system.
19528
+@<Register device configuration widgets@>=
19529
+app.registerDeviceConfigurationWidget("rangetimer",
19530
+RangeTimerConfWidget::staticMetaObject);
19531
+
19532
+@ The implementation chunk for now is in the main source file.
19533
+
19534
+@<Class implementations@>=
19535
+@<RangeTimerConfWidget implementation@>
19536
+
19537
+@ The multirange timer is a little different. To keep configuration tractible,
19538
+this is slightly less general purpose than the range timer and only supports
19539
+automatic triggering on a single data series.
19540
+
19541
+@<Class declarations@>=
19542
+class MultiRangeTimerConfWidget : public BasicDeviceConfigurationWidget
19543
+{
19544
+    @[Q_OBJECT@]@/
19545
+    public:@/
19546
+        @[Q_INVOKABLE@]@, MultiRangeTimerConfWidget(DeviceTreeModel *model,
19547
+                                                    const QModelIndex &index);
19548
+    @[private slots@]:@/
19549
+        void updateColumnName(const QString &text);
19550
+        void updateRangeData();
19551
+    private:@/
19552
+        SaltModel *tablemodel;
19553
+};
19554
+
19555
+@ These limitations allow a rather small set of controls for configuration. A
19556
+line edit to specify the data series used for automatic triggering and a table
19557
+which specifies the name of the timed range and an ending temperature.
19558
+
19559
+@<MultiRangeTimerConfWidget implementation@>=
19560
+MultiRangeTimerConfWidget::MultiRangeTimerConfWidget(DeviceTreeModel *model,
19561
+                                                     const QModelIndex &index)
19562
+: BasicDeviceConfigurationWidget(model, index), tablemodel(new SaltModel(2))
19563
+{
19564
+    QFormLayout *layout = new QFormLayout;
19565
+    QLineEdit *trigger = new QLineEdit;
19566
+    layout->addRow(tr("Trigger column name:"), trigger);
19567
+    tablemodel->setHeaderData(0, Qt::Horizontal, "Range Name");
19568
+    tablemodel->setHeaderData(1, Qt::Horizontal, "End Temperature");
19569
+    QTableView *rangeTable = new QTableView;
19570
+    rangeTable->setModel(tablemodel);
19571
+    layout->addRow(tr("Range data:"), rangeTable);
19572
+    @<Get device configuration data for current node@>@;
19573
+    for(int i = 0; i < configData.size(); i++)
19574
+    {
19575
+        node = configData.at(i).toElement();
19576
+        if(node.attribute("name") == "trigger")
19577
+        {
19578
+            trigger->setText(node.attribute("value"));
19579
+        }
19580
+        else if(node.attribute("name") == "rangenames")
19581
+        {
19582
+            QString data = node.attribute("value");
19583
+            if(data.length() > 3)
19584
+            {
19585
+                data.chop(2);
19586
+                data = data.remove(0, 2);
19587
+            }
19588
+            QStringList itemList = data.split(", ");
19589
+            for(int j = 0; j < itemList.size(); j++)
19590
+            {
19591
+                QString item = itemList.at(j);
19592
+                item.chop(1);
19593
+                item = item.remove(0, 1);
19594
+                tablemodel->setData(tablemodel->index(j, 0),
19595
+                                    QVariant(item), Qt::DisplayRole);
19596
+            }
19597
+        }
19598
+        else if(node.attribute("name") == "endtemps")
19599
+        {
19600
+            @<Convert numeric array literal to list@>@;
19601
+            int column = 1;
19602
+            @<Populate model column from list@>@;
19603
+        }
19604
+    }
19605
+    updateColumnName(trigger->text());
19606
+    updateRangeData();
19607
+    connect(trigger, SIGNAL(textEdited(QString)), this, SLOT(updateColumnName(QString)));
19608
+    connect(tablemodel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(updateRangeData()));
19609
+    setLayout(layout);
19610
+}
19611
+
19612
+@ The update mechanisms are reasonably straightforward. Table updates just
19613
+refresh the entire table instead of attempting to be clever about updating only
19614
+the element that changed.
19615
+
19616
+@<MultiRangeTimerConfWidget implementation@>=
19617
+void MultiRangeTimerConfWidget::updateRangeData()
19618
+{
19619
+    updateAttribute("rangenames", tablemodel->quotedArrayLiteral(0, Qt::DisplayRole));
19620
+    updateAttribute("endtemps", tablemodel->arrayLiteral(1, Qt::DisplayRole));
19621
+}
19622
+
19623
+void MultiRangeTimerConfWidget::updateColumnName(const QString &text)
19624
+{
19625
+    updateAttribute("trigger", text);
19626
+}
19627
+
19628
+@ The widget is registered with the configuration system.
19629
+@<Register device configuration widgets@>=
19630
+app.registerDeviceConfigurationWidget("multirangetimer",
19631
+MultiRangeTimerConfWidget::staticMetaObject);
19632
+
19633
+@ The implementation is in the main source file.
19634
+
19635
+@<Class implementations@>=
19636
+@<MultiRangeTimerConfWidget implementation@>
19637
+
19158 19638
 @* Profile Translation Configuration Widget.
19159 19639
 
19160 19640
 \noindent Configuring profile translation requires knowing which column to use

Loading…
Cancel
Save