Files
seaclient/device.cpp

1459 lines
34 KiB
C++

#include "device.h"
#include <qapplication.h>
#include <qdialog.h>
#include <qpushbutton.h>
#include <qtooltip.h>
#include <qcheckbox.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qlayout.h>
#include <qwhatsthis.h>
#include <qvalidator.h>
#include <qptrstack.h>
#include <stdio.h>
#include <qpixmap.h>
#include <qtimer.h>
#include <qvaluelist.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qlistbox.h>
#include <math.h>
#include <stdlib.h>
#include "utils.h"
static const char *rPix[] = {
"10 10 2 1",
" c None",
"X c #0000CC",
"XX ",
"XXXX ",
"XXXXXX ",
"XXXXXXXX ",
"XXXXXXXXXX",
"XXXXXXXXXX",
"XXXXXXXX ",
"XXXXXX ",
"XXXX ",
"XX ",
};
static const char *dPix[] = {
"10 10 2 1",
" c None",
"X c #0000CC",
"XXXXXXXXXX",
"XXXXXXXXXX",
" XXXXXXXX ",
" XXXXXXXX ",
" XXXXXX ",
" XXXXXX ",
" XXXX ",
" XXXX ",
" XX ",
" XX ",
};
/*
static const char *grPix[] = {
"16 12 4 1",
" c None",
"/ c #CC0000",
"- c #0000CC",
"X c #000000",
"XXXXXXXXXXXXXXXX",
"X X",
"X X",
"X - X",
"X ---- X",
"X -- ----- X",
"X ---- ----X",
"X----- -X",
"X-- X",
"X X",
"X X",
"XXXXXXXXXXXXXXXX",
};
static const char *gnPix[] = {
"16 12 4 1",
" c None",
"/ c #CC0000",
"- c #0000CC",
"X c #000000",
"X//XXXXXXXXXX//X",
"X // // X",
"X // // X",
"X // - // X",
"X //--// X",
"X ////---- X",
"X ----// ----X",
"X-----//// -X",
"X-- // // X",
"X // // X",
"X // // X",
"XX//XXXXXXXX//XX",
};
*/
static int lineEditFrameWidth = 0;
LineInput::LineInput(QWidget *parent, QString &labelTxt, const char *var) : QHBox(parent, var), value("") {
QBoxLayout *l = dynamic_cast<QBoxLayout *>(layout());
l->setAutoAdd(false);
label = new QLabel(labelTxt, this);
label->setAlignment(Qt::AlignRight);
l->addWidget(label);
le = new QLineEdit(this, var);
connect(le, SIGNAL(returnPressed()), this, SLOT(handleReturn()));
connect(le, SIGNAL(lostFocus()), this, SLOT(focusLost()));
QFont monospace("Courier");
monospace.setStyleHint(QFont::TypeWriter);
le->setFont(monospace);
l->addWidget(le);
l->setSpacing(6);
}
void LineInput::setLength(int l) {
QFontMetrics fm = le->fontMetrics();
if (l==0) {
l = 9;
}
if (l <= 9) {
le->setAlignment(Qt::AlignRight);
} else {
le->setAlignment(Qt::AlignLeft);
}
lineEditFrameWidth = le->frameWidth();
le->setFixedWidth(fm.width("0") * l + 2 * lineEditFrameWidth + 4);
}
int LineInput::stdWidth() {
QBoxLayout *l = dynamic_cast<QBoxLayout *>(layout());
setLength(0);
l->activate();
return label->width() + l->spacing() + 2 * l->margin() + le->width();
}
void LineInput::handleReturn() {
QString c(name());
if (le->text().isEmpty()) {
c.append(" \"\"");
} else {
c.append(" ");
c.append(le->text());
}
sendCmd(c.latin1());
value = le->text();
changed();
}
void LineInput::focusLost() {
if (value.compare(le->text()) != 0) {
handleReturn();
}
}
void LineInput::setValue(const QString &value) {
if ((this->value.compare(le->text()) == 0) && this->value.compare(value) != 0) {
le->setText(value);
this->value = value;
}
}
void LineInput::setEraseColor(const QColor & color) {
QHBox::setEraseColor(color);
label->setEraseColor(color);
label->setEraseColor(color);
}
RdOnly::RdOnly(QWidget *parent, QString &labelTxt, QString &val, const char *var) : QHBox(parent, var) {
QBoxLayout *l = dynamic_cast<QBoxLayout *>(layout());
l->setAutoAdd(false);
label = new QLabel(labelTxt, this);
value = new QLabel(val, this);
QFont monospace("Courier");
monospace.setStyleHint(QFont::TypeWriter);
value->setFont(monospace);
label->setAlignment(Qt::AlignRight);
value->setAlignment(Qt::AlignRight);
l->addWidget(label);
l->addWidget(value);
l->setSpacing(6);
len = 9;
}
void RdOnly::setLength(int l) {
QFontMetrics fm = value->fontMetrics();
if (l==0) {
l = 9;
}
len = l;
if (l <= 9) {
value->setAlignment(Qt::AlignRight);
} else {
value->setAlignment(Qt::AlignLeft);
}
value->setFixedWidth(fm.width("0") * l + 2 * lineEditFrameWidth + 4);
}
void RdOnly::setValue(const QString &val) {
bool ok;
double f;
int p, i;
QString v, ve;
if (val.length() <= len) {
// length is ok
value->setText(val);
return;
}
f = val.stripWhiteSpace().toDouble(&ok);
if (!ok) {
// it's not a number
value->setText(val);
return;
}
// try to reduce the length by reducing the precision
for (p = 6; p > 0; p--) {
v.setNum(f, 'g', p);
i = v.find('e');
if (i >= 0) {
i++;
if (v[i] == '-') {
i++;
} else if (v[i] == '+') {
// skip + in exponent
v.remove(i,1);
}
if (v[i] == '0') {
// skip leading 0 in exponent
v.remove(i,1);
}
}
if (v.length() <= len) {
value->setText(v);
return;
}
}
value->setText(v);
}
CheckBox::CheckBox(const QString &label, QWidget *parent, const char *var)
: QCheckBox(label, parent, var) {
connect(this, SIGNAL(clicked()), this, SLOT(handleReturn()));
}
void CheckBox::handleReturn() {
QString c(name());
if (isOn()) {
c.append(" 1");
} else {
c.append(" 0");
}
sendCmd(c.latin1());
changed();
}
void CheckBox::setValue(const QString &value) {
if (value[0] == '0' || value[0] <= ' ') {
if (isOn()) {
setChecked(false);
}
} else {
if (!isOn()) {
setChecked(true);
}
}
}
ClickButton::ClickButton(QWidget *parent, const char *var)
: QPushButton(parent, var) {
dx = 0;
}
void ClickButton::handleReturn() {
setFocus();
sendCmd(name());
changed();
}
void ClickButton::setLabel(const QString &label) {
QFontMetrics fm = fontMetrics();
if (dx == 0) {
setText("BUTTON");
dx = (width() - fm.width("BUTTON")) / 3;
}
setText(label);
setMaximumWidth(fm.width(text()) + dx);
}
RadioButton::RadioButton(const QString &label, QWidget *parent,
const QString &cmdArg, const char *value) : QRadioButton(label, parent, value)
{
cmd = cmdArg;
connect(this, SIGNAL(clicked()), this , SLOT(handleClick()));
}
void RadioButton::handleClick() {
QString c(cmd);
c.append(" ");
c.append(name());
sendCmd(c.latin1());
clearOthers(name());
changed();
setFocus();
}
void RadioButton::setValue(const QString &value) {
setChecked(value.compare(name()) == 0);
}
void ColorMenu::init() {
const QPixmap *pixmap;
int i;
setEditable(true);
listBox()->setRowMode(QListBox::FitToHeight);
insertItem(QString("auto"), 0);
for (i=1; i < 16; i++) {
pixmap = thisPixmap(i);
if (pixmap == NULL) {
i = -1;
break;
}
insertItem(*pixmap, i);
}
connect(this, SIGNAL(activated(int)),
this, SLOT(handleAct(int)));
}
ColorMenu::ColorMenu(QString &color, QWidget *parent)
: QComboBox(parent, "settings")
{
init();
setCurrentItem(0);
setCurrentText(color);
}
ColorMenu::ColorMenu(QWidget *parent, const char *var)
: QComboBox(parent, var)
{
init();
nochange = true;
setCurrentItem(0);
setCurrentText("");
nochange = false;
setLength(0);
value = "";
connect(this, SIGNAL(textChanged(const QString &)),
this, SLOT(handleChange(const QString &)));
}
void ColorMenu::handleAct(int index) {
QString text;
// printf("*** handleAct %d\n", index);
if (index > 0 && index < 16) {
Convert2ColorName(index, text);
nochange = true;
setCurrentItem(0);
nochange = false;
value = text;
setCurrentText(text);
}
// printf("*** handleAct end\n");
}
void ColorMenu::setValue(const QString &text) {
if (value.compare(currentText()) == 0 && value.compare(text) != 0) {
// printf("*** setValue %s -> %s\n", value.latin1(), text.latin1());
nochange = true;
setCurrentItem(0);
value = text;
setCurrentText(text);
nochange = false;
}
}
void ColorMenu::handleChange(const QString &text) {
QString c(name());
int index;
// printf("*** nochange %d empty %d\n", nochange, (text == ""));
if (nochange || text == "") return;
index = Convert2ColorIndex(text);
if (index < -1) return; // not a valid text
value = text;
// printf("*** handleChange %s\n", text.latin1());
c.append(" ");
c.append(text);
sendCmd(c.latin1());
changed();
}
int ColorMenu::getColorIndex() {
int index = Convert2ColorIndex(currentText());
if (index < -1) {
index = -1;
}
return index;
}
void ColorMenu::setLength(int min, int max) {
QFontMetrics fm = fontMetrics();
if (min == 0) {
min = 10;
}
if (max < min) {
max = min;
}
setMinimumWidth(fm.width("0") * min + 8);
setMaximumWidth(fm.width("0") * max + 8);
}
Menu::Menu(const QString &label, QWidget *parent, const char *var)
: QComboBox(parent, var)
{
connect(this, SIGNAL(activated(const QString &)),
this, SLOT(handleAct(const QString &)));
}
void Menu::handleAct(const QString &value) {
QString c(name());
c.append(" ");
c.append(value);
sendCmd(c.latin1());
changed();
}
void Menu::setValue(const QString &value) {
setCurrentText(value);
}
/*
GraphButton::GraphButton(QWidget *parent, const char *name)
: QPushButton(parent, name)
{
setFlat(true);
setPixmap(QPixmap(grPix));
connect(this, SIGNAL(clicked()), this, SLOT(handleClick()));
setFixedSize(24,20);
hide();
}
void GraphButton::handleClick() {
selectItem(name());
changed();
}
*/
bool PathStartsWith(QString &path, const char *name) {
if (path.startsWith(name)) {
int l = strlen(name);
// if (path.length(name) == l || path[l] == '/') return true;
if (path[l] == 0 || path[l] == '/') return true;
}
return false;
}
void Group::init() {
indent = 0;
isSelectMenu = false;
colDiv = 1;
}
Group::Group(Device *p, const char *name, bool selectMenu)
: QVBox(p->viewport(), name)
, items(101,false)
{
//title = new QLabel("Title", this);
//boxLayout->addWidget(title);
parentGroup = 0;
device = p;
init();
arrow = 0;
shown=true;
title = 0;
isSelectMenu = selectMenu;
autoclose = false;
}
Group::Group(Group *p, const QString &tit, const char *name)
: QVBox(p->device->viewport(), name)
, items(101,false)
{
QFont bold;
QBoxLayout *lay;
parentGroup = p;
device = p->device;
init();
isSelectMenu = p->isSelectMenu;
if (tit.isEmpty()) {
arrow = 0;
shown = true;
} else {
title = new QLabel(tit, this);
lay = dynamic_cast<QBoxLayout *>(layout());
lay->setAutoAdd(false);
lay->add(title);
lay->addStretch(1);
setFrameStyle(QFrame::MenuBarPanel);
indent = p->indent + 20;
arrow = new QPushButton(this, "arrow");
arrow->setFlat(true);
SetEraseColor(arrow, topLevelWidget(), true);
arrow->setPixmap(QPixmap(rPix));
arrow->setFixedSize(16, 16);
bold = font();
bold.setWeight(75);
setFont(bold);
connect(arrow, SIGNAL(clicked()), this, SLOT(toggle()));
shown=false;
}
}
void Group::showIt(bool yes) {
shown = yes;
if (arrow) { // && arrow->isShown()) {
if (shown) {
arrow->setPixmap(QPixmap(dPix));
} else {
arrow->setPixmap(QPixmap(rPix));
}
}
}
void Group::newline() {
device->x = indent;
device->y = device->nextY;
}
void Group::add(Item *item, QWidget *w) {
int frac, offs, hei, wid;
QFont font;
if (w == 0) w = item->w;
if (wStyle != item->wStyle) {
switch (item->wStyle) {
case 0:
item->normalFont = w->font();
case 'W': // remove warning style
case 'A': // remove warning style
// case 'G': // remove graph settings style
w->setEraseColor(eraseColor());
break;
case 'H': // remove header style
w->setFont(item->normalFont);
}
switch (wStyle) {
case 'W': // warning: yellow background
w->setEraseColor(QColor(255,255,0));
break;
case 'A': // warning: orange background
w->setEraseColor(QColor(255,127,0));
break;
// case 'G': // graph settings: grey background
// w->setEraseColor(QColor(150,150,150));
// break;
case 'H': // header style
font = item->normalFont;
font.setWeight(QFont::Normal);
if (font.pointSize() > 0) {
font.setPointSize(font.pointSize() * 6 / 4);
} else {
font.setPixelSize(font.pixelSize() * 6 / 4);
}
w->setFont(font);
}
item->wStyle = wStyle;
}
wStyle = 0;
//printf("%s: add %s/%s %d\n", name(), w->className(), w->name(), sameRow);
if (!sameRow) {
frac = (device->x - indent) % (device->columnWidth / colDiv);
device->x -= frac;
if (frac > device->xspace / 2) {
device->x += device->columnWidth / colDiv;
}
}
if (item->w->layout()) {
item->w->layout()->activate();
}
w->resize(w->sizeHint());
wid = w->width();
hei = w->height();
if (device->x + wid > device->visibleWidth()) {
newline();
}
device->x += device->xspace;
if (hei >= device->lineHeight) {
offs = 0;
device->nextY = QMAX(device->nextY, device->y + hei + device->yspace);
} else {
offs = (device->lineHeight - hei) / 2;
device->nextY = QMAX(device->nextY, device->y + device->lineHeight + device->yspace);
}
device->addChild(item->w, device->x, device->y + offs);
device->x += wid;
device->maxWid = QMAX(device->maxWid, device->x);
item->w->show();
item->used = true;
sameRow = false;
tight = false;
if (!tip.isEmpty()) {
QToolTip::add(item->w, tip);
tip="";
}
}
void Group::initItem(Item *item, QWidget *w, const char *line, bool activate) {
if (activate) {
connect(w, SIGNAL(sendCmd(const char *)), device->com, SLOT(sendCmd(const char *)));
connect(w, SIGNAL(changed()), device, SLOT(update()));
}
if (item->w) delete item->w;
item->w = w;
items.replace(line, item);
}
void Group::toggle() {
if (shown) {
if (autoclose) {
autocloseAll(); // close containing groups
} else {
}
autoclose = false;
}
showIt(!shown);
device->update(false);
}
Item *Group::findItem(const char *name) {
Item *item;
item = items.find(name);
if (!item) {
item = new Item();
item->grp = this;
}
return item;
}
void Group::hideContents() {
Item *item;
Group *g;
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
if (item->used) {
g = dynamic_cast<Group *>(item->w);
if (g) {
if (g->shown) {
g->hideContents();
}
g->arrow->hide();
}
item->w->hide();
/*
if (item->graphButton) {
item->graphButton->hide();
}
*/
}
}
}
void Group::updateLayout(QStringList::Iterator &sit) {
QString lineQ;
int lwid=0;
LineInput *lineInp;
CheckBox *cb;
QLabel *label;
RdOnly *rdonly;
Menu *menu=0;
ColorMenu *colorMenu=0;
ClickButton *pb;
QString tit("");
QPtrStack<Group> stack;
Group *grp;
QString value;
const char *line;
Item *item;
Item *rightItem = 0;
int labelNum=0;
char labelCode[8];
const char *arg;
RadioButton *rb;
QString radioName("");
QString radioLine("");
int i;
int menuItem;
int yline;
bool autocloseOnRadio = false;
// obsolete graph: char groupName[256];
device->x = indent;
tip="";
sameRow = false;
tight = false;
wStyle = 0;
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
item->used = false;
}
for (; sit != device->code.end(); ++sit) {
lineQ = (*sit);
line = lineQ.latin1();
if (line[0] != '-') {
if (line[0]) {
if (printit()) printf("%s\n", line);
}
continue;
}
arg = line+2;
//printf("L %s\n", line);
switch (line[1]) {
case '-': // no line break for next item
tight = true;
if (line[2] != '-') {
sameRow = true;
}
break;
case 'P': // line break
newline();
break;
case 'W': // custom width
lwid = atoi(arg);
break;
case 'T': // group title
tit = arg;
break;
case 'H': // help (tool tip)
if (!tip.isEmpty()) {
tip.append("\n");
}
tip.append(arg);
break;
case '>': // add last item to group title line (experimental)
rightItem = item;
break;
/*
case 's': // auto open (for stick group), will be obsolete
if (device->openGroups == "") {
device->openGroups = "sticks";
device->update();
}
break;
*/
case 'G': // group
item = findItem(line);
grp = dynamic_cast<Group *>(item->w);
if (grp == 0) {
grp = new Group(this, tit, arg);
initItem(item, grp, line);
} else {
grp->title->setText(tit);
}
if (device->openGroup != "" && PathStartsWith(device->openGroup, arg)) {
grp->autoclose = false;
if (device->openGroup == arg) {
device->openGroup = ""; // opening finished
}
if (!grp->shown) grp->showIt(true);
device->update(false);
}
if (arg[0] != '-' || grp->shown) {
newline();
sameRow = true;
device->x += 14;
add(item, grp->title);
if (shown && grp->arrow) {
yline = device->y + 2;
device->addChild(grp->arrow, indent + 2, yline);
grp->arrow->show();
}
/*
if (device->doJump && !grp->shown) {
// open automatically group tree in visibleGr (clicked on graph icon)
snprintf(groupName, sizeof groupName, " %s ", grp->name());
if (device->visibleGr.find(groupName) >= 0) {
grp->showIt(true);
grp->closeLater = true;
//printf("open %s\n", groupName);
}
}
*/
if (rightItem) {
// device->addChild(rightItem->w, device->x + device->xspace, device->y);
rightItem = 0;
} else {
newline();
}
}
tit="";
++sit;
grp->updateLayout(sit);
newline();
if (grp->shown) {
grp->setLineWidth(1);
grp->setFrameStyle(QFrame::Box | QFrame::Sunken);
grp->setFixedSize(device->width(), device->y - yline);
device->y += 4;
device->nextY += 4;
} else {
grp->setFrameStyle(QFrame::MenuBarPanel);
grp->setFixedSize(device->width(), grp->title->height());
}
grp->update();
if (sit == device->code.end()) --sit;
break;
case 'V': // value for next item
value = arg;
break;
case 'i': // readonly
item = findItem(line);
rdonly = dynamic_cast<RdOnly *>(item->w);
if (rdonly == 0) {
rdonly = new RdOnly(device->viewport(), tit, value, arg);
initItem(item, rdonly, line);
} else {
rdonly->label->setText(tit);
}
if (tight) {
rdonly->label->setMinimumWidth(0);
rdonly->value->setMinimumWidth(0);
} else {
rdonly->label->setMinimumWidth(device->labelWidth);
rdonly->value->setMinimumWidth(device->leWidth);
}
add(item);
lwid = 0;
rdonly->setValue(value);
value="";
break;
case 'I': // text input
item = findItem(line);
lineInp = dynamic_cast<LineInput *>(item->w);
if (lineInp == 0) {
lineInp = new LineInput(device->viewport(), tit, arg);
initItem(item, lineInp, line, true);
} else {
lineInp->label->setText(tit);
}
lineInp->setLength(lwid);
if (tight) {
lineInp->label->setMinimumWidth(0);
} else {
lineInp->label->setMinimumWidth(device->labelWidth);
}
add(item);
lwid = 0;
lineInp->setValue(value);
value="";
break;
case 'S': // set style
wStyle = arg[0];
break;
case 'D': // divide column (typically -D2: double number of columns)
colDiv = atoi(arg);
break;
case 'L': // label
snprintf(labelCode, sizeof labelCode, "%d", labelNum);
labelNum++;
item = findItem(labelCode);
label = dynamic_cast<QLabel *>(item->w);
if (label == 0) {
label = new QLabel(arg, device->viewport());
initItem(item, label, labelCode);
} else {
label->setText(arg);
}
add(item);
break;
case 'M': // menu (experimental ?)
if (arg[0] == 0) { // end of menu
if (menu) {
for (i=menu->count(); i<menuItem; i++) {
menu->removeItem(i);
}
}
menu=0;
value = "";
break;
}
item = findItem(line);
menu = dynamic_cast<Menu *>(item->w);
if (menu == 0) {
menu = new Menu(tit, device->viewport(), arg);
initItem(item, menu, line, true);
}
menuItem = 0;
add(item);
break;
case 'm': // menu item
if (menu) {
if (menuItem < menu->count()) {
if (menu->text(menuItem).compare(value) != 0) {
menu->changeItem(arg, menuItem);
}
} else {
menu->insertItem(arg, menuItem);
}
menuItem++;
}
break;
case 'c': // pen style menu
item = findItem(line);
colorMenu = dynamic_cast<ColorMenu *>(item->w);
if (colorMenu == 0) {
colorMenu = new ColorMenu(device->viewport(), arg);
initItem(item, colorMenu, line, true);
}
colorMenu->setValue(value);
colorMenu->setLength(lwid);
add(item);
case 'a': // autoclose on radio button (experimental?)
//device->closeGroup = this;
autocloseOnRadio = true;
//closeLater = true;
break;
case 'R': // radio button group
radioName = arg;
device->selectCmd = radioName;
device->selectCmd.append(" ");
device->selectCmd.append(value);
break;
case 'r': // radio button
if (radioName.isEmpty()) break;
radioLine = radioName + line;
line = radioLine.latin1();
item = findItem(line);
if (tit == "") {
tit = arg;
}
rb = dynamic_cast<RadioButton *>(item->w);
if (rb == 0) {
rb = new RadioButton(tit, device->viewport(), radioName, arg);
if (isSelectMenu) {
initItem(item, rb, line, false);
connect(rb, SIGNAL(sendCmd(const char *)), device, SLOT(setSelectCmd(const char *)));
connect(rb, SIGNAL(clearOthers(const QString &)), this, SIGNAL(clearRadioButtons(const QString &)));
connect(this, SIGNAL(clearRadioButtons(const QString &)), rb, SLOT(setValue(const QString &)));
} else {
initItem(item, rb, line, true);
// if (device->closeGroup) {
// connect(rb, SIGNAL(clicked()), device->closeGroup, SLOT(toggle()));
// }
if (autocloseOnRadio) {
connect(rb, SIGNAL(clicked()), device, SLOT(closeMarkedGroups()));
}
}
} else {
rb->setText(tit);
}
if (sameRow) {
rb->setMinimumWidth(0);
} else {
rb->setMinimumWidth(device->labelWidth / 2);
}
add(item);
rb->setChecked(value.compare(arg) == 0);
tit="";
break;
case 'B': // push button
item = findItem(line);
pb = dynamic_cast<ClickButton *>(item->w);
if (pb == 0) {
pb = new ClickButton(device->viewport(), arg);
pb->setLabel(tit);
switch (arg[0]) {
case 'C':
initItem(item, pb, line, false);
connect(pb, SIGNAL(clicked()), device, SLOT(switchLayout()));
break;
case 'D':
initItem(item, pb, line, false);
connect(pb, SIGNAL(clicked()), device, SLOT(selectIt()));
pb->setDefault(true);
break;
case 'S':
initItem(item, pb, line, false);
connect(pb, SIGNAL(sendCmd(const char *)), device, SLOT(openGrps(const char *)));
connect(pb, SIGNAL(changed()), device, SLOT(update()));
connect(pb, SIGNAL(clicked()), pb, SLOT(handleReturn()));
break;
default:
initItem(item, pb, line, true);
connect(pb, SIGNAL(clicked()), pb, SLOT(handleReturn()));
break;
}
}
add(item);
pb->setLabel(tit);
tit="";
break;
case 'C': // check box
item = findItem(line);
cb = dynamic_cast<CheckBox *>(item->w);
if (cb == 0) {
cb = new CheckBox(tit, device->viewport(), arg);
initItem(item, cb, line, true);
if (autocloseOnRadio) {
connect(cb, SIGNAL(clicked()), device, SLOT(closeMarkedGroups()));
}
} else {
cb->setText(tit);
}
add(item);
cb->setValue(value);
value="";
tit="";
break;
/*
case 'X': // make graphic button
if (item) {
if (item->graphButton == 0) {
item->graphButton = new GraphButton(this, arg);
connect(item->graphButton, SIGNAL(selectItem(const char *)),
device, SLOT(selectGraphItem(const char *)));
}
if (device->graphOn) {
device->addChild(item->graphButton, device->x, device->y);
device->x += device->graphButtonWidth;
item->graphButton->show();
arg = strrchr(arg, ' ');
if (arg) {
tip = "go to graph settings for this item (";
tip.append(arg + 3);
tip.append(")");
QToolTip::add(item->graphButton, tip);
tip = "";
}
} else {
item->graphButton->hide();
}
}
break;
*/
case 'g': // graph descriptor
if (device->graphDesc == "") {
device->graphDesc = arg;
} else if (device->graphDesc != arg) {
device->graphDesc = arg;
device->rebuildTime = DoubleTime() + 1;
// printf("*** desc changed\n");
// a graph rebuild will become necessary
} else if (device->rebuildTime != 0
&& DoubleTime() > device->rebuildTime) {
// but we do not rebuild before the descriptor was two times the
// same in succession and at least 1 second has passed
device->rebuildTime = 0;
device->updateInterval = 0.5;
// printf("*** rebuild\n");
QTimer::singleShot(1, device, SLOT(rebuild()));
}
break;
/*
case 'J': // jump to me
if (device->doJump) {
device->doJump = false;
device->yJump = device->y;
}
break;
*/
case 'E': // end of nested group
goto END;
default:
if (printit()) printf("%s\n", line);
}
}
END:
// if (device->closeGroup == this) {
// device->closeGroup = 0;
// }
/* graph obsolete
if (device->closeGr && shown && closeLater) {
// check if group is to be closed
snprintf(groupName, sizeof groupName, " %s ", name());
if (device->visibleGr.find(groupName) < 0) {
closeLater = false;
showIt(false);
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
item->used = false;
}
}
}
*/
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
if (!item->used) {
grp = dynamic_cast<Group *>(item->w);
if (grp) {
grp->hideContents();
grp->arrow->hide();
}
item->w->hide();
/*
if (item->graphButton) {
item->graphButton->hide();
}
*/
}
}
}
void Group::appendTo(QString &c) {
Group *g;
Item *item;
c.append(" ");
c.append(name());
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
g = dynamic_cast<Group *>(item->w);
if (g) {
if (g->shown) {
g->appendTo(c);
}
}
}
}
void Group::autocloseAll() {
Group *g;
Item *item;
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
g = dynamic_cast<Group *>(item->w);
if (g) {
g->autocloseAll();
if (g->shown && g->autoclose) {
printf("autoclose %s\n", g->name());
g->toggle();
}
}
}
}
bool Group::openGroup(QString &path) {
Group *g;
Item *item;
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
g = dynamic_cast<Group *>(item->w);
if (g && PathStartsWith(path, g->name())) {
if (!g->shown) {
g->toggle();
// g->autoclose = true;
}
if (path == g->name()) {
return g->shown;
}
return g->openGroup(path);
}
}
return false;
}
Group* Group::findGroup(QString &path) {
Group *g;
Item *item;
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
g = dynamic_cast<Group *>(item->w);
if (g) {
if (PathStartsWith(path, g->name())) {
if (path == g->name()) return g;
return g->findGroup(path);
}
}
}
return NULL;
}
Device::Device(QWidget* parent)
: QScrollView(parent)
{
LineInput *lineInp;
SetEraseColor(viewport(), topLevelWidget());
setFrameStyle(0);
xspace=6;
yspace=4;
QString tit("This is a very long label");
lineInp = new LineInput(this, tit, "test");
lineInp->setLength(0);
columnWidth = lineInp->stdWidth() + xspace;
leWidth = lineInp->le->width();
labelWidth = lineInp->label->width();
// graphButtonWidth = 24;
lineHeight = QMAX(lineInp->le->sizeHint().height(), lineInp->label->sizeHint().height());
delete lineInp;
/*
gButton = new GraphButton(this, "g-0");
graphOn = false;
visibleGr = "";
doJump = false;
yJump = 0;
*/
updateMode = update_idle;
stopUpdate = false;
//selectState = select_idle;
rebuildTime = 0;
//enableClipper(true);
}
void Device::init(Command *command, SeaSet *initSet) {
set = initSet;
com = command;
device = new Group(this, "main");
select = new Group(this, "select", true);
mainGroup = device;
addChild(mainGroup, 0, 0);
y = yspace;
update(false);
/*
QToolTip::add(gButton, "graph settings");
connect(gButton, SIGNAL(clicked()), this, SLOT(graphToggle()));
*/
updateInterval = 5.0;
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timedUpdate()));
timer->start(10);
}
void Device::rebuild() {
restart(graphDesc);
}
/*
void Device::graphToggle() {
if (graphOn) {
QToolTip::add(gButton, "graph settings");
columnWidth -= graphButtonWidth;
graphOn = false;
gButton->setPixmap(QPixmap(grPix));
visibleGr = "";
closeGr = true;
} else {
QToolTip::add(gButton, "close graph settings");
columnWidth += graphButtonWidth;
graphOn = true;
gButton->setPixmap(QPixmap(gnPix));
}
visibleGr = "";
update(false);
}
*/
void Device::switchLayout() {
mainGroup->hideContents();
if (mainGroup == select) {
mainGroup = device;
} else {
mainGroup = select;
}
update(false);
}
void Device::selectIt() {
mainGroup->hideContents();
com->sendCmd(selectCmd.latin1());
mainGroup = device;
update(false);
QTimer::singleShot(100,this,SLOT(update()));
}
void Device::setSelectCmd(const char *cmd) {
selectCmd = cmd;
}
void Device::resizeEvent(QResizeEvent *e) {
if (e->size().width() != e->oldSize().width()) {
if (e->size().width() > 10 || e->oldSize().width() > 10) {
if (updateInterval > 0) {
updateInterval = 0;
QTimer::singleShot(100,this,SLOT(update()));
}
}
}
QScrollView::resizeEvent(e);
}
/*
void Device::selectGraphItem(const char *id) {
//printf("SELECT %s\n", id);
visibleGr = "";
if (id) {
visibleGr = " ";
visibleGr.append(id);
closeGr = true;
doJump = true;
}
update(false);
}
*/
void Device::timedUpdate() {
double now;
if (updateMode == update_start) {
// printf("*** update start\n");
updateStart();
updateMode = update_complete;
tmot.start();
}
if (updateMode == update_complete) {
if (tmot.elapsed() > 10000) {
set->sc->reconnect();
tmot.start();
printf("timeout -> reconnect\n");
updateMode = update_idle;
}
if (set->sc->handleBuffer(0) <= 0) return;
// printf("*** update complete\n");
if (set->sc->getResponse() < 0) {
set->sc->reconnect();
printf("timeout -> reconnected\n");
updateMode = update_idle;
return;
}
updateComplete();
updateMode = update_idle;
return;
}
if (mainGroup == select && lastUpdate > 0) {
return;
}
now = DoubleTime();
if (updateInterval == 0) {
updateInterval = 0.5;
// printf("*** immediate update\n");
} else {
if (now < lastUpdate + updateInterval) {
return;
}
if (updateInterval < 0.99) {
updateInterval += 0.1;
} else {
updateInterval *= 2;
}
if (updateInterval >= 10) {
updateInterval = 10;
}
// printf("*** next update in %g sec\n", updateInterval);
}
if (isHidden() || height() < 3) {
lastUpdate = now;
return;
}
updateMode = update_start;
}
void Device::activate() {
double now;
if (mainGroup == select) return;
now = DoubleTime();
if (now > lastUpdate) {
update(false);
// lastUpdate = now;
}
}
void Device::closeMarkedGroups() {
mainGroup->autocloseAll();
//selectState = select_idle;
}
void Device::openGrps(const char *groups) {
Group *g;
bool openit;
openGroup = groups + 1; // skip first letter S in button name
g = mainGroup->findGroup(openGroup);
openit = !g || !g->shown;
mainGroup->autocloseAll();
if (openit) {
if (!mainGroup->openGroup(openGroup)) {
update(false);
return;
}
}
openGroup = "";
update(false);
}
void Device::update(bool refresh) {
if (refresh) {
updateInterval = 0.5;
stopUpdate = true;
}
lastUpdate = 0;
}
void Device::updateStart() {
QString c("layout");
lastUpdate = DoubleTime();
code.clear();
mainGroup->appendTo(c);
/*
if (graphOn && !visibleGr.isEmpty()) {
if (doJump) {
c.append(visibleGr);
} else {
int i = visibleGr.findRev(' ');
if (i >= 0) {
c.append(visibleGr.mid(i));
}
}
}
*/
// printf("*** SEND %s\n", c.latin1());
set->sc->sendCommand(c.latin1());
//printf("%s\n", c.latin1());
}
void Device::updateComplete() {
QString line;
while (set->sc->getLine(line) > 0) {
code.append(line);
}
if (stopUpdate) {
stopUpdate = false;
return;
}
QStringList::Iterator it = code.begin();
y = yspace;
nextY = yspace;
maxWid = 0;
/* graph obsolete:
addChild(gButton, this->visibleWidth() - graphButtonWidth, 2);
gButton->show();
*/
// closeGroup = 0;
mainGroup->updateLayout(it);
resizeContents(maxWid, y);
/*
if (yJump > 0) {
ensureVisible(0, yJump);
yJump = 0;
}
*/
}