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
 		var roasterIndex = roasterlist.currentIndex;
67
 		var roasterIndex = roasterlist.currentIndex;
68
 		var channels = new Array();
68
 		var channels = new Array();
69
 		var annotationButtons = new Array();
69
 		var annotationButtons = new Array();
70
+                var rangetimers = new Array();
70
 		var nidevices = new Array();
71
 		var nidevices = new Array();
71
 		var dataqsdkdevices = new Array();
72
 		var dataqsdkdevices = new Array();
72
 		var jsdevices = new Array();
73
 		var jsdevices = new Array();
612
 					scale.open(3);
613
 					scale.open(3);
613
 					window.scales.push(scale);
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
 		for(var i = 1; i < tabControls.length; i++)
763
 		for(var i = 1; i < tabControls.length; i++)
805
 				log.addOutputAnnotationColumn(lc + channels.length - channelSkip);
951
 				log.addOutputAnnotationColumn(lc + channels.length - channelSkip);
806
                 var filename = log.saveTemporary();
952
                 var filename = log.saveTemporary();
807
                 currentBatchInfo.tempData = filename;
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
                 currentBatchInfo.raise();
959
                 currentBatchInfo.raise();
809
                 currentBatchInfo.activateWindow();
960
                 currentBatchInfo.activateWindow();
810
             }
961
             }

+ 483
- 3
src/typica.w View File

4155
     return QScriptValue();
4155
     return QScriptValue();
4156
 }
4156
 }
4157
 
4157
 
4158
+
4158
 @** Application Configuration.
4159
 @** Application Configuration.
4159
 
4160
 
4160
 \noindent While \pn{} is intended as a data logging application, the diversity
4161
 \noindent While \pn{} is intended as a data logging application, the diversity
10554
 Q_PROPERTY(QTime resetValue READ resetValue WRITE setResetValue)@/
10555
 Q_PROPERTY(QTime resetValue READ resetValue WRITE setResetValue)@/
10555
 Q_PROPERTY(QString displayFormat READ displayFormat WRITE setDisplayFormat)@/
10556
 Q_PROPERTY(QString displayFormat READ displayFormat WRITE setDisplayFormat)@/
10556
 Q_PROPERTY(bool autoReset READ autoReset WRITE setAutoReset)@/
10557
 Q_PROPERTY(bool autoReset READ autoReset WRITE setAutoReset)@/
10558
+Q_PROPERTY(QString value READ value)@/
10557
 
10559
 
10558
 @ A number of private variables are used to implement this class.
10560
 @ A number of private variables are used to implement this class.
10559
 
10561
 
10673
         s = nt;
10675
         s = nt;
10674
         emit valueChanged(s);
10676
         emit valueChanged(s);
10675
     }
10677
     }
10678
+} else {
10679
+    stopTimer();
10676
 }
10680
 }
10677
 
10681
 
10678
 @ The clock mode is the simplest case as it just needs to find out if the time
10682
 @ The clock mode is the simplest case as it just needs to find out if the time
10867
 QScriptValue constructTimerDisplay(QScriptContext *context,
10871
 QScriptValue constructTimerDisplay(QScriptContext *context,
10868
                                    QScriptEngine *engine);
10872
                                    QScriptEngine *engine);
10869
 void setTimerDisplayProperties(QScriptValue value, QScriptEngine *engine);
10873
 void setTimerDisplayProperties(QScriptValue value, QScriptEngine *engine);
10874
+QScriptValue TimerDisplay_setTimerMode(QScriptContext *context, QScriptEngine *engine);
10870
 
10875
 
10871
 @ The engine must be informed of the script constructor.
10876
 @ The engine must be informed of the script constructor.
10872
 
10877
 
10888
 void setTimerDisplayProperties(QScriptValue value, QScriptEngine *engine)
10893
 void setTimerDisplayProperties(QScriptValue value, QScriptEngine *engine)
10889
 {
10894
 {
10890
     setQLCDNumberProperties(value, engine);
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
     @<Add annotation control node inserters@>@;
16039
     @<Add annotation control node inserters@>@;
16005
     addAnnotationControlButton->setMenu(annotationMenu);
16040
     addAnnotationControlButton->setMenu(annotationMenu);
16006
     layout->addWidget(addAnnotationControlButton);
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
     QPushButton *advancedButton = new QPushButton(tr("Advanced Features"));
16060
     QPushButton *advancedButton = new QPushButton(tr("Advanced Features"));
16008
     QMenu *advancedMenu = new QMenu;
16061
     QMenu *advancedMenu = new QMenu;
16009
     NodeInserter *linearsplineinserter = new NodeInserter(tr("Linear Spline Interpolated Series"), tr("Linear Spline Interpolated Series"), "linearspline");
16062
     NodeInserter *linearsplineinserter = new NodeInserter(tr("Linear Spline Interpolated Series"), tr("Linear Spline Interpolated Series"), "linearspline");
16015
     @<Add node inserters to advanced features menu@>@;
16068
     @<Add node inserters to advanced features menu@>@;
16016
     advancedButton->setMenu(advancedMenu);
16069
     advancedButton->setMenu(advancedMenu);
16017
     layout->addWidget(advancedButton);
16070
     layout->addWidget(advancedButton);
16071
+    
16018
     QHBoxLayout *idLayout = new QHBoxLayout;
16072
     QHBoxLayout *idLayout = new QHBoxLayout;
16019
     QLabel *idLabel = new QLabel(tr("Machine ID for database:"));
16073
     QLabel *idLabel = new QLabel(tr("Machine ID for database:"));
16020
     idLayout->addWidget(idLabel);
16074
     idLayout->addWidget(idLabel);
19123
 model.
19177
 model.
19124
 
19178
 
19125
 @<Populate model column from list@>=
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
                    Qt::DisplayRole);
19184
                    Qt::DisplayRole);
19131
 }
19185
 }
19132
 
19186
 
19155
 @<Register device configuration widgets@>=
19209
 @<Register device configuration widgets@>=
19156
 app.registerDeviceConfigurationWidget("linearspline", LinearSplineInterpolationConfWidget::staticMetaObject);
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
 @* Profile Translation Configuration Widget.
19638
 @* Profile Translation Configuration Widget.
19159
 
19639
 
19160
 \noindent Configuring profile translation requires knowing which column to use
19640
 \noindent Configuring profile translation requires knowing which column to use

Loading…
Cancel
Save