//OpenSCADA module UI.Vision file: vis_shapes.cpp /*************************************************************************** * Copyright (C) 2007-2024 by Roman Savochenko, * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vis_run.h" #include "vis_devel.h" #include "vis_run_widgs.h" #include "vis_devel_widgs.h" #include "../QTStarter/lib_qtgen.h" #include "vis_shapes.h" #if HAVE_MULTIMEDIA # include # include # if QT_VERSION >= 0x060000 # include # define setVolume(vol) audioOutput()->setVolume(vol) # define setMedia(url) setSource(url) # define state() playbackState() # endif #elif HAVE_PHONON # ifdef HAVE_PHONON_VIDEOPLAYER # include # include # include # else # include # include # include # endif using namespace Phonon; #endif #if QT_VERSION >= 0x050000 # include # include #else # include #endif #if QT_VERSION < 0x060000 # define MiddleButton MidButton # define setSecsSinceEpoch(tm) setTime_t(tm) # define typeId() type() #endif using namespace OSCADA_QT; using namespace VISION; //************************************************* //* Widget shape abstract object * //************************************************* WdgShape::WdgShape( const string &iid ) : m_id(iid) { } bool WdgShape::event( WdgView *view, QEvent *event ) { switch(event->type()) { case QEvent::Paint: if(qobject_cast(view)) { QPainter pnt( view ); pnt.setWindow(view->rect()); pnt.drawImage(view->rect(),QImage(":/images/attention.png")); event->accept(); view->setToolTip(QString(_("Widget's shape '%1' is not implemented yet!")).arg(id().c_str())); } return true; default: break; } return false; } void WdgShape::borderDraw( QPainter &pnt, QRect dA, QPen bpen, int bordStyle ) { int bordWidth = bpen.width(); if(bordStyle && bordWidth) switch(bordStyle) { case FBRD_DOT: bpen.setStyle(Qt::DotLine); pnt.setPen(bpen); pnt.drawRect(dA.adjusted(bordWidth/2,bordWidth/2,-bordWidth/2-bordWidth%2,-bordWidth/2-bordWidth%2)); break; case FBRD_DASH: bpen.setStyle(Qt::DashLine); pnt.setPen(bpen); pnt.drawRect(dA.adjusted(bordWidth/2,bordWidth/2,-bordWidth/2-bordWidth%2,-bordWidth/2-bordWidth%2)); break; case FBRD_SOL: bpen.setStyle(Qt::SolidLine); pnt.setPen(bpen); pnt.drawRect(dA.adjusted(bordWidth/2,bordWidth/2,-bordWidth/2-bordWidth%2,-bordWidth/2-bordWidth%2)); break; case FBRD_DBL: bpen.setStyle(Qt::SolidLine); if(bordWidth/3) { int brdLnSpc = bordWidth-2*(bordWidth/3); bordWidth/=3; bpen.setWidth(bordWidth); pnt.setPen(bpen); pnt.drawRect(dA.adjusted(bordWidth/2,bordWidth/2,-bordWidth/2-bordWidth%2,-bordWidth/2-bordWidth%2)); pnt.drawRect(dA.adjusted(bordWidth+brdLnSpc+bordWidth/2,bordWidth+brdLnSpc+bordWidth/2, -bordWidth-brdLnSpc-bordWidth/2-bordWidth%2,-bordWidth-brdLnSpc-bordWidth/2-bordWidth%2)); } else { pnt.setPen(bpen); pnt.drawRect(dA.adjusted(bordWidth/2,bordWidth/2,-bordWidth/2-bordWidth%2,-bordWidth/2-bordWidth%2)); } break; case FBRD_GROOVE: { QPalette plt; plt.setColor(QPalette::Light,bpen.color().lighter(150)); plt.setColor(QPalette::Dark,bpen.color().lighter(50)); qDrawShadeRect(&pnt,dA,plt,true,bordWidth/2); break; } case FBRD_RIDGE: { QPalette plt; plt.setColor(QPalette::Light,bpen.color().lighter(150)); plt.setColor(QPalette::Dark,bpen.color().lighter(50)); qDrawShadeRect(&pnt,dA,plt,false,bordWidth/2); break; } case FBRD_INSET: { QPalette plt; plt.setColor(QPalette::Light,bpen.color().lighter(150)); plt.setColor(QPalette::Dark,bpen.color().lighter(50)); qDrawShadePanel(&pnt,dA,plt,true,bordWidth); break; } case FBRD_OUTSET: { QPalette plt; plt.setColor(QPalette::Light,bpen.color().lighter(150)); plt.setColor(QPalette::Dark,bpen.color().lighter(50)); qDrawShadePanel(&pnt,dA,plt,false,bordWidth); break; } } } bool WdgShape::attrSet( WdgView *view, int uiPrmPos, const string &val, const string &attr ) { return false; } //============ Support widget's shapes ============ //************************************************* //* Form element shape widget * //************************************************* ShapeFormEl::ShapeFormEl( ) : WdgShape("FormEl"), forceStl(NULL) { } void ShapeFormEl::init( WdgView *w ) { w->shpData = new ShpDt(); new QVBoxLayout(w); } void ShapeFormEl::destroy( WdgView *w ) { delete (ShpDt*)w->shpData; } bool ShapeFormEl::attrSet( WdgView *w, int uiPrmPos, const string &val, const string &attr ) { ShpDt *shD = (ShpDt*)w->shpData; DevelWdgView *devW = qobject_cast(w); RunWdgView *runW = qobject_cast(w); bool rel_cfg = false; //Reload configuration shD->evLock = true; switch(uiPrmPos) { case A_COM_LOAD: rel_cfg = true; break; case A_NO_ID: rel_cfg = true; if(attr == "vs_background") w->setProperty("vs_background", val.c_str()); else if(attr == "vs_border")w->setProperty("vs_border", val.c_str()); else rel_cfg = false; break; case A_EN: if(!runW) break; shD->en = (bool)s2i(val); runW->setVisible(shD->en && runW->permView()); if(shD->elType >= 0 && shD->addrWdg) //!!!! shD->addrWdg can to be not ready here in some cases shD->addrWdg->setVisible(shD->en && runW->permView()); break; case A_ACTIVE: if(!runW) break; shD->active = (bool)s2i(val); setActive(w, shD->active && runW->permCntr()); break; case A_GEOM_W: case A_GEOM_X_SC: rel_cfg = (shD->elType==F_TABLE); break; case A_GEOM_MARGIN: w->layout()->setContentsMargins(s2i(val), s2i(val), s2i(val), s2i(val)); rel_cfg = (shD->elType==F_BUTTON); break; case A_FormElType: if(shD->elType == s2i(val)) break; shD->elType = s2i(val); shD->setType = false; rel_cfg = true; break; case A_FormElValue: //if(shD->value != val) //To prevent for the possibility the value difference in the widget and the model. //Check for equality in setValue()! setValue(w, val); break; case A_FormElName: shD->name = TSYS::strDecode(val, TSYS::ShieldSymb); if(!shD->setType) break; switch(shD->elType) { case F_CHECK_BOX: ((QCheckBox*)shD->addrWdg)->setText(shD->name.c_str()); break; case F_BUTTON: ((QPushButton*)shD->addrWdg)->setText(shD->name.c_str()); break; case F_TREE: ((QTreeWidget*)shD->addrWdg)->setHeaderLabels(QStringList() << shD->name.c_str()); ((QTreeWidget*)shD->addrWdg)->headerItem()->setHidden(!shD->name.size()); break; } break; case A_FormElMixP1: rel_cfg = true; switch(shD->elType) { case F_LINE_ED: shD->view = s2i(val); break; case F_TEXT_ED: shD->opt1 = s2i(val); break; case F_BUTTON: shD->img = val; break; case F_COMBO: case F_LIST: case F_TREE: case F_TABLE: shD->items = val; break; case F_SLIDER: case F_SCROLL_BAR: shD->cfg = val; break; default: rel_cfg = false; } break; case A_FormElMixP2: rel_cfg = true; switch(shD->elType) { case F_LINE_ED: shD->cfg = val; break; case F_BUTTON: shD->color = val; break; case F_LIST: shD->opt1 = s2i(val); break; default: rel_cfg = false; } break; case A_FormElMixP3: shD->mode = s2i(val); rel_cfg = true; break; case A_FormElFont: shD->font = getFont(val,vmin(w->xScale(true),w->yScale(true))); rel_cfg = true; break; case A_FormElMixP4: shD->colorText = val; rel_cfg = true; break; } if(rel_cfg && !w->allAttrLoad()) { bool mk_new = false; int wAlign = 0; QFont elFnt = shD->font; //if(elFnt.pixelSize() > 0) elFnt.setPixelSize((int)((float)elFnt.pixelSize()*vmin(w->xScale(true),w->yScale(true)))); switch(shD->elType) { case F_LINE_ED: { LineEdit *wdg = (LineEdit*)shD->addrWdg; if(!wdg || !qobject_cast(wdg)) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new LineEdit(w, LineEdit::Text, !shD->mode); if(runW) connect(wdg, SIGNAL(apply()), this, SLOT(lineAccept())); mk_new = true; } //View LineEdit::LType tp = LineEdit::Text; switch(shD->view) { case FL_TEXT: tp = LineEdit::Text; break; case FL_PASS: tp = LineEdit::Password;break; case FL_COMBO: tp = LineEdit::Combo; break; case FL_INTEGER: tp = LineEdit::Integer; break; case FL_REAL: tp = LineEdit::Real; break; case FL_TIME: tp = LineEdit::Time; break; case FL_DATE: tp = LineEdit::Date; break; case FL_DATE_TM: tp = LineEdit::DateTime;break; } if(wdg->type() != tp) { wdg->setType(tp); mk_new = true; } if(shD->view == FL_COMBO) wdg->workWdg()->setFocusPolicy(Qt::StrongFocus); wdg->setCfg(shD->cfg.c_str()); //Cfg wdg->setFont(elFnt); //Font setValue(w, shD->value, true); //Value break; } case F_TEXT_ED: { TextEdit *wdg = (TextEdit*)shD->addrWdg; if(!wdg || !qobject_cast(wdg) || (runW && wdg->lang != ((VisRun*)runW->mainWin())->lang())) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new TextEdit(w, !shD->mode); if(runW) connect(wdg, SIGNAL(apply()), this, SLOT(textAccept())); mk_new = true; } wdg->workWdg()->setFont(elFnt); //Font setValue(w, shD->value, true); //Value wdg->workWdg()->setLineWrapMode(shD->opt1 ? QTextEdit::WidgetWidth : QTextEdit::NoWrap); //WordWrap break; } case F_CHECK_BOX: { QCheckBox *wdg = (QCheckBox*)shD->addrWdg; if(!wdg || !qobject_cast(wdg)) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new QCheckBox("test", w); if(runW) connect(wdg, SIGNAL(stateChanged(int)), this, SLOT(checkChange(int))); mk_new = true; } wdg->setFont(elFnt); //Font wdg->setText(shD->name.c_str());//Name setValue(w, shD->value, true); //Value break; } case F_BUTTON: { QPushButton *wdg = (QPushButton*)shD->addrWdg; if(!wdg || !qobject_cast(wdg)) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new QPushButton("test", w); wdg->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); if(runW) { connect(wdg, SIGNAL(pressed()), this, SLOT(buttonPressed())); connect(wdg, SIGNAL(released()), this, SLOT(buttonReleased())); connect(wdg, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool))); } mk_new = true; } bool toStlSYS = false; wdg->setText(shD->name.c_str()); //Name //Img QImage img; string backimg = w->resGet(shD->img); wdg->setStyle(NULL); if(!backimg.empty() && img.loadFromData((const uchar*)backimg.data(),backimg.size())) { if(mod->dropCommonWdgStls()) toStlSYS = true; int icSzW = 0, icSzH = 0; w->layout()->getContentsMargins(&icSzW, &icSzH, NULL, NULL); icSzW = w->width() - icSzW, icSzH = w->height() - icSzH; //int icSzW = w->width() - w->layout()->margin(); //int icSzH = w->height() - w->layout()->margin(); img = img.scaled(icSzW, icSzH, Qt::KeepAspectRatio, Qt::SmoothTransformation); wdg->setIconSize(QSize(icSzW,icSzH)); wdg->setIcon(QPixmap::fromImage(img)); } else wdg->setIcon(QPixmap()); //Color QPalette plt; QColor clr = getColor(shD->color); if(clr.isValid()) { plt.setColor(QPalette::Button, clr); if(mod->dropCommonWdgStls()) toStlSYS = true; //!!!! Early set CSS styles cannot be removed more //else wdg->setStyleSheet(QString("background: %1").arg(plt.color(QPalette::Button).name()/*shD->color.c_str()*/)); //But the alpha doesn't work here } //else if(!mod->dropCommonWdgStls()) wdg->setStyleSheet(QString("background: %1").arg(plt.color(QPalette::Button).name())); clr = getColor(shD->colorText); if(clr.isValid()) plt.setColor(QPalette::ButtonText, clr); wdg->setPalette(plt); wdg->setFont(elFnt); //Font setValue(w, shD->value, true); //Value //Force style processing if(toStlSYS) { if(!forceStl) #if QT_VERSION < 0x050000 forceStl = new QPlastiqueStyle(); #else forceStl = new QCommonStyle(); #endif wdg->setStyle(forceStl); } else if(wdg->style() != qApp->style()) wdg->setStyle(qApp->style()); break; } case F_COMBO: { QComboBox *wdg = (QComboBox*)shD->addrWdg; if(!wdg || !qobject_cast(wdg)) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new QComboBox(w); wdg->setFocusPolicy(Qt::StrongFocus); if(runW) connect(wdg, SIGNAL(currentIndexChanged(int)), this, SLOT(comboChange(int))); mk_new = true; } //Font wdg->setFont(elFnt); //Items wdg->clear(); wdg->addItems(QString(shD->items.c_str()).split("\n")); setValue(w, shD->value, true); //Value break; } case F_LIST: { QListWidget *wdg = (QListWidget*)shD->addrWdg; if(!wdg || !qobject_cast(wdg)) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new QListWidget(w); if(runW) connect(wdg, SIGNAL(itemSelectionChanged()), this, SLOT(listChange())); mk_new = true; } wdg->setSelectionMode(shD->opt1?QAbstractItemView::ExtendedSelection:QAbstractItemView::SingleSelection); //Items // Light updating for true work on mobile devices like to Maemo, MeeGo int itN = 0; string itVl; for(int off = 0; (itVl=TSYS::strLine(shD->items,0,&off)).size() || off < (int)shD->items.size(); itN++) { if(itN >= wdg->count()) wdg->addItem(itVl.c_str()); else if(wdg->item(itN)->text() != itVl.c_str()) wdg->item(itN)->setText(itVl.c_str()); } while(itN < wdg->count()) delete wdg->takeItem(wdg->count()-1); //wdg->clear(); //wdg->addItems(QString(shD->items.c_str()).split("\n")); wdg->setFont(elFnt); //Font setValue(w, shD->value, true); //Value break; } case F_TREE: { QTreeWidget *wdg = (QTreeWidget*)shD->addrWdg; if(!wdg || !qobject_cast(wdg)) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new QTreeWidget(w); wdg->setAlternatingRowColors(true); wdg->setSelectionMode(QAbstractItemView::SingleSelection); wdg->setSelectionBehavior(QAbstractItemView::SelectRows); wdg->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); wdg->setHeaderLabels(QStringList() << shD->name.c_str()); wdg->headerItem()->setHidden(!shD->name.size()); if(runW) connect(wdg, SIGNAL(itemSelectionChanged()), this, SLOT(treeChange())); mk_new = true; } //Items wdg->clear(); string ipath, item; QTreeWidgetItem *cur_it = NULL, *t_it = NULL; shD->addrWdg->blockSignals(true); QFont noSelFnt = elFnt; noSelFnt.setItalic(true); for(int off = 0; (ipath=TSYS::strLine(shD->items,0,&off)).size(); ) { for(int off1 = 0, lev = 0; (item=TSYS::pathLev(ipath,0,true,&off1)).size(); lev++) if(lev == 0) { cur_it = NULL; for(int iR = 0; !cur_it && iR < wdg->topLevelItemCount(); iR++) if(wdg->topLevelItem(iR)->text(0) == item.c_str()) cur_it = wdg->topLevelItem(iR); if(!cur_it) { cur_it = new QTreeWidgetItem(0); cur_it->setText(0, item.c_str()); cur_it->setFlags(cur_it->flags()&(~Qt::ItemIsSelectable)); cur_it->setData(0, Qt::FontRole, noSelFnt); wdg->addTopLevelItem(cur_it); } } else { t_it = NULL; for(int iR = 0; !t_it && iR < cur_it->childCount(); iR++) if(cur_it->child(iR)->text(0) == item.c_str()) t_it = cur_it->child(iR); if(!t_it) { t_it = new QTreeWidgetItem(cur_it); t_it->setText(0, item.c_str()); t_it->setFlags(cur_it->flags()&(~Qt::ItemIsSelectable)); t_it->setData(0, Qt::FontRole, noSelFnt); } cur_it = t_it; } if(cur_it) { cur_it->setFlags(cur_it->flags()|Qt::ItemIsSelectable); cur_it->setData(0, Qt::FontRole, elFnt); cur_it->setData(0, Qt::UserRole, ipath.c_str()); } } shD->addrWdg->blockSignals(false); wdg->setFont(elFnt); //Font setValue(w, shD->value, true); //Value break; } case F_TABLE: { QTableWidget *wdg = (QTableWidget*)shD->addrWdg; if(!wdg || !qobject_cast(wdg)) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = new QTableWidget(w); wdg->setItemDelegate(new TableDelegate); wdg->setAlternatingRowColors(true); wdg->setSelectionMode(QAbstractItemView::SingleSelection); wdg->setSelectionBehavior(QAbstractItemView::SelectItems); wdg->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); if(runW) { connect(wdg, SIGNAL(itemSelectionChanged()), this, SLOT(tableSelectChange())); connect(wdg, SIGNAL(cellChanged(int,int)), this, SLOT(tableChange(int,int))); } mk_new = true; } bool toReFit = (elFnt != wdg->font()); wdg->setFont(elFnt); //Font //Items if(shD->items == "") break; shD->addrWdg->blockSignals(true); XMLNode tX("tbl"); bool hdrPresent = false, colsWdthFit = false; int maxCols = 0, maxRows = 0; try { tX.load(shD->items); } catch(...) { } if(tX.name() != "tbl") { wdg->clear(); wdg->horizontalHeader()->setVisible(false); wdg->verticalHeader()->setVisible(false); } else { int scrollPosV = -1, scrollPosH = -1; //Review the sorting implementation in edition the table if(wdg->isSortingEnabled()) { // Saving the user sorting configuration if(wdg->verticalScrollBar() && wdg->verticalScrollBar()->isVisible()) scrollPosV = wdg->verticalScrollBar()->value(); if(wdg->horizontalScrollBar() && wdg->horizontalScrollBar()->isVisible()) scrollPosH = wdg->horizontalScrollBar()->value(); wdg->setProperty("sortCol", (wdg->horizontalHeader()->sortIndicatorSection()+1)*((wdg->horizontalHeader()->sortIndicatorOrder()==Qt::AscendingOrder)?1:-1)); // Disabling the sorting before processing wdg->setSortingEnabled(false); wdg->setRowCount(0); } else wdg->setProperty("sortCol", QVariant()); string wVl, rClr, rClrTxt, rFnt, rPrec; int sortCol = 0; // Items for(unsigned iR = 0, iRR = 0, iCh = 0; iCh < tX.childSize() || (int)iR < wdg->rowCount(); iCh++) { XMLNode *tR = (iCh < tX.childSize()) ? tX.childGet(iCh) : NULL; bool isH = false; QTableWidgetItem *hit = NULL, *tit = NULL; if(tR && !((isH=(tR->name()=="h")) || tR->name() == "r")) continue; if(!isH && (int)iR >= wdg->rowCount()) { wdg->setRowCount(iR+1); toReFit = true; } //!!!! Column width must be refitted at adding rows also if(!isH && tR) { rClr = tR->attr("color"); rClrTxt = tR->attr("colorText"); rFnt = tR->attr("font"); rPrec = tR->attr("prec"); } for(unsigned iC = 0, iCR = 0, iCh1 = 0; (tR && iCh1 < tR->childSize()) || (int)iC < wdg->columnCount(); iCh1++) { XMLNode *tC = (tR && iCh1 < tR->childSize()) ? tR->childGet(iCh1) : NULL; if(tC && (int)iC >= wdg->columnCount()) { wdg->setColumnCount(iC+1); toReFit = true; } if(!(hit=wdg->horizontalHeaderItem(iC))) { wdg->setHorizontalHeaderItem(iC, (hit=new QTableWidgetItem())); toReFit = true; } if(isH) { //Header process hit->setText(tC?tC->text().c_str():""); hit->setData(Qt::FontRole, elFnt); if(tC) { if(tC->text() != hit->text().toStdString()) toReFit = true; if((wVl=tC->attr("width")) != hit->data(Qt::UserRole+7).toString().toStdString()) { hit->setData(Qt::UserRole+7, wVl.c_str()); hit->setData(Qt::UserRole, QVariant()); wdg->showColumn(iC); //!!!! Need for updating the columns width if(wVl.size()) { int wdthCel = fmax(0, s2i(wVl)); if(!wdthCel) wdg->hideColumn(iC); else hit->setData(Qt::UserRole, (wVl.find("%") == wVl.size()-1) ? -wdthCel : wdthCel); } toReFit = true; } hit->setData(Qt::UserRole+1, (bool)s2i(tC->attr("edit"))); hit->setData(Qt::UserRole+2, ((wVl=tC->attr("color")).size()) ? QString::fromStdString(wVl) : QVariant()); hit->setData(Qt::UserRole+3, ((wVl=tC->attr("colorText")).size()) ? QString::fromStdString(wVl) : QVariant()); hit->setData(Qt::UserRole+4, ((wVl=tC->attr("font")).size()) ? QString::fromStdString(wVl) : QVariant()); hit->setData(Qt::UserRole+6, tC->attr("align").c_str()); if((wVl=tC->attr("sort")).size()) { sortCol = iC+1; if(s2i(wVl)) sortCol *= -1; } hit->setData(Qt::UserRole+8, ((wVl=tC->attr("prec")).size()) ? QString::fromStdString(wVl) : QVariant()); } } else { //Rows content process if(!(tit=wdg->item(iR,iC))) wdg->setItem(iR, iC, (tit=new QTableWidgetItem())); // Value QVariant v; if(tC) switch(tC->name()[0]) { case 'b': v = (bool)s2i(tC->text()); break; case 'i': v = s2ll(tC->text()); break; case 'r': if((wVl=tC->attr("prec")).empty() && (wVl=hit->data(Qt::UserRole+8).toString().toStdString()).empty() && (wVl=rPrec).empty()) wVl = "6"; v = s2r(r2s(s2r(tC->text()),s2i(wVl))); break; case 't': tit->setData(TableDelegate::OneLineString, false); v = QString::fromStdString(tC->text()); break; default: tit->setData(TableDelegate::OneLineString, true); v = QString::fromStdString(tC->text()); break; } tit->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); tit->setData(Qt::DisplayRole, QVariant()); //!!!! To clean up the stored QVariant type for next reusing tit->setData(Qt::DisplayRole, v); // Back color if((tC && (wVl=tC->attr("color")).size()) || (wVl=hit->data(Qt::UserRole+2).toString().toStdString()).size() || (wVl=rClr).size()) tit->setData(Qt::BackgroundRole, QColor(wVl.c_str())); else tit->setData(Qt::BackgroundRole, QVariant()); // Text font and color if((tC && (wVl=tC->attr("colorText")).size()) || (wVl=hit->data(Qt::UserRole+3).toString().toStdString()).size() || (wVl=rClrTxt).size()) tit->setData(Qt::ForegroundRole, QColor(wVl.c_str())); else tit->setData(Qt::ForegroundRole, QVariant()); if((tC && (wVl=tC->attr("font")).size()) || (wVl=hit->data(Qt::UserRole+4).toString().toStdString()).size() || (wVl=rFnt).size()) tit->setData(Qt::FontRole, getFont(wVl.c_str(),vmin(w->xScale(true),w->yScale(true)),true,elFnt)); else tit->setData(Qt::FontRole, QVariant()); // Cell image QImage img; if(tC && (wVl=w->resGet(tC->attr("img"))).size() && img.loadFromData((const uchar*)wVl.data(),wVl.size())) tit->setData(Qt::DecorationRole, QPixmap::fromImage(img)); else tit->setData(Qt::DecorationRole, QVariant()); // Modify set if(hit->data(Qt::UserRole+1).toBool() || (tC && s2i(tC->attr("edit")))) tit->setFlags(tit->flags()|Qt::ItemIsEditable); else tit->setFlags(tit->flags()&(~Qt::ItemIsEditable)); // Alignment set if((tC && (wVl=tC->attr("align")).size()) || (wVl=hit->data(Qt::UserRole+6).toString().toStdString()).size()) { int flgs = Qt::TextWordWrap | Qt::AlignVCenter; if(wVl == "left") flgs |= Qt::AlignLeft; else if(wVl == "right") flgs |= Qt::AlignRight; else if(wVl == "center") flgs |= Qt::AlignHCenter; tit->setData(Qt::TextAlignmentRole, flgs); } else tit->setData(Qt::TextAlignmentRole, QVariant()); // Original position tit->setData(Qt::UserRole+1, iC); tit->setData(Qt::UserRole+2, iR); } if(tC) { ++iCR; maxCols = vmax(maxCols, (int)iCR); } iC++; } if(!isH) { if(tR) { ++iRR; maxRows = vmax(maxRows, (int)iRR); } iR++; } else hdrPresent = true; } // Generic properties set int keyID = s2i(tX.attr("keyID")); wdg->setProperty("sel", (wVl=tX.attr("sel")).c_str()); if(wVl == "row") { wdg->setSelectionBehavior(QAbstractItemView::SelectRows); keyID = vmin(keyID, maxCols-1); } else if(wVl == "col") { wdg->setSelectionBehavior(QAbstractItemView::SelectColumns); keyID = vmin(keyID, maxRows-1); } else wdg->setSelectionBehavior(QAbstractItemView::SelectItems); wdg->setProperty("keyID", keyID); colsWdthFit = s2i(tX.attr("colsWdthFit")); wdg->horizontalHeader()->setVisible(tX.attr("hHdrVis").size()?s2i(tX.attr("hHdrVis")):hdrPresent); wdg->verticalHeader()->setVisible(s2i(tX.attr("vHdrVis"))); if(wdg->columnCount() != maxCols) toReFit = true; wdg->setColumnCount(maxCols); wdg->setRowCount(maxRows); wdg->setProperty("colsWdthFit", colsWdthFit); shD->addrWdg->blockSignals(false); if(s2i(tX.attr("sortEn")) || sortCol) { if(sortCol) { if(wdg->property("sortColSet").isValid() && sortCol != wdg->property("sortColSet").toInt()) wdg->setProperty("sortCol", QVariant()); wdg->setProperty("sortColSet", sortCol); } else wdg->setProperty("sortColSet", QVariant()); wdg->setSortingEnabled(true); // Restorring/enabling the sorting // First visible column detection for(int iC = 0; !sortCol && iC < wdg->columnCount(); iC++) if(!wdg->isColumnHidden(iC)) sortCol = iC+1; if(toReFit || !wdg->property("sortCol").isValid()) wdg->setProperty("sortCol", sortCol); sortCol = wdg->property("sortCol").toInt(); wdg->sortItems((sortCol?abs(sortCol)-1:0), ((sortCol>=0)?Qt::AscendingOrder:Qt::DescendingOrder)); if(scrollPosV > 0) wdg->verticalScrollBar()->setValue(scrollPosV); if(scrollPosH > 0) wdg->horizontalScrollBar()->setValue(scrollPosH); } setValue(w, shD->value, true); //Value wdg->resize(w->size()); if(toReFit) tableFit(w); else { wdg->resizeRowsToContents(); for(int iRW = 0; iRW < wdg->rowCount(); iRW++) wdg->setRowHeight(iRW, vmin(wdg->rowHeight(iRW), wdg->size().height()/2)); } } if(shD->items.size() > 10000) shD->items = ""; break; } case F_SLIDER: case F_SCROLL_BAR: { QAbstractSlider *wdg = (QAbstractSlider*)shD->addrWdg; if(!wdg || (shD->elType == F_SLIDER && !qobject_cast(wdg)) || (shD->elType == F_SCROLL_BAR && !qobject_cast(wdg))) { if(wdg) wdg->deleteLater(); shD->addrWdg = wdg = (shD->elType == F_SLIDER ? (QAbstractSlider*)new QSlider(w) : (QAbstractSlider*)new QScrollBar(w)); if(shD->elType == F_SLIDER) ((QSlider*)wdg)->setTickPosition(QSlider::TicksBothSides); wdg->setTracking(false); if(runW) connect(wdg, SIGNAL(valueChanged(int)), this, SLOT(sliderMoved(int))); mk_new = true; } int cfgOff = 0; if(s2i(TSYS::strSepParse(shD->cfg,0,':',&cfgOff))) { wdg->setOrientation(Qt::Vertical); wAlign = Qt::AlignHCenter; } else { wdg->setOrientation(Qt::Horizontal); wAlign = Qt::AlignVCenter; } wdg->blockSignals(true); wdg->setMinimum(s2i(TSYS::strSepParse(shD->cfg,0,':',&cfgOff))); wdg->setMaximum(s2i(TSYS::strSepParse(shD->cfg,0,':',&cfgOff))); wdg->setSingleStep(s2i(TSYS::strSepParse(shD->cfg,0,':',&cfgOff))); wdg->setPageStep(s2i(TSYS::strSepParse(shD->cfg,0,':',&cfgOff))); wdg->blockSignals(false); setValue(w, shD->value, true); break; } } shD->setType = true; if(mk_new) { // Install event's filter and disable focus eventFilterSet(w, shD->addrWdg, true); w->setFocusProxy(shD->addrWdg); if(devW) setFocus(w, shD->addrWdg, false, devW); if(runW) setActive(w, shD->active && runW->permCntr()); shD->addrWdg->setVisible(shD->en); // Fix widget ((QVBoxLayout*)w->layout())->addWidget(shD->addrWdg); } if(wAlign) ((QVBoxLayout*)w->layout())->setAlignment(shD->addrWdg, (Qt::AlignmentFlag)wAlign); } if(rel_cfg && !w->allAttrLoad() && shD->addrWdg) switch(shD->elType) { case F_LINE_ED: case F_TEXT_ED: case F_COMBO: case F_LIST: case F_TREE: case F_TABLE: { string tVl, tVl1; if((tVl=w->property("vs_background").toString().toStdString()).size()) { tVl1 = TSYS::strParse(tVl, 0, " "); QPalette plt(shD->addrWdg->palette()); QBrush brsh = plt.brush(QPalette::Base); brsh.setColor(getColor(tVl1)); if(!brsh.color().isValid()) brsh.setColor(QPalette().brush(QPalette::Base).color()); QImage img; tVl1 = w->resGet(TSYS::strParse(tVl,1," ")); if(tVl1.size()) img.loadFromData((const uchar*)tVl1.data(), tVl1.size()); brsh.setTextureImage(img); brsh.setStyle(brsh.textureImage().isNull() ? Qt::SolidPattern : Qt::TexturePattern); plt.setBrush(QPalette::Base, brsh); shD->addrWdg->setPalette(plt); } tVl = w->property("vs_border").toString().toStdString(); shD->addrWdg->setStyleSheet(tVl.size()?QString("border: %1").arg(tVl.c_str()):""); } } shD->evLock = false; return true; } void ShapeFormEl::setActive( WdgView *w, bool val ) { ShpDt *shD = (ShpDt*)w->shpData; if(!shD->setType) return; switch(shD->elType) { case F_LINE_ED: ((LineEdit*)shD->addrWdg)->setReadOnly(!val); break; case F_TEXT_ED: ((TextEdit*)shD->addrWdg)->workWdg()->setReadOnly(!val); break; case F_BUTTON: shD->addrWdg->setEnabled(val); if(val) shD->addrWdg->setCursor(Qt::PointingHandCursor); else shD->addrWdg->unsetCursor(); break; case F_TABLE: ((QTableWidget*)shD->addrWdg)->itemDelegate()->setProperty("active", val); break; default: shD->addrWdg->setEnabled(val); } setFocus(w, shD->addrWdg, val); } void ShapeFormEl::setValue( WdgView *w, const string &val, bool force ) { RunWdgView *runW = qobject_cast(w); ShpDt *shD = (ShpDt*)w->shpData; shD->value = val; if(!shD->addrWdg || (!force && !shD->setType)) return; switch(shD->elType) { case F_LINE_ED: //if(!((LineEdit*)shD->addrWdg)->isEdited()) ((LineEdit*)shD->addrWdg)->setValue(val.c_str()); break; case F_TEXT_ED: ((TextEdit*)shD->addrWdg)->setText(val.c_str()); break; case F_CHECK_BOX: shD->addrWdg->blockSignals(true); ((QCheckBox*)shD->addrWdg)->setChecked(s2i(val)); shD->addrWdg->blockSignals(false); break; case F_BUTTON: { QPushButton *wdg = (QPushButton*)shD->addrWdg; wdg->setCheckable(false); wdg->setAutoRepeat(false); if(wdg->menu()) { wdg->menu()->deleteLater(); wdg->setMenu(NULL); } switch(shD->mode) { case FBT_STD: { unsigned delay = 0, interv = 0; sscanf(shD->value.c_str(), "%u-%u", &delay, &interv); if(delay && interv) { wdg->setAutoRepeat(true); wdg->setAutoRepeatDelay(delay); wdg->setAutoRepeatInterval(interv); } break; } case FBT_CHECK: wdg->setCheckable(true); //Checkable wdg->setChecked(s2i(shD->value)); //Value break; case FBT_MENU: { QAction *cur_act = NULL; QMenu *menu = new QMenu(wdg), *menuNext; wdg->setMenu(menu); while(wdg->actions().size()) wdg->removeAction(wdg->actions()[0]); //Fill menu string ipath, item; for(int off = 0; (ipath=TSYS::strLine(shD->value,0,&off)).size(); ) { string treeItPath = ""; menu = menuNext = wdg->menu(); for(int off1 = 0, lev = 0; (item=TSYS::pathLev(ipath,0,true,&off1)).size(); lev++) { treeItPath += "/"+item; if(menuNext) menu = menuNext; else { menu = new QMenu(menu); cur_act->setMenu(menu); connect(menu->menuAction(), SIGNAL(triggered()), this, SLOT(buttonMenuTrig())); } cur_act = NULL; for(int iA = 0; iA < menu->actions().size(); iA++) if(menu->actions()[iA]->text() == item.c_str()) cur_act = menu->actions()[iA]; if(!cur_act) { cur_act = new QAction(item.c_str(), wdg); connect(cur_act, SIGNAL(triggered()), this, SLOT(buttonMenuTrig())); cur_act->setData(treeItPath.c_str()); menu->addAction(cur_act); } menuNext = cur_act->menu(); } } break; } case FBT_SAVE: if(!runW) break; shD->opt1 = true; QTimer::singleShot(100, wdg, SIGNAL(released())); break; } break; } case F_COMBO: if(((QComboBox*)shD->addrWdg)->currentText().toStdString() == val) break; if(((QComboBox*)shD->addrWdg)->findText(val.c_str()) < 0) ((QComboBox*)shD->addrWdg)->addItem(val.c_str()); ((QComboBox*)shD->addrWdg)->setCurrentIndex(((QComboBox*)shD->addrWdg)->findText(val.c_str())); break; case F_LIST: { QListWidget *wdg = (QListWidget*)shD->addrWdg; //Light updating for true work on mobile devices like to Maemo, MeeGo string vl; bool scrollTo = false; for(int off = 0, cnt = 0; (vl=TSYS::strLine(val,0,&off)).size(); cnt++) { QList its = wdg->findItems(vl.c_str(), Qt::MatchExactly); if(!its.size()) { wdg->addItem(vl.c_str()); its = wdg->findItems(vl.c_str(), Qt::MatchExactly); } if(its.size()) { if(!its[0]->isSelected()) { wdg->setCurrentItem(its[0], QItemSelectionModel::Select); if(!scrollTo) wdg->scrollToItem(its[0]); scrollTo = true; } its[0]->setData(Qt::UserRole, true); } } //Clean from the last selections QList its = wdg->selectedItems(); for(int iT = 0; iT < its.size(); iT++) { if(its[iT]->isSelected() && !its[iT]->data(Qt::UserRole).toBool()) its[iT]->setSelected(false); its[iT]->setData(Qt::UserRole, false); } break; } case F_TREE: { QTreeWidget *wdg = (QTreeWidget*)shD->addrWdg; QTreeWidgetItem *cur_it = NULL; string item; for(int off = 0, lev = 0; (item=TSYS::pathLev(val,0,true,&off)).size(); lev++) if(lev == 0) { for(int iR = 0; !cur_it && iR < wdg->topLevelItemCount(); iR++) if(wdg->topLevelItem(iR)->text(0) == item.c_str()) cur_it = wdg->topLevelItem(iR); if(!cur_it) break; } else { bool findOK = false; for(int iR = 0; !findOK && iR < cur_it->childCount(); iR++) if(cur_it->child(iR)->text(0) == item.c_str()) { cur_it = cur_it->child(iR); findOK = true; } if(!findOK) { cur_it = NULL; break; } } while(wdg->selectedItems().size()) wdg->selectedItems()[0]->setSelected(false); if(cur_it) { shD->addrWdg->blockSignals(true); cur_it->setSelected(true); shD->addrWdg->blockSignals(false); wdg->scrollToItem(cur_it); //Expand all parents for visible selected //for(int i_l = 0; cur_it; i_l++) { if(i_l > 0) cur_it->setExpanded(true); cur_it = cur_it->parent(); } } break; } case F_TABLE: { QTableWidget *wdg = (QTableWidget*)shD->addrWdg; QList foundIts = wdg->findItems(val.c_str(), Qt::MatchExactly); QTableWidgetItem *selIt = NULL, *selItPrev = wdg->currentItem(); switch(wdg->selectionBehavior()) { case QAbstractItemView::SelectRows: for(QList::iterator iIt = foundIts.begin(); !selIt && iIt != foundIts.end(); ++iIt) if((*iIt)->data(Qt::UserRole+1).toInt() == wdg->property("keyID").toInt()) selIt = *iIt; break; case QAbstractItemView::SelectColumns: for(QList::iterator iIt = foundIts.begin(); !selIt && iIt != foundIts.end(); ++iIt) if((*iIt)->data(Qt::UserRole+2).toInt() == wdg->property("keyID").toInt()) selIt = *iIt; break; default: { if(wdg->property("sel").toString() == "cell") selIt = foundIts.length() ? foundIts.front() : NULL; else selIt = wdg->item(s2i(TSYS::strParse(val,0,":")), s2i(TSYS::strParse(val,1,":"))); break; } } shD->addrWdg->blockSignals(true); if(selIt) { wdg->setCurrentItem(selIt); if(selIt != selItPrev) wdg->scrollToItem(selIt); } else wdg->setCurrentItem(NULL); shD->addrWdg->blockSignals(false); break; } case F_SLIDER: case F_SCROLL_BAR: shD->addrWdg->blockSignals(true); ((QAbstractSlider*)shD->addrWdg)->setValue(s2i(val)); shD->addrWdg->blockSignals(false); break; } } void ShapeFormEl::tableFit( WdgView *w ) { ShpDt *shD = (ShpDt*)w->shpData; QTableWidget *wdg = (QTableWidget*)shD->addrWdg; if(shD->elType != F_TABLE || !wdg || !qobject_cast(wdg)) return; wdg->horizontalHeader()->setStretchLastSection(false); if(wdg->columnCount() > 1) wdg->resizeColumnsToContents(); int tblWdth = wdg->maximumViewportSize().width() - ((wdg->verticalScrollBar()&&wdg->verticalScrollBar()->isVisible())?wdg->verticalScrollBar()->size().width():0); int averWdth = wdg->columnCount() ? (tblWdth/wdg->columnCount()) : 0; int fullColsWdth = 0, niceForceColsWdth = 0, busyCols = 0, tVl; //Count width params for(int iC = 0; iC < wdg->columnCount(); iC++) { fullColsWdth += wdg->columnWidth(iC); if(wdg->horizontalHeaderItem(iC) && (tVl=wdg->horizontalHeaderItem(iC)->data(Qt::UserRole).toInt())) { tVl = (tVl < 0) ? tblWdth*abs(tVl)/100 : tVl*w->xScale(true); niceForceColsWdth += tVl; wdg->setColumnWidth(iC, tVl); } else if(wdg->columnWidth(iC) <= averWdth) niceForceColsWdth += wdg->columnWidth(iC); else busyCols++; } if(wdg->property("colsWdthFit").toBool() && wdg->rowCount()) { for(int iIt = 0; busyCols && iIt < 10; iIt++) { int busyColsWdth = (tblWdth-niceForceColsWdth)/busyCols; int busyCols_ = 0, niceForceColsWdth_ = 0; for(int iC = 0; iC < wdg->columnCount(); iC++) if((wdg->horizontalHeaderItem(iC) && wdg->horizontalHeaderItem(iC)->data(Qt::UserRole).toInt()) || wdg->columnWidth(iC) < busyColsWdth) niceForceColsWdth_ += wdg->columnWidth(iC); else busyCols_++; if(busyCols_ == busyCols) break; busyCols = busyCols_; niceForceColsWdth = niceForceColsWdth_; } //Set busyCols if(fullColsWdth > tblWdth && busyCols) { int busyColsWdth = (tblWdth-niceForceColsWdth)/busyCols; for(int iC = 0; iC < wdg->columnCount(); iC++) if((!wdg->horizontalHeaderItem(iC) || !wdg->horizontalHeaderItem(iC)->data(Qt::UserRole).toInt()) && wdg->columnWidth(iC) > averWdth && wdg->columnWidth(iC) > busyColsWdth) wdg->setColumnWidth(iC, busyColsWdth); } } if(wdg->property("colsWdthFit").toBool()) wdg->horizontalHeader()->setStretchLastSection(true); wdg->resizeRowsToContents(); for(int iRW = 0; iRW < wdg->rowCount(); iRW++) wdg->setRowHeight(iRW, vmin(wdg->rowHeight(iRW), wdg->size().height()/2)); } bool ShapeFormEl::event( WdgView *w, QEvent *event ) { if(qobject_cast(w)) switch(event->type()) { case QEvent::Hide: { ShpDt *shD = (ShpDt*)w->shpData; switch(shD->elType) { case F_LINE_ED: ((LineEdit*)shD->addrWdg)->setValue(((LineEdit*)shD->addrWdg)->value()); break; case F_TEXT_ED: ((TextEdit*)shD->addrWdg)->setText(((TextEdit*)shD->addrWdg)->text()); break; } break; } default: break; } return false; } bool ShapeFormEl::eventFilter( WdgView *w, QObject *object, QEvent *event ) { //Common actions switch(event->type()) { case QEvent::Resize: if(((ShpDt*)w->shpData)->elType == F_TABLE && object == ((ShpDt*)w->shpData)->addrWdg && ((QResizeEvent*)event)->size() != ((QResizeEvent*)event)->oldSize()) tableFit(w); break; case QEvent::Show: if(((ShpDt*)w->shpData)->elType == F_TABLE && (object == ((QTableWidget*)((ShpDt*)w->shpData)->addrWdg)->verticalScrollBar() || object == ((QTableWidget*)((ShpDt*)w->shpData)->addrWdg)->verticalHeader())) tableFit(w); break; default: break; } //Specific actions to the mode if(qobject_cast(w)) switch(event->type()) { case QEvent::Enter: case QEvent::Leave: return true; case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::ContextMenu: QApplication::sendEvent(w, event); return true; default: break; } else { //AttrValS attrs; switch(event->type()) { case QEvent::FocusIn: qobject_cast(w)->mainWin()->setFocus(w->id()); break; /*if(!w->hasFocus()) break; attrs.push_back(std::make_pair("focus","1")); attrs.push_back(std::make_pair("event","ws_FocusIn")); w->attrsSet(attrs); break; case QEvent::FocusOut: if(w->hasFocus()) break; attrs.push_back(std::make_pair("focus","0")); attrs.push_back(std::make_pair("event","ws_FocusOut")); w->attrsSet(attrs); break;*/ case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: QApplication::sendEvent(w, event); break; case QEvent::Wheel: if(qobject_cast(object) && !((QComboBox*)object)->hasFocus()) { event->ignore(); return true; } default: break; } } return false; } void ShapeFormEl::lineAccept( ) { LineEdit *el = (LineEdit*)sender(); WdgView *view = (WdgView *)el->parentWidget(); AttrValS attrs; attrs.push_back(std::make_pair("value",el->value().toStdString())); attrs.push_back(std::make_pair("event","ws_LnAccept")); view->attrsSet(attrs); } void ShapeFormEl::textAccept( ) { TextEdit *el = (TextEdit*)sender(); WdgView *view = (WdgView *)el->parentWidget(); AttrValS attrs; attrs.push_back(std::make_pair("value",el->text().toStdString())); attrs.push_back(std::make_pair("event","ws_TxtAccept")); view->attrsSet(attrs); } void ShapeFormEl::checkChange( int st ) { WdgView *view = (WdgView *)((QCheckBox*)sender())->parentWidget(); AttrValS attrs; attrs.push_back(std::make_pair("value",i2s(st))); attrs.push_back(std::make_pair("event","ws_ChkChange")); view->attrsSet(attrs); } void ShapeFormEl::buttonPressed( ) { WdgView *w = (WdgView *)((QPushButton*)sender())->parentWidget(); switch(((ShpDt*)w->shpData)->mode) { case FBT_STD: case FBT_SAVE: w->attrSet("event", "ws_BtPress", A_NO_ID, true); break; } } void ShapeFormEl::buttonReleased( ) { RunWdgView *w = (RunWdgView *)((QPushButton*)sender())->parentWidget(); ShpDt *shD = (ShpDt*)w->shpData; switch(shD->mode) { case FBT_STD: w->attrSet("event", "ws_BtRelease", A_NO_ID, true); break; case FBT_SAVE: { if(!shD->opt1) { //The event from timer w->attrSet("event", "ws_BtRelease", A_NO_ID, true); break; } shD->opt1 = false; int off = 0; string fHead = TSYS::strLine(shD->value, 0, &off); string fCtx = shD->value.substr(off); off = 0; string fTmpl = TSYS::strParse(fHead, 0, "|", &off), fTitle = TSYS::strParse(fHead, 0, "|", &off), fDefFile = TSYS::strParse(fHead, 0, "|", &off); if(fTmpl.empty()) break; if(fTitle.empty()) fTitle = _("Saving a file"); QString fn = w->mainWin()->getFileName(fTitle.c_str(), fDefFile.c_str(), fTmpl.c_str(), QFileDialog::AcceptSave); if(fn.size()) { QFile file(fn); if(!file.open(QIODevice::WriteOnly|QIODevice::Truncate)) { mod->postMess(mod->nodePath().c_str(), QString(_("Error opening the file '%1': %2")).arg(fn).arg(file.errorString()), TVision::Error); break; } if(file.write(fCtx.data(),fCtx.size()) != (int)fCtx.size()) mod->postMess(mod->nodePath().c_str(), QString(_("Error writing the data to the file '%1': %2")).arg(fn).arg(file.errorString()), TVision::Error); } //!!!! Clearing the attribute "value", but it can be spare for multiple connections to one session. w->attrSet("value", "", A_NO_ID, true); break; } case FBT_LOAD: { int off = 0; string fHead = TSYS::strLine(shD->value, 0, &off); string fCtx = shD->value.substr(off); off = 0; string fTmpl = TSYS::strParse(fHead, 0, "|", &off), fTitle = TSYS::strParse(fHead, 0, "|", &off), fDefFile = TSYS::strParse(fHead, 0, "|", &off), fMime = TSYS::strParse(fHead, 0, "|", &off); if(fTmpl.empty()) break; if(fTitle.empty()) fTitle = _("Loading a file"); QString fn = w->mainWin()->getFileName(fTitle.c_str(), fDefFile.c_str(), fTmpl.c_str(), QFileDialog::AcceptOpen); if(!fn.size()) break; QFile file(fn); if(!file.open(QFile::ReadOnly)) { mod->postMess(mod->nodePath().c_str(), QString(_("Error opening the file '%1': %2")).arg(fn).arg(file.errorString()), TVision::Error); break; } if(file.size() >= limUserFile_SZ) { mod->postMess(mod->nodePath().c_str(), QString(_("The download file '%1' is very large.")).arg(fn), TVision::Error); break; } QByteArray data = file.readAll(); AttrValS attrs; attrs.push_back(std::make_pair("event","ws_BtLoad")); attrs.push_back(std::make_pair("value",fTmpl+"|"+fTitle+"|"+fn.toStdString()+"|"+fMime+"\n"+string(data.data(),data.size()))); w->attrsSet(attrs); break; } } } void ShapeFormEl::buttonToggled( bool val ) { WdgView *w = (WdgView *)((QPushButton*)sender())->parentWidget(); if(((ShpDt*)w->shpData)->evLock) return; AttrValS attrs; attrs.push_back(std::make_pair("event", string("ws_BtToggleChange\n")+(val?"ws_BtPress":"ws_BtRelease"))); attrs.push_back(std::make_pair("value", i2s(val))); w->attrsSet(attrs); } void ShapeFormEl::buttonMenuTrig( ) { QAction *act = (QAction*)sender(); QWidget *wA = dynamic_cast(act->parent()); WdgView *w = wA ? dynamic_cast(wA->parentWidget()) : NULL; if(w) w->attrSet("event", "ws_BtMenu="+act->data().toString().toStdString(), A_NO_ID, true); } void ShapeFormEl::comboChange( int id ) { QComboBox *comb = (QComboBox *)sender(); WdgView *w = (WdgView *)comb->parentWidget(); if(((ShpDt*)w->shpData)->evLock) return; AttrValS attrs; attrs.push_back(std::make_pair("value",comb->itemText(id).toStdString())); attrs.push_back(std::make_pair("event","ws_CombChange")); w->attrsSet(attrs); } void ShapeFormEl::listChange( ) { QListWidget *el = (QListWidget*)sender(); WdgView *w = (WdgView *)el->parentWidget(); if(((ShpDt*)w->shpData)->evLock) return; string vl = ""; for(int iS = 0; iS < el->selectedItems().size(); iS++) vl += (vl.size()?"\n":"") + el->selectedItems()[iS]->text().toStdString(); AttrValS attrs; attrs.push_back(std::make_pair("value",vl)); attrs.push_back(std::make_pair("event","ws_ListChange")); w->attrsSet(attrs); } void ShapeFormEl::treeChange( ) { QTreeWidget *el = (QTreeWidget*)sender(); WdgView *w = (WdgView*)el->parentWidget(); if(((ShpDt*)w->shpData)->evLock || !el->selectedItems().size()) return; AttrValS attrs; attrs.push_back(std::make_pair("value",el->selectedItems()[0]->data(0,Qt::UserRole).toString().toStdString())); attrs.push_back(std::make_pair("event","ws_TreeChange")); w->attrsSet(attrs); } void ShapeFormEl::tableSelectChange( ) { QTableWidget *el = (QTableWidget*)sender(); RunWdgView *w = (RunWdgView*)el->parentWidget(); if(((ShpDt*)w->shpData)->evLock || !el->selectedItems().size()) return; //Unselect the table due its inactivity if(!(((ShpDt*)w->shpData)->active && w->permCntr())) { for(int iS = 0; iS < el->selectedItems().size(); iS++) el->selectedItems()[iS]->setSelected(false); return; } AttrValS attrs; QTableWidgetItem *wIt = el->selectedItems()[0]; string value = wIt->text().toStdString(); switch(el->selectionBehavior()) { case QAbstractItemView::SelectRows: value = wIt->tableWidget()->item(wIt->row()/*data(Qt::UserRole+2).toInt()*/, el->property("keyID").toInt())->text().toStdString(); break; case QAbstractItemView::SelectColumns: value = wIt->tableWidget()->item(el->property("keyID").toInt(), wIt->column()/*data(Qt::UserRole+1).toInt()*/)->text().toStdString(); break; default: if(el->property("sel").toString() != "cell") value = i2s(wIt->row()/*data(Qt::UserRole+2).toInt()*/)+":"+i2s(wIt->column()/*data(Qt::UserRole+1).toInt()*/); break; } //Events prepare attrs.push_back(std::make_pair("value",value)); attrs.push_back(std::make_pair("event","ws_TableChangeSel")); w->attrsSet(attrs); } void ShapeFormEl::tableChange( int row, int col ) { QTableWidget *el = (QTableWidget*)sender(); RunWdgView *w = (RunWdgView*)el->parentWidget(); if(((ShpDt*)w->shpData)->evLock /*|| !el->selectedItems().size()*/) return; QTableWidgetItem *wIt = el->item(row, col); QVariant val = wIt->data(Qt::DisplayRole); if(val.typeId() == QVariant::Bool) val = val.toInt(); //Events prepare AttrValS attrs; attrs.push_back(std::make_pair("set",val.toString().toStdString())); attrs.push_back(std::make_pair("event",TSYS::strMess("ws_TableEdit_%d_%d",wIt->data(Qt::UserRole+1).toInt(),wIt->data(Qt::UserRole+2).toInt()))); w->attrsSet(attrs); } void ShapeFormEl::sliderMoved( int val ) { QAbstractSlider *el = (QAbstractSlider*)sender(); WdgView *w = (WdgView *)el->parentWidget(); AttrValS attrs; attrs.push_back(std::make_pair("value",i2s(val))); attrs.push_back(std::make_pair("event","ws_SliderChange")); w->attrsSet(attrs); } void ShapeFormEl::eventFilterSet( WdgView *view, QWidget *wdg, bool en ) { if(en) wdg->installEventFilter(view); else wdg->removeEventFilter(view); //Process childs for(int iC = 0; iC < wdg->children().size(); iC++) if(qobject_cast(wdg->children().at(iC))) eventFilterSet(view,(QWidget*)wdg->children().at(iC),en); } void ShapeFormEl::setFocus( WdgView *w, QWidget *wdg, bool en, bool devel ) { int isFocus = wdg->windowIconText().toInt(); //Set up current widget if(en) { if(isFocus && !devel) wdg->setFocusPolicy((Qt::FocusPolicy)isFocus); } else { if(wdg->focusPolicy() != Qt::NoFocus) { wdg->setWindowIconText(QString::number((int)wdg->focusPolicy())); wdg->setFocusPolicy(Qt::NoFocus); } if(devel) wdg->setMouseTracking(true); } //Process childs for(int iC = 0; iC < wdg->children().size(); iC++) if(qobject_cast(wdg->children().at(iC))) setFocus(w, (QWidget*)wdg->children().at(iC), en, devel); } //************************************************ //* Text element shape widget * //************************************************ ShapeText::ShapeText( ) : WdgShape("Text") { } void ShapeText::init( WdgView *w ) { w->shpData = new ShpDt(); } void ShapeText::destroy( WdgView *w ) { delete (ShpDt*)w->shpData; } bool ShapeText::attrSet( WdgView *w, int uiPrmPos, const string &val, const string &attr ) { bool up = true, //Update view checking reform = false; //Text reformation ShpDt *shD = (ShpDt*)w->shpData; switch(uiPrmPos) { case A_COM_LOAD: up = reform = true; break; case A_EN: if(!qobject_cast(w)) { up = false; break; } shD->en = (bool)s2i(val); w->setVisible(s2i(val) && ((RunWdgView*)w)->permView()); break; case A_ACTIVE: { if(!qobject_cast(w)) break; shD->active = (bool)s2i(val); shD->realAct = (shD->active && ((RunWdgView*)w)->permCntr()); w->setFocusPolicy(shD->realAct ? Qt::StrongFocus : Qt::NoFocus); break; } case A_GEOM_MARGIN: shD->geomMargin = s2i(val); up = true; break; case A_BackColor: { shD->backGrnd.setColor(getColor(val)); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setColor(shD->backGrnd.color()); if(!brsh.color().isValid()) brsh.setColor(QPalette().brush(QPalette::Window).color()); brsh.setStyle(brsh.textureImage().isNull() ? Qt::SolidPattern : Qt::TexturePattern); plt.setBrush(QPalette::Window, brsh); w->setPalette(plt); up = true; break; } case A_BackImg: { QImage img; string backimg = w->resGet(val); shD->backGrnd.setTextureImage((!backimg.empty()&&img.loadFromData((const uchar*)backimg.data(),backimg.size()))?img:QImage()); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setTextureImage(img); brsh.setStyle(!brsh.textureImage().isNull() ? Qt::TexturePattern : Qt::SolidPattern); plt.setBrush(QPalette::Base,brsh); w->setPalette(plt); up = true; break; } case A_BordWidth: shD->border.setWidth(s2i(val)); up = true; break; case A_BordColor: shD->border.setColor(getColor(val)); up = true;break; case A_BordStyle: shD->bordStyle = s2i(val); up = true; break; case A_TextFont: shD->font = val; up = true; break; case A_TextColor: shD->color = getColor(val); break; case A_TextOrient: shD->orient = s2i(val); break; case A_TextWordWrap: shD->options.setWrapMode(s2i(val)?QTextOption::WordWrap:QTextOption::NoWrap); break; case A_TextAlignment: { short int text_flg = 0; switch(s2i(val)&0x3) { case 0: text_flg |= Qt::AlignLeft; break; case 1: text_flg |= Qt::AlignRight; break; case 2: text_flg |= Qt::AlignHCenter; break; case 3: text_flg |= Qt::AlignJustify; break; } switch(s2i(val)>>2) { case 0: text_flg |= Qt::AlignTop; break; case 1: text_flg |= Qt::AlignBottom; break; case 2: text_flg |= Qt::AlignVCenter; break; } shD->options.setAlignment((Qt::Alignment)text_flg); break; } case A_TextText: if(shD->text_tmpl == val.c_str()) break; shD->text_tmpl = val; reform = true; break; case A_TextHTML: { if((bool)shD->inHtml == (bool)s2i(val)) break; shD->inHtml = (bool)s2i(val); reform = true; break; } case A_TextNumbArg: { int numbArg = s2i(val); while((int)shD->args.size() < numbArg) shD->args.push_back(ArgObj()); while((int)shD->args.size() > numbArg) shD->args.pop_back(); reform = true; break; } default: //Individual arguments process if(uiPrmPos >= A_TextArs) { int argN = (uiPrmPos-A_TextArs)/A_TextArsSz; if(argN >= (int)shD->args.size()) break; if((uiPrmPos%A_TextArsSz) == A_TextArsVal || (uiPrmPos%A_TextArsSz) == A_TextArsTp) { QVariant gval = shD->args[argN].val(); int tp = (gval.typeId()==QVariant::Double) ? 1 : ((gval.typeId()==QVariant::String) ? 2 : 0); if((uiPrmPos%A_TextArsSz) == A_TextArsVal) gval = val.c_str(); if((uiPrmPos%A_TextArsSz) == A_TextArsTp) tp = s2i(val); switch(tp) { case FT_INT: shD->args[argN].setVal(gval.toInt()); break; case FT_REAL: shD->args[argN].setVal(gval.toDouble()); break; case FT_STR: shD->args[argN].setVal(gval.toString()); break; } } if((uiPrmPos%A_TextArsSz) == A_TextArsCfg) shD->args[argN].setCfg(val.c_str()); reform = true; } else up = false; } //Text reformation if(reform && !w->allAttrLoad()) { string text = shD->text_tmpl, argT; for(unsigned iA = 0; iA < shD->args.size(); iA++) { int off = 0, wdth = s2i(TSYS::strSepParse(shD->args[iA].cfg(), 0, ';', &off)); switch(shD->args[iA].val().typeId()) { case QVariant::Double: { string form = TSYS::strSepParse(shD->args[iA].cfg(), 0, ';', &off); int prec = s2i(TSYS::strSepParse(shD->args[iA].cfg(),0,';',&off)); argT = r2s(shD->args[iA].val().toDouble(), vmax(0,prec), form.empty()?'0':form[0]); break; } default: argT = shD->args[iA].val().toString().toStdString(); break; } text = TRegExp("%"+i2s(iA+1),"g").replace(text, (((int)argT.size()text) { shD->text = text; up = true; } } if(up) { if(shD->realAct && shD->text.size() && shD->backGrnd.color().isValid() && shD->backGrnd.color().alpha()) w->setCursor(Qt::PointingHandCursor); else w->unsetCursor(); } if(up && !w->allAttrLoad() && uiPrmPos != -1) w->update(); return up; } bool ShapeText::event( WdgView *w, QEvent *event ) { ShpDt *shD = (ShpDt*)w->shpData; if(!shD->en) return false; switch(event->type()) { case QEvent::Paint: { QPainter pnt(w); QRect dA = w->rect(); // Decoration draw area //Draw decoration if(shD->backGrnd.color().isValid()) pnt.fillRect(dA, shD->backGrnd.color()); if(!shD->backGrnd.textureImage().isNull()) pnt.fillRect(dA, shD->backGrnd.textureImage()); //Draw border if(shD->border.width()) { borderDraw(pnt, dA, shD->border, shD->bordStyle); dA.adjust(shD->border.width(), shD->border.width(), -shD->border.width(), -shD->border.width()); } dA.adjust(shD->geomMargin, shD->geomMargin, -shD->geomMargin, -shD->geomMargin); //Text translation pnt.translate(w->rect().width()/2, w->rect().height()/2); pnt.rotate(shD->orient); //Calc whidth and hight draw rect at rotate double rad_angl = fabs(M_PI*(double)shD->orient/180); double rect_rate = 1/(fabs(cos(rad_angl))+fabs(sin(rad_angl))); int wdth = (int)(rect_rate*dA.size().width()+fabs(sin(rad_angl))*(dA.size().height()-dA.size().width())); int heigt = (int)(rect_rate*dA.size().height()+fabs(sin(rad_angl))*(dA.size().width()-dA.size().height())); dA = QRect(QPoint(-wdth/2,-heigt/2), QSize(wdth,heigt)); //Draw text if(shD->inHtml) { QTextDocument td; td.setPageSize(QSize(wdth,heigt)); td.setDocumentMargin(0); QString htmlStl; //htmlStl += QString("margin: 0; padding: 0; "); if(shD->color.isValid()) htmlStl += QString("color: %1; ").arg(shD->color.name()); htmlStl += QString("white-space: %1; ").arg(shD->options.wrapMode()?"pre-wrap":"pre"); td.setDefaultStyleSheet(QString("body { %1 }").arg(htmlStl)); td.setDefaultFont(getFont(shD->font,vmin(w->xScale(true),w->yScale(true)))); td.setDefaultTextOption(shD->options); td.setHtml(QString("%1").arg(shD->text.c_str())); if(shD->options.alignment()&Qt::AlignVCenter) heigt = td.size().height(); else if(shD->options.alignment()&Qt::AlignBottom) heigt -= 2*(heigt - td.size().height()); pnt.translate(-wdth/2, -heigt/2); dA = QRect(QPoint(0,0), QSize(wdth,td.size().height())); td.drawContents(&pnt, dA); } else { pnt.setPen(shD->color); pnt.setFont(getFont(shD->font,vmin(w->xScale(true),w->yScale(true)))); pnt.drawText(dA, shD->text.c_str(), shD->options); } event->accept( ); return true; } default: break; } return false; } //************************************************ //* Media view shape widget * //************************************************ ShapeMedia::ShapeMedia( ) : WdgShape("Media") { } void ShapeMedia::init( WdgView *w ) { w->shpData = new ShpDt(); new QVBoxLayout(w); } void ShapeMedia::destroy( WdgView *w ) { ShpDt *shD = (ShpDt*)w->shpData; if(shD->tfile.size()) remove(shD->tfile.c_str()); if(shD->chkTimer) { delete shD->chkTimer; shD->chkTimer = NULL; } clear(w); delete shD; } void ShapeMedia::clear( WdgView *w ) { ShpDt *shD = (ShpDt*)w->shpData; //Clear label widget's elements QLabel *lab = dynamic_cast(shD->addrWdg); if(lab) { if(lab->movie()) { if(lab->movie()->device()) delete lab->movie()->device(); //lab->movie()->device()->deleteLater(); //!!!! Crashes here for GIF playback delete lab->movie(); //lab->movie()->deleteLater(); //!!!! Crashes here for GIF playback lab->clear(); } #if HAVE_MULTIMEDIA || HAVE_PHONON if(shD->mediaType == FM_VIDEO || shD->mediaType == FM_AUDIO) { shD->addrWdg->deleteLater(); shD->addrWdg = NULL; } #endif } #if HAVE_MULTIMEDIA || HAVE_PHONON # if HAVE_MULTIMEDIA QMediaPlayer *player = dynamic_cast(shD->addrWdg); # elif HAVE_PHONON VideoPlayer *player = dynamic_cast(shD->addrWdg); # endif if(player && (shD->mediaType == FM_IMG || shD->mediaType == FM_ANIM)) { player->deleteLater(); shD->addrWdg = NULL; if(shD->chkTimer) { delete shD->chkTimer; shD->chkTimer = NULL; } } #endif } void ShapeMedia::chkTimer( ) { WdgView *w = dynamic_cast(((QWidget*)sender())->parentWidget()); if(!w) return; ShpDt *shD = (ShpDt*)w->shpData; #if HAVE_MULTIMEDIA || HAVE_PHONON # if HAVE_MULTIMEDIA QMediaPlayer *player = dynamic_cast(shD->addrWdg); if(player->duration() != shD->videoSize) w->attrSet("size", r2s(shD->videoSize=player->duration()), A_NO_ID, true); if(player->position() != shD->videoSeek) w->attrSet("seek", r2s(shD->videoSeek=player->position()), A_NO_ID, true); if(!w->isEnabled() && player->state() == QMediaPlayer::PlayingState) player->stop(); bool isFinished = (w->isEnabled() && shD->videoPlay && player->state() == QMediaPlayer::StoppedState); # elif HAVE_PHONON VideoPlayer *player = dynamic_cast(shD->addrWdg); if(player->totalTime() != shD->videoSize) w->attrSet("size", r2s(shD->videoSize=player->totalTime()), A_NO_ID, true); if(player->currentTime() != shD->videoSeek) w->attrSet("seek", r2s(shD->videoSeek=player->currentTime()), A_NO_ID, true); if(!w->isEnabled() && player->isPlaying()) player->stop(); bool isFinished = (w->isEnabled() && shD->videoPlay && player->mediaObject()->state() == StoppedState); # endif if(isFinished) { AttrValS attrs; if(shD->videoRoll && player) player->play(); else attrs.push_back(std::make_pair("play","0")); attrs.push_back(std::make_pair("event","ws_MediaFinished")); w->attrsSet(attrs); } #endif } bool ShapeMedia::attrSet( WdgView *w, int uiPrmPos, const string &val, const string &attr ) { QLabel *lab; bool up = true, reld_cfg = false; ShpDt *shD = (ShpDt*)w->shpData; QWidget *endW = NULL; #if HAVE_MULTIMEDIA QMediaPlayer *player = dynamic_cast(shD->addrWdg); #elif HAVE_PHONON VideoPlayer *player = dynamic_cast(shD->addrWdg); #endif switch(uiPrmPos) { case A_COM_LOAD: reld_cfg = true; break; case A_EN: if(!qobject_cast(w)) { up = false; break; } shD->en = (bool)s2i(val); w->setVisible(shD->en && ((RunWdgView*)w)->permView()); break; case A_ACTIVE: if(!qobject_cast(w)) break; shD->active = s2i(val); shD->realActive = shD->active && ((RunWdgView*)w)->permCntr(); if((endW=qobject_cast(shD->addrWdg))) endW->setMouseTracking(shD->realActive); w->setMouseTracking(shD->realActive); break; case A_GEOM_MARGIN: shD->geomMargin = s2i(val); w->layout()->setContentsMargins(shD->geomMargin, shD->geomMargin, shD->geomMargin, shD->geomMargin); break; case A_BackColor: { shD->backGrnd.setColor(getColor(val)); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setColor(shD->backGrnd.color()); if(!brsh.color().isValid()) brsh.setColor(QPalette().brush(QPalette::Window).color()); brsh.setStyle( brsh.textureImage().isNull() ? Qt::SolidPattern : Qt::TexturePattern ); plt.setBrush(QPalette::Window,brsh); w->setPalette(plt); break; } case A_BackImg: { QImage img; string backimg = w->resGet(val); shD->backGrnd.setTextureImage(QImage()); if(!backimg.empty() && img.loadFromData((const uchar*)backimg.data(),backimg.size())) shD->backGrnd.setTextureImage(img); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setTextureImage(img); brsh.setStyle(!brsh.textureImage().isNull() ? Qt::TexturePattern : Qt::SolidPattern); plt.setBrush(QPalette::Window,brsh); w->setPalette(plt); break; } case A_BordWidth: shD->border.setWidth(s2i(val)); break; case A_BordColor: shD->border.setColor(getColor(val)); break; case A_BordStyle: shD->bordStyle = s2i(val); break; case A_MediaSrc: if(shD->mediaSrc == val) break; shD->mediaSrc = val; reld_cfg = true; break; case A_MediaFit: shD->mediaFit = (bool)s2i(val); if(shD->mediaType == FM_IMG) reld_cfg = true; else if((lab=dynamic_cast(shD->addrWdg))) lab->setScaledContents(shD->mediaFit); break; case A_MediaKeepAspect: shD->mediaKeepAspect = (bool)s2i(val); reld_cfg = true; break; case A_MediaType: if(shD->mediaType == s2i(val)) break; shD->mediaType = s2i(val); reld_cfg = true; break; case A_MediaAreas: { int numbMAr = s2i(val); while((int)shD->maps.size() < numbMAr) shD->maps.push_back(MapArea()); while((int)shD->maps.size() > numbMAr) shD->maps.pop_back(); break; } case A_MediaSpeedPlay: switch(shD->mediaType) { case FM_IMG: case FM_ANIM: shD->mediaSpeed = s2i(val); break; case FM_VIDEO: case FM_AUDIO: shD->videoPlay = (bool)s2i(val); break; } if((lab=dynamic_cast(shD->addrWdg))) { if(!lab->movie()) break; if(shD->mediaSpeed <= 1) lab->movie()->stop(); else { lab->movie()->setSpeed(shD->mediaSpeed); lab->movie()->start(); } } #if HAVE_MULTIMEDIA || HAVE_PHONON else if(player) { if(shD->videoPlay) player->play(); else player->stop(); } #endif break; #if HAVE_MULTIMEDIA || HAVE_PHONON case A_MediaRoll: shD->videoRoll = (bool)s2i(val); break; case A_MediaPause: shD->videoPause = (bool)s2i(val); if(player) { # if HAVE_MULTIMEDIA if(shD->videoPause && player->state() != QMediaPlayer::PausedState) player->pause(); if(!shD->videoPause && player->state() == QMediaPlayer::PausedState) player->play(); # elif HAVE_PHONON if(shD->videoPause && !player->isPaused()) player->pause(); if(!shD->videoPause && player->isPaused()) player->play(); # endif } break; case A_MediaSeek: if(shD->videoSeek == s2r(val)) break; shD->videoSeek = s2r(val); # if HAVE_MULTIMEDIA if(player) player->setPosition(shD->videoSeek); # elif HAVE_PHONON if(player) player->seek(shD->videoSeek); # endif break; case A_MediaVolume: if(shD->audioVolume == s2r(val)) break; shD->audioVolume = s2r(val); # if HAVE_MULTIMEDIA if(player) player->setVolume(shD->audioVolume); # elif HAVE_PHONON if(player) player->setVolume(shD->audioVolume/100); # endif break; #endif default: //Individual arguments process if(uiPrmPos >= A_MediaArs) { int areaN = (uiPrmPos-A_MediaArs)/A_MediaArsSz; if(areaN >= (int)shD->maps.size()) break; switch((uiPrmPos-A_MediaArs)%A_MediaArsSz) { case A_MediaArShape: shD->maps[areaN].shp = s2i(val); break; case A_MediaArCoord: { string stmp; shD->maps[areaN].pnts.clear(); for(int ncrd = 0, pos = 0; (stmp=TSYS::strSepParse(val,0,',',&ncrd)).size(); pos++) if(!(pos%2)) shD->maps[areaN].pnts.push_back(QPoint(s2i(stmp),0)); else shD->maps[areaN].pnts[shD->maps[areaN].pnts.size()-1].setY(s2i(stmp)); } case A_MediaArTitle: shD->maps[areaN].title = val; break; } } } if(reld_cfg && !w->allAttrLoad()) { bool mk_new = false; string sdata; if(shD->mediaSrc.find("data:") == 0) { int offL = 0; string fLine = TSYS::strLine(shD->mediaSrc, 0, &offL); sdata = TSYS::strDecode(shD->mediaSrc.substr(offL), TSYS::base64); } else sdata = w->resGet(shD->mediaSrc); switch(shD->mediaType) { case FM_IMG: { QImage img; //Free movie data, if set clear(w); //Create label widget if(!shD->addrWdg) { shD->addrWdg = new QLabel(w); mk_new = true; } //Set new image lab = dynamic_cast(shD->addrWdg); if(!lab) break; lab->setAlignment(Qt::AlignCenter); lab->setScaledContents(false); if(!sdata.empty() && img.loadFromData((const uchar*)sdata.data(),sdata.size())) { if(shD->mediaFit) lab->setPixmap(QPixmap::fromImage(img.scaled( w->width()-2*shD->geomMargin,w->height()-2*shD->geomMargin, (shD->mediaKeepAspect?Qt::KeepAspectRatio:Qt::IgnoreAspectRatio), Qt::SmoothTransformation))); else lab->setPixmap(QPixmap::fromImage(img.scaled( (int)((float)img.width()*w->xScale(true)), (int)((float)img.height()*w->yScale(true)), Qt::KeepAspectRatio,Qt::SmoothTransformation))); //lab->setScaledContents(shD->mediaFit); } else lab->setPixmap(QPixmap()); break; } case FM_ANIM: { //Clear previous movie data clear(w); //Create label widget if(!shD->addrWdg) { shD->addrWdg = new QLabel(w); mk_new = true; } //Set new data lab = dynamic_cast(shD->addrWdg); if(!lab) break; lab->setAlignment(Qt::AlignCenter); if(sdata.size()) { QBuffer *buf = new QBuffer(w); buf->setData(sdata.data(), sdata.size()); buf->open(QIODevice::ReadOnly); lab->setMovie(new QMovie(buf)); //Play speed set if(shD->mediaSpeed <= 1) lab->movie()->stop(); else { lab->movie()->setSpeed(shD->mediaSpeed); lab->movie()->start(); } //Fit set lab->setScaledContents(shD->mediaFit); if(!shD->mediaFit && lab->movie()->jumpToNextFrame()) { QImage img = lab->movie()->currentImage(); lab->movie()->setScaledSize(QSize((int)((float)img.width()*w->xScale(true)),(int)((float)img.height()*w->yScale(true)))); } } else lab->setText(""); break; } #if HAVE_MULTIMEDIA || HAVE_PHONON case FM_VIDEO: case FM_AUDIO: { //Clearing previous movie data clear(w); //Creating the media player shD->chkTimer = new QTimer(w); shD->chkTimer->setSingleShot(false); connect(shD->chkTimer, SIGNAL(timeout()), this, SLOT(chkTimer())); shD->chkTimer->start(prmWait_TM*1000); # if HAVE_MULTIMEDIA if(!shD->addrWdg) { shD->addrWdg = player = new QMediaPlayer(w); # if QT_VERSION >= 0x060000 player->setAudioOutput(new QAudioOutput); # endif if(shD->mediaType == FM_VIDEO) { shD->extO = endW = new QVideoWidget(w); player->setVideoOutput((QVideoWidget*)endW); endW->show(); endW->installEventFilter(w); } else shD->extO = NULL; mk_new = true; } player = dynamic_cast(shD->addrWdg); if(!player) break; if(player->state() == QMediaPlayer::PlayingState) { player->stop(); player->setPosition(0); } //Try playing the local file if(shD->mediaSrc.find("file:") == 0) { QString fNm = shD->mediaSrc.substr(5).c_str(), fPath = QDir::currentPath() + "/" + fNm; if(QFile(fPath).open(QIODevice::ReadOnly) || QFile(fPath=fNm).open(QIODevice::ReadOnly)) player->setMedia(QUrl::fromLocalFile(fPath)); else player->setMedia(QUrl()); } //Try playing a Stream by URL else if(shD->mediaSrc.find("stream:") == 0) player->setMedia(QUrl(shD->mediaSrc.substr(5).c_str())); //Try for remote VCAEngine resource at last if(shD->mediaSrc.size() && # if QT_VERSION < 0x060000 player->currentMedia().isNull()) # else player->mediaStatus() == QMediaPlayer::NoMedia) # endif { if(sdata.size()) { shD->tfile = TSYS::path2sepstr(w->id(), '_'); int tfid = open(shD->tfile.c_str(), O_CREAT|O_TRUNC|O_WRONLY, SYS->permCrtFiles()); if(tfid >= 0) { if(write(tfid,sdata.data(),sdata.size()) != (ssize_t)sdata.size()) mod->postMess(mod->nodePath().c_str(), QString(_("Error writing to the file '%1'.")).arg(shD->tfile.c_str()), TVision::Error); if(close(tfid) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), tfid, strerror(errno), errno); player->setMedia(QUrl::fromLocalFile(shD->tfile.c_str())); } } } # if QT_VERSION < 0x060000 if(!player->currentMedia().isNull()) # else if(player->mediaStatus() != QMediaPlayer::NoMedia) # endif { if(shD->videoPlay) player->play(); else player->stop(); if(shD->videoPause) player->pause(); player->setPosition(shD->videoSeek); player->setVolume(shD->audioVolume); } # elif HAVE_PHONON if(!shD->addrWdg) { shD->addrWdg = player = new VideoPlayer((shD->mediaType==FM_AUDIO)?Phonon::MusicCategory:Phonon::VideoCategory, w); player->videoWidget()->installEventFilter(w); mk_new = true; } //Set new data player = dynamic_cast(shD->addrWdg); if(!player) break; if(player->isPlaying()) { player->stop(); player->seek(0); } MediaSource mSrc; //Try playing the local file if(shD->mediaSrc.find("file:") == 0) { QString fNm = shD->mediaSrc.substr(5).c_str(), fPath = QDir::currentPath() + "/" + fNm; if(QFile(fPath).open(QIODevice::ReadOnly) || QFile(fPath=fNm).open(QIODevice::ReadOnly)) mSrc = MediaSource(QUrl::fromLocalFile(fPath)); //mSrc = MediaSource(QUrl(shD->mediaSrc.substr(5).c_str())); } //Try playing a Stream by URL else if(shD->mediaSrc.find("stream:") == 0) mSrc = MediaSource(QUrl(shD->mediaSrc.substr(7).c_str())); //Try remote VCAEngine resource at last if(shD->mediaSrc.size() && (mSrc.type() == MediaSource::Invalid || mSrc.type() == MediaSource::Empty)) { if(sdata.size()) { shD->tfile = TSYS::path2sepstr(w->id(), '_'); int tfid = open(shD->tfile.c_str(), O_CREAT|O_TRUNC|O_WRONLY, SYS->permCrtFiles()); if(tfid >= 0) { if(write(tfid,sdata.data(),sdata.size()) != (ssize_t)sdata.size()) mod->postMess(mod->nodePath().c_str(), QString(_("Error writing to the file '%1'.")).arg(shD->tfile.c_str()), TVision::Error); if(close(tfid) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), tfid, strerror(errno), errno); mSrc = MediaSource(QUrl(shD->tfile.c_str())); } } } if(mSrc.type() != MediaSource::Invalid && mSrc.type() != MediaSource::Empty) { player->load(mSrc); if(shD->videoPlay) player->play(); else player->stop(); if(shD->videoPause) player->pause(); player->seek(shD->videoSeek); player->setVolume(shD->audioVolume/100); } # endif break; } #endif } if(mk_new && (endW || (endW=qobject_cast(shD->addrWdg)))) { #if HAVE_PHONON if(shD->mediaType == FM_AUDIO) endW->setVisible(false); #endif w->setMouseTracking(qobject_cast(w) || (shD->active && ((RunWdgView*)w)->permCntr())); endW->setMouseTracking(qobject_cast(w) || (shD->active && ((RunWdgView*)w)->permCntr())); endW->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); ((QVBoxLayout*)w->layout())->addWidget(endW); } } if(up && !w->allAttrLoad() && uiPrmPos != -1) w->update(); return up; } bool ShapeMedia::event( WdgView *w, QEvent *event ) { ShpDt *shD = (ShpDt*)w->shpData; if(!shD->en) return false; switch(event->type()) { case QEvent::Paint: { QPainter pnt(w); //Prepare draw area QRect dA = w->rect().adjusted(0, 0, -2*shD->geomMargin, -2*shD->geomMargin); pnt.setWindow(dA); pnt.setViewport(w->rect().adjusted(shD->geomMargin,shD->geomMargin,-shD->geomMargin,-shD->geomMargin)); //Draw decoration if(shD->backGrnd.color().isValid()) pnt.fillRect(dA,shD->backGrnd.color()); if(!shD->backGrnd.textureImage().isNull()) pnt.fillRect(dA,shD->backGrnd.textureImage()); //Draw border borderDraw(pnt, dA, shD->border, shD->bordStyle); return true; } case QEvent::MouseMove: { Qt::CursorShape new_shp = Qt::ArrowCursor; if(shD->realActive && !shD->maps.size() && shD->backGrnd.color().isValid() && shD->backGrnd.color().alpha() && shD->mediaSrc.size()) new_shp = Qt::PointingHandCursor; for(unsigned iA = 0; iA < shD->maps.size(); iA++) if(shD->maps[iA].containsPoint(w->mapFromGlobal(w->cursor().pos()))) { new_shp = Qt::PointingHandCursor; if(!shD->maps[iA].title.empty()) QToolTip::showText(w->cursor().pos(),shD->maps[iA].title.c_str()); break; } if(new_shp != w->cursor().shape()) { if(new_shp != Qt::ArrowCursor) w->setCursor(new_shp); else w->unsetCursor(); } return true; } case QEvent::MouseButtonPress: { string sev; for(unsigned iA = 0; iA < shD->maps.size(); iA++) if(shD->maps[iA].containsPoint(w->mapFromGlobal(w->cursor().pos()))) { sev = "ws_MapAct"+i2s(iA); break; } if(!sev.empty()) { switch(((QMouseEvent*)event)->button()) { case Qt::LeftButton: sev += "Left"; break; case Qt::RightButton: sev += "Right"; break; case Qt::MiddleButton: sev += "Midle"; break; default: return false; } w->attrSet("event", sev, A_NO_ID, true); //return true; //For common Press event produce } break; } default: break; } return false; } bool ShapeMedia::eventFilter( WdgView *w, QObject *object, QEvent *event ) { #if HAVE_MULTIMEDIA QVideoWidget *playerW = dynamic_cast(((ShpDt*)w->shpData)->extO); if(playerW && playerW == object) if(event->type() == QEvent::MouseButtonDblClick && ((QMouseEvent*)event)->button() == Qt::LeftButton) { playerW->setFullScreen(!playerW->isFullScreen()); return true; } #elif HAVE_PHONON VideoPlayer *player = dynamic_cast(((ShpDt*)w->shpData)->addrWdg); if(player && player->videoWidget() == object) if(event->type() == QEvent::MouseButtonDblClick && ((QMouseEvent*)event)->button() == Qt::LeftButton) { player->videoWidget()->setFullScreen(!player->videoWidget()->isFullScreen()); return true; } #endif return false; } //* Map areas structure * //************************************************* bool ShapeMedia::MapArea::containsPoint( const QPoint & point ) { switch(shp) { case FM_RECT: if(pnts.size() < 2) return false; return QRect(pnts[0],pnts[1]).contains(point); case FM_POLY: return QPolygon(pnts).containsPoint(point, Qt::OddEvenFill); case FM_CIRCLE: { if(pnts.size() < 2) return false; QPoint work = point-pnts[0]; return (pow(pow((float)work.x(),2)+pow((float)work.y(),2),0.5) < pnts[1].x()); } } return false; } //************************************************* //* Diagram view shape widget * //************************************************* ShapeDiagram::ShapeDiagram( ) : WdgShape("Diagram") { } void ShapeDiagram::init( WdgView *w ) { w->shpData = new ShpDt(); //Init tracing timer ((ShpDt*)w->shpData)->trcTimer = new QTimer(w); connect(((ShpDt*)w->shpData)->trcTimer, SIGNAL(timeout()), this, SLOT(tracing())); //Activate vizualizer specific attributes RunWdgView *rw = qobject_cast(w); if(rw) { ((ShpDt*)w->shpData)->en = false; w->setVisible(false); XMLNode reqSpc("activate"); reqSpc.setAttr("path", rw->id()+"/%2fserv%2fattr%2fsclWin"); rw->mainWin()->cntrIfCmd(reqSpc); } } void ShapeDiagram::destroy( WdgView *w ) { ((ShpDt*)w->shpData)->trcTimer->stop(); delete (ShpDt*)w->shpData; } bool ShapeDiagram::attrSet( WdgView *w, int uiPrmPos, const string &val, const string &attr ) { bool up = false, //Repaint diagram picture make_pct = false; //Remake diagram picture int reld_tr_dt = 0; //Reload trend's data (1-reload addons, 2-full reload) ShpDt *shD = (ShpDt*)w->shpData; switch(uiPrmPos) { case A_NO_ID: if(attr == "sclWin") shD->sclWin = s2i(val); break; case A_COM_LOAD: up = make_pct = true; reld_tr_dt = 2; break; case A_COM_FOCUS: up = ((bool)s2i(val) != w->hasFocus()); break; case A_EN: if(!qobject_cast(w)) break; shD->en = (bool)s2i(val); //w->setVisible(shD->en && ((RunWdgView*)w)->permView()); up = true; break; case A_ACTIVE: shD->active = (bool)s2i(val); if(!qobject_cast(w)) break; w->setFocusPolicy((shD->active&&((RunWdgView*)w)->permCntr())?Qt::StrongFocus:Qt::NoFocus); break; case A_GEOM_W: case A_GEOM_H: make_pct = true; break; case A_GEOM_MARGIN: shD->geomMargin = s2i(val); make_pct = true; break; case A_BackColor: { shD->backGrnd.setColor(getColor(val)); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setColor(shD->backGrnd.color()); if(!brsh.color().isValid()) brsh.setColor(QPalette().brush(QPalette::Window).color()); brsh.setStyle(brsh.textureImage().isNull() ? Qt::SolidPattern : Qt::TexturePattern); plt.setBrush(QPalette::Window, brsh); w->setPalette(plt); up = true; break; } case A_BackImg: { QImage img; string backimg = w->resGet(val); shD->backGrnd.setTextureImage(QImage()); if(!backimg.empty() && img.loadFromData((const uchar*)backimg.data(),backimg.size())) shD->backGrnd.setTextureImage(img); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setTextureImage(img); brsh.setStyle(!brsh.textureImage().isNull() ? Qt::TexturePattern : Qt::SolidPattern); plt.setBrush(QPalette::Window, brsh); w->setPalette(plt); up = true; break; } case A_BordWidth: shD->border.setWidth(s2i(val)); make_pct = true; break; case A_BordColor: shD->border.setColor(getColor(val)); up = true; break; case A_BordStyle: shD->bordStyle = s2i(val); up = true; break; case A_DiagramTrcPer: shD->trcPer = s2r(val); if(shD->trcPer < 0.01) { shD->trcPer = 0; shD->trcTimer->stop(); } else shD->trcTimer->start(vmax(qobject_cast(w)?0.01:1,shD->trcPer)*1000); break; case A_DiagramType: shD->type = s2i(val); reld_tr_dt = 2; break; case A_DiagramTSek: shD->tTimeCurent = false; if(s2ll(val) == 0) { shD->tTime = (int64_t)time(NULL)*1000000; shD->tTimeCurent = true; } else shD->tTime = s2ll(val)*1000000 + shD->tTime%1000000; reld_tr_dt = 1; break; case A_DiagramTUSek: shD->tTime = 1000000ll*(shD->tTime/1000000)+s2ll(val); reld_tr_dt = 1; break; case A_DiagramTSize: shD->tSize = vmax(1e-3,s2r(val)); reld_tr_dt = 2; break; case A_DiagramCurSek: if((shD->curTime/1000000) == s2i(val)) break; shD->curTime = s2ll(val)*1000000 + shD->curTime%1000000; shD->holdCur = (shD->curTime >= (shD->tTime-(shD->pictRect.width()?(int64_t)(3*1e6*shD->tSize)/shD->pictRect.width():0))); //No more 3 pixels //(shD->curTime >= shD->tTime); up = true; break; case A_DiagramCurUSek: if((shD->curTime%1000000) == s2i(val)) break; shD->curTime = 1000000ll*(shD->curTime/1000000)+s2ll(val); shD->holdCur = (shD->curTime >= shD->tTime); up = true; break; case A_DiagramCurColor: shD->curColor = getColor(val); up = true; break; case A_DiagramSclColor: shD->sclColor = getColor(val); make_pct = true; break; case A_DiagramSclHor: shD->sclHor = s2i(val); make_pct = true; break; case A_DiagramSclVer: shD->sclVer = s2i(val); make_pct = true; break; case A_DiagramSclMarkColor: shD->sclMarkColor = getColor(val); make_pct = true; break; case A_DiagramSclMarkFont: shD->sclMarkFont = getFont(val,vmin(w->xScale(true),w->yScale(true))); make_pct = true; break; case A_DiagramValArch: if(shD->valArch != val) { shD->valArch = val; reld_tr_dt = 2; } break; case A_DiagramParNum: { int parNum = s2i(val); while((int)shD->prms.size() < parNum) shD->prms.push_back(TrendObj(w)); while((int)shD->prms.size() > parNum) shD->prms.pop_back(); make_pct = true; break; } case A_DiagramSclVerScl: if(shD->sclVerScl != s2r(val)) { shD->sclVerScl = s2r(val); make_pct = true; } break; case A_DiagramSclVerSclOff: if(shD->sclVerSclOff != s2r(val)) { shD->sclVerSclOff = s2r(val); make_pct = true; } break; case A_DiagramSclHorScl: if(shD->sclHorScl != s2r(val)) { shD->sclHorScl = s2r(val); make_pct = true; } break; case A_DiagramSclHorSclOff: if(shD->sclHorSclOff != s2r(val)) { shD->sclHorSclOff = s2r(val); make_pct = true; } break; case A_DiagramValsForPix: if(shD->valsForPix == vmin(10,vmax(0,s2i(val)))) break; shD->valsForPix = vmin(10,vmax(0,s2i(val))); reld_tr_dt = 2; break; case A_DiagramSclHorPer: shD->sclHorPer = vmax(0, s2r(val))*1e6; make_pct = true; break; default: //Individual trend's attributes process if(uiPrmPos >= A_DiagramTrs) { int trndN = (uiPrmPos-A_DiagramTrs)/A_DiagramTrsSz; if(trndN >= (int)shD->prms.size()) break; make_pct = true; switch(uiPrmPos%A_DiagramTrsSz) { case A_DiagramTrAddr: shD->prms[trndN].setAddr(val); break; case A_DiagramTrBordL: shD->prms[trndN].setBordL(s2r(val)); break; case A_DiagramTrBordU: shD->prms[trndN].setBordU(s2r(val)); break; case A_DiagramTrClr: shD->prms[trndN].setColor(getColor(val)); break; case A_DiagramTrVal: shD->prms[trndN].setCurVal((val==EVAL_STR) ? EVAL_REAL : s2r(val)); make_pct = false; break; case A_DiagramTrScl: shD->prms[trndN].setScale(s2i(val)); break; case A_DiagramTrWdth: shD->prms[trndN].setWidth(s2i(val)); break; case A_DiagramTrProp: make_pct = false; break; } } } if(!w->allAttrLoad()) { if(reld_tr_dt) { loadData(w, reld_tr_dt==2); make_pct = true; } if(make_pct) { makePicture(w); up = true; } if(up /*&& uiPrmPos != A_COM_LOAD*/) { //!!!! Due to the cursor can be loaded under w->allAttrLoad() w->update(); setCursor(w, shD->curTime); } if(up && qobject_cast(w)) w->setVisible(shD->en && ((RunWdgView*)w)->permView()); } return (reld_tr_dt || make_pct || up); } void ShapeDiagram::loadData( WdgView *w, bool full ) { ShpDt *shD = (ShpDt*)w->shpData; XMLNode req("set"); req.setAttr("path", w->id()+"/%2fserv%2fattr")->setAttr("noUser", "1")->setAttr("reforwardRedundOff", "1"); for(unsigned iP = 0; iP < shD->prms.size(); iP++) { shD->prms[iP].loadData(full); if(shD->prms[iP].arh_beg && shD->prms[iP].arh_end) req.childAdd("el")->setAttr("id",TSYS::strMess("prm%dprop",iP))->setText(TSYS::strMess("%.15g:%.15g:%.15g", (double)shD->prms[iP].arh_beg*1e-6,(double)shD->prms[iP].arh_end*1e-6,(double)shD->prms[iP].arh_per*1e-6)); } if(req.childSize()) w->cntrIfCmd(req); } void ShapeDiagram::makePicture( WdgView *w ) { ShpDt *shD = (ShpDt*)w->shpData; if(!shD->en) return; switch(shD->type) { case FD_TRND: makeTrendsPicture(w); break; case FD_SPECTR: makeSpectrumPicture(w); break; case FD_XY: makeXYPicture(w); break; } } void ShapeDiagram::makeXYPicture( WdgView *w ) { int64_t d_cnt = 0; QPen grdPen, mrkPen; int mrkHeight = 0, mrkWidth = 0; ShpDt *shD = (ShpDt*)w->shpData; if(mess_lev() == TMess::Debug) d_cnt = TSYS::curTime(); //Prepare picture shD->pictObj = QImage(w->rect().size(),QImage::Format_ARGB32_Premultiplied); shD->pictObj.fill(0); QPainter pnt(&shD->pictObj); //Get generic parameters int64_t tSize = (int64_t)(1e6*shD->tSize); //Trends size (us) int64_t tEnd = shD->tTime; //Trends end point (us) if(shD->tTimeCurent) tEnd = shD->arhEnd(shD->tTime); int64_t tPict = tEnd; int64_t tBeg = tEnd - tSize; //Trends begin point (us) if(shD->prms.empty() || tSize <= 0) return; int sclHor = shD->sclHor; //Horisontal scale mode int sclVer = shD->sclVer; //Vertical scale mode //Trends' area rect definition QRect tAr = w->rect().adjusted(1, 1, -2*(shD->geomMargin+shD->border.width()+1), -2*(shD->geomMargin+shD->border.width()+1)); //Main scales definition if(sclHor&FD_GRD_MARKS || sclVer&FD_GRD_MARKS) { // Set grid pen grdPen.setColor(shD->sclColor); grdPen.setStyle(Qt::SolidLine); grdPen.setWidth(vmax(1,(int)rRnd(vmin(w->xScale(true),w->yScale(true))))); // Set markers font and color if(sclHor&FD_MARKS || sclVer&FD_MARKS) { mrkPen.setColor(shD->sclMarkColor); QFont mrkFnt = shD->sclMarkFont; //mrkFnt.setPixelSize((double)mrkFnt.pixelSize()*vmin(w->xScale(true),w->yScale(true))); pnt.setFont(mrkFnt); mrkHeight = pnt.fontMetrics().height() - pnt.fontMetrics().descent(); mrkWidth = pnt.fontMetrics().size(Qt::TextSingleLine,"000000").width(); if(sclHor&FD_MARKS) { if(tAr.height() < (int)(100*vmin(w->xScale(true),w->yScale(true)))) sclHor &= ~(FD_MARKS); else tAr.adjust(0, 0, 0, -mrkHeight); } if(sclVer&FD_MARKS && tAr.width() < (int)(100*vmin(w->xScale(true),w->yScale(true)))) sclVer &= ~(FD_MARKS); } } //Calc vertical scale for main and individual int64_t aVbeg, aVend; //Corrected for allow data the trend begin and end point bool vsPerc = true, //Vertical scale percent mode isLog = sclVer&FD_LOG, //Logarithmic scale isScale = (fabs(shD->sclVerSclOff) > 1 || fabs(shD->sclVerScl-100) > 1); double curVl, vsMax = -3e300, vsMin = 3e300; //Trend's vertical scale border // Get main scale for non individual parameters int prmInGrp = 0, prmGrpLast = -1; for(unsigned iP = 0, mainPerc = false; iP < shD->prms.size(); iP += 2) { TrendObj &cP = shD->prms[iP]; if(!cP.val().size() || !cP.color().isValid() || (iP+1) >= shD->prms.size() || !shD->prms[iP+1].val().size() || !shD->prms[iP+1].color().isValid()) continue; cP.adjU = -3e300; cP.adjL = 3e300; if(cP.bordU() <= cP.bordL() && cP.valTp() != TFld::Boolean) { // Check trend for valid data aVbeg = vmax(tBeg, cP.valBeg()); aVend = vmin(tEnd, cP.valEnd()); if(aVbeg >= aVend) return; // Calc value borders bool end_vl = false; int ipos = cP.val(aVbeg); if(ipos && cP.val()[ipos].tm > aVbeg) ipos--; while(true) { if(ipos >= (int)cP.val().size() || end_vl) break; if(cP.val()[ipos].tm >= aVend) end_vl = true; if(cP.val()[ipos].val != EVAL_REAL) { curVl = cP.val()[ipos].val; cP.adjL = vmin(cP.adjL, curVl); cP.adjU = vmax(cP.adjU, curVl); } ipos++; } // Value range expanding // No value if(cP.adjU == -3e300) { cP.adjU = 1; cP.adjL = 0; } // Range and absolute value are very small else if((cP.adjU-cP.adjL) < 1e-30 && fabs(cP.adjU) < 1e-30) { cP.adjU += 0.5; cP.adjL -= 0.5; } // Only range is very small else if((cP.adjU-cP.adjL) < 1e-30) { cP.adjL -= ((double)iP/(double)shD->prms.size())*fabs(cP.adjU); cP.adjU += (1.0-(double)iP/(double)shD->prms.size())*fabs(cP.adjU); } // Range smaller relatively to absolute value else if((cP.adjU-cP.adjL) / fabs(cP.adjL+(cP.adjU-cP.adjL)/2) < 0.001) { double wnt_dp = 0.001*fabs(cP.adjL+(cP.adjU-cP.adjL)/2)-(cP.adjU-cP.adjL); cP.adjL -= ((double)iP/(double)shD->prms.size())*wnt_dp; cP.adjU += (1.0-(double)iP/(double)shD->prms.size())*wnt_dp; } } else if(cP.bordU() <= cP.bordL() && cP.valTp() == TFld::Boolean) { cP.adjU = 1.5; cP.adjL = -0.5; } else { cP.adjU = cP.bordU(); cP.adjL = cP.bordL(); } cP.wScale = cP.mScale&(sclVer|FD_LOG); if(cP.wScale&FD_GRD_MARKS) continue; // Check for value border allow if(!mainPerc && (vsMin > vsMax || vmax(fabs((vsMax-cP.adjL)/(vsMax-vsMin)-1),fabs((cP.adjU-vsMin)/(vsMax-vsMin)-1)) < 0.2)) { vsMin = vmin(vsMin, cP.adjL); vsMax = vmax(vsMax, cP.adjU); } else { vsMax = -3e300; vsMin = 3e300; mainPerc = true; } prmInGrp++; prmGrpLast = iP; } // Checking for individual parameters and for the possibility to merge their to groups or create a new one for no group int prmIndiv = 0, prmIndivSc = -1; vector prmsInd; for(unsigned iP = 0; iP < shD->prms.size(); iP += 2) { TrendObj &cP = shD->prms[iP]; cP.isIndiv = false; if(!cP.val().size() || !cP.color().isValid() || !(cP.wScale&FD_GRD_MARKS) || (iP+1) >= shD->prms.size() || !shD->prms[iP+1].val().size() || !shD->prms[iP+1].color().isValid()) continue; // Checking for include to the present one or create a new group and exclude from individual ones if((!prmInGrp || (vsMin < vsMax && vmax(fabs((vsMax-cP.adjL)/(vsMax-vsMin)-1),fabs((cP.adjU-vsMin)/(vsMax-vsMin)-1)) < 0.2)) && (cP.mScale&FD_LOG) == (sclVer&FD_LOG)) { vsMin = vmin(vsMin, cP.adjL); vsMax = vmax(vsMax, cP.adjU); prmInGrp++; prmGrpLast = iP; continue; } cP.isIndiv = true; prmIndiv++; if(prmIndivSc < 0 && cP.mScale&FD_GRD) prmIndivSc = iP; else prmsInd.push_back(iP); if(cP.mScale&FD_LOG) { cP.adjU = log10(vmax(1e-100,cP.adjU)); cP.adjL = log10(vmax(1e-100,cP.adjL)); if((cP.adjU-cP.adjL) / fabs(cP.adjL+(cP.adjU-cP.adjL)/2) < 0.0001) { double wnt_dp = 0.0001*fabs(cP.adjL+(cP.adjU-cP.adjL)/2)-(cP.adjU-cP.adjL); cP.adjL -= wnt_dp/2; cP.adjU += wnt_dp/2; } } if(isScale) { //Vertical scale and offset apply float vsDif = cP.adjU - cP.adjL; cP.adjU += shD->sclVerSclOff*vsDif/100; cP.adjL += shD->sclVerSclOff*vsDif/100; cP.adjU += (shD->sclVerScl*vsDif/100-vsDif)/2; cP.adjL -= (shD->sclVerScl*vsDif/100-vsDif)/2; } } if(prmInGrp) prmsInd.push_back(-1); if(prmIndivSc >= 0) prmsInd.push_back(prmIndivSc); // Final main scale adapting if(vsMin > vsMax) { vsPerc = true; vsMax = 100; vsMin = isLog ? pow(10,vmin(0,2-(tAr.height()/150))) : 0; } else vsPerc = false; if(isLog) { vsMax = log10(vmax(1e-100,vsMax)); vsMin = log10(vmax(1e-100,vsMin)); if((vsMax-vsMin) / fabs(vsMin+(vsMax-vsMin)/2) < 0.0001) { double wnt_dp = 0.0001*fabs(vsMin+(vsMax-vsMin)/2) - (vsMax-vsMin); vsMin -= wnt_dp/2; vsMax += wnt_dp/2; } } if(isScale) { //Vertical scale and offset apply float vsDif = vsMax - vsMin; vsMax += shD->sclVerSclOff*vsDif/100; vsMin += shD->sclVerSclOff*vsDif/100; vsMax += (shD->sclVerScl*vsDif/100-vsDif)/2; vsMin -= (shD->sclVerScl*vsDif/100-vsDif)/2; } //Draw main and individual vertical scales float vmax_ln = tAr.height() / ((sclVer&FD_MARKS)?(2*mrkHeight):(int)(15*vmin(w->xScale(true),w->yScale(true)))); for(unsigned iP = 0; vmax_ln >= 2 && iP < prmsInd.size(); iP++) { //prmsInd[i]=-1 - for main scale bool isLogT, vsPercT; char sclVerT; QPen grdPenT = grdPen; double vsMinT, vsMaxT; double vDiv = 1; if(prmsInd[iP] < 0) { //Main scale process // Draw environment vsPercT = vsPerc; isLogT = isLog; sclVerT = sclVer; grdPenT.setColor(shD->sclColor); mrkPen.setColor(shD->sclMarkColor); if(prmInGrp == 1 && prmGrpLast >= 0) { //Set color for single parameter in main group grdPenT.setColor(shD->prms[prmGrpLast].color()); mrkPen.setColor(shD->prms[prmGrpLast].color()); } // Rounding double v_len = vsMax - vsMin; while(v_len > vmax_ln) { vDiv *= 10; v_len /= 10; } while(v_len && v_len < vmax_ln/10) { vDiv /= 10; v_len *= 10; } if(!isScale) { vsMin = floor(vsMin/vDiv)*vDiv; vsMax = ceil(vsMax/vDiv)*vDiv; } while(!isLogT && ((vsMax-vsMin)/vDiv) < vmax_ln/2) vDiv /= 2; vsMinT = vsMin; vsMaxT = vsMax; } else { //Individual scale process TrendObj &cP = shD->prms[prmsInd[iP]]; // Draw environment vsPercT = false; isLogT = cP.mScale&FD_LOG; sclVerT = cP.wScale; grdPenT.setColor(cP.color()); mrkPen.setColor(cP.color()); // Rounding double v_len = cP.adjU - cP.adjL; while(v_len > vmax_ln) { vDiv *= 10; v_len /= 10; } while(v_len && v_len < vmax_ln/10) { vDiv /= 10; v_len *= 10; } if(!isScale) { cP.adjL = floor(cP.adjL/vDiv)*vDiv; cP.adjU = ceil(cP.adjU/vDiv)*vDiv; } while(!isLogT && ((cP.adjU-cP.adjL)/vDiv) < vmax_ln/2) vDiv /= 2; vsMinT = cP.adjL; vsMaxT = cP.adjU; } if(iP < (prmsInd.size()-1)) sclVerT &= ~(FD_GRD); //Hide grid for not last scale //Draw vertical grid and markers int markWdth = 0; if(sclVerT&FD_GRD_MARKS) { string labVal; pnt.setPen(grdPenT); pnt.drawLine(tAr.x()-1, tAr.y(), tAr.x()-1, tAr.height()); for(double iV = floor((vsMinT/vDiv)+0.5)*vDiv; (vsMaxT-iV)/vDiv > -0.1; iV += vDiv) { int v_pos = tAr.y() + tAr.height() - (int)((double)tAr.height()*(iV-vsMinT)/(vsMaxT-vsMinT)); if(sclVerT&FD_GRD) { pnt.setPen(grdPen); pnt.drawLine(tAr.x(), v_pos, tAr.x()+tAr.width(), v_pos); } else { pnt.setPen(grdPenT); pnt.drawLine(tAr.x()-3, v_pos, tAr.x()+3, v_pos); } if(sclVerT&FD_MARKS) { bool isPerc = vsPercT && ((vsMaxT-iV-vDiv)/vDiv <= -0.1); bool isMax = (v_pos-1-mrkHeight) < tAr.y(); pnt.setPen(mrkPen); labVal = TSYS::strMess("%0.5g",(isLogT?pow(10,iV):iV)) + (isPerc?" %":""); pnt.drawText(tAr.x()+2, v_pos-1+(isMax?mrkHeight:0), labVal.c_str()); markWdth = vmax(markWdth, pnt.fontMetrics().size(Qt::TextSingleLine,labVal.c_str()).width()); } } } if(iP < (prmsInd.size()-1)) tAr.adjust((markWdth?(markWdth+5):0), 0, 0, 0); } mrkPen.setColor(shD->sclMarkColor); //Restore mark color //Calc horizontal scale for main and individual int64_t aHbeg, aHend; //Corrected for allow data the trend begin and end point bool hsPerc = true, //Horizontal scale percent mode isHLog = sclHor&FD_LOG, //Logarithmic horizontal scale isHScale = (fabs(shD->sclHorSclOff) > 1 || fabs(shD->sclHorScl-100) > 1); double hsMax = -3e300, hsMin = 3e300; //Trend's horizontal scale border // Get main scale for non individual parameters prmInGrp = 0, prmGrpLast = -1; for(unsigned iP = 1, mainPerc = false; iP < shD->prms.size(); iP += 2) { TrendObj &cP = shD->prms[iP]; if(!cP.val().size() || !cP.color().isValid() || !shD->prms[iP-1].val().size() || !shD->prms[iP-1].color().isValid()) continue; cP.adjU = -3e300; cP.adjL = 3e300; if(cP.bordU() <= cP.bordL() && cP.valTp() != TFld::Boolean) { // Check trend for valid data aHbeg = vmax(tBeg, cP.valBeg()); aHend = vmin(tEnd, cP.valEnd()); if(aHbeg >= aHend) return; // Calc value borders bool end_vl = false; int ipos = cP.val(aHbeg); if(ipos && cP.val()[ipos].tm > aHbeg) ipos--; while(true) { if(ipos >= (int)cP.val().size() || end_vl) break; if(cP.val()[ipos].tm >= aHend) end_vl = true; if(cP.val()[ipos].val != EVAL_REAL) { curVl = cP.val()[ipos].val; cP.adjL = vmin(cP.adjL, curVl); cP.adjU = vmax(cP.adjU, curVl); } ipos++; } // Value range expanding // No value if(cP.adjU == -3e300) { cP.adjU = 1; cP.adjL = 0; } // Range and absolute value are very small else if((cP.adjU-cP.adjL) < 1e-30 && fabs(cP.adjU) < 1e-30) { cP.adjU += 0.5; cP.adjL -= 0.5; } // Only range is very small else if((cP.adjU-cP.adjL) < 1e-30) { cP.adjL -= ((double)iP/(double)shD->prms.size())*fabs(cP.adjU); cP.adjU += (1.0-(double)iP/(double)shD->prms.size())*fabs(cP.adjU); } // Range smaller relatively to absolute value else if((cP.adjU-cP.adjL) / fabs(cP.adjL+(cP.adjU-cP.adjL)/2) < 0.001) { double wnt_dp = 0.001*fabs(cP.adjL+(cP.adjU-cP.adjL)/2)-(cP.adjU-cP.adjL); cP.adjL -= ((double)iP/(double)shD->prms.size())*wnt_dp; cP.adjU += (1.0-(double)iP/(double)shD->prms.size())*wnt_dp; } } else if(cP.bordU() <= cP.bordL() && cP.valTp() == TFld::Boolean) { cP.adjU = 1.5; cP.adjL = -0.5; } else { cP.adjU = cP.bordU(); cP.adjL = cP.bordL(); } cP.wScale = cP.mScale&(sclHor|FD_LOG); if(cP.wScale&FD_GRD_MARKS) continue; // Check for value border allow if(!mainPerc && (hsMin > hsMax || vmax(fabs((hsMax-cP.adjL)/(hsMax-hsMin)-1),fabs((cP.adjU-hsMin)/(hsMax-hsMin)-1)) < 0.2)) { hsMin = vmin(hsMin, cP.adjL); hsMax = vmax(hsMax, cP.adjU); } else { hsMax = -3e300; hsMin = 3e300; mainPerc = true; } prmInGrp++; prmGrpLast = iP; } // Check for individual parameters and for possibility to merge it to group or create new for no group prmIndiv = 0, prmIndivSc = -1; prmsInd.clear(); for(unsigned iP = 1; iP < shD->prms.size(); iP += 2) { TrendObj &cP = shD->prms[iP]; cP.isIndiv = false; if(!cP.val().size() || !cP.color().isValid() || !(cP.wScale&FD_GRD_MARKS) || !shD->prms[iP-1].val().size() || !shD->prms[iP-1].color().isValid()) continue; // Check for include to present or create new group and exclude from individual if((!prmInGrp || (hsMin < hsMax && vmax(fabs((hsMax-cP.adjL)/(hsMax-hsMin)-1),fabs((cP.adjU-hsMin)/(hsMax-hsMin)-1)) < 0.2)) && (cP.mScale&FD_LOG) == (sclHor&FD_LOG)) { hsMin = vmin(hsMin, cP.adjL); hsMax = vmax(hsMax, cP.adjU); prmInGrp++; prmGrpLast = iP; continue; } cP.isIndiv = true; prmIndiv++; if(prmIndivSc < 0 && cP.mScale&FD_GRD) prmIndivSc = iP; else prmsInd.push_back(iP); if(cP.mScale&FD_LOG) { cP.adjU = log10(vmax(1e-100,cP.adjU)); cP.adjL = log10(vmax(1e-100,cP.adjL)); if((cP.adjU-cP.adjL) / fabs(cP.adjL+(cP.adjU-cP.adjL)/2) < 0.0001) { double wnt_dp = 0.0001*fabs(cP.adjL+(cP.adjU-cP.adjL)/2)-(cP.adjU-cP.adjL); cP.adjL -= wnt_dp/2; cP.adjU += wnt_dp/2; } } if(isHScale) { //horizontal scale and offset apply float hsDif = cP.adjU - cP.adjL; cP.adjU += shD->sclHorSclOff*hsDif/100; cP.adjL += shD->sclHorSclOff*hsDif/100; cP.adjU += (shD->sclHorScl*hsDif/100-hsDif)/2; cP.adjL -= (shD->sclHorScl*hsDif/100-hsDif)/2; } } if(prmInGrp) prmsInd.push_back(-1); if(prmIndivSc >= 0) prmsInd.push_back(prmIndivSc); // Final main scale adapting if(hsMin > hsMax) { hsPerc = true; hsMax = 100; hsMin = isHLog ? pow(10,vmin(0,2-(tAr.width()/150))) : 0; } else hsPerc = false; if(isHLog) { hsMax = log10(vmax(1e-100,hsMax)); hsMin = log10(vmax(1e-100,hsMin)); if((hsMax-hsMin) / fabs(hsMin+(hsMax-hsMin)/2) < 0.0001) { double wnt_dp = 0.0001*fabs(hsMin+(hsMax-hsMin)/2) - (hsMax-hsMin); hsMin -= wnt_dp/2; hsMax += wnt_dp/2; } } if(isHScale) { //Horizontal scale and offset apply float hsDif = hsMax - hsMin; hsMax += shD->sclHorSclOff*hsDif/100; hsMin += shD->sclHorSclOff*hsDif/100; hsMax += (shD->sclHorScl*hsDif/100-hsDif)/2; hsMin -= (shD->sclHorScl*hsDif/100-hsDif)/2; } // Draw main and individual horizontal scales float hmax_ln = tAr.width() / (int)((sclHor&FD_MARKS)?mrkWidth:15*vmin(w->xScale(true),w->yScale(true))); for(unsigned iP = 0; hmax_ln >= 2 && iP < prmsInd.size(); iP++) { //prmsInd[i]=-1 - for main scale bool isLogT, hsPercT; char sclHorT; QPen grdPenT = grdPen; double hsMinT, hsMaxT; double hDiv = 1; if(prmsInd[iP] < 0) { //Main scale process // Draw environment hsPercT = hsPerc; isLogT = isHLog; sclHorT = sclHor; grdPenT.setColor(shD->sclColor); mrkPen.setColor(shD->sclMarkColor); if(prmInGrp == 1 && prmGrpLast >= 0) { //Set color for single parameter in main group grdPenT.setColor(shD->prms[prmGrpLast].color()); mrkPen.setColor(shD->prms[prmGrpLast].color()); } // Rounding double h_len = hsMax - hsMin; while(h_len > hmax_ln) { hDiv *= 10; h_len /= 10; } while(h_len && h_len < hmax_ln/10) { hDiv /= 10; h_len *= 10; } if(!isHScale) { hsMin = floor(hsMin/hDiv)*hDiv; hsMax = ceil(hsMax/hDiv)*hDiv; } while(!isLogT && ((hsMax-hsMin)/hDiv) < hmax_ln/2) hDiv /= 2; hsMinT = hsMin; hsMaxT = hsMax; } else { //Individual scale process TrendObj &cP = shD->prms[prmsInd[iP]]; // Draw environment hsPercT = false; isLogT = cP.mScale&FD_LOG; sclHorT = cP.wScale; grdPenT.setColor(cP.color()); mrkPen.setColor(cP.color()); // Rounding double h_len = cP.adjU - cP.adjL; while(h_len > hmax_ln) { hDiv *= 10; h_len /= 10; } while(h_len && h_len < hmax_ln/10) { hDiv /= 10; h_len *= 10; } if(!isHScale) { cP.adjL = floor(cP.adjL/hDiv)*hDiv; cP.adjU = ceil(cP.adjU/hDiv)*hDiv; } while(!isLogT && ((cP.adjU-cP.adjL)/hDiv) < hmax_ln/2) hDiv /= 2; hsMinT = cP.adjL; hsMaxT = cP.adjU; } if(iP < (prmsInd.size()-1)) sclHorT &= ~(FD_GRD); //Hide grid for no last scale //Draw horizontal grid and markers if(sclHorT&FD_GRD_MARKS) { string labVal; int begMarkBrd = -5, endMarkBrd = tAr.x() + tAr.width() + 5; pnt.setPen(grdPenT); pnt.drawLine(tAr.x(), tAr.y()+tAr.height()+1, tAr.x()+tAr.width(), tAr.y()+tAr.height()+1); for(double iH = ceil(hsMinT/hDiv)*hDiv; (hsMaxT-iH)/hDiv > -0.1; iH += hDiv) { int h_pos = tAr.x() + (int)((double)tAr.width()*(iH-hsMinT)/(hsMaxT-hsMinT)); if(sclHorT&FD_GRD) { pnt.setPen(grdPen); pnt.drawLine(h_pos, tAr.y(), h_pos, tAr.y()+tAr.height()); } else { pnt.setPen(grdPenT); pnt.drawLine(h_pos, tAr.y()+tAr.height()-3, h_pos, tAr.y()+tAr.height()+3); } if(sclHorT&FD_MARKS) { pnt.setPen(mrkPen); bool isPerc = hsPercT && ((hsMaxT-iH-hDiv)/hDiv <= -0.1); labVal = TSYS::strMess("%0.5g",(isLogT?pow(10,iH):iH)) + (isPerc?" %":""); int wdth = pnt.fontMetrics().size(Qt::TextSingleLine, labVal.c_str()).width(); int tpos = vmax(0, vmin(endMarkBrd-3-wdth,h_pos-wdth/2)); if((tpos+wdth) <= (endMarkBrd-3) && tpos >= (begMarkBrd+3)) { pnt.drawText(tpos, tAr.y()+tAr.height()+mrkHeight, labVal.c_str()); begMarkBrd = vmax(begMarkBrd, tpos+wdth); } } } } if(iP < (prmsInd.size()-1)) tAr.adjust(0, (mrkHeight?(mrkHeight+5):0), 0, 0); } mrkPen.setColor(shD->sclMarkColor); //Restore mark color //Draw curves for(unsigned iT = 0; (iT+1) < shD->prms.size(); iT += 2) { TrendObj &cP = shD->prms[iT], &cPX = shD->prms[iT+1]; // Set trend's pen QPen trpen(cP.color()); trpen.setStyle(Qt::SolidLine); trpen.setWidth(vmax(1,vmin(10,(int)rRnd(cP.width()*vmin(w->xScale(true),w->yScale(true)))))); //#if QT_VERSION < 0x050000 // if(cP.valTp() != TFld::Boolean && trpen.width() > 1) trpen.setCapStyle(Qt::RoundCap); //#else trpen.setCapStyle(Qt::FlatCap); //#endif pnt.setRenderHint(QPainter::Antialiasing, (trpen.width()>=2)); pnt.setPen(trpen); // Prepare generic parameters aVbeg = vmax(tBeg, vmax(cP.valBeg(),cPX.valBeg())); aVend = vmin(tEnd, vmin(cP.valEnd(),cPX.valEnd())); if(aVbeg >= aVend || !cP.color().isValid() || !cPX.color().isValid()) continue; int aPosBeg = cP.val(aVbeg); if(aPosBeg && cP.val()[aPosBeg].tm > aVbeg) aPosBeg--; bool vsPercT = cP.isIndiv ? false : vsPerc; bool isLogT = cP.isIndiv ? (cP.wScale&FD_LOG) : isLog; double vsMaxT = cP.isIndiv ? cP.adjU : vsMax; double vsMinT = cP.isIndiv ? cP.adjL : vsMin; int aPosBegX = cPX.val(aVbeg); if(aPosBegX && cPX.val()[aPosBegX].tm > aVbeg) aPosBegX--; bool hsPercT = cPX.isIndiv ? false : hsPerc; bool isHLogT = cPX.isIndiv ? (cPX.wScale&FD_LOG) : isHLog; double hsMaxT = cPX.isIndiv ? cPX.adjU : hsMax; double hsMinT = cPX.isIndiv ? cPX.adjL : hsMin; // Y: Prepare border for percent trend, ONLY! float bordL = cP.bordL(); float bordU = cP.bordU(); if(vsPercT && bordL >= bordU) { bordU = cP.adjU; bordL = cP.adjL; } /*bordU = -3e300, bordL = 3e300; bool end_vl = false; for(int ipos = aPosBeg; true; ipos++) { if(ipos >= (int)cP.val().size() || end_vl) break; if(cP.val()[ipos].tm >= aVend) end_vl = true; if(cP.val()[ipos].val != EVAL_REAL) { bordL = vmin(bordL, cP.val()[ipos].val); bordU = vmax(bordU, cP.val()[ipos].val); } } float vMarg = (bordU-bordL)/10; if(vMarg == 0) vMarg = 0.5; bordL -= vMarg; bordU += vMarg; }*/ // X: Prepare XY data buffer and prepare border for percent trend, ONLY! float xBordL = cPX.bordL(); float xBordU = cPX.bordU(); int maxVlX = -1; vector< pair > dBuf; { bool xNeedRngChk = (hsPercT && xBordL >= xBordU); if(xNeedRngChk) xBordU = -3e300, xBordL = 3e300; bool end_vl = false; for(int ipos = aPosBegX, iVpos = 0; true; ipos++) { if(ipos >= (int)cPX.val().size() || end_vl) break; if(cPX.val()[ipos].tm >= aVend) end_vl = true; if(cPX.val()[ipos].val != EVAL_REAL) { if((iVpos=cP.val(cPX.val()[ipos].tm)) < (int)cP.val().size() && cP.val()[iVpos].val != EVAL_REAL) { dBuf.push_back(pair(cPX.val()[ipos].val,cP.val()[iVpos].val)); if(maxVlX < 0 || cPX.val()[ipos].val >= cPX.val()[maxVlX].val) maxVlX = ipos; } if(xNeedRngChk) { xBordL = vmin(xBordL, cPX.val()[ipos].val); xBordU = vmax(xBordU, cPX.val()[ipos].val); } } } if(xNeedRngChk) { float vMarg = (xBordU-xBordL)/10; xBordL -= vMarg; xBordU += vMarg; } } // Draw curve int c_vpos, c_hpos, c_vposPrev = -1, c_hposPrev = -1; double curVl, curVlX; for(vector< pair >::iterator iD = dBuf.begin(); iD != dBuf.end(); ++iD) { curVl = vsPercT ? 100*(iD->second-bordL)/(bordU-bordL) : iD->second; curVlX = hsPercT ? 100*(iD->first-xBordL)/(xBordU-xBordL) : iD->first; c_vpos = tAr.y() + tAr.height()-(int)((double)tAr.height()*vmax(0,vmin(1,((isLogT?log10(vmax(1e-100,curVl)):curVl)-vsMinT)/(vsMaxT-vsMinT)))); c_hpos = tAr.x() + (int)((double)tAr.width()*vmax(0,vmin(1,((isHLogT?log10(vmax(1e-100,curVlX)):curVlX)-hsMinT)/(hsMaxT-hsMinT)))); if(c_vposPrev < 0 || c_hposPrev < 0) pnt.drawPoint(c_hpos, c_vpos); else if(c_hposPrev != c_hpos || c_vposPrev != c_vpos) pnt.drawLine(c_hposPrev, c_vposPrev, c_hpos, c_vpos); c_hposPrev = c_hpos; c_vposPrev = c_vpos; } // Draw curent point int iVpos = cP.val(aVend); int iVposX = cPX.val(aVend); if(iVpos < (int)cP.val().size() && iVposX < (int)cPX.val().size() && iVposX != maxVlX && cP.val()[iVpos].val != EVAL_REAL && cPX.val()[iVposX].val != EVAL_REAL) { curVl = vsPercT ? 100*(cP.val()[iVpos].val-bordL)/(bordU-bordL) : cP.val()[iVpos].val; curVlX = hsPercT ? 100*(cPX.val()[iVposX].val-xBordL)/(xBordU-xBordL) : cPX.val()[iVposX].val; c_vpos = tAr.y() + tAr.height()-(int)((double)tAr.height()*vmax(0,vmin(1,((isLogT?log10(vmax(1e-100,curVl)):curVl)-vsMinT)/(vsMaxT-vsMinT)))); c_hpos = tAr.x() + (int)((double)tAr.width()*vmax(0,vmin(1,((isHLogT?log10(vmax(1e-100,curVlX)):curVlX)-hsMinT)/(hsMaxT-hsMinT)))); pnt.drawLine(c_hpos-trpen.width()*3, c_vpos-trpen.width()*3, c_hpos+trpen.width()*3, c_vpos+trpen.width()*3); pnt.drawLine(c_hpos-trpen.width()*3, c_vpos+trpen.width()*3, c_hpos+trpen.width()*3, c_vpos-trpen.width()*3); AttrValS attrs; attrs.push_back(std::make_pair(TSYS::strMess("prm%dval",iT),r2s(cP.val()[iVpos].val))); attrs.push_back(std::make_pair(TSYS::strMess("prm%dval",iT+1),r2s(cPX.val()[iVposX].val))); attrs.push_back(std::make_pair("curSek",i2s(aVend/1000000))); attrs.push_back(std::make_pair("curUSek",i2s(aVend%1000000))); w->attrsSet(attrs); } } shD->pictRect = tAr; shD->tPict = tPict; if(mess_lev() == TMess::Debug) mess_debug(mod->nodePath().c_str(), _("Time of building the trend: %f ms."), 1e-3*(TSYS::curTime()-d_cnt)); } void ShapeDiagram::makeSpectrumPicture( WdgView *w ) { QPen grdPen, mrkPen; int mrkHeight = 0, mrkWidth = 0; ShpDt *shD = (ShpDt*)w->shpData; //Prepare picture shD->pictObj = QImage(w->rect().size(), QImage::Format_ARGB32_Premultiplied); shD->pictObj.fill(0); QPainter pnt(&shD->pictObj); //Get generic parameters int64_t tSize = (int64_t)(1e6*shD->tSize); //Time size (us) if(shD->prms.empty() || tSize <= 0) return; int sclHor = shD->sclHor; //Horisontal scale mode int sclVer = shD->sclVer; //Vertical scale mode //Trends' area rect definition QRect tAr = w->rect().adjusted(1,1,-2*(shD->geomMargin+shD->border.width()+1),-2*(shD->geomMargin+shD->border.width()+1)); //Curves of spectrum area rect //Main scales definition if(sclHor&FD_GRD_MARKS || sclVer&FD_GRD_MARKS) { // Set grid pen grdPen.setColor(shD->sclColor); grdPen.setStyle(Qt::SolidLine); grdPen.setWidth(vmax(1,rRnd(vmin(w->xScale(true),w->yScale(true))))); // Set markers font and color if(sclHor&FD_MARKS || sclVer&FD_MARKS) { mrkPen.setColor(shD->sclMarkColor); QFont mrkFnt = shD->sclMarkFont; //mrkFnt.setPixelSize((double)mrkFnt.pixelSize()*vmin(w->xScale(true),w->yScale(true))); pnt.setFont(mrkFnt); mrkHeight = pnt.fontMetrics().height() - pnt.fontMetrics().descent(); mrkWidth = pnt.fontMetrics().size(Qt::TextSingleLine, "000000").width(); if(sclHor&FD_MARKS) { if(tAr.height() < (int)(100*vmin(w->xScale(true),w->yScale(true)))) sclHor &= ~(FD_MARKS); else tAr.adjust(0,0,0,-mrkHeight); } if(sclVer&FD_MARKS && tAr.width() < (int)(100*vmin(w->xScale(true),w->yScale(true)))) sclVer &= ~(FD_MARKS); } } #if HAVE_FFTW3_H //Calc vertical scale for main and individual double curVl, vsMax = -3e300, vsMin = 3e300;//Trend's vertical scale border bool vsPerc = true; //Vertical scale percent mode bool isScale = (fabs(shD->sclVerSclOff) > 1 || fabs(shD->sclVerScl-100) > 1); // Get main scale for non individual parameters int prmInGrp = 0, prmGrpLast = -1; for(unsigned iP = 0, mainPerc = false; iP < shD->prms.size(); iP++) { TrendObj &cP = shD->prms[iP]; if(!cP.fftN || !cP.color().isValid()) continue; cP.adjU = -3e300; cP.adjL = 3e300; if(cP.bordU() <= cP.bordL()) { // Calc value borders double vlOff = cP.fftOut[0][0]/cP.fftN; for(int iV = 1; iV < (cP.fftN/2+1); iV++) { curVl = vlOff+pow(pow(cP.fftOut[iV][0],2)+pow(cP.fftOut[iV][1],2),0.5)/(cP.fftN/2+1); cP.adjL = vmin(cP.adjL, curVl); cP.adjU = vmax(cP.adjU, curVl); } if(cP.adjU == cP.adjL) { cP.adjU += 1.0; cP.adjL -= 1.0; } else if((cP.adjU-cP.adjL) / fabs(cP.adjL+(cP.adjU-cP.adjL)/2) < 0.001) { double wnt_dp = 0.001*fabs(cP.adjL+(cP.adjU-cP.adjL)/2)-(cP.adjU-cP.adjL); cP.adjL -= wnt_dp/2; cP.adjU += wnt_dp/2; } } else { cP.adjU = cP.bordU(); cP.adjL = cP.bordL(); } cP.wScale = cP.mScale&(sclVer|FD_LOG); if(cP.wScale&FD_GRD_MARKS) continue; // Check for value border allow if(!mainPerc && (vsMin > vsMax || vmax(fabs((vsMax-cP.adjL)/(vsMax-vsMin)-1),fabs((cP.adjU-vsMin)/(vsMax-vsMin)-1)) < 0.2)) { vsMin = vmin(vsMin, cP.adjL); vsMax = vmax(vsMax, cP.adjU); } else { vsMax = -3e300; vsMin = 3e300; mainPerc = true; } prmInGrp++; prmGrpLast = iP; } // Check for individual parameters and for possibility to merge it to group or create new for no group int prmIndiv = 0; int prmIndivSc = -1; vector prmsInd; for(unsigned iP = 0; iP < shD->prms.size(); iP++) { TrendObj &cP = shD->prms[iP]; cP.isIndiv = false; if(!cP.fftN || !cP.color().isValid() || !(cP.wScale&FD_GRD_MARKS)) continue; // Check for include to present or create new group and exclude from individual if((!prmInGrp || (vsMin < vsMax && vmax(fabs((vsMax-cP.adjL)/(vsMax-vsMin)-1),fabs((cP.adjU-vsMin)/(vsMax-vsMin)-1)) < 0.2))) { vsMin = vmin(vsMin, cP.adjL); vsMax = vmax(vsMax, cP.adjU); prmInGrp++; prmGrpLast = iP; continue; } cP.isIndiv = true; prmIndiv++; if(prmIndivSc < 0 && cP.mScale&FD_GRD) prmIndivSc = iP; else prmsInd.push_back(iP); if(isScale) { //Vertical scale and offset apply float vsDif = cP.adjU - cP.adjL; cP.adjU += shD->sclVerSclOff*vsDif/100; cP.adjL += shD->sclVerSclOff*vsDif/100; cP.adjU += (shD->sclVerScl*vsDif/100-vsDif)/2; cP.adjL -= (shD->sclVerScl*vsDif/100-vsDif)/2; } } if(prmInGrp) prmsInd.push_back(-1); if(prmIndivSc >= 0) prmsInd.push_back(prmIndivSc); // Final main scale adapting if(vsMin > vsMax) { vsPerc = true; vsMax = 100; vsMin = 0; } else vsPerc = false; if(isScale) { //Vertical scale and offset apply float vsDif = vsMax - vsMin; vsMax += shD->sclVerSclOff*vsDif/100; vsMin += shD->sclVerSclOff*vsDif/100; vsMax += (shD->sclVerScl*vsDif/100-vsDif)/2; vsMin -= (shD->sclVerScl*vsDif/100-vsDif)/2; } //Draw main and individual vertical scales double vmax_ln = tAr.height() / ((sclVer&FD_MARKS)?(2*mrkHeight):(int)(15*vmin(w->xScale(true),w->yScale(true)))); for(unsigned iP = 0; vmax_ln >= 2 && iP < prmsInd.size(); iP++) { //prmsInd[i]=-1 - for main scale bool vsPercT; char sclVerT; QPen grdPenT = grdPen; double vsMinT, vsMaxT; double vDiv = 1; if(prmsInd[iP] < 0) { //Main scale process // Draw environment vsPercT = vsPerc; sclVerT = sclVer; grdPenT.setColor(shD->sclColor); mrkPen.setColor(shD->sclMarkColor); if(prmInGrp == 1 && prmGrpLast >= 0) { //Set color for single parameter in main group grdPenT.setColor(shD->prms[prmGrpLast].color()); mrkPen.setColor(shD->prms[prmGrpLast].color()); } // Rounding double v_len = vsMax - vsMin; while(v_len > vmax_ln) { vDiv *= 10; v_len /= 10; } while(v_len < vmax_ln/10) { vDiv /= 10; v_len *= 10; } if(!isScale) { vsMin = floor(vsMin/vDiv)*vDiv; vsMax = ceil(vsMax/vDiv)*vDiv; } while(((vsMax-vsMin)/vDiv) < vmax_ln/2) vDiv /= 2; vsMinT = vsMin; vsMaxT = vsMax; } else { //Individual scale process TrendObj &cP = shD->prms[prmsInd[iP]]; // Draw environment vsPercT = false; sclVerT = cP.wScale; grdPenT.setColor(cP.color()); mrkPen.setColor(cP.color()); // Rounding double v_len = cP.adjU - cP.adjL; while(v_len > vmax_ln) { vDiv *= 10; v_len /= 10; } while(v_len < vmax_ln/10) { vDiv /= 10; v_len *= 10; } if(!isScale) { cP.adjL = floor(cP.adjL/vDiv)*vDiv; cP.adjU = ceil(cP.adjU/vDiv)*vDiv; } while(((cP.adjU-cP.adjL)/vDiv) < vmax_ln/2) vDiv /= 2; vsMinT = cP.adjL; vsMaxT = cP.adjU; } if(iP < (prmsInd.size()-1)) sclVerT &= ~(FD_GRD); //Hide grid for no last scale // Draw vertical grid and markers int markWdth = 0; if(sclVerT&FD_GRD_MARKS) { string labVal; pnt.setPen(grdPenT); pnt.drawLine(tAr.x()-1, tAr.y(), tAr.x()-1, tAr.height()); for(double iV = ceil(vsMinT/vDiv)*vDiv; (vsMaxT-iV)/vDiv > -0.1; iV += vDiv) { int v_pos = tAr.y()+tAr.height()-(int)((double)tAr.height()*(iV-vsMinT)/(vsMaxT-vsMinT)); if(sclVerT&FD_GRD) { pnt.setPen(grdPen); pnt.drawLine(tAr.x(), v_pos, tAr.x()+tAr.width(), v_pos); } else { pnt.setPen(grdPenT); pnt.drawLine(tAr.x()-3, v_pos, tAr.x()+3, v_pos); } if(sclVerT&FD_MARKS) { bool isPerc = vsPercT && ((vsMaxT-iV-vDiv)/vDiv <= -0.1); bool isMax = (v_pos-1-mrkHeight) < tAr.y(); pnt.setPen(mrkPen); labVal = TSYS::strMess("%0.5g",iV)+(isPerc?" %":""); pnt.drawText(tAr.x()+2, v_pos-1+(isMax?mrkHeight:0), labVal.c_str()); markWdth = vmax(markWdth, pnt.fontMetrics().size(Qt::TextSingleLine,labVal.c_str()).width()); } } } if(iP < (prmsInd.size()-1)) tAr.adjust((markWdth?(markWdth+5):0), 0, 0, 0); } mrkPen.setColor(shD->sclMarkColor); //Restore mark color #endif //Calc horizontal scale int fftN = w->size().width(); double fftBeg = 1e6/(double)tSize; //Minimum frequency or maximum period time (s) double fftEnd = (double)fftN*fftBeg/2; //Maximum frequency or minimum period time (s) double hDiv = 1; //Horisontal scale divisor int hmax_ln = tAr.width() / (int)((sclHor&FD_MARKS)?mrkWidth:15*vmin(w->xScale(true),w->yScale(true))); if(hmax_ln >= 2) { double hLen = fftEnd-fftBeg; while(hLen/hDiv > hmax_ln) hDiv *= 10; while(hLen/hDiv < hmax_ln/10) hDiv /= 10; fftBeg = floor(10*fftBeg/hDiv)*hDiv/10; fftEnd = ceil(10*fftEnd/hDiv)*hDiv/10; while(((fftEnd-fftBeg)/hDiv) < hmax_ln/2) hDiv/=2; // Draw horisontal grid and markers if(sclHor&FD_GRD_MARKS) { string labH; double labDiv = 1; if(fftEnd > 1000) labDiv = 1000; // Draw generic grid line pnt.setPen(grdPen); pnt.drawLine(tAr.x(),tAr.y()+tAr.height(),tAr.x()+tAr.width(),tAr.y()+tAr.height()); // Draw full trend's data and time to the trend end position int begMarkBrd = -5; int endMarkBrd = tAr.x()+tAr.width(); if(sclHor&FD_MARKS) { pnt.setPen(mrkPen); labH = TSYS::strMess("%0.5g",fftEnd/labDiv)+((labDiv==1000)?_("kHz"):_("Hz")); int markBrd = tAr.x()+tAr.width()-pnt.fontMetrics().size(Qt::TextSingleLine, labH.c_str()).width(); endMarkBrd = vmin(endMarkBrd,markBrd); pnt.drawText(markBrd,tAr.y()+tAr.height()+mrkHeight,labH.c_str()); } // Draw grid and/or markers for(double iH = fftBeg; (fftEnd-iH)/hDiv > -0.1; iH += hDiv) { // Draw grid pnt.setPen(grdPen); int h_pos = tAr.x()+(int)((double)tAr.width()*(iH-fftBeg)/(fftEnd-fftBeg)); if(sclHor&FD_GRD) pnt.drawLine(h_pos, tAr.y(), h_pos, tAr.y()+tAr.height()); else pnt.drawLine(h_pos, tAr.y()+tAr.height()-3, h_pos, tAr.y()+tAr.height()+3); if(sclHor&FD_MARKS) { pnt.setPen(mrkPen); labH = TSYS::strMess("%0.5g", iH/labDiv); int wdth = pnt.fontMetrics().size(Qt::TextSingleLine, labH.c_str()).width(); int tpos = vmax(h_pos-wdth/2, 0); if((tpos+wdth) < (endMarkBrd-3) && tpos > (begMarkBrd+3)) pnt.drawText(tpos, tAr.y()+tAr.height()+mrkHeight, labH.c_str()); begMarkBrd = vmax(begMarkBrd,tpos+wdth); } } } } #if HAVE_FFTW3_H // Draw trends for(unsigned iT = 0; iT < shD->prms.size(); iT++) { TrendObj &cP = shD->prms[iT]; if(!cP.fftN || !cP.color().isValid()) continue; // Set trend's pen QPen trpen(cP.color()); trpen.setStyle(Qt::SolidLine); trpen.setWidth(vmax(1,vmin(10,(int)rRnd(cP.width()*vmin(w->xScale(true),w->yScale(true)))))); //#if QT_VERSION < 0x050000 // if(trpen.width() > 1) trpen.setCapStyle(Qt::RoundCap); //#else trpen.setCapStyle(Qt::FlatCap); //#endif pnt.setRenderHint(QPainter::Antialiasing, (trpen.width()>=2)); pnt.setPen(trpen); // Prepare generic parameters double vlOff = cP.fftOut[0][0]/cP.fftN; double fftDt = (1e6/(double)tSize)*(double)w->size().width()/cP.fftN; bool vsPercT = cP.isIndiv ? false : vsPerc; double vsMaxT = cP.isIndiv ? cP.adjU : vsMax; double vsMinT = cP.isIndiv ? cP.adjL : vsMin; // Prepare border for percent trend double bordL = cP.bordL(); double bordU = cP.bordU(); if(vsPercT && bordL >= bordU) { bordU = -3e300, bordL = 3e300; for(int iV = 1; iV < (cP.fftN/2+1); iV++) { curVl = vlOff + pow(pow(cP.fftOut[iV][0],2)+pow(cP.fftOut[iV][1],2),0.5)/(cP.fftN/2+1); bordL = vmin(bordL, curVl); bordU = vmax(bordU, curVl); } double vMarg = (bordU-bordL)/10; bordL -= vMarg; bordU += vMarg; } // Draw trend double prevVl = EVAL_REAL; int curPos = 0, prevPos = 0; for(int iV = 1; iV < (cP.fftN/2+1); iV++) { curVl = vlOff + pow(pow(cP.fftOut[iV][0],2)+pow(cP.fftOut[iV][1],2),0.5)/(cP.fftN/2+1); if(vsPercT) curVl = 100*(curVl-bordL)/(bordU-bordL); curPos = tAr.x() + (int)((double)tAr.width()*(fftDt*iV-fftBeg)/(fftEnd-fftBeg)); int c_vpos = tAr.y()+tAr.height()-(int)((double)tAr.height()*vmax(0,vmin(1,(curVl-vsMinT)/(vsMaxT-vsMinT)))); if(prevVl == EVAL_REAL) pnt.drawPoint(curPos, c_vpos); else { int c_vpos_prv = tAr.y() + tAr.height() - (int)((double)tAr.height()*vmax(0,vmin(1,(prevVl-vsMinT)/(vsMaxT-vsMinT)))); pnt.drawLine(prevPos, c_vpos_prv, curPos, c_vpos); } prevPos = curPos; prevVl = curVl; } // Update value on cursor if(shD->active && shD->tTimeCurent && shD->trcPer) { double curFrq = vmax(vmin(1e6/(double)shD->curTime,fftEnd),fftBeg); curPos = (int)(curFrq/fftDt); if(curPos >= 1 && curPos < (cP.fftN/2+1)) { double val = cP.fftOut[0][0]/cP.fftN + pow(pow(cP.fftOut[curPos][0],2)+pow(cP.fftOut[curPos][1],2),0.5)/(cP.fftN/2+1); w->attrSet(TSYS::strMess("prm%dval",iT), r2s(val,6), A_DiagramTrs+A_DiagramTrVal+A_DiagramTrsSz*iT, true); } } } #endif shD->fftBeg = fftBeg; shD->fftEnd = fftEnd; shD->pictRect = tAr; } void ShapeDiagram::makeTrendsPicture( WdgView *w ) { RunWdgView *runW = qobject_cast(w); int64_t d_cnt = 0; QPen grdPen, mrkPen; int mrkHeight = 0, mrkWidth = 0; ShpDt *shD = (ShpDt*)w->shpData; if(mess_lev() == TMess::Debug) d_cnt = TSYS::curTime(); //Prepare picture shD->pictObj = QImage(w->rect().size(),QImage::Format_ARGB32_Premultiplied); shD->pictObj.fill(0); QPainter pnt(&shD->pictObj); //Get generic parameters int64_t tSize = (int64_t)(1e6*shD->tSize); //Trends size (us) int64_t tEnd = shD->tTime; //Trends end point (us) if(shD->tTimeCurent) tEnd = shD->arhEnd(shD->tTime); int64_t tPict = tEnd; int64_t tBeg = tEnd - tSize; //Trends begin point (us) if(shD->prms.empty() || tSize <= 0) return; int sclHor = shD->sclHor; //Horisontal scale mode int sclVer = shD->sclVer; //Vertical scale mode //Trends' area rect definition QRect tAr = w->rect().adjusted(1,1,-2*(shD->geomMargin+shD->border.width()+1),-2*(shD->geomMargin+shD->border.width()+1)); //Main scales definition if(sclHor&FD_GRD_MARKS || sclVer&FD_GRD_MARKS) { // Set grid pen grdPen.setColor(shD->sclColor); grdPen.setStyle(Qt::SolidLine); grdPen.setWidth(vmax(1,(int)rRnd(vmin(w->xScale(true),w->yScale(true))))); // Set markers font and color if(sclHor&FD_MARKS || sclVer&FD_MARKS) { mrkPen.setColor(shD->sclMarkColor); QFont mrkFnt = shD->sclMarkFont; //mrkFnt.setPixelSize((double)mrkFnt.pixelSize()*vmin(w->xScale(true),w->yScale(true))); pnt.setFont(mrkFnt); mrkHeight = pnt.fontMetrics().height()-pnt.fontMetrics().descent(); mrkWidth = pnt.fontMetrics().size(Qt::TextSingleLine, "000000").width(); if(sclHor&FD_MARKS) { if(tAr.height() < (int)(100*vmin(w->xScale(true),w->yScale(true)))) sclHor &= ~(FD_MARKS); else tAr.adjust(0,0,0,-2*mrkHeight); } if(sclVer&FD_MARKS && tAr.width() < (int)(100*vmin(w->xScale(true),w->yScale(true)))) sclVer &= ~(FD_MARKS); } } //Calc vertical scale for main and individual int64_t aVend; //Corrected for allow data the trend end point int64_t aVbeg; //Corrected for allow data the trend begin point bool vsPerc = true; //Vertical scale percent mode bool isLog = sclVer&FD_LOG; //Logarithmic scale double curVl, vsMax = -3e300, vsMin = 3e300; //Trend's vertical scale border bool isScale = (fabs(shD->sclVerSclOff) > 1 || fabs(shD->sclVerScl-100) > 1); // Get main scale for non individual parameters int prmInGrp = 0, prmGrpLast = -1; for(unsigned iP = 0, mainPerc = false; iP < shD->prms.size(); iP++) { TrendObj &cP = shD->prms[iP]; if(!cP.val().size() || !cP.color().isValid()) continue; cP.adjU = -3e300; cP.adjL = 3e300; if(cP.bordU() <= cP.bordL() && cP.valTp() != 0) { // Check trend for valid data aVbeg = vmax(tBeg, cP.valBeg()); aVend = vmin(tEnd, cP.valEnd()); if(aVbeg >= aVend) return; // Calc value borders bool end_vl = false; int ipos = cP.val(aVbeg); if(ipos && cP.val()[ipos].tm > aVbeg) ipos--; while(true) { if(ipos >= (int)cP.val().size() || end_vl) break; if(cP.val()[ipos].tm >= aVend) end_vl = true; if(cP.val()[ipos].val != EVAL_REAL) { curVl = cP.val()[ipos].val; cP.adjL = vmin(cP.adjL, curVl); cP.adjU = vmax(cP.adjU, curVl); } ipos++; } // Value range expanding // No value if(cP.adjU == -3e300) { cP.adjU = 1.0; cP.adjL = 0.0; } // Range and absolute value are very small else if((cP.adjU-cP.adjL) < 1e-30 && fabs(cP.adjU) < 1e-30) { cP.adjU += 0.5; cP.adjL -= 0.5; } // Only range is very small else if((cP.adjU-cP.adjL) < 1e-30) { cP.adjL -= ((double)iP/(double)shD->prms.size())*fabs(cP.adjU); cP.adjU += (1.0-(double)iP/(double)shD->prms.size())*fabs(cP.adjU); } // Range smaller relatively to absolute value else if((cP.adjU-cP.adjL) / fabs(cP.adjL+(cP.adjU-cP.adjL)/2) < 0.001) { double wnt_dp = 0.001*fabs(cP.adjL+(cP.adjU-cP.adjL)/2)-(cP.adjU-cP.adjL); cP.adjL -= ((double)iP/(double)shD->prms.size())*wnt_dp; cP.adjU += (1.0-(double)iP/(double)shD->prms.size())*wnt_dp; } } else if(cP.bordU() <= cP.bordL() && cP.valTp() == 0) { cP.adjU = 1.5; cP.adjL = -0.5; } else { cP.adjU = cP.bordU(); cP.adjL = cP.bordL(); } cP.wScale = cP.mScale&(sclVer|FD_LOG); if(cP.wScale&FD_GRD_MARKS) continue; // Check for value border allow if(!mainPerc && (vsMin > vsMax || vmax(fabs((vsMax-cP.adjL)/(vsMax-vsMin)-1),fabs((cP.adjU-vsMin)/(vsMax-vsMin)-1)) < 0.2)) { vsMin = vmin(vsMin, cP.adjL); vsMax = vmax(vsMax, cP.adjU); } else { vsMax = -3e300; vsMin = 3e300; mainPerc = true; } prmInGrp++; prmGrpLast = iP; } // Check for individual parameters and for possibility to merge it to group or create new for no group int prmIndiv = 0; int prmIndivSc = -1; vector prmsInd; for(unsigned iP = 0; iP < shD->prms.size(); iP++) { TrendObj &cP = shD->prms[iP]; cP.isIndiv = false; if(!cP.val().size() || !cP.color().isValid() || !(cP.wScale&FD_GRD_MARKS)) continue; // Check for include to present or create new group and exclude from individual if((!prmInGrp || (vsMin < vsMax && vmax(fabs((vsMax-cP.adjL)/(vsMax-vsMin)-1),fabs((cP.adjU-vsMin)/(vsMax-vsMin)-1)) < 0.2)) && (cP.mScale&FD_LOG) == (sclVer&FD_LOG)) { vsMin = vmin(vsMin, cP.adjL); vsMax = vmax(vsMax, cP.adjU); prmInGrp++; prmGrpLast = iP; continue; } cP.isIndiv = true; prmIndiv++; if(prmIndivSc < 0 && cP.mScale&FD_GRD) prmIndivSc = iP; else prmsInd.push_back(iP); if(cP.mScale&FD_LOG) { cP.adjU = log10(vmax(1e-100,cP.adjU)); cP.adjL = log10(vmax(1e-100,cP.adjL)); if((cP.adjU-cP.adjL) / fabs(cP.adjL+(cP.adjU-cP.adjL)/2) < 0.0001) { double wnt_dp = 0.0001*fabs(cP.adjL+(cP.adjU-cP.adjL)/2)-(cP.adjU-cP.adjL); cP.adjL -= wnt_dp/2; cP.adjU += wnt_dp/2; } } if(isScale) { //Vertical scale and offset apply float vsDif = cP.adjU - cP.adjL; cP.adjU += shD->sclVerSclOff*vsDif/100; cP.adjL += shD->sclVerSclOff*vsDif/100; cP.adjU += (shD->sclVerScl*vsDif/100-vsDif)/2; cP.adjL -= (shD->sclVerScl*vsDif/100-vsDif)/2; } } if(prmInGrp) prmsInd.push_back(-1); if(prmIndivSc >= 0) prmsInd.push_back(prmIndivSc); // Final main scale adapting if(vsMin > vsMax) { vsPerc = true; vsMax = 100; vsMin = isLog ? pow(10,vmin(0,2-(tAr.height()/150))) : 0; } else vsPerc = false; if(isLog) { vsMax = log10(vmax(1e-100,vsMax)); vsMin = log10(vmax(1e-100,vsMin)); if((vsMax-vsMin) / fabs(vsMin+(vsMax-vsMin)/2) < 0.0001) { double wnt_dp = 0.0001*fabs(vsMin+(vsMax-vsMin)/2)-(vsMax-vsMin); vsMin -= wnt_dp/2; vsMax += wnt_dp/2; } } if(isScale) { //Vertical scale and offset apply float vsDif = vsMax - vsMin; vsMax += shD->sclVerSclOff*vsDif/100; vsMin += shD->sclVerSclOff*vsDif/100; vsMax += (shD->sclVerScl*vsDif/100-vsDif)/2; vsMin -= (shD->sclVerScl*vsDif/100-vsDif)/2; } //Draw main and individual vertical scales float vmax_ln = tAr.height() / ((sclVer&FD_MARKS)?(2*mrkHeight):(int)(15*vmin(w->xScale(true),w->yScale(true)))); for(unsigned iP = 0; vmax_ln >= 2 && iP < prmsInd.size(); iP++) { //prmsInd[i]=-1 - for main scale bool isLogT, vsPercT; char sclVerT; QPen grdPenT = grdPen; double vsMinT, vsMaxT; double vDiv = 1; if(prmsInd[iP] < 0) { //Main scale process // Draw environment vsPercT = vsPerc; isLogT = isLog; sclVerT = sclVer; grdPenT.setColor(shD->sclColor); mrkPen.setColor(shD->sclMarkColor); if(prmInGrp == 1 && prmGrpLast >= 0) { //Set color for single parameter in main group grdPenT.setColor(shD->prms[prmGrpLast].color()); mrkPen.setColor(shD->prms[prmGrpLast].color()); } // Rounding double v_len = vsMax - vsMin; while(v_len > vmax_ln) { vDiv *= 10; v_len /= 10; } while(v_len && v_len < vmax_ln/10) { vDiv /= 10; v_len *= 10; } if(!isScale) { vsMin = floor(vsMin/vDiv)*vDiv; vsMax = ceil(vsMax/vDiv)*vDiv; } while(!isLogT && ((vsMax-vsMin)/vDiv) < vmax_ln/2) vDiv /= 2; vsMinT = vsMin; vsMaxT = vsMax; } else { //Individual scale process TrendObj &cP = shD->prms[prmsInd[iP]]; // Draw environment vsPercT = false; isLogT = cP.mScale&FD_LOG; sclVerT = cP.wScale; grdPenT.setColor(cP.color()); mrkPen.setColor(cP.color()); // Rounding double v_len = cP.adjU - cP.adjL; while(v_len > vmax_ln) { vDiv *= 10; v_len /= 10; } while(v_len && v_len < vmax_ln/10) { vDiv /= 10; v_len *= 10; } if(!isScale) { cP.adjL = floor(cP.adjL/vDiv)*vDiv; cP.adjU = ceil(cP.adjU/vDiv)*vDiv; } while(!isLogT && ((cP.adjU-cP.adjL)/vDiv) < vmax_ln/2) vDiv /= 2; vsMinT = cP.adjL; vsMaxT = cP.adjU; } if(iP < (prmsInd.size()-1)) sclVerT &= ~(FD_GRD); //Hide grid for no last scale //Draw vertical grid and markers int markWdth = 0; if(sclVerT&FD_GRD_MARKS) { string labVal; pnt.setPen(grdPenT); pnt.drawLine(tAr.x()-1, tAr.y(), tAr.x()-1, tAr.height()); for(double iV = ceil(vsMinT/vDiv)*vDiv; (vsMaxT-iV)/vDiv > -0.1; iV += vDiv) { int v_pos = tAr.y()+tAr.height()-(int)((double)tAr.height()*(iV-vsMinT)/(vsMaxT-vsMinT)); if(sclVerT&FD_GRD) { pnt.setPen(grdPen); pnt.drawLine(tAr.x(), v_pos, tAr.x()+tAr.width(), v_pos); } else { pnt.setPen(grdPenT); pnt.drawLine(tAr.x()-3, v_pos, tAr.x()+3, v_pos); } if(sclVerT&FD_MARKS) { bool isPerc = vsPercT && ((vsMaxT-iV-vDiv)/vDiv <= -0.1); bool isMax = (v_pos-1-mrkHeight) < tAr.y(); pnt.setPen(mrkPen); labVal = TSYS::strMess("%0.5g",(isLogT?pow(10,iV):iV)) + (isPerc?" %":""); pnt.drawText(tAr.x()+2, v_pos-1+(isMax?mrkHeight:0), labVal.c_str()); markWdth = vmax(markWdth, pnt.fontMetrics().size(Qt::TextSingleLine, labVal.c_str()).width()); } } } if(iP < (prmsInd.size()-1)) tAr.adjust((markWdth?(markWdth+5):0), 0, 0, 0); } mrkPen.setColor(shD->sclMarkColor); //Restore mark color //Calc and draw the horizontal scale int64_t hDiv = 1; //Horisontal scale divisor int hmax_ln = tAr.width() / (int)((sclHor&FD_MARKS)?mrkWidth:15*vmin(w->xScale(true),w->yScale(true))); if(hmax_ln >= 2) { int hvLev = 0; int64_t hLen = tEnd - tBeg; if(hLen/2635200000000ll >= 5) { hvLev = 7; hDiv = 2635200000000ll; } //Month a unstrict interval else if(hLen/86400000000ll >= 5){ hvLev = 6; hDiv = 86400000000ll; } //More days and no time in the scale else if(hLen/86400000000ll >= 2){ hvLev = 5; hDiv = 86400000000ll; } //Days else if(hLen/3600000000ll >= 2) { hvLev = 4; hDiv = 3600000000ll; } //Hours else if(hLen/60000000 >= 2) { hvLev = 3; hDiv = 60000000ll; } //Minutes else if(hLen/1000000 >= 2) { hvLev = 2; hDiv = 1000000ll; } //Seconds else if(hLen/1000 >= 2) { hvLev = 1; hDiv = 1000ll; } //Milliseconds int64_t hDiv_ = hDiv; while(hLen/hDiv_ > hmax_ln) hDiv_ *= 10; while(hLen/hDiv_ < hmax_ln/5 && (hDiv_/5)%hDiv == 0) hDiv_ /= 5; while(hLen/hDiv_ < hmax_ln/2 && (hvLev < 6 || (hDiv_/2)%hDiv == 0)) hDiv_ /= 2; hDiv = hDiv_; if(shD->sclHorPer > 0 && (hLen/shD->sclHorPer) > 2 && (tAr.width()/(hLen/shD->sclHorPer)) > 15) hDiv = shD->sclHorPer; int64_t UTChourDt = 1000000ll*TSYS::str2atime(TSYS::atime2str(tEnd/1000000),"",true) - tEnd; if((hLen/hDiv) >= 5 && shD->trcPer) { tPict = hDiv*(tEnd/hDiv+1); if((tPict-tEnd) > llabs(UTChourDt)) tPict -= UTChourDt; tBeg = tPict-hLen; } // Draw horisontal grid and markers if(sclHor&FD_GRD_MARKS) { time_t tm_t = 0; struct tm ttm, ttm1 = ttm; string lab_tm, lab_dt; // Draw generic grid line pnt.setPen(grdPen); pnt.drawLine(tAr.x(), tAr.y()+tAr.height(), tAr.x()+tAr.width(), tAr.y()+tAr.height()); // Draw full trend's data and time to the trend end position int begMarkBrd = -5; int endMarkBrd = tAr.x()+tAr.width(); if(sclHor&FD_MARKS) { pnt.setPen(mrkPen); tm_t = tPict/1000000; localtime_r(&tm_t, &ttm); lab_dt = TSYS::strMess("%d-%02d-%d", ttm.tm_mday, ttm.tm_mon+1, ttm.tm_year+1900); if(ttm.tm_sec == 0 && tPict%1000000 == 0) lab_tm = TSYS::strMess("%d:%02d", ttm.tm_hour, ttm.tm_min); else if(tPict%1000000 == 0) lab_tm = TSYS::strMess("%d:%02d:%02d", ttm.tm_hour, ttm.tm_min, ttm.tm_sec); else lab_tm = TSYS::strMess("%d:%02d:%g", ttm.tm_hour, ttm.tm_min, (float)ttm.tm_sec+(float)(tPict%1000000)/1e6); int markBrd = 0, markY = tAr.y()+tAr.height()+mrkHeight; if(hvLev < 6) { markBrd = tAr.x() + tAr.width() - pnt.fontMetrics().size(Qt::TextSingleLine, lab_tm.c_str()).width(); endMarkBrd = vmin(endMarkBrd, markBrd); pnt.drawText(markBrd, markY, lab_tm.c_str()); markY += mrkHeight; } markBrd = tAr.x() + tAr.width() - pnt.fontMetrics().size(Qt::TextSingleLine, lab_dt.c_str()).width(); endMarkBrd = vmin(endMarkBrd, markBrd); pnt.drawText(markBrd, markY, lab_dt.c_str()); } // Drawing the grid and/or markers bool first_m = true; for(int64_t iH = tBeg; true; ) { // Drawing the grid pnt.setPen(grdPen); int h_pos = tAr.x()+tAr.width()*(iH-tBeg)/(tPict-tBeg); if(sclHor&FD_GRD) pnt.drawLine(h_pos, tAr.y(), h_pos, tAr.y()+tAr.height()); else pnt.drawLine(h_pos, tAr.y()+tAr.height()-3, h_pos, tAr.y()+tAr.height()+3); if(sclHor&FD_MARKS && (!((iH+UTChourDt)%hDiv) || hvLev >= 7) && iH != tPict) { if(first_m) tm_t = (tBeg-(tEnd-tBeg))/1000000, localtime_r(&tm_t, &ttm1); tm_t = iH/1000000; localtime_r(&tm_t, &ttm); int chLev = 0; if(ttm.tm_year-ttm1.tm_year) chLev = 6; else if(ttm.tm_mon-ttm1.tm_mon) chLev = 5; else if(ttm.tm_mday-ttm1.tm_mday) chLev = 4; else if(ttm.tm_hour-ttm1.tm_hour) chLev = 3; else if(ttm.tm_min-ttm1.tm_min) chLev = 2; else if(ttm.tm_sec-ttm1.tm_sec) chLev = 1; //Check for data present lab_dt.clear(), lab_tm.clear(); //Date if(hvLev == 7) lab_dt = TSYS::atime2str(iH/1000000, (chLev>=6)?"%B %Y":"%B", false, runW?((VisRun*)runW->mainWin())->user()+"\n"+((VisRun*)runW->mainWin())->lang():""); else if(/*hvLev == 5 ||*/ chLev >= 4) lab_dt = TSYS::strMess((chLev>=5?"%d-%02d-%d":"%d"), ttm.tm_mday, ttm.tm_mon+1, ttm.tm_year+1900); //Hours and minuts if((hvLev == 4 || hvLev == 3 || ttm.tm_hour || ttm.tm_min) && !ttm.tm_sec) lab_tm = TSYS::strMess("%d:%02d",ttm.tm_hour,ttm.tm_min); //Seconds else if((hvLev == 2 || ttm.tm_sec) && !(iH%1000000)) lab_tm = chLev >= 2 ? TSYS::strMess("%d:%02d:%02d",ttm.tm_hour,ttm.tm_min,ttm.tm_sec) : TSYS::strMess(_("%ds"),ttm.tm_sec); //Milliseconds else if(hvLev <= 1 || iH%1000000) lab_tm = chLev >= 2 ? TSYS::strMess("%d:%02d:%g",ttm.tm_hour,ttm.tm_min,(float)ttm.tm_sec+(float)(iH%1000000)/1e6) : chLev >= 1 ? TSYS::strMess(_("%gs"),(float)ttm.tm_sec+(float)(iH%1000000)/1e6) : TSYS::strMess(_("%gms"),(double)(iH%1000000)/1000.); int wdth, tpos, endPosTm = 0, endPosDt = 0, markY = tAr.y()+tAr.height()+mrkHeight; pnt.setPen(mrkPen); if(hvLev < 6) { if(lab_tm.size()) { wdth = pnt.fontMetrics().size(Qt::TextSingleLine, lab_tm.c_str()).width(); tpos = vmax(h_pos-wdth/2,0); if(first_m || ((tpos+wdth) < (endMarkBrd-3) && tpos > (begMarkBrd+3))) { if(first_m) tpos = vmax(begMarkBrd, tpos); pnt.drawText(tpos, markY, lab_tm.c_str()); endPosTm = tpos+wdth; } } markY += mrkHeight; } if(lab_dt.size()) { wdth = pnt.fontMetrics().size(Qt::TextSingleLine, lab_dt.c_str()).width(); tpos = vmax(h_pos-wdth/2, 0); if(first_m || ((tpos+wdth) < (endMarkBrd-3) && tpos > (begMarkBrd+3))) { if(first_m) tpos = vmax(begMarkBrd, tpos); pnt.drawText(tpos, markY, lab_dt.c_str()); endPosDt = tpos+wdth; } } begMarkBrd = vmax(begMarkBrd, vmax(endPosTm,endPosDt)); memcpy((char*)&ttm1, (char*)&ttm, sizeof(tm)); first_m = false; } // Next if(iH >= tPict) break; if(hvLev >= 7) { //Per month tm_t = iH/1000000; localtime_r(&tm_t, &ttm); ttm.tm_sec = ttm.tm_min = ttm.tm_hour = 0; ttm.tm_mday = 1; ttm.tm_mon++; ttm.tm_wday = ttm.tm_yday = ttm.tm_isdst = -1; iH = 1000000ll * mktime(&ttm); } else iH = ((iH+UTChourDt)/hDiv)*hDiv + hDiv - UTChourDt; iH = vmin(tPict, iH); } } } //Draw trends for(unsigned iT = 0; iT < shD->prms.size(); iT++) { TrendObj &cP = shD->prms[iT]; // Set trend's pen QPen trpen(cP.color()); trpen.setStyle(Qt::SolidLine); trpen.setWidth(vmax(1,vmin(10,(int)rRnd(cP.width()*vmin(w->xScale(true),w->yScale(true)))))); //#if QT_VERSION < 0x050000 // if(cP.valTp() != 0 && trpen.width() > 1) trpen.setCapStyle(Qt::RoundCap); //#else trpen.setCapStyle((cP.valTp() != 0 && trpen.width() > 1)?Qt::RoundCap:Qt::FlatCap); //#endif pnt.setRenderHint(QPainter::Antialiasing, (trpen.width()>=2)); pnt.setPen(trpen); // Prepare generic parameters aVbeg = vmax(tBeg, cP.valBeg()); aVend = vmin(tEnd, cP.valEnd()); if(aVbeg >= aVend || !cP.color().isValid()) continue; int aPosBeg = cP.val(aVbeg); if(aPosBeg && cP.val()[aPosBeg].tm > aVbeg) aPosBeg--; bool vsPercT = cP.isIndiv ? false : vsPerc; bool isLogT = cP.isIndiv ? (cP.wScale&FD_LOG) : isLog; double vsMaxT = cP.isIndiv ? cP.adjU : vsMax; double vsMinT = cP.isIndiv ? cP.adjL : vsMin; // Prepare border for percent trend, ONLY! float bordL = cP.bordL(); float bordU = cP.bordU(); if(vsPercT && bordL >= bordU) { bordU = cP.adjU; bordL = cP.adjL; } /*bordU = -3e300, bordL = 3e300; bool end_vl = false; int ipos = aPosBeg; while(true) { if(ipos >= (int)cP.val().size() || end_vl) break; if(cP.val()[ipos].tm >= aVend) end_vl = true; if(cP.val()[ipos].val != EVAL_REAL) { bordL = vmin(bordL, cP.val()[ipos].val); bordU = vmax(bordU, cP.val()[ipos].val); } ipos++; } float vMarg = (bordU-bordL)/10; bordL -= vMarg; bordU += vMarg; }*/ // Draw trend bool end_vl = false; double curVl = EVAL_REAL, averVl = EVAL_REAL, prevVl = EVAL_REAL; int curPos, averPos = 0, prevPos = 0, c_vpos, z_vpos = 0; int64_t curTm = 0, averTm = 0, averLstTm = 0; for(int a_pos = aPosBeg; true; a_pos++) { if(a_pos < (int)cP.val().size() && !end_vl) { curTm = vmin(aVend,vmax(aVbeg,cP.val()[a_pos].tm)); curVl = cP.val()[a_pos].val; if(vsPercT && curVl != EVAL_REAL) curVl = 100*(curVl-bordL)/(bordU-bordL); if(isnan(curVl)) curVl = EVAL_REAL; curPos = tAr.x()+tAr.width()*(curTm-tBeg)/(tPict-tBeg); } else curPos = 0; if(!curPos || cP.val()[a_pos].tm >= aVend) end_vl = true; //Square Average if(averPos == curPos) { if(!(2*curTm-averTm-averLstTm)) continue; if(averVl == EVAL_REAL) averVl = curVl; else if(curVl != EVAL_REAL) averVl = (averVl*(double)(curTm-averTm)+curVl*(double)(curTm-averLstTm))/((double)(2*curTm-averTm-averLstTm)); averLstTm = curTm; continue; } //Writing a point and a line if(averVl != EVAL_REAL) { if(cP.valTp() == 0) z_vpos = tAr.y()+tAr.height()-(int)((double)tAr.height()*vmax(0,vmin(1,((vsPercT?(100.*(0-bordL)/(bordU-bordL)):0)-vsMinT)/(vsMaxT-vsMinT)))); c_vpos = tAr.y()+tAr.height()-(int)((double)tAr.height()*vmax(0,vmin(1,((isLogT?log10(vmax(1e-100,averVl)):averVl)-vsMinT)/(vsMaxT-vsMinT)))); if(prevVl == EVAL_REAL) { if(cP.valTp() != 0) pnt.drawPoint(averPos, c_vpos); else pnt.drawLine(averPos, z_vpos, averPos, vmin(z_vpos-trpen.width(),c_vpos)); } else { if(cP.valTp() != 0) { int c_vpos_prv = tAr.y()+tAr.height()-(int)((double)tAr.height()*vmax(0,vmin(1,((isLogT?log10(vmax(1e-100,prevVl)):prevVl)-vsMinT)/(vsMaxT-vsMinT)))); pnt.drawLine(prevPos, c_vpos_prv, averPos, c_vpos); } else for(int sps = prevPos+1; sps <= averPos; sps++) pnt.drawLine(sps, z_vpos, sps, vmin(z_vpos-trpen.width(),c_vpos)); } } prevVl = averVl; prevPos = averPos; averVl = curVl; averPos = curPos; averTm = averLstTm = curTm; if(!curPos) break; } } shD->pictRect = tAr; shD->tPict = tPict; if(mess_lev() == TMess::Debug) mess_debug(mod->nodePath().c_str(), _("Time of building the trend: %f ms."), 1e-3*(TSYS::curTime()-d_cnt)); } void ShapeDiagram::tracing( ) { WdgView *w = (WdgView*)((QTimer*)sender())->parent(); RunWdgView *runW = qobject_cast(((QTimer*)sender())->parent()); if(runW && runW->mainWin()->f_winClose) return; ShpDt *shD = (ShpDt*)w->shpData; if(!w->isEnabled()) return; int64_t trcPer = shD->trcPer*1e6; if(shD->tTimeCurent)shD->tTime = (int64_t)time(NULL)*1000000; else if(shD->tTime) shD->tTime += trcPer; loadData(w); makePicture(w); //Trace cursors value if(shD->tTimeCurent) shD->tTime = shD->arhEnd(shD->tTime); //Force for cursor limit to the real data if(shD->type == 0 && shD->active && (shD->holdCur || shD->curTime <= (shD->tPict-(int64_t)(1e6*shD->tSize)))) setCursor(w, shD->tTime); w->update(); } bool ShapeDiagram::event( WdgView *w, QEvent *event ) { int64_t d_cnt = 0; ShpDt *shD = (ShpDt*)w->shpData; if(!shD->en) return false; //Process event switch(event->type()) { case QEvent::Paint: { if(mess_lev() == TMess::Debug) d_cnt = TSYS::curTime(); QPainter pnt(w); // Draw decoration QRect dA = w->rect().adjusted(0, 0, -2*shD->geomMargin, -2*shD->geomMargin); pnt.setWindow(dA); pnt.setViewport(w->rect().adjusted(shD->geomMargin,shD->geomMargin,-shD->geomMargin,-shD->geomMargin)); if(shD->backGrnd.color().isValid()) pnt.fillRect(dA,shD->backGrnd.color()); if(!shD->backGrnd.textureImage().isNull()) pnt.fillRect(dA,shD->backGrnd.textureImage()); // Draw border borderDraw(pnt, dA, shD->border, shD->bordStyle); // Trend's picture pnt.drawImage(shD->border.width(), shD->border.width(), shD->pictObj); // Draw focused border if(w->hasFocus()) qDrawShadeRect(&pnt,dA.x(),dA.y(),dA.width(),dA.height(),w->palette()); // Draw cursor int curPos = -1; if(shD->type == FD_TRND && shD->active) { int64_t tTimeGrnd = shD->tPict - (int64_t)(1e6*shD->tSize); int64_t curTime = vmax(vmin(shD->curTime,shD->tPict), tTimeGrnd); if(curTime && tTimeGrnd && shD->tPict && (curTime >= tTimeGrnd || curTime <= shD->tPict)) curPos = shD->pictRect.x() + shD->pictRect.width()*(curTime-tTimeGrnd)/(shD->tPict-tTimeGrnd); } else if(shD->type == FD_SPECTR && shD->active) { float curFrq = vmax(vmin(1e6/(float)shD->curTime,shD->fftEnd),shD->fftBeg); curPos = shD->pictRect.x() + (int)(shD->pictRect.width()*(curFrq-shD->fftBeg)/(shD->fftEnd-shD->fftBeg)); } if(curPos >= 0 && (curPos-shD->pictRect.x()) <= shD->pictRect.width()) { QPen curpen(shD->curColor); curpen.setWidth(1); pnt.setPen(curpen); pnt.drawLine(curPos, shD->pictRect.y(), curPos,shD->pictRect.y()+shD->pictRect.height()); } // Draw selection window if(shD->sclWin && shD->fMoveHold && shD->type == FD_TRND && shD->active) { pnt.setPen("white"); pnt.drawRect(QRect(shD->startPnt,shD->holdPnt)); QPen pen(QColor("black")); pen.setStyle(Qt::DashLine); pnt.setPen(pen); pnt.drawRect(QRect(shD->startPnt,shD->holdPnt)); } if(mess_lev() == TMess::Debug) mess_debug(mod->nodePath().c_str(), _("Time of drawing the trend: %f ms."), 1e-3*(TSYS::curTime()-d_cnt)); return true; } case QEvent::KeyPress: { QKeyEvent *key = static_cast(event); switch(key->key()) { case Qt::Key_Left: case Qt::Key_Right: if(!shD->active) break; if(shD->type == 0) { int64_t tTimeGrnd = shD->tPict - (int64_t)(1e6*shD->tSize); int64_t curTime = vmax(vmin(shD->curTime,shD->tPict),tTimeGrnd); setCursor(w, curTime+((key->key()==Qt::Key_Left)?-1:1)*(shD->tTime-tTimeGrnd)/shD->pictRect.width()); } else if(shD->type == 1) { float curFrq = vmax(vmin(1e6/(float)shD->curTime,shD->fftEnd),shD->fftBeg); setCursor(w, (int64_t)(1e6/(curFrq+((key->key()==Qt::Key_Left)?-1:1)*(shD->fftEnd-shD->fftBeg)/shD->pictRect.width()))); } w->update(); return true; } break; } case QEvent::MouseButtonPress: { if(!shD->active || !w->hasFocus()) break; QPoint curp = w->mapFromGlobal(w->cursor().pos()); if(curp.x() < shD->pictRect.x() || curp.x() > (shD->pictRect.x()+shD->pictRect.width())) break; //Hold processing if((static_cast(event))->buttons()&Qt::LeftButton && shD->type == FD_TRND) shD->holdPnt = shD->startPnt = curp; break; } case QEvent::MouseButtonRelease: if(shD->fMoveHold) { shD->fMoveHold = false; w->setCursor(Qt::ArrowCursor); AttrValS attrs; if(shD->sclWin) { //Calcullate the time scale int64_t tTimeGrnd = shD->tPict - (int64_t)(1e6*shD->tSize); int64_t tP1 = tTimeGrnd + (shD->tPict-tTimeGrnd)*(shD->startPnt.x()-shD->pictRect.x())/shD->pictRect.width(); int64_t tP2 = tTimeGrnd + (shD->tPict-tTimeGrnd)*(shD->holdPnt.x()-shD->pictRect.x())/shD->pictRect.width(); tTimeGrnd = vmin(tP1, tP2); tP1 = vmax(tP1, tP2); attrs.push_back(std::make_pair("tSek",i2s(tP1/1000000))); attrs.push_back(std::make_pair("tUSek",i2s(tP1%1000000))); attrs.push_back(std::make_pair("tSize",r2s(1e-6*(tP1-tTimeGrnd)))); attrs.push_back(std::make_pair("trcPer","0")); //Calculate the vertical scale float vScl = fabs(shD->startPnt.y()-shD->holdPnt.y())/shD->pictRect.height(); float vOff = ((float)vmin(shD->startPnt.y(),shD->holdPnt.y())/shD->pictRect.height() + vScl/2 - 0.5)*shD->sclVerScl; attrs.push_back(std::make_pair("sclVerScl",r2s(shD->sclVerScl*vScl))); attrs.push_back(std::make_pair("sclVerSclOff",r2s(shD->sclVerSclOff-vOff))); w->attrsSet(attrs); } else if(shD->fMoveTmCh) { attrs.push_back(std::make_pair("tSek",i2s(shD->tTime/1000000))); attrs.push_back(std::make_pair("tUSek",i2s(shD->tTime%1000000))); attrs.push_back(std::make_pair("trcPer","0")); w->attrsSet(attrs); } } else { //Cursor set QPoint curp = w->mapFromGlobal(w->cursor().pos()); if(curp.x() < shD->pictRect.x() || curp.x() > (shD->pictRect.x()+shD->pictRect.width())) break; switch(shD->type) { case FD_TRND: { int64_t tTimeGrnd = shD->tPict - (int64_t)(1e6*shD->tSize); setCursor(w, tTimeGrnd + (shD->tPict-tTimeGrnd)*(curp.x()-shD->pictRect.x())/shD->pictRect.width()); break; } case FD_SPECTR: setCursor(w, (int64_t)(1e6/(shD->fftBeg+(shD->fftEnd-shD->fftBeg)*(curp.x()-shD->pictRect.x())/shD->pictRect.width()))); break; default: break; } w->update(); } break; case QEvent::MouseMove: { if(shD->type != FD_TRND) break; QMouseEvent *mev = (QMouseEvent*)event; QPoint dP = mev->pos() - shD->holdPnt; if(shD->fMoveHold || ((mev->buttons()&Qt::LeftButton) && dP.manhattanLength() >= QApplication::startDragDistance())) { if(!shD->fMoveHold) { w->setCursor(shD->sclWin?Qt::CrossCursor:Qt::ClosedHandCursor); shD->fMoveTmCh = false; } shD->fMoveHold = true; shD->holdPnt = mev->pos(); if(shD->sclWin) w->update(); else if(dP.x() > 0 || (dP.x() < 0 && !shD->tTimeCurent)) { if(shD->trcPer) w->attrSet("trcPer", "0", A_DiagramTrcPer); shD->tTimeCurent = false; int64_t toTm = vmax(0, vmin((int64_t)time(NULL)*1000000,shD->tTime-((int64_t)(1e6*shD->tSize)/shD->pictRect.width())*dP.x())); if(toTm != shD->tTime) { shD->tTime = toTm; shD->fMoveTmCh = true; //Load by parameters after moving drop. makePicture(w); w->update(); } } } if(shD->fMoveHold && !(((QMouseEvent*)event)->buttons()&Qt::LeftButton)) { shD->fMoveHold = false; w->setCursor(Qt::ArrowCursor); } } default: break; } return false; } void ShapeDiagram::setCursor( WdgView *w, int64_t itm ) { ShpDt *shD = (ShpDt*)w->shpData; if(shD->type == FD_TRND) { int64_t tTimeGrnd = shD->tTime - (int64_t)(1e6*shD->tSize); int64_t curTime = vmax(vmin(itm,shD->tTime), tTimeGrnd); shD->curTime = curTime; shD->holdCur = (curTime >= (shD->tTime-(shD->pictRect.width()?(int64_t)(3*1e6*shD->tSize)/shD->pictRect.width():0))); //No more 3 pixels //(curTime==shD->tTime); XMLNode req("set"); req.setAttr("path",w->id()+"/%2fserv%2fattr")->setAttr("noUser", "1")->setAttr("reforwardRedundOff", "1"); req.childAdd("el")->setAttr("id","curSek")->setText(i2s(curTime/1000000)); req.childAdd("el")->setAttr("id","curUSek")->setText(i2s(curTime%1000000)); //Update trend's current values for(unsigned iP = 0; iP < shD->prms.size(); iP++) { int vpos = shD->prms[iP].val(curTime); double val = EVAL_REAL; if(shD->prms[iP].val().size() && curTime >= shD->prms[iP].valBeg() && (shD->holdCur || vpos < (int)shD->prms[iP].val().size())) { vpos = vmax(0,vmin((int)shD->prms[iP].val().size()-1,vpos)); if(vpos && shD->prms[iP].val()[vpos].tm > curTime) vpos--; val = shD->prms[iP].val()[vpos].val; } if(val != shD->prms[iP].curVal()) { req.childAdd("el")->setAttr("id",TSYS::strMess("prm%dval",iP))->setText(r2s(val)); shD->prms[iP].setCurVal(val); } } w->cntrIfCmd(req); } else if(shD->type == FD_SPECTR) { float curFrq = vmax(vmin(1e6/(float)itm,shD->fftEnd),shD->fftBeg); shD->curTime = 1e6/curFrq; XMLNode req("set"); req.setAttr("path",w->id()+"/%2fserv%2fattr")->setAttr("noUser", "1")->setAttr("reforwardRedundOff", "1"); req.childAdd("el")->setAttr("id","curSek")->setText(i2s(shD->curTime/1000000)); req.childAdd("el")->setAttr("id","curUSek")->setText(i2s(shD->curTime%1000000)); #if HAVE_FFTW3_H //Update trend's current values for(unsigned iP = 0; iP < shD->prms.size(); iP++) { if(!shD->prms[iP].fftN) continue; float fftDt = (1/shD->tSize)*(float)w->size().width()/shD->prms[iP].fftN; int vpos = (int)(curFrq/fftDt); double val = EVAL_REAL; if(vpos >= 1 && vpos < (shD->prms[iP].fftN/2+1)) val = shD->prms[iP].fftOut[0][0]/shD->prms[iP].fftN + pow(pow(shD->prms[iP].fftOut[vpos][0],2)+pow(shD->prms[iP].fftOut[vpos][1],2),0.5)/(shD->prms[iP].fftN/2+1); req.childAdd("el")->setAttr("id",TSYS::strMess("prm%dval",iP))->setText(r2s(val)); shD->prms[iP].setCurVal(val); } #endif w->cntrIfCmd(req); } } //* Trend object's class * //************************************************ ShapeDiagram::TrendObj::TrendObj( WdgView *iview ) : adjL(3e300), adjU(-3e300), isIndiv(false), wScale(0), #if HAVE_FFTW3_H fftN(0), fftOut(NULL), #endif mBordLow(0), mBordUp(0), mCurvl(EVAL_REAL), mWidth(1), mScale(0), arh_per(0), arh_beg(0), arh_end(0), val_tp(0), view(iview) { loadData(); } ShapeDiagram::TrendObj::~TrendObj( ) { #if HAVE_FFTW3_H if(fftOut) { free(fftOut); fftN = 0; } #endif } int64_t ShapeDiagram::TrendObj::valBeg( ) { return vals.empty() ? 0 : vals.front().tm; } int64_t ShapeDiagram::TrendObj::valEnd( ) { return vals.empty() ? 0 : vals.back().tm; } int ShapeDiagram::TrendObj::val( int64_t tm ) { unsigned iP = 0; for(unsigned d_win = vals.size()/2; d_win > 10; d_win/=2) if(tm > vals[iP+d_win].tm) iP += d_win; for( ; iP < vals.size(); iP++) if(vals[iP].tm >= tm) return iP; return vals.size(); } void ShapeDiagram::TrendObj::setAddr( const string &vl ) { if(vl == mAddr) return; mAddr = vl; loadData(true); } void ShapeDiagram::TrendObj::loadData( bool full ) { ShpDt *shD = (ShpDt*)view->shpData; switch(shD->type) { case FD_TRND: case FD_XY: loadTrendsData(full); break; case FD_SPECTR: loadSpectrumData(full); break; } } void ShapeDiagram::TrendObj::loadTrendsData( bool full ) { ShpDt *shD = (ShpDt*)view->shpData; int64_t tSize = (int64_t)(1e6*shD->tSize); int64_t tTime = shD->tTime; int64_t tTimeGrnd = tTime - tSize; int64_t wantPer = tSize/(view->size().width()*shD->valsForPix); unsigned bufLim = 2*view->size().width()*shD->valsForPix; XMLNode req("get"); //Clear trend for empty address and for full reload data if(full || addr().empty()) { arh_per = arh_beg = arh_end = 0; val_tp = TFld::Boolean; vals.clear(); if(addr().empty()) return; } bool isDataDir = (addr().compare(0,5,"data:") == 0 || addr().compare(0,5,"line:") == 0); if(!isDataDir) { //From archive by address // Get archive parameters if(!arh_per || tTime > arh_end || shD->tTimeCurent) { XMLNode req("info"); req.setAttr("arch",shD->valArch)->setAttr("path",addr()+"/%2fserv%2fval"); if(view->cntrIfCmd(req,true) || (val_tp=s2i(req.attr("vtp"))) == TFld::String || val_tp == TFld::Object) { arh_per = arh_beg = arh_end = 0; return; } else { val_tp = s2i(req.attr("vtp")); arh_beg = s2ll(req.attr("beg")); arh_end = s2ll(req.attr("end")); arh_per = s2ll(req.attr("per")); // Correct to the real data if(shD->tTimeCurent) tTimeGrnd = (tTime=shD->arhEnd(tTime)) - tSize; } } // One request check and prepare int trcPer = shD->trcPer*1e6; if(shD->tTimeCurent && trcPer && shD->valArch.empty() && (!arh_per || (vmax(arh_per,wantPer) >= trcPer && (tTime-valEnd()) < 2*arh_per /*(tTime-valEnd())/vmax(arh_per,vmax(wantPer,trcPer)) < 2*/))) //!!!! Causes to uneven call for current and archive { XMLNode req("get"); req.setAttr("path", addr()+"/%2fserv%2fval")-> setAttr("tm", ll2s(tTime))-> setAttr("tm_grnd", "0"); if(view->cntrIfCmd(req,true)) return; int64_t lstTm = (s2ll(req.attr("tm"))/wantPer)*wantPer, valEnd_ = (valEnd()/wantPer)*wantPer; if(lstTm && lstTm >= valEnd_) { double curVal = (req.text() == EVAL_STR) ? EVAL_REAL : s2r(req.text()); if((val_tp == TFld::Boolean && curVal == EVAL_BOOL) || (val_tp == TFld::Integer && (int64_t)curVal == EVAL_INT) || isinf(curVal)) curVal = EVAL_REAL; /*if(valEnd_ && (lstTm-valEnd_)/vmax(wantPer,trcPer) > 2) vals.push_back(SHg(lstTm-trcPer,EVAL_REAL)); //!!!! Can cause to flaws on slow remote channels else*/ if((lstTm-valEnd_) >= wantPer) vals.push_back(SHg(lstTm,curVal)); else if((lstTm == valEnd_ && curVal != EVAL_REAL) || vals[vals.size()-1].val == EVAL_REAL) vals[vals.size()-1].val = curVal; else if(curVal != EVAL_REAL) { int s_k = lstTm-wantPer*(lstTm/wantPer), n_k = trcPer; vals[vals.size()-1].val = (vals[vals.size()-1].val*s_k+curVal*n_k)/(s_k+n_k); } while(vals.size() > bufLim) vals.pop_front(); } return; } } else //Data direct in the address field by searilised XML string or horizontal line try { if(addr().compare(0,5,"data:") == 0) { req.load(addr().substr(5)); bool inSec = s2i(req.attr("s")); arh_beg = s2ll(req.attr("tm_grnd")) * (inSec?1000000ll:1ll); if(!arh_beg) arh_beg = tTimeGrnd; req.setAttr("tm_grnd", ll2s(arh_beg)); arh_end = s2ll(req.attr("tm")) * (inSec?1000000ll:1ll); if(!arh_end) arh_end = tTime; req.setAttr("tm", ll2s(arh_end)); arh_per = s2ll(req.attr("per")) * (inSec?1000000ll:1ll); req.setAttr("per", ll2s(arh_per)); } else if(addr().compare(0,5,"line:") == 0) req.setAttr("vtp", i2s(TFld::Real))-> setAttr("tm", ll2s(tTime))-> setAttr("tm_grnd", ll2s(tTimeGrnd))-> setAttr("per", ll2s(wantPer))-> setText("0 "+addr().substr(5)); val_tp = req.attr("vtp").size() ? s2i(req.attr("vtp")) : TFld::Real; arh_beg = s2ll(req.attr("tm_grnd")); arh_end = s2ll(req.attr("tm")); arh_per = s2ll(req.attr("per")); } catch(TError&) { arh_per = arh_beg = arh_end = 0; return; } if(!arh_per) return; //Correct request to archive border wantPer = (vmax(wantPer,arh_per)/arh_per)*arh_per; tTime = vmin(tTime, arh_end); tTimeGrnd = vmax(tTimeGrnd, arh_beg); //For prevent possible cycling //Clear data at time error if(tTime <= tTimeGrnd || tTimeGrnd/wantPer > valEnd()/wantPer || tTime/wantPer < valBeg()/wantPer) vals.clear(); if(tTime <= tTimeGrnd) return; //Check for request to present in buffer data if(tTime/wantPer <= valEnd()/wantPer && tTimeGrnd/wantPer >= valBeg()/wantPer) return; //Correcting request to the presented data if(valEnd() && tTime > valEnd()) tTimeGrnd = valEnd()+wantPer;//1; else if(valBeg() && tTimeGrnd < valBeg()) tTime = valBeg()-wantPer;//1; //Get values data int64_t bbeg, bend, bper, bbeg_prev = tTime; int curPos, prevPos, maxPos; double curVal = EVAL_REAL, prevVal; string svl, curValS; vector buf; bool toEnd = (tTimeGrnd >= valEnd()); int endBlks = 0; m1: if(!isDataDir) { req.clear()-> setAttr("arch", shD->valArch)-> setAttr("path", addr()+"/%2fserv%2fval")-> setAttr("tm", ll2s(tTime))-> setAttr("tm_grnd", ll2s(tTimeGrnd))-> setAttr("per", ll2s(wantPer))-> setAttr("mode", "1")-> //setAttr("real_prec", "6")-> setAttr("round_perc", "0");//r2s(100/(float)view->size().height())); if(view->cntrIfCmd(req,true)) return; } //Get data buffer parameters bbeg = s2ll(req.attr("tm_grnd")); bend = s2ll(req.attr("tm")); bper = s2ll(req.attr("per")); bool toAprox = s2i(req.attr("aprox")); if(bbeg <= 0 || bend <= 0 || bper <= 0 || bbeg > bend || req.text().empty()) return; prevPos = 0, prevVal = EVAL_REAL, maxPos = (bend-bbeg)/bper; buf.clear(); for(int v_off = 0, var_off = 0; true; ) { if((svl=TSYS::strLine(req.text(),0,&v_off)).size()) { var_off = 0; curPos = s2i(TSYS::strParse(svl,0," ",&var_off,true)); curVal = s2r((curValS=TSYS::strParse(svl,0," ",&var_off,true))); if(curValS == EVAL_STR || (val_tp == TFld::Boolean && curVal == EVAL_BOOL) || (val_tp == TFld::Integer && (int64_t)curVal == EVAL_INT) || isinf(curVal)) curVal = EVAL_REAL; } else curPos = maxPos+1; if(curPos < 0 || curPos > (maxPos+1)) break; //Exit for out of the range for(int stPos = prevPos; prevPos < curPos; prevPos++) if(toAprox && prevVal != EVAL_REAL && curVal != EVAL_REAL) buf.push_back(SHg(bbeg+prevPos*bper,prevVal+(curVal-prevVal)*(prevPos-stPos)/(curPos-stPos))); else buf.push_back(SHg(bbeg+prevPos*bper,prevVal)); if(prevPos > maxPos) break; //Normal exit prevVal = curVal; } //Append buffer to values deque if(isDataDir) vals.assign(buf.begin(), buf.end()); else if(toEnd) { vals.insert(vals.end()-endBlks, buf.begin(), buf.end()); while(vals.size() > bufLim) vals.pop_front(); endBlks += buf.size(); } else { vals.insert(vals.begin(), buf.begin(), buf.end()); while(vals.size() > bufLim) vals.pop_back(); } //Check for archive jump if(!isDataDir && shD->valArch.empty() && (bbeg-tTimeGrnd)/bper && bper < bbeg_prev) { bbeg_prev = bper; tTime = bbeg-bper; goto m1; } } void ShapeDiagram::TrendObj::loadSpectrumData( bool full ) { ShpDt *shD = (ShpDt*)view->shpData; loadTrendsData(true); if(!valBeg() || !valEnd()) return; #if HAVE_FFTW3_H if(fftOut) { free(fftOut); fftN = 0; } int64_t tSize = (int64_t)(1e6*shD->tSize); int64_t tTime = shD->tTime; int64_t tTimeGrnd = tTime - tSize; if(shD->tTimeCurent) tTimeGrnd = (tTime=shD->arhEnd(tTime)) - tSize; int64_t workPer = tSize/view->size().width(); tTimeGrnd = vmax(tTimeGrnd, valBeg()); tTime = vmin(tTime, valEnd()); if((fftN=vmax(0,(tTime-tTimeGrnd)/workPer)) == 0) return; double fftIn[fftN]; fftOut = (fftw_complex*)malloc(sizeof(fftw_complex)*(fftN/2+1)); int fftFirstPos = -1, fftLstPos = -1; for(unsigned a_pos = val(tTimeGrnd); a_pos < val().size() && val()[a_pos].tm <= tTime; a_pos++) { int fftPos = (val()[a_pos].tm-tTimeGrnd)/workPer; if(fftPos >= fftN) break; if(val()[a_pos].val == EVAL_REAL) continue; if(fftFirstPos < 0) fftFirstPos = fftPos; if(fftLstPos == fftPos) fftIn[fftPos-fftFirstPos] = (fftIn[fftPos-fftFirstPos]+val()[a_pos].val)/2; else fftIn[fftPos-fftFirstPos] = val()[a_pos].val; for( ; fftLstPos >= 0 && (fftLstPos+1) < fftPos; fftLstPos++ ) fftIn[fftLstPos-fftFirstPos+1] = fftIn[fftLstPos-fftFirstPos]; fftLstPos = fftPos; } fftN = fftLstPos-fftFirstPos; if(fftN < 20) { free(fftOut); fftOut = NULL; fftN = 0; return; } fftw_plan p = fftw_plan_dft_r2c_1d( fftN, fftIn, fftOut, FFTW_ESTIMATE ); fftw_execute(p); fftw_destroy_plan(p); #endif } int64_t ShapeDiagram::ShpDt::arhEnd( int64_t def ) { int64_t rez = 0, rez1 = 0; for(vector::iterator iP = prms.begin(); iP != prms.end(); ++iP) { rez = vmax(rez, iP->arhEnd()); rez1 = vmax(rez1, iP->arhEnd()+2*iP->arhPer()); //!!!! To allow for curent values update on the periodicity in minutes and hours. } return (rez && rez1 < def) ? rez : def; } //************************************************ //* Protocol view shape widget * //************************************************ ShapeProtocol::ShapeProtocol( ) : WdgShape("Protocol") { } void ShapeProtocol::init( WdgView *w ) { w->shpData = new ShpDt(); ShpDt *shD = (ShpDt*)w->shpData; //Init main widget QVBoxLayout *lay = new QVBoxLayout(w); shD->addrWdg = new QTableWidget(w); shD->addrWdg->setItemDelegate(new TableDelegate); shD->addrWdg->setSelectionBehavior(QAbstractItemView::SelectRows); //shD->addrWdg->setSortingEnabled(true); eventFilterSet(w, shD->addrWdg, true); w->setFocusProxy(shD->addrWdg); if(qobject_cast(w)) setFocus(w, shD->addrWdg, false, true); lay->addWidget(shD->addrWdg); //Init tracing timer shD->trcTimer = new QTimer(w); connect(shD->trcTimer, SIGNAL(timeout()), this, SLOT(tracing())); //Bckground palette init QPalette plt(shD->addrWdg->palette()); plt.setBrush(QPalette::Window, QPalette().brush(QPalette::Window)); shD->addrWdg->setPalette(plt); } void ShapeProtocol::destroy( WdgView *w ) { ((ShpDt*)w->shpData)->trcTimer->stop(); delete (ShpDt*)w->shpData; } bool ShapeProtocol::attrSet( WdgView *w, int uiPrmPos, const string &val, const string &attr ) { int reld_dt = 0; //Reload data ( 1-reload addons, 2-full reload ) ShpDt *shD = (ShpDt*)w->shpData; switch(uiPrmPos) { case A_COM_LOAD: reld_dt = 2; shD->addrWdg->clear(); shD->addrWdg->setColumnCount(0); shD->addrWdg->setRowCount(0); break; case A_EN: if(!qobject_cast(w)) break; w->setVisible((bool)s2i(val) && ((RunWdgView*)w)->permView()); break; case A_ACTIVE: if(!qobject_cast(w)) break; shD->active = (bool)s2i(val) && ((RunWdgView*)w)->permCntr(); setFocus(w, shD->addrWdg, shD->active); shD->addrWdg->setSelectionMode(shD->active ? QAbstractItemView::SingleSelection : QAbstractItemView::NoSelection); // shD->addrWdg->setEnabled( shD->active && ((RunWdgView*)w)->permCntr() ); break; case A_GEOM_MARGIN: w->layout()->setContentsMargins(s2i(val), s2i(val), s2i(val), s2i(val)); break; case A_BackColor: { QPalette plt(shD->addrWdg->palette()); QBrush brsh = plt.brush(QPalette::Base); brsh.setColor(getColor(val)); if(!brsh.color().isValid()) brsh.setColor(QPalette().brush(QPalette::Base).color()); brsh.setStyle(brsh.textureImage().isNull() ? Qt::SolidPattern : Qt::TexturePattern); plt.setBrush(QPalette::Base, brsh); shD->addrWdg->setPalette(plt); break; } case A_BackImg: { QImage img; QPalette plt(shD->addrWdg->palette()); QBrush brsh = plt.brush(QPalette::Base); string backimg = w->resGet(val); if(!backimg.empty()) img.loadFromData((const uchar*)backimg.data(),backimg.size()); brsh.setTextureImage(img); brsh.setStyle(!brsh.textureImage().isNull() ? Qt::TexturePattern : Qt::SolidPattern); plt.setBrush(QPalette::Base, brsh); shD->addrWdg->setPalette(plt); break; } case A_ProtFont: shD->addrWdg->setFont(getFont(val,vmin(w->xScale(true),w->yScale(true)))); break; case A_ProtHeadVis: shD->addrWdg->horizontalHeader()->setVisible(s2i(val)); shD->addrWdg->verticalHeader()->setVisible(s2i(val)); break; case A_ProtTime: { unsigned int tm = strtoul(val.c_str(), 0, 10); //if(shD->time == tm) break; shD->tTimeCurent = false; if(tm == 0) { shD->time = (unsigned int)time(NULL); shD->tTimeCurent = true; }else shD->time = tm; reld_dt = 1; break; } case A_ProtTSize: if(shD->tSize == strtoul(val.c_str(),0,10)) break; shD->tSize = (unsigned int)strtoul(val.c_str(), 0, 10); reld_dt = 1; break; case A_ProtTrcPer: { int trcPer = vmax(0, s2i(val)); if(shD->trcPer == trcPer) break; shD->trcPer = trcPer; if(trcPer) shD->trcTimer->start(trcPer*1000); else shD->trcTimer->stop(); break; } case A_ProtArch: if(shD->arch != val) { shD->arch = val; reld_dt = 2; } break; case A_ProtTmpl: if(shD->tmpl != val) { shD->tmpl = val; reld_dt = 2; } break; case A_ProtLev: if(shD->lev != s2i(val)) { shD->lev = s2i(val); reld_dt = 2; } break; case A_ProtViewOrd: if(shD->viewOrd != s2i(val)) { shD->viewOrd = s2i(val); reld_dt = 1; } break; case A_ProtCol: if(shD->col != val) { shD->col = val; reld_dt = 1; } break; case A_ProtItProp: { int itNum = s2i(val); if((int)shD->itProps.size() == itNum) break; while((int)shD->itProps.size() < itNum) shD->itProps.push_back(ShpDt::ItProp()); while((int)shD->itProps.size() > itNum) shD->itProps.pop_back(); reld_dt = 1; break; } default: //Item's properties configuration if(uiPrmPos >= A_ProtProps) { int itNum = (uiPrmPos-A_ProtProps)/A_ProtPropsSz; if(itNum >= (int)shD->itProps.size()) break; reld_dt = 1; switch(uiPrmPos%A_ProtPropsSz) { case A_ProtPropLev: shD->itProps[itNum].lev = s2i(val); break; case A_ProtPropTmpl: shD->itProps[itNum].tmpl = val; break; case A_ProtPropFnt: shD->itProps[itNum].font = val.empty() ? shD->addrWdg->font() : getFont(val, vmin(w->xScale(true),w->yScale(true))); break; case A_ProtPropClr: shD->itProps[itNum].clr = getColor(val); break; } } } if(reld_dt && !w->allAttrLoad()) loadData(w, (reld_dt==2)); return true; } void ShapeProtocol::loadData( WdgView *w, bool full ) { ShpDt *shD = (ShpDt*)w->shpData; unsigned int tTime = shD->time, tTimeGrnd = tTime - shD->tSize, arhBeg = shD->arhBeg, arhEnd = shD->arhEnd; bool toUp = false, isDtChang = false, newFill = false, isDbl = false; //Check table structure //Clear columns for(int ncl = 0; ncl < shD->addrWdg->columnCount(); ncl++) if(shD->col.find(shD->addrWdg->horizontalHeaderItem(ncl)->data(Qt::UserRole).toString().toStdString()) == string::npos) { shD->addrWdg->removeColumn(ncl); ncl--; newFill = true; } //Get columns indexes int c_tm = -1, c_tmu = -1, c_lev = -1, c_cat = -1, c_mess = -1; shD->addrWdg->verticalHeader()->setVisible(false); string clm; for(int c_off = 0; (clm=TSYS::strSepParse(shD->col,0,';',&c_off)).size(); ) { string clmNm; int ncl; for(ncl = 0; ncl < shD->addrWdg->columnCount(); ncl++) if(shD->addrWdg->horizontalHeaderItem(ncl)->data(Qt::UserRole).toString() == clm.c_str()) break; if(clm == "pos") shD->addrWdg->verticalHeader()->setVisible(true); else if(clm == "tm") { clmNm = _("Date and time"); c_tm = ncl; } else if(clm == "utm") { clmNm = _("mcsec"); c_tmu = ncl; } else if(clm == "lev") { clmNm = _("Level"); c_lev = ncl; } else if(clm == "cat") { clmNm = _("Category"); c_cat = ncl; } else if(clm == "mess") { clmNm = _("Message"); c_mess = ncl; } if(clmNm.empty() || ncl < shD->addrWdg->columnCount()) continue; ncl = shD->addrWdg->columnCount(); shD->addrWdg->setColumnCount(ncl+1); shD->addrWdg->setHorizontalHeaderItem(ncl, new QTableWidgetItem()); shD->addrWdg->horizontalHeaderItem(ncl)->setText(clmNm.c_str()); shD->addrWdg->horizontalHeaderItem(ncl)->setData(Qt::UserRole, clm.c_str()); shD->addrWdg->horizontalHeaderItem(ncl)->setData(Qt::FontRole, shD->addrWdg->font()); newFill = true; } newFill = newFill || !shD->messList.size(); if(shD->lev < 0) shD->messList.clear(); else { //Clear loaded data if(full) { shD->messList.clear(); arhBeg = arhEnd = 0; } //Get archive parameters if(!arhBeg || !arhEnd || tTime > arhEnd || shD->tTimeCurent) { XMLNode req("info"); req.setAttr("arch",shD->arch)->setAttr("path","/Archive/%2fserv%2fmess"); if(w->cntrIfCmd(req,true)) arhBeg = arhEnd = 0; else { arhBeg = strtoul(req.attr("beg").c_str(), 0, 10); arhEnd = strtoul(req.attr("end").c_str(), 0, 10); } } if(!arhBeg || !arhEnd) return; //Correct request to archive border tTime = shD->tTimeCurent ? arhEnd : vmin(tTime, arhEnd); tTimeGrnd = vmax(tTimeGrnd, arhBeg); } //Clear data at time error unsigned int valEnd = 0, valBeg = 0; while(shD->messList.size() && (valEnd=shD->messList[0].time) > tTime) { shD->messList.pop_front(); isDtChang = true; } while(shD->messList.size() && (valBeg=shD->messList[shD->messList.size()-1].time) < tTimeGrnd) { shD->messList.pop_back(); isDtChang = true; } if(shD->messList.empty()) valEnd = valBeg = 0; if(tTime < tTimeGrnd || (tTime < valEnd && tTimeGrnd > valBeg)) { shD->messList.clear(); shD->addrWdg->setRowCount(0); valEnd = valBeg = 0; return; } //Correct request to the present data if(shD->time > shD->tmPrev) { if(valEnd) tTimeGrnd = valEnd; toUp = true; } else if((shD->time-shD->tSize) < shD->tmGrndPrev) { if(valBeg) tTime = valBeg-1; } else return; shD->tmPrev = shD->time; shD->tmGrndPrev = shD->time-shD->tSize; //Get values data XMLNode req("get"); req.clear()-> setAttr("arch", shD->arch)-> setAttr("path", "/Archive/%2fserv%2fmess")-> setAttr("tm", ll2s(tTime))-> setAttr("tm_grnd", ll2s(tTimeGrnd))-> setAttr("cat", shD->tmpl)-> setAttr("lev", i2s(shD->lev)); if(w->cntrIfCmd(req,true)) return; if(toUp) for(unsigned iReq = 0; iReq < req.childSize(); iReq++) { XMLNode *rcd = req.childGet(iReq); TMess::SRec mess(strtoul(rcd->attr("time").c_str(),0,10), s2i(rcd->attr("utime")), rcd->attr("cat"), (TMess::Type)abs(s2i(rcd->attr("lev"))), rcd->text()); // Check for dublicates isDbl = false; for(unsigned iP = 0; !isDbl && iP < shD->messList.size(); iP++) { if(mess.time > shD->messList[0].time && iP) break; if(shD->messList[iP].utime == mess.utime && shD->messList[iP].level == mess.level && shD->messList[iP].categ == mess.categ && shD->messList[iP].mess == mess.mess) isDbl = true; } if(isDbl) continue; // Insert a new row shD->messList.push_front(mess); isDtChang = true; } else for(int iReq = req.childSize()-1; iReq >= 0; iReq--) { XMLNode *rcd = req.childGet(iReq); TMess::SRec mess(strtoul(rcd->attr("time").c_str(),0,10), s2i(rcd->attr("utime")), rcd->attr("cat"), (TMess::Type)abs(s2i(rcd->attr("lev"))), rcd->text()); // Check for dublicates isDbl = false; for(int iP = shD->messList.size()-1; !isDbl && iP >= 0; iP--) { if(mess.time < shD->messList[shD->messList.size()-1].time && iP < ((int)shD->messList.size()-1)) break; if(shD->messList[iP].utime == mess.utime && shD->messList[iP].level == mess.level && shD->messList[iP].categ == mess.categ && shD->messList[iP].mess == mess.mess) isDbl = true; } if(isDbl) continue; // Insert new row shD->messList.push_back(mess); isDtChang = true; } if(shD->addrWdg->rowCount() == (int)shD->messList.size() && !isDtChang) return; //Sort data vector< pair > sortIts; switch(shD->viewOrd&0x3) { case FP_ON_TM: for(unsigned iM = 0; iM < shD->messList.size(); iM++) sortIts.push_back(pair(u2s(shD->messList[iM].time)+" "+u2s(shD->messList[iM].utime),iM)); break; case FP_ON_LEV: for(unsigned iM = 0; iM < shD->messList.size(); iM++) sortIts.push_back(pair(i2s(shD->messList[iM].level),iM)); break; case FP_ON_CAT: for(unsigned iM = 0; iM < shD->messList.size(); iM++) sortIts.push_back(pair(shD->messList[iM].categ,iM)); break; case FP_ON_MESS: for(unsigned iM = 0; iM < shD->messList.size(); iM++) sortIts.push_back(pair(shD->messList[iM].mess,iM)); break; } sort(sortIts.begin(), sortIts.end()); if(shD->viewOrd&0x4) reverse(sortIts.begin(), sortIts.end()); //Write to the table shD->addrWdg->setRowCount(sortIts.size()); QTableWidgetItem *tit; for(unsigned iM = 0; iM < sortIts.size(); iM++) { QFont fnt; QColor clr, fclr; // Check the properties for(int iIt = 0, lst_lev = -1; iIt < (int)shD->itProps.size(); iIt++) if(shD->messList[sortIts[iM].second].level >= shD->itProps[iIt].lev && shD->itProps[iIt].lev > lst_lev && TRegExp(shD->itProps[iIt].tmpl, "p").test(shD->messList[sortIts[iM].second].categ)) { fnt = shD->itProps[iIt].font; clr = shD->itProps[iIt].clr; if(shD->messList[sortIts[iM].second].level == shD->itProps[iIt].lev) break; lst_lev = shD->itProps[iIt].lev; } if(clr.isValid()) fclr = ((0.3*clr.red()+0.59*clr.green()+0.11*clr.blue()) > 128) ? Qt::black : Qt::white; for(int iCl = 0; iCl < shD->addrWdg->columnCount(); iCl++) { tit = NULL; if(iCl == c_tm) { QDateTime dtm; dtm.setSecsSinceEpoch(shD->messList[sortIts[iM].second].time); shD->addrWdg->setItem(iM, c_tm, tit=new QTableWidgetItem(dtm.toString("dd.MM.yyyy hh:mm:ss"))); tit->setData(Qt::TextAlignmentRole, (int)(Qt::AlignCenter|Qt::TextWordWrap)); } else if(iCl == c_tmu) { shD->addrWdg->setItem(iM, c_tmu, tit=new QTableWidgetItem(QString::number(shD->messList[sortIts[iM].second].utime))); tit->setData(Qt::TextAlignmentRole, Qt::AlignCenter); } else if(iCl == c_lev) { shD->addrWdg->setItem(iM, c_lev, tit=new QTableWidgetItem(QString::number(shD->messList[sortIts[iM].second].level))); tit->setData(Qt::TextAlignmentRole, Qt::AlignCenter); } else if(iCl == c_cat) shD->addrWdg->setItem(iM, c_cat, tit=new QTableWidgetItem(shD->messList[sortIts[iM].second].categ.c_str())); else if(iCl == c_mess) shD->addrWdg->setItem(iM, c_mess, tit=new QTableWidgetItem(shD->messList[sortIts[iM].second].mess.c_str())); else continue; tit->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); tit->setData(Qt::FontRole, fnt); tit->setData(Qt::BackgroundRole, clr.isValid() ? clr : QVariant()); tit->setData(Qt::ForegroundRole, fclr.isValid() ? fclr : QVariant()); } } if(newFill) { shD->addrWdg->resizeColumnsToContents(); //Resize too long columns int max_col_sz = vmax(w->size().width()/2, 40); for(int iC = 0; iC < shD->addrWdg->columnCount(); iC++) shD->addrWdg->setColumnWidth(iC,vmin(max_col_sz,shD->addrWdg->columnWidth(iC))); shD->addrWdg->horizontalHeader()->setStretchLastSection(true); } shD->addrWdg->resizeRowsToContents(); } void ShapeProtocol::tracing( ) { WdgView *w = (WdgView *)((QTimer*)sender())->parent(); RunWdgView *runW = qobject_cast(((QTimer*)sender())->parent()); if(runW && runW->mainWin()->f_winClose) return; ShpDt *shD = (ShpDt*)w->shpData; if(!w->isEnabled()) return; if(shD->tTimeCurent)shD->time = (unsigned int)time(NULL); else if(shD->time) shD->time += shD->trcPer; loadData(w); } bool ShapeProtocol::event( WdgView *w, QEvent *event ) { return false; } bool ShapeProtocol::eventFilter( WdgView *w, QObject *object, QEvent *event ) { if(qobject_cast(w)) switch(event->type()) { case QEvent::Enter: case QEvent::Leave: return true; case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: QApplication::sendEvent(w, event); return true; default: break; } else { AttrValS attrs; switch(event->type()) { case QEvent::FocusIn: qobject_cast(w)->mainWin()->setFocus(w->id()); break; /*attrs.push_back(std::make_pair("focus","1")); attrs.push_back(std::make_pair("event","ws_FocusIn")); w->attrsSet(attrs); break; case QEvent::FocusOut: attrs.push_back(std::make_pair("focus","0")); attrs.push_back(std::make_pair("event","ws_FocusOut")); w->attrsSet(attrs); break;*/ default: break; } } return false; } void ShapeProtocol::eventFilterSet( WdgView *view, QWidget *wdg, bool en ) { if(en) wdg->installEventFilter(view); else wdg->removeEventFilter(view); //Process childs for(int iC = 0; iC < wdg->children().size(); iC++) if(qobject_cast(wdg->children().at(iC))) { eventFilterSet(view, (QWidget*)wdg->children().at(iC), en); if(en) ((QWidget*)wdg->children().at(iC))->setMouseTracking(true); } } void ShapeProtocol::setFocus(WdgView *view, QWidget *wdg, bool en, bool devel ) { int isFocus = wdg->windowIconText().toInt(); //Set up current widget if(en) { if(isFocus) wdg->setFocusPolicy((Qt::FocusPolicy)isFocus); } else { if(wdg->focusPolicy() != Qt::NoFocus) { wdg->setWindowIconText(QString::number((int)wdg->focusPolicy())); wdg->setFocusPolicy(Qt::NoFocus); } if(devel) wdg->setMouseTracking(true); } //Process childs for(int iC = 0; iC < wdg->children().size(); iC++) if(qobject_cast(wdg->children().at(iC))) setFocus(view, (QWidget*)wdg->children().at(iC), en, devel); } //************************************************ //* Document view shape widget * //************************************************ const char *ShapeDocument::XHTML_entity = "\n" "]>\n"; ShapeDocument::ShapeDocument( ) : WdgShape("Document") { } void ShapeDocument::init( WdgView *w ) { w->shpData = new ShpDt(); ShpDt *shD = (ShpDt*)w->shpData; DevelWdgView *devW = qobject_cast(w); QVBoxLayout *lay = new QVBoxLayout(w); if(devW) shD->web = new QTextBrowser(w); //!!!! Only QTextBrowser in the development mode else { #if HAVE_WEBENGINE shD->web = new QWebEngineView(w); # if QT_VERSION >= 0x060000 connect(shD->web, SIGNAL(printFinished(bool)), this, SLOT(printFinished())); # endif #elif HAVE_WEBKIT shD->web = new QWebView(w); shD->web->setAttribute(Qt::WA_AcceptTouchEvents, false); #else shD->web = new QTextBrowser(w); #endif shD->web->setContextMenuPolicy(Qt::CustomContextMenu); connect(shD->web, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(custContextMenu())); } eventFilterSet(w, shD->web, true); w->setFocusProxy(shD->web); if(devW) setFocus(w, shD->web, false, true); lay->addWidget(shD->web); } void ShapeDocument::destroy( WdgView *w ) { //Waiting for the print finish while(((ShpDt*)w->shpData)->printCB) qApp->processEvents(); delete (ShpDt*)w->shpData; } bool ShapeDocument::attrSet( WdgView *w, int uiPrmPos, const string &val, const string &attr ) { ShpDt *shD = (ShpDt*)w->shpData; RunWdgView *runW = qobject_cast(w); bool relDoc = false; //Reload configuration switch(uiPrmPos) { case A_COM_LOAD: relDoc = true; break; case A_EN: if(!runW) break; shD->en = (bool)s2i(val); shD->web->setVisible(shD->en && runW->permView()); break; case A_ACTIVE: if(!runW) break; shD->active = (bool)s2i(val); setFocus(w, shD->web, shD->active && runW->permCntr()); shD->web->setEnabled(shD->active && runW->permCntr()); break; case A_GEOM_MARGIN: w->layout()->setContentsMargins(s2i(val), s2i(val), s2i(val), s2i(val)); break; case A_DocStyle: if(shD->style != val) { shD->style = val; relDoc = true; } break; case A_DocTmpl: if((!shD->doc.empty() && !shD->tmpl) || shD->doc == val) break; shD->doc = val; relDoc = true; shD->tmpl = true; break; case A_DocDoc: if(sTrm(val).empty() || shD->doc == val) break; shD->doc = val; relDoc = true; shD->tmpl = false; break; case A_DocFont: if(shD->font != val) { shD->font = val; relDoc = true;} break; } if(relDoc && !w->allAttrLoad()) { shD->web->setFont(getFont(shD->font,vmin(w->xScale(true),w->yScale(true)),false)); if(!runW) ((QTextBrowser*)shD->web)->setHtml(shD->toHtml().c_str()); else { #if HAVE_WEBENGINE QWebEngineView *wb = (QWebEngineView *)shD->web; //!!!! Impossible to change the scroll position in WebEngine, only read #elif HAVE_WEBKIT QWebView *wb = (QWebView *)shD->web; QPoint scrollPos; if(wb->page() && wb->page()->mainFrame()) scrollPos = wb->page()->mainFrame()->scrollPosition(); #else QTextBrowser *wb = (QTextBrowser *)shD->web; int scrollPos = wb->verticalScrollBar()->value(); #endif wb->setHtml(shD->toHtml().c_str()); #if HAVE_WEBENGINE //!!!! Impossible to change the scroll position in WebEngine, only read #elif HAVE_WEBKIT if(!scrollPos.isNull() && wb->page() && wb->page()->mainFrame()) wb->page()->mainFrame()->setScrollPosition(scrollPos); #else wb->verticalScrollBar()->setValue(scrollPos); #endif } } return true; } bool ShapeDocument::event( WdgView *w, QEvent *event ) { return false; } bool ShapeDocument::eventFilter( WdgView *w, QObject *object, QEvent *event ) { if(qobject_cast(w)) switch(event->type()) { case QEvent::Enter: case QEvent::Leave: return true; case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::ContextMenu: case QEvent::Wheel: QApplication::sendEvent(w,event); return true; default: break; } else { AttrValS attrs; switch(event->type()) { case QEvent::FocusIn: qobject_cast(w)->mainWin()->setFocus(w->id()); break; /*attrs.push_back(std::make_pair("focus","1")); attrs.push_back(std::make_pair("event","ws_FocusIn")); w->attrsSet(attrs); break; case QEvent::FocusOut: attrs.push_back(std::make_pair("focus","0")); attrs.push_back(std::make_pair("event","ws_FocusOut")); w->attrsSet(attrs); break;*/ default: break; } } return false; } void ShapeDocument::eventFilterSet( WdgView *view, QWidget *wdg, bool en ) { if(en) wdg->installEventFilter(view); else wdg->removeEventFilter(view); //Process childs for(int iC = 0; iC < wdg->children().size(); iC++) if(qobject_cast(wdg->children().at(iC))) eventFilterSet(view,(QWidget*)wdg->children().at(iC),en); } void ShapeDocument::custContextMenu( ) { QObject *web = sender(); RunWdgView *w = dynamic_cast(web->parent()); if(!w) return; #if HAVE_WEBENGINE QMenu *menu = new QMenu(w); //!!!! Due to there is no sense in the StandardContextMenu /*# if QT_VERSION < 0x060000 QMenu *menu = ((QWebEngineView*)web)->page()->createStandardContextMenu(); # else QMenu *menu = ((QWebEngineView*)web)->createStandardContextMenu(); # endif*/ #elif HAVE_WEBKIT QMenu *menu = ((QWebView*)web)->page()->createStandardContextMenu(); #else QMenu *menu = ((QTextBrowser*)web)->createStandardContextMenu(); #endif menu->addSeparator(); QImage ico_t; if(!ico_t.load(TUIS::icoGet("print",NULL,true).c_str())) ico_t.load(":/images/print.png"); QAction *actPrint = new QAction(QPixmap::fromImage(ico_t),_("Print"),this); menu->addAction(actPrint); if(!ico_t.load(TUIS::icoGet("export",NULL,true).c_str())) ico_t.load(":/images/export.png"); QAction *actExp = new QAction(QPixmap::fromImage(ico_t),_("Export"),this); menu->addAction(actExp); QAction *rez = menu->exec(QCursor::pos()); if(rez == actPrint) w->mainWin()->printDoc(w->id()); else if(rez == actExp) w->mainWin()->exportDoc(w->id()); //#if !HAVE_WEBENGINE menu->deleteLater(); //delete menu; //#endif } void ShapeDocument::printFinished( ) { WdgView *w = dynamic_cast(sender()->parent()); if(w) ((ShpDt*)w->shpData)->printCB = false; } void ShapeDocument::setFocus( WdgView *view, QWidget *wdg, bool en, bool devel ) { int isFocus = wdg->windowIconText().toInt(); //Set up current widget if(en) { if(isFocus && !devel) wdg->setFocusPolicy((Qt::FocusPolicy)isFocus); } else { if(wdg->focusPolicy() != Qt::NoFocus) { wdg->setWindowIconText(QString::number((int)wdg->focusPolicy())); wdg->setFocusPolicy(Qt::NoFocus); } if(devel) wdg->setMouseTracking(true); } //Process childs for(int iC = 0; iC < wdg->children().size(); iC++) if(qobject_cast(wdg->children().at(iC))) setFocus(view,(QWidget*)wdg->children().at(iC), en, devel); } //Shape node date string ShapeDocument::ShpDt::toHtml( ) { if(!web) return ""; //Process source document // Parse document XMLNode xproc("body"); try{ if(!doc.empty()) xproc.load(string(XHTML_entity)+doc, true, Mess->charset()); } catch(TError &err) { mess_err(mod->nodePath().c_str(), _("Error parsing the document: %s"), err.mess.c_str()); } nodeProcess(&xproc); return "\n" "\n" "\n" "\n" " \n" " \n" "\n"+ xproc.save(XMLNode::Clean, Mess->charset())+ ""; } void ShapeDocument::ShpDt::nodeProcess( XMLNode *xcur ) { //Delete process instructions //xcur->prcInstrClear(); //Go to include nodes for(unsigned iC = 0; iC < xcur->childSize(); ) { // Check for special tags if(xcur->childGet(iC)->name().compare(0,3,"doc") == 0) { xcur->childDel(iC); continue; } nodeProcess(xcur->childGet(iC)); iC++; } } #ifndef QT_NO_PRINTER void ShapeDocument::ShpDt::print( QPrinter *printer ) { //Waiting for the print finish while(printCB) qApp->processEvents(); # if HAVE_WEBENGINE //Starting the print printCB = true; # if QT_VERSION < 0x060000 ((QWebEngineView*)web)->page()->print(printer, [this](bool) { this->printCB = false; } ); # else ((QWebEngineView*)web)->print(printer); # endif # elif HAVE_WEBKIT ((QWebView*)web)->print(printer); # else ((QTextBrowser*)web)->document()->print(printer); # endif } #endif //************************************************ //* User function shape widget * //************************************************ ShapeFunction::ShapeFunction( ) : WdgShape("Function") { } /*bool ShapeFunction::event( WdgView *view, QEvent *event ) { }*/ //************************************************ //* User element shape widget * //************************************************ ShapeBox::ShapeBox( ) : WdgShape("Box") { } void ShapeBox::init( WdgView *w ) { w->shpData = new ShpDt(); RunWdgView *rw = qobject_cast(w); if(rw) { ((ShpDt*)w->shpData)->en = false; w->setVisible(false); } } void ShapeBox::destroy( WdgView *w ) { delete (ShpDt*)w->shpData; } bool ShapeBox::attrSet( WdgView *w, int uiPrmPos, const string &val, const string &attr ) { bool up = true; ShpDt *shD = (ShpDt*)w->shpData; RunWdgView *runW = qobject_cast(w); RunPageView *runP = runW ? qobject_cast(w) : NULL; switch(uiPrmPos) { case A_COM_LOAD: up = true; //if(runW && shD->inclPg) shD->inclPg->setMinimumSize(w->size()); break; case A_NO_ID: if(runP && attr == "vs_winTitle") w->window()->setWindowTitle(val.c_str()); break; case A_COM_FOCUS: break; case A_EN: if(!runW) { up = false; break; } shD->en = (bool)s2i(val); //w->setVisible(shD->en && (runW->permView() || runP)); break; case A_ACTIVE: if(!runW) { up = false; break; } shD->active = (bool)s2i(val); shD->realAct = (shD->active && ((RunWdgView*)w)->permCntr()); w->setFocusPolicy(shD->realAct ? Qt::TabFocus : Qt::NoFocus); break; case A_GEOM_MARGIN: shD->geomMargin = s2i(val); if(w->layout()) w->layout()->setContentsMargins(shD->geomMargin, shD->geomMargin, shD->geomMargin, shD->geomMargin); break; case A_BackColor: { shD->backGrnd.setColor(getColor(val)); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setColor(shD->backGrnd.color()); if(!brsh.color().isValid()) brsh.setColor(QPalette().brush(QPalette::Window).color()); brsh.setStyle(brsh.textureImage().isNull() ? Qt::SolidPattern : Qt::TexturePattern); plt.setBrush(QPalette::Window, brsh); w->setPalette(plt); if(runP && (!runP->mainWin()->masterPg() || runP->mainWin()->masterPg() == w) && !shD->border.width()) runP->mainWin()->setPalette(plt); break; } case A_BackImg: { QImage img; string backimg = w->resGet(val); shD->backGrnd.setTextureImage(QImage()); if(!backimg.empty() && img.loadFromData((const uchar*)backimg.data(),backimg.size())) shD->backGrnd.setTextureImage(img); QPalette plt(w->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setTextureImage(img); brsh.setStyle(!brsh.textureImage().isNull() ? Qt::TexturePattern : Qt::SolidPattern); plt.setBrush(QPalette::Window, brsh); w->setPalette(plt); if(runP && (!runP->mainWin()->masterPg() || runP->mainWin()->masterPg() == w) && !shD->border.width()) runP->mainWin()->setPalette(plt); break; } case A_BordWidth: shD->border.setWidth(s2i(val)); if(runP && (!runP->mainWin()->masterPg() || runP->mainWin()->masterPg() == w)) runP->mainWin()->setPalette(shD->border.width() ? QPalette() : w->palette()); break; case A_BordColor: shD->border.setColor(getColor(val)); break; case A_BordStyle: shD->bordStyle = s2i(val); break; case A_PG_OPEN_SRC: if(!runW || runP) { up = false; break; } //Put previous include widget to page cache if((shD->inclPg && val != shD->inclPg->id()) || (!shD->inclPg && !val.empty())) { if(shD->inclPg) { shD->inclPg->setReqTm(shD->inclPg->mainWin()->reqTm()); runW->mainWin()->pgCacheAdd(shD->inclPg); shD->inclPg->setEnabled(false); shD->inclPg->setVisible(false); shD->inclPg->toPgCache(); shD->inclScrl->takeWidget(); shD->inclPg->setParent(NULL); shD->inclPg->wx_scale = shD->inclPg->mainWin()->xScale(); shD->inclPg->wy_scale = shD->inclPg->mainWin()->yScale(); shD->inclPg = NULL; w->setProperty("inclPg", ""); } // Create new include widget if(val.size()) { if(!shD->inclScrl) { QGridLayout *wlay = (QGridLayout*)w->layout(); if(!wlay) wlay = new QGridLayout(w); wlay->setContentsMargins(0, 0, 0, 0); shD->inclScrl = new QScrollArea(w); shD->inclScrl->setFocusPolicy(Qt::NoFocus); shD->inclScrl->setFrameShape(QFrame::NoFrame); wlay->addWidget(shD->inclScrl); } QLabel *lab = new QLabel(QString(_("Loading page: '%1'.")).arg(val.c_str()), shD->inclPg); lab->setAlignment(Qt::AlignCenter); lab->setWordWrap(true); lab->resize(w->size()); QPalette plt = lab->palette(); plt.setColor(QPalette::WindowText, shD->border.color()); lab->setPalette(plt); lab->setLineWidth(shD->border.width()); lab->setFrameShape(QFrame::Box); shD->inclScrl->setWidget(lab); qApp->processEvents(); shD->inclPg = runW->mainWin()->pgCacheGet(val); if(shD->inclPg) { shD->inclPg->setProperty("cntPg", TSYS::addr2str(w).c_str()); shD->inclScrl->setWidget(shD->inclPg); shD->inclPg->setEnabled(true); shD->inclPg->setVisible(true); //!!!! In any case complete reload the page due to the possibility of the last changes loss at the closing shD->inclPg->load(""); //shD->inclPg->setMinimumSize(w->size()); /*if(shD->inclPg->wx_scale != shD->inclPg->mainWin()->xScale() || shD->inclPg->wy_scale != shD->inclPg->mainWin()->yScale()) shD->inclPg->load(""); else { unsigned trt = shD->inclPg->mainWin()->reqTm(); shD->inclPg->mainWin()->setReqTm(shD->inclPg->reqTm()); shD->inclPg->update(false); shD->inclPg->mainWin()->setReqTm(trt); }*/ } else { shD->inclPg = new RunPageView(val, (VisRun*)w->mainWin(), shD->inclScrl, Qt::SubWindow); shD->inclPg->setProperty("cntPg", TSYS::addr2str(w).c_str()); shD->inclScrl->setWidget(shD->inclPg); shD->inclPg->resizeF(shD->inclPg->sizeF()); //To realign //shD->inclPg->load(""); //That does in the constructor shD->inclPg->setAttribute(Qt::WA_WindowPropagation, true); } w->setProperty("inclPg", TSYS::addr2str(shD->inclPg).c_str()); } } else up = false; break; default: up = false; } if(up && runW) { if(shD->realAct && shD->backGrnd.color().isValid() && shD->backGrnd.color().alpha()) w->setCursor(Qt::PointingHandCursor); else w->setCursor(Qt::ArrowCursor); // w->unsetCursor(); } if(up && !w->allAttrLoad()) { if(uiPrmPos != -1) w->update(); if(runW) runW->setVisible(shD->en && (runW->permView() || runP)); } return up; } bool ShapeBox::event( WdgView *w, QEvent *event ) { ShpDt *shD = (ShpDt*)w->shpData; if(!shD->en) return false; switch(event->type()) { case QEvent::Paint: { if(shD->inclPg) return false; QPainter pnt(w); //Apply margin QRect dA = w->rect().adjusted(0, 0, -2*shD->geomMargin, -2*shD->geomMargin); pnt.setWindow(dA); pnt.setViewport(w->rect().adjusted(shD->geomMargin,shD->geomMargin,-shD->geomMargin,-shD->geomMargin)); //Draw background if(shD->backGrnd.color().isValid()) pnt.fillRect(dA, shD->backGrnd.color()); if(!shD->backGrnd.textureImage().isNull()) pnt.fillRect(dA, shD->backGrnd.textureImage()); //Draw border borderDraw(pnt, dA, shD->border, shD->bordStyle); //Draw focused border //if(w->hasFocus()) qDrawShadeRect(&pnt,dA,w->palette(),false,1); return true; } //case QEvent::User: // if(shD->inclPg) shD->inclPg->update(); default: return false; } return false; }