1915 lines
44 KiB
C++
1915 lines
44 KiB
C++
#include "seaset.h"
|
|
#include <time.h>
|
|
#include <qstringlist.h>
|
|
#include <qvaluelist.h>
|
|
#include <qmap.h>
|
|
#include <qptrlist.h>
|
|
#include <qpixmap.h>
|
|
#include <qlabel.h>
|
|
#include <qtooltip.h>
|
|
#include <qsize.h>
|
|
#include <qwt_scale.h>
|
|
#include <qwt_plot_layout.h>
|
|
#include <qwt_dyngrid_layout.h>
|
|
#include <qvbox.h>
|
|
#include <qhbox.h>
|
|
#include <qgrid.h>
|
|
#include <qlayout.h>
|
|
#include <qscrollview.h>
|
|
#include <qevent.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "instr_hosts.h"
|
|
#include "utils.h"
|
|
|
|
#define MAX_LABELS 20
|
|
#define MAX_FUTURE 600
|
|
#define ONE_YEAR 365*24*3600
|
|
|
|
static int prt = 2;
|
|
|
|
void setprintit(int p) {
|
|
prt = p;
|
|
}
|
|
|
|
int printit(void) {
|
|
return prt>0;
|
|
}
|
|
|
|
SeaRow::SeaRow(QWidget *parent) : QScrollView(parent) {
|
|
this->plot = 0;
|
|
state = newRow;
|
|
setHScrollBarMode(QScrollView::AlwaysOff);
|
|
setVScrollBarMode(QScrollView::AlwaysOff);
|
|
usedLegend = 0;
|
|
timeLabel = 0;
|
|
};
|
|
|
|
void SeaRow::resizeEvent(QResizeEvent *e) {
|
|
int w, rightW, legW, rowW, rowH;
|
|
SeaRow *row;
|
|
bool isfirstrow;
|
|
|
|
if (e->size() == e->oldSize()) {
|
|
return;
|
|
}
|
|
if (isHidden()) {
|
|
if (set->showPlot) {
|
|
set->saveRowHeight(this, 0);
|
|
}
|
|
return;
|
|
}
|
|
rowH = e->size().height(); // row height
|
|
if (rowH == 1) {
|
|
rowH = 0;
|
|
}
|
|
if (set->showPlot) {
|
|
set->saveRowHeight(this, rowH);
|
|
}
|
|
if (right->isHidden() && rowH > 0) {
|
|
state = shownRow;
|
|
if (set->showPlot) {
|
|
set->reread = true;
|
|
right->show();
|
|
hBox->show();
|
|
}
|
|
}
|
|
rightW = bBox->sizeHint().width();
|
|
for (row = set->rows.first(); row != 0; set->rows.findRef(row), row = set->rows.next()) {
|
|
if (row->state != hiddenRow) {
|
|
legW = row->leg->sizeHint().width();
|
|
legW += row->legScroll->width() - row->legScroll->visibleWidth();
|
|
if (legW > rightW) {
|
|
rightW = legW;
|
|
}
|
|
}
|
|
}
|
|
rowW = e->size().width();
|
|
isfirstrow = true;
|
|
for (row = set->rows.first(); row != 0; set->rows.findRef(row), row = set->rows.next()) {
|
|
if (row->state != hiddenRow) {
|
|
if (row->right->width() != rightW) {
|
|
row->right->setFixedWidth(rightW);
|
|
}
|
|
w = e->size().width() - rightW - hBox->layout()->spacing();
|
|
if (row->plot->width() != w && w > 1) {
|
|
row->plot->setFixedWidth(w);
|
|
}
|
|
if (row == this) {
|
|
if (plot->height() != rowH) {
|
|
setInnerHeights(isfirstrow, rowH);
|
|
}
|
|
if (rowW != hBox->width()) {
|
|
hBox->setFixedWidth(rowW);
|
|
}
|
|
}
|
|
isfirstrow = false;
|
|
}
|
|
}
|
|
set->setFirstRow();
|
|
}
|
|
|
|
void SeaRow::setInnerHeights(bool isfirstrow, int rowH) {
|
|
int legH, butH, axisH;
|
|
|
|
axisH = 0;
|
|
butH = bBox->height();
|
|
legH = QMAX(rowH - butH, butH);
|
|
if (isfirstrow) {
|
|
// space for time label
|
|
legH -= timeLabel->height();
|
|
axisH = 0;
|
|
} else {
|
|
// plot height has to be increased by this value to hide the time axis
|
|
axisH = plot->axis(SeaPlot::xBottom)->height();
|
|
}
|
|
plot->setFixedHeight(rowH + axisH);
|
|
hBox->setFixedHeight(rowH + axisH);
|
|
if (legH > butH) {
|
|
legScroll->setFixedHeight(legH);
|
|
}
|
|
}
|
|
|
|
void SeaRow::hideRow() {
|
|
state = hiddenRow;
|
|
set->saveRowHeight(this, 0);
|
|
right->hide();
|
|
hBox->hide();
|
|
set->hideRow();
|
|
}
|
|
|
|
QSize SeaRow::minimumSizeHint() const {
|
|
QSize size = QScrollView::minimumSizeHint();
|
|
size.setHeight(30);
|
|
return size;
|
|
}
|
|
|
|
SeaData::SeaData(const QString &name, const QString &label, const QString &plotName, int color) {
|
|
this->name = name;
|
|
this->label = label;
|
|
this->plotName = plotName;
|
|
step_m = 1;
|
|
lastx = 0;
|
|
size_m = 0;
|
|
clr = false;
|
|
dirty = true;
|
|
key = 0;
|
|
plot = 0;
|
|
row = 0;
|
|
bold = true;
|
|
decipos = 3;
|
|
size = 0;
|
|
style = color;
|
|
//printf("curve %s %s\n", name.latin1(), plotName.latin1());
|
|
}
|
|
|
|
SeaData::~SeaData() {
|
|
}
|
|
|
|
bool SeaData::isActive() {
|
|
return bold && row != 0 && row->state != hiddenRow;
|
|
}
|
|
|
|
void SeaData::init(time_t step, int siz) {
|
|
step_m = step;
|
|
size_m = 0;
|
|
lastx = 1e30;
|
|
modified = true;
|
|
if (siz > size) {
|
|
if (size > 0) {
|
|
free(x);
|
|
free(y);
|
|
}
|
|
size = siz;
|
|
x = (double *)calloc(size, sizeof(*x));
|
|
y = (double *)calloc(size, sizeof(*y));
|
|
}
|
|
}
|
|
|
|
int SeaData::addValue(double xx, QString value) {
|
|
double yy;
|
|
bool ok;
|
|
|
|
if (size_m >= size) return -1;
|
|
while (size_m > 0 && xx <= x[size_m-1] + 0.5) {
|
|
size_m--;
|
|
}
|
|
if (period >= 0) {
|
|
if (size_m > 0 && xx > lastx + 2 * period) { /* gap, additional point needed */
|
|
x[size_m] = xx - period;
|
|
y[size_m] = y[size_m-1];
|
|
lastx = 1e30;
|
|
size_m++;
|
|
if (size_m >= size) return -1;
|
|
}
|
|
}
|
|
yy = value.toDouble(&ok);
|
|
//iret = sscanf(value, "%lf", &yy);
|
|
if (ok) { // valid value
|
|
/*
|
|
if (size_m >= 2 && yy == y[size_m-1] && yy == y[size_m-2]) {
|
|
size_m--; // do not draw the middle of 3 points on a horizontal line
|
|
}
|
|
*/
|
|
x[size_m] = xx;
|
|
y[size_m] = yy;
|
|
lastx = xx;
|
|
size_m++;
|
|
modified = true;
|
|
} else if (size_m > 0) { /* invalid value -> an undefined value is marked with DATA_UNDEF */
|
|
if (size_m > 0 && y[size_m-1] == DATA_UNDEF) {
|
|
return size_m;
|
|
}
|
|
x[size_m] = x[size_m-1];
|
|
y[size_m] = DATA_UNDEF;
|
|
lastx = 1e30;
|
|
size_m++;
|
|
modified = true;
|
|
}
|
|
return size_m;
|
|
}
|
|
|
|
bool SeaData::update() {
|
|
if (plot) {
|
|
if (modified) {
|
|
modified = false;
|
|
plot->setCurveRawData(key, x, y, size_m);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SeaData::showValueAt(double at) {
|
|
QString text("");
|
|
int pos, epos;
|
|
int i, l;
|
|
double value = DATA_UNDEF;
|
|
|
|
if (size_m > 0) {
|
|
if (at == DATA_UNDEF) {
|
|
at = x[size_m-1];
|
|
}
|
|
}
|
|
for (i = size_m-1; i >= 0; i--) {
|
|
if (x[i] <= at + 0.5) {
|
|
value = y[i];
|
|
// if (i > 0 && x[i-1] >= x[i]-0.5 && value == DATA_UNDEF) {
|
|
// value = y[i-1];
|
|
// }
|
|
break;
|
|
}
|
|
}
|
|
if (value != DATA_UNDEF) {
|
|
text.sprintf(" %9.5g", value);
|
|
pos = text.find('.');
|
|
epos = text.find('e');
|
|
if (epos >= 0) {
|
|
epos ++;
|
|
if (text[epos] == '+') {
|
|
text.remove(epos, 1);
|
|
} else if (text[epos] == '-') {
|
|
epos ++;
|
|
}
|
|
if (text[epos] == '0') {
|
|
text.remove(epos, 1);
|
|
}
|
|
pos = text.length();
|
|
if (pos > 10) { // remove last digit before 'e' when number too long
|
|
epos = text.find('e');
|
|
text.remove(epos - 1, 1);
|
|
}
|
|
} else {
|
|
l = text.length();
|
|
if (pos < 0) pos = l;
|
|
while (pos < decipos && pos < 2 && l < 10) {
|
|
text.prepend(' ');
|
|
pos++;
|
|
l++;
|
|
}
|
|
}
|
|
while (pos > decipos && text[1] == ' ') {
|
|
text.remove(0, 1);
|
|
text.append(' ');
|
|
pos--;
|
|
}
|
|
text.truncate(10);
|
|
}
|
|
shownValue->setText(text);
|
|
}
|
|
|
|
void SeaSet::clrDataList() {
|
|
SeaData *d;
|
|
for (d = dataList.first(); d != 0; dataList.findRef(d), d = dataList.first()) {
|
|
dataList.remove();
|
|
delete d;
|
|
}
|
|
}
|
|
|
|
SeaData *SeaSet::findData(const QString &name) {
|
|
SeaData *d;
|
|
for (d = dataList.first(); d != 0; dataList.findRef(d), d = dataList.next()) {
|
|
if (d->name.compare(name) == 0) {
|
|
return d;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void SeaSet::insertData(const QString &name, const QString &label, const QString &plotName, const int color) {
|
|
SeaData *d;
|
|
QString pName;
|
|
if (plotName == 0) {
|
|
pName = "";
|
|
} else {
|
|
pName = plotName;
|
|
}
|
|
if (name.compare("!") < 0) return; // do not make curves with blank name
|
|
d = findData(name);
|
|
if (d) {
|
|
d->clr = false;
|
|
d->label = label;
|
|
d->plotName = pName;
|
|
//d->bold = true;
|
|
d->style = color;
|
|
return;
|
|
}
|
|
dataList.append(new SeaData(name, label, pName, color));
|
|
}
|
|
|
|
void SeaSet::finishDataList() {
|
|
SeaData *d;
|
|
SeaPlot *plot;
|
|
bool dirty;
|
|
SeaRow *row, *unused;
|
|
LegendButton *legButton;
|
|
QLabel *valueLabel;
|
|
QFont monospace("Courier");
|
|
monospace.setStyleHint(QFont::TypeWriter);
|
|
QFontMetrics fm(monospace);
|
|
QGridLayout *gridLayout;
|
|
uint idx;
|
|
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
row->plot->removeAll();
|
|
row->usedLegend = 0;
|
|
}
|
|
for (d = dataList.first(); d != 0; dataList.findRef(d), d = dataList.next()) {
|
|
if (! d->clr) {
|
|
// find plot with that name
|
|
unused = 0;
|
|
plot=0;
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
plot = row->plot;
|
|
if (plot->tag.compare(d->plotName) == 0) break;
|
|
if (!unused && plot->tag.compare("") == 0) {
|
|
unused = row;
|
|
}
|
|
}
|
|
if (!row) {
|
|
if (unused) {
|
|
row = unused;
|
|
plot = row->plot;
|
|
plot->tag = d->plotName;
|
|
row->setTag(d->plotName);
|
|
} else {
|
|
row = newPlot(d->plotName);
|
|
plot = row->plot;
|
|
}
|
|
//plot->setAxisTitle(SeaPlot::yLeft, d->plotName);
|
|
}
|
|
|
|
if (row->legendList.count() > row->usedLegend) {
|
|
legButton = row->legendList.at(row->usedLegend);
|
|
valueLabel = legButton->valueLabel;
|
|
legButton = plot->putCurve(d, row->leg, legButton);
|
|
d->row = row;
|
|
gridLayout = dynamic_cast<QGridLayout *>(row->leg->layout());
|
|
legButton->label->setText(d->label);
|
|
legButton->show();
|
|
legButton->label->show();
|
|
valueLabel->show();
|
|
// printf("recycle %s %s\n", plot->tag.latin1(), d->label.latin1());
|
|
} else {
|
|
valueLabel = new QLabel(row->leg);
|
|
valueLabel->setFont(monospace);
|
|
valueLabel->setFixedWidth(fm.width(" -0.0000e-0") + 2 * valueLabel->frameWidth());
|
|
legButton = plot->putCurve(d, row->leg);
|
|
d->row = row;
|
|
legButton->valueLabel = valueLabel;
|
|
row->legendList.append(legButton);
|
|
gridLayout = dynamic_cast<QGridLayout *>(row->leg->layout());
|
|
assert(gridLayout);
|
|
gridLayout->addWidget(legButton, d->key, 0, Qt::AlignLeft + Qt::AlignBottom);
|
|
gridLayout->addWidget(legButton->label, d->key, 1, Qt::AlignLeft + Qt::AlignBottom);
|
|
gridLayout->addWidget(valueLabel, d->key, 2, Qt::AlignRight + Qt::AlignBottom);
|
|
legButton->show();
|
|
legButton->label->show();
|
|
valueLabel->show();
|
|
// printf("new %s %s\n", plot->tag.latin1(), d->label.latin1());
|
|
}
|
|
row->usedLegend++;
|
|
d->shownValue = valueLabel;
|
|
|
|
|
|
gridLayout->activate();
|
|
if (showPlot) {
|
|
row->hBox->show();
|
|
row->right->show();
|
|
} else {
|
|
row->hBox->hide();
|
|
row->right->hide();
|
|
}
|
|
}
|
|
}
|
|
dirty = true;
|
|
while (dirty) {
|
|
dirty= false;
|
|
for (d = dataList.first(); d != 0; dataList.findRef(d), d = dataList.next()) {
|
|
if (d->clr) {
|
|
dataList.remove(d);
|
|
delete d;
|
|
dirty = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
for (idx = row->usedLegend; idx < row->legendList.count(); idx++) {
|
|
legButton = row->legendList.at(idx);
|
|
legButton->setCurvePen(QPen(Qt::NoPen));
|
|
legButton->valueLabel->setText("");
|
|
legButton->label->setText("");
|
|
}
|
|
if (row->usedLegend == 0) {
|
|
row->hide();
|
|
row->state = hiddenRow;
|
|
} else {
|
|
row->show();
|
|
if (row->state == hiddenRow) row->state = shownRow;
|
|
row->plot->autoColors();
|
|
}
|
|
}
|
|
adjustSizes();
|
|
readNewReplot();
|
|
}
|
|
|
|
void SeaSet::saveRowHeight(SeaRow *row, int height) {
|
|
int *rowheight;
|
|
|
|
// printf("*** save %s %d\n", row->plot->tag.latin1(), height);
|
|
rowheight = rowHeightDict.find(row->plot->tag);
|
|
if (rowheight) {
|
|
*rowheight = height;
|
|
} else {
|
|
rowHeightDict.insert(row->plot->tag, new int(height));
|
|
}
|
|
}
|
|
|
|
void SeaSet::saveBoldState(SeaData *data) {
|
|
bool *boldstate;
|
|
|
|
boldstate = boldDict.find(data->name);
|
|
if (boldstate) {
|
|
*boldstate = data->bold;
|
|
} else if (!data->bold) {
|
|
boldDict.insert(data->name, new bool(false));
|
|
}
|
|
}
|
|
|
|
int SeaSet::getRowHeight(SeaRow *row) {
|
|
int *rowheight;
|
|
|
|
rowheight = rowHeightDict.find(row->plot->tag);
|
|
if (rowheight) {
|
|
// printf("** getRow %s %d\n", row->plot->tag.latin1(), *rowheight);
|
|
return *rowheight;
|
|
} else {
|
|
// printf("** getRow %s %d\n", row->plot->tag.latin1(), -1);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void SeaSet::getBoldState(SeaData *data) {
|
|
bool *boldstate;
|
|
|
|
boldstate = boldDict.find(data->name);
|
|
if (boldstate) {
|
|
data->bold = *boldstate;
|
|
} else {
|
|
data->bold = true;
|
|
}
|
|
}
|
|
|
|
void SeaSet::adjustSizes() {
|
|
QValueList<int> sizes;
|
|
int i, cnt, rowN, h, tot;
|
|
int rowheight;
|
|
SeaRow *row;
|
|
bool isfirstrow;
|
|
/*
|
|
if (initSizes) {
|
|
initSizes = false;
|
|
sizes = split->sizes();
|
|
h = 400;
|
|
for (i = 0; i<(int)sizes.count(); i++) {
|
|
sizes[i] = h;
|
|
h = 200;
|
|
}
|
|
split->setSizes(sizes);
|
|
goto quit;
|
|
}
|
|
*/
|
|
tot = 0; /* sum of known sizes */
|
|
cnt = 0; /* count of known sizes (first row is counted twice) */
|
|
sizes = split->sizes();
|
|
rowN = 0;
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
rowheight = getRowHeight(row);
|
|
if (rowheight == 0 && row->state != newRow) {
|
|
row->state = hiddenRow;
|
|
sizes[rowN] = 0;
|
|
} else if (rowheight <= 0) {
|
|
row->state = shownRow;
|
|
sizes[rowN] = -1;
|
|
} else {
|
|
row->state = shownRow;
|
|
cnt++;
|
|
tot += rowheight;
|
|
if (rowN == 0) {
|
|
cnt++;
|
|
}
|
|
sizes[rowN] = rowheight;
|
|
}
|
|
rowN++;
|
|
}
|
|
assert(rowN == (int)sizes.count());
|
|
if (cnt == 0) {
|
|
h = 200;
|
|
} else {
|
|
h = tot / cnt;
|
|
}
|
|
for (i = 0; i < rowN; i++) {
|
|
if (sizes[i] < 0) {
|
|
if (i == 0) {
|
|
sizes[i] = h*2;
|
|
} else {
|
|
sizes[i] = h;
|
|
}
|
|
}
|
|
}
|
|
split->setSizes(sizes);
|
|
//quit:
|
|
isfirstrow = true;
|
|
for (row = rows.first(), i = 0; row != 0; i++, rows.findRef(row), row = rows.next()) {
|
|
if (row->state != hiddenRow) {
|
|
rowheight = row->height();
|
|
if (rowheight > row->bBox->height()) {
|
|
row->setInnerHeights(isfirstrow, rowheight);
|
|
saveRowHeight(row, rowheight);
|
|
}
|
|
isfirstrow = false;
|
|
} else {
|
|
saveRowHeight(row, 0);
|
|
}
|
|
}
|
|
setFirstRow();
|
|
return;
|
|
}
|
|
|
|
void SeaSet::setFirstRow() {
|
|
SeaRow *row;
|
|
|
|
for (row = rows.first(); row != 0; row = rows.next()) {
|
|
if (row->state == shownRow) {
|
|
// this is the first row
|
|
if (row != firstRow) {
|
|
if (firstRow) {
|
|
firstRow->setInnerHeights(false, firstRow->height());
|
|
firstRow->timeLabel->setText("");
|
|
}
|
|
firstRow = row;
|
|
firstRow->setInnerHeights(true, firstRow->height());
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
SeaSet::SeaSet(QSplitter *parent, long range, const char *name)
|
|
: QObject(parent, name), rowHeightDict(31, false), boldDict(127, false)
|
|
{
|
|
|
|
hostport = "";
|
|
sc = new SicsConnection(this);
|
|
uc = new SicsConnection(this);
|
|
uc->setUser("seauser seaser\n");
|
|
gc = new SicsConnection(this);
|
|
// gc->debug = "G";
|
|
ec = new SicsConnection(this);
|
|
connect(sc, SIGNAL(reconnected()), uc, SLOT(reconnect()));
|
|
|
|
firstRow = 0;
|
|
split = parent;
|
|
labelWidth = 30;
|
|
actLegendWidth = 10;
|
|
legendWidth = 10;
|
|
if (range > ONE_YEAR) { // range is definitly not a relative date
|
|
startRange = range - 1800;
|
|
endRange = range + 1800;
|
|
} else {
|
|
startRange = - range;
|
|
endRange = QMIN(MAX_FUTURE, range / 2);
|
|
}
|
|
live = liveOff;
|
|
lastRead = time(NULL);
|
|
reread = true;
|
|
undoPlot = 0;
|
|
undoStart = 0;
|
|
labelMode = 0;
|
|
initSizes = true;
|
|
refresh = 0;
|
|
xSize = 1000;
|
|
autoDo = false;
|
|
getDo = false;
|
|
getNewData = false;
|
|
autoArg.vars = "";
|
|
base = 0;
|
|
async_mode = async_idle;
|
|
asyncTimer = new QTimer(this);
|
|
connect(asyncTimer, SIGNAL(timeout()), SLOT(asyncHandler()));
|
|
asyncTimer->start(1);
|
|
meas.start();
|
|
showPlot = false;
|
|
markerPos = DATA_UNDEF;
|
|
markerWasOn = false;
|
|
}
|
|
|
|
void SeaSet::setHost(const QString &hostport) {
|
|
static char cmd[128], psw[32];
|
|
static char *user;
|
|
char host[128], instr[32];
|
|
char *hp = (char *)hostport.latin1();
|
|
char *p;
|
|
int port;
|
|
|
|
|
|
this->hostport = hostport;
|
|
sc->setHost(hostport.latin1(), "sea");
|
|
uc->setHost(hostport.latin1(), "sea");
|
|
gc->setHost(hostport.latin1(), "graph");
|
|
ec->setHost(hostport.latin1(), "graph");
|
|
|
|
p = strchr(hp, ':');
|
|
if (p == NULL) {
|
|
InstrHost("sea", hp, instr, sizeof instr, host, sizeof host, &port);
|
|
if (strcmp(host, instr) == 0) {
|
|
snprintf(psw, sizeof psw, "SSHPASS=%sLNS", strtoupper(instr));
|
|
user = instr;
|
|
} else if (strcmp(host, "linse-c") == 0) {
|
|
snprintf(psw, sizeof psw, "SSHPASS=1%dlns1", 7);
|
|
user = "l_samenv";
|
|
} else {
|
|
return;
|
|
}
|
|
putenv(psw);
|
|
snprintf(cmd, sizeof cmd, "sshpass -e ssh -Y %s@%s sea start %s",
|
|
user, host, instr);
|
|
sc->startServer = cmd;
|
|
for (int i=0; i<30; i++) {
|
|
sc->handleBuffer(1);
|
|
if (sc->connect_state == SicsConnection::connect_waitlogin) {
|
|
break;
|
|
}
|
|
usleep(250000);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SeaSet::setLive(bool on) {
|
|
time_t range, now;
|
|
if (lastRead >= 0) {
|
|
now = lastRead;
|
|
} else {
|
|
now = time(NULL);
|
|
}
|
|
if (on) {
|
|
if (live == liveOff) {
|
|
range = QMAX(MAX_FUTURE, endRange - startRange);
|
|
if (endRange < now - range && endRange > MAX_FUTURE*2) {
|
|
live = liveAuto;
|
|
} else {
|
|
live = liveOn;
|
|
if (startRange <= 0) {
|
|
rescale(startRange, range / 2);
|
|
} else {
|
|
rescale(startRange, now + range / 2);
|
|
}
|
|
}
|
|
}
|
|
} else if (live != liveOff) {
|
|
live = liveOff;
|
|
if (endRange > now) {
|
|
endRange = now;
|
|
}
|
|
rescale(startRange, endRange);
|
|
}
|
|
}
|
|
|
|
void SeaSet::restart(const char *vars) {
|
|
if (autoArg.vars == "" || autoArg.vars.compare(vars) != 0) {
|
|
autoArgDo.vars = "0 ";
|
|
autoArgDo.vars.append(vars);
|
|
autoDo = true;
|
|
}
|
|
}
|
|
|
|
void SeaSet::setTimeRange(time_t startrange, long seconds) {
|
|
|
|
undoStart = 0;
|
|
undoPlot = 0;
|
|
undoEnabled(false);
|
|
showPlot = false;
|
|
rescale(startrange, startrange + QMIN(SEA_MAX_RANGE, QMAX(60, seconds)));
|
|
}
|
|
|
|
QString SeaSet::dateLabel(long dayOffset) {
|
|
QString str;
|
|
static char *wday[] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su" };
|
|
static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
|
time_t t = base+12*3600+dayOffset*(24*3600);
|
|
struct tm basetm = *localtime(&t);
|
|
str.sprintf("%s.%d.%s.%2.2d", wday[basetm.tm_wday], basetm.tm_mday, month[basetm.tm_mon], basetm.tm_year % 100);
|
|
return str;
|
|
}
|
|
|
|
int SeaSet::sicsCommand(QString &cmd, int graph) {
|
|
int iret, cnt;
|
|
const char *hp;
|
|
SicsConnection *conn;
|
|
|
|
if (graph) {
|
|
conn = gc;
|
|
} else {
|
|
conn = sc;
|
|
}
|
|
iret = conn->command(cmd.latin1());
|
|
cnt = 2;
|
|
while (iret <= 0) {
|
|
if (iret == 0) {
|
|
if (printit()) printf("empty response\n");
|
|
} else {
|
|
hp = hostport.latin1();
|
|
if (hp == NULL || *hp == '\0') hp = "localhost";
|
|
if (printit()) printf("connection to %s failed\n", hp);
|
|
}
|
|
cnt --;
|
|
if (cnt <= 0) return -1;
|
|
if (printit()) printf("retry\n");
|
|
iret = conn->command(cmd.latin1());
|
|
}
|
|
return iret;
|
|
}
|
|
|
|
int SeaSet::sendSicsCommand(QString &cmd, int graph) {
|
|
int iret, cnt;
|
|
const char *hp;
|
|
SicsConnection *conn;
|
|
|
|
if (graph) {
|
|
conn = gc;
|
|
} else {
|
|
conn = sc;
|
|
}
|
|
iret = conn->sendCommand(cmd.latin1());
|
|
cnt = 2;
|
|
while (iret <= 0) {
|
|
if (iret == 0) {
|
|
if (printit()) printf("empty response\n");
|
|
} else {
|
|
hp = hostport.latin1();
|
|
if (hp == NULL || *hp == '\0') hp = "localhost";
|
|
if (printit()) printf("connection to %s failed\n", hp);
|
|
}
|
|
cnt --;
|
|
if (cnt <= 0) return -1;
|
|
if (printit()) printf("retry\n");
|
|
iret = conn->sendCommand(cmd.latin1());
|
|
}
|
|
return iret;
|
|
}
|
|
|
|
static const char *yZoomPix[] = {
|
|
"16 16 2 1",
|
|
" c None",
|
|
"X c #000000",
|
|
" ",
|
|
" XX ",
|
|
" XXXX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" ",
|
|
" ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XXXX ",
|
|
" XX ",
|
|
" "
|
|
};
|
|
|
|
static const char *yDownPix[] = {
|
|
"16 16 2 1",
|
|
" c None",
|
|
"X c #000000",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XXXX ",
|
|
" XX ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
};
|
|
|
|
static const char *yUpPix[] = {
|
|
"16 16 2 1",
|
|
" c None",
|
|
"X c #000000",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" XX ",
|
|
" XXXX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
" ",
|
|
};
|
|
|
|
static const char *yMaxPix[] = {
|
|
"16 16 2 1",
|
|
" c None",
|
|
"X c #000000",
|
|
" ",
|
|
"XXXXX XX XXXXX",
|
|
" XXXX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" ",
|
|
" ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XXXX ",
|
|
"XXXXX XX XXXXX",
|
|
" "
|
|
};
|
|
|
|
static const char *closePix[] = {
|
|
"16 16 2 1",
|
|
" c None",
|
|
"X c #000000",
|
|
" ",
|
|
" ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XXXX ",
|
|
" XX ",
|
|
" XXXX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" XX XX ",
|
|
" ",
|
|
" ",
|
|
" "
|
|
};
|
|
|
|
static const char *logPix[] = {
|
|
"16 16 2 1",
|
|
" c None",
|
|
"X c #000000",
|
|
" ",
|
|
" ",
|
|
" XX ",
|
|
" XX XXX XXX ",
|
|
" XX XX XX XX XX ",
|
|
" XX XX XX XXXX ",
|
|
" XX XXX XX ",
|
|
" XXX ",
|
|
" X X ",
|
|
" X XXXX ",
|
|
" X X X X ",
|
|
" X X X X ",
|
|
" X X X X ",
|
|
" ",
|
|
" ",
|
|
" "
|
|
};
|
|
|
|
static const char *linPix[] = {
|
|
"16 16 2 1",
|
|
" c None",
|
|
"X c #000000",
|
|
" ",
|
|
" ",
|
|
" X ",
|
|
" X XX XX ",
|
|
" X X X X X ",
|
|
" X X X XXX ",
|
|
" X XX X ",
|
|
" XX ",
|
|
" XX XX ",
|
|
" XX XXXXX ",
|
|
" XX XX XX XX ",
|
|
" XX XX XX XX ",
|
|
" XX XX XX XX ",
|
|
" ",
|
|
" ",
|
|
" "
|
|
};
|
|
|
|
void SeaRow::linLog() {
|
|
if (plot->toggleLinLog()) {
|
|
lBut->setPixmap(pmLog);
|
|
} else {
|
|
lBut->setPixmap(pmLin);
|
|
}
|
|
}
|
|
|
|
void SeaRow::setTag(QString tag) {
|
|
int pos;
|
|
|
|
pos = tag.findRev('_');
|
|
if (pos > 0) {
|
|
tag.truncate(pos);
|
|
}
|
|
tag.prepend(" [");
|
|
tag.append("]");
|
|
tagLabel->setText(tag);
|
|
}
|
|
|
|
SeaRow *SeaSet::newPlot(const char *name) {
|
|
QPushButton *zBut, *oBut, *uBut, *dBut, *cBut;
|
|
SeaPlot *plot;
|
|
QString txt;
|
|
int rowN = rows.count();
|
|
QPixmap pmOut(yZoomPix);
|
|
QPixmap pmMax(yMaxPix);
|
|
QPixmap pmUp(yUpPix);
|
|
QPixmap pmDown(yDownPix);
|
|
QPixmap pmClose(closePix);
|
|
|
|
SeaRow *row;
|
|
QVBox *vbox;
|
|
QBoxLayout *rowLayout, *bLayout, *vLayout;
|
|
QScrollView *scroll;
|
|
QSizePolicy narrow(QSizePolicy::Maximum, QSizePolicy::Maximum, 1, 0);
|
|
QSizePolicy wide(QSizePolicy::Expanding, QSizePolicy::Expanding, 5, 0);
|
|
//QSizePolicy high(QSizePolicy::Expanding, QSizePolicy::Expanding, 5, 10);
|
|
int w, h;
|
|
|
|
row = new SeaRow(split);
|
|
row->setFrameStyle(0);
|
|
row->hBox = new QHBox(row, "rowHbox");
|
|
rowLayout = dynamic_cast<QBoxLayout *>(row->hBox->layout());
|
|
assert(rowLayout);
|
|
row->hBox->setSpacing(6);
|
|
rowLayout->setAutoAdd(false);
|
|
|
|
row->set = this;
|
|
|
|
row->pmLog = (const char **)logPix;
|
|
row->pmLin = linPix;
|
|
|
|
split->setResizeMode(row, QSplitter::Stretch);
|
|
txt.sprintf("plot%d", rowN);
|
|
plot = new SeaPlot(row->hBox, this, txt);
|
|
plot->tag = name;
|
|
plot->setSizePolicy(wide);
|
|
row->plot = plot;
|
|
|
|
rowLayout->addWidget(plot);
|
|
|
|
vbox = new QVBox(row->hBox, "vbox");
|
|
vLayout = dynamic_cast<QBoxLayout *>(vbox->layout());
|
|
vLayout->setAutoAdd(false);
|
|
vbox->setSizePolicy(narrow);
|
|
vLayout->setAlignment(Qt::AlignTop);
|
|
|
|
rowLayout->addWidget(vbox, 0, Qt::AlignTop);
|
|
row->right = vbox;
|
|
|
|
row->bBox = new QHBox(vbox, "bBox");
|
|
bLayout = dynamic_cast<QBoxLayout *>(row->bBox->layout());
|
|
assert(bLayout);
|
|
bLayout->setAutoAdd(false);
|
|
vLayout->addWidget(row->bBox);
|
|
|
|
scroll = new QScrollView(vbox, "scroll", Qt::WNoAutoErase);
|
|
scroll->setHScrollBarMode(QScrollView::AlwaysOff);
|
|
scroll->setFrameStyle(0);
|
|
scroll->setSizePolicy(wide);
|
|
row->legScroll = scroll;
|
|
vLayout->addWidget(scroll);
|
|
|
|
row->timeLabel = new QLabel(row->right);
|
|
row->timeLabel->setText("");
|
|
vLayout->addWidget(row->timeLabel);
|
|
row->timeLabel->setFont(row->plot->axisFont(QwtPlot::xBottom));
|
|
vLayout->addStretch(1);
|
|
|
|
row->leg = new QGrid(3,scroll->viewport(),"legendGrid1");
|
|
SetEraseColor(scroll->viewport(), scroll->topLevelWidget());
|
|
row->leg->layout()->setAutoAdd(false);
|
|
scroll->addChild(row->leg);
|
|
|
|
uBut = new QPushButton(row->bBox);
|
|
uBut->setPixmap(pmUp);
|
|
bLayout->addWidget(uBut);
|
|
|
|
dBut = new QPushButton(row->bBox);
|
|
dBut->setPixmap(pmDown);
|
|
bLayout->addWidget(dBut);
|
|
|
|
oBut = new QPushButton(row->bBox);
|
|
oBut->setPixmap(pmOut);
|
|
bLayout->addWidget(oBut);
|
|
|
|
zBut = new QPushButton(row->bBox);
|
|
zBut->setPixmap(pmMax);
|
|
bLayout->addWidget(zBut);
|
|
|
|
row->lBut = new QPushButton(row->bBox);
|
|
row->lBut->setPixmap(row->pmLin);
|
|
bLayout->addWidget(row->lBut);
|
|
|
|
row->tagLabel = new QLabel(row->bBox);
|
|
row->setTag(name);
|
|
bLayout->addWidget(row->tagLabel);
|
|
|
|
bLayout->addStretch(1);
|
|
|
|
cBut = new QPushButton(row->bBox);
|
|
cBut->setPixmap(pmClose);
|
|
bLayout->addWidget(cBut);
|
|
|
|
w = QMAX(22, uBut->sizeHint().width() - 6);
|
|
h = QMAX(22, uBut->sizeHint().height() - 6);
|
|
if (w > h) { // Mac like
|
|
h += 6;
|
|
w -= 6;
|
|
}
|
|
uBut->setFixedSize(w, h);
|
|
QToolTip::add(uBut, "scroll up");
|
|
oBut->setFixedSize(w, h);
|
|
QToolTip::add(oBut, "zoom out vertically");
|
|
dBut->setFixedSize(w, h);
|
|
QToolTip::add(dBut, "scroll down");
|
|
zBut->setFixedSize(w, h);
|
|
QToolTip::add(zBut, "auto y-range");
|
|
cBut->setFixedSize(w, h);
|
|
QToolTip::add(cBut, "hide this row");
|
|
row->lBut->setFixedSize(w, h);
|
|
QToolTip::add(row->lBut, "log / lin scale");
|
|
|
|
zBut->setEnabled(false);
|
|
|
|
plot->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
|
|
rows.append(row);
|
|
connect(oBut, SIGNAL(clicked()),
|
|
plot, SLOT(zoomOut()));
|
|
connect(uBut, SIGNAL(clicked()),
|
|
plot, SLOT(shiftUp()));
|
|
connect(dBut, SIGNAL(clicked()),
|
|
plot, SLOT(shiftDown()));
|
|
connect(plot, SIGNAL(setAutoOff(bool)),
|
|
zBut, SLOT(setEnabled(bool)));
|
|
connect(zBut, SIGNAL(clicked()),
|
|
plot, SLOT(zoomMax()));
|
|
connect(cBut, SIGNAL(clicked()),
|
|
row, SLOT(hideRow()));
|
|
connect(row->lBut, SIGNAL(clicked()),
|
|
row, SLOT(linLog()));
|
|
row->leg->show();
|
|
return row;
|
|
}
|
|
|
|
void SeaSet::autoCurves(const char *vars) {
|
|
if (vars == NULL) {
|
|
autoArgDo.vars = "";
|
|
} else {
|
|
autoArgDo.vars = vars;
|
|
}
|
|
autoDo = true;
|
|
// printf("*** autoCurves\n");
|
|
}
|
|
|
|
|
|
bool SeaSet::autoCurvesP1() {
|
|
QString cmd;
|
|
int iret;
|
|
|
|
if (autoArg.vars != "" && autoArg.vars != "now") {
|
|
return false;
|
|
}
|
|
if (autoArg.vars == "now") {
|
|
cmd.sprintf("graph 0 0 text vars");
|
|
autoArg.vars = "";
|
|
} else {
|
|
cmd.sprintf("graph %ld %ld text vars", startRange, endRange);
|
|
//printf("DEBUG graph $ld %ld test vars\n", startRange, endRange);
|
|
}
|
|
iret = gc->sendCommand(cmd);
|
|
if (iret < 0) {
|
|
if (printit()) {
|
|
printf("failed autoCurves\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
// printf("*** end autoCurvesP1\n");
|
|
return true;
|
|
}
|
|
|
|
void SeaSet::autoCurvesP2() {
|
|
QString line;
|
|
int iret;
|
|
time_t now;
|
|
|
|
QString item, pName, label;
|
|
QStringList list, itemS;
|
|
QStringList::iterator its;
|
|
SeaData *d;
|
|
long style;
|
|
|
|
if (autoArg.vars == "") {
|
|
iret = gc->getLine(line);
|
|
if (iret <= 0) goto badresponse;
|
|
|
|
/* get returned absolute time */
|
|
now = line.toLong();
|
|
//sscanf(line, "%ld", &now);
|
|
|
|
iret = gc->getLine(line);
|
|
if (iret <= 0) goto badresponse;
|
|
|
|
if (!line.startsWith("*vars")) {
|
|
if (printit()) printf("missing *vars\n");
|
|
goto badresponse;
|
|
}
|
|
iret = gc->getLine(line);
|
|
if (iret <= 0) goto badresponse;
|
|
|
|
iret = line.find(' ');
|
|
if (iret >= 0) {
|
|
autoArg.vars = line.mid(iret).stripWhiteSpace();
|
|
}
|
|
|
|
base = 0; // force calcBase
|
|
|
|
} else {
|
|
time(&now);
|
|
line = autoArg.vars;
|
|
}
|
|
if (base == 0) {
|
|
if (startRange < 0) {
|
|
startRange += now;
|
|
}
|
|
calcBase(startRange);
|
|
if (endRange <= ONE_YEAR) {
|
|
endRange += now;
|
|
}
|
|
}
|
|
clrDataList();
|
|
while (!line.startsWith("*")) {
|
|
iret = line.find(' ');
|
|
if (iret >= 0) {
|
|
list = QStringList::split(" ", line.mid(iret));
|
|
for (its = list.end(); its != list.begin(); ) {
|
|
its--;
|
|
item = *its;
|
|
if (item.contains('|')) {
|
|
itemS = QStringList::split("|", item, TRUE);
|
|
} else {
|
|
itemS = QStringList::split("/", item, TRUE);
|
|
}
|
|
style = -1;
|
|
if (itemS.count() > 1) {
|
|
pName = itemS[1];
|
|
item = itemS[0];
|
|
if (itemS.count() > 2) {
|
|
if (itemS.count() > 3) {
|
|
style = Convert2ColorIndex(itemS[3]);
|
|
if (style < -1) {
|
|
style = -1; // set bad colors to auto
|
|
}
|
|
}
|
|
label = itemS[2];
|
|
} else {
|
|
label = item;
|
|
}
|
|
} else {
|
|
pName = "";
|
|
label = item;
|
|
}
|
|
if (pName == 0) {
|
|
pName = "";
|
|
}
|
|
d = findData(item);
|
|
if (d) {
|
|
dataList.remove(d);
|
|
d->plotName = pName;
|
|
d->clr = false;
|
|
//d->bold = true;
|
|
d->label = label;
|
|
d->style = style;
|
|
} else {
|
|
d = new SeaData(item, label, pName, style);
|
|
getBoldState(d);
|
|
}
|
|
dataList.prepend(d);
|
|
}
|
|
}
|
|
if (autoArg.vars != "") break;
|
|
iret = gc->getLine(line);
|
|
if (iret <= 0) goto badresponse;
|
|
};
|
|
//printf("DEBUG end graph\n");
|
|
if (prt) {
|
|
printf("reading curves,\n");
|
|
}
|
|
// printf("*** start finishDataList\n");
|
|
finishDataList();
|
|
// printf("*** end autoCurvesP2\n");
|
|
return; // 0
|
|
badresponse:
|
|
if (printit()) {
|
|
if (iret > 0) {
|
|
printf("syntax error in response %s\n", line.latin1());
|
|
} else if (iret == 0) {
|
|
printf("early end of response\n");
|
|
} else if (iret == -2) {
|
|
printf("timeout on sics connection\n");
|
|
} else {
|
|
printf("error on response\n");
|
|
}
|
|
}
|
|
return; // -1
|
|
}
|
|
|
|
void SeaSet::getCurves(bool all, time_t from, time_t to) {
|
|
getArgDo.all = all;
|
|
getArgDo.append = false;
|
|
getArgDo.from = from;
|
|
getArgDo.to = to;
|
|
getDo = true;
|
|
}
|
|
|
|
int SeaSet::getCurvesP1() {
|
|
QString cmd;
|
|
int iret, cnt;
|
|
SeaData *d;
|
|
|
|
// printf("*** do getCurvesP1\n");
|
|
|
|
if (getArg.from == getArg.to) {
|
|
getArg.from = startRange;
|
|
getArg.to = endRange;
|
|
}
|
|
cnt = 0;
|
|
if (getArg.append) {
|
|
curveStep = 1;
|
|
} else {
|
|
curveStep = long(getArg.to - getArg.from) / xSize + 1;
|
|
}
|
|
cmd.sprintf("graph %ld %ld np %d", getArg.from, getArg.to, xSize);
|
|
for (d = dataList.first(); d != 0; dataList.findRef(d), d = dataList.next()) {
|
|
if ((d->dirty || getArg.all) && d->row->state != hiddenRow) {
|
|
cmd.append(" ");
|
|
cmd.append(d->name);
|
|
cnt++;
|
|
}
|
|
}
|
|
if (cnt == 0) {
|
|
// printf("*** no data\n");
|
|
return 0;
|
|
}
|
|
//printf("*** %s\n", cmd.latin1());
|
|
iret = gc->sendCommand(cmd);
|
|
return 1;
|
|
}
|
|
|
|
void SeaSet::getCurvesP2() {
|
|
QString line;
|
|
int iret, siz;
|
|
time_t t, dt, tmax;
|
|
SeaData *d;
|
|
int iperiod;
|
|
bool ok;
|
|
|
|
// printf("*** do getCurvesP2\n");
|
|
assert(async_mode == async_get);
|
|
|
|
iret = gc->getLine(line);
|
|
if (iret <= 0) goto badresponse;
|
|
//printf("> %s\n", line);
|
|
|
|
/* get returned absolute time */
|
|
lastRead = line.toLong();
|
|
|
|
iret = gc->getLine(line);
|
|
if (iret <= 0) goto badresponse;
|
|
//printf("> %s\n", line.latin1());
|
|
if (!line.startsWith("*")) goto badresponse;
|
|
|
|
tmax = 0;
|
|
for (d = dataList.first(); d != 0; dataList.findRef(d), d = dataList.next()) {
|
|
if ((d->dirty || getArg.all) && d->row->state != hiddenRow) {
|
|
d->dirty = false;
|
|
d->period = 1;
|
|
iret = line.find(' ');
|
|
if (iret >= 0) {
|
|
iperiod = line.find("period", iret);
|
|
if (iperiod >= iret) {
|
|
d->period = line.mid(iperiod + 7).toLong();
|
|
}
|
|
//if (period) {
|
|
// sscanf(period, "period %lf", &d->period);
|
|
//}
|
|
line = line.left(iret);
|
|
}
|
|
if (d->name == line.mid(1)) {
|
|
t = 0;
|
|
if (!getArg.append) {
|
|
d->init(curveStep, xSize*2);
|
|
}
|
|
siz = 0;
|
|
while (1) {
|
|
iret = gc->getLine(line);
|
|
if (iret <= 0) goto badresponse;
|
|
//printf("> %s\n", line);
|
|
if (line.startsWith("*")) break;
|
|
/* decode line to x[n] / y[n] */
|
|
dt = line.section(' ', 0, 0).toLong(&ok);
|
|
//cnt = sscanf(line, "%ld %n", &dt, &pos);
|
|
//if (cnt < 1) {
|
|
if (!ok) {
|
|
if (printit()) printf("bad timestep %s\n", line.latin1());
|
|
goto badresponse;
|
|
}
|
|
t += dt;
|
|
siz = d->addValue(double(t - base), line.section(' ', 1));
|
|
}
|
|
d->showValueAt(markerPos);
|
|
if (siz < 0) {
|
|
if (printit()) printf("overflow\n");
|
|
if (t < endRange) endRange = t;
|
|
// } else if (siz > d->size - 5) {
|
|
// if (t < endRange) endRange = t;
|
|
}
|
|
tmax = QMAX(tmax, t);
|
|
if (d->update() && getArg.append) {
|
|
refresh = 1; //ref
|
|
}
|
|
}
|
|
//printf("DEBUG end line %s\n", line.latin1());
|
|
}
|
|
}
|
|
lastTime = tmax - base;
|
|
if (markerPos == DATA_UNDEF) {
|
|
setTimeLabel(lastTime);
|
|
}
|
|
if (!getArg.append) {
|
|
compressed = line.mid(1,1) != '0';
|
|
//printf("*** compressed %d\n", compressed);
|
|
}
|
|
iret = gc->getLine(line);
|
|
//printf("> %s\n", line.latin1());
|
|
if (iret != 0) {
|
|
if (printit()) printf("missing end\n");
|
|
}
|
|
// printf("*** end getCurves\n");
|
|
if (!showPlot) {
|
|
showAll();
|
|
showPlot = true;
|
|
}
|
|
QTimer::singleShot(0, this, SLOT(replot()));
|
|
return; // 1
|
|
|
|
badresponse:
|
|
if (printit()) {
|
|
if (iret > 0) {
|
|
printf("syntax error in response %s\n", line.latin1());
|
|
} else if (iret == 0) {
|
|
printf("early end of response\n");
|
|
} else if (iret == -2) {
|
|
printf("timeout on sics connection\n");
|
|
} else {
|
|
printf("error on response\n");
|
|
}
|
|
}
|
|
return; // -1
|
|
}
|
|
|
|
|
|
void SeaSet::asyncHandler() {
|
|
int msec;
|
|
if ((msec=meas.restart()) > 100) {
|
|
// printf("%d msec\n", msec);
|
|
}
|
|
if (async_mode == async_idle) {
|
|
if (autoDo) {
|
|
autoArg = autoArgDo;
|
|
autoDo = false;
|
|
if (autoCurvesP1()) {
|
|
async_mode = async_auto;
|
|
tmot.start();
|
|
} else {
|
|
autoCurvesP2();
|
|
}
|
|
} else if (getDo) {
|
|
getArg = getArgDo;
|
|
if (getCurvesP1() == 0) {
|
|
async_mode = async_idle;
|
|
} else {
|
|
async_mode = async_get;
|
|
tmot.start();
|
|
}
|
|
getDo = false;
|
|
if (getArg.all) {
|
|
reread = false;
|
|
}
|
|
} else if (getNewData) {
|
|
getArg.append = true;
|
|
getArg.all = true;
|
|
getArg.from = lastRead;
|
|
getArg.to = 0;
|
|
getNewData = false;
|
|
// printf("*** getCurvesP1\n");
|
|
if (getCurvesP1() == 0) {
|
|
async_mode = async_idle;
|
|
} else {
|
|
async_mode = async_get;
|
|
tmot.start();
|
|
}
|
|
} else if (reread) {
|
|
getCurves(true, startRange, endRange);
|
|
reread = false;
|
|
}
|
|
}
|
|
if (async_mode == async_auto) {
|
|
if (tmot.elapsed() > 10000) {
|
|
if (printit()) printf("autoCurves timeout\n");
|
|
gc->reconnect();
|
|
tmot.start();
|
|
async_mode = async_idle;
|
|
return;
|
|
}
|
|
if (gc->handleBuffer(0) <= 0) return;
|
|
if (gc->getResponse() < 0) {
|
|
if (printit()) printf("autoCurves2 timeout\n");
|
|
gc->reconnect();
|
|
async_mode = async_idle;
|
|
return;
|
|
}
|
|
// printf("*** start autoCurvesP2\n");
|
|
autoCurvesP2();
|
|
async_mode = async_idle;
|
|
}
|
|
if (async_mode == async_get) {
|
|
if (tmot.elapsed() > 10000) {
|
|
if (printit()) printf("getCurves timeout\n");
|
|
tmot.start();
|
|
gc->reconnect();
|
|
async_mode = async_idle;
|
|
return;
|
|
}
|
|
if (gc->handleBuffer(0) <= 0) return;
|
|
if (gc->getResponse() < 0) {
|
|
// printf("*** again getCurvesP1\n");
|
|
if (printit()) printf("getCurves2 timeout\n");
|
|
gc->reconnect();
|
|
async_mode = async_idle;
|
|
return;
|
|
}
|
|
// printf("*** start getCurvesP2\n");
|
|
getCurvesP2();
|
|
async_mode = async_idle;
|
|
}
|
|
}
|
|
|
|
void SeaSet::calcLeftLabelWidth() {
|
|
SeaRow *row;
|
|
|
|
labelMode = 2; // set to max mode
|
|
labelWidth = 0;
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
if (row->state != hiddenRow) {
|
|
// force recursive calls for all labels on all plots
|
|
row->plot->axis(QwtPlot::yLeft)->minimumSizeHint();
|
|
}
|
|
}
|
|
if (labelWidth == 0) {
|
|
labelWidth = 30;
|
|
}
|
|
labelMode = 1; // set to cached mode
|
|
}
|
|
|
|
int SeaSet::leftLabelWidth(int in) {
|
|
|
|
if (prt == 1) {
|
|
setprintit(0);
|
|
}
|
|
if (labelMode == 2) { // max (calc) mode
|
|
if (in > labelWidth) labelWidth = in;
|
|
// printf("*** in %d\n", in);
|
|
return in;
|
|
}
|
|
if (labelMode == 1) { // cached mode
|
|
// printf("*** lwc %d\n", labelWidth + 4);
|
|
return labelWidth + 4;
|
|
}
|
|
calcLeftLabelWidth();
|
|
labelMode = 1; // set to cached mode
|
|
// printf("*** lw %d\n", labelWidth);
|
|
return labelWidth;
|
|
}
|
|
|
|
void SeaSet::showAll() {
|
|
SeaRow *row;
|
|
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
if (getRowHeight(row) == 0) {
|
|
saveRowHeight(row, -1);
|
|
}
|
|
row->state = shownRow;
|
|
row->hBox->show();
|
|
row->right->show();
|
|
if (showPlot) row->plot->showAgain();
|
|
}
|
|
adjustSizes();
|
|
readNewReplot();
|
|
}
|
|
|
|
void SeaSet::shiftLeft() {
|
|
long w;
|
|
saveRange();
|
|
w = (endRange - startRange) * 3 / 4;
|
|
rescale(startRange - w, endRange - w);
|
|
}
|
|
|
|
void SeaSet::shiftRight() {
|
|
long w;
|
|
saveRange();
|
|
w = (endRange - startRange) * 3 / 4;
|
|
rescale(startRange + w, endRange + w);
|
|
}
|
|
|
|
void SeaSet::zoomOutX() {
|
|
long w;
|
|
time_t s, t;
|
|
|
|
saveRange();
|
|
w = endRange - startRange;
|
|
if (w > SEA_MAX_RANGE/2) w = SEA_MAX_RANGE/2;
|
|
if (startRange <= 0) {
|
|
rescaleRange(w * 2);
|
|
} else {
|
|
if (liveTime < base) {
|
|
t = time(NULL);
|
|
} else {
|
|
t = liveTime;
|
|
}
|
|
if (endRange + w/2 > t + MAX_FUTURE) {
|
|
s = t + MAX_FUTURE - w * 2;
|
|
} else {
|
|
s = startRange - w / 2;
|
|
}
|
|
rescale(s, s + w * 2);
|
|
}
|
|
}
|
|
|
|
void SeaSet::saveRange() {
|
|
undoEnabled(true);
|
|
undoPlot = 0;
|
|
undoStart = startRange;
|
|
undoEnd = endRange;
|
|
}
|
|
|
|
void SeaSet::saveRange(SeaPlot *plot, QwtDoubleRect &old, bool yAuto) {
|
|
saveRange();
|
|
undoPlot = plot;
|
|
undoAuto = yAuto;
|
|
undoRect = old;
|
|
}
|
|
|
|
void SeaSet::undoZoom() {
|
|
if (undoPlot) {
|
|
undoPlot->undoZoom(undoRect);
|
|
undoPlot->autoZoom(undoAuto);
|
|
}
|
|
if (undoStart != 0) {
|
|
rescale(undoStart, undoEnd);
|
|
}
|
|
undoStart = 0;
|
|
undoPlot = 0;
|
|
undoEnabled(false);
|
|
}
|
|
|
|
void SeaSet::liveUpdate() {
|
|
if (live == liveOn) {
|
|
if (endRange < ONE_YEAR) {
|
|
endRange += lastRead;
|
|
}
|
|
if (startRange < ONE_YEAR) {
|
|
startRange += lastRead;
|
|
}
|
|
if (lastRead >= endRange) {
|
|
endRange += QMIN(MAX_FUTURE, (endRange - startRange)/2);
|
|
getCurves(true, startRange, endRange);
|
|
} else {
|
|
getNewData = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SeaSet::replot() {
|
|
if (refresh <= 0) return;
|
|
replotAnyway();
|
|
refresh--;
|
|
if (refresh > 0) {
|
|
QTimer::singleShot(0, this, SLOT(replot()));
|
|
}
|
|
}
|
|
|
|
void SeaSet::replotAnyway() {
|
|
float xrange;
|
|
float tick;
|
|
SeaPlot *plot;
|
|
SeaRow *row;
|
|
static long steps[]={30,60,
|
|
2*60,5*60,10*60,30*60,
|
|
3600,2*3600,3*3600,6*3600,24*3600,
|
|
0};
|
|
int i;
|
|
double x1, x2;
|
|
SeaData *d;
|
|
int lw;
|
|
int maxpos;
|
|
double y;
|
|
char txt[16], *pos;
|
|
SeaCurve *crv;
|
|
|
|
x1 = startRange - base;
|
|
x2 = endRange - base;
|
|
xrange = x2 - x1;
|
|
for (i=0; steps[i] > 0; i++) {
|
|
tick = steps[i];
|
|
if (xrange < tick*MAX_LABELS) break;
|
|
}
|
|
|
|
legendWidth = 50;
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
plot = row->plot;
|
|
i = plot->replotRange(x1, x2, tick);
|
|
QwtPlotCurveIterator itc = plot->curveIterator();
|
|
maxpos = 0;
|
|
for (QwtPlotCurve *c = itc.toFirst(); c != 0; c = ++itc ) {
|
|
crv = (dynamic_cast<SeaCurve *>(c));
|
|
if (crv) {
|
|
d = crv->data;
|
|
if (d->size_m > 0) {
|
|
y = d->y[d->size_m-1];
|
|
snprintf(txt, sizeof(txt), "%1.5g", y);
|
|
pos = strchr(txt, '.');
|
|
if (pos == 0) {
|
|
pos = txt + strlen(txt);
|
|
}
|
|
maxpos = QMAX(maxpos, (pos - txt));
|
|
}
|
|
}
|
|
}
|
|
for (QwtPlotCurve *c = itc.toFirst(); c != 0; c = ++itc ) {
|
|
crv = (dynamic_cast<SeaCurve *>(c));
|
|
if (crv) {
|
|
d = crv->data;
|
|
d->decipos = maxpos + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
lw = labelWidth;
|
|
calcLeftLabelWidth();
|
|
if (labelWidth != lw) {
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
if (row->state != hiddenRow) {
|
|
((QWidget *)row->plot->axis(QwtPlot::yLeft))->updateGeometry();
|
|
}
|
|
}
|
|
}
|
|
|
|
//layout->activate();
|
|
|
|
// printf("*** end replot\n");
|
|
if (prt) prt = 1;
|
|
}
|
|
|
|
void SeaSet::hideRow() {
|
|
SeaRow *row;
|
|
int rowN = 0, firstRow = -1, tot = 0;
|
|
QValueList<int> sizes;
|
|
|
|
sizes = split->sizes();
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
if (row->hBox->isHidden()) {
|
|
tot += sizes[rowN];
|
|
sizes[rowN] = 0;
|
|
} else if (firstRow < 0) {
|
|
firstRow = rowN;
|
|
}
|
|
rowN ++;
|
|
}
|
|
if (firstRow < 0) {
|
|
firstRow = 0;
|
|
}
|
|
sizes[firstRow] += tot;
|
|
split->setSizes(sizes);
|
|
}
|
|
|
|
void SeaSet::calcBase(time_t from) {
|
|
struct tm basetm;
|
|
// calculate new base
|
|
// printf("*** calc base %ld\n", from);
|
|
if (from <= 0) {
|
|
from += time(NULL);
|
|
}
|
|
basetm = *localtime(&from);
|
|
basetm.tm_hour = 0;
|
|
basetm.tm_min = 0;
|
|
basetm.tm_sec = 0;
|
|
base = mktime(&basetm);
|
|
}
|
|
|
|
void SeaSet::rescale(time_t from, time_t to) {
|
|
|
|
if (to < lastRead && live == liveOn) {
|
|
live = liveAuto;
|
|
}
|
|
if (from < startRange || to > endRange
|
|
|| (compressed && (from != startRange || to != endRange))) {
|
|
reread = true;
|
|
}
|
|
startRange = from;
|
|
endRange = to;
|
|
if ((to > lastRead || (to >= 0 && to < SEA_MAX_RANGE)) && live == liveAuto) {
|
|
live = liveOn;
|
|
}
|
|
|
|
replotAnyway();
|
|
|
|
if (from < base || from > base + 30*3600) {
|
|
calcBase(from);
|
|
reread = true;
|
|
}
|
|
|
|
if (reread) {
|
|
getCurves(true, from, to);
|
|
} else {
|
|
getCurves(false, startRange, endRange);
|
|
}
|
|
refresh = 2;
|
|
reread = false;
|
|
}
|
|
|
|
void SeaSet::rescaleRange(time_t range) {
|
|
time_t t1, t2, now;
|
|
|
|
undoStart = 0;
|
|
undoPlot = 0;
|
|
undoEnabled(false);
|
|
|
|
now = time(NULL);
|
|
|
|
t1 = - QMIN(SEA_MAX_RANGE, QMAX(60, range));
|
|
if (live != liveOff) {
|
|
t2 = QMIN(MAX_FUTURE, range / 2);
|
|
} else {
|
|
t2 = 1;
|
|
}
|
|
startRange = t1 + now;
|
|
endRange = t2 + now;
|
|
replotAnyway();
|
|
|
|
calcBase(now - range - 4000);
|
|
|
|
getCurves(true, t1, t2);
|
|
startRange = t1 + lastRead;
|
|
endRange = t2 + lastRead;
|
|
if (live == liveAuto) live = liveOn;
|
|
refresh = 2;
|
|
}
|
|
|
|
// called on zoom:
|
|
void SeaSet::rescale(double x1, double x2) {
|
|
rescale(base + (long)(x1), base + (long)(x2));
|
|
}
|
|
|
|
void SeaSet::readNewReplot() {
|
|
// if (live == liveAuto) live = liveOn;
|
|
getCurves(false, startRange, endRange);
|
|
refresh = 2;
|
|
}
|
|
|
|
void SeaSet::runningMarkerOff(bool beforeEvent) {
|
|
// before and after a MousePress, MouseDblClick or KeyPress event
|
|
// the marker is set off
|
|
// markerWasOn is set accordingly
|
|
// if clicked inside a plot, SeaPlotZommer will then set the marker with a MouseReleaseEvent
|
|
if (markerPos == DATA_UNDEF) {
|
|
markerWasOn = false;
|
|
} else {
|
|
markerWasOn = beforeEvent;
|
|
if (!markerFix) {
|
|
setMarker(DATA_UNDEF);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SeaSet::setTimeLabel(double x) {
|
|
QString tstr;
|
|
QTime time;
|
|
|
|
if (firstRow != 0) {
|
|
if (x == DATA_UNDEF) {
|
|
firstRow->timeLabel->setText("");
|
|
} else {
|
|
time.setHMS(0,0,0);
|
|
tstr = dateLabel(floor(x/(24*3600)));
|
|
tstr += " " + time.addSecs(floor(x)).toString("hh:mm");
|
|
firstRow->timeLabel->setText(tstr);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SeaSet::setMarker(double x) {
|
|
SeaRow *row;
|
|
SeaPlot *plot;
|
|
|
|
if (x != DATA_UNDEF) {
|
|
if (x < startRange - base) {
|
|
x = startRange - base;
|
|
} else if (x > endRange - base) {
|
|
x = endRange - base;
|
|
}
|
|
}
|
|
markerPos = x;
|
|
for (row = rows.first(); row != 0; rows.findRef(row), row = rows.next()) {
|
|
plot = row->plot;
|
|
plot->setMarker(x);
|
|
plot->replot();
|
|
}
|
|
if (x == DATA_UNDEF) {
|
|
setTimeLabel(lastTime);
|
|
} else {
|
|
setTimeLabel(x);
|
|
}
|
|
}
|
|
|
|
void SeaSet::setMarker(time_t t) {
|
|
if (t == 0) {
|
|
setMarker(DATA_UNDEF);
|
|
} else {
|
|
setMarker((double)(t - base));
|
|
}
|
|
}
|
|
|
|
void SeaSet::gotoTime(double at, bool silent) {
|
|
gotoTime(startRange, base + (long)at, endRange, silent);
|
|
}
|