diff options
Diffstat (limited to 'src/pmview/main.cpp')
-rw-r--r-- | src/pmview/main.cpp | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/src/pmview/main.cpp b/src/pmview/main.cpp new file mode 100644 index 0000000..115a90b --- /dev/null +++ b/src/pmview/main.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2009, Aconex. All Rights Reserved. + * + * 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. + */ +#include <QtCore/QSettings> +#include <QtCore/QTextStream> +#include <QtGui/QMessageBox> +#include <Inventor/nodes/SoCube.h> +#include <Inventor/nodes/SoBaseColor.h> +#include <Inventor/nodes/SoSeparator.h> +#include <Inventor/nodes/SoTranslation.h> +#include "qed_fileiconprovider.h" +#include "qed_timecontrol.h" +#include "qed_console.h" +#include "scenegroup.h" +#include "pcpcolor.h" +#include "modlist.h" +#include "viewobj.h" +#include "main.h" + +#include <iostream> +using namespace std; + +int Cflag; +int Lflag; +int Wflag; +char *outgeometry; +Settings globalSettings; + +float theScale = 1.0; +const int theBufferLen = 2048; +char theBuffer[theBufferLen]; + +// Globals used to provide single instances of classes used across pmview +SceneGroup *liveGroup; // one metrics class group for all hosts +SceneGroup *archiveGroup; // one metrics class group for all archives +SceneGroup *activeGroup; // currently active metric fetchgroup +QedTimeControl *pmtime; // one timecontrol class for pmtime +PmView *pmview; + +static const char *options = "A:a:Cc:D:g:h:Ln:O:p:S:T:t:VzZ:?"; + +static void usage(void) +{ + pmprintf("Usage: %s [options] [sources]\n\n" +"Options:\n" +" -A align align sample times on natural boundaries\n" +" -a archive add PCP log archive to metrics source list\n" +" -c configfile initial view to load\n" +" -C with -c, parse config, report any errors and exit\n" +" -CC like -C, but also connect to pmcd to check semantics\n" +" -g geometry image geometry Width x Height (WxH)\n" +" -h host add host to list of live metrics sources\n" +" -L directly fetch metrics from localhost, PMCD is not used\n" +" -O offset initial offset into the time window\n" +" -p port port name for connection to existing time control\n" +" -S starttime start of the time window\n" +" -T endtime end of the time window\n" +" -t interval sample interval [default: %d seconds]\n" +" -V display pmview version number and exit\n" +" -Z timezone set reporting timezone\n" +" -z set reporting timezone to local time of metrics source\n", + pmProgname, (int)PmView::defaultViewDelta()); + pmflush(); + exit(1); +} + +int warningMsg(const char *file, int line, const char *msg, ...) +{ + int sts = QMessageBox::Ok; + va_list arg; + va_start(arg, msg); + + int pos = sprintf(theBuffer, "%s: Warning: ", pmProgname); + pos += vsprintf(theBuffer + pos, msg, arg); + sprintf(theBuffer+pos, "\n"); + + if (pmDebug) { + QTextStream cerr(stderr); + cerr << file << ":" << line << ": " << theBuffer << endl; + } + + sts = QMessageBox::warning(pmview, "Warning", theBuffer, sts, sts); + va_end(arg); + + return sts; +} + +double QmcTime::secondsToUnits(double value, QmcTime::DeltaUnits units) +{ + switch (units) { + case Milliseconds: + value = value * 1000.0; + break; + case Minutes: + value = value / 60.0; + break; + case Hours: + value = value / (60.0 * 60.0); + break; + case Days: + value = value / (60.0 * 60.0 * 24.0); + break; + case Weeks: + value = value / (60.0 * 60.0 * 24.0 * 7.0); + break; + case Seconds: + default: + break; + } + return value; +} + +double QmcTime::deltaValue(QString delta, QmcTime::DeltaUnits units) +{ + return QmcTime::secondsToUnits(delta.trimmed().toDouble(), units); +} + +QString QmcTime::deltaString(double value, QmcTime::DeltaUnits units) +{ + QString delta; + + value = QmcTime::secondsToUnits(value, units); + if ((double)(int)value == value) + delta.sprintf("%.2f", value); + else + delta.sprintf("%.6f", value); + return delta; +} + +void writeSettings(void) +{ + QSettings userSettings; + + userSettings.beginGroup(pmProgname); + if (globalSettings.viewDeltaModified) { + globalSettings.viewDeltaModified = false; + userSettings.setValue("viewDelta", globalSettings.viewDelta); + } + if (globalSettings.loggerDeltaModified) { + globalSettings.loggerDeltaModified = false; + userSettings.setValue("loggerDelta", globalSettings.loggerDelta); + } + if (globalSettings.viewBackgroundModified) { + globalSettings.viewBackgroundModified = false; + userSettings.setValue("viewBackgroundColor", + globalSettings.viewBackgroundName); + } + if (globalSettings.viewHighlightModified) { + globalSettings.viewHighlightModified = false; + userSettings.setValue("viewHighlightColor", + globalSettings.viewHighlightName); + } + if (globalSettings.gridBackgroundModified) { + globalSettings.gridBackgroundModified = false; + userSettings.setValue("gridBackgroundColor", + globalSettings.gridBackgroundName); + } + if (globalSettings.initialToolbarModified) { + globalSettings.initialToolbarModified = false; + userSettings.setValue("initialToolbar", globalSettings.initialToolbar); + } + if (globalSettings.nativeToolbarModified) { + globalSettings.nativeToolbarModified = false; + userSettings.setValue("nativeToolbar", globalSettings.nativeToolbar); + } + if (globalSettings.toolbarLocationModified) { + globalSettings.toolbarLocationModified = false; + userSettings.setValue("toolbarLocation", + globalSettings.toolbarLocation); + } + if (globalSettings.toolbarActionsModified) { + globalSettings.toolbarActionsModified = false; + userSettings.setValue("toolbarActions", globalSettings.toolbarActions); + } + userSettings.endGroup(); +} + +void readSettings(void) +{ + QSettings userSettings; + userSettings.beginGroup(pmProgname); + + // + // Parameters related to sampling + // + globalSettings.viewDeltaModified = false; + globalSettings.viewDelta = userSettings.value("viewDelta", + PmView::defaultViewDelta()).toDouble(); + globalSettings.loggerDeltaModified = false; + globalSettings.loggerDelta = userSettings.value("loggerDelta", + PmView::defaultLoggerDelta()).toDouble(); + + // + // Everything colour related + // + globalSettings.viewBackgroundModified = false; + globalSettings.viewBackgroundName = userSettings.value( + "viewBackgroundColor", "black").toString(); + globalSettings.viewBackground = QColor(globalSettings.viewBackgroundName); + + globalSettings.viewHighlightModified = false; + globalSettings.viewHighlightName = userSettings.value( + "viewHighlightColor", "white").toString(); + globalSettings.viewHighlight = QColor(globalSettings.viewHighlightName); + + globalSettings.gridBackgroundModified = false; + globalSettings.gridBackgroundName = userSettings.value( + "gridBackgroundColor", "rgbi:0.15/0.15/0.15").toString(); + globalSettings.gridBackground = QColor(globalSettings.gridBackgroundName); + + // + // Toolbar user preferences + // + globalSettings.initialToolbarModified = false; + globalSettings.initialToolbar = userSettings.value( + "initialToolbar", 1).toInt(); + globalSettings.nativeToolbarModified = false; + globalSettings.nativeToolbar = userSettings.value( + "nativeToolbar", 1).toInt(); + globalSettings.toolbarLocationModified = false; + globalSettings.toolbarLocation = userSettings.value( + "toolbarLocation", 0).toInt(); + QStringList actionList; + globalSettings.toolbarActionsModified = false; + if (userSettings.contains("toolbarActions") == true) + globalSettings.toolbarActions = + userSettings.value("toolbarActions").toStringList(); + // else: (defaults come from the pmview.ui interface specification) + + userSettings.endGroup(); +} + +int +genInventor(void) +{ + int sts = 0; + const char *configfile; + QTextStream cerr(stderr); + + if (theConfigName.length()) { + configfile = strdup((const char *)theConfigName.toAscii()); + if (!(yyin = fopen(configfile, "r"))) { + pmprintf( + "%s: Error: Unable to open configuration file \"%s\": %s\n", + pmProgname, configfile, strerror(errno)); + return -1; + } + theAltConfigName = theConfigName; + } else { + configfile = mktemp(strdup("/tmp/pmview.XXXXXX")); + if (pmDebug & DBG_TRACE_APPL0) + cerr << "genInventor: Copy of configuration saved to " + << configfile << endl; + if (!(theAltConfig = fopen(configfile, "w"))) { + pmprintf("%s: Warning: Unable to save configuration for " + "recording to \"%s\": %s\n", + pmProgname, configfile, strerror(errno)); + } + theAltConfigName = configfile; + } + + yyparse(); + + if (theAltConfig) + fclose(theAltConfig); + + if (pmDebug & DBG_TRACE_APPL0) { + cerr << pmProgname << ": " << errorCount << " errors detected in " + << theConfigName << endl; + } + + sts = -errorCount; + + if (rootObj != NULL) { + rootObj->setTran(0, 0, rootObj->width(), rootObj->depth()); + + SoSeparator *sep = new SoSeparator; + SoTranslation *tran = new SoTranslation(); + tran->translation.setValue(rootObj->width() / -2.0, 0.0, + rootObj->depth() / -2.0); + sep->addChild(tran); + + if (pmDebug & DBG_TRACE_APPL0 || + pmDebug & DBG_TRACE_APPL1 || + pmDebug & DBG_TRACE_APPL2) { + SoBaseColor *col = new SoBaseColor; + col->rgb.setValue(1.0, 0.0, 0.0); + sep->addChild(col); + SoCube * cube = new SoCube; + cube->width = 10; + cube->depth = 5.0; + cube->height = 25; + sep->addChild(cube); + } + + sep->addChild(rootObj->root()); + theModList->setRoot(sep); + } + + if ((ViewObj::numModObjects() == 0 || theModList->size() == 0) && + elementalNodeList.getLength() == 0) { + pmprintf("%s: No valid modulated objects in the scene\n", + pmProgname); + sts--; + } + else if (sts < 0) { + pmprintf("%s: Unrecoverable errors in the configuration file %s\n", + pmProgname, (const char *)theConfigName.toAscii()); + } + + return sts; +} + +int +main(int argc, char **argv) +{ + int c, sts; + int errflg = 0; + char *msg; + + QedApp a(argc, argv); + readSettings(); + + liveGroup = new SceneGroup(); + archiveGroup = new SceneGroup(); + + while ((c = a.getopts(options)) != EOF) { + switch (c) { + + case 'C': + Cflag++; + break; + + case 'g': + outgeometry = optarg; + break; + + case 'c': + theConfigName = optarg; + break; + + case '?': + default: + usage(); + } + } + + a.startconsole(); + + if (a.my.archives.size() > 0) + while (optind < argc) + a.my.archives.append(argv[optind++]); + else + while (optind < argc) + a.my.hosts.append(argv[optind++]); + + if (optind != argc) + errflg++; + if (errflg) + usage(); + + if (a.my.pmnsfile && (sts = pmLoadNameSpace(a.my.pmnsfile)) < 0) { + pmprintf("%s: %s\n", pmProgname, pmErrStr(sts)); + pmflush(); + exit(1); + } + + // Create all of the sources + if (a.my.Lflag) { + liveGroup->use(PM_CONTEXT_LOCAL, QmcSource::localHost); + Lflag = 1; + } + for (c = 0; c < a.my.hosts.size(); c++) { + if (liveGroup->use(PM_CONTEXT_HOST, a.my.hosts[c]) < 0) + a.my.hosts.removeAt(c); + } + for (c = 0; c < a.my.archives.size(); c++) { + if (archiveGroup->use(PM_CONTEXT_ARCHIVE, a.my.archives[c]) < 0) + a.my.archives.removeAt(c); + } + if (!a.my.Lflag && a.my.hosts.size() == 0 && a.my.archives.size() == 0) + liveGroup->createLocalContext(); + pmflush(); + console->post("Metric group setup complete (%d hosts, %d archives)", + a.my.hosts.size(), a.my.archives.size()); + + if (a.my.zflag) { + if (a.my.archives.size() > 0) + archiveGroup->useTZ(); + if (a.my.hosts.size() > 0) + liveGroup->useTZ(); + } + else if (a.my.tz != NULL) { + if (a.my.archives.size() > 0) + archiveGroup->useTZ(QString(a.my.tz)); + if (a.my.hosts.size() > 0) + liveGroup->useTZ(QString(a.my.tz)); + if ((sts = pmNewZone(a.my.tz)) < 0) { + pmprintf("%s: cannot set timezone to \"%s\": %s\n", + pmProgname, (char *)a.my.tz, pmErrStr(sts)); + pmflush(); + exit(1); + } + } + + // + // Choose which View will be displayed initially - archive/live. + // If any archives given on command line, we go Archive mode; + // otherwise Live mode wins. Our initial pmtime connection is + // set in that mode too. Later we'll make a second connection + // in the other mode (and only "on-demand"). + // + if (a.my.archives.size() > 0) { + activeGroup = archiveGroup; + archiveGroup->defaultTZ(a.my.tzLabel, a.my.tzString); + archiveGroup->updateBounds(); + a.my.logStartTime = archiveGroup->logStart(); + a.my.logEndTime = archiveGroup->logEnd(); + if ((sts = pmParseTimeWindow(a.my.Sflag, a.my.Tflag, + a.my.Aflag, a.my.Oflag, + &a.my.logStartTime, &a.my.logEndTime, + &a.my.realStartTime, &a.my.realEndTime, + &a.my.position, &msg)) < 0) { + pmprintf("Cannot parse archive time window\n%s\n", msg); + free(msg); + usage(); + } + } + else { + activeGroup = liveGroup; + liveGroup->defaultTZ(a.my.tzLabel, a.my.tzString); + gettimeofday(&a.my.logStartTime, NULL); + a.my.logEndTime.tv_sec = a.my.logEndTime.tv_usec = INT_MAX; + if ((sts = pmParseTimeWindow(a.my.Sflag, a.my.Tflag, + a.my.Aflag, a.my.Oflag, + &a.my.logStartTime, &a.my.logEndTime, + &a.my.realStartTime, &a.my.realEndTime, + &a.my.position, &msg)) < 0) { + pmprintf("Cannot parse live time window\n%s\n", msg); + free(msg); + usage(); + } + } + console->post("Timezones and time window setup complete"); + + pmview = new PmView; + pmtime = new QedTimeControl; + fileIconProvider = new QedFileIconProvider(); + console->post("Phase1 user interface constructors complete"); + + // Start pmtime process for time management + pmtime->init(a.my.port, a.my.archives.size() == 0, &a.my.delta, + &a.my.position, &a.my.realStartTime, &a.my.realEndTime, + a.my.tzString, a.my.tzLabel); + + pmview->init(); + liveGroup->init(pmtime->liveInterval(), pmtime->livePosition()); + archiveGroup->init(pmtime->archiveInterval(), pmtime->archivePosition()); + console->post("Phase2 user interface setup complete"); + + PCPColor::initClass(); + theModList = new ModList(pmview->viewer(), &PmView::selectionCB, NULL, NULL); + if (genInventor() < 0) { + pmflush(); + exit(1); + } + + if (Cflag) // done with -c config, quit + return 0; + + if (pmview->view(false, 0, 1, 0, M_PI / 4.0, theGlobalScale) == false) { + pmflush(); + exit(1); + } + + pmview->viewer()->viewAll(); + pmview->enableUi(); + pmview->show(); + console->post("Top level window shown"); + + a.connect(&a, SIGNAL(lastWindowClosed()), pmview, SLOT(quit())); + return a.exec(); +} |