781 lines
24 KiB
C++
781 lines
24 KiB
C++
#include <QScrollBar>
|
|
#include <QMessageBox>
|
|
#include <math.h>
|
|
#include "kx_pult.h"
|
|
#include "ui_kx_pult.h"
|
|
#include "piqt.h"
|
|
#include "qpiconfig.h"
|
|
|
|
|
|
bool isNormalDouble(const double & v) {
|
|
#ifdef WINDOWS
|
|
return true;
|
|
#else
|
|
return !isnan(v) && !isinf(v);
|
|
#endif
|
|
}
|
|
|
|
|
|
XCheck::XCheck(int index): QWidget() {
|
|
index_ = index;
|
|
setProperty("index", index);
|
|
setMouseTracking(true);
|
|
check.setText(QString::number(index + 1) + " ");
|
|
check.setAutoFillBackground(true);
|
|
spin.setMaximum(KX_X_COUNT - 1);
|
|
QBoxLayout * l = new QBoxLayout(QBoxLayout::LeftToRight);
|
|
l->setMargin(0);
|
|
l->setSpacing(2);
|
|
l->addWidget(&check);
|
|
l->addWidget(&spin);
|
|
setLayout(l);
|
|
//check.installEventFilter(this);
|
|
//spin.installEventFilter(this);
|
|
connect(&spin, SIGNAL(valueChanged(int)), this, SLOT(spinChanged(int)));
|
|
connect(&check, SIGNAL(toggled(bool)), this, SLOT(checkChanged_(bool)));
|
|
}
|
|
|
|
|
|
bool XCheck::eventFilter(QObject * o, QEvent * e) {
|
|
if (e->type() == QEvent::Enter)
|
|
qApp->postEvent(this, new QEvent(e->type()));
|
|
return QWidget::eventFilter(o, e);
|
|
}
|
|
|
|
|
|
|
|
|
|
KX_Pult::KX_Pult(): QMainWindow(), config_("kx_pult.conf"), name_("x"), config(piqt(config_), QIODevice::ReadWrite), coeffs(config_, "k", true) {
|
|
//cout << sizeof(coeffsK.k_protocol->to_k) << endl;
|
|
ui = new Ui::KX_Pult();
|
|
ui->setupUi(this);
|
|
ui->configWidget->setQPIConfig(&config);
|
|
ui->configWidget->expandAll();
|
|
ui->list->viewport()->installEventFilter(this);
|
|
ui->treeK->viewport()->installEventFilter(this);
|
|
log_menu.addAction(ui->actionClear);
|
|
prot_x = 0;
|
|
show_x = config.getValue("show_x", true);
|
|
if (!show_x)
|
|
ui->tabWidget->removeTab(1);
|
|
session.setFile("session_KX_Pult.conf");
|
|
session.addEntry(this);
|
|
session.addEntry(ui->tabWidget);
|
|
session.addEntry(ui->checkKHideEmpty);
|
|
session.addEntry(ui->checkKHideNormal);
|
|
session.addEntry(ui->checkKHideExpressions);
|
|
session.addEntry(ui->checkKAutoCalculate);
|
|
needWrite = isPause = false;
|
|
timer = 0;
|
|
//x.resize(KX_X_PACKET_NUM);
|
|
//k.resize(K_NUM);
|
|
QPalette pal = palette();
|
|
QColor col;
|
|
ui->graphic->setGraphicsCount(0);
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i) {
|
|
XCheck * xc = new XCheck(i);
|
|
xc->installEventFilter(this);
|
|
connect(xc, SIGNAL(valueChanged(int, int)), this, SLOT(changedX(int,int)));
|
|
connect(xc, SIGNAL(checkChanged(int, bool)), this, SLOT(toggledX(int, bool)));
|
|
col = QColor::fromHsv(360 / KX_X_PACKET_NUM * i, 255, 200);
|
|
pal.setColor(QPalette::Button, col);
|
|
pal.setColor(QPalette::Window, col);
|
|
pal.setColor(QPalette::WindowText, invertColor(col));
|
|
xc->check.setPalette(pal);
|
|
ui->graphic->addGraphic(QString::number(i), col);
|
|
ui->graphic->setGraphicVisible(false, i);
|
|
checks << xc;
|
|
((QGridLayout * )(ui->widgetChecks->layout()))->addWidget(xc, (i / 10) * 2, i % 10);
|
|
QLabel * lbl = new QLabel("0"); lbl->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
|
|
values << lbl;
|
|
((QGridLayout * )(ui->widgetChecks->layout()))->addWidget(lbl, (i / 10) * 2 + 1, i % 10);
|
|
//xc->show();
|
|
}
|
|
renew();
|
|
icon_record = QIcon(":/icons/media-record.png");
|
|
icon_stop = QIcon(":/icons/media-playback-stop.png");
|
|
outdir = dir.absolutePath();
|
|
if (!dir.exists()) dir.mkdir(outdir);
|
|
outdir += "/";
|
|
ui->treeK->setColumnWidth(0, 60);
|
|
ui->treeK->setColumnWidth(1, 250);
|
|
ui->treeK->setColumnWidth(3, 100);
|
|
ui->treeK->setColumnWidth(4, 100);
|
|
//ui->table->setK(coeffsK.k()->data(), coeffsK.count());
|
|
ui->spinSize->setValue(K.size_s());
|
|
addToList(trUtf8("Read K file \"%1\": %2 coeffs, %3 bytes").arg(PI2QString(coeffs.fileName())).arg(K.size_s()).arg(coeffs.k_content.size_s()), Qt::darkMagenta);
|
|
CONNECT(void, &coeffs, sendFailed, this, pip_sendFailed);
|
|
CONNECT(void, &coeffs, sendSucceed, this, pip_sendSucceed);
|
|
CONNECT(void, &coeffs, receiveFailed, this, pip_receiveFailed);
|
|
CONNECT(void, &coeffs, receiveSucceed, this, pip_receiveSucceed);
|
|
connect(this, SIGNAL(q_k_sendFailed()), this, SLOT(k_sendFailed()), Qt::QueuedConnection);
|
|
connect(this, SIGNAL(q_k_sendSucceed()), this, SLOT(k_sendSucceed()), Qt::QueuedConnection);
|
|
connect(this, SIGNAL(q_k_receiveFailed()), this, SLOT(k_receiveFailed()), Qt::QueuedConnection);
|
|
connect(this, SIGNAL(q_k_receiveSucceed()), this, SLOT(k_receiveSucceed()), Qt::QueuedConnection);
|
|
connect(&timer_diag, SIGNAL(timeout()), this, SLOT(updateDiag()));
|
|
connect(&session, SIGNAL(loading(QPIConfig&)), this, SLOT(loading(QPIConfig&)));
|
|
connect(&session, SIGNAL(saving(QPIConfig&)), this, SLOT(saving(QPIConfig&)));
|
|
connect(ui->checkKHideEmpty, SIGNAL(toggled(bool)), this, SLOT(filterTree()));
|
|
connect(ui->checkKHideNormal, SIGNAL(toggled(bool)), this, SLOT(filterTree()));
|
|
connect(ui->checkKHideExpressions, SIGNAL(toggled(bool)), this, SLOT(filterTree()));
|
|
connect(ui->lineKSearch, SIGNAL(textChanged(QString)), this, SLOT(filterTree()));
|
|
session.load();
|
|
updateKDesc();
|
|
timer_diag.start(40);
|
|
timer_update = startTimer(25);
|
|
}
|
|
|
|
|
|
KX_Pult::~KX_Pult() {
|
|
session.save();
|
|
}
|
|
|
|
|
|
void KX_Pult::loading(QPIConfig & conf) {
|
|
kdesc_file = conf.getValue("kdesc_file").stringValue();
|
|
}
|
|
|
|
|
|
void KX_Pult::saving(QPIConfig & conf) {
|
|
conf.setValue("kdesc_file", kdesc_file);
|
|
}
|
|
|
|
|
|
bool KX_Pult::eventFilter(QObject * o, QEvent * e) {
|
|
if (o == ui->list->viewport()) {
|
|
if (e->type() == QEvent::ContextMenu) {
|
|
clear_target = 0;
|
|
log_menu.popup(((QContextMenuEvent*)e)->globalPos());
|
|
}
|
|
return QMainWindow::eventFilter(o, e);
|
|
}
|
|
if (o == ui->treeK->viewport()) {
|
|
if (e->type() == QEvent::ContextMenu) {
|
|
clear_target = 1;
|
|
log_menu.popup(((QContextMenuEvent*)e)->globalPos());
|
|
}
|
|
return QMainWindow::eventFilter(o, e);
|
|
}
|
|
int ind = o->property("index").toInt();
|
|
//qDebug() << "event" << i << e->type();
|
|
switch (e->type()) {
|
|
case QEvent::Enter:
|
|
ui->graphic->setAutoUpdate(false);
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i)
|
|
ui->graphic->setGraphicLineWidth(ind == i ? 3. : 1., i);
|
|
ui->graphic->setAutoUpdate(true);
|
|
ui->graphic->update();
|
|
break;
|
|
case QEvent::Leave:
|
|
ui->graphic->setAutoUpdate(false);
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i)
|
|
ui->graphic->setGraphicLineWidth(1., i);
|
|
ui->graphic->setAutoUpdate(true);
|
|
ui->graphic->update();
|
|
break;
|
|
default: break;
|
|
}
|
|
return QMainWindow::eventFilter(o, e);
|
|
}
|
|
|
|
|
|
void KX_Pult::timerEvent(QTimerEvent * e) {
|
|
if (e->timerId() == timer_update) {
|
|
if (need_update) {
|
|
need_update = false;
|
|
ui->graphic->updateGraphics();
|
|
}
|
|
}
|
|
if (e->timerId() == timer) {
|
|
static QString sPI = QString::number(atan(1) * 4., 'f', 14).leftJustified(14);
|
|
static int cnt = 0;
|
|
int si = qMax<int>(cnt - 6, 0);
|
|
++cnt;
|
|
cnt %= 23;
|
|
ui->labelWait->setText(QString(si, QChar(' ')) + sPI.mid(cnt - 6, 6).trimmed());
|
|
if (!coeffs.isReady()) return;
|
|
//ui->table->setK(coeffsK.k()->data(), coeffsK.count());
|
|
//ui->table->showK();
|
|
}
|
|
}
|
|
|
|
|
|
void KX_Pult::setControlsEnable(bool enable) {
|
|
foreach (XCheck * i, checks)
|
|
i->setEnabled(enable);
|
|
ui->buttonShowAll->setEnabled(enable);
|
|
ui->buttonHideAll->setEnabled(enable);
|
|
}
|
|
|
|
|
|
void KX_Pult::setX(const KX_X_Data & data) {
|
|
if (!show_x) return;
|
|
ui->graphic->lock();
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i) {
|
|
if (!isNormalDouble(data.x_data[i])) continue;
|
|
ui->graphic->addPoint(data.x_data[i], i, false);
|
|
values[i]->setText(QString("(%1): %2").arg(data.x_num[i]).arg(data.x_data[i]));
|
|
}
|
|
ui->graphic->unlock();
|
|
if (!isPause) {
|
|
need_update = true;
|
|
}
|
|
if (!needWrite) return;
|
|
stream << QString::number(tm.elapsed() / 1000., 'f', 3) << " " << QTime::currentTime().toString("hh:mm:ss") << " " << wcnt++;
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i)
|
|
stream << " " << QString::number(data.x_data[i], 'f', 4);
|
|
stream << "\n";
|
|
}
|
|
|
|
|
|
void KX_Pult::addToList(const QString & s, const QColor & c) {
|
|
ui->list->addItem(QDateTime::currentDateTime().toString("dd/MM/yyyy hh:ss - ") + s);
|
|
ui->list->item(ui->list->count() - 1)->setTextColor(c);
|
|
ui->list->scrollToBottom();
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonRecord_clicked() {
|
|
static bool isRec = false;
|
|
int cinc = 0;
|
|
QString str;
|
|
isRec = !isRec;
|
|
setControlsEnable(!isRec);
|
|
if (isRec) {
|
|
tm.restart();
|
|
file.close();
|
|
file.setFileName(outdir + getNewFileName(cinc));
|
|
while (file.exists())
|
|
file.setFileName(outdir + getNewFileName(cinc++));
|
|
file.open(QIODevice::ReadWrite);
|
|
stream.setDevice(&file);
|
|
stream << "T V C";
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i)
|
|
stream << " X" + QString::number(checks[i]->spin.value());
|
|
stream << "\n";
|
|
wcnt = 0;
|
|
needWrite = true;
|
|
ui->buttonRecord->setText(trUtf8("Finish record"));
|
|
ui->buttonRecord->setIcon(icon_stop);
|
|
emit recordStarted(QFileInfo(file).completeBaseName());
|
|
} else {
|
|
needWrite = false;
|
|
stream.setDevice(0);
|
|
file.close();
|
|
ui->buttonRecord->setText(trUtf8("Start record"));
|
|
ui->buttonRecord->setIcon(icon_record);
|
|
emit recordStopped(QFileInfo(file).completeBaseName());
|
|
}
|
|
}
|
|
|
|
|
|
void KX_Pult::on_actionClear_triggered() {
|
|
switch (clear_target) {
|
|
case 0:
|
|
ui->list->clear();
|
|
break;
|
|
case 1:
|
|
clearSelected();
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
|
|
void KX_Pult::clearSelected() {
|
|
QList<QTreeWidgetItem * > si = ui->treeK->selectedItems();
|
|
ui->treeK->setUpdatesEnabled(false);
|
|
ui->treeK->blockSignals(true);
|
|
foreach (QTreeWidgetItem * i, si) {
|
|
int ki = i->text(0).toInt();
|
|
i->setText(2, "");
|
|
coeffs.setFormula(ki, "");
|
|
}
|
|
ui->treeK->blockSignals(false);
|
|
ui->treeK->setUpdatesEnabled(true);
|
|
if (ui->checkKAutoCalculate->isChecked()) {
|
|
QApplication::processEvents();
|
|
calculate();
|
|
}
|
|
}
|
|
|
|
|
|
QString KX_Pult::typeName(const QString & n) const {
|
|
if (n.isEmpty()) return "";
|
|
switch (n[0].toLatin1()) {
|
|
case 'l': return trUtf8("list"); break;
|
|
case 'b': return trUtf8("bool"); break;
|
|
case 'n': return trUtf8("int"); break;
|
|
case 'f': return trUtf8("double"); break;
|
|
case 'c': return trUtf8("color"); break;
|
|
case 'r': return trUtf8("rect"); break;
|
|
case 'a': return trUtf8("rect"); break;
|
|
case 'p': return trUtf8("point"); break;
|
|
case 'v': return trUtf8("vector"); break;
|
|
case 'i': return trUtf8("IP"); break;
|
|
case 'e': return trUtf8("enum"); break;
|
|
case 'F': return trUtf8("file"); break;
|
|
case 'D': return trUtf8("dir"); break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
void KX_Pult::received(bool ok) {
|
|
if (!ok) return;
|
|
setX(prot_x->from_x);
|
|
}
|
|
|
|
|
|
void KX_Pult::on_treeK_itemClicked(QTreeWidgetItem * item, int column) {
|
|
Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
|
if (column == 2) f |= Qt::ItemIsEditable;
|
|
item->setFlags(f);
|
|
}
|
|
|
|
|
|
void KX_Pult::on_treeK_itemChanged(QTreeWidgetItem * item, int column) {
|
|
if (column != 2) return;
|
|
int ki = item->text(0).toInt();
|
|
coeffs.setFormula(ki, piqt(item->text(column)));
|
|
if (ui->checkKAutoCalculate->isChecked())
|
|
calculate();
|
|
}
|
|
|
|
|
|
QString KX_Pult::getNewFileName(int inc) {
|
|
dir.refresh();
|
|
dir.setNameFilters(QStringList("Experiment_*.txt"));
|
|
return "Experiment_" + QDateTime::currentDateTime().toString("dd_MM_yy__hh_mm_ss") + "__" +
|
|
QString::number(dir.entryList().count() + inc) + ".txt";
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonSendK_clicked() {
|
|
on_buttonWrite_clicked();
|
|
coeffs.sendCoeffs();
|
|
if (timer != 0) killTimer(timer);
|
|
timer = startTimer(100);
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonReceiveK_clicked() {
|
|
coeffs.receiveCoeffs();
|
|
if (timer != 0) killTimer(timer);
|
|
timer = startTimer(100);
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonShowAll_clicked() {
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i) {
|
|
checks[i]->check.setChecked(true);
|
|
//ui->graphic->setGraphicVisible(true, i);
|
|
}
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonHideAll_clicked() {
|
|
for (int i = 0; i < KX_X_PACKET_NUM; ++i) {
|
|
checks[i]->check.setChecked(false);
|
|
//ui->graphic->setGraphicVisible(false, i);
|
|
}
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonRead_clicked() {
|
|
coeffs.readCoeffs();
|
|
addToList(trUtf8("Read K file \"%1\": %2 coeffs, %3 bytes").arg(PI2QString(coeffs.fileName())).arg(K.size_s()).arg(coeffs.k_content.size_s()), Qt::darkMagenta);
|
|
updateTree();
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonWrite_clicked() {
|
|
coeffs.writeCoeffs();
|
|
addToList(trUtf8("Write K file \"%1\": %2 coeffs, %3 bytes").arg(PI2QString(coeffs.fileName())).arg(K.size_s()).arg(coeffs.k_content.size_s()), Qt::darkMagenta);
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonResize_clicked() {
|
|
K.resize(ui->spinSize->value());
|
|
coeffs.formulas.resize(ui->spinSize->value());
|
|
ui->spinSize->setStyleSheet("");
|
|
updateTree();
|
|
}
|
|
|
|
|
|
void KX_Pult::on_buttonSetDesc_clicked() {
|
|
QString ret = QFileDialog::getOpenFileName(this, trUtf8("Select *.h file with K description"), kdesc_file, "C/C++ header files(*.h *.hpp);;All files(*)");
|
|
if (ret.isEmpty()) return;
|
|
kdesc_file = QDir::current().relativeFilePath(ret);
|
|
updateKDesc(true);
|
|
}
|
|
|
|
|
|
void KX_Pult::on_spinSize_valueChanged(int) {
|
|
ui->spinSize->setStyleSheet("");
|
|
}
|
|
|
|
|
|
void KX_Pult::k_sendFailed() {
|
|
stopWait();
|
|
addToList(trUtf8("K not sended"), Qt::darkRed);
|
|
}
|
|
|
|
|
|
void KX_Pult::k_sendSucceed() {
|
|
stopWait();
|
|
addToList(trUtf8("K sended"), Qt::darkGreen);
|
|
}
|
|
|
|
|
|
void KX_Pult::k_receiveFailed() {
|
|
stopWait();
|
|
addToList(trUtf8("K not received"), Qt::darkRed);
|
|
}
|
|
|
|
|
|
void KX_Pult::k_receiveSucceed() {
|
|
stopWait();
|
|
addToList(trUtf8("K received"), Qt::darkGreen);
|
|
addToList(trUtf8("Write K file \"%1\": %2 coeffs, %3 bytes").arg(PI2QString(coeffs.fileName())).arg(K.size_s()).arg(coeffs.k_content.size_s()), Qt::darkMagenta);
|
|
ui->spinSize->setValue(K.size_s());
|
|
updateTree();
|
|
//ui->table->setK(coeffsK.k()->data(), coeffsK.count());
|
|
}
|
|
|
|
|
|
void KX_Pult::on_spinBuffer_editingFinished() {
|
|
ui->graphic->setHistorySize(ui->spinBuffer->value());
|
|
}
|
|
|
|
|
|
void KX_Pult::stopWait() {
|
|
killTimer(timer);
|
|
timer = 0;
|
|
ui->labelWait->setText(" ");
|
|
}
|
|
|
|
|
|
void KX_Pult::updateGraph() {
|
|
ui->graphic->updateGraphics();
|
|
}
|
|
|
|
|
|
void KX_Pult::updateDiag() {
|
|
|
|
ui->labelKReceiver->setText(piqt(coeffs.k_protocol->receiverDeviceName() + " - " + coeffs.k_protocol->receiverDeviceState()));
|
|
ui->labelKSender->setText(piqt(coeffs.k_protocol->senderDeviceName()));
|
|
ui->spinKSended->setValue(coeffs.k_protocol->sendCount());
|
|
ui->spinKReceived->setValue(coeffs.k_protocol->receiveCount());
|
|
ui->spinKWrong->setValue(coeffs.k_protocol->wrongCount());
|
|
ui->spinKMissed->setValue(coeffs.k_protocol->missedCount());
|
|
ui->labelKType->setText("0x" + QString::number(coeffs.k_protocol->from_k.type, 16).toUpper().rightJustified(2, '0'));
|
|
ui->labelKAddrPult->setText("0x" + QString::number(coeffs.k_protocol->from_k.addr_to, 16).toUpper().rightJustified(2, '0'));
|
|
ui->labelKAddr->setText("0x" + QString::number(coeffs.k_protocol->to_k.addr_to, 16).toUpper().rightJustified(2, '0'));
|
|
|
|
ui->labelXReceiver->setText(piqt(prot_x->receiverDeviceName() + " - " + prot_x->receiverDeviceState()));
|
|
ui->labelXSender->setText(piqt(prot_x->senderDeviceName()));
|
|
ui->spinXSended->setValue(prot_x->sendCount());
|
|
ui->spinXReceived->setValue(prot_x->receiveCount());
|
|
ui->spinXWrong->setValue(prot_x->wrongCount());
|
|
ui->spinXMissed->setValue(prot_x->missedCount());
|
|
ui->labelXType->setText("0x" + QString::number(prot_x->from_x.type, 16).toUpper().rightJustified(2, '0'));
|
|
ui->labelXAddrPult->setText("0x" + QString::number(prot_x->from_x.addr_to, 16).toUpper().rightJustified(2, '0'));
|
|
ui->labelXAddr->setText("0x" + QString::number(prot_x->to_x.addr_to, 16).toUpper().rightJustified(2, '0'));
|
|
|
|
}
|
|
|
|
|
|
void KX_Pult::updateKDesc(bool ask_move) {
|
|
kdesc.clear();
|
|
QFile f(kdesc_file);
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
updateTree();
|
|
addToList(trUtf8("Update descriptions from \"%1\": error").arg(kdesc_file), Qt::darkRed);
|
|
return;
|
|
}
|
|
addToList(trUtf8("Update descriptions from \"%1\"").arg(kdesc_file), Qt::darkMagenta);
|
|
QTextStream s(&f);
|
|
int cind = -1;
|
|
bool found = false;
|
|
//qDebug() << "\nparse" << kdesc_file;
|
|
while (!s.atEnd()) {
|
|
QString line = s.readLine().trimmed(), num, name, type, comment;
|
|
int i = line.indexOf("//");
|
|
if (i >= 0) {
|
|
comment = line.right(line.length() - i - 2);
|
|
type = comment.left(1);
|
|
comment = comment.right(comment.length() - 1).trimmed();
|
|
line = line.left(i).trimmed();
|
|
}
|
|
if (line.isEmpty()) continue;
|
|
if (line.contains("enum")) {
|
|
found = true;
|
|
continue;
|
|
}
|
|
if (!found) continue;
|
|
if (line.contains('}'))
|
|
break;
|
|
line.remove(',').remove(' ').remove('\t');
|
|
i = line.indexOf("=");
|
|
if (i >= 0) {
|
|
num = line.right(line.length() - i - 1).trimmed();
|
|
line = line.left(i).trimmed();
|
|
}
|
|
name = line;
|
|
if (num.isEmpty())
|
|
++cind;
|
|
else
|
|
cind = Q2PIString(num).toInt();
|
|
KDesc kd;
|
|
kd.index = cind;
|
|
kd.name = name;
|
|
kd.type = type;
|
|
kd.comment = comment;
|
|
kdesc[kd.index] = kd;
|
|
//qDebug() << name << cind << type << comment;
|
|
}
|
|
cind++;
|
|
if (K.size_s() < cind) {
|
|
ui->spinSize->setValue(cind);
|
|
ui->spinSize->setStyleSheet("background-color: rgb(220, 220, 255);");
|
|
}
|
|
bool move = false;
|
|
if (ask_move)
|
|
move = (QMessageBox::question(this, "KX Pult", "Save values at associated names?", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes);
|
|
updateTree(move);
|
|
}
|
|
|
|
|
|
bool stringComp(const QString & s1, const QString & s2) {
|
|
if (s1.size() != s2.size())
|
|
return s1.size() > s2.size();
|
|
return s1 > s2;
|
|
}
|
|
|
|
|
|
void KX_Pult::updateTree(bool move) {
|
|
int sp = ui->treeK->verticalScrollBar()->value();
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
//qDebug() << "fill tree ...";
|
|
QMap<QString, QString> prev_val;
|
|
if (move) {
|
|
for (int i = 0; i < ui->treeK->topLevelItemCount(); ++i) {
|
|
QTreeWidgetItem * ti = ui->treeK->topLevelItem(i);
|
|
if (!ti->text(1).isEmpty())
|
|
prev_val[ti->text(1)] = ti->text(2);
|
|
}
|
|
}
|
|
ui->treeK->clear();
|
|
ui->treeK->setUpdatesEnabled(false);
|
|
eval.clearCustomVariables();
|
|
for (int i = 0; i < K.size_s(); ++i) {
|
|
QTreeWidgetItem * ti = new QTreeWidgetItem();
|
|
KDesc kd = kdesc[i];
|
|
QString kn = QString("k%1").arg(i);
|
|
knames[kn] = i;
|
|
knames_sort << kn;
|
|
if (eval.content.findVariable(kn) < 0)
|
|
eval.content.addVariable(kn, 0., false);
|
|
if (!kd.name.isEmpty()) {
|
|
knames[kd.name] = i;
|
|
knames_sort << kd.name;
|
|
eval.content.addVariable(kd.name, 0., false);
|
|
}
|
|
if (move && !kd.name.isEmpty()) {
|
|
if (prev_val.contains(kd.name))
|
|
coeffs.setFormula(i, Q2PIString(prev_val[kd.name]));
|
|
}
|
|
ti->setText(0, QString::number(i));
|
|
ti->setText(1, kd.name);
|
|
ti->setText(2, PI2QString(coeffs.formula(i)));
|
|
ti->setText(3, QString::number(K[i]));
|
|
ti->setText(4, typeName(kd.type));
|
|
ti->setText(5, kd.comment);
|
|
ui->treeK->addTopLevelItem(ti);
|
|
}
|
|
eval.content.sortVariables();
|
|
//qDebug() << "fill tree ok";
|
|
//qDebug() << "sort ...";
|
|
qSort(knames_sort.begin(), knames_sort.end(), stringComp);
|
|
//qDebug() << "names" << knames_sort;
|
|
//qDebug() << "sort ok";
|
|
QApplication::restoreOverrideCursor();
|
|
ui->treeK->setUpdatesEnabled(true);
|
|
ui->treeK->verticalScrollBar()->setValue(sp);
|
|
calculate();
|
|
filterTree();
|
|
}
|
|
|
|
|
|
void KX_Pult::filterTree() {
|
|
bool he = ui->checkKHideEmpty->isChecked();
|
|
bool hn = ui->checkKHideNormal->isChecked();
|
|
bool hs = ui->checkKHideExpressions->isChecked();
|
|
bool ok = false;
|
|
QString fl = ui->lineKSearch->text();
|
|
int lc = ui->treeK->topLevelItemCount();
|
|
for (int i = 0; i < lc; ++i) {
|
|
QTreeWidgetItem * ti = ui->treeK->topLevelItem(i);
|
|
if (ti->text(1).isEmpty() && he)
|
|
ti->setHidden(true);
|
|
else
|
|
if (fl.isEmpty())
|
|
ti->setHidden(false);
|
|
else
|
|
ti->setHidden(!ti->text(0).contains(fl, Qt::CaseInsensitive) &&
|
|
!ti->text(1).contains(fl, Qt::CaseInsensitive) &&
|
|
!ti->text(2).contains(fl, Qt::CaseInsensitive) &&
|
|
!ti->text(3).contains(fl, Qt::CaseInsensitive) &&
|
|
!ti->text(4).contains(fl, Qt::CaseInsensitive));
|
|
if (hn)
|
|
if (ti->data(0, Qt::UserRole).toBool())
|
|
ti->setHidden(true);
|
|
if (hs) {
|
|
ti->data(2, Qt::DisplayRole).toDouble(&ok);
|
|
if (!ok)
|
|
ti->setHidden(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void KX_Pult::calculate() {
|
|
calculated.clear();
|
|
ui->treeK->setUpdatesEnabled(false);
|
|
ui->treeK->blockSignals(true);
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
progress(0, 100);
|
|
ui->buttonCalculate->setEnabled(false);
|
|
QApplication::processEvents();
|
|
for (int i = 0; i < K.size_s(); ++i) {
|
|
ui->treeK->topLevelItem(i)->setToolTip(2, QString());
|
|
ui->treeK->topLevelItem(i)->setToolTip(3, QString());
|
|
}
|
|
for (int i = 0; i < K.size_s(); ++i) {
|
|
progress(i, K.size_s());
|
|
calculateExpression(i, QVector<int>());
|
|
}
|
|
ui->buttonCalculate->setEnabled(true);
|
|
ui->progress->setValue(100);
|
|
QApplication::restoreOverrideCursor();
|
|
ui->treeK->blockSignals(false);
|
|
ui->treeK->setUpdatesEnabled(true);
|
|
}
|
|
|
|
|
|
bool KX_Pult::calculateExpression(int i, QVector<int> trace) {
|
|
if (calculated.contains(i)) return true;
|
|
trace << i;
|
|
QTreeWidgetItem * ti = ui->treeK->topLevelItem(i);
|
|
QString expr = ti->text(2);
|
|
if (expr.isEmpty() || expr == "0" || expr == "0,00000000" || expr == "0.00000000") {
|
|
markNormal(ti);
|
|
calculated << i;
|
|
K[i] = 0.;
|
|
ti->setText(3, "0");
|
|
return true;
|
|
}
|
|
//ti->setToolTip(2, QString());
|
|
if (!eval.check(expr)) {
|
|
markError(ti, eval.error());
|
|
return false;
|
|
}
|
|
foreach (const QString & n, knames_sort) {
|
|
if (expr.contains(n)) {
|
|
int ki = knames.value(n, -1);
|
|
if (trace.contains(ki)) {
|
|
QString strace;
|
|
trace << ki;
|
|
for (int j = 0; j < trace.size(); ++j) {
|
|
//calculated << trace[j];
|
|
if (j > 0) strace += " -> ";
|
|
strace += "k" + QString::number(trace[j]);
|
|
}
|
|
for (int j = 0; j < trace.size(); ++j) {
|
|
QTreeWidgetItem * pti = ui->treeK->topLevelItem(trace[j]);
|
|
markError(pti, QString("Circular dependency: %1!").arg(strace));
|
|
}
|
|
return false;
|
|
}
|
|
if (ki < 0) {
|
|
markError(ti);
|
|
return false;
|
|
}
|
|
if (calculated.contains(ki)) {
|
|
eval.setVariable(n, K[ki]);
|
|
} else {
|
|
if (calculateExpression(ki, trace))
|
|
eval.setVariable(n, K[ki]);
|
|
else {
|
|
markError(ti);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
markNormal(ti);
|
|
calculated << i;
|
|
complexd ret = eval.evaluate();
|
|
K[i] = ret.real();
|
|
ti->setText(3, QString::number(K[i]));
|
|
return true;
|
|
}
|
|
|
|
|
|
void KX_Pult::markError(QTreeWidgetItem * item, const QString & tool_tip) {
|
|
int cc = item->columnCount();
|
|
for (int i = 0; i < cc; ++i)
|
|
item->setBackgroundColor(i, QColor(255, 200, 200));
|
|
if (item->toolTip(2).isEmpty())
|
|
item->setToolTip(2, tool_tip);
|
|
if (item->toolTip(3).isEmpty())
|
|
item->setToolTip(3, tool_tip);
|
|
item->setData(0, Qt::UserRole, false);
|
|
item->setText(3, "Error");
|
|
}
|
|
|
|
|
|
void KX_Pult::markNormal(QTreeWidgetItem * item) {
|
|
int cc = item->columnCount();
|
|
for (int i = 0; i < cc; ++i)
|
|
item->setBackground(i, Qt::NoBrush);
|
|
item->setToolTip(2, QString());
|
|
item->setToolTip(3, QString());
|
|
item->setData(0, Qt::UserRole, true);
|
|
}
|
|
|
|
|
|
void KX_Pult::progress(int val, int max) {
|
|
if (ctm.elapsed() < 50) return;
|
|
ctm.restart();
|
|
ui->progress->setValue(qRound(val * 100. / max));
|
|
QApplication::processEvents();
|
|
}
|
|
|
|
|
|
void KX_Pult::renew(bool write) {
|
|
addToList(trUtf8("Update settings from \"%1\"").arg(PI2QString(config_)), Qt::darkMagenta);
|
|
dir.setPath(config.getValue("x.output_dir", "./Experiments/").stringValue());
|
|
setWindowTitle(config.getValue("title", "Noname").stringValue() + trUtf8(" - KX Pult"));
|
|
//if (write) ui->configWidget->write();
|
|
if (prot_x != 0) {
|
|
prot_x->stop();
|
|
delete prot_x;
|
|
}
|
|
prot_x = new __KX_Protocol_X(config_, name_);
|
|
ui->graphic->setAutoXIncrement(prot_x->expectedFrequency() > 0. ? 1. / prot_x->expectedFrequency() : 1.);
|
|
coeffs.renew();
|
|
CONNECT1(void, bool, prot_x, received, this, received);
|
|
}
|
|
|
|
|
|
void KX_Pult::toggledX(int index, bool on) {
|
|
ui->graphic->setGraphicVisible(on, index);
|
|
}
|
|
|
|
|
|
void KX_Pult::changedX(int index, int num) {
|
|
prot_x->to_x.x_num[index] = num;
|
|
}
|