//OpenSCADA module UI.Vision file: vis_run.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 "../QTStarter/lib_qtgen.h" #include "vis_run.h" #include "vis_run_widgs.h" #include "vis_shapes.h" #if HAVE_MULTIMEDIA # include # if QT_VERSION >= 0x060000 # include # 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 setSecsSinceEpoch(tm) setTime_t(tm) # define typeId() type() # define setSource(url) setMedia(url) #endif #undef _ #define _(mess) mod->I18N(mess, lang().c_str()).c_str() using namespace OSCADA_QT; using namespace VISION; VisRun::VisRun( const string &iprjSes_it, const string &open_user, const string &user_pass, const string &VCAstat, bool icrSessForce, unsigned iScr ) : #if QT_VERSION < 0x050000 QMainWindow(QDesktopWidget().screen(iScr)), #endif f_winClose(false), f_resizeManual(false), f_updPage(false), updTmMax(0), planePer(0), #ifndef QT_NO_PRINTER prPg(NULL), prDiag(NULL), prDoc(NULL), #endif fileDlg(NULL), conErr(NULL), crSessForce(icrSessForce), mKeepAspectRatio(true), mWinPosCntrSave(false), prjSes_it(iprjSes_it), master_pg(NULL), mPeriod(1000), mConId(0), mScreen(iScr), wPrcCnt(0), reqtm(1), expDiagCnt(1), expDocCnt(1), expTblCnt(1), x_scale(1), y_scale(1), mAlrmSt(0xFFFFFF), alrLevSet(false), ntfSet(0), alrmUpdCnt(0), host(NULL) { #if QT_VERSION >= 0x050000 if(qApp->screens().size() > 1 && iScr < qApp->screens().size() && windowHandle()) windowHandle()->setScreen(qApp->screens()[iScr]); //?!?! Check sometime #endif QImage ico_t; connect(this, SIGNAL(makeStarterMenu(QWidget*,const QString&)), qApp, SLOT(makeStarterMenu(QWidget*,const QString&))); setAttribute(Qt::WA_DeleteOnClose, true); mod->regWin(this); setWindowIcon(mod->icon()); //Create actions // Generic actions // Print if(!ico_t.load(TUIS::icoGet("print",NULL,true).c_str())) ico_t.load(":/images/print.png"); menuPrint = new QMenu(this); menuPrint->setIcon(QPixmap::fromImage(ico_t)); menuPrint->menuAction()->setShortcut(QKeySequence::Print); connect(menuPrint->menuAction(), SIGNAL(triggered()), this, SLOT(print())); actPrintPg = new QAction(this); connect(actPrintPg, SIGNAL(triggered()), this, SLOT(printPg())); menuPrint->addAction(actPrintPg); actPrintDiag = new QAction(this); connect(actPrintDiag, SIGNAL(triggered()), this, SLOT(printDiag())); menuPrint->addAction(actPrintDiag); actPrintDoc = new QAction(this); connect(actPrintDoc, SIGNAL(triggered()), this, SLOT(printDoc())); menuPrint->addAction(actPrintDoc); // Export if(!ico_t.load(TUIS::icoGet("export",NULL,true).c_str())) ico_t.load(":/images/export.png"); menuExport = new QMenu(this); menuExport->setIcon(QPixmap::fromImage(ico_t)); connect(menuExport->menuAction(), SIGNAL(triggered()), this, SLOT(exportDef())); actExpPg = new QAction(this); connect(actExpPg, SIGNAL(triggered()), this, SLOT(exportPg())); menuExport->addAction(actExpPg); actExpDiag = new QAction(this); connect(actExpDiag, SIGNAL(triggered()), this, SLOT(exportDiag())); menuExport->addAction(actExpDiag); actExpDoc = new QAction(this); connect(actExpDoc, SIGNAL(triggered()), this, SLOT(exportDoc())); menuExport->addAction(actExpDoc); actExpTable = new QAction(this); connect(actExpTable, SIGNAL(triggered()), this, SLOT(exportTable())); menuExport->addAction(actExpTable); // Close if(!ico_t.load(TUIS::icoGet("close",NULL,true).c_str())) ico_t.load(":/images/close.png"); actClose = new QAction(QPixmap::fromImage(ico_t), "", this); actClose->setShortcut(Qt::CTRL|Qt::Key_W); connect(actClose, SIGNAL(triggered()), this, SLOT(close())); // Quit if(!ico_t.load(TUIS::icoGet("exit",NULL,true).c_str())) ico_t.load(":/images/exit.png"); actQuit = new QAction(QPixmap::fromImage(ico_t), "", this); actQuit->setShortcut(Qt::CTRL|Qt::Key_Q); connect(actQuit, SIGNAL(triggered()), this, SLOT(quitSt())); // View actions // Fullscreen actFullScr = new QAction(this); actFullScr->setCheckable(true); connect(actFullScr, SIGNAL(toggled(bool)), this, SLOT(fullScreen(bool))); // Help actions // About "System info" if(!ico_t.load(TUIS::icoGet("help",NULL,true).c_str())) ico_t.load(":/images/help.png"); actAbout = new QAction(QPixmap::fromImage(ico_t), "", this); connect(actAbout, SIGNAL(triggered()), this, SLOT(about())); // About Qt actQtAbout = new QAction(this); connect(actQtAbout, SIGNAL(triggered()), this, SLOT(aboutQt())); // The project manual if(!ico_t.load(TUIS::icoGet("manual",NULL,true).c_str())) ico_t.load(":/images/manual.png"); actProjManual = new QAction(QPixmap::fromImage(ico_t),"",this); actProjManual->setShortcut(Qt::Key_F1); connect(actProjManual, SIGNAL(triggered()), this, SLOT(enterManual())); // Vision manual actManual = new QAction(QPixmap::fromImage(ico_t), "", this); connect(actManual, SIGNAL(triggered()), this, SLOT(enterManual())); // OpenSCADA manual index actManualSYS = new QAction(QPixmap::fromImage(ico_t), "", this); connect(actManualSYS, SIGNAL(triggered()), this, SLOT(enterManual())); // What is if(!ico_t.load(TUIS::icoGet("contexthelp",NULL,true).c_str())) ico_t.load(":/images/contexthelp.png"); actWhatIs = new QAction(QPixmap::fromImage(ico_t), "", this); actWhatIs->setShortcut(Qt::SHIFT|Qt::Key_F1); connect(actWhatIs, SIGNAL(triggered()), this, SLOT(enterWhatsThis())); // Alarms actions // Alarm level display button and full alarms quietance if(!ico_t.load(TUIS::icoGet("alarmLev",NULL,true).c_str())) ico_t.load(":/images/alarmLev.png"); actAlrmLev = new QAction(QPixmap::fromImage(ico_t), "", this); actAlrmLev->setObjectName("alarmLev"); menuFile.addAction(menuPrint->menuAction()); menuFile.addAction(menuExport->menuAction()); menuFile.addSeparator(); menuFile.addAction(actClose); menuFile.addAction(actQuit); menuAlarm.addAction(actAlrmLev); menuView.addAction(actFullScr); menuHelp.addAction(actAbout); menuHelp.addAction(actQtAbout); menuHelp.addAction(actProjManual); menuHelp.addAction(actManual); menuHelp.addAction(actManualSYS); menuHelp.addSeparator(); menuHelp.addAction(actWhatIs); //Init tool bars // Generic tools bar toolBarStatus = new QToolBar(this); connect(toolBarStatus, SIGNAL(actionTriggered(QAction*)), this, SLOT(alarmAct(QAction*))); toolBarStatus->setIconSize(QSize(icoSize(),icoSize())); toolBarStatus->addAction(actProjManual); toolBarStatus->addSeparator(); toolBarStatus->addAction(menuPrint->menuAction()); toolBarStatus->addAction(menuExport->menuAction()); toolBarStatus->addSeparator(); toolBarStatus->addAction(actAlrmLev); //Init status bar mWTime = new QLabel(this); mWTime->setVisible(false); mWTime->setAlignment(Qt::AlignCenter); statusBar()->insertPermanentWidget(0, mWTime); mWUser = new UserStBar(open_user.c_str(), user_pass.c_str(), VCAstat.c_str(), this); connect(mWUser, SIGNAL(userChanged(const QString&,const QString&)), this, SLOT(userChanged(const QString&,const QString&))); statusBar()->insertPermanentWidget(0, mWUser); mWStat = new QLabel(VCAStation().c_str(), this); mWStat->setVisible(VCAStation() != "."); statusBar()->insertPermanentWidget(0, mWStat); mStlBar = new StylesStBar(-1, this); connect(mStlBar, SIGNAL(styleChanged()), this, SLOT(styleChanged())); statusBar()->insertPermanentWidget(0, mStlBar); statusBar()->insertPermanentWidget(0, toolBarStatus); //statusBar()->setVisible(mod->runPrjsSt()); //Init scroller QScrollArea *scrl = new QScrollArea; scrl->setFocusPolicy(Qt::NoFocus); scrl->setAlignment(Qt::AlignCenter); setCentralWidget(scrl); //Create timers // End run timer endRunTimer = new QTimer(this); endRunTimer->setSingleShot(false); connect(endRunTimer, SIGNAL(timeout()), this, SLOT(endRunChk())); endRunTimer->start(1e3*prmWait_DL); // Update timer updateTimer = new QTimer(this); updateTimer->setSingleShot(false); connect(updateTimer, SIGNAL(timeout()), this, SLOT(updatePage())); //actProjManual->setEnabled(TUIS::docGet(actProjManual->property("doc").toString().toStdString(),NULL,TUIS::GetFilePath).size()); if(!s2i(SYS->cmdOpt("showWin"))) resize(1024, 768); //Establish connection to the remote station //?!?! Disabled by default for the requesting in different threads before resolving the mouse release event in the same widget processing the press event if(SYS->cmdOptPresent("ReqInDifThread")) initHost(); initSess(prjSes_it, crSessForce); //init session messUpd(); //mWStat->setText(host.st_nm.c_str()); statusBar()->showMessage(_("Ready"), 2000); //Restoring the main window position if(!s2i(SYS->cmdOpt("showWin")) && winPosCntrSave() && masterPg() && !(windowState()&(Qt::WindowMaximized|Qt::WindowFullScreen))) { string xPos, yPos; if((xPos=wAttrGet(masterPg()->id(),i2s(screen())+"geomX",true)).size() && (yPos=wAttrGet(masterPg()->id(),i2s(screen())+"geomY",true)).size()) move(s2i(xPos), s2i(yPos)); else if(abs(masterPg()->posF().x()) || abs(masterPg()->posF().y())) move(masterPg()->posF().x(), masterPg()->posF().y()); } alarmSet(0); } VisRun::~VisRun( ) { f_winClose = true; endRunTimer->stop(); updateTimer->stop(); alarmSet(0); for(map::iterator iN = mNotify.begin(); iN != mNotify.end(); ++iN) delete iN->second; //alrmPlay->wait(); //Disconnect/delete session XMLNode req("disconnect"); req.setAttr("path", "/%2fserv%2fsess")->setAttr("sess", work_sess)->setAttr("conId", i2s(mConId)); cntrIfCmd(req); //Unregister window mod->unregWin(this); //Clear cache pgCacheClear(); if(masterPg()) delete masterPg(); #ifndef QT_NO_PRINTER if(prPg) delete prPg; if(prDiag) delete prDiag; if(prDoc) delete prDoc; if(fileDlg) delete fileDlg; #endif if(host && host->inHostReq) mess_err(mod->nodePath().c_str(), _("Session '%s(%s)' using the remote host %d times."), workSess().c_str(), srcProject().c_str(), host->inHostReq); if(host) { delete host; // Push down all Qt events of the window to free the module for(int iTr = 0; iTr < 5; iTr++) qApp->processEvents(); } } void VisRun::setFocus( const string &addr, bool ack ) { if(focusWdf == addr) return; XMLNode req("set"); if(focusWdf.size()) { req.setAttr("path", focusWdf+"/%2fserv%2fattr"); req.childAdd("el")->setAttr("id","focus")->setText("0"); req.childAdd("el")->setAttr("id","event")->setText("ws_FocusOut"); cntrIfCmd(req); } if(ack) focusWdf = addr; req.clear()->setAttr("path", addr+"/%2fserv%2fattr"); req.childAdd("el")->setAttr("id","focus")->setText("1"); req.childAdd("el")->setAttr("id","event")->setText("ws_FocusIn"); cntrIfCmd(req); } bool VisRun::winMenu( ) { return menuBar()->actions().length(); } void VisRun::setWinMenu( bool act ) { menuBar()->clear(); //Create menu if(act) { menuBar()->addMenu(&menuFile); menuBar()->addMenu(&menuAlarm); if(s2i(SYS->cmdOpt("showWin")) != 2) menuBar()->addMenu(&menuView); menuBar()->addMenu(&menuHelp); emit makeStarterMenu(NULL, lang().c_str()); } } string VisRun::user( ) { return mWUser->user(); } bool VisRun::userSel( const string &hint ) { return mWUser->userSel(hint); } string VisRun::password( ) { return mWUser->pass(); } string VisRun::VCAStation( ) { return mWUser->VCAStation(); } int VisRun::style( ) { return mStlBar->style(); } void VisRun::setStyle( int istl ) { mStlBar->setStyle(istl); } void VisRun::initHost( ) { if(!host) { host = new SCADAHost(this); host->start(); } } int VisRun::cntrIfCmd( XMLNode &node, bool glob, bool main ) { node.setAttr("reforwardRedundOff", "1"); //To prevent for redundancy if(masterPg() && conErr && (!main || (time(NULL)-conErr->property("tm").toLongLong()) < conErr->property("tmRest").toInt())) { if(main && conErr->property("labTmpl").toString().size()) conErr->setText(conErr->property("labTmpl").toString().arg(conErr->property("tmRest").toInt()-(time(NULL)-conErr->property("tm").toLongLong()))); return TError::Tr_Connect; } int rez = 0; if(host) { host->inHostReq++; while(host->reqBusy()) { qApp->processEvents(); TSYS::sysSleep(0.01); } //Do and wait for the request bool done = false; if(!host->reqDo(node,done,glob)) while(!done) { qApp->processEvents(); TSYS::sysSleep(0.01); } host->inHostReq--; if(f_winClose && !host->inHostReq) close(); rez = s2i(node.attr("rez")); } else rez = mod->cntrIfCmd(node, user(), password(), VCAStation(), glob); //Display error message about connection error if(rez == TError::Tr_Connect && main && masterPg()) { if(!conErr) { //Create error message conErr = new QLabel(masterPg()); conErr->setAlignment(Qt::AlignCenter); conErr->setWordWrap(true); //Prepare message's style conErr->setFrameStyle(QFrame::StyledPanel|QFrame::Raised); conErr->setAutoFillBackground(true); QPalette plt(conErr->palette()); QBrush brsh = plt.brush(QPalette::Window); brsh.setColor(Qt::red); brsh.setStyle(Qt::SolidPattern); plt.setBrush(QPalette::Window, brsh); conErr->setPalette(plt); //Calc size and position conErr->resize(300, 100); conErr->move((masterPg()->size().width()-conErr->size().width())/2, (masterPg()->size().height()-conErr->size().height())/2); //conErr->show(); conErr->setProperty("tmRest", 0); } else conErr->setProperty("tmRest", vmin(mod->restoreTime(),conErr->property("tmRest").toInt()+1)); conErr->setProperty("tm", (long long)time(NULL)); if(conErr->property("tmRest").toInt() > 3) { if(!conErr->isVisible()) conErr->show(); conErr->setProperty("labTmpl", QString(_("Error connecting to the visualization server '%1': %2.\nThe next recovery attempt after %3s!")) .arg(VCAStation().c_str()).arg(node.text().c_str()).arg("%1")); conErr->setText(conErr->property("labTmpl").toString().arg(conErr->property("tmRest").toInt())); } } //Remove the error message about the connection error else if(rez != TError::Tr_Connect && main && conErr) { if(masterPg()) conErr->deleteLater(); conErr = NULL; updTmMax = planePer = 0; } return rez; } QString VisRun::getFileName( const QString &caption, const QString &dir, const QString &filter, QFileDialog::AcceptMode mode ) { if(!fileDlg) fileDlg = new QFileDialog(this); fileDlg->setFileMode(QFileDialog::AnyFile); fileDlg->setAcceptMode(mode); fileDlg->setWindowTitle(caption); fileDlg->setNameFilter(filter); if(dir.size()) { QString dirF = dir; fileDlg->selectFile(dirF.replace("\"","")); } #if QT_VERSION >= 0x040500 fileDlg->setOption(QFileDialog::ReadOnly, !winMenu()); #endif if(fileDlg->exec() && !fileDlg->selectedFiles().empty()) return fileDlg->selectedFiles()[0]; return ""; } void VisRun::closeEvent( QCloseEvent* ce ) { f_winClose = true; //Call for next processing by the events handler for the real closing after release all background requests if(host && host->inHostReq) { ce->ignore(); /*QCoreApplication::postEvent(this, new QCloseEvent());*/ return; } if(endRunTimer->isActive()) { //Save main window position if(winPosCntrSave() && masterPg()) { wAttrSet(masterPg()->id(), i2s(screen())+"geomX", i2s(pos().x()), true); wAttrSet(masterPg()->id(), i2s(screen())+"geomY", i2s(pos().y()), true); } //Exit on close last run project if(mod->exitLstRunPrjCls() && masterPg()) { unsigned winCnt = 0; for(int iW = 0; iW < QApplication::topLevelWidgets().size(); iW++) if(qobject_cast(QApplication::topLevelWidgets()[iW]) && QApplication::topLevelWidgets()[iW]->isVisible()) winCnt++; if(winCnt <= 1 && !qApp->property("closeToTray").toBool()) SYS->stop(); } endRunTimer->stop(); updateTimer->stop(); } ce->accept(); } void VisRun::resizeEvent( QResizeEvent *ev ) { if(masterPg()) { float x_scale_old = x_scale; float y_scale_old = y_scale; if(windowState()&(Qt::WindowMaximized|Qt::WindowFullScreen) || aFullScr()->isChecked()) { x_scale = (float)((QScrollArea*)centralWidget())->maximumViewportSize().width()/(masterPg()->sizeOrigF().width()*masterPg()->xScale()); y_scale = (float)((QScrollArea*)centralWidget())->maximumViewportSize().height()/(masterPg()->sizeOrigF().height()*masterPg()->yScale()); if(x_scale > 1 && x_scale < 1.02) x_scale = 1; if(y_scale > 1 && y_scale < 1.02) y_scale = 1; if(keepAspectRatio()) x_scale = y_scale = vmin(x_scale, y_scale); } else x_scale = y_scale = 1; if(x_scale_old != x_scale || y_scale_old != y_scale) fullUpdatePgs(); //Fit to the master page size if((x_scale_old != x_scale || y_scale_old != y_scale || !ev || !ev->oldSize().isValid()) && !(windowState()&(Qt::WindowMaximized|Qt::WindowFullScreen))) { #if QT_VERSION < 0x050000 QRect ws = QApplication::desktop()->availableGeometry(this); #else QRect ws = qApp->screens().size() ? qApp->screens()[0]->availableGeometry() : QRect(); #endif if(!ws.isNull()) resize(fmin(ws.width()-10,masterPg()->size().width()+(centralWidget()->parentWidget()->width()-centralWidget()->width())+5), fmin(ws.height()-10,masterPg()->size().height()+(centralWidget()->parentWidget()->height()-centralWidget()->height())+5)); } mess_debug(mod->nodePath().c_str(), _("Scale of the root page [%f:%f]."), x_scale, y_scale); } mWTime->setVisible(windowState()==Qt::WindowFullScreen); } void VisRun::endRunChk( ) { if(mod->endRun()) close(); } void VisRun::quitSt( ) { SYS->stop(); } void VisRun::print( ) { if(masterPg()) { //Check for the single and big document present for default the printing RunPageView *rpg; RunWdgView *rwdg; vector lst; for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) rpg->shapeList("Document",lst); if(lst.size() == 1 && (rwdg=findOpenWidget(lst[0])) && ((masterPg()->width()/vmax(1,rwdg->width())) < 2 || (masterPg()->height()/vmax(1,rwdg->height())) < 2)) printDoc(rwdg->id()); //Print master page else printPg(masterPg()->id()); } } void VisRun::printPg( const string &ipg ) { #ifndef QT_NO_PRINTER RunPageView *rpg; string pg = ipg; if(pgList.empty()) { QMessageBox::warning(this,_("Printing a page"),_("There is no page to print!")); return; } if(pg.empty() && pgList.size() == 1) pg = pgList[0]; if(pg.empty() && pgList.size() > 1) { //Make select page dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("print",NULL,true).c_str())) ico_t.load(":/images/print.png"); InputDlg sdlg(this, QPixmap::fromImage(ico_t), _("Select a page to print."), _("Printing a page"), false, false, lang().c_str()); sdlg.edLay()->addWidget(new QLabel(_("Pages:"),&sdlg), 2, 0); QComboBox *spg = new QComboBox(&sdlg); sdlg.edLay()->addWidget(spg, 2, 1); for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) spg->addItem((rpg->name()+" ("+pgList[iP]+")").c_str(),pgList[iP].c_str()); if(sdlg.exec() != QDialog::Accepted) return; pg = spg->itemData(spg->currentIndex()).toString().toStdString(); } //Find need page rpg = master_pg; if(rpg->id() != pg) rpg = findOpenPage(pg); if(!rpg) return; string pnm = rpg->name(); if(!prPg) prPg = new QPrinter(QPrinter::HighResolution); QPrintDialog dlg(prPg, this); dlg.setWindowTitle(QString(_("Printing the page: \"%1\" (%2)")).arg(pnm.c_str()).arg(pg.c_str())); if(dlg.exec() == QDialog::Accepted) { # if QT_VERSION >= 0x050300 QRect paperRect = prPg->pageLayout().fullRectPixels(prPg->resolution()), pgRect = prPg->pageLayout().paintRectPixels(prPg->resolution()); # else QRect paperRect = prPg->paperRect(), pgRect = prPg->pageRect(); # endif int fntSize = 35; QSize papl(2048, 2048*paperRect.height()/paperRect.width()); QSize pagl(papl.width()*pgRect.width()/paperRect.width(), papl.height()*pgRect.height()/paperRect.height()); QPainter painter; painter.begin(prPg); painter.setWindow(QRect(QPoint(),papl)); painter.setViewport(paperRect); //Draw image # if QT_VERSION >= 0x050000 QImage im = rpg->grab().toImage(); # else QImage im = QPixmap::grabWidget(rpg).toImage(); # endif im = im.scaled(QSize(vmin(im.width()*4,pagl.width()),vmin(im.height()*4,pagl.height()-2*fntSize)),Qt::KeepAspectRatio/*,Qt::SmoothTransformation*/); painter.drawImage((pagl.width()-im.width())/2,fntSize,im); //Draw notes painter.setPen(Qt::black); QFont fnt("Arial"); fnt.setPixelSize(fntSize-5); painter.setFont(fnt); painter.drawText(QRect(0,0,pagl.width(),fntSize),Qt::AlignLeft,QString(_("OpenSCADA project: \"%1\"")).arg(windowTitle())); painter.drawText(QRect(0,0,pagl.width(),fntSize),Qt::AlignRight,QString(_("User: \"%1\"")).arg(user().c_str())); painter.drawText(QRect(0,im.height()+fntSize,pagl.width(),fntSize),Qt::AlignLeft,(pnm+" ("+pg+")").c_str()); QDateTime dt; dt.setSecsSinceEpoch(time(NULL)); painter.drawText(QRect(0,im.height()+fntSize,pagl.width(),fntSize),Qt::AlignRight,dt.toString("d.MM.yyyy h:mm:ss")); painter.end(); } #endif } void VisRun::printDiag( const string &idg ) { #ifndef QT_NO_PRINTER RunWdgView *rwdg; string dg = idg; if(pgList.empty()) { QMessageBox::warning(this,_("Printing a diagram"),_("There is no page!")); return; } if(dg.empty()) { RunPageView *rpg; vector lst; for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) rpg->shapeList("Diagram", lst); if(lst.empty()) { QMessageBox::warning(this,_("Printing a diagram"),_("There is no diagram!")); return; } if(lst.size() == 1) dg = lst[0]; else { //Make select diagrams dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("print",NULL,true).c_str())) ico_t.load(":/images/print.png"); InputDlg sdlg(this, QPixmap::fromImage(ico_t), _("Select a diagram to print."), _("Printing a diagram"), false, false, lang().c_str()); sdlg.edLay()->addWidget(new QLabel(_("Diagrams:"),&sdlg), 2, 0); QComboBox *spg = new QComboBox(&sdlg); sdlg.edLay()->addWidget(spg, 2, 1); for(unsigned iL = 0; iL < lst.size(); iL++) if((rwdg=findOpenWidget(lst[iL]))) spg->addItem((rwdg->name()+" ("+lst[iL]+")").c_str(),lst[iL].c_str()); if(sdlg.exec() != QDialog::Accepted) return; dg = spg->itemData(spg->currentIndex()).toString().toStdString(); } } if(!(rwdg=findOpenWidget(dg))) return; string dgnm = rwdg->name(); if(!prDiag) prDiag = new QPrinter(QPrinter::HighResolution); QPrintDialog dlg(prDiag, this); dlg.setWindowTitle(QString(_("Printing the diagram: \"%1\" (%2)")).arg(dgnm.c_str()).arg(dg.c_str())); if(dlg.exec() == QDialog::Accepted) { # if QT_VERSION >= 0x050300 QRect paperRect = prDiag->pageLayout().fullRectPixels(prDiag->resolution()), pgRect = prDiag->pageLayout().paintRectPixels(prDiag->resolution()); # else QRect paperRect = prDiag->paperRect(), pgRect = prDiag->pageRect(); # endif int fntSize = 35; QSize papl(2048, 2048*paperRect.height()/paperRect.width()); QSize pagl(papl.width()*pgRect.width()/paperRect.width(), papl.height()*pgRect.height()/paperRect.height()); ShapeDiagram::ShpDt *sD = (ShapeDiagram::ShpDt*)rwdg->shpData; int elLine = sD->prms.size()/2+((sD->prms.size()%2)?1:0); QPainter painter; painter.begin(prDiag); painter.setWindow(QRect(QPoint(0,0),papl)); painter.setViewport(paperRect); //Draw image # if QT_VERSION >= 0x050000 QImage im = rwdg->grab().toImage(); # else QImage im = QPixmap::grabWidget(rwdg).toImage(); # endif im = im.scaled(QSize(vmin(im.width()*4,pagl.width()),vmin(im.height()*4,pagl.height()-(2+elLine)*fntSize)),Qt::KeepAspectRatio/*,Qt::SmoothTransformation*/); painter.drawImage((pagl.width()-im.width())/2,fntSize*2,im); //Draw notes painter.setPen(Qt::black); QFont fnt("Arial"); fnt.setPixelSize(fntSize-5); painter.setFont(fnt); QDateTime dt; dt.setSecsSinceEpoch(time(NULL)); painter.drawText(QRect(0,0,pagl.width(),fntSize*2),Qt::AlignLeft,QString(_("OpenSCADA project: \"%1\"\n%2 (%3)")).arg(windowTitle()).arg(dgnm.c_str()).arg(dg.c_str())); painter.drawText(QRect(0,0,pagl.width(),fntSize*2),Qt::AlignRight,QString(_("User: \"%1\"\n%2")).arg(user().c_str()).arg(dt.toString("d.MM.yyyy h:mm:ss"))); // Draw trend's elements XMLNode reqName("name"); for(unsigned iE = 0; iE < sD->prms.size(); iE++) { QPoint pnt((iE/elLine)*(pagl.width()/2),im.height()+fntSize*(2+iE%elLine)); if(sD->prms[iE].val().empty() || !sD->prms[iE].color().isValid()) continue; // Trend name request reqName.setAttr("path",sD->prms[iE].addr()+"/%2fserv%2fval"); if(cntrIfCmd(reqName,true) || reqName.text().empty()) reqName.setText(sD->prms[iE].addr()); painter.fillRect(QRect(pnt.x()+2,pnt.y()+2,fntSize-5,fntSize-5),QBrush(sD->prms[iE].color())); painter.drawRect(QRect(pnt.x()+2,pnt.y()+2,fntSize-5,fntSize-5)); painter.drawText(QRect(pnt.x()+fntSize,pnt.y(),pagl.width()/2,fntSize),Qt::AlignLeft, QString("%1 [%2...%3]").arg(reqName.text().c_str()).arg(sD->prms[iE].bordL()).arg(sD->prms[iE].bordU())); } painter.end(); } #endif } void VisRun::printDoc( const string &idoc ) { #ifndef QT_NO_PRINTER RunWdgView *rwdg; string doc = idoc; if(pgList.empty()) { QMessageBox::warning(this,_("Printing a document"),_("There is no page!")); return; } if(doc.empty()) { RunPageView *rpg; vector lst; for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) rpg->shapeList("Document",lst); if(lst.empty()) { QMessageBox::warning(this,_("Printing a document"),_("There is no document!")); return; } if(lst.size() == 1) doc = lst[0]; else { //Make select diagrams dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("print",NULL,true).c_str())) ico_t.load(":/images/print.png"); InputDlg sdlg(this, QPixmap::fromImage(ico_t), _("Select a document to print."), _("Printing a document"), false, false, lang().c_str()); sdlg.edLay()->addWidget(new QLabel(_("Document:"),&sdlg), 2, 0); QComboBox *spg = new QComboBox(&sdlg); sdlg.edLay()->addWidget(spg, 2, 1); for(unsigned iL = 0; iL < lst.size(); iL++) if((rwdg=findOpenWidget(lst[iL]))) spg->addItem((rwdg->name()+" ("+lst[iL]+")").c_str(),lst[iL].c_str()); if(sdlg.exec() != QDialog::Accepted) return; doc = spg->itemData(spg->currentIndex()).toString().toStdString(); } } if(!(rwdg=findOpenWidget(doc))) return; string docnm = rwdg->name(); if(!prDoc) prDoc = new QPrinter(QPrinter::HighResolution); QPrintDialog dlg(prDoc, this); dlg.setWindowTitle(QString(_("Printing the document: \"%1\" (%2)")).arg(docnm.c_str()).arg(doc.c_str())); if(dlg.exec() == QDialog::Accepted) ((ShapeDocument::ShpDt*)rwdg->shpData)->print(prDoc); #endif } void VisRun::exportDef( ) { if(master_pg) { //Check for the single and big document present for default the exporting RunPageView *rpg; RunWdgView *rwdg; vector lstDoc, lstDiagr, lstTbls; for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) { rpg->shapeList("Document", lstDoc); rpg->shapeList("Diagram", lstDiagr); rpg->shapeList("FormEl",lstTbls); //Getting only tables for(int iW = 0; iW < (int)lstTbls.size(); iW++) { if((rwdg=findOpenWidget(lstTbls[iW])) && qobject_cast(((ShapeFormEl::ShpDt*)rwdg->shpData)->addrWdg)) continue; lstTbls.erase(lstTbls.begin()+iW); iW--; } } if(lstDoc.size() == 1 && (rwdg=findOpenWidget(lstDoc[0])) && ((masterPg()->width()/vmax(1,rwdg->width())) < 2 || (masterPg()->height()/vmax(1,rwdg->height())) < 2)) exportDoc(rwdg->id()); else if(lstDiagr.size() == 1 && (rwdg=findOpenWidget(lstDiagr[0])) && ((masterPg()->width()/vmax(1,rwdg->width())) < 2 || (masterPg()->height()/vmax(1,rwdg->height())) < 2)) exportDiag(rwdg->id()); else if(lstTbls.size() == 1 && (rwdg=findOpenWidget(lstTbls[0])) && ((masterPg()->width()/vmax(1,rwdg->width())) < 2 || (masterPg()->height()/vmax(1,rwdg->height())) < 2)) exportTable(rwdg->id()); //Export the master page else exportPg(master_pg->id()); } } void VisRun::exportPg( const string &ipg ) { RunPageView *rpg; string pg = ipg; if(pgList.empty()) { QMessageBox::warning(this,_("Exporting a page"),_("There is no page for exporting!")); return; } if(pg.empty() && pgList.size() == 1) pg = pgList[0]; if(pg.empty() && pgList.size() > 1) { //Make select page dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("export",NULL,true).c_str())) ico_t.load(":/images/export.png"); InputDlg sdlg(this, QPixmap::fromImage(ico_t), _("Select a page to export."), _("Exporting a page"), false, false, lang().c_str()); sdlg.edLay()->addWidget(new QLabel(_("Pages:"),&sdlg), 2, 0); QComboBox *spg = new QComboBox(&sdlg); sdlg.edLay()->addWidget(spg, 2, 1); for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) spg->addItem((rpg->name()+" ("+pgList[iP]+")").c_str(),pgList[iP].c_str()); if(sdlg.exec() != QDialog::Accepted) return; pg = spg->itemData(spg->currentIndex()).toString().toStdString(); } //Find need page rpg = master_pg; if(rpg->id() != pg) rpg = findOpenPage(pg); if(!rpg) return; #if QT_VERSION >= 0x050000 QPixmap img = rpg->grab(); #else QPixmap img = QPixmap::grabWidget(rpg); #endif QString fn = getFileName(_("Saving the page image"), (rpg->name()+".png").c_str(), _("Images (*.png *.xpm *.jpg)"), QFileDialog::AcceptSave); if(fn.size() && !img.save(fn)) mod->postMess(mod->nodePath().c_str(), QString(_("Error saving to the file '%1'.")).arg(fn), TVision::Error, this); } void VisRun::exportDiag( const string &idg ) { RunWdgView *rwdg; string dg = idg; if(pgList.empty()) { QMessageBox::warning(this,_("Exporting a diagram"),_("There is no page!")); return; } if(dg.empty()) { RunPageView *rpg; vector lst; for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) rpg->shapeList("Diagram",lst); if(lst.empty()) { QMessageBox::warning(this,_("Exporting a diagram"),_("There is no diagram!")); return; } if(lst.size() == 1) dg = lst[0]; else { //Make select diagrams dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("print",NULL,true).c_str())) ico_t.load(":/images/export.png"); InputDlg sdlg(this, QPixmap::fromImage(ico_t), _("Select a diagram to export."), _("Exporting a diagram"), false, false, lang().c_str()); sdlg.edLay()->addWidget(new QLabel(_("Diagrams:"),&sdlg), 2, 0); QComboBox *spg = new QComboBox(&sdlg); sdlg.edLay()->addWidget(spg, 2, 1); for(unsigned iL = 0; iL < lst.size(); iL++) if((rwdg=findOpenWidget(lst[iL]))) spg->addItem((rwdg->name()+" ("+lst[iL]+")").c_str(),lst[iL].c_str()); if(sdlg.exec() != QDialog::Accepted) return; dg = spg->itemData(spg->currentIndex()).toString().toStdString(); } } if(!(rwdg=findOpenWidget(dg))) return; #if QT_VERSION >= 0x050000 QPixmap img = rwdg->grab(); #else QPixmap img = QPixmap::grabWidget(rwdg); #endif QString fileName = getFileName(_("Saving a diagram"), QString(_("Trend %1.png")).arg(expDiagCnt++), _("Images (*.png *.xpm *.jpg);;CSV file (*.csv)"), QFileDialog::AcceptSave); if(!fileName.isEmpty()) { // Export to CSV if(fileName.toStdString().rfind(".csv") == (fileName.toStdString().size()-4)) { // Open destination file int fd = open(fileName.toStdString().c_str(), O_WRONLY|O_CREAT|O_TRUNC, SYS->permCrtFiles()); if(fd < 0) { mod->postMess(mod->nodePath().c_str(),QString(_("Error saving to the file '%1'.")).arg(fileName),TVision::Error,this); return; } ShapeDiagram::ShpDt *dgDt = (ShapeDiagram::ShpDt*)rwdg->shpData; string CSVr; // Trend type process if(dgDt->type == 0) { int firstPrm = -1, vPos = 0; // Prepare header CSVr += _("\"Date and time\";\"us\""); for(unsigned iP = 0; iP < dgDt->prms.size(); iP++) if(dgDt->prms[iP].val().size() && dgDt->prms[iP].color().isValid()) { CSVr += ";\""+TSYS::path2sepstr(dgDt->prms[iP].addr())+"\""; if(firstPrm < 0) firstPrm = iP; } CSVr += "\x0D\x0A"; if(firstPrm < 0) return; // Place data deque &baseVls = dgDt->prms[firstPrm].val(); int64_t eTmVl = dgDt->tTime; int64_t bTmVl = eTmVl - 1e6*dgDt->tSize; for(unsigned i_v = 0; i_v < baseVls.size() && baseVls[i_v].tm <= eTmVl; i_v++) { if(baseVls[i_v].tm < bTmVl) continue; CSVr += atm2s(baseVls[i_v].tm/1000000, "\"%d/%m/%Y %H:%M:%S\"") + ";" + i2s(baseVls[i_v].tm%1000000); for(unsigned iP = 0; iP < dgDt->prms.size(); iP++) { ShapeDiagram::TrendObj &cPrm = dgDt->prms[iP]; if(cPrm.val().size() && cPrm.color().isValid()) { vPos = cPrm.val(baseVls[i_v].tm); CSVr = CSVr + ";"+((vPos < (int)cPrm.val().size())?((cPrm.val()[vPos].val!=EVAL_REAL)?QLocale().toString(cPrm.val()[vPos].val).toStdString():"\""+string(_("Empty"))+"\""):""); } } CSVr += "\x0D\x0A"; } } // Frequency spectrum type else if(dgDt->type == 1) { #if HAVE_FFTW3_H // Prepare header CSVr += _("\"Frequency (Hz)\""); for(unsigned iP = 0; iP < dgDt->prms.size(); iP++) if(dgDt->prms[iP].fftN && dgDt->prms[iP].color().isValid()) CSVr += ";\""+TSYS::path2sepstr(dgDt->prms[iP].addr())+"\""; CSVr += "\x0D\x0A"; // Place data int fftN = rwdg->size().width(); //Samples number double fftBeg = 1/dgDt->tSize; //Minimum frequency or maximum period time (s) double fftEnd = (double)fftN*fftBeg/2; //Maximum frequency or minimum period time (s) for(double i_frq = fftBeg; i_frq <= fftEnd; i_frq += fftBeg) { CSVr += QLocale().toString(i_frq).toStdString(); for(unsigned iP = 0; iP < dgDt->prms.size(); iP++) { ShapeDiagram::TrendObj &cPrm = dgDt->prms[iP]; if(cPrm.fftN && cPrm.color().isValid()) { int vpos = (int)((i_frq*cPrm.fftN)/(fftBeg*fftN)); double val = EVAL_REAL; if(vpos >= 1 && vpos < (cPrm.fftN/2+1)) val = cPrm.fftOut[0][0]/cPrm.fftN + pow(pow(cPrm.fftOut[vpos][0],2)+pow(cPrm.fftOut[vpos][1],2),0.5)/(cPrm.fftN/2+1); CSVr += ";"+QLocale().toString(val).toStdString(); } } CSVr += "\x0D\x0A"; } #endif } // Save to file bool fOK = (write(fd,CSVr.data(),CSVr.size()) == (int)CSVr.size()); if(::close(fd) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), fd, strerror(errno), errno); if(!fOK) mod->postMess(mod->nodePath().c_str(), QString(_("Error writing to: %1.")).arg(fileName), TVision::Error, this); } // Export to image else if(!img.save(fileName)) mod->postMess(mod->nodePath().c_str(),QString(_("Error saving to the file '%1'.")).arg(fileName),TVision::Error,this); } } void VisRun::exportDoc( const string &idoc ) { RunWdgView *rwdg; string doc = idoc; if(pgList.empty()) { QMessageBox::warning(this,_("Exporting a document"),_("There is no page!")); return; } if(doc.empty()) { RunPageView *rpg; vector lst; for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) rpg->shapeList("Document",lst); if(lst.empty()) { QMessageBox::warning(this,_("Exporting a document"),_("There is no document!")); return; } if(lst.size() == 1) doc = lst[0]; else { //Make select diagrams dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("print",NULL,true).c_str())) ico_t.load(":/images/export.png"); InputDlg sdlg(this, QPixmap::fromImage(ico_t), _("Select a document to export."), _("Exporting a document"), false, false, lang().c_str()); sdlg.edLay()->addWidget(new QLabel(_("Document:"),&sdlg), 2, 0); QComboBox *spg = new QComboBox(&sdlg); sdlg.edLay()->addWidget(spg, 2, 1); for(unsigned iL = 0; iL < lst.size(); iL++) if((rwdg=findOpenWidget(lst[iL]))) spg->addItem((rwdg->name()+" ("+lst[iL]+")").c_str(),lst[iL].c_str()); if(sdlg.exec() != QDialog::Accepted) return; doc = spg->itemData(spg->currentIndex()).toString().toStdString(); } } if(!(rwdg=findOpenWidget(doc))) return; QString fileName = getFileName(_("Saving a document"), QString(_("Document %1.html")).arg(expDocCnt++), _("XHTML (*.html);;CSV file (*.csv)"), QFileDialog::AcceptSave); if(!fileName.isEmpty()) { int fd = open(fileName.toStdString().c_str(), O_WRONLY|O_CREAT|O_TRUNC, SYS->permCrtFiles()); if(fd < 0) { mod->postMess(mod->nodePath().c_str(),QString(_("Error saving to the file '%1'.")).arg(fileName),TVision::Error,this); return; } string rez; // Export to CSV if(fileName.toStdString().rfind(".csv") == (fileName.toStdString().size()-4)) { // Parse document XMLNode docTree; docTree.load(((ShapeDocument::ShpDt*)rwdg->shpData)->doc, true); XMLNode *curNode = &docTree; vector treeStk; treeStk.push_back(0); while(curNode->parent() || treeStk.back() < curNode->childSize()) { if(treeStk.back() < curNode->childSize()) { curNode = curNode->childGet(treeStk.back()); treeStk.push_back(0); // Check for marked table and process it if(strcasecmp(curNode->name().c_str(),"table") != 0 || !s2i(curNode->attr("export"))) continue; map rowSpn; XMLNode *tblN = NULL, *tblRow; string val; for(int iSt = 0; iSt < 4; iSt++) { switch(iSt) { case 0: tblN = curNode->childGet("thead", 0, true); break; case 1: tblN = curNode->childGet("tbody", 0, true); break; case 2: tblN = curNode->childGet("tfoot", 0, true); break; case 3: tblN = curNode; break; default: tblN = NULL; } if(!tblN) continue; // Rows processing for(unsigned iN = 0; iN < tblN->childSize(); iN++) { if(strcasecmp(tblN->childGet(iN)->name().c_str(),"tr") != 0) continue; tblRow = tblN->childGet(iN); bool cellAllow = false; for(unsigned iC = 0, iCl = 0; iC < tblRow->childSize(); iC++) { if(!(strcasecmp(tblRow->childGet(iC)->name().c_str(),"th") == 0 || strcasecmp(tblRow->childGet(iC)->name().c_str(),"td") == 0)) continue; cellAllow = true; while(rowSpn[iCl] > 1) { rez += ";"; rowSpn[iCl]--; iCl++; } rowSpn[iCl] = s2i(tblRow->childGet(iC)->attr("rowspan",false)); val = tblRow->childGet(iC)->text(true,true); for(size_t iSz = 0; (iSz=val.find("\"",iSz)) != string::npos; iSz += 2) val.replace(iSz, 1, 2, '"'); rez += "\"" + sTrm(val) + "\";"; // Colspan process int colSpan = s2i(tblRow->childGet(iC)->attr("colspan",false)); for(int iCs = 1; iCs < colSpan; iCs++) rez += ";"; iCl++; } if(cellAllow) rez += "\x0D\x0A"; } } rez += "\x0D\x0A"; } curNode = curNode->parent(); treeStk.pop_back(); treeStk.back()++; } } // Export to XHTML else rez = ((ShapeDocument::ShpDt*)rwdg->shpData)->toHtml(); bool fOK = true; if(rez.empty()) mod->postMess(mod->nodePath().c_str(),QString(_("No data to export.")),TVision::Error,this); else fOK = (write(fd,rez.data(),rez.size()) == (int)rez.size()); if(::close(fd) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), fd, strerror(errno), errno); if(!fOK) mod->postMess(mod->nodePath().c_str(), QString(_("Error writing to: %1.")).arg(fileName), TVision::Error, this); } } void VisRun::exportTable( const string &itbl ) { RunWdgView *rwdg; QTableWidget *wdg; string tbl = itbl; if(pgList.empty()) { QMessageBox::warning(this,_("Exporting a table"),_("There is no page!")); return; } if(tbl.empty()) { RunPageView *rpg; vector lst; //Getting all FormEls for(unsigned iP = 0; iP < pgList.size(); iP++) if((rpg=findOpenPage(pgList[iP]))) rpg->shapeList("FormEl",lst); //Getting only tables for(int iW = 0; iW < (int)lst.size(); iW++) { if((rwdg=findOpenWidget(lst[iW])) && qobject_cast(((ShapeFormEl::ShpDt*)rwdg->shpData)->addrWdg)) continue; lst.erase(lst.begin()+iW); iW--; } //Specifying a source if(lst.empty()) { QMessageBox::warning(this,_("Exporting a table"),_("There is no table!")); return; } if(lst.size() == 1) tbl = lst[0]; else { //Make select diagrams dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("table",NULL,true).c_str())) ico_t.load(":/images/export.png"); InputDlg sdlg(this, QPixmap::fromImage(ico_t), _("Select a table to export."), _("Exporting a table"), false, false, lang().c_str()); sdlg.edLay()->addWidget(new QLabel(_("Table:"),&sdlg), 2, 0); QComboBox *spg = new QComboBox(&sdlg); sdlg.edLay()->addWidget(spg, 2, 1); for(unsigned iL = 0; iL < lst.size(); iL++) if((rwdg=findOpenWidget(lst[iL]))) spg->addItem((rwdg->name()+" ("+lst[iL]+")").c_str(),lst[iL].c_str()); if(sdlg.exec() != QDialog::Accepted) return; tbl = spg->itemData(spg->currentIndex()).toString().toStdString(); } } if(!(rwdg=findOpenWidget(tbl)) || !(wdg=qobject_cast(((ShapeFormEl::ShpDt*)rwdg->shpData)->addrWdg))) return; QString fileName = getFileName(_("Saving a table"), QString(_("Table %1.csv")).arg(expTblCnt++), _("CSV file (*.csv)"), QFileDialog::AcceptSave); if(!fileName.isEmpty()) { int fd = open(fileName.toStdString().c_str(), O_WRONLY|O_CREAT|O_TRUNC, SYS->permCrtFiles()); if(fd < 0) { mod->postMess(mod->nodePath().c_str(),QString(_("Error saving to the file '%1'.")).arg(fileName),TVision::Error,this); return; } string rez; //Export to CSV if(fileName.toStdString().rfind(".csv") == (fileName.toStdString().size()-4)) { QTableWidgetItem *tit; for(int iC = 0; iC < wdg->columnCount(); iC++) rez += "\""+((tit=wdg->horizontalHeaderItem(iC))?tit->text().toStdString():string(""))+"\";"; rez += "\x0D\x0A"; for(int iR = 0; iR < wdg->rowCount(); iR++) { for(int iC = 0; iC < wdg->columnCount(); iC++) { QVariant vl = (tit=wdg->item(iR,iC)) ? tit->data(Qt::DisplayRole) : QVariant(); if(!vl.isValid()) rez += ";"; else if(vl.typeId() == QVariant::String) rez += "\""+TSYS::strEncode(vl.toString().toStdString(),TSYS::SQL,"\"")+"\";"; else rez += vl.toString().toStdString()+";"; } rez += "\x0D\x0A"; } } bool fOK = true; if(rez.empty()) mod->postMess(mod->nodePath().c_str(),QString(_("No data to export.")),TVision::Error,this); else fOK = (write(fd,rez.data(),rez.size()) == (int)rez.size()); if(::close(fd) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), fd, strerror(errno), errno); if(!fOK) mod->postMess(mod->nodePath().c_str(), QString(_("Error writing to: %1.")).arg(fileName), TVision::Error, this); } } void VisRun::about( ) { TrCtxAlloc trCtx; if(Mess->translDyn()) trCtx.hold(user()+"\n"+lang()); QString mess = _("%1 v%2 on Qt v%12.\n%3\nAuthor: %4\nLicense: %5\n\n" "%6 v%7.\n%8\nLicense: %9\nAuthor: %10\nWeb site: %11"); #undef _ #define _(mess) Mess->I18N(mess, lang().c_str()).c_str() QMessageBox::about(this, windowTitle(), mess. arg(_(mod->modInfo("Name"))).arg(mod->modInfo("Version").c_str()).arg(_(mod->modInfo("Description"))). arg(_(mod->modInfo("Author"))).arg(mod->modInfo("License").c_str()). arg(PACKAGE_NAME).arg(VERSION).arg(_(PACKAGE_DESCR)).arg(PACKAGE_LICENSE).arg(_(PACKAGE_AUTHOR)).arg(PACKAGE_SITE). arg(QT_VERSION_STR)); #undef _ #define _(mess) mod->I18N(mess, lang().c_str()).c_str() } void VisRun::userChanged( const QString &oldUser, const QString &oldPass ) { //Try second connect to the session for permission check XMLNode req("connect"); req.setAttr("path","/%2fserv%2fsess")->setAttr("sess",workSess())->setAttr("userChange","1"); if(cntrIfCmd(req)) { mWUser->setUser(oldUser.toStdString()); mWUser->setPass(oldPass.toStdString()); mod->postMess(req.attr("mcat").c_str(), req.text().c_str(), TVision::Error, this); return; } if(req.attr("userIsRoot").size()) setWinMenu(s2i(req.attr("userIsRoot"))); else setWinMenu(SYS->security().at().access(user(),SEC_WR,"root","root",RWRWR_)); mConId = s2i(req.attr("conId")); req.clear()->setName("CntrReqs")->setAttr("path",""); req.childAdd("get")->setAttr("path","/ses_"+workSess()+"/%2fobj%2fcfg%2fstyle"); if(!cntrIfCmd(req)) setStyle(s2i(req.childGet(0)->text())); //Update pages after the user change pgCacheClear(); bool oldMenuVis = winMenu(); QApplication::processEvents(); if(masterPg()) { if(oldMenuVis != winMenu() && (windowState() == Qt::WindowMaximized || windowState() == Qt::WindowFullScreen)) { x_scale *= (float)((QScrollArea*)centralWidget())->maximumViewportSize().width()/(float)master_pg->size().width(); y_scale *= (float)((QScrollArea*)centralWidget())->maximumViewportSize().height()/(float)master_pg->size().height(); if(x_scale > 1 && x_scale < 1.05) x_scale = 1; if(y_scale > 1 && y_scale < 1.05) y_scale = 1; if(keepAspectRatio()) x_scale = y_scale = vmin(x_scale, y_scale); mess_debug(mod->nodePath().c_str(), _("Scale of the root page [%f:%f]."), x_scale, y_scale); } fullUpdatePgs(); messUpd(); //Resize resizeEvent(NULL); } } void VisRun::styleChanged( ) { //Get current style XMLNode req("set"); req.setAttr("path","/ses_"+work_sess+"/%2fobj%2fcfg%2fstyle")->setText(i2s(style())); if(cntrIfCmd(req)) { mod->postMess(req.attr("mcat").c_str(),req.text().c_str(),TVision::Error,this); return; } fullUpdatePgs(); pgCacheClear(); } void VisRun::aboutQt( ) { QMessageBox::aboutQt(this, mod->modInfo("Name").c_str()); } void VisRun::fullScreen( bool vl ) { setWindowState(vl?Qt::WindowFullScreen:Qt::WindowNoState); //!!!! But switching to the WindowMaximized is performed only through the WindowNoState if(!vl && s2i(SYS->cmdOpt("showWin"))) { QCoreApplication::processEvents(); setWindowState(Qt::WindowMaximized); } } void VisRun::enterWhatsThis( ) { QWhatsThis::enterWhatsThisMode(); } void VisRun::enterManual( ) { string findDoc = TUIS::docGet(sender()->property("doc").toString().toStdString()+"\n"+lang()); if(findDoc.size()) system(findDoc.c_str()); else QMessageBox::information(this, _("Manual"), QString(_("The manual '%1' was not found offline or online!")).arg(sender()->property("doc").toString())); } void VisRun::alarmAct( QAction *alrm ) { if(alrm == NULL) return; int quietance = 0; bool quietanceRet = false; string qwdg; if(alrm->objectName() == "alarmLev") quietance = 0xFF; else if(alrm->objectName().toStdString().compare(0,8,"alarmNtf") == 0) { quietanceRet = alrm->property("quietanceRet").toBool(); quietanceRet = quietanceRet && !alrm->isChecked(); quietance = s2i(alrm->objectName().toStdString().substr(8)); map::iterator iN = mNotify.find(quietance); if(!quietanceRet && iN != mNotify.end()) qwdg = iN->second->curQueueWdg(); quietance = (1< setAttr("tmpl", u2s(quietance))-> setAttr("ret", i2s(quietanceRet))-> setAttr("wdg", qwdg); cntrIfCmd(req); //Send event to master page if(master_pg) master_pg->attrSet("event", ("ws_"+alrm->objectName()).toStdString(), A_NO_ID, true); } void VisRun::usrStatus( const string &val, RunPageView *pg ) { UserItStBar *userSt; if(!pg) pg = masterPg(); if(!pg || pg != masterPg()) return; //Presence mark clean for(int iC = 0; iC < statusBar()->children().size(); iC++) if((userSt=qobject_cast(statusBar()->children().at(iC))) && userSt->objectName().indexOf("usr_") == 0) userSt->setProperty("usrStPresent", false); //Items list parse string iLn; for(int off = 0, lCnt = 0; (iLn=TSYS::strLine(val,0,&off)).size(); lCnt++) { // Parse line in the format: "{id}:{label}:{tip}:{color}:{ico} int offIt = 0; string itId = TSYS::strParse(iLn, 0, ":", &offIt), itLab = TSYS::strParse(iLn, 0, ":", &offIt), itTip = TSYS::strParse(iLn, 0, ":", &offIt), itColor = TSYS::strParse(iLn, 0, ":", &offIt), itIco = TSYS::strParse(iLn, 0, ":", &offIt); if(itTip.empty()) itTip = itId; if(itColor.empty()) itColor = "black"; // Try presence yet userSt = statusBar()->findChild(("usr_"+itId).c_str()); // Create new one if(!userSt) { userSt = new UserItStBar(this); userSt->setObjectName(("usr_"+itId).c_str()); userSt->setAlignment(Qt::AlignCenter); statusBar()->insertPermanentWidget(0, userSt); } // Set properties userSt->setProperty("usrStPresent", true); userSt->setProperty("usrStPos", lCnt); userSt->setToolTip(itTip.c_str()); QImage ico_t; if(!itIco.empty()) { itIco = pg->resGet(itIco); ico_t.loadFromData((const uchar*)itIco.data(), itIco.size()); if(!ico_t.isNull()) ico_t = ico_t.scaled(icoSize(2), icoSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation); } userSt->setPixmap(QPixmap::fromImage(ico_t)); if(itLab.size()) userSt->setText(QString("%2").arg(itColor.c_str()).arg(itLab.c_str())); } //Check for remove and order for(int iC = 0; iC < statusBar()->children().size(); iC++) if((userSt=qobject_cast(statusBar()->children().at(iC))) && userSt->objectName().indexOf("usr_") == 0) { if(!userSt->property("usrStPresent").toBool()) //delete userSt; userSt->deleteLater(); /*else for(int iC1 = iC; iC1 > 0 ; iC1--) { if(!(userSt1=qobject_cast(statusBar()->children().at(iC1-1))) || userSt1->objectName().indexOf("usr_") != 0) continue; if(userSt->property("usrStPos").toInt() < userSt1->property("usrStPos").toInt()) userSt1->stackUnder(userSt); }*/ } } void VisRun::initSess( const string &iprjSes_it, bool icrSessForce ) { bool isSess = false; string openPgs; src_prj = work_sess = ""; //Connect/create session int off = 0; if((src_prj=TSYS::pathLev(iprjSes_it,0,true,&off)).empty()) return; if(off > 0 && off < (int)iprjSes_it.size()) openPgs = iprjSes_it.substr(off); // Check for ready session connection or project if(src_prj.compare(0,4,"ses_") == 0) { work_sess = src_prj.substr(4); src_prj = ""; isSess = true; } else if(src_prj.compare(0,4,"prj_") == 0) src_prj.erase(0,4); else return; //Get opened sessions list for our page and put dialog for connection XMLNode req("list"); req.setAttr("path","/%2fserv%2fsess")->setAttr("prj",src_prj); if(!isSess && !icrSessForce && !cntrIfCmd(req) && req.childSize()) { // Prepare and execute a session selection dialog QImage ico_t; if(!ico_t.load(TUIS::icoGet("vision_prj_run",NULL,true).c_str())) ico_t.load(":/images/prj_run.png"); InputDlg conreq(this,QPixmap::fromImage(ico_t), QString(_("Several sessions are already opened for the project \"%1\".\n" "You can create a new or connect to the present session. Please select the one you want or click \"Cancel\".")).arg(src_prj.c_str()), _("Selecting a session for connection or a new one creating"), false, false, lang().c_str()); QListWidget *ls_wdg = new QListWidget(&conreq); conreq.edLay()->addWidget(ls_wdg, 0, 0); ls_wdg->addItem(_("")); for(unsigned iCh = 0; iCh < req.childSize(); iCh++) ls_wdg->addItem(req.childGet(iCh)->text().c_str()); ls_wdg->setCurrentRow(0); if(conreq.exec() == QDialog::Accepted && ls_wdg->currentItem()) work_sess = (ls_wdg->currentRow() > 0) ? ls_wdg->currentItem()->text().toStdString() : ""; else { close(); return; } } req.clear()->setName("connect")-> setAttr("path", "/%2fserv%2fsess")-> setAttr("conTm", i2s(mod->restoreTime()*1000)); //Initial for allow the project loading and //the session creation on the server side mostly/. if(work_sess.empty()) req.setAttr("prj", src_prj); else req.setAttr("sess", work_sess); if(cntrIfCmd(req)) { if(!(conErr && s2i(req.attr("rez")) == TError::Tr_Connect)) { //Need check for prevent the warning dialog and the run closing by the session creation wait mod->postMess(req.attr("mcat").c_str(), req.text().c_str(), TVision::Error, this); close(); } return; } if(req.attr("userIsRoot").size()) setWinMenu(s2i(req.attr("userIsRoot"))); else setWinMenu(SYS->security().at().access(user(),SEC_WR,"root","root",RWRWR_)); if(work_sess.empty()) work_sess = req.attr("sess"); if(src_prj.empty()) src_prj = req.attr("prj"); mConId = s2i(req.attr("conId")); bool toRestore = master_pg; if(openPgs.size()) openPgs = "/ses_"+work_sess+openPgs; if(toRestore) f_resizeManual = true; //Prepare group for parameters request and apply setWindowTitle(QString(_("Running project: %1")).arg(src_prj.c_str())); //Default title setWindowIcon(mod->icon()); req.clear()->setName("CntrReqs")->setAttr("path",""); req.childAdd("get")->setAttr("path","/prj_"+src_prj+"/%2fobj%2fcfg%2fname"); req.childAdd("get")->setAttr("path","/ses_"+work_sess+"/%2fico"); req.childAdd("get")->setAttr("path","/ses_"+work_sess+"/%2fobj%2fcfg%2fper"); req.childAdd("get")->setAttr("path","/ses_"+work_sess+"/%2fobj%2fcfg%2fstyle"); req.childAdd("get")->setAttr("path","/ses_"+work_sess+"/%2fobj%2fcfg%2fstLst"); //req.childAdd("get")->setAttr("path","/prj_"+src_prj+"/%2fobj%2fcfg%2fflgs"); //req.childAdd("openlist")->setAttr("path","/ses_"+work_sess+"/%2fserv%2fpg")->setAttr("tm","0")->setAttr("conId", i2s(mConId)); if(!cntrIfCmd(req)) { // Title XMLNode *pN = req.childGet(0); setWindowTitle(pN->text().c_str()); // Icon pN = req.childGet(1); QImage img; string simg = TSYS::strDecode(pN->text(), TSYS::base64); if(img.loadFromData((const uchar*)simg.data(),simg.size())) setWindowIcon(QPixmap::fromImage(img)); // Period pN = req.childGet(2); mPeriod = s2i(pN->text()); // Style pN = req.childGet(3); setStyle(s2i(pN->text())); pN = req.childGet(4); mStlBar->setVisible(style() >= 0 && pN->childSize() > 1); //if(style() < 0 && pN->childSize() <= 1) mStlBar->setVisible(false); // Clean up the previous pages for clean reconnection if(toRestore) { pgCacheClear(); openPgs = ""; for(unsigned iP = 0; iP < pgList.size(); iP++) { RunPageView *pg = master_pg->findOpenPage(pgList[iP]); if(pg) { pg->deleteLater(); openPgs += pgList[iP] + ";"; } } ((QScrollArea *)centralWidget())->takeWidget(); master_pg->deleteLater(); master_pg = NULL; focusWdf = ""; setXScale(1); setYScale(1); } // Open pages list //pN = req.childGet(5); pgList.clear(); /*for(unsigned iCh = 0; iCh < pN->childSize(); iCh++) { pgList.push_back(pN->childGet(iCh)->text()); callPage(pN->childGet(iCh)->text()); }*/ reqtm = 0; //strtoul(pN->attr("tm").c_str(), NULL, 10); //Open direct-selected page or openned before ones if(openPgs.size()) { req.clear()->setName("CntrReqs")->setAttr("path", "/ses_"+work_sess); string pIt; for(int off = 0; (pIt=TSYS::strParse(openPgs,0,";",&off)).size(); ) req.childAdd("open")->setAttr("path","/%2fserv%2fpg")->setAttr("pg",pIt); if(!cntrIfCmd(req)) openPgs = ""; } } //QCoreApplication::processEvents(); //Start timer updTmMax = planePer = 0; updateTimer->start(/*period()*/); } void VisRun::fullUpdatePgs( ) { f_resizeManual = true; for(unsigned iP = 0; iP < pgList.size(); iP++) { RunPageView *pg = master_pg->findOpenPage(pgList[iP]); if(pg) pg->update(true); } } string VisRun::lang( ) { return Mess->langCode(user(), true); //try { return SYS->security().at().usrAt(user()).at().lang(); } catch(...) { } //return ""; } void VisRun::messUpd( ) { qApp->setProperty("lang", lang().c_str()); //For the Qt internal messages translation //setWindowTitle(_("Vision runtime")); //Close actClose->setText(_("&Close")); actClose->setToolTip(_("Close the Vision window")); actClose->setWhatsThis(_("The button for closing the Vision runtime window")); actClose->setStatusTip(_("Press to close of the current Vision runtime window.")); //Quit actQuit->setText(_("&Quit")); actQuit->setToolTip(_("Quit the program")); actQuit->setWhatsThis(_("The button for complete quit the program")); actQuit->setStatusTip(_("Press for complete quit the program.")); //Full screen actFullScr->setText(_("Full screen")); actFullScr->setToolTip(_("Full screen mode toggling")); actFullScr->setWhatsThis(_("The button for full screen mode toggling")); actFullScr->setStatusTip(_("Press for toggling the full screen mode.")); //About actAbout->setText(_("&About")); actAbout->setToolTip(_("Program and OpenSCADA information")); actAbout->setWhatsThis(_("The button of the information of the program and OpenSCADA")); actAbout->setStatusTip(_("Press for information of the program and OpenSCADA.")); //About Qt actQtAbout->setText(_("About &Qt")); actQtAbout->setToolTip(_("Qt information")); actQtAbout->setWhatsThis(_("The button for getting the using Qt information")); actQtAbout->setStatusTip(_("Press for getting the using Qt information.")); //Menus menuFile.setTitle(_("&File")); menuAlarm.setTitle(_("&Alarm")); menuView.setTitle(_("&View")); menuHelp.setTitle(_("&Help")); //Menu "Print" menuPrint->setTitle(_("&Print")); menuPrint->menuAction()->setToolTip(_("Print the master page")); menuPrint->menuAction()->setWhatsThis(_("The button for printing the master page, by default")); menuPrint->menuAction()->setStatusTip(_("Press for printing the master page, by default.")); actPrintPg->setText(_("Page")); actPrintPg->setToolTip(_("Print the selected page")); actPrintPg->setWhatsThis(_("The button for printing the selected page")); actPrintPg->setStatusTip(_("Press for printing the selected page.")); actPrintDiag->setText(_("Diagram")); actPrintDiag->setToolTip(_("Print the selected diagram")); actPrintDiag->setWhatsThis(_("The button for printing the selected diagram")); actPrintDiag->setStatusTip(_("Press for printing the selected diagram.")); actPrintDoc->setText(_("Document")); actPrintDoc->setToolTip(_("Print the selected document")); actPrintDoc->setWhatsThis(_("The button for printing the selected document")); actPrintDoc->setStatusTip(_("Press for printing the selected document.")); //Menu "Export" menuExport->setTitle(_("&Export")); menuExport->menuAction()->setToolTip(_("Export the master page")); menuExport->menuAction()->setWhatsThis(_("The button for exporting the master page, by default")); menuExport->menuAction()->setStatusTip(_("Press for exporting the master page, by default.")); actExpPg->setText(_("Page")); actExpPg->setToolTip(_("Export the selected page")); actExpPg->setWhatsThis(_("The button for exporting the selected page")); actExpPg->setStatusTip(_("Press for exporting the selected page.")); actExpDiag->setText(_("Diagram")); actExpDiag->setToolTip(_("Export the selected diagram")); actExpDiag->setWhatsThis(_("The button for exporting the selected diagram")); actExpDiag->setStatusTip(_("Press for exporting the selected diagram.")); actExpDoc->setText(_("Document")); actExpDoc->setToolTip(_("Export the selected document")); actExpDoc->setWhatsThis(_("The button for exporting the selected document")); actExpDoc->setStatusTip(_("Press for exporting the selected document.")); actExpTable->setText(_("Table")); actExpTable->setToolTip(_("Export the selected table")); actExpTable->setWhatsThis(_("The button for exporting the selected table")); actExpTable->setStatusTip(_("Press for exporting the selected table.")); //Project's manual actProjManual->setText(QString(_("Project '%1' manual")).arg(srcProject().c_str())); actProjManual->setProperty("doc", srcProject().c_str()); actProjManual->setWhatsThis(QString(_("The button for getting the using project '%1' manual")).arg(srcProject().c_str())); actProjManual->setStatusTip(QString(_("Press for getting the using project '%1' manual.")).arg(srcProject().c_str())); //Module manual actManual->setText(QString(_("Manual on '%1'")).arg(mod->modId().c_str())); actManual->setProperty("doc", "Modules/Vision|Modules/Vision"); actManual->setWhatsThis(QString(_("The button for getting the using '%1' manual")).arg(mod->modId().c_str())); actManual->setStatusTip(QString(_("Press for getting the using '%1' manual.")).arg(mod->modId().c_str())); //OpenSCADA manual actManualSYS->setText(QString(_("Manual on '%1'")).arg(PACKAGE_STRING)); actManualSYS->setProperty("doc", "index|Documents"); actManualSYS->setWhatsThis(QString(_("The button for getting the using '%1' manual")).arg(PACKAGE_STRING)); actManualSYS->setStatusTip(QString(_("Press for getting the using '%1' manual.")).arg(PACKAGE_STRING)); //What is actWhatIs->setText(_("What's &This")); actWhatIs->setToolTip(_("The button for requesting the information about GUI elements")); actWhatIs->setWhatsThis(_("Requesting the information about GUI elements")); actWhatIs->setStatusTip(_("Press for requesting the information about GUI elements.")); //Alarm level display button and full alarms quietance actAlrmLev->setText(_("Alarm level")); actAlrmLev->setToolTip(_("Alarm level")); actAlrmLev->setWhatsThis(_("The button for quietance all alarms")); actAlrmLev->setStatusTip(_("Press for quietance all alarms.")); //Generic tools bar toolBarStatus->setWindowTitle(_("General (status)")); //Init status bar mWTime->setWhatsThis(_("This label shows the current system time.")); mWUser->setWhatsThis(_("This label displays the current user.")); mWUser->setToolTip(_("Field for displaying the current user.")); mWUser->setStatusTip(_("Double click to change the user.")); mWStat->setWhatsThis(_("This label displays the used VCA engine station.")); mWStat->setToolTip(_("Field for displaying the used VCA engine station.")); mStlBar->setWhatsThis(_("This label displays the used interface style.")); mStlBar->setToolTip(_("Field for displaying the used interface style.")); mStlBar->setStatusTip(_("Double click to change the style.")); //Style update setStyle(style()); } void VisRun::callPage( const string& pg_it, bool updWdg ) { vector idst; string stmp; //Scan and update opened page if(master_pg) { RunPageView *pg = master_pg->findOpenPage(pg_it); if(pg) { if(!(wPrcCnt%(5000/vmin(5000,period())))) pg->update(false, NULL, true); else if(updWdg) pg->update(false); return; } } //Placing all needed atrributes to one request XMLNode req("CntrReqs"), *chN; req.setAttr("path", pg_it); req.childAdd("get")->setAttr("path", "/%2fattr%2fpgGrp"); req.childAdd("get")->setAttr("path", "/%2fattr%2fpgOpenSrc"); // For per-page notification for(unsigned iNtf = 0; iNtf < 8; iNtf++) { req.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fnotifyVis"+mod->modId()+i2s(iNtf)); req.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fnotify"+i2s(iNtf)); } cntrIfCmd(req); //Get group and parent page string pgGrp = (chN=req.getElementBy("path","/%2fattr%2fpgGrp")) ? chN->text() : ""; //wAttrGet(pg_it, "pgGrp"); string pgSrc = (chN=req.getElementBy("path","/%2fattr%2fpgOpenSrc")) ? chN->text() : ""; //wAttrGet(pg_it, "pgOpenSrc"); //Check for master page replace if(!master_pg || pgGrp == "main" || pgGrp.empty() || master_pg->pgGrp() == pgGrp) { // Send close command if(master_pg) { XMLNode req("close"); req.setAttr("path","/ses_"+work_sess+"/%2fserv%2fpg")->setAttr("pg",master_pg->id()); cntrIfCmd(req); //!!!! Without the next rows the master page removing performs just in setWidget() of the scroll area ((QScrollArea*)centralWidget())->takeWidget(); master_pg->deleteLater(); } // Get and activate for specific attributes to the master-page XMLNode reqSpc("CntrReqs"); reqSpc.setAttr("path", pg_it); reqSpc.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2frunWin")-> setAttr("aNm", _("Running window"))-> setAttr("aTp", i2s(TFld::Integer))->setAttr("aFlg", i2s(TFld::Selectable))-> setAttr("aVls", "0;1;2")->setAttr("aNms", _("Original size;Maximize;Full screen")); reqSpc.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fkeepAspectRatio")-> setAttr("aNm", _("Keep aspect ratio on the scaling"))-> setAttr("aTp", i2s(TFld::Boolean))-> setText("1"); reqSpc.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fstBarNoShow")-> setAttr("aNm", _("Do not show the status bar"))-> setAttr("aTp", i2s(TFld::Boolean)); reqSpc.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fwinPosCntrSave")-> setAttr("aNm", _("Control and save window positions"))-> setAttr("aTp", i2s(TFld::Boolean)); reqSpc.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fstatLine"); reqSpc.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fuserSetVis"); reqSpc.childAdd("activate")->setAttr("path", "/%2fserv%2fattr%2fprjDoc"); cntrIfCmd(reqSpc); // Create widget view master_pg = new RunPageView(pg_it, this, centralWidget()); conErr = NULL; //possible a connection error status clean up focusWdf = ""; //master_pg->load(""); master_pg->setFocusPolicy(Qt::StrongFocus); ((QScrollArea *)centralWidget())->setWidget(master_pg); if(windowState()&(Qt::WindowFullScreen|Qt::WindowMaximized)) x_scale = y_scale = 1.0; resizeEvent(NULL); /*if(!(windowState()&(Qt::WindowFullScreen|Qt::WindowMaximized))) { QRect ws = QApplication::desktop()->availableGeometry(this); resize(vmin(master_pg->size().width()+10,ws.width()-10), vmin(master_pg->size().height()+55,ws.height()-10)); } else { x_scale = y_scale = 1.0; resizeEvent(NULL); }*/ } //Put to check for include else master_pg->callPage(pg_it, pgGrp, pgSrc); } void VisRun::pgCacheClear( ) { while(!cachePg.empty()) { cachePg.front()->deleteLater(); //delete cachePg.front(); cachePg.pop_front(); } } void VisRun::pgCacheAdd( RunPageView *wdg ) { if(!wdg) return; cachePg.push_front(wdg); while(mod->cachePgSz() && (int)cachePg.size() > mod->cachePgSz()) { cachePg.back()->deleteLater(); //delete cachePg.back(); cachePg.pop_back(); } } RunPageView *VisRun::pgCacheGet( const string &id ) { RunPageView *pg = NULL; for(unsigned iPg = 0; iPg < cachePg.size(); iPg++) if(cachePg[iPg]->id() == id) { pg = cachePg[iPg]; cachePg.erase(cachePg.begin()+iPg); break; } return pg; } RunPageView *VisRun::findOpenPage( const string &pg ) { if(!master_pg) return NULL; return master_pg->findOpenPage(pg); } RunWdgView *VisRun::findOpenWidget( const string &wdg ) { int woff = 0; for(int off = 0; true; woff = off) { string sel = TSYS::pathLev(wdg, 0, true, &off); if(sel.empty() || sel.find("wdg_") == 0) break; } RunPageView *rpg = findOpenPage(wdg.substr(0,woff)); if(!rpg) return NULL; if(woff >= (int)wdg.size()) return rpg; return rpg->findOpenWidget(wdg); } string VisRun::wAttrGet( const string &path, const string &attr, bool sess ) { XMLNode req("get"); if(sess) req.setAttr("path",path+"/%2fserv%2fattrSess%2f"+attr); else req.setAttr("path",path+"/%2fattr%2f"+attr); return cntrIfCmd(req) ? "" : req.text(); } bool VisRun::wAttrSet( const string &path, const string &attr, const string &val, bool sess ) { XMLNode req("set"); if(sess) req.setAttr("path",path+"/%2fserv%2fattrSess%2f"+attr)->setText(val); else req.setAttr("path",path+"/%2fserv%2fattr")-> childAdd("el")->setAttr("id",attr)->setText(val); return !cntrIfCmd(req); } void VisRun::alarmSet( unsigned alarm ) { unsigned ch_tp = alarm^mAlrmSt; //Check for early this session running equalent project bool isMaster = true; MtxAlloc res(mod->dataRes(), true); for(unsigned iW = 0; iW < mod->mnWinds.size(); iW++) if(qobject_cast(mod->mnWinds[iW]) && ((VisRun*)mod->mnWinds[iW])->srcProject() == srcProject()) { if(((VisRun*)mod->mnWinds[iW])->workSess() != workSess()) isMaster = false; break; } res.unlock(); //Set notify to the alarm for(map::iterator iN = mNotify.begin(); isMaster && iN != mNotify.end(); ++iN) iN->second->ntf(alarm); for(int iAl = 0; iAl < menuAlarm.actions().size(); ++iAl) { QAction *cO = menuAlarm.actions()[iAl]; if(!cO || cO->objectName().toStdString().compare(0,8,"alarmNtf") != 0) continue; unsigned nTp = s2i(cO->objectName().toStdString().substr(8)); bool newSt; if((ch_tp>>8)&(1<>8)&(1<isVisible()) cO->setVisible(newSt); if((ch_tp>>16)&(1<>16)&(1<property("quietanceRet").toBool() && !newSt != cO->isChecked()) cO->setChecked(!newSt); if(!cO->property("quietanceRet").toBool() && newSt != cO->isEnabled()) cO->setEnabled(newSt); } } //Alarm action indicators update // Alarm level icon update if(ch_tp&0xFF || (alarm>>16)&ntfSet /*|| (alarm>>16)&(TVision::Light|TVision::Alarm|TVision::Sound)*/ || !alrLevSet) { int alarmLev = alarm&0xFF; actAlrmLev->setToolTip(QString(_("Alarm level: %1")).arg(alarmLev)); QImage lens(":/images/alarmLev.png"); QImage levImage(lens.size(), lens.format()); QPainter painter(&levImage); //QColor lclr( alarmLev ? 224 : 0, alarmLev ? 224-(int)(0.87*alarmLev) : 224, 0 ); QColor lclr(alarmLev ? 255 : 0, alarmLev ? 255-alarmLev : 255, 0); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.fillRect(levImage.rect(),Qt::transparent); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); if(!((alarm>>16)&ntfSet && alrLevSet)) { for(int iX = 0; iX < lens.size().width(); iX++) for(int iY = 0; iY < lens.size().height(); iY++) if(lens.pixel(iX,iY)&0xFF000000) levImage.setPixel(iX, iY, lclr.rgba()); alrLevSet = true; } else alrLevSet = false; painter.drawImage(0, 0, lens); painter.end(); actAlrmLev->setIcon(QPixmap::fromImage(levImage)); } mAlrmSt = alarm; } void VisRun::ntfReg( int8_t tp, const string &props, const string &pgCrtor, bool prior ) { if(tp < 0) { for(unsigned iNtf = 0; iNtf < 8; iNtf++) ntfReg(iNtf, props, pgCrtor, prior); return; } vector pgPropsQ; //Searching for the presented notification type map::iterator iN = mNotify.find(tp); if(iN != mNotify.end()) { if(pgCrtor == iN->second->pgCrtor() && (props == iN->second->props() || !prior)) return; pgPropsQ = iN->second->pgPropsQ; if(pgCrtor != iN->second->pgCrtor()) { // Check the queue for the page already here for(vector::iterator iQ = iN->second->pgPropsQ.begin(); iQ != iN->second->pgPropsQ.end(); ++iQ) if(TSYS::strLine(*iQ,0) == pgCrtor) { if(props.empty()) iN->second->pgPropsQ.erase(iQ); else *iQ = pgCrtor + "\n" + props; return; } if(props.empty()) return; pgPropsQ.push_back(iN->second->pgProps); } delete iN->second; mNotify.erase(iN); ntfSet &= ~(1<pgPropsQ = pgPropsQ; ntfSet |= (1<::iterator ires = mCacheRes.find(res); if(ires == mCacheRes.end()) return ""; ires->second.tm = SYS->sysTm(); return ires->second.val; } void VisRun::cacheResSet( const string &res, const string &val ) { if(val.size() > limUserFile_SZ) return; mCacheRes[res] = CacheEl(SYS->sysTm(), val); if(mCacheRes.size() > (limCacheIts_N+limCacheIts_N/10)) { vector< pair > sortQueue; for(map::iterator itr = mCacheRes.begin(); itr != mCacheRes.end(); ++itr) sortQueue.push_back(pair(itr->second.tm,itr->first)); sort(sortQueue.begin(), sortQueue.end()); for(unsigned i_del = 0; i_del < (limCacheIts_N/10); ++i_del) mCacheRes.erase(sortQueue[i_del].second); } } void VisRun::updatePage( ) { if(f_winClose || f_updPage) return; int rez; int64_t d_cnt = TSYS::curTime(); f_updPage = true; //Pages update XMLNode req("openlist"); req.setAttr("tm", u2s(reqtm))->setAttr("conId", i2s(mConId))-> setAttr("path", "/ses_"+work_sess+"/%2fserv%2fpg"); if(!(rez=cntrIfCmd(req,false,true))) { // Check for delete the pages RunPageView *pg; for(unsigned iP = 0, iCh; iP < pgList.size(); iP++) { for(iCh = 0; iCh < req.childSize(); iCh++) if(pgList[iP] == req.childGet(iCh)->text()) break; if(iCh < req.childSize() || !(master_pg && (pg=master_pg->findOpenPage(pgList[iP])))) continue; if(!pg->property("cntPg").toString().isEmpty()) ((RunWdgView*)TSYS::str2addr(pg->property("cntPg").toString().toStdString()))->setPgOpenSrc(""); else { if(pg != master_pg) { if(pg->isWindow()) pg->close(); pg->deleteLater(); } else { ((QScrollArea*)centralWidget())->setWidget(new QWidget()); master_pg = NULL; conErr = NULL; //possible a connection error status clean up focusWdf = ""; } } } // Process the opened pages pgList.clear(); for(unsigned iCh = 0, iCh2 = 0; iCh < req.childSize(); ++iCh) { XMLNode *chN = req.childGet(iCh); pgList.push_back(chN->text()); // Detection the double container pages and opening the last one if(chN->attr("pgGrp").size() && chN->attr("pgGrp") != "main" && chN->attr("pgGrp") != "fl") { for(iCh2 = iCh+1; iCh2 < req.childSize(); ++iCh2) if(req.childGet(iCh2)->attr("pgGrp") == chN->attr("pgGrp")) break; if(iCh2 < req.childSize()) { // Force closing lost opened and included pages XMLNode reqClose("close"); reqClose.setAttr("path","/ses_"+workSess()+"/%2fserv%2fpg")->setAttr("pg", chN->text()); cntrIfCmd(reqClose); continue; } } // Opening callPage(chN->text(), s2i(chN->attr("updWdg"))); } } // Restore closed session of used project. else if(rez == 2) { mess_warning(mod->nodePath().c_str(),_("Restore the session creation for '%s'."),prjSes_it.c_str()); updateTimer->stop(); initSess(prjSes_it, crSessForce); f_updPage = false; return; } reqtm = strtoul(req.attr("tm").c_str(),NULL,10); //Alarms update (0.5 second update) if((alrmUpdCnt+=1e-3*planePer) > TM_ALRM_UPD) { alrmUpdCnt = 0; // Get the alarm status unsigned wAlrmSt = alarmSt(); req.clear()-> setName("get")-> setAttr("mode", "stat")-> setAttr("path", "/ses_"+work_sess+"/%2fserv%2falarm"); if(!cntrIfCmd(req,false,true)) wAlrmSt = s2i(req.attr("alarmSt")); // Set the alarm alarmSet(wAlrmSt); } //Calc the planed executing period to correct the main one float updTm = 1e-3*(TSYS::curTime()-d_cnt); updTmMax = vmax(updTmMax, updTm); if(!planePer) planePer = period(); planePer += (vmax(period(),updTm*3)-planePer)/100; if(mess_lev() == TMess::Debug) mess_debug(mod->nodePath().c_str(), _("Time of the session updating '%s': %s[%s]ms. Planer period %s(%s)ms"), workSess().c_str(), tm2s(1e-3*updTm).c_str(), tm2s(1e-3*updTmMax).c_str(), tm2s(1e-3*planePer).c_str(), tm2s(1e-3*period()).c_str()); updateTimer->start(vmax(0,planePer-updTm)); //Removing from the cache for old pages for(unsigned iPg = 0; iPg < cachePg.size(); ) if(mod->cachePgLife() > 0.01 && (period()*(reqTm()-cachePg[iPg]->reqTm())/1000) > (unsigned)(mod->cachePgLife()*60*60)) { cachePg[iPg]->deleteLater(); //delete cachePg[iPg]; cachePg.erase(cachePg.begin()+iPg); } else iPg++; //Time update if(mWTime->isVisible() && !(wPrcCnt%vmax(1000/vmin(1000,period()),1))) { QDateTime dtm = QDateTime::currentDateTime(); mWTime->setText(locale().toString(dtm,"hh:mm:ss\nddd, d MMM")); mWTime->setToolTip(locale().toString(dtm,"dddd, dd-MMM-yyyy")); } //Scale for full screen check if(centralWidget() && master_pg && !(wPrcCnt%vmax(1000/vmin(1000,period()),1)) && (windowState() == Qt::WindowMaximized || windowState() == Qt::WindowFullScreen)) { float xSc = (float)((QScrollArea*)centralWidget())->maximumViewportSize().width()/(float)master_pg->size().width(); float ySc = (float)((QScrollArea*)centralWidget())->maximumViewportSize().height()/(float)master_pg->size().height(); if(xSc < 1 || ySc < 1) { x_scale *= xSc; y_scale *= ySc; //Proportional scale if(keepAspectRatio()) x_scale = y_scale = vmin(x_scale,y_scale); fullUpdatePgs(); } } wPrcCnt++; f_updPage = f_resizeManual = false; } #undef _ #define _(mess) mod->I18N(mess, owner()->lang().c_str()).c_str() //* Notify: Generic notifying object. * //************************************************ VisRun::Notify::Notify( uint8_t itp, const string &ipgProps, VisRun *iown, bool isPriorProc ) : pgProps(ipgProps), tp(itp), alSt(0/*xFFFFFFFF*/), //!!!!: 0 - to notify the active alarms at the start from the procedures, also as for Phonon repDelay(-1), comIsExtScript(false), f_notify(false), f_resource(false), f_queue(false), f_quietanceRet(false), toDo(false), alEn(false), delay(0), queueCurTm(0), dataM(true), mOwner(iown), actAlrm(NULL), ntfPlay(NULL) { //Parsing the properties string iLn, iOpt, ico, name, iProps = props(); bool hasLang = false, hasFlags = false; for(int off = 0, lCnt = 0, fPos; (!hasLang || !hasFlags || ico.empty() || name.empty()) && (iLn=TSYS::strLine(iProps,0,&off)).size(); lCnt++) if(!hasLang && !lCnt && iLn.find("#!") == 0) { hasLang = comIsExtScript = true; continue; } else if(!hasFlags && (size_t)(fPos=iLn.find("flags=")) != string::npos) { for(fPos += 6; (iOpt=TSYS::strParse(iLn,0,"|",&fPos)).size(); ) if(iOpt.compare(0,6,"notify") == 0) { f_notify = true; repDelay = (iOpt.size() > 6) ? vmax(0,vmin(100,atoi(iOpt.c_str()+6))) : -1; } else if(iOpt == "resource") f_resource = true; else if(iOpt == "queue") { f_queue = true; if(repDelay < 0) repDelay = 0; } else if(iOpt == "quietanceRet") f_quietanceRet = true; hasFlags = true; } else if(ico.empty() && (size_t)(fPos=iLn.find("ico=")) != string::npos) ico = iLn.substr(fPos+4); else if(name.empty() && (size_t)(fPos=iLn.find("name=")) != string::npos) name = iLn.substr(fPos+5); #if HAVE_MULTIMEDIA || HAVE_PHONON if(f_notify && (f_queue || f_resource) && !isPriorProc) # if HAVE_MULTIMEDIA ntfPlay = new QMediaPlayer; # elif HAVE_PHONON ntfPlay = new VideoPlayer(Phonon::MusicCategory); # endif #endif //The command procedure prepare if(comIsExtScript) { // Prepare the external script comProc = "sesRun_"+owner()->workSess()+"_ntf"+i2s(tp); bool fOK = false; int hd = open(comProc.c_str(), O_CREAT|O_TRUNC|O_WRONLY, SYS->permCrtFiles(true)); if(hd >= 0) { fOK = write(hd, props().data(), props().size()) == (ssize_t)props().size(); if(::close(hd) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), hd, strerror(errno), errno); } if(!fOK) { mess_err((mod->nodePath()+"/sesRun_"+owner()->workSess()).c_str(), _("Error function of the notificator '%s': %s"), comProc.c_str(), strerror(errno)); comProc = ""; } } else { // Prepare an internal procedure TFunction funcIO("sesRun_"+owner()->workSess()+"_ntf"+i2s(tp)); //funcIO.setStor(DB()); funcIO.ioIns(new IO("en",trS("Enabled notification"),IO::Boolean,IO::Default), IFA_en); funcIO.ioIns(new IO("doNtf",trS("Performing the notification, always 1"),IO::Boolean,IO::Default), IFA_doNtf); funcIO.ioIns(new IO("doRes",trS("Making the resource, always 0"),IO::Boolean,IO::Default), IFA_doRes); funcIO.ioIns(new IO("res",trS("Resource stream"),IO::String,IO::Output), IFA_res); funcIO.ioIns(new IO("mess",trS("Notification message"),IO::String,IO::Default), IFA_mess); funcIO.ioIns(new IO("lang",trS("Language of the notification message"),IO::String,IO::Default), IFA_lang); funcIO.ioIns(new IO("resTp",trS("Resource stream type"),IO::String,IO::Return), IFA_resTp); funcIO.ioIns(new IO("prcID",trS("Procedure ID"),IO::String,IO::Default), IFA_prcID); try { comProc = SYS->daq().at().at("JavaLikeCalc").at().compileFunc("JavaScript", funcIO, props()); } catch(TError &er) { mess_err((mod->nodePath()+"/sesRun_"+owner()->workSess()).c_str(), _("Error function of the notificator '%s': %s"), funcIO.id().c_str(), er.mess.c_str()); } } if(f_notify && !ntfPlay) { //Call conditional variable init pthread_cond_init(&callCV, NULL); //Notification task create SYS->taskCreate(mod->nodePath('.',true)+".sesRun_"+owner()->workSess()+".ntf"+i2s(tp), 0, VisRun::Notify::Task, this); } //The quietance action prepare and place QImage ico_t; if(!ico.empty()) { ico = owner()->masterPg()->resGet(ico); ico_t.loadFromData((const uchar*)ico.data(), ico.size()); } if(ico_t.isNull() && !ico_t.load(TUIS::icoGet("alarmAlarm",NULL,true).c_str())) ico_t.load(":/images/alarmAlarm.png"); if(name.empty()) name = TSYS::strMess(_("Notificator %d"), tp); actAlrm = new QAction(QPixmap::fromImage(ico_t), name.c_str(), owner()); actAlrm->setObjectName(("alarmNtf"+i2s(tp)).c_str()); //actAlrm->setToolTip(_("Blink alarm")); if(f_queue) { actAlrm->setWhatsThis(QString(_("The button for quietance the current \"%1\"")).arg(name.c_str())); actAlrm->setStatusTip(QString(_("Press for quietance the current \"%1\".")).arg(name.c_str())); } else { actAlrm->setWhatsThis(QString(_("The button for quietance all \"%1\"")).arg(name.c_str())); actAlrm->setStatusTip(QString(_("Press for quietance all \"%1\".")).arg(name.c_str())); } actAlrm->setProperty("quietanceRet", (bool)f_quietanceRet); actAlrm->setCheckable(f_quietanceRet); owner()->menuAlarm.addAction(actAlrm); owner()->toolBarStatus->addAction(actAlrm); //Apply to the current alarm status actAlrm->setVisible((owner()->alarmSt()>>8)&(1<setChecked(!((owner()->alarmSt()>>16)&(1<setEnabled((owner()->alarmSt()>>16)&(1<cntrIter("UI:Vision:Notify", 1); } VisRun::Notify::~Notify( ) { if(f_notify && !ntfPlay) { SYS->taskDestroy(mod->nodePath('.',true)+".sesRun_"+owner()->workSess()+".ntf"+i2s(tp), NULL, 60, false, &callCV); pthread_cond_destroy(&callCV); } #if HAVE_MULTIMEDIA || HAVE_PHONON if(ntfPlay) { delete ntfPlay; ntfPlay = NULL; } #endif //The resource file remove if(resFile.size()) remove(resFile.c_str()); //The command procedure remove if(comIsExtScript && comProc.size()) remove(comProc.c_str()); //The quietance action remove if(actAlrm) actAlrm->deleteLater(); actAlrm = NULL; if(mess_lev() == TMess::Debug) SYS->cntrIter("UI:Vision:Notify", -1); } string VisRun::Notify::pgCrtor( ) { return TSYS::strLine(pgProps, 0); } string VisRun::Notify::props( ) { int off = 0; TSYS::strLine(pgProps, 0, &off); return pgProps.substr(off); } string VisRun::Notify::curQueueWdg( ) { if(!hasQueue()) return ""; pthread_mutex_lock(&dataM.mtx()); string rez = queueCurPath; pthread_mutex_unlock(&dataM.mtx()); return rez; } void VisRun::Notify::ntf( int ialSt ) { alEn = (bool)((ialSt>>16)&(1<state(); bool plSt = (mSt == QMediaPlayer::PlayingState); if(!alEn && !((QMediaPlayer*)ntfPlay)->currentMedia().isNull()) ((QMediaPlayer*)ntfPlay)->setMedia(QMediaContent()); else if(alEn && (((QMediaPlayer*)ntfPlay)->currentMedia().isNull() || # else QMediaPlayer::PlaybackState mSt = ((QMediaPlayer*)ntfPlay)->playbackState(); bool plSt = (mSt == QMediaPlayer::PlayingState); if(!alEn && ((QMediaPlayer*)ntfPlay)->mediaStatus() != QMediaPlayer::NoMedia) ((QMediaPlayer*)ntfPlay)->setSource(QUrl()); else if(alEn && (((QMediaPlayer*)ntfPlay)->mediaStatus() == QMediaPlayer::NoMedia || # endif # elif HAVE_PHONON State mSt = ((VideoPlayer*)ntfPlay)->mediaObject()->state(); bool plSt = (mSt == LoadingState || mSt == BufferingState || mSt == PlayingState); if(!alEn && ((VideoPlayer*)ntfPlay)->mediaObject()->currentSource().type() != MediaSource::Empty) ((VideoPlayer*)ntfPlay)->load(MediaSource()); else if(alEn && (((VideoPlayer*)ntfPlay)->mediaObject()->currentSource().type() == MediaSource::Empty || # endif (repDelay >= 0 && !plSt && (delay-=vmax(TM_ALRM_UPD,1e-3*owner()->planePer)) <= 0))) { string nRes, nResTp, nMess, nLang; nRes = ntfRes(nResTp, nMess, nLang); commCall(nRes, nResTp, nMess, nLang); delay = repDelay; } return; } else #endif //Check for the alarm state change if(f_notify && (((ialSt^alSt)>>16)&(1<workSess()+"/%2fserv%2falarm")-> setAttr("mode", "resource")-> setAttr("tp", i2s(tp))-> setAttr("tm", u2s(queueCurTm))-> setAttr("wdg", queueCurPath); //if(!owner()->cntrIfCmd(req)) { if(!mod->cntrIfCmd(req,owner()->user(),owner()->password(),owner()->VCAStation())) { queueCurTm = strtoul(req.attr("tm").c_str(), NULL, 10); queueCurPath = req.attr("wdg"); rez = TSYS::strDecode(req.text(), TSYS::base64); mess = req.attr("mess"); lang = req.attr("lang"); resTp = req.attr("resTp"); } return rez; } void VisRun::Notify::commCall( string &res, string &resTp, const string &mess, const string &lang ) { if(comProc.empty()) return; //Shared data obtain pthread_mutex_lock(&dataM.mtx()); string wcomProc = comProc; pthread_mutex_unlock(&dataM.mtx()); //Loading the resource if(ntfPlay || comIsExtScript) { resFile = "sesRun_"+owner()->workSess()+"_res"+i2s(tp); int hdRes = res.size() ? open(resFile.c_str(), O_CREAT|O_TRUNC|O_WRONLY, SYS->permCrtFiles()) : -1; if(hdRes >= 0) { write(hdRes, res.data(), res.size()); if(::close(hdRes) != 0) mess_warning(mod->nodePath().c_str(), _("Closing the file %d error '%s (%d)'!"), hdRes, strerror(errno), errno); } else resFile = ""; } //Playing by an internal mechanism (Phonon) #if HAVE_MULTIMEDIA if(ntfPlay) { QMediaPlayer *player = (QMediaPlayer*)ntfPlay; # if QT_VERSION >= 0x060000 if(!player->audioOutput()) player->setAudioOutput(new QAudioOutput); # endif player->setSource(QUrl::fromLocalFile(QDir::currentPath()+"/"+resFile.c_str())); player->play(); } else #elif HAVE_PHONON if(ntfPlay) ((VideoPlayer*)ntfPlay)->play(MediaSource(QUrl::fromLocalFile(QDir::currentPath()+"/"+resFile.c_str()))); else #endif //Call external procedures if(comIsExtScript) // Prepare environment and execute the external script system(("prcID=sesRun_"+owner()->workSess()+"_ntf"+i2s(tp)+" en="+i2s(alEn)+" doNtf=1 doRes=0 res="+resFile+" resTp="+resTp+ " mess=\""+TSYS::strEncode(mess,TSYS::ShieldSymb,"\"")+"\" lang=\""+TSYS::strEncode(lang,TSYS::ShieldSymb,"\"")+"\" ./"+wcomProc).c_str()); else { // Prepare and execute internal procedure TValFunc funcV; funcV.setFunc(&((AutoHD)SYS->nodeAt(wcomProc)).at()); // Load inputs funcV.setB(IFA_en, alEn); funcV.setB(IFA_doNtf, true); funcV.setB(IFA_doRes, false); funcV.setS(IFA_res, res); funcV.setS(IFA_mess, mess); funcV.setS(IFA_lang, lang); funcV.setS(IFA_resTp, resTp); funcV.setS(IFA_prcID, "sesRun_"+owner()->workSess()+"_ntf"+i2s(tp)); // Call to processing funcV.calc(); } } void *VisRun::Notify::Task( void *intf ) { VisRun::Notify &ntf = *(VisRun::Notify*)intf; pthread_mutex_lock(&ntf.dataM.mtx()); while(!TSYS::taskEndRun() || ntf.toDo) { if(!ntf.toDo) pthread_cond_wait(&ntf.callCV, &ntf.dataM.mtx()); if(!ntf.toDo || ntf.comProc.empty()) { ntf.toDo = false; continue; } ntf.toDo = false; pthread_mutex_unlock(&ntf.dataM.mtx()); string ntfRes, ntfResTp, ntfMess, ntfLang; unsigned delayCnt = 0; do { if(delayCnt) { TSYS::sysSleep(1); delayCnt--; continue; } // Geting the resources of the notification if((ntf.f_queue || ntf.f_resource) && ntf.alEn) ntfRes = ntf.ntfRes(ntfResTp, ntfMess, ntfLang); // Same notification ntf.commCall(ntfRes, ntfResTp, ntfMess, ntfLang); delayCnt = ntf.repDelay; } while((ntf.repDelay >= 0 || ntf.f_queue) && ntf.alEn && !TSYS::taskEndRun()); pthread_mutex_lock(&ntf.dataM.mtx()); } pthread_mutex_unlock(&ntf.dataM.mtx()); return NULL; } //*********************************************** // SHost - Host thread's control object * SCADAHost::SCADAHost( QObject *p ) : QThread(p), inHostReq(0), endRun(false), reqDone(false), glob(false), req(NULL), done(NULL), pid(0) { } SCADAHost::~SCADAHost( ) { endRun = true; while(!wait(100)) sendSIGALRM(); } void SCADAHost::sendSIGALRM( ) { if(pid) pthread_kill(pid, SIGALRM); } bool SCADAHost::reqDo( XMLNode &node, bool &idone, bool iglob ) { if(req) return false; //Set the request mtx.lock(); reqDone = false; glob = iglob; req = &node; done = &idone; *done = false; cond.wakeOne(); cond.wait(mtx, 10); if(!reqDone) { mtx.unlock(); return false; } *done = true; done = NULL; req = NULL; reqDone = false; mtx.unlock(); return true; } bool SCADAHost::reqBusy( ) { if(req && !reqDone) return true; //Free done status if(reqDone) { mtx.lock(); done = NULL; req = NULL; reqDone = false; mtx.unlock(); } return false; } void SCADAHost::run( ) { pid = pthread_self(); while(!endRun) { //Interface's requests processing mtx.lock(); if(!req || reqDone) cond.wait(mtx, 1000); if(req && !reqDone) { mtx.unlock(); mod->cntrIfCmd(*req, owner()->user(), owner()->password(), owner()->VCAStation(), glob); mtx.lock(); reqDone = *done = true; cond.wakeOne(); } mtx.unlock(); } } VisRun *SCADAHost::owner( ) const { return dynamic_cast(parent()); }