summaryrefslogtreecommitdiff
path: root/src/pmview
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
committerIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
commit47e6e7c84f008a53061e661f31ae96629bc694ef (patch)
tree648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmview
downloadpcp-debian.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmview')
-rw-r--r--src/pmview/GNUmakefile102
-rw-r--r--src/pmview/app-defaults207
-rw-r--r--src/pmview/barmod.cpp603
-rw-r--r--src/pmview/barmod.h133
-rw-r--r--src/pmview/barobj.cpp539
-rw-r--r--src/pmview/barobj.h125
-rw-r--r--src/pmview/baseobj.cpp125
-rw-r--r--src/pmview/baseobj.h119
-rw-r--r--src/pmview/colorlist.cpp186
-rw-r--r--src/pmview/colorlist.h77
-rw-r--r--src/pmview/colormod.cpp161
-rw-r--r--src/pmview/colormod.h59
-rw-r--r--src/pmview/colorscale.cpp158
-rw-r--r--src/pmview/colorscale.h89
-rw-r--r--src/pmview/colorscalemod.cpp190
-rw-r--r--src/pmview/colorscalemod.h65
-rw-r--r--src/pmview/defaultobj.cpp175
-rw-r--r--src/pmview/defaultobj.h152
-rw-r--r--src/pmview/error.cpp47
-rw-r--r--src/pmview/front-ends/GNUmakefile25
-rwxr-xr-xsrc/pmview/front-ends/clustervis331
-rw-r--r--src/pmview/front-ends/config.clustervis13
-rwxr-xr-xsrc/pmview/front-ends/config.dkvis14
-rwxr-xr-xsrc/pmview/front-ends/config.mpvis13
-rwxr-xr-xsrc/pmview/front-ends/config.nfsvis12
-rwxr-xr-xsrc/pmview/front-ends/config.osvis31
-rwxr-xr-xsrc/pmview/front-ends/config.weblogvis20
-rwxr-xr-xsrc/pmview/front-ends/config.webpingvis8
-rw-r--r--src/pmview/front-ends/config.webvis51
-rwxr-xr-xsrc/pmview/front-ends/dkvis572
-rwxr-xr-xsrc/pmview/front-ends/mpvis452
-rwxr-xr-xsrc/pmview/front-ends/nfsvis244
-rw-r--r--src/pmview/front-ends/osvis651
-rw-r--r--src/pmview/front-ends/pmview-args625
-rwxr-xr-xsrc/pmview/front-ends/weblogvis451
-rwxr-xr-xsrc/pmview/front-ends/weblogvis.load103
-rw-r--r--src/pmview/front-ends/weblogvis.rgbbin0 -> 206570 bytes
-rw-r--r--src/pmview/front-ends/webpingvis372
-rw-r--r--src/pmview/front-ends/webpingvis.rgbbin0 -> 365706 bytes
-rwxr-xr-xsrc/pmview/front-ends/webvis707
-rw-r--r--src/pmview/front-ends/webvis.rgbbin0 -> 502112 bytes
-rw-r--r--src/pmview/gram.y1391
-rw-r--r--src/pmview/gridobj.cpp314
-rw-r--r--src/pmview/gridobj.h107
-rw-r--r--src/pmview/iconbin0 -> 9247 bytes
-rw-r--r--src/pmview/labelobj.cpp112
-rw-r--r--src/pmview/labelobj.h99
-rw-r--r--src/pmview/launch.cpp421
-rw-r--r--src/pmview/launch.h113
-rw-r--r--src/pmview/lex.l456
-rw-r--r--src/pmview/link.cpp218
-rw-r--r--src/pmview/link.h52
-rw-r--r--src/pmview/main.cpp493
-rw-r--r--src/pmview/main.h152
-rw-r--r--src/pmview/metriclist.cpp234
-rw-r--r--src/pmview/metriclist.h84
-rw-r--r--src/pmview/modlist.cpp471
-rw-r--r--src/pmview/modlist.h134
-rw-r--r--src/pmview/modobj.h43
-rw-r--r--src/pmview/modulate.cpp134
-rw-r--r--src/pmview/modulate.h117
-rw-r--r--src/pmview/pcpcolor.cpp100
-rw-r--r--src/pmview/pcpcolor.h61
-rw-r--r--src/pmview/pipeobj.cpp187
-rw-r--r--src/pmview/pipeobj.h54
-rw-r--r--src/pmview/pmview.cpp708
-rw-r--r--src/pmview/pmview.desktop8
-rw-r--r--src/pmview/pmview.h162
-rw-r--r--src/pmview/pmview.info.in18
-rw-r--r--src/pmview/pmview.pro34
-rw-r--r--src/pmview/pmview.qrc23
-rw-r--r--src/pmview/pmview.ui386
-rw-r--r--src/pmview/scalemod.cpp183
-rw-r--r--src/pmview/scalemod.h62
-rw-r--r--src/pmview/scenefileobj.cpp127
-rw-r--r--src/pmview/scenefileobj.h53
-rw-r--r--src/pmview/scenegroup.cpp178
-rw-r--r--src/pmview/scenegroup.h62
-rw-r--r--src/pmview/stackmod.cpp594
-rw-r--r--src/pmview/stackmod.h98
-rw-r--r--src/pmview/stackobj.cpp146
-rw-r--r--src/pmview/stackobj.h76
-rw-r--r--src/pmview/text.cpp334
-rw-r--r--src/pmview/text.h83
-rw-r--r--src/pmview/togglemod.cpp106
-rw-r--r--src/pmview/togglemod.h75
-rw-r--r--src/pmview/viewobj.cpp170
-rw-r--r--src/pmview/viewobj.h135
-rw-r--r--src/pmview/xing.cpp202
-rw-r--r--src/pmview/xing.h48
-rw-r--r--src/pmview/yscalemod.cpp46
-rw-r--r--src/pmview/yscalemod.h44
92 files changed, 17715 insertions, 0 deletions
diff --git a/src/pmview/GNUmakefile b/src/pmview/GNUmakefile
new file mode 100644
index 0000000..c6e039f
--- /dev/null
+++ b/src/pmview/GNUmakefile
@@ -0,0 +1,102 @@
+TOPDIR = ../..
+COMMAND = pmview
+PROJECT = $(COMMAND).pro
+include $(TOPDIR)/src/include/builddefs
+
+WRAPPER = $(COMMAND).sh
+QRCFILE = $(COMMAND).qrc
+ICNFILE = $(COMMAND).icns
+ICOFILE = $(COMMAND).ico
+XMLFILE = $(COMMAND).info
+DESKTOP = $(COMMAND).desktop
+UIFILES = $(shell echo *.ui)
+CLASSES = main.h pmview.h colorlist.h \
+ barmod.h barobj.h baseobj.h \
+ defaultobj.h gridobj.h labelobj.h stackobj.h \
+ text.h viewobj.h pipeobj.h link.h xing.h \
+ scenefileobj.h scenegroup.h \
+ colorscalemod.h colormod.h colorscale.h \
+ metriclist.h modlist.h modulate.h \
+ scalemod.h stackmod.h togglemod.h \
+ yscalemod.h pcpcolor.h launch.h
+SOURCES = $(CLASSES:.h=.cpp) error.cpp
+HEADERS = $(CLASSES) modobj.h
+GENERATED = gram.cpp lex.cpp
+LFILES = lex.l
+YFILES = gram.y
+LDIRT = $(COMMAND) $(WRAPPER) $(XMLFILE) $(GENERATED) gram.h y.tab.? images
+
+SUBDIRS = front-ends
+
+default: build-me
+
+include $(BUILDRULES)
+
+ifeq "$(ENABLE_QT)" "true"
+build-me:: images wrappers $(GENERATED)
+ $(QTMAKE)
+ $(LNMAKE)
+
+build-me:: $(SUBDIRS)
+ $(SUBDIRS_MAKERULE)
+
+lex.cpp: lex.l
+ $(LEX) -t lex.l > $@
+
+gram.h y.tab.c: gram.y
+ $(YACC) -d gram.y && cp y.tab.h gram.h
+
+gram.cpp: y.tab.c
+ cp y.tab.c $@
+
+lex.o: gram.h
+
+ifeq ($(WINDOW),mac)
+MACBUILD = $(COMMAND).app/Contents
+PKG_MAC_DIR = /Applications/$(COMMAND).app/Contents
+wrappers: $(WRAPPER)
+else
+wrappers:
+endif
+
+$(WRAPPER): $(WRAPPER).IN
+ $(SED) -e '/\# .*/b' -e 's;PKG_MAC_DIR;$(PKG_MAC_DIR);g' < $< > $@
+
+install: default
+ $(SUBDIRS_MAKERULE)
+ $(INSTALL) -m 755 -d $(PCP_BIN_DIR)
+ifeq ($(WINDOW),win)
+ $(INSTALL) -m 755 $(BINARY) $(PKG_BIN_DIR)/$(COMMAND)
+endif
+ifeq ($(WINDOW),x11)
+ $(INSTALL) -m 755 $(BINARY) $(PKG_BIN_DIR)/$(COMMAND)
+ $(INSTALL) -m 755 -d $(PKG_DESKTOP_DIR)
+ $(INSTALL) -m 644 $(DESKTOP) $(PKG_DESKTOP_DIR)/$(DESKTOP)
+endif
+ifeq ($(WINDOW),mac)
+ $(INSTALL) -m 755 $(WRAPPER) $(PKG_BIN_DIR)/$(COMMAND)
+ $(INSTALL) -m 755 -d /Applications
+ $(INSTALL) -m 755 -d /Applications/$(COMMAND).app
+ $(INSTALL) -m 755 -d $(PKG_MAC_DIR)
+ $(INSTALL) -m 644 $(MACBUILD)/Info.plist $(PKG_MAC_DIR)/Info.plist
+ $(INSTALL) -m 644 $(MACBUILD)/PkgInfo $(PKG_MAC_DIR)/PkgInfo
+ $(INSTALL) -m 755 -d $(PKG_MAC_DIR)/MacOS
+ $(INSTALL) -m 755 $(BINARY) $(PKG_MAC_DIR)/MacOS/$(COMMAND)
+ $(INSTALL) -m 755 -d $(PKG_MAC_DIR)/Resources
+ $(INSTALL) -m 644 $(ICNFILE) $(PKG_MAC_DIR)/Resources/$(ICNFILE)
+endif
+
+else
+build-me:
+install:
+endif
+
+default_pcp: default
+
+install_pcp: install
+
+images: $(ICNFILE)
+ $(LN_S) $(TOPDIR)/images images
+
+$(ICNFILE):
+ $(LN_S) $(TOPDIR)/images/$(ICNFILE) $(ICNFILE)
diff --git a/src/pmview/app-defaults b/src/pmview/app-defaults
new file mode 100644
index 0000000..94cb915
--- /dev/null
+++ b/src/pmview/app-defaults
@@ -0,0 +1,207 @@
+! Copyright (c) 1995-2002 Silicon Graphics, Inc. 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.
+!
+! 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
+!
+
+
+!
+!Activate schemes and sgi mode by default
+!
+PmView+*useSchemes: all
+PmView+*sgiMode: true
+
+#ifdef __linux
+!
+! default fonts
+!
+PmView+*defaultFontList: -*-helvetica-bold-o-*-*-*-140-75-75-*-*-iso8859-1
+PmView+*form*fontList: -*-helvetica-medium-r-*-*-*-120-75-75-*-*-iso8859-1
+PmView+*form.scaleText.fontList: -*-helvetica-medium-r-*-*-*-140-75-75-*-*-iso8859-1
+PmView+*form.timeLabel.fontList: -*-helvetica-medium-r-*-*-*-140-75-75-*-*-iso8859-1
+PmView+*form.metricLabel.fontList: -*-helvetica-medium-r-*-*-*-140-75-75-*-*-iso8859-1
+#endif
+!
+!SGI Style guide specifies explicit focus within PmView+s
+!
+PmView+*keyboardFocusPolicy: explicit
+
+!
+! Menus
+!
+PmView+*title: Performance Metrics Viewer
+PmView+*fileMenu.labelString: File
+PmView+*fileMenu.mnemonic: F
+PmView+*recordButton.labelString: Record
+PmView+*recordButton.mnemonic: R
+PmView+*recordButton.accelerator: Ctrl<Key>R
+PmView+*recordButton.acceleratorText: Ctrl+R
+PmView+*saveButton.labelString: Save
+PmView+*saveButton.mnemonic: S
+PmView+*saveButton.accelerator: Ctrl<Key>S
+PmView+*saveButton.acceleratorText: Ctrl+S
+PmView+*printButton.labelString: Print
+PmView+*printButton.mnemonic: P
+PmView+*printButton.accelerator: Ctrl<Key>P
+PmView+*printButton.acceleratorText: Ctrl+P
+PmView+*exitButton.labelString: Quit
+PmView+*exitButton.mnemonic: Q
+PmView+*exitButton.accelerator: Ctrl<Key>Q
+PmView+*exitButton.acceleratorText: Ctrl+Q
+PmView+*optionsMenu.labelString: Options
+PmView+*optionsMenu.mnemonic: O
+PmView+*showVCRButton.labelString: Show Time Control
+PmView+*showVCRButton.mnemonic: T
+PmView+*showVCRButton.accelerator: Ctrl<Key>T
+PmView+*showVCRButton.acceleratorText: Ctrl+T
+PmView+*newVCRButton.mnemonic: N
+PmView+*newVCRButton.labelString: New Time Control
+PmView+*newVCRButton.accelerator: Ctrl<Key>N
+PmView+*newVCRButton.acceleratorText: Ctrl+N
+
+PmView+*launchMenu.labelString: Launch
+PmView+*launchMenu.mnemonic: L
+
+PmView+*helpPane.labelString: Help
+PmView+*helpPane.mnemonic: H
+PmView+*help_click_for_help.labelString: Click For Help
+PmView+*help_click_for_help.mnemonic: C
+PmView+*help_click_for_help.accelerator: Shift<Key>F1
+PmView+*help_click_for_help.acceleratorText: Shift+F1
+PmView+*help_overview.labelString: Overview
+PmView+*help_overview.mnemonic: O
+PmView+*help_index.labelString: Index
+PmView+*help_index.mnemonic: I
+PmView+*help_keys_and_short.labelString: Keys and Shortcuts
+PmView+*help_keys_and_short.mnemonic: K
+PmView+*help_prod_info.labelString: Product Information
+PmView+*help_prod_info.mnemonic: P
+PmView+*overviewButton.labelString: Overview
+PmView+*overviewButton.mnemonic: O
+PmView+*indexButton.labelString: Index
+PmView+*indexButton.mnemonic: I
+
+!
+! Scale Thumb Wheel (see SgThumbWheel(3))
+! These resources control the coarseness of the scale wheel (which is
+! logarithmic). These settings force the wheel to have no maximum or
+! minimum value and is reasonably fine near the center (scale of 1.0):
+!
+! PmView+*scaleWheel.homePosition: 0
+! PmView+*scaleWheel.maximum: 0
+! PmView+*scaleWheel.minimum: 0
+! PmView+*scaleWheel.unitsPerRotation: 100
+!
+! These settings force a minimum and maximum value which is not as fine
+! for values near the center:
+!
+! PmView+*scaleWheel.homePosition: 0
+! PmView+*scaleWheel.maximum: 80
+! PmView+*scaleWheel.minimum: -80
+! PmView+*scaleWheel.angleRange: 240
+!
+PmView+*scaleText.value: 1.0000
+PmView+*scaleLabel.labelString: Scale
+PmView+*scaleWheel.homePosition: 0
+PmView+*scaleWheel.maximum: 0
+PmView+*scaleWheel.minimum: 0
+PmView+*scaleWheel.unitsPerRotation: 100
+PmView+*scaleWheel.angleRange: 240
+
+!
+! Default label text
+!
+PmView+*metricLabel.labelString: \n
+PMView*timeLabel.labelString:
+
+!
+! Background color of read-only labels
+!
+!PmView+*readOnlyBackground: Black
+
+!
+! Maximum value before saturation
+! The default of 1.05 allows for 5% error in the time delta when
+! determining rates, before values are deemed saturated.
+!
+PmView+*saturation: 1.05
+
+!
+! Use fast anti-aliasing
+! See SoXtRenderArea(3)
+!
+PmView+*antiAliasSmooth: tree
+
+!
+! Number of anti-aliasing passes: 1 to 255. Only 1 pass disables antialiasing.
+PmView+*antiAliasPasses: 1
+
+!
+! Title, geometry etc.
+!
+PmView+*vkwindow.title: Performance Metrics Viewer
+PmView+*vkwindow.geometry: 512x512
+
+!
+! Better handling of limited colors with pixmaps
+!
+PmView+*silenceWarnings: true
+PmView+*xpmColorCloseness: 113512
+
+!
+! Dialogs
+!
+PmView+*fileSelectionDialog.width: 358
+PmView+*fileSelectionDialog.height: 417
+
+!
+! Help
+!
+*helpSubSys: pcp_eoe.books.PmViewHelp
+*helpTitle: pmview Help
+
+!
+! Layout - can be overridden in configuration files
+!
+
+! Grid, Bar and Stack object base borders
+PmView+*baseBorderWidth: 8
+PmView+*baseBorderDepth: 8
+
+! Height of Grid, Bar and Stack bases
+PmView+*baseHeight: 2
+
+! Color of base plane
+PmView+*baseColor: rgbi:0.15/0.15/0.15
+
+! Spacing between Bar blocks
+PmView+*barSpaceWidth: 8
+PmView+*barSpaceDepth: 8
+
+! Spacing between Bar base and labels
+PmView+*barSpaceLabel: 6
+
+! Width and depth of Bar blocks
+PmView+*barLength: 28
+PmView+*barHeight: 80
+
+! Margin around a Label
+PmView+*labelMargin: 5
+
+! Color of labels
+PmView+*labelColor: rgbi:1.0/1.0/1.0
+
+! Width and depth of Grid columns and rows
+PmView+*gridMinWidth: 20
+PmView+*gridMinDepth: 20
diff --git a/src/pmview/barmod.cpp b/src/pmview/barmod.cpp
new file mode 100644
index 0000000..206f32c
--- /dev/null
+++ b/src/pmview/barmod.cpp
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/SoPath.h>
+#include <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoScale.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoSelection.h>
+#include "barmod.h"
+#include "modlist.h"
+#include "launch.h"
+
+#include <iostream>
+using namespace std;
+
+//
+// Use debug flag LIBPMDA to trace Bar refreshes
+//
+
+const char BarMod::theBarId = 'b';
+
+BarMod::~BarMod()
+{
+}
+
+BarMod::BarMod(MetricList *metrics,
+ SoNode *obj,
+ BarMod::Direction dir,
+ BarMod::Grouping group,
+ float xScale, float yScale, float zScale,
+ float xSpace, float zSpace)
+: Modulate(metrics),
+ _blocks(),
+ _dir(dir),
+ _mod(BarMod::yScale),
+ _group(group),
+ _colScale(0.0, 0.0, 0.0),
+ _selectCount(0),
+ _infoValue(0),
+ _infoMetric(0),
+ _infoInst(0),
+ _xScale(xScale),
+ _yScale(yScale),
+ _zScale(zScale)
+{
+ generate(obj, xSpace, zSpace);
+}
+
+BarMod::BarMod(MetricList *metrics,
+ const ColorScale &colScale,
+ SoNode *obj,
+ BarMod::Direction dir,
+ BarMod::Modulation mod,
+ BarMod::Grouping group,
+ float xScale, float yScale, float zScale,
+ float xSpace, float zSpace)
+: Modulate(metrics),
+ _blocks(),
+ _dir(dir),
+ _mod(mod),
+ _group(group),
+ _colScale(colScale),
+ _selectCount(0),
+ _infoValue(0),
+ _infoMetric(0),
+ _infoInst(0),
+ _xScale(xScale),
+ _yScale(yScale),
+ _zScale(zScale)
+{
+ generate(obj, xSpace, zSpace);
+}
+
+void
+BarMod::generate(SoNode *obj, float xSpace, float zSpace)
+{
+ int numMetrics = _metrics->numMetrics();
+ int numValues = _metrics->numValues();
+ int maxInst = 0;
+ char buf[32];
+ int m, i, v;
+
+ _root = new SoSeparator;
+
+ if (numValues > 0) {
+
+ for (m = 0; m < numMetrics; m++)
+ if (_metrics->metric(m).numValues() > maxInst)
+ maxInst = _metrics->metric(m).numValues();
+
+ if (_dir == instPerCol) {
+ _cols = maxInst;
+ _rows = numMetrics;
+ }
+ else {
+ _cols = numMetrics;
+ _rows = maxInst;
+ }
+
+ _blocks.resize(numValues);
+
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ const QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ BarBlock &block = _blocks[v];
+ sprintf(buf, "%c%d", theBarId, v);
+ block._sep = new SoSeparator;
+ block._sep->setName((SbName)buf);
+ _root->addChild(block._sep);
+
+ block._tran = new SoTranslation;
+ block._sep->addChild(block._tran);
+
+ block._color = new SoBaseColor;
+ block._sep->addChild(block._color);
+
+ block._scale = new SoScale;
+ block._sep->addChild(block._scale);
+
+ block._sep->addChild(obj);
+ }
+ }
+
+ regenerate(_xScale, _zScale, xSpace, zSpace);
+ _infoValue = numValues;
+
+ add();
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "BarMod::generate: Added " << numValues << " in " << _cols
+ << " cols and " << _rows << " rows." << endl;
+#endif
+
+ }
+
+ // Invalid object
+ else {
+ _sts = -1;
+ }
+}
+
+void
+BarMod::refresh(bool fetchFlag)
+{
+ int m, i, v;
+
+ if (status() < 0)
+ return;
+
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ QmcMetric &metric = _metrics->metric(m);
+
+ if (fetchFlag)
+ metric.update();
+
+ for (i = 0; i < metric.numValues(); i++, v++) {
+
+ BarBlock &block = _blocks[v];
+
+ if (metric.error(i) <= 0) {
+
+ if (block._state != Modulate::error) {
+ block._color->rgb.setValue(_errorColor.getValue());
+ if (_mod != color)
+ block._scale->scaleFactor.setValue(_xScale,
+ theMinScale,
+ _zScale);
+ block._state = Modulate::error;
+ }
+ }
+ else {
+ double unscaled = metric.value(i);
+ double value = unscaled * theScale;
+
+ if (value > theNormError) {
+ if (block._state != Modulate::saturated) {
+ block._color->rgb.setValue(Modulate::_saturatedColor);
+ if (_mod != color)
+ block._scale->scaleFactor.setValue(_xScale,
+ _yScale,
+ _zScale);
+ block._state = Modulate::saturated;
+ }
+ }
+ else {
+ if (block._state != Modulate::normal) {
+ block._state = Modulate::normal;
+ if (_mod == yScale)
+ block._color->rgb.setValue(_metrics->color(m).getValue());
+ }
+ else if (_mod != yScale)
+ block._color->rgb.setValue(_colScale.step(unscaled).color().getValue());
+ if (_mod != color) {
+ if (value < Modulate::theMinScale)
+ value = Modulate::theMinScale;
+ else if (value > 1.0)
+ value = 1.0;
+ block._scale->scaleFactor.setValue(_xScale,
+ _yScale * value,
+ _zScale);
+ }
+
+ }
+ }
+ }
+ }
+}
+
+void
+BarMod::selectAll()
+{
+ int i;
+
+ if (_selectCount == _blocks.size())
+ return;
+
+ theModList->selectAllId(_root, _blocks.size());
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "BarMod::selectAll" << endl;
+#endif
+
+ for (i = 0; i < _blocks.size(); i++) {
+ if (_blocks[i]._selected == false) {
+ _selectCount++;
+ theModList->selectSingle(_blocks[i]._sep);
+ _blocks[i]._selected = true;
+ }
+ }
+}
+
+int
+BarMod::select(SoPath *path)
+{
+ int metric, inst, value;
+
+ findBlock(path, metric, inst, value, false);
+ if (value < _blocks.size() && _blocks[value]._selected == false) {
+ _blocks[value]._selected = true;
+ _selectCount++;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "BarMod::select: value = " << value
+ << ", count = " << _selectCount << endl;
+#endif
+ }
+ return _selectCount;
+}
+
+int
+BarMod::remove(SoPath *path)
+{
+ int metric, inst, value;
+
+ findBlock(path, metric, inst, value, false);
+ if (value < _blocks.size() && _blocks[value]._selected == true) {
+ _blocks[value]._selected = false;
+ _selectCount--;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "BarMod::remove: value = " << value
+ << ", count = " << _selectCount << endl;
+#endif
+
+ }
+
+#ifdef PCP_DEBUG
+ else if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "BarMod::remove: did not remove " << value
+ << ", count = " << _selectCount << endl;
+#endif
+
+ return _selectCount;
+}
+
+void BarMod::infoText(QString &str, bool selected) const
+{
+ int m = _infoMetric;
+ int i = _infoInst;
+ int v = _infoValue;
+ bool found = false;
+
+ if (selected && _selectCount == 1) {
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ const QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++)
+ if (_blocks[v]._selected) {
+ found = true;
+ break;
+ }
+ if (found)
+ break;
+ }
+ }
+
+ if (v >= _blocks.size()) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "BarMod::infoText: infoText requested but nothing selected"
+ << endl;
+#endif
+ str = "";
+ }
+ else {
+ const QmcMetric &metric = _metrics->metric(m);
+ str = metric.spec(true, true, i);
+ str.append(QChar('\n'));
+
+ if (_blocks[v]._state == Modulate::error)
+ str.append(theErrorText);
+ else if (_blocks[v]._state == Modulate::start)
+ str.append(theStartText);
+ else {
+ QString value;
+ str.append(value.setNum(metric.realValue(i), 'g', 4));
+ str.append(QChar(' '));
+ if (metric.desc().units().size() > 0)
+ str.append(metric.desc().units());
+ str.append(" [");
+ str.append(value.setNum(metric.value(i) * 100.0, 'g', 4));
+ str.append("% of expected max]");
+ }
+ }
+}
+
+void BarMod::launch(Launch &launch, bool all) const
+{
+ int m, i, v;
+ bool needClose;
+ bool always = all;
+ bool keepGoing = true;
+
+ if (status() < 0)
+ return;
+
+ if (_selectCount == _blocks.size())
+ always = true;
+
+ // Group by metric
+ if (_group == groupByMetric ||
+ (_group == groupByRow && _dir == instPerCol) ||
+ (_group == groupByCol && _dir == instPerRow)) {
+
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ QmcMetric &metric = _metrics->metric(m);
+
+ // Do we have to check that an instance of this metric has
+ // been selected?
+ if (!always) {
+ needClose = false;
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ if (_blocks[v]._selected) {
+ if (needClose == false) {
+ launch.startGroup("point");
+ needClose = true;
+ }
+ if (_mod == yScale)
+ launch.addMetric(metric, _metrics->color(m), i);
+ else
+ launch.addMetric(metric, _colScale, i);
+ }
+ }
+ if (needClose)
+ launch.endGroup();
+ }
+ else {
+ launch.startGroup("point");
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ if (_mod == yScale)
+ launch.addMetric(metric, _metrics->color(m), i);
+ else
+ launch.addMetric(metric, _colScale, i);
+ }
+ launch.endGroup();
+ }
+ }
+ }
+
+ // Group by instance, this gets a little tricky
+ else {
+ for (i = 0; keepGoing ; i++) {
+ needClose = false;
+ keepGoing = false;
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ QmcMetric &metric = _metrics->metric(m);
+ if (metric.numValues() > i) {
+ if (always || _blocks[v+i]._selected) {
+ if (needClose == false) {
+ launch.startGroup("point");
+ needClose = true;
+ }
+ if (_mod == yScale)
+ launch.addMetric(metric, _metrics->color(m), i);
+ else
+ launch.addMetric(metric, _colScale, i);
+ }
+ keepGoing = true;
+ }
+ v += metric.numValues();
+ }
+ if (needClose)
+ launch.endGroup();
+ }
+ }
+}
+
+void
+BarMod::selectInfo(SoPath *path)
+{
+ findBlock(path, _infoMetric, _infoInst, _infoValue);
+}
+
+void
+BarMod::removeInfo(SoPath *)
+{
+ _infoValue = _blocks.size();
+ _infoMetric = _infoInst = 0;
+}
+
+void
+BarMod::dump(QTextStream &os) const
+{
+ int m, i, v;
+
+ os << "BarMod: ";
+
+ if (_dir == instPerCol)
+ os << "inst per col";
+ else
+ os << "inst per row";
+
+ if (_mod == yScale)
+ os << ", Y-Scale: ";
+ else if (_mod == color)
+ os << ", Color Only: ";
+ else
+ os << ", Color & Y-Scale: ";
+
+ if (status() < 0)
+ os << "Invalid metrics: " << pmErrStr(status()) << endl;
+ else {
+ os << endl;
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ os << " [" << v << "]: ";
+ if (_blocks[v]._selected == true)
+ os << '*';
+ else
+ os << ' ';
+ dumpState(os, _blocks[v]._state);
+ os << ": ";
+ metric.dump(os, true, i);
+ }
+ }
+ }
+}
+
+void
+BarMod::findBlock(SoPath *path, int &metric, int &inst,
+ int &value, bool idMetric)
+{
+ SoNode *node;
+ char *str;
+ int m, i, v;
+ char c;
+
+ for (i = path->getLength() - 1; i >= 0; --i) {
+ node = path->getNode(i);
+ str = (char *)(node->getName().getString());
+ if (strlen(str) && str[0] == theBarId)
+ break;
+ }
+
+ if (i >= 0) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "BarMod::findBlock: Bar id = " << str << endl;
+#endif
+
+ sscanf(str, "%c%d", &c, &value);
+
+ if (value == 0 || idMetric == false) {
+ metric = 0;
+ inst = 0;
+ }
+ else {
+ m = 0;
+ v = value;
+ while (m < _metrics->numMetrics()) {
+ i = _metrics->metric(m).numValues();
+ if (v < i) {
+ metric = m;
+ inst = v;
+ break;
+ }
+ else {
+ v -= i;
+ m++;
+ }
+ }
+ }
+ }
+ else {
+ value = _blocks.size();
+ metric = inst = 0;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ cerr << "BarMod::findBlock: metric = " << metric
+ << ", inst = " << inst << ", value = " << value << endl;
+ }
+#endif
+
+ return;
+}
+
+void
+BarMod::regenerate(float xScale, float zScale, float xSpace, float zSpace)
+{
+ int m, i, v;
+ float halfX = xScale / 2.0;
+ float halfZ = zScale / 2.0;
+
+ if (status() < 0)
+ return;
+
+ _xScale = xScale;
+ _zScale = zScale;
+
+ _width = (unsigned int)((_cols * (_xScale + xSpace)) - xSpace);
+ _depth = (unsigned int)((_rows * (_zScale + zSpace)) - zSpace);
+
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ const QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ BarBlock &block = _blocks[v];
+
+ if (_dir == instPerCol)
+ block._tran->translation.setValue(i * (_xScale+xSpace) + halfX,
+ 0,
+ m * (_zScale+zSpace) + halfZ);
+ else
+ block._tran->translation.setValue(m * (_xScale+xSpace) + halfX,
+ 0,
+ i * (_zScale+zSpace) + halfZ);
+
+ block._color->rgb.setValue(_errorColor.getValue());
+ block._scale->scaleFactor.setValue(_xScale, _yScale, _zScale);
+ block._state = Modulate::start;
+ block._selected = false;
+ }
+ }
+}
+
+const char *
+BarMod::dirStr() const
+{
+ const char *str = NULL;
+
+ if (_dir == instPerCol)
+ str = "instances in columns";
+ else
+ str = "instances in rows";
+
+ return str;
+}
+
+const char *
+BarMod::modStr() const
+{
+ const char *str = NULL;
+
+ switch (_mod) {
+ case yScale:
+ str = "Y-Scale";
+ break;
+ case color:
+ str = "Colored";
+ break;
+ case colYScale:
+ str = "Colored Y-Scale";
+ break;
+ }
+ return str;
+}
diff --git a/src/pmview/barmod.h b/src/pmview/barmod.h
new file mode 100644
index 0000000..073f7ce
--- /dev/null
+++ b/src/pmview/barmod.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _BARMOD_H_
+#define _BARMOD_H_
+
+#include "colorscale.h"
+#include "modulate.h"
+#include <QtCore/QVector>
+
+class SoBaseColor;
+class SoScale;
+class SoNode;
+class SoTranslation;
+class Launch;
+
+struct BarBlock {
+ SoSeparator *_sep;
+ SoBaseColor *_color;
+ SoScale *_scale;
+ SoTranslation *_tran;
+ Modulate::State _state;
+ bool _selected;
+};
+
+typedef QVector<BarBlock> BarBlockList;
+
+class BarMod : public Modulate
+{
+public:
+
+ enum Direction { instPerCol, instPerRow };
+ enum Modulation { yScale, color, colYScale };
+ enum Grouping { groupByRow, groupByCol, groupByMetric, groupByInst };
+
+private:
+
+ static const char theBarId;
+
+ BarBlockList _blocks;
+ Direction _dir;
+ Modulation _mod;
+ Grouping _group;
+ ColorScale _colScale;
+ int _selectCount;
+ int _infoValue;
+ int _infoMetric;
+ int _infoInst;
+ float _xScale;
+ float _yScale;
+ float _zScale;
+ int _width;
+ int _depth;
+ int _cols;
+ int _rows;
+
+public:
+
+ virtual ~BarMod();
+
+ BarMod(MetricList *list,
+ SoNode *obj,
+ BarMod::Direction dir,
+ BarMod::Grouping group,
+ float xScale, float yScale, float zScale,
+ float xSpace, float zSpace);
+
+ BarMod(MetricList *list,
+ const ColorScale &colScale,
+ SoNode *obj,
+ BarMod::Direction dir,
+ BarMod::Modulation mod,
+ BarMod::Grouping group,
+ float xScale, float yScale, float zScale,
+ float xSpace, float zSpace);
+
+ Direction dir() const
+ { return _dir; }
+ int width() const
+ { return _width; }
+ int depth() const
+ { return _depth; }
+ int numBars() const
+ { return _blocks.size(); }
+ int rows() const
+ { return _rows; }
+ int cols() const
+ { return _cols; }
+
+ virtual void refresh(bool fetchFlag);
+
+ virtual void selectAll();
+ virtual int select(SoPath *);
+ virtual int remove(SoPath *);
+
+ virtual void selectInfo(SoPath *);
+ virtual void removeInfo(SoPath *);
+
+ virtual void infoText(QString &str, bool) const;
+
+ virtual void launch(Launch &launch, bool) const;
+
+ virtual void dump(QTextStream &) const;
+
+ void regenerate(float xScale, float zScale, float xSpace, float zSpace);
+
+ const char *dirStr() const;
+ const char *modStr() const;
+
+private:
+
+ BarMod();
+ BarMod(const BarMod &);
+ const BarMod &operator=(const BarMod &);
+ // Never defined
+
+ void generate(SoNode *obj, float xSpace, float zSpace);
+ void findBlock(SoPath *path, int &metric, int &inst,
+ int &value, bool idMetric = true);
+};
+
+#endif /* _BARMOD_H_ */
diff --git a/src/pmview/barobj.cpp b/src/pmview/barobj.cpp
new file mode 100644
index 0000000..da3e621
--- /dev/null
+++ b/src/pmview/barobj.cpp
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoScale.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoTransform.h>
+
+#include "barobj.h"
+#include "colorlist.h"
+#include "yscalemod.h"
+#include "colormod.h"
+#include "colorscalemod.h"
+#include "text.h"
+#include "defaultobj.h"
+
+#include <iostream>
+using namespace std;
+
+BarObj::~BarObj()
+{
+}
+
+BarObj::BarObj(ViewObj::Shape shape,
+ BarMod::Direction dir,
+ BarMod::Modulation mod,
+ BarMod::Grouping group,
+ bool baseFlag,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols, int rows,
+ BaseObj::Alignment align)
+: ModObj(baseFlag, defaults, x, y, cols, rows, align),
+ _shape(shape),
+ _dir(dir),
+ _mod(mod),
+ _group(group),
+ _width(0),
+ _depth(0),
+ _xSpace(defaults.barSpaceX()),
+ _zSpace(defaults.barSpaceZ()),
+ _labelSpace(defaults.barSpaceLabel()),
+ _bars(0),
+ _metDir(towards),
+ _metLabels(new QStringList),
+ _instDir(away),
+ _instLabels(new QStringList)
+{
+ _objtype |= BAROBJ;
+
+ int i;
+ for (i = 0; i < numSides; i++)
+ _margins[i] = 0.0;
+ _labelColor[0] = defaults.labelColor(0);
+ _labelColor[1] = defaults.labelColor(1);
+ _labelColor[2] = defaults.labelColor(2);
+}
+
+void
+BarObj::finishedAdd()
+{
+ const ColorSpec *colSpec = NULL;
+ SoNode *object = ViewObj::object(_shape);
+ SoSeparator *labelSep = NULL;
+ SoSeparator *metricSep = NULL;
+ SoSeparator *instSep = NULL;
+ SoSeparator *barSep = new SoSeparator;
+ SoSeparator *baseSep = new SoSeparator;
+ SoTranslation *objTran = new SoTranslation;
+ SoTranslation *barTran = new SoTranslation;
+ SoTranslation *baseTran = new SoTranslation;
+ SoTranslation *modTran = new SoTranslation;
+ ColorScale *colScale = NULL;
+ LabelSide metSide = left;
+ LabelSide instSide = left;
+ Text **metText = NULL;
+ Text **instText = NULL;
+ int i;
+ int max = 0;
+ int numMetLabels = 0;
+ int numInstLabels = 0;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "BarObj::finishedAdd:" << endl;
+#endif
+
+ if (_metrics.numMetrics() == 0) {
+ BaseObj::addBase(_root);
+ pmprintf("%s: Error: Bar object has no metrics\n",
+ pmProgname);
+ _length = 0;
+ _width = baseWidth();
+ _depth = baseDepth();
+ return;
+ }
+
+ _root->addChild(objTran);
+
+ if (_metLabels->size() || _instLabels->size()) {
+ labelSep = new SoSeparator;
+ _root->addChild(labelSep);
+ SoBaseColor *base = new SoBaseColor;
+ base->rgb.setValue(_labelColor[0], _labelColor[1], _labelColor[2]);
+ labelSep->addChild(base);
+ }
+ _root->addChild(barSep);
+ barSep->addChild(barTran);
+ barSep->addChild(baseSep);
+ baseSep->addChild(baseTran);
+ barSep->addChild(modTran);
+ BaseObj::addBase(baseSep);
+
+ // Determine color mapping
+
+ if (_colors.size())
+ colSpec = theColorLists.list((const char *)_colors.toAscii());
+
+ if (colSpec != NULL) {
+ if (colSpec->_scale) {
+ if (_mod == BarMod::yScale) {
+ pmprintf("%s: Warning: Color scale ignored for Y-Scale Bar object.\n",
+ pmProgname);
+ }
+ else {
+ if (colSpec->_list.size() == 0)
+ colScale = new ColorScale(0.0, 0.0, 1.0);
+ else {
+ colScale = new ColorScale(*(colSpec->_list[0]));
+ for (i = 1; i < colSpec->_list.size(); i++)
+ colScale->add(new ColorStep(*(colSpec->_list[i]),
+ colSpec->_max[i]));
+ }
+ }
+ }
+ else if (_mod == BarMod::color || _mod == BarMod::colYScale) {
+ pmprintf("%s: Warning: Expected color scale for color modulated Bar object.\n",
+ pmProgname);
+
+ if (colSpec->_list.size() == 0)
+ colScale = new ColorScale(0.0, 0.0, 1.0);
+ else
+ colScale = new ColorScale(*(colSpec->_list[0]));
+ }
+ }
+ else {
+ pmprintf("%s: Warning: No colours specified for Bar objects, defaulting to blue.\n",
+ pmProgname);
+
+ if (_mod == BarMod::color || _mod == BarMod::colYScale)
+ colScale = new ColorScale(0.0, 0.0, 1.0);
+ }
+
+ if (_mod == BarMod::yScale) {
+ if (colSpec != NULL)
+ for (i = 0; i < colSpec->_list.size(); i++)
+ _metrics.add(*(colSpec->_list)[i]);
+ _metrics.resolveColors(MetricList::perMetric);
+ }
+
+ // Generate Bar Modulate Object
+ if (_mod == BarMod::yScale)
+ _bars = new BarMod(&_metrics, object, _dir, _group,
+ (float)_length, (float)_maxHeight, (float)_length,
+ (float)_xSpace, (float)_zSpace);
+ else {
+ _bars = new BarMod(&_metrics, *colScale, object, _dir, _mod, _group,
+ (float)_length, (float)_maxHeight, (float)_length,
+ (float)_xSpace, (float)_zSpace);
+ }
+
+ barSep->addChild(_bars->root());
+ BaseObj::add(_bars);
+
+ // Generate Labels
+
+ if (_metLabels->size()) {
+ if (_dir == BarMod::instPerRow)
+ if (_metDir == away)
+ metSide = below;
+ else
+ metSide = above;
+ else
+ if (_metDir == away)
+ metSide = right;
+ else
+ metSide = left;
+
+ metricSep = new SoSeparator;
+ labelSep->addChild(metricSep);
+
+ if (_metLabels->size() < _metrics.numMetrics())
+ numMetLabels = _metLabels->size();
+ else
+ numMetLabels = _metrics.numMetrics();
+
+ metText = calcLabels(*_metLabels, metSide, numMetLabels);
+ }
+
+ if (_instLabels->size()) {
+ if (_dir == BarMod::instPerCol) {
+ max = _bars->cols();
+ if (_instDir == away)
+ instSide = below;
+ else
+ instSide = above;
+ }
+ else {
+ max = _bars->rows();
+ if (_instDir == away)
+ instSide = right;
+ else
+ instSide = left;
+ }
+
+ instSep = new SoSeparator;
+ labelSep->addChild(instSep);
+
+ if (_instLabels->size() < max)
+ numInstLabels = _instLabels->size();
+ else
+ numInstLabels = max;
+
+ instText = calcLabels(*_instLabels, instSide, numInstLabels);
+ }
+
+ // Width and depth of bars only, effects of labels added later
+
+ _width = _bars->width();
+ _depth = _bars->depth();
+
+ // Insert the labels
+
+ if (numMetLabels)
+ metricSep->addChild(doLabels(metText, metSide, numMetLabels));
+
+ if (numInstLabels)
+ instSep->addChild(doLabels(instText, instSide, numInstLabels));
+
+ // Work out where the bars live
+
+ _bars->regenerate(_length, _length, _xSpace, _zSpace);
+ _width = _bars->width();
+ _depth = _bars->depth();
+
+ baseTran->translation.setValue(_width / 2.0, 0.0, _depth / 2.0);
+
+ _width += (u_int32_t)(baseWidth() + _margins[left] + _margins[right]+0.5);
+ _depth += (u_int32_t)(baseDepth() + _margins[above] + _margins[below]+0.5);
+
+ objTran->translation.setValue((_width / -2.0), 0.0, (_depth / -2.0));
+
+ barTran->translation.setValue(_margins[left] + borderX(), 0.0,
+ _margins[above] + borderZ());
+
+
+ modTran->translation.setValue(0.0,
+ (BaseObj::state() ? baseHeight() : 0.0),
+ 0.0);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "BarObj::finishedAdd: metric list = " << endl
+ << _metrics << endl;
+#endif
+
+ if (_metrics.numMetrics())
+ ViewObj::theNumModObjects++;
+
+ // Cleanup
+
+ if (colScale)
+ delete colScale;
+ delete _metLabels;
+ delete _instLabels;
+}
+
+void
+BarObj::setTran(float xTran, float zTran, int setWidth, int setDepth)
+{
+ BaseObj::setBaseSize(width() - _margins[left] - _margins[right],
+ depth() - _margins[above] - _margins[below]);
+ BaseObj::setTran(xTran + (width() / 2.0),
+ zTran + (depth() / 2.0),
+ setWidth, setDepth);
+}
+
+QTextStream&
+operator<<(QTextStream& os, BarObj const& rhs)
+{
+ rhs.display(os);
+ return os;
+}
+
+void
+BarObj::display(QTextStream& os) const
+{
+ BaseObj::display(os);
+
+ if (_bars == NULL) {
+ os << "No valid metrics" << endl;
+ return;
+ }
+
+ os << ", dir = "
+ << (_dir == BarMod::instPerCol ? "instPerCol" : "instPerRow")
+ << ", length = " << _length << ", xSpace = " << _xSpace << ", zSpace = "
+ << _zSpace << ", labelSpace = " << _labelSpace << ", rows = " << _rows
+ << ", cols = " << _cols << ", num bars = " << _bars->numBars()
+ << ", shape = ";
+ ViewObj::dumpShape(os, _shape);
+ os << ", margins: left = " << _margins[left] << ", right = "
+ << _margins[right] << ", above = " << _margins[above]
+ << ", below = " << _margins[below];
+}
+
+const char*
+BarObj::name() const
+{
+ static QString myName;
+
+ if (myName.size() == 0) {
+ if (_bars == NULL)
+ myName = "Invalid bar object";
+ else {
+ myName = _bars->modStr();
+ myName.append(" Bar Object (");
+ myName.append(_bars->dirStr());
+ myName.append(QChar(')'));
+ }
+ }
+
+ return (const char *)myName.toAscii();
+}
+
+Text **
+BarObj::calcLabels(const QStringList &labels, LabelSide side, int numLabels)
+{
+ Text **text = NULL;
+ int i;
+ int maxWidth = 0;
+ int maxDepth = 0;
+
+ text= new Text*[numLabels];
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ cerr << "BarObj::calcLabels: " << numLabels << " labels on the ";
+ switch(side) {
+ case left:
+ cerr << "left";
+ break;
+ case right:
+ cerr << "right";
+ break;
+ case above:
+ cerr << "above";
+ break;
+ case below:
+ cerr << "below";
+ break;
+ }
+ cerr << " side" << endl;
+ }
+#endif
+
+ // Create the text objects so that we know how big they are
+
+ for (i = 0; i < numLabels; i++) {
+ if (side == above || side == below)
+ text[i] = new Text(labels[i], Text::down, Text::medium);
+ else
+ text[i] = new Text(labels[i], Text::right, Text::medium);
+
+ if (text[i]->width() > maxWidth)
+ maxWidth = text[i]->width();
+ if (text[i]->depth() > maxDepth)
+ maxDepth = text[i]->depth();
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "BarObj::calcLabels: maxWidth = " << maxWidth
+ << ", maxDepth = " << maxDepth << endl;
+#endif
+
+ // Determine if the size of the bars will need to be increased
+
+ if (side == above || side == below) {
+ _margins[side] = maxDepth + _labelSpace;
+ if (maxWidth > _length) {
+ _length = maxWidth;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "BarObj::calcLabels: length (width) increased to "
+ << _length << endl;
+#endif
+
+ }
+ }
+ else {
+ _margins[side] = maxWidth + _labelSpace;
+ if (maxDepth > _length) {
+ _length = maxDepth;
+
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "BarObj::calcLabels: length (depth) increased to "
+ << _length << endl;
+#endif
+ }
+ }
+ return text;
+}
+
+SoNode *
+BarObj::doLabels(Text **text, LabelSide side, int numLabels)
+{
+ SoSeparator *sep = new SoSeparator;
+ SoTranslation *tran = new SoTranslation;
+ int i;
+ int maxWidth = 0;
+ int maxDepth = 0;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ cerr << "BarObj::doLabels: " << numLabels << " labels on the ";
+ switch(side) {
+ case left:
+ cerr << "left";
+ break;
+ case right:
+ cerr << "right";
+ break;
+ case above:
+ cerr << "above";
+ break;
+ case below:
+ cerr << "below";
+ break;
+ }
+ cerr << " side" << endl;
+ }
+#endif
+
+ sep->addChild(tran);
+
+ // Determine the translation to the first label, subsequent labels
+ // are translated from the first
+
+ maxWidth = _length + _xSpace;
+ maxDepth = _length + _zSpace;
+
+ switch (side) {
+ case left:
+ tran->translation.setValue(_margins[left] - _labelSpace, 0.0,
+ _margins[above] + borderZ());
+ break;
+ case right:
+ tran->translation.setValue(
+ _margins[left] + _width + baseWidth() + _labelSpace,
+ 0.0, _margins[above] + borderZ());
+ break;
+ case above:
+ tran->translation.setValue(_margins[left] + borderX(), 0.0,
+ _margins[above] - _labelSpace);
+ break;
+ case below:
+ tran->translation.setValue(_margins[left] + borderX(), 0.0,
+ _margins[above] + _depth + baseDepth() + _labelSpace);
+ break;
+ default:
+ break;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ float x, y, z;
+ tran->translation.getValue().getValue(x, y, z);
+ cerr << "BarObj::doLabels: translation set to " << x << ',' << y
+ << ',' << z << endl;
+ }
+#endif
+
+ // Add each label to the scene graph
+
+ for (i = 0; i < numLabels; i++) {
+ SoSeparator *labelSep = new SoSeparator;
+ sep->addChild(labelSep);
+
+ SoTranslation *labelTran = new SoTranslation;
+ labelSep->addChild(labelTran);
+
+ switch (side) {
+ case left:
+ labelTran->translation.setValue(0.0,
+ 0.0,
+ (maxDepth * i) + ((_length - (float)text[i]->depth())/ 2.0));
+ break;
+ case right:
+ labelTran->translation.setValue(text[i]->width(), 0.0,
+ (maxDepth * i) + ((_length - (float)text[i]->depth())/ 2.0));
+ break;
+ case above:
+ labelTran->translation.setValue(
+ (maxWidth * i) + ((_length - (float)text[i]->width())/ 2.0),
+ 0.0, 0.0);
+ break;
+ case below:
+ labelTran->translation.setValue(
+ (maxWidth * i) + ((_length - (float)text[i]->width())/ 2.0),
+ 0.0, text[i]->depth());
+ break;
+ default:
+ break;
+ }
+
+ labelSep->addChild(text[i]->root());
+ }
+
+ // Do not delete contents, just the array pointer
+ delete [] text;
+
+ return sep;
+}
diff --git a/src/pmview/barobj.h b/src/pmview/barobj.h
new file mode 100644
index 0000000..c9566a7
--- /dev/null
+++ b/src/pmview/barobj.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _BAROBJ_H_
+#define _BAROBJ_H_
+
+#include "barmod.h"
+#include "modobj.h"
+#include "metriclist.h"
+#include <QtCore/QStringList>
+
+class SoNode;
+class SoTranslation;
+class Text;
+
+class BarObj : public ModObj
+{
+public:
+
+ enum LabelDir { away, towards };
+ enum LabelSide { left, right, above, below, numSides };
+
+protected:
+
+ ViewObj::Shape _shape;
+ BarMod::Direction _dir;
+ BarMod::Modulation _mod;
+ BarMod::Grouping _group;
+ int _width;
+ int _depth;
+ int _xSpace;
+ int _zSpace;
+ int _labelSpace;
+ BarMod *_bars;
+ LabelDir _metDir;
+ QStringList *_metLabels;
+ LabelDir _instDir;
+ QStringList *_instLabels;
+ float _margins[numSides];
+ float _labelColor[3];
+
+public:
+
+ virtual ~BarObj();
+
+ BarObj(ViewObj::Shape shape,
+ BarMod::Direction dir,
+ BarMod::Modulation mod,
+ BarMod::Grouping group,
+ bool baseFlag,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols = 1, int rows = 1,
+ BaseObj::Alignment align = BaseObj::center);
+
+ virtual int width() const
+ { return _width; }
+ virtual int depth() const
+ { return _depth; }
+ Shape shape() const
+ { return _shape; }
+ BarMod::Direction dir() const
+ { return _dir; }
+ BarMod::Modulation mod() const
+ { return _mod; }
+ int numMetricLabels() const
+ { return _metLabels->size(); }
+ LabelDir metricLabelDir() const
+ { return _metDir; }
+ int numInstLabels() const
+ { return _instLabels->size(); }
+ LabelDir instLabelDir() const
+ { return _instDir; }
+
+ void addMetric(const char *metric, double scale, const char *label)
+ { if (_metrics.add(metric, scale) >= 0) _metLabels->append(label); }
+
+ void addMetricLabel(const char *label)
+ { _metLabels->append(label); }
+ void addInstLabel(const char *label)
+ { _instLabels->append(label); }
+
+ virtual void finishedAdd();
+
+ // Local change
+ int &xSpace()
+ { return _xSpace; }
+ int &zSpace()
+ { return _zSpace; }
+ LabelDir &metricLabelDir()
+ { return _metDir; }
+ LabelDir &instLabelDir()
+ { return _instDir; }
+
+ virtual void setTran(float xTran, float zTran, int width, int depth);
+
+ virtual const char* name() const;
+
+ virtual void display(QTextStream& os) const;
+
+ friend QTextStream& operator<<(QTextStream& os, BarObj const& rhs);
+
+private:
+
+ Text ** calcLabels(const QStringList &labels, LabelSide side,
+ int numLabels);
+ SoNode *doLabels(Text **text, LabelSide side, int numLabels);
+
+ BarObj();
+ BarObj(BarObj const&);
+ BarObj const& operator=(BarObj const &);
+};
+
+#endif /* _BAROBJ_H_ */
diff --git a/src/pmview/baseobj.cpp b/src/pmview/baseobj.cpp
new file mode 100644
index 0000000..8646381
--- /dev/null
+++ b/src/pmview/baseobj.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoCube.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include "baseobj.h"
+#include "defaultobj.h"
+
+BaseObj::~BaseObj()
+{
+ delete(_mod);
+}
+
+BaseObj::BaseObj(bool onFlag,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols, int rows,
+ BaseObj::Alignment align)
+: ViewObj(x, y, cols, rows, align),
+ _on(onFlag),
+ _borderX(defaults.baseBorderX()),
+ _borderZ(defaults.baseBorderZ()),
+ _baseHeight(defaults.baseHeight()),
+ _length(defaults.barLength()),
+ _maxHeight(defaults.barHeight()),
+ _mod(0),
+ _cube(0),
+ _label("\n")
+{
+ _objtype |= BASEOBJ;
+
+ _baseColor[0] = defaults.baseColor(0);
+ _baseColor[1] = defaults.baseColor(1);
+ _baseColor[2] = defaults.baseColor(2);
+}
+
+void
+BaseObj::addBase(SoSeparator *sep)
+{
+ SoSeparator *cubeSep = new SoSeparator;
+
+ if (_on) {
+ SoTranslation *tran = new SoTranslation;
+ tran->translation.setValue(0.0, _baseHeight / 2, 0.0);
+ sep->addChild(tran);
+ SoBaseColor *col = new SoBaseColor;
+ col->rgb.setValue(_baseColor[0], _baseColor[1], _baseColor[2]);
+ cubeSep->addChild(col);
+ _cube = new SoCube;
+ _cube->width = baseWidth();
+ _cube->depth = baseDepth();
+ _cube->height = _baseHeight;
+ cubeSep->addChild(_cube);
+ }
+
+ _mod = new ToggleMod(cubeSep, (const char *)_label.toAscii());
+ sep->addChild(_mod->root());
+
+ if (_on) {
+ SoTranslation *tran2 = new SoTranslation;
+ tran2->translation.setValue(0.0, _baseHeight / 2.0, 0.0);
+ sep->addChild(tran2);
+ }
+}
+
+void
+BaseObj::setBaseSize(int width, int depth)
+{
+ if (_on) {
+ _cube->width = width;
+ _cube->depth = depth;
+ }
+}
+
+#if 0
+void
+BaseObj::setTran(float xTran, float zTran, int setWidth, int setDepth)
+{
+ ViewObj::setTran(xTran, zTran, setWidth, setDepth);
+}
+
+#endif
+
+QTextStream&
+operator<<(QTextStream& os, BaseObj const& rhs)
+{
+ rhs.display(os);
+ return os;
+}
+
+void
+BaseObj::display(QTextStream& os) const
+{
+ ViewObj::display(os);
+ os << ", border: X = " << _borderX << ", Z = " << _borderZ
+ << ", height = " << _baseHeight << ", length = " << _length
+ << ", maxHeight = " << _maxHeight << ", color = " << _baseColor[0]
+ << ',' << _baseColor[1] << ',' << _baseColor[2] << ", on = "
+ << (_on == true ? "true" : "false") << ", label = "
+ << (_label == "\n" ? "\\n" : _label);
+}
+
+void
+BaseObj::add(Modulate *mod)
+{
+ _mod->addMod(mod);
+}
+
+void
+BaseObj::finishedAdd()
+{
+}
diff --git a/src/pmview/baseobj.h b/src/pmview/baseobj.h
new file mode 100644
index 0000000..e2736c0
--- /dev/null
+++ b/src/pmview/baseobj.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _BASEOBJ_H_
+#define _BASEOBJ_H_
+
+#include "viewobj.h"
+#include "togglemod.h"
+
+class SoCube;
+
+class BaseObj : public ViewObj
+{
+protected:
+
+ bool _on;
+ int _borderX;
+ int _borderZ;
+ int _baseHeight;
+ int _length;
+ int _maxHeight;
+ float _baseColor[3];
+ ToggleMod *_mod;
+ SoCube *_cube;
+ QString _label;
+
+public:
+
+ virtual ~BaseObj();
+
+ BaseObj(bool onFlag,
+ const DefaultObj &defaults,
+ int, int,
+ int cols = 1, int rows = 1,
+ BaseObj::Alignment align = BaseObj::center);
+
+ int borderX() const
+ { return _borderX; }
+ int borderZ() const
+ { return _borderZ; }
+ int baseWidth() const
+ { return _borderX * 2; }
+ int baseDepth() const
+ { return _borderZ * 2; }
+ int baseHeight() const
+ { return _baseHeight; }
+ float baseColor(int i) const
+ { return _baseColor[i]; }
+ const QString &label() const
+ { return _label; }
+ int length() const
+ { return _length; }
+ int maxHeight() const
+ { return _maxHeight; }
+
+ // Local changes
+ int &borderX()
+ { return _borderX; }
+ int &borderZ()
+ { return _borderZ; }
+ int &baseHeight()
+ { return _baseHeight; }
+ void baseColor(float r, float g, float b)
+ { _baseColor[0] = r; _baseColor[1] = g; _baseColor[2] = b; }
+ QString &label()
+ { return _label; }
+ int &length()
+ { return _length; }
+ int& maxHeight()
+ { return _maxHeight; }
+
+ bool state() const
+ { return _on; }
+ void state(bool flag);
+
+ virtual int width() const = 0;
+ virtual int depth() const = 0;
+
+ void addBase(SoSeparator *sep);
+
+ void setBaseSize (int width, int depth);
+
+// virtual void setTran(float xTran, float zTran, int width, int depth);
+
+ virtual Modulate *modObj()
+ { return _mod; }
+
+ virtual void finishedAdd();
+
+ // Output
+ virtual void display(QTextStream& os) const;
+
+ virtual const char* name() const = 0;
+
+ friend QTextStream& operator<<(QTextStream& os, BaseObj const& rhs);
+
+protected:
+
+ void add(Modulate *mod);
+
+private:
+
+ BaseObj();
+ BaseObj(BaseObj const &);
+ BaseObj const& operator=(BaseObj const &);
+};
+
+#endif /* _BASEOBJ_H_ */
diff --git a/src/pmview/colorlist.cpp b/src/pmview/colorlist.cpp
new file mode 100644
index 0000000..5709a89
--- /dev/null
+++ b/src/pmview/colorlist.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 "main.h"
+#include "colorlist.h"
+#include <QtGui/QColor>
+
+ColorList theColorLists;
+
+ColorList::~ColorList()
+{
+ int i, j;
+
+ for (i = 0; i < _colors.size(); i++) {
+ ColorSpec &spec = *_colors[i];
+ for (j = 0; j < spec._list.size(); j++)
+ delete spec._list[j];
+ delete _colors[i];
+ }
+}
+
+ColorList::ColorList()
+: _names(),
+ _colors()
+{
+}
+
+const ColorSpec *
+ColorList::list(const char *name)
+{
+ int i;
+
+ for (i = 0; i < _names.size(); i++)
+ if (_names[i] == name)
+ return _colors[i];
+ return NULL;
+}
+
+bool
+ColorList::add(const char *name, const char *scaleColor)
+{
+ if (list(name) != NULL)
+ return false;
+
+ _names.append(name);
+ if (scaleColor != NULL) {
+ _colors.append(new ColorSpec(true));
+ if (addColor(scaleColor, 0.0) == false) {
+ _colors.last()->_list.append(new SbColor(0.0, 0.0, 1.0));
+ _colors.last()->_max.append(0.0);
+ }
+ }
+ else
+ _colors.append(new ColorSpec(false));
+
+ return true;
+}
+
+bool
+ColorList::add(const char *name, float red, float green, float blue)
+{
+ if (list(name) != NULL)
+ return false;
+
+ _names.append(name);
+ _colors.append(new ColorSpec(true));
+ _colors.last()->_list.append(new SbColor(red, green, blue));
+ _colors.last()->_max.append(0.0);
+
+ return true;
+}
+
+bool
+ColorList::findColor(const char *color, float &red, float &green, float &blue)
+{
+ QColor col;
+
+ col.setAllowX11ColorNames(true);
+ col.setNamedColor(color);
+ if (!col.isValid())
+ return false;
+
+ red = col.redF();
+ green = col.greenF();
+ blue = col.blueF();
+ return true;
+}
+
+bool
+ColorList::findColor(const char *color)
+{
+ QColor col;
+
+ col.setAllowX11ColorNames(true);
+ col.setNamedColor(color);
+ if (!col.isValid())
+ return false;
+
+ _colors.last()->_list.append(
+ new SbColor(col.redF(), col.greenF(), col.blueF()));
+ return true;
+}
+
+bool
+ColorList::addColor(const char *color)
+{
+ assert(_colors.size() > 0);
+ assert(_colors.last()->_scale == false);
+ return findColor(color);
+}
+
+bool
+ColorList::addColor(const char *color, double max)
+{
+ bool result;
+
+ assert(_colors.size() > 0);
+ assert(_colors.last()->_scale == true);
+ result = findColor(color);
+ if (result)
+ _colors.last()->_max.append(max);
+ return result;
+}
+
+bool
+ColorList::addColor(float red, float green, float blue)
+{
+ if (red < 0.0 || red > 1.0 || green < 0.0 || green > 1.0 ||
+ blue < 0.0 || blue > 1.0)
+ return false;
+
+ assert(_colors.size() > 0);
+ assert(_colors.last()->_scale == false);
+ _colors.last()->_list.append(new SbColor(red, green, blue));
+ return true;
+}
+
+bool
+ColorList::addColor(float red, float green, float blue, double max)
+{
+ if (red < 0.0 || red > 1.0 || green < 0.0 || green > 1.0 ||
+ blue < 0.0 || blue > 1.0)
+ return false;
+
+ assert(_colors.size() > 0);
+ assert(_colors.last()->_scale == true);
+ _colors.last()->_list.append(new SbColor(red, green, blue));
+ _colors.last()->_max.append(max);
+ return true;
+}
+
+QTextStream&
+operator<<(QTextStream& os, ColorList const& rhs)
+{
+ int i, j;
+ float r, g, b;
+
+ for (i = 0; i < rhs.numLists(); i++) {
+ const ColorSpec &list = *(rhs._colors[i]);
+ os << '[' << i << "] = " << rhs._names[i] << ", scale = "
+ << (list._scale == true ? "true" : "false") << ": ";
+ if (list._list.size()) {
+ for (j = 0; j < list._list.size(); j++) {
+ list._list[j]->getValue(r, g, b);
+ os << r << ',' << g << ',' << b;
+ if (list._scale)
+ os << "<=" << list._max[j];
+ os << ' ';
+ }
+ }
+ os << endl;
+ }
+ return os;
+}
+
diff --git a/src/pmview/colorlist.h b/src/pmview/colorlist.h
new file mode 100644
index 0000000..8f8a431
--- /dev/null
+++ b/src/pmview/colorlist.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _COLORLIST_H_
+#define _COLORLIST_H_
+
+#include "metriclist.h"
+#include <QStringList>
+
+struct ColorSpec;
+
+typedef QList<ColorSpec *> ColorsList;
+
+class ColorList
+{
+private:
+
+ QStringList _names;
+ ColorsList _colors;
+
+public:
+
+ virtual ~ColorList();
+
+ ColorList();
+
+ int numLists() const
+ { return _colors.size(); }
+
+ const ColorSpec *list(const char *name);
+
+ bool add(const char *name, const char *color = NULL);
+ bool add(const char *name, float red, float green, float blue);
+
+ // Add colors
+ bool addColor(const char *color);
+ bool addColor(float red, float blue, float green);
+
+ // Add scaled colors
+ bool addColor(const char *color, double max);
+ bool addColor(float red, float green, float blue, double max);
+
+ static bool findColor(const char *color, float &r, float &g, float &b);
+
+ friend QTextStream& operator<<(QTextStream& os, ColorList const& rhs);
+
+private:
+ bool findColor(const char *color);
+
+ ColorList(ColorList const &);
+ ColorList const& operator=(ColorList const &);
+ // Never defined
+};
+
+struct ColorSpec
+{
+ bool _scale;
+ SbColorList _list;
+ QList<double> _max;
+
+ ColorSpec(bool scale) : _scale(scale) {}
+};
+
+extern ColorList theColorLists;
+
+#endif /* _COLORLIST_H_ */
diff --git a/src/pmview/colormod.cpp b/src/pmview/colormod.cpp
new file mode 100644
index 0000000..b2cefd9
--- /dev/null
+++ b/src/pmview/colormod.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include "main.h"
+#include "colormod.h"
+#include "modlist.h"
+#include "launch.h"
+
+#include <iostream>
+using namespace std;
+
+ColorMod::~ColorMod()
+{
+}
+
+ColorMod::ColorMod(const char *metric, double scale,
+ const ColorScale &colors, SoNode *obj)
+: Modulate(metric, scale),
+ _state(Modulate::start),
+ _scale(colors),
+ _color(0)
+{
+ _root = new SoSeparator;
+ _color = new SoBaseColor;
+
+ _color->rgb.setValue(_errorColor.getValue());
+ _root->addChild(_color);
+ _root->addChild(obj);
+
+ if (_metrics->numValues() == 1 && _scale.numSteps() && status() >= 0) {
+ add();
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ColorMod: Added " << metric << " (Id = "
+ << _root->getName().getString() << ")" << endl;
+#endif
+
+ }
+ else if (_metrics->numValues() > 1) {
+ warningMsg(_POS_,
+ "Color modulated metric (%s) has more than one value (%d)",
+ metric, _metrics->numValues());
+ }
+ else if (_scale.numSteps() == 0) {
+ warningMsg(_POS_,
+ "No color steps for color modulated metric (%s)",
+ metric);
+ }
+}
+
+void
+ColorMod::refresh(bool fetchFlag)
+{
+ QmcMetric &metric = _metrics->metric(0);
+
+ if (status() < 0)
+ return;
+
+ if (fetchFlag)
+ metric.update();
+
+ if (metric.error(0) <= 0) {
+ if (_state != Modulate::error) {
+ _color->rgb.setValue(_errorColor.getValue());
+ _state = Modulate::error;
+ }
+ }
+ else {
+ double value = metric.value(0) * theScale;
+ if (value > theNormError) {
+ if (_state != Modulate::saturated) {
+ _color->rgb.setValue(Modulate::_saturatedColor);
+ _state = Modulate::saturated;
+ }
+ }
+ else {
+ if (_state != Modulate::normal)
+ _state = Modulate::normal;
+ _color->rgb.setValue(_scale.step(value).color().getValue());
+ }
+ }
+}
+
+void
+ColorMod::dump(QTextStream &os) const
+{
+ os << "ColorMod: ";
+ if (status() < 0)
+ os << "Invalid Metric: " << pmErrStr(status()) << endl;
+ else {
+ os << "state = ";
+ dumpState(os, _state);
+ os << ", scale = " << _scale << ": ";
+ _metrics->metric(0).dump(os, true);
+ }
+}
+
+void
+ColorMod::infoText(QString &str, bool) const
+{
+ const QmcMetric &metric = _metrics->metric(0);
+ str = metric.spec(true, true, 0);
+ str.append(QChar('\n'));
+ if (_state == Modulate::error)
+ str.append(theErrorText);
+ else if (_state == Modulate::start)
+ str.append(theStartText);
+ else {
+ QString value;
+ str.append(value.setNum(metric.realValue(0), 'g', 4));
+ str.append(QChar(' '));
+ if (metric.desc().units().length() > 0)
+ str.append(metric.desc().units());
+ str.append(" [");
+ str.append(value.setNum(metric.value(0) * 100.0 * theScale, 'g', 4));
+ str.append("% of color scale]");
+ }
+}
+
+void
+ColorMod::launch(Launch &launch, bool) const
+{
+ if (status() < 0)
+ return;
+ launch.startGroup("point");
+ launch.addMetric(_metrics->metric(0), _scale, 0);
+ launch.endGroup();
+}
+
+int
+ColorMod::select(SoPath *)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ColorMod::select: " << _metrics->metric(0) << endl;
+#endif
+ return 1;
+}
+
+int
+ColorMod::remove(SoPath *)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ColorMod::remove: " << _metrics->metric(0) << endl;
+#endif
+ return 0;
+}
diff --git a/src/pmview/colormod.h b/src/pmview/colormod.h
new file mode 100644
index 0000000..c41f957
--- /dev/null
+++ b/src/pmview/colormod.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _COLORMOD_H
+#define _COLORMOD_H
+
+#include "colorscale.h"
+#include "modulate.h"
+
+class SoBaseColor;
+class SoNode;
+class Launch;
+
+class ColorMod : public Modulate
+{
+private:
+
+ State _state;
+ ColorScale _scale;
+ SoBaseColor *_color;
+
+public:
+
+ virtual ~ColorMod();
+
+ ColorMod(const char *metric, double scale,
+ const ColorScale &colors, SoNode *obj);
+
+ virtual void refresh(bool fetchFlag);
+
+ virtual int select(SoPath *);
+ virtual int remove(SoPath *);
+
+ virtual void infoText(QString &str, bool) const;
+
+ virtual void launch(Launch &launch, bool) const;
+
+ virtual void dump(QTextStream &) const;
+
+private:
+
+ ColorMod();
+ ColorMod(const ColorMod &);
+ const ColorMod &operator=(const ColorMod &);
+ // Never defined
+};
+
+#endif /* _COLORMOD_H */
diff --git a/src/pmview/colorscale.cpp b/src/pmview/colorscale.cpp
new file mode 100644
index 0000000..c90658d
--- /dev/null
+++ b/src/pmview/colorscale.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 "main.h"
+#include "colorscale.h"
+
+ColorStep::~ColorStep()
+{
+}
+
+ColorStep::ColorStep(SbColor col, float val)
+: _color(),
+ _min(val)
+{
+ _color.setValue(col.getValue());
+}
+
+ColorStep::ColorStep(float r, float g, float b, float val)
+: _color(),
+ _min(val)
+{
+ SbColor tmp(r, g, b);
+ _color.setValue(tmp.getValue());
+}
+
+ColorStep::ColorStep(uint32_t col, float val)
+: _color(),
+ _min(val)
+{
+ float dummy = 0.0;
+ _color.setPackedValue(col, dummy);
+}
+
+ColorStep::ColorStep(const ColorStep &rhs)
+: _color(),
+ _min(rhs._min)
+{
+ _color.setValue(rhs._color.getValue());
+}
+
+const ColorStep &
+ColorStep::operator=(const ColorStep &rhs)
+{
+ if (this != &rhs) {
+ _color.setValue(rhs._color.getValue());
+ _min = rhs._min;
+ }
+ return *this;
+}
+
+ColorScale::~ColorScale()
+{
+ int i;
+
+ for (i = 0; i < _colors.size(); i++)
+ delete _colors.takeAt(i);
+}
+
+ColorScale::ColorScale(const SbColor &col)
+: _colors()
+{
+ add(new ColorStep(col));
+}
+
+ColorScale::ColorScale(float r, float g, float b)
+: _colors()
+{
+ add(new ColorStep(r, g, b));
+}
+
+ColorScale::ColorScale(uint32_t col)
+: _colors()
+{
+ add(new ColorStep(col));
+}
+
+ColorScale::ColorScale(const ColorScale &rhs)
+: _colors()
+{
+ int i;
+
+ for (i = 0; i < rhs._colors.size(); i++)
+ add(new ColorStep(rhs[i]));
+}
+
+const ColorScale &
+ColorScale::operator=(const ColorScale &rhs)
+{
+ int i;
+
+ if (this != &rhs) {
+ for (i = 0; i < _colors.size(); i++)
+ delete _colors.takeAt(i);
+ for (i = 0; i < rhs._colors.size(); i++)
+ add(new ColorStep(rhs[i]));
+ }
+ return *this;
+}
+
+int
+ColorScale::add(ColorStep *ptr)
+{
+ if (_colors.size()) {
+ float prev = _colors.last()->min();
+ if (prev >= ptr->min()) {
+ warningMsg(_POS_,
+ "Color step (%f) was less than previous step (%f), skipping.",
+ ptr->min(), prev);
+ return -1;
+ }
+ }
+ _colors.append(ptr);
+
+ return 0;
+}
+
+const ColorStep &
+ColorScale::step(float value)
+{
+ int i = _colors.size();
+
+ while (i > 0 && _colors[i-1]->min() > value)
+ i--;
+
+ if (i == 0)
+ return *(_colors[0]);
+ return *(_colors[i-1]);
+}
+
+QTextStream&
+operator<<(QTextStream &os, const ColorScale &rhs)
+{
+ int i;
+
+ if (rhs._colors.size() > 0) {
+ os << '[' << rhs[0].min();
+ for (i = 1; i < rhs.numSteps(); i++)
+ os << ", " << rhs[i].min();
+ os << ']';
+ }
+ else {
+ os << "empty";
+ }
+
+ return os;
+}
+
diff --git a/src/pmview/colorscale.h b/src/pmview/colorscale.h
new file mode 100644
index 0000000..5578092
--- /dev/null
+++ b/src/pmview/colorscale.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _COLORSCALE_H
+#define _COLORSCALE_H
+
+#include <Inventor/SbColor.h>
+#include <QtCore/QTextStream>
+#include <QtCore/QList>
+
+class ColorStep
+{
+private:
+
+ SbColor _color;
+ float _min;
+
+public:
+
+ ~ColorStep();
+
+ ColorStep(SbColor col, float val = 0.0);
+ ColorStep(float r, float g, float b, float val = 0.0);
+ ColorStep(uint32_t col, float val = 0.0);
+ ColorStep(const ColorStep &rhs);
+
+ const ColorStep &operator=(const ColorStep &);
+
+ const SbColor &color() const
+ { return _color; }
+ SbColor &color()
+ { return _color; }
+
+ const float &min() const
+ { return _min; }
+ float &min()
+ { return _min; }
+};
+
+typedef QList<ColorStep *> ColorStepList;
+
+class ColorScale
+{
+private:
+
+ ColorStepList _colors;
+
+public:
+
+ ~ColorScale();
+
+ ColorScale(const SbColor &col);
+ ColorScale(float r, float g, float b);
+ ColorScale(uint32_t col);
+ ColorScale(const ColorScale &);
+ const ColorScale &operator=(const ColorScale &);
+
+ int numSteps() const
+ { return _colors.size(); }
+
+ int add(ColorStep *ptr);
+
+ const ColorStep &operator[](int i) const
+ { return *(_colors[i]); }
+ ColorStep &operator[](int i)
+ { return *(_colors[i]); }
+
+ const ColorStep &step(float);
+
+ friend QTextStream &operator<<(QTextStream &os, const ColorScale &rhs);
+
+private:
+
+ ColorScale();
+ // Not defined
+};
+
+#endif /* _COLORSCALE_H */
diff --git a/src/pmview/colorscalemod.cpp b/src/pmview/colorscalemod.cpp
new file mode 100644
index 0000000..b162b49
--- /dev/null
+++ b/src/pmview/colorscalemod.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoScale.h>
+#include "main.h"
+#include "colorscalemod.h"
+#include "modlist.h"
+#include "launch.h"
+
+#include <iostream>
+using namespace std;
+
+ColorScaleMod::~ColorScaleMod()
+{
+}
+
+ColorScaleMod::ColorScaleMod(const char *metric, double scale,
+ const ColorScale &colors, SoNode *obj,
+ float xScale, float yScale, float zScale)
+: Modulate(metric, scale),
+ _state(Modulate::start),
+ _colScale(colors),
+ _scale(0),
+ _xScale(xScale),
+ _yScale(yScale),
+ _zScale(zScale),
+ _color(0)
+{
+ _root = new SoSeparator;
+ _color = new SoBaseColor;
+
+ _color->rgb.setValue(_errorColor.getValue());
+ _root->addChild(_color);
+
+ if (_metrics->numValues() == 1 && _colScale.numSteps() && status() >= 0) {
+
+ _scale = new SoScale;
+ _scale->scaleFactor.setValue(1.0, 1.0, 1.0);
+ _root->addChild(_scale);
+ _root->addChild(obj);
+
+ add();
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ColorScaleMod: Added " << metric << " (Id = "
+ << _root->getName().getString() << ")" << endl;
+#endif
+
+ }
+ else if (_metrics->numValues() > 1) {
+ warningMsg(_POS_,
+ "Color modulated metric (%s) has more than one value (%d)",
+ metric, _metrics->numValues());
+ _root->addChild(obj);
+ }
+ else if (status() < 0)
+ _root->addChild(obj);
+ else {
+ warningMsg(_POS_,
+ "No color steps for color modulated metric (%s)",
+ metric);
+ _root->addChild(obj);
+ }
+}
+
+void
+ColorScaleMod::refresh(bool fetchFlag)
+{
+ QmcMetric &metric = _metrics->metric(0);
+
+ if (status() < 0)
+ return;
+
+ if (fetchFlag)
+ metric.update();
+
+ if (metric.error(0) <= 0) {
+ if (_state != Modulate::error) {
+ _color->rgb.setValue(_errorColor.getValue());
+ _scale->scaleFactor.setValue((_xScale==0.0f ? 1.0 : theMinScale),
+ (_yScale==0.0f ? 1.0 : theMinScale),
+ (_zScale==0.0f ? 1.0 : theMinScale));
+ _state = Modulate::error;
+ }
+ }
+ else {
+ double value = metric.value(0) * theScale;
+ if (value > theNormError) {
+ if (_state != Modulate::saturated) {
+ _color->rgb.setValue(Modulate::_saturatedColor);
+ _scale->scaleFactor.setValue(1.0, 1.0, 1.0);
+ _state = Modulate::saturated;
+ }
+ }
+ else {
+ if (_state != Modulate::normal)
+ _state = Modulate::normal;
+ _color->rgb.setValue(_colScale.step(value).color().getValue());
+ if (value < Modulate::theMinScale)
+ value = Modulate::theMinScale;
+ else if (value > 1.0)
+ value = 1.0;
+ _scale->scaleFactor.setValue((_xScale==0.0f ? 1.0 : _xScale*value),
+ (_yScale==0.0f ? 1.0 : _yScale*value),
+ (_zScale==0.0f ? 1.0 : _zScale*value));
+ }
+ }
+}
+
+void
+ColorScaleMod::dump(QTextStream &os) const
+{
+ os << "ColorScaleMod: ";
+ if (status() < 0)
+ os << "Invalid Metric: " << pmErrStr(status()) << endl;
+ else {
+ os << "state = ";
+ dumpState(os, _state);
+ os << ", col scale = " << _colScale << ", y scale = "
+ << _scale->scaleFactor.getValue()[1]
+ << ": ";
+ _metrics->metric(0).dump(os, true);
+ }
+}
+
+void
+ColorScaleMod::infoText(QString &str, bool) const
+{
+ const QmcMetric &metric = _metrics->metric(0);
+
+ str = metric.spec(true, true, 0);
+ str.append(QChar('\n'));
+ if (_state == Modulate::error)
+ str.append(theErrorText);
+ else if (_state == Modulate::start)
+ str.append(theStartText);
+ else {
+ QString value;
+ str.append(value.setNum(metric.realValue(0), 'g', 4));
+ str.append(QChar(' '));
+ if (metric.desc().units().length() > 0)
+ str.append(metric.desc().units());
+ str.append(" [");
+ str.append(value.setNum(metric.realValue(0) * 100.0 * theScale, 'g', 4));
+ str.append("% of color scale]");
+ }
+}
+
+void
+ColorScaleMod::launch(Launch &launch, bool) const
+{
+ if (status() < 0)
+ return;
+ launch.startGroup("point");
+ launch.addMetric(_metrics->metric(0), _colScale, 0);
+ launch.endGroup();
+}
+
+int
+ColorScaleMod::select(SoPath *)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ColorScaleMod::select: " << _metrics->metric(0) << endl;
+#endif
+ return 1;
+}
+
+int
+ColorScaleMod::remove(SoPath *)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ColorScaleMod::remove: " << _metrics->metric(0) << endl;
+#endif
+ return 0;
+}
diff --git a/src/pmview/colorscalemod.h b/src/pmview/colorscalemod.h
new file mode 100644
index 0000000..66c670f
--- /dev/null
+++ b/src/pmview/colorscalemod.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _COLORSCALEMOD_H
+#define _COLORSCALEMOD_H
+
+#include "colorscale.h"
+#include "modulate.h"
+
+class SoBaseColor;
+class SoScale;
+class SoNode;
+class Launch;
+
+class ColorScaleMod : public Modulate
+{
+private:
+
+ State _state;
+ ColorScale _colScale;
+ SoScale *_scale;
+ float _xScale;
+ float _yScale;
+ float _zScale;
+ SoBaseColor *_color;
+
+public:
+
+ virtual ~ColorScaleMod();
+
+ ColorScaleMod(const char *metric, double scale,
+ const ColorScale &colors, SoNode *obj,
+ float xScale, float yScale, float zScale);
+
+ virtual void refresh(bool fetchFlag);
+
+ virtual int select(SoPath *);
+ virtual int remove(SoPath *);
+
+ virtual void infoText(QString &str, bool) const;
+
+ virtual void launch(Launch &launch, bool) const;
+
+ virtual void dump(QTextStream &) const;
+
+private:
+
+ ColorScaleMod();
+ ColorScaleMod(const ColorScaleMod &);
+ const ColorScaleMod &operator=(const ColorScaleMod &);
+ // Never defined
+};
+
+#endif /* _COLORSCALEMOD_H */
diff --git a/src/pmview/defaultobj.cpp b/src/pmview/defaultobj.cpp
new file mode 100644
index 0000000..977186e
--- /dev/null
+++ b/src/pmview/defaultobj.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 "defaultobj.h"
+#include "colorlist.h"
+#include <QtCore/QSettings>
+
+#include <iostream>
+using namespace std;
+
+DefaultObj *DefaultObj::theDefaultObj;
+
+DefaultObj::DefaultObj()
+: _baseBorderX(8),
+ _baseBorderZ(8),
+ _baseHeight(6),
+ _barSpaceX(8),
+ _barSpaceZ(8),
+ _barSpaceLabel(6),
+ _barLength(28),
+ _barHeight(80),
+ _labelMargin(5),
+ _gridMinWidth(20),
+ _gridMinDepth(20)
+{
+ _baseColor[0] = _baseColor[1] = _baseColor[2] = 0.15;
+ _labelColor[0] = _labelColor[1] = _labelColor[2] = 1.0;
+ _pipeLength = _barHeight;
+}
+
+const DefaultObj &
+DefaultObj::defObj()
+{
+ if (!theDefaultObj) {
+ theDefaultObj = new DefaultObj;
+ theDefaultObj->getResources();
+ }
+ return *theDefaultObj;
+}
+
+DefaultObj &
+DefaultObj::changeDefObj()
+{
+ if (!theDefaultObj) {
+ theDefaultObj = new DefaultObj;
+ theDefaultObj->getResources();
+ }
+ return *theDefaultObj;
+}
+
+DefaultObj::DefaultObj(const DefaultObj &rhs)
+: _baseBorderX(rhs._baseBorderX),
+ _baseBorderZ(rhs._baseBorderZ),
+ _baseHeight(rhs._baseHeight),
+ _barSpaceX(rhs._barSpaceX),
+ _barSpaceZ(rhs._barSpaceZ),
+ _barSpaceLabel(rhs._barSpaceLabel),
+ _barLength(rhs._barLength),
+ _barHeight(rhs._barHeight),
+ _labelMargin(rhs._labelMargin),
+ _gridMinWidth(rhs._gridMinWidth),
+ _gridMinDepth(rhs._gridMinDepth),
+ _pipeLength(rhs._pipeLength)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ _baseColor[i] = rhs._baseColor[i];
+ _labelColor[i] = rhs._labelColor[i];
+ }
+}
+
+const DefaultObj &
+DefaultObj::operator=(const DefaultObj &rhs)
+{
+ int i;
+
+ if (this != &rhs) {
+ _baseBorderX = rhs._baseBorderX;
+ _baseBorderZ = rhs._baseBorderZ;
+ _baseHeight = rhs._baseHeight;
+ _barSpaceX = rhs._barSpaceX;
+ _barSpaceZ = rhs._barSpaceZ;
+ _barSpaceLabel = rhs._barSpaceLabel;
+ _barLength = rhs._barLength;
+ _barHeight = rhs._barHeight;
+ _labelMargin = rhs._labelMargin;
+ _gridMinWidth = rhs._gridMinWidth;
+ _gridMinDepth = rhs._gridMinDepth;
+
+ for (i = 0; i < 3; i++) {
+ _baseColor[i] = rhs._baseColor[i];
+ _labelColor[i] = rhs._labelColor[i];
+ }
+ }
+ return *this;
+}
+
+QTextStream&
+operator<<(QTextStream &os, const DefaultObj &rhs)
+{
+ os << "baseBorderX=" << rhs._baseBorderX;
+ os << ", baseBorderZ=" << rhs._baseBorderZ;
+ os << ", baseHeight=" << rhs._baseHeight;
+ os << ", baseColor=" << rhs._baseColor[0] << ',' << rhs._baseColor[1]
+ << ',' << rhs._baseColor[2] << endl;
+ os << ", barSpaceX=" << rhs._barSpaceX;
+ os << ", barSpaceZ=" << rhs._barSpaceZ;
+ os << ", barSpaceLabel=" << rhs._barSpaceLabel;
+ os << ", barLength=" << rhs._barLength;
+ os << ", barHeight=" << rhs._barHeight;
+ os << ", labelMargin=" << rhs._labelMargin;
+ os << ", labelColor=" << rhs._labelColor[0] << ',' << rhs._labelColor[1]
+ << ',' << rhs._labelColor[2] << endl;
+ os << ", gridMinWidth=" << rhs._gridMinWidth;
+ os << ", gridMinDepth=" << rhs._gridMinDepth;
+ return os;
+}
+
+static void
+getColorResource(const char *name, QString label, float &r, float &g, float &b)
+{
+ if (label != QString::null && label.compare("default") != 0) {
+ const char *str = (const char *)label.toAscii();
+ if (ColorList::findColor(str, r, g, b) == false) {
+ pmprintf("%s: Unable to map color resource \"%s\" to \"%s\", "
+ "using default color rgbi:%f/%f/%f\n",
+ pmProgname, name, str, r, g, b);
+ }
+ }
+}
+
+void
+DefaultObj::getResources()
+{
+ QString color;
+ QSettings resources;
+ resources.beginGroup(pmProgname);
+
+ _baseBorderX = resources.value("baseBorderWidth", 8).toInt();
+ _baseBorderZ = resources.value("baseBorderDepth", 8).toInt();
+ _baseHeight = resources.value("baseHeight", 2).toInt();
+ color = resources.value("baseColor", QString("default")).toString();
+ getColorResource("baseColor", color,
+ _baseColor[0], _baseColor[1], _baseColor[2]);
+ _barSpaceX = resources.value("barSpaceWidth", 8).toInt();
+ _barSpaceZ = resources.value("barSpaceDepth", 8).toInt();
+ _barSpaceLabel = resources.value("barSpaceLabel", 6).toInt();
+ _barLength = resources.value("barLength", 28).toInt();
+ _barHeight = resources.value("barHeight", 80).toInt();
+ _labelMargin = resources.value("labelMargin", 5).toInt();
+ color = resources.value("labelColor", QString("default")).toString();
+ getColorResource("labelColor", color,
+ _labelColor[0], _labelColor[1], _labelColor[2]);
+ _gridMinWidth = resources.value("gridMinWidth", 20).toInt();
+ _gridMinDepth = resources.value("gridMinDepth", 20).toInt();
+
+ resources.endGroup();
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "DefaultObj::getResources: " << *this << endl;
+#endif
+}
diff --git a/src/pmview/defaultobj.h b/src/pmview/defaultobj.h
new file mode 100644
index 0000000..f600790
--- /dev/null
+++ b/src/pmview/defaultobj.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _DEFAULTOBJ_H_
+#define _DEFAULTOBJ_H_
+
+#include "main.h"
+#include <QtCore/QTextStream>
+
+class DefaultObj
+{
+private:
+
+ static DefaultObj *theDefaultObj;
+
+ int _baseBorderX;
+ int _baseBorderZ;
+ int _baseHeight;
+ float _baseColor[3];
+
+ int _barSpaceX;
+ int _barSpaceZ;
+ int _barSpaceLabel;
+ int _barLength;
+ int _barHeight;
+
+ int _labelMargin;
+ float _labelColor[3];
+
+ int _gridMinWidth;
+ int _gridMinDepth;
+ int _pipeLength;
+
+public:
+
+ ~DefaultObj()
+ {}
+
+ DefaultObj();
+ DefaultObj(const DefaultObj &);
+ const DefaultObj &operator=(const DefaultObj &rhs);
+
+ static const DefaultObj &defObj();
+
+ // Query
+ int baseBorderX() const
+ { return _baseBorderX; }
+ int baseBorderZ() const
+ { return _baseBorderZ; }
+ int baseHeight() const
+ { return _baseHeight; }
+ float baseColor(int i) const
+ { return _baseColor[i]; }
+ int barSpaceX() const
+ { return _barSpaceX; }
+ int barSpaceZ() const
+ { return _barSpaceZ; }
+ int barSpaceLabel() const
+ { return _barSpaceLabel; }
+ int barLength() const
+ { return _barLength; }
+ int barHeight() const
+ { return _barHeight; }
+ int labelMargin() const
+ { return _labelMargin; }
+ float labelColor(int i) const
+ { return _labelColor[i]; }
+ int gridMinWidth() const
+ { return _gridMinWidth; }
+ int gridMinDepth() const
+ { return _gridMinDepth; }
+ int pipeLength () const
+ { return _pipeLength; }
+
+ // Local Changes
+ int &baseBorderX()
+ { return _baseBorderX; }
+ int & pipeLength ()
+ { return _pipeLength; }
+ int &baseBorderZ()
+ { return _baseBorderZ; }
+ int &baseHeight()
+ { return _baseHeight; }
+ void baseColor(float r, float g, float b)
+ { _baseColor[0] = r; _baseColor[1] = g; _baseColor[2] = b; }
+ int &barSpaceX()
+ { return _barSpaceX; }
+ int &barSpaceZ()
+ { return _barSpaceZ; }
+ int &barSpaceLabel()
+ { return _barSpaceLabel; }
+ int &barLength()
+ { return _barLength; }
+ int &barHeight()
+ { return _barHeight; }
+ int &labelMargin()
+ { return _labelMargin; }
+ void labelColor(float r, float g, float b)
+ { _labelColor[0] = r; _labelColor[1] = g; _labelColor[2] = b; }
+ int &gridMinWidth()
+ { return _gridMinWidth; }
+ int &gridMinDepth()
+ { return _gridMinDepth; }
+
+ // Global
+ static void baseBorderX(int val)
+ { changeDefObj()._baseBorderX = val; }
+ static void baseBorderZ(int val)
+ { changeDefObj()._baseBorderZ = val; }
+ static void baseHeight(int val)
+ { changeDefObj()._baseHeight = val; }
+ static void baseColors(float r, float g, float b)
+ { changeDefObj().baseColor(r, g, b); }
+ static void barSpaceX(int val)
+ { changeDefObj()._barSpaceX = val; }
+ static void barSpaceZ(int val)
+ { changeDefObj()._barSpaceZ = val; }
+ static void barSpaceLabel(int val)
+ { changeDefObj()._barSpaceLabel = val; }
+ static void barLength(int val)
+ { changeDefObj()._barLength = val; }
+ static void barHeight(int val)
+ { changeDefObj()._barHeight = val; }
+ static void labelMargin(int val)
+ { changeDefObj()._labelMargin = val; }
+ static void labelColors(float r, float g, float b)
+ { changeDefObj().labelColor(r, g, b); }
+ static void gridMinWidth(int val)
+ { changeDefObj()._gridMinWidth = val; }
+ static void gridMinDepth(int val)
+ { changeDefObj()._gridMinDepth = val; }
+
+ friend QTextStream& operator<<(QTextStream &os, const DefaultObj &rhs);
+
+private:
+
+ static DefaultObj &changeDefObj();
+ void getResources();
+};
+
+#endif /* _DEFAULTOBJ_H_ */
diff --git a/src/pmview/error.cpp b/src/pmview/error.cpp
new file mode 100644
index 0000000..c5981d3
--- /dev/null
+++ b/src/pmview/error.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 "main.h"
+
+int errorCount;
+int lineNum;
+
+void
+yywarn(const char *s)
+{
+ const char * fmt = theConfigName.length() ? "%s: warning - %s(%d): %s\n":
+ "%s: warning - line %3$d: %4$s\n";
+ const char * config = (const char *)theConfigName.toAscii();
+
+ pmprintf(fmt, pmProgname, config, lineNum+1, s);
+ pmflush();
+}
+
+void
+yyerror(const char *s)
+{
+ const char * fmt = theConfigName.length() ? "%s: error - %s(%d): %s\n":
+ "%s: error - line %3$d: %4$s\n";
+ const char * config = (const char *)theConfigName.toAscii();
+ const char badeof[] = "unexpected end of file";
+
+ markpos();
+ if (!locateError())
+ s = (char *)badeof;
+
+ pmprintf(fmt, pmProgname, config, lineNum+1, s);
+ pmflush();
+ errorCount++; /* It's used in pmview.cpp to abort the execution */
+}
+
diff --git a/src/pmview/front-ends/GNUmakefile b/src/pmview/front-ends/GNUmakefile
new file mode 100644
index 0000000..c67f02b
--- /dev/null
+++ b/src/pmview/front-ends/GNUmakefile
@@ -0,0 +1,25 @@
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+
+#VIEWDIR = $(PCP_VAR_DIR)/config/pmview
+VIEWDIR = $(PCP_BIN_DIR)
+LOGDIR = $(PCP_VAR_DIR)/config/pmlogger
+ARGSDIR = $(PCP_SHARE_DIR)/lib
+
+VIEWS = clustervis dkvis mpvis nfsvis osvis weblogvis webpingvis webvis
+LOGGERS = config.dkvis config.mpvis config.nfsvis config.osvis \
+ config.weblogvis config.webpingvis config.webvis
+
+LSRCFILES = $(VIEWS) $(LOGGERS) pmview-args
+
+default build-me:
+
+include $(BUILDRULES)
+
+install: default
+ #$(INSTALL) -m 755 -d $(VIEWDIR)
+ $(INSTALL) -m 755 $(VIEWS) $(VIEWDIR)
+ $(INSTALL) -m 755 -d $(LOGDIR)
+ $(INSTALL) -m 444 $(LOGGERS) $(LOGDIR)
+ $(INSTALL) -m 755 -d $(ARGSDIR)
+ $(INSTALL) -m 755 pmview-args $(ARGSDIR)/pmview-args
diff --git a/src/pmview/front-ends/clustervis b/src/pmview/front-ends/clustervis
new file mode 100755
index 0000000..6cab7aa
--- /dev/null
+++ b/src/pmview/front-ends/clustervis
@@ -0,0 +1,331 @@
+#!/bin/sh
+#
+# Copyright (c) 2001 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+debug=false
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+# --- scaling parameters ---
+#
+
+# maximum packets per second
+max=750
+
+# maximum req rate (default: 5% of packet rate)
+maxreq=`expr $max / 20`
+
+# milliseconds per CPU
+maxcpu=1000
+
+#
+# clustervis tolerates multiple hosts or archives
+_pmview_multiple_sources_are_ok
+
+# --- define usage message ---
+#
+_usage()
+{
+ echo >$tmp.msg 'Usage: '$prog' [options]
+
+Default hosts are specified in /etc/nodes (or /etc/ace/nodes)
+or specify the file specifying cluster hosts with the -H flag.
+The -h flag may be used to specify multiple hosts or the -a flag
+may be used to specify multiple archives. The -h, -a and -H flags
+are all mutually exclusive.
+
+options:
+ -H nodes file specifying hosts in cluster
+ [default $PCP_CLUSTER_CONFIG or /etc/nodes or /etc/ace/nodes]
+ -m max maximum expected packets sent or received per sec [default 750]
+ -V verbose/diagnostic output
+
+pmview(1) options:'
+
+ _pmview_usage >> $tmp.msg
+ echo >> $tmp.msg
+ echo >> $tmp.msg 'Default title is: Web Server Activity'
+ echo >> $tmp.msg '
+ By default all network interfaces are shown, with a maximum packet rate
+ of '$max' packets per second. The maximum request rate is 5% (of the
+ maximum packet rate) and the maximum error rate is 20% of the maximum
+ request rate.
+
+ If given, the [interface ...] regular expressions restrict
+ the network statistics displayed to matching network interface names only.'
+
+ _pmview_info -f $tmp.msg
+}
+
+# --- build WM_COMMAND X(1) property for restart after login/logout ---
+#
+echo -n "pmview Version 2.1 \"$prog\"" > $tmp.pmview
+for arg
+do
+ echo -n " \"$arg\"" >>$tmp.pmview
+done
+echo >> $tmp.pmview
+
+# --- parse command line arguments ---
+#
+verbose=false
+argInterfaces=""
+hosts=""
+interfaces=""
+numsource=1
+if [ -z "$PCP_CLUSTER_CONFIG" ]
+then
+ nodesfile=/etc/nodes
+ [ ! -f "$nodesfile" ] && nodesfile=/etc/ace/nodes
+else
+ nodesfile="$PCP_CLUSTER_CONFIG"
+ if [ ! -f "$nodesfile" ]
+ then
+ echo "Error: \"$nodesfile\" specified in \$PCP_CLUSTER_CONFIG: file not found"
+ _usage
+ exit 1
+ fi
+fi
+
+livemode=false
+for f in $*
+do
+ [ $f = "-h" ] && livemode=true
+done
+
+_pmview_args "$@"
+$debug && echo "DEBUG msource=\"$msource\""
+
+if [ -n "$otherArgs" ]
+then
+ while getopts "?H:m:v:V" c $otherArgs
+ do
+ case $c
+ in
+ H)
+ nodesfile=$OPTARG
+ if [ ! -f "$nodesfile" ]
+ then
+ _pmview_error "$prog: \"$nodesfile\" for -H file not found"
+ #NOTREACHED
+ fi
+ ;;
+ m)
+ max=$OPTARG
+ if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -m must have a positive integral argument"
+ #NOTREACHED
+ fi
+ maxreq=`expr $max / 20`
+ ;;
+
+ V)
+ verbose=true
+ ;;
+
+ '?')
+ _usage
+ exit 1
+ ;;
+ esac
+ done
+fi
+
+if [ $numsource -eq 0 ]
+then
+ if [ -f $nodesfile ]
+ then
+ livemode=true
+ sourcelist=`sed -e '/^#/d' $nodesfile`
+ numsource=`echo $sourcelist | wc -w`
+ else
+ _pmview_error "$prog: -H, -a or -h must be given"
+ fi
+fi
+
+$debug && echo DEBUG sourcelist=\"$sourcelist\"
+hostcols=`echo "sqrt($numsource)" | bc`
+$debug && echo hostcols=$hostcols
+
+
+# --- set the window title ---
+#
+if [ -z "$titleArg" ]
+then
+ titleArg="SGI PCP : Cluster Node Activity"
+fi
+
+
+# ---- the real config starts here ---
+# pmview Version 2.1
+#
+cat << end-of-file >> $tmp.pmview
+
+_stackLength 26
+_marginWidth 4
+_marginDepth 4
+
+_colorList net_colors (
+ rgbi:0.8/0.0/0.0
+ rgbi:0.0/0.8/0.8
+ rgbi:1.0/0.5/0.0
+)
+
+_colorList cpu_colors ( red2 blue2 blue2 )
+
+# main grid
+_grid _show (
+
+end-of-file
+
+hostrow=0
+hostcol=0
+for source in $sourcelist
+do
+ if $livemode
+ then
+ host=$source
+ msource="-h $source"
+ else
+ host=`pmdumplog -l $source | $PCP_AWK_PROG '/^Performance/ {print $NF}'`
+ msource="-a $source"
+ fi
+
+ nice=`pmprobe $msource -i kernel.all.cpu.nice | $PCP_AWK_PROG '{print $2; exit}'`
+ if [ "$nice" = 1 ]
+ then
+ nicemetric=kernel.percpu.cpu.nice
+ else
+ nicemetric=""
+ fi
+
+ _pmview_cache_fetch -v \
+ kernel.percpu.cpu.user $nicemetric \
+ network.interface.in.packets \
+ network.interface.out.packets
+
+ # --- how many CPUs on this system? ---
+ #
+ if _pmview_fetch -I kernel.percpu.cpu.user
+ then
+ ncpu=`wc -l <$tmp.pmview_result`
+ else
+ _pmview_fetch_fail "get the number of CPUs"
+ fi
+
+ _pmview_cache_fetch -I network.interface.total.bytes
+
+ # --- how many network interfaces on this system? ---
+ #
+ if _pmview_fetch -I network.interface.in.packets
+ then
+ nnet=`grep -v '^lo' $tmp.pmview_result | wc -l`
+ else
+ _pmview_fetch_fail "get the number of network interfaces"
+ fi
+
+ rows=`echo "sqrt($ncpu + $ncpu + $nnet + $nnet)" | bc`
+ [ $rows -lt 4 ] && rows=4
+ row=0
+ col=0
+
+ echo "# grid for host $host" >>$tmp.pmview
+ echo "_baseHeight 8" >>$tmp.pmview
+ echo "_grid $hostcol $hostrow _hide (" >>$tmp.pmview
+
+ echo " _baseColor rgbi:0.4/0.4/0.6" >>$tmp.pmview
+ echo " _label 0 0 _down _large \"$host\"" >>$tmp.pmview
+ echo " _grid 1 0 _show (" >>$tmp.pmview
+
+ _pmview_fetch -I kernel.percpu.cpu.user
+ for cpu in `cat $tmp.pmview_result`
+ do
+ echo " _label $row $col _west \"$cpu\"" >>$tmp.pmview
+ echo " _stack `expr $row + 1` $col _hide (" >>$tmp.pmview
+ echo " _metrics (" >>$tmp.pmview
+ echo " $host:kernel.percpu.cpu.sys[$cpu] $maxcpu" >>$tmp.pmview
+ if [ ! -z "$nicemetric" ]
+ then
+ echo " $host:kernel.percpu.cpu.nice[$cpu] $maxcpu" >>$tmp.pmview
+ fi
+ echo " $host:kernel.percpu.cpu.user[$cpu] $maxcpu" >>$tmp.pmview
+ echo " )" >>$tmp.pmview
+ echo " _colorlist cpu_colors" >>$tmp.pmview
+ echo " )" >>$tmp.pmview
+
+ $debug && echo stack at row=`expr $row + 1` col=$col \"$cpu\"
+ $debug && echo label at row=$row col=$col
+
+ col=`expr $col + 1`
+ if [ $col -ge $rows ]
+ then
+ col=0
+ row=`expr $row + 2`
+ fi
+ done
+
+ _pmview_fetch -I network.interface.in.packets
+ grep -v '^lo' $tmp.pmview_result >$tmp.net
+ for net in `cat $tmp.net`
+ do
+ echo " _label $row $col _west \"$net\"" >>$tmp.pmview
+ echo " _stack `expr $row + 1` $col _hide (" >>$tmp.pmview
+ echo " _metrics (" >>$tmp.pmview
+ echo " $host:network.interface.total.errors[$net] $max" >>$tmp.pmview
+ echo " $host:network.interface.in.packets[$net] $max" >>$tmp.pmview
+ echo " $host:network.interface.out.packets[$net] $max" >>$tmp.pmview
+ echo " )" >>$tmp.pmview
+ echo " _colorlist net_colors" >>$tmp.pmview
+ echo " )" >>$tmp.pmview
+
+ $debug && echo stack at row=`expr $row + 1` col=$col \"$net\"
+ $debug && echo label at row=$row col=$col
+
+ col=`expr $col + 1`
+ if [ $col -ge $rows ]
+ then
+ col=0
+ row=`expr $row + 2`
+ fi
+
+ done
+ echo " )" >>$tmp.pmview
+ row=`expr $row + 1`
+ echo "# end of host grid" >>$tmp.pmview
+ echo ")" >>$tmp.pmview
+
+ hostcol=`expr $hostcol + 1`
+ if [ $hostcol -ge $hostcols ]
+ then
+ hostcol=0
+ hostrow=`expr $hostrow + 1`
+ fi
+
+done
+
+echo "" >>$tmp.pmview
+echo "# end of main grid" >>$tmp.pmview
+echo ")" >>$tmp.pmview
+
+$verbose && cat $tmp.pmview
+
+eval $PMVIEW <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'"
+
+exit
+
diff --git a/src/pmview/front-ends/config.clustervis b/src/pmview/front-ends/config.clustervis
new file mode 100644
index 0000000..118cb34
--- /dev/null
+++ b/src/pmview/front-ends/config.clustervis
@@ -0,0 +1,13 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with clustervis(1)
+#
+
+log advisory on default {
+ kernel.percpu.cpu.sys
+ kernel.percpu.cpu.user
+ network.interface.in.packets
+ network.interface.out.packets
+ network.interface.total.bytes
+ network.interface.total.errors
+}
diff --git a/src/pmview/front-ends/config.dkvis b/src/pmview/front-ends/config.dkvis
new file mode 100755
index 0000000..03e0e31
--- /dev/null
+++ b/src/pmview/front-ends/config.dkvis
@@ -0,0 +1,14 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with dkvis(1)
+#
+
+log advisory on default {
+ disk.dev.total
+ disk.dev.read
+ disk.dev.write
+ disk.dev.bytes
+ disk.dev.read_bytes
+ disk.dev.write_bytes
+ disk.dev.total_bytes
+}
diff --git a/src/pmview/front-ends/config.mpvis b/src/pmview/front-ends/config.mpvis
new file mode 100755
index 0000000..f28ce84
--- /dev/null
+++ b/src/pmview/front-ends/config.mpvis
@@ -0,0 +1,13 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with mpvis(1)
+#
+
+log advisory on default {
+ kernel.percpu.cpu.idle
+ kernel.percpu.cpu.intr
+ kernel.percpu.cpu.sys
+ kernel.percpu.cpu.sxbrk
+ kernel.percpu.cpu.user
+ kernel.percpu.cpu.wait.total
+}
diff --git a/src/pmview/front-ends/config.nfsvis b/src/pmview/front-ends/config.nfsvis
new file mode 100755
index 0000000..f8ab0fb
--- /dev/null
+++ b/src/pmview/front-ends/config.nfsvis
@@ -0,0 +1,12 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with nfsvis(1)
+#
+
+log advisory on default {
+ nfs
+}
+
+log advisory on default {
+ nfs3
+}
diff --git a/src/pmview/front-ends/config.osvis b/src/pmview/front-ends/config.osvis
new file mode 100755
index 0000000..629a3a4
--- /dev/null
+++ b/src/pmview/front-ends/config.osvis
@@ -0,0 +1,31 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with osvis(1)
+#
+log mandatory on once {
+ hinv.ncpu
+ hinv.ndisk
+ hinv.physmem
+ mem.physmem
+}
+
+log advisory on default {
+ disk.all.avg_disk.active
+ disk.all.read
+ disk.all.write
+ disk.ctl.avg_disk.active
+ kernel.all.load
+ kernel.all.cpu.intr
+ kernel.all.cpu.sys
+ kernel.all.cpu.user
+ kernel.all.cpu.wait.total
+ mem.freemem
+ mem.util
+ network.interface.in.bytes
+ network.interface.in.packets
+ network.interface.in.errors
+ network.interface.out.bytes
+ network.interface.out.packets
+ network.interface.out.errors
+}
+
diff --git a/src/pmview/front-ends/config.weblogvis b/src/pmview/front-ends/config.weblogvis
new file mode 100755
index 0000000..1d3453f
--- /dev/null
+++ b/src/pmview/front-ends/config.weblogvis
@@ -0,0 +1,20 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with weblogvis(1)
+#
+
+log advisory on default {
+ web.perserver.logidletime
+ web.perserver.requests.total
+ web.perserver.bytes.total
+ web.perserver.requests.size.unknown
+ web.perserver.requests.size.gt3m
+ web.perserver.requests.size.le3m
+ web.perserver.requests.size.le1m
+ web.perserver.requests.size.le300k
+ web.perserver.requests.size.le100k
+ web.perserver.requests.size.le30k
+ web.perserver.requests.size.le10k
+ web.perserver.requests.size.le3k
+ web.perserver.requests.size.zero
+}
diff --git a/src/pmview/front-ends/config.webpingvis b/src/pmview/front-ends/config.webpingvis
new file mode 100755
index 0000000..078ab3c
--- /dev/null
+++ b/src/pmview/front-ends/config.webpingvis
@@ -0,0 +1,8 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with webpingvis(1)
+#
+
+log advisory on default {
+ webpingvis
+}
diff --git a/src/pmview/front-ends/config.webvis b/src/pmview/front-ends/config.webvis
new file mode 100644
index 0000000..08394fc
--- /dev/null
+++ b/src/pmview/front-ends/config.webvis
@@ -0,0 +1,51 @@
+#
+# pmlogger(1) configuration file suitable creating an archive to be
+# used with webvis(1)
+#
+
+# file system and hinv stats
+# (log these once so they _definitely_ exist at start of archive)
+log advisory on once {
+ hinv.ncpu
+ hinv.physmem
+ hinv.ndisk
+ mem.physmem
+ disk.dev.read
+}
+
+log advisory on 60 seconds {
+ # Kernel, disk and swap and paging metrics
+ disk.all.read
+ disk.all.write
+ disk.all.avg_disk.active
+ kernel.all.cpu.idle
+ kernel.all.cpu.intr
+ kernel.all.cpu.sys
+ kernel.all.cpu.user
+ kernel.all.cpu.wait.total
+ mem.freemem
+ mem.util.kernel
+ mem.util.fs_ctl
+ mem.util.fs_dirty
+ mem.util.fs_clean
+ mem.util.user
+ swap.pagesout
+ network.interface.out.drops
+ network.interface.out.errors
+ network.interface.out.packets
+ network.interface.in.drops
+ network.interface.in.errors
+ network.interface.in.packets
+ network.interface.total.bytes
+ # Network data rates and error conditions
+ network.tcp.drops
+ network.tcp.conndrops
+ network.tcp.timeoutdrop
+ network.tcp.sndrexmitpack
+ network.tcp.rcvbadsum
+ network.tcp.rexmttimeo
+ network.mbuf.failed
+ network.mbuf.waited
+ # Web logs - both frequent and infrequent samples
+ web.allservers
+}
diff --git a/src/pmview/front-ends/dkvis b/src/pmview/front-ends/dkvis
new file mode 100755
index 0000000..5cf7267
--- /dev/null
+++ b/src/pmview/front-ends/dkvis
@@ -0,0 +1,572 @@
+#! /bin/sh
+#
+# Copyright (c) 1997-2005 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+_usage()
+{
+ echo >$tmp.msg 'Usage: '$prog' [options] [diskid ...]
+
+options:
+ -b display data throughput (Kbytes/sec) rather than IOPs
+ -m maxrate maximum activity expected (integer)
+ [default 150 IOPs (without -b) or 2048 Kbytes/sec (with -b)]
+ -r display only the read activity
+ -V verbose/diagnostic output
+ -w display only the write activity
+ -X ndisk limit layout to at most this many disks per row, set
+ to 0 for no limit [default 12]
+ -Y nctl limit layout to at most this many controllers per column
+ before starting a new group of controllers, set to 0
+ for no limit [default 16]
+
+pmview(1) options:'
+
+ _pmview_usage >> $tmp.msg
+ echo >> $tmp.msg
+ echo 'Default title is: Total Disk Activity (IOPS) for Host' >> $tmp.msg
+ _pmview_info -f $tmp.msg
+}
+
+verbose=false
+type=total
+Type=Total
+Thru=IOPS
+max=''
+force=false
+maxnctl=16
+maxndisk=12
+diskargs=
+debug=false
+
+# build WM_COMMAND X(1) property for restart after login/logout
+#
+echo -n "pmview Version 2.1 \"dkvis\"" >$tmp.conf
+for arg
+do
+ echo -n " \"$arg\"" >>$tmp.conf
+done
+
+_pmview_args "$@"
+
+if [ -n "$otherArgs" ]
+then
+ while getopts "?bdm:R:rv:VX:Y:w" c $otherArgs
+ do
+ case $c
+ in
+ b)
+ Thru="Kbytes/sec"
+ ;;
+ d)
+ debug=true
+ ;;
+ m)
+ _pmview_unsigned $c
+ max=$OPTARG
+ ;;
+ r)
+ if [ $type != total ]
+ then
+ _pmview_error "$prog: only one -r or -w option may be specified"
+ # NOTREACHED
+ fi
+ type=read
+ Type=Read
+ ;;
+
+ v)
+ if [ $OPTARG = "1" ]
+ then
+ _pmview_warning "$prog: pmview version 1 no longer supported, using version 2"
+ elif [ $OPTARG != "2" ]
+ then
+ _pmview_error "$prog: only version 2 supported for -v"
+ # NOTREACHED
+ fi
+ ;;
+
+ V)
+ verbose=true
+ ;;
+ w)
+ if [ $type != total ]
+ then
+ _pmview_error "$prog: only one -r or -w option may be specified"
+ # NOTREACHED
+ fi
+ type=write
+ Type=Write
+ ;;
+ X)
+ _pmview_unsigned $c
+ maxndisk=$OPTARG
+ ;;
+ [YR])
+ # used to be -R, so support both for backwards compatibility
+ _pmview_unsigned $c
+ maxnctl=$OPTARG
+ force=true
+ ;;
+ ?)
+ _usage
+ exit 1
+ ;;
+
+ esac
+ done
+ set -- $otherArgs
+ shift `expr $OPTIND - 1`
+
+ [ $# -gt 0 ] && diskargs=$@
+fi
+
+if [ "$Thru" != "IOPS" ]
+then
+ case $type
+ in
+ read)
+ type=read_bytes
+ ;;
+ write)
+ type=write_bytes
+ ;;
+ *)
+ if pminfo $msource disk.dev.total_bytes >/dev/null 2>&1
+ then
+ type=total_bytes
+ else
+ type=bytes
+ fi
+ ;;
+ esac
+fi
+
+# default max depends on -b or not
+#
+if [ "$Thru" != "IOPS" ]
+then
+ [ -z "$max" ] && max=2048
+else
+ [ -z "$max" ] && max=150
+fi
+
+pminfo -f $msource $namespace disk.dev.$type >$tmp.info 2>$tmp.err
+if [ -s $tmp.err ]
+then
+ cat $tmp.err | _pmview_fetch_mesg >> $tmp.msg
+ echo "$prog: Failed to get disk inventory from host \"$host\"" | fmt >> $tmp.msg
+ _pmview_error -f $tmp.msg
+ # NOTREACHED
+fi
+
+$PCP_AWK_PROG < $tmp.info -F'"' '/inst/ { print $2 }' > $tmp.disks
+
+if [ ! -s $tmp.disks ]
+then
+ cat $tmp.info | _pmview_fetch_mesg >> $tmp.msg
+ echo "$prog: Failed to get disk inventory from host \"$host\"" | fmt >> $tmp.msg
+ _pmview_error -f $tmp.msg
+ # NOTREACHED
+fi
+
+if [ ! -z "$diskargs" ]
+then
+ rm -f $tmp.tmp $tmp.msg
+ for dk in $diskargs
+ do
+ if echo "$dk" | grep '[.[^]' >/dev/null
+ then
+ # assume egrep(1) regular expression
+ #
+ if egrep "$dk" $tmp.disks >>$tmp.tmp
+ then
+ # found some matches
+ #
+ :
+ else
+ echo "$prog: pattern \"$dk\" does not match any disks ..." >$tmp.msg
+ fi
+ elif grep "^$dk\$" $tmp.disks >/dev/null
+ then
+ echo $dk >>$tmp.tmp
+ else
+ echo "$prog: disk \"$dk\" not in the disk inventory ..." >$tmp.msg
+ fi
+ done
+ if [ -s $tmp.msg ]
+ then
+ echo "Disks on host \"$host\" are:" >> $tmp.msg
+ fmt $tmp.disks | sed -e 's/^/ /' >> $tmp.msg
+ _pmview_error -f $tmp.msg
+ # NOTREACHED
+ fi
+ mv $tmp.tmp $tmp.disks
+fi
+
+if $debug
+then
+ echo "Disks ..."
+ cat $tmp.disks
+fi
+
+ndisk=`wc -l <$tmp.disks | sed -e 's/ //g'`
+
+if [ "$ndisk" -lt 1 ]
+then
+ echo "$prog: Cannot get disk inventory for host \"$host\"\n" > $tmp.msg
+ cat $tmp.info >> $tmp.msg
+ _pmview_error -f $tmp.msg
+ # NOTREACHED
+fi
+
+cat << end-of-file >> $tmp.conf
+
+#
+# dkvis
+#
+end-of-file
+
+if $verbose
+then
+ echo "# Disk Inventory:" >> $tmp.conf
+ fmt <$tmp.disks | sed -e 's/^/# /' >> $tmp.conf
+fi
+cp $tmp.disks $tmp.in
+
+# get controller-based order
+#
+# the mapping is controlled by the here-is document below, where each
+# (non-comment) line contains three fields separated by tabs:
+# 1. pattern to match disk names (must match the start of a disk indom name)
+# - don't bother escaping / (fixed up later)
+# - <n> is expanded to \([0-9][0-9]*\) later
+# - <h> is expanded to \([0-9a-f][0-9a-f]*\) later
+# 2. controller-tag ... construction from literals and substrings (in sed
+# syntax, so \1, \2, etc) from the pattern
+# 3. sort field order ... constructed from the ordinal labels of the
+# substrings in the pattern (comma separated) ... "n" is appended
+# for numerical sorting
+#
+# so the control line
+# dks<n>d<n>l*\([0-9]*\) dks\1 1n,2n,3n
+#
+# will first turn disk indom names like dks14d3, dks14d3l2, dks14d3l10,
+# dks14d2, dks10d7, dks10d10 and dks10d1 into records like
+#
+# dks14 14 3 dks14d3
+# dks14 14 3 2 dks14d3l2
+# dks14 14 3 10 dks14d3l10
+# dks14 14 2 dks14d2
+# dks10 10 7 dks10d7
+# dks10 10 1 10 dks10d110
+# dks10 10 1 dks10d1
+# --+-- -+ -+ -+ ----+----
+# | | | | |
+# | | | | +-- full disk name
+# | | | +-- 3rd sort key (lun, may be missing)
+# | | +-- 2nd sort key (target)
+# | +-- 1st sort key (controller)
+# +-- controller-tag for dkvis scene and used for grouping "related"
+# disks
+#
+# and generate a sort(1) key of the form "+1n -2 +2n -3 +3n -4"
+#
+# after sorting this list becomes
+#
+# dks10 10 1 dks10d1
+# dks10 10 1 10 dks10d110
+# dks10 10 7 dks10d7
+# dks14 14 2 dks14d2
+# dks14 14 3 dks14d3
+# dks14 14 3 2 dks14d3l2
+# dks14 14 3 10 dks14d3l10
+#
+# and after grouping based on the common controller-tag and stripping
+# the sort fields this becomes
+#
+# dks10 dks10d1 dks10d110 dks10d7
+# dks14 dks14d2 dks14d3 dks14d3l2 dks14d3l10
+#
+sed >$tmp.ctl <<'End-of-File' \
+ -e '/^#/d' \
+ -e 's/ */ /g' \
+ -e 's/\//\\\//g' \
+ -e 's/<n>/\\([0-9][0-9]*\\)/g' \
+ -e 's/<h>/\\([0-9a-f][0-9a-f]*\\)/g' \
+ -e 's/^/^/'
+# Linux 2.2, no sard, IDE and SCSI
+sd\([a-z]\)+hd\([abcd]\) sd+hd 1
+# Linux IDE, no devfs
+hd\([abcd]\) hd 1
+# Linux IDE, with devfs
+ide/host<n>/bus<n>/target<n>/lun<n> ide\1b\2 1n,2n,3n,4n
+# Linux SCSI, no devfs
+sd\([a-z]\) sd 1
+# Linux XSCSI, dual port HBA, with devfs
+# e.g. xscsi/pci00.01.0-1/target2/lun0/disc (and similar for fabric device)
+xscsi/pci<h>\.<h>\.<n>-<n>/target<n>/lun<n> xscsi\1.\2 1,2,3n,4n,5n,6n
+xscsi/pci<h>\.<h>\.<n>-<n>/node<h>/lun<n> xscsi\1.\2 1,2,3n,4n,5,6n
+# Linux XSCSI, single port HBA, with devfs
+# e.g. xscsi/pci05.01.0/target2/lun0/disc (and similar for fabric device)
+xscsi/pci<h>\.<h>\.<n>/target<n>/lun<n> xscsi\1.\2 1,2,3n,4n,5n
+xscsi/pci<h>\.<h>\.<n>/node<h>/lun<n> xscsi\1.\2 1,2,3n,4,5n
+# Linux SCSI, with devfs
+scsi/host<n>/bus<n>/target<n>/lun<n> scsi\1b\2 1n,2n,3n,4n
+# Linux Mylex RAID, no devfs
+rd/c<n>d<n> dac 1n,2n
+# Linux Mylex RAID, with devfs (old style)
+dac960/c<n>d<n> dac 1n,2n
+# Linux Mylex RAID, with devfs (new style)
+dac960/host<n>/disc<n> dac 1n,2n
+# IRIX Firewire
+# two name formats: first is IRIX before 6.5.11, second is 6.5.11 or later
+/hw/rdisk/1394/\([^/]*\)/lun<n>vol/c<n>p<n> 1394c\3 3n,2n,1,2n
+1394/\([^/]*\)/lun<n>vol/c<n>p<n> 1394c\3 3n,2n,1,2n
+# IRIX SCSI, note l<n> is missing for LUN 0, so pattern is a little different
+# at the end
+dks<n>d<n>l*\([0-9]*\) dks\1 1n,2n,3n
+# IRIX FC
+\(................\)/lun<n>/c<n>p<n> fc\3p\4 3n,4n,1,2n
+# Linux direct attach xscsi
+# e.g. xscsi/pci15.01.0-2/target4/lun0/disc
+xscsi/pci<n>\.\(..\)\.\(.*\)/target<n>/lun<n> xscsi\1b\2 1n,2,3,4n,5n
+# Linux fabric attach xscsi
+# e.g. xscsi/pci04.01.0/node50060946700083e9/port1/lun0/disc
+xscsi/pci<n>\.\(..\)\.\(.*\)/node\(................\)/port<n>/lun<n> xfc\1b\2 1n,2,3,4,5n,6n
+# Linux IDA, with devfs
+ida/disc<n> ida 1n
+# Old style IRIX Jaguar drives
+jag<n>d<n> jag\1 1n,2n
+# Old style IRIX RAID drives
+rad<n>d<n> rad\1 1n,2n
+End-of-File
+
+if $debug
+then
+ echo "Control lines ..."
+ cat $tmp.ctl
+fi
+
+nctl=`wc -l <$tmp.ctl | sed -e 's/ //g'`
+i=1
+
+# loop once per contol line in $tmp.ctl ...
+# - select matching disks
+# - generate the sort keys with the disk names
+# - sort and group by the controller-tag
+# - remove the matching lists from consideration
+#
+while [ $i -le $nctl ]
+do
+ $PCP_AWK_PROG -F' ' <$tmp.ctl '
+NR == '$i' { print "/" $1 "/p" >"'$tmp.sed-in'"
+ print "/" $1 "/!p" >"'$tmp.sed-out'"
+ nfld = split($3,fld,/,/)
+ maxfld = 1
+ for (i = 1; i <= nfld; i++) {
+ if (fld[i] > maxfld) maxfld = fld[i]
+ printf "+%s -%d ",fld[i],fld[i]+1 >"'$tmp.sort-arg'"
+ }
+ print "" >"'$tmp.sort-arg'"
+ printf "%s","s/" $1 "/" $2 >"'$tmp.sed-key'"
+ for (i = 1; i <= maxfld; i++) {
+ printf " \\%d",i >"'$tmp.sed-key'"
+ }
+ print " &/" >"'$tmp.sed-key'"
+ exit
+ }'
+
+ sed -n -f $tmp.sed-in <$tmp.in \
+ | sed -f $tmp.sed-key >$tmp.key
+ sort `cat $tmp.sort-arg` $tmp.key \
+ | $PCP_AWK_PROG >>$tmp.order '
+BEGIN { ctl = "" }
+$1 != ctl { if (NR > 1) print ""
+ ctl = $1
+ ndisk = 0
+ printf "%s",ctl
+ }
+ { ndisk++
+ if ('"$maxndisk"' > 0 && ndisk > '"$maxndisk"') {
+ print ""
+ printf "%s",ctl
+ ndisk = 1
+ }
+ printf " %s",$NF
+ }
+END { if (NR > 0) print "" }'
+ sed -n -f $tmp.sed-out <$tmp.in >$tmp.out
+ mv $tmp.out $tmp.in
+
+ i=`expr $i + 1`
+done
+
+# any leftovers do not match any control pattern
+#
+if [ -s $tmp.in ]
+then
+ echo "$prog: The following disk names do not match a known controller pattern," >$tmp.warn
+ echo "and they will be ungrouped in the scene:" >>$tmp.warn
+ fmt <$tmp.in | sed -e 's/^/ /' >>$tmp.warn
+ _pmview_warning -f $tmp.warn
+ sed -e 's/.*/& &/' <$tmp.in >>$tmp.order
+fi
+
+nctl=`wc -l <$tmp.order | sed -e 's/ //g'`
+
+# shape the base geometry for the scene ... there are groups, each with
+# $maxnctl controller rows, and the groups are arranged in a grid that
+# is $nrow groups deep and $ncol groups across
+#
+if [ $nctl -le $maxnctl ]
+then
+ # less than $maxnctl controller rows, so just one group
+ #
+ ncol=1
+ nrow=1
+else
+ # have some shaping to do ... assume each group is $maxnctl controller
+ # rows deep and as wide as the maximum number of disks per controller
+ # row, then square up the scene and maybe adjust $maxnctl
+ #
+ eval `$PCP_AWK_PROG <$tmp.order '
+START { maxdk = 0 }
+ { if (NF - 1 > maxdk) maxdk = NF - 1 }
+END {
+ if ('"$nctl"' % "'$maxnctl'" == 0)
+ ngrp = '"$nctl"' / "'$maxnctl'"
+ else
+ ngrp = int('"$nctl"' / "'$maxnctl'") + 1
+ # add 2 to maxdk as an estimate of the label length in units of
+ # displayed blocks, i.e. the label is about as long as the width
+ # of 2 blocks
+ ncol = int(0.5 + sqrt(ngrp)*'"$maxnctl"'/(maxdk + 2))
+ if (ncol < 1) ncol = 1
+ if (ngrp % ncol == 0)
+ nrow = ngrp / ncol
+ else
+ nrow = int(ngrp / ncol) + 1
+ # use all of the space in the base layout
+ ngrp = nrow * ncol
+ # make all the groups have the same number of controller rows
+ if ('"$nctl"' % ngrp == 0)
+ maxnctl = '"$nctl"' / ngrp
+ else
+ maxnctl = int('"$nctl"' / ngrp) + 1
+ print "ncol=" ncol " nrow=" nrow " maxnctl=" maxnctl
+ }'`
+fi
+
+#DEBUG echo "nctl=$nctl maxnctl=$maxnctl ncol=$ncol nrow=$nrow"
+
+# heuristic hack for pmlaunch
+#
+if [ "$nctl" -gt 6 ]
+then
+ group="_groupByInst"
+else
+ group="_groupByMetric"
+fi
+
+if [ -z "$titleArg" ]
+then
+ titleArg="$Type Disk Activity ($Thru) for Host $host"
+fi
+
+#
+# pmview 2.0
+#
+
+echo '
+_grid (' >> $tmp.conf
+
+$PCP_AWK_PROG -v io=$Type -v max=$max -v group=$group -v thru="$Thru" <$tmp.order '
+BEGIN { row = 0; col = 0; cnt = 0; type = ""; ctl = ""
+ start_ctl = ""; label = ""; last_label = ""; last_ctl = ""
+ color[0] = "green"
+ color[1] = "blue"
+ color[2] = "red"
+ color[3] = "cyan"
+ color[4] = "violet"
+ color[5] = "yellow"
+ ncol = 5
+ colorlist = ""
+ }
+
+function dumpLabel(start, last)
+{
+ printf(" _baseLabel \"%s Activity for Disks on ", io)
+ if (start != last)
+ printf("Controllers %s to %s", start, last)
+ else
+ printf("Controller %s", start)
+ printf("\\nNormalized to %s %s\"\n", max, thru)
+ printf(" _colorlist (%s )\n", colorlist )
+ colorlist = ""
+}
+
+ { if (cnt % '"$maxnctl"' == 0) {
+ if (cnt > 0) {
+ print " )"
+ dumpLabel(start_ctl, last_ctl)
+ print " )"
+ }
+ printf("\n _bar %d %d north %s (\n", 2*col, 2*row, group)
+ print " _metrics ("
+ start_ctl = $1
+ row++
+ if (row >= '"$nrow"') {
+ col++
+ row = 0
+ }
+ }
+ printf(" disk.dev.'$type'[")
+
+ for (d = 2; d <= NF; d++) {
+ if (d == 2)
+ printf("%s", $d)
+ else
+ printf(",%s", $d)
+ }
+ printf("] %s \"%s\"\n", max, $1)
+ if ($1 != last_ctl) {
+ # new controller, change colors
+ ncol++
+ if (ncol > 5)
+ ncol = 0
+ }
+ colorlist = colorlist " " color[ncol]
+ last_ctl = $1
+ cnt++
+ }
+END { if (cnt > 0) {
+ print " )"
+ dumpLabel(start_ctl, last_ctl)
+ print " )"
+ }
+ print ")"
+ }' >> $tmp.conf
+
+$verbose && cat $tmp.conf
+
+eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" # -xrm "'*iconName:dkvis'"
+
+exit
diff --git a/src/pmview/front-ends/mpvis b/src/pmview/front-ends/mpvis
new file mode 100755
index 0000000..dd7db78
--- /dev/null
+++ b/src/pmview/front-ends/mpvis
@@ -0,0 +1,452 @@
+#!/bin/sh
+# Copyright (c) 1997-2001 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+gridspace=120
+cpuargs=
+
+algorithm="k"
+default_layout=true
+force=false
+maxrowlen=16
+verbose=false
+showinst=false
+version=2
+
+_usage()
+{
+ echo >$tmp.msg 'Usage: mpvis [options] [cpuid...]
+
+options:
+ -b use row:column ratio of 1:8 (soft limit)
+ [default, if 64 or more CPUs]
+ -i show CPU numbers
+ -r rowlen maximum number of CPUs per row (soft limit)
+ [default 16, if less than 64 CPUs]
+ -R rowlen force this number of CPUs per row
+ -V verbose/diagnostic output
+
+pmview(1) options:'
+
+ _pmview_usage >>$tmp.msg
+ echo >>$tmp.msg
+ echo 'Default title is: CPU Utilization for Host' >>$tmp.msg
+ _pmview_info -f $tmp.msg
+}
+
+# generate one row of the scene
+#
+_do_row()
+{
+if [ "$1" = "$2" ]
+then
+ msg="$titleArg\n$1 only"
+else
+ msg="$titleArg\n$1 to $2"
+fi
+
+cat <<End-of-File >>$tmp.conf
+ _grid 0 $3 show (
+ _baseLabel "$msg"
+ _bar $group (
+ _metrics (
+End-of-File
+$have_idle && echo " kernel.percpu.cpu.idle[$rowlist] $max_util \"idle\"" >>$tmp.conf
+$have_wait && echo " kernel.percpu.cpu.wait.total[$rowlist] $max_util \"wait\"" >>$tmp.conf
+$have_intr && echo " kernel.percpu.cpu.intr[$rowlist] $max_util \"intr\"" >>$tmp.conf
+$have_nice && echo " kernel.percpu.cpu.nice[$rowlist] $max_util \"nice\"" >>$tmp.conf
+$have_sys && echo " kernel.percpu.cpu.sys[$rowlist] $max_util \"sys\"" >>$tmp.conf
+$have_user && echo " kernel.percpu.cpu.user[$rowlist] $max_util \"user\"" >>$tmp.conf
+cat <<End-of-File >>$tmp.conf
+ )
+End-of-File
+$showinst && echo " _instlabels away ( $labels )" >>$tmp.conf
+cat <<End-of-File >>$tmp.conf
+ _colorlist cpu
+ _baseLabel "$msg"
+ )
+ )
+End-of-File
+}
+
+# build WM_COMMAND X(1) property for restart after login/logout
+#
+echo -n "pmview Version 2.1 \"mpvis\"" >$tmp.conf
+for arg
+do
+ echo -n " \"$arg\"" >>$tmp.conf
+done
+
+_pmview_args "$@"
+
+if [ "X$otherArgs" != X ]
+then
+ while getopts "bir:R:v:V?" c $otherArgs
+ do
+ case $c
+ in
+ b)
+ algorithm="b"
+ default_layout=false
+ ;;
+ i)
+ showinst=true
+ gridspace=60
+ ;;
+ r)
+ _pmview_unsigned $c
+ maxrowlen=$OPTARG
+ default_layout=false
+ ;;
+ R)
+ _pmview_unsigned $c
+ maxrowlen=$OPTARG
+ default_layout=false
+ force=true
+ ;;
+
+ v)
+ version=$OPTARG
+ if [ $version = "1" ]
+ then
+ _pmview_warning "$prog: pmview version 1 no longer supported, using version 2"
+ version=2
+ elif [ $version != "2" ]
+ then
+ _pmview_error "$prog: only version 2 supported for -v"
+ # NOTREACHED
+ fi
+ ;;
+
+ V)
+ verbose=true
+ ;;
+ ?)
+ _usage
+ exit 1
+ ;;
+ esac
+ done
+ set -- $otherArgs
+ shift `expr $OPTIND - 1`
+
+ [ $# -gt 0 ] && cpuargs=$@
+fi
+
+[ -z "$titleArg" ] && titleArg="SGI PCP : CPU Utilization for Host $host"
+
+_pmview_cache_fetch -I kernel.percpu.cpu.user
+_pmview_cache_fetch -v kernel.percpu.cpu.idle \
+ kernel.percpu.cpu.wait.total \
+ kernel.percpu.cpu.intr \
+ kernel.percpu.cpu.nice \
+ kernel.percpu.cpu.sys \
+ kernel.percpu.cpu.user
+
+
+# Check that we can get the metrics
+#
+if _pmview_fetch_indom kernel.percpu.cpu.user
+then
+ if [ ! -s "$tmp.pmview_result" -o "$number" -lt 1 ]
+ then
+ _pmview_fetch_fail "get CPU inventory"
+ fi
+else
+ _pmview_fetch_fail "get CPU inventory"
+ # NOTREACHED
+fi
+
+if [ ! -z "$cpuargs" ]
+then
+ # restrict based on command line args
+ #
+ rm -f $tmp.tmp $tmp.msg
+ ncpu=0
+ for cpu in $cpuargs
+ do
+ if echo "$cpu" | grep '[.[^]' >/dev/null
+ then
+ # assume egrep(1) regular expression
+ #
+ if egrep "$cpu" $tmp.pmview_result >>$tmp.tmp
+ then
+ # found some matches
+ #
+ :
+ else
+ echo "$prog: pattern \"$cpu\" does not match any CPUs ..." >$tmp.msg
+ fi
+ elif grep "^$cpu\$" $tmp.pmview_result >/dev/null
+ then
+ echo $cpu >>$tmp.tmp
+ else
+ echo "$prog: CPU \"$cpu\" not in the CPU inventory" >$tmp.msg
+ fi
+ done
+ if [ -s $tmp.msg ]
+ then
+ echo "CPUs on host \"$host\" are:" >> $tmp.msg
+ tr < $tmp.pmview_result '\012' ' ' | fmt | sed -e "s/^/ /" >> $tmp.msg
+ _pmview_error -f $tmp.msg
+ # NOTREACHED
+ fi
+ sort $tmp.tmp | uniq > $tmp.pmview_result
+ ncpu=`wc -l $tmp.pmview_result | $PCP_AWK_PROG '{print $1}'`
+else
+ ncpu=$number
+fi
+
+if [ "$ncpu" -ge 64 -a "$default_layout" = true ]
+then
+ # >= 64p, no -b, -r or -R options ... make -b the default
+ #
+ algorithm="b"
+fi
+
+# sort list
+#
+if grep cpu: $tmp.pmview_result >/dev/null
+then
+ # Origin series name style
+ sed -e 's/:/./' < $tmp.pmview_result \
+ | sort -t. +1n -2 +2n -3 +3 -4 \
+ | sed -e 's/\./:/' \
+ > $tmp.cpulist
+else
+ # CPU names for older systems
+ sed -e 's/cpu/cpu./' < $tmp.pmview_result \
+ | sort -t. +1n -2 \
+ | sed -e 's/\.//' \
+ > $tmp.cpulist
+fi
+
+scale=''
+have_idle=false
+if _pmview_fetch_values kernel.percpu.cpu.idle
+then
+ have_idle=true
+ [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.idle| sed -n '/Semantics:/s/.*Units: //p'`
+fi
+
+have_wait=false
+if _pmview_fetch_values kernel.percpu.cpu.wait.total
+then
+ have_wait=true
+ [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.wait.total | sed -n '/Semantics:/s/.*Units: //p'`
+fi
+
+have_intr=false
+if _pmview_fetch_values kernel.percpu.cpu.intr
+then
+# linux 2.6 has wait and intr, but 2.4 does not
+ have_intr=`$PCP_AWK_PROG -v found=false '
+ $1 > 0 { found="true" }
+ END { print found }' $tmp.pmview_result`
+ have_wait=$have_intr
+ [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.intr | sed -n '/Semantics:/s/.*Units: //p'`
+fi
+
+have_nice=false
+if _pmview_fetch_values kernel.percpu.cpu.nice
+then
+ have_nice=true
+ [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.nice | sed -n '/Semantics:/s/.*Units: //p'`
+fi
+
+have_sys=false
+if _pmview_fetch_values kernel.percpu.cpu.sys
+then
+ have_sys=true
+ [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.sys | sed -n '/Semantics:/s/.*Units: //p'`
+fi
+
+have_user=false
+if _pmview_fetch_values kernel.percpu.cpu.user
+then
+ have_user=true
+ [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.user | sed -n '/Semantics:/s/.*Units: //p'`
+fi
+
+case $scale
+in
+ microsec)
+ max_util=1000000
+ ;;
+ millisec)
+ max_util=1000
+ ;;
+ *)
+ _pmview_warning "$prog: cannot determine CPU time units, assuming milliseconds"
+ max_util=1000
+ ;;
+esac
+
+# shape the base geometry for the scene
+#
+if [ $ncpu -le "$maxrowlen" ]
+then
+ nrows=1
+ ncols=$ncpu
+elif $force
+then
+ nrows=`echo $ncpu $maxrowlen | $PCP_AWK_PROG ' \
+ { x = $1 / $2; y = $1 % $2; if (y > 0) ++x; printf "%d\n", x; }'`
+ ncols=$maxrowlen
+else
+ case $algorithm in
+ a) # this algorithm doesn't work at the moment
+ # (the exit condition is not robust enough)
+ nrows=1
+ ncols=1
+ bound=1
+ num=0
+ while [ $num -gt $ncols -o $num -lt $bound ]
+ do
+ nrows=`expr $nrows \* 2`
+ ncols=`expr $ncpu / $nrows`
+ bound=`expr $ncols / 2`
+ num=`expr $nrows \* 4`
+ done
+ ncols=`echo $ncpu $nrows | $PCP_AWK_PROG ' { x = $1 / $2; y = $1 % $2; \
+ if (y > 0) ++x; printf "%d\n", x }'`
+ ;;
+ b)
+ # use a ratio for rows:columns of 1:8
+ #
+ nrows=`echo $ncpu | $PCP_AWK_PROG ' { x = sqrt ($1 / 8.0);
+ y = int (x); if (y < x) ++y; print y }'`
+ ncols=`expr $ncpu + $nrows - 1`
+ ncols=`expr $ncols / $nrows`
+ ;;
+ k)
+ nrows=`expr $ncpu + $maxrowlen - 1`
+ nrows=`expr $nrows / $maxrowlen`
+ ncols=`expr $ncpu + $nrows - 1`
+ ncols=`expr $ncols / $nrows`
+ esac
+fi
+
+if [ "$ncols" -gt 6 ]
+then
+ group="_groupByMetric"
+else
+ group="_groupByInst"
+fi
+
+cat <<End-of-File >>$tmp.conf
+
+#
+# mpvis
+#
+# ncpus = $ncpu
+# nrows = $nrows
+# ncols = $ncols
+#
+# List:
+End-of-File
+
+col=0
+rowlist=""
+cat $tmp.cpulist | while read cpu
+do
+ if [ $col -eq 0 ]
+ then
+ echo -n "$cpu " > $tmp.rowlist
+ else
+ echo -n "$cpu " >> $tmp.rowlist
+ fi
+ col=`expr $col + 1`
+ if [ "$col" -eq $ncols ]
+ then
+ echo "# "`cat $tmp.rowlist` >>$tmp.conf
+ col=0
+ rm -f $tmp.rowlist
+ fi
+done
+
+[ -s $tmp.rowlist ] && echo "# "`cat $tmp.rowlist` >>$tmp.conf
+
+echo "_gridSpace $gridspace" >>$tmp.conf
+echo >>$tmp.conf
+
+colorlist="_colorlist cpu ("
+$have_idle && colorlist="$colorlist green2"
+$have_wait && colorlist="$colorlist cyan2"
+$have_intr && colorlist="$colorlist yellow2"
+$have_nice && colorlist="$colorlist rgbi:0.6/1.0/0.7"
+$have_sys && colorlist="$colorlist red2"
+$have_user && colorlist="$colorlist blue2"
+colorlist="$colorlist )"
+
+echo "$colorlist" >>$tmp.conf
+echo "_grid 0 0 _hide ( # outer grid" >>$tmp.conf
+
+# build rows from front-to-back of scene
+# fill rows with CPUs from left-to-right
+#
+y=`expr $nrows \* 2 - 2`
+col=0
+rowlist=""
+labels=""
+cat $tmp.cpulist | while read cpu
+do
+ if [ $col -eq 0 ]
+ then
+ rowlist=$cpu
+ start=$cpu
+ else
+ rowlist="$rowlist,$cpu"
+ fi
+ $showinst && labels="$labels \"`echo $cpu | sed -e 's/cpu:*//'`\""
+ col=`expr $col + 1`
+ echo "$start $cpu $y $rowlist $labels" > $tmp.rowlist
+ if [ $col -eq $ncols ]
+ then
+ _do_row $start $cpu $y
+ col=0
+ echo -n "" > $tmp.rowlist
+ labels=""
+ y=`expr $y - 2`
+ fi
+done
+
+if [ -s $tmp.rowlist ]
+then
+ read start cpu y rowlist labels < $tmp.rowlist
+ # cat $tmp.rowlist
+ _do_row $start $cpu $y
+fi
+
+echo ")" >>$tmp.conf
+
+if [ $nrows -eq 1 ]
+then
+ # remove unnecessary _grid for a single row
+ #
+ sed -e '/^ _grid/d' -e '/^ )/d' <$tmp.conf >$tmp.tmp
+ mv $tmp.tmp $tmp.conf
+fi
+
+$verbose && cat $tmp.conf
+
+eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" -xrm "'*iconName:mpvis'"
+
+exit
diff --git a/src/pmview/front-ends/nfsvis b/src/pmview/front-ends/nfsvis
new file mode 100755
index 0000000..26b87ae
--- /dev/null
+++ b/src/pmview/front-ends/nfsvis
@@ -0,0 +1,244 @@
+#! /bin/sh
+# Copyright (c) 1997-2001 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+_usage()
+{
+ echo >$tmp.msg 'Usage: '$prog' [options]
+
+options:
+ -c version Monitor NFS version (integer) client metrics [default 2]
+ -m maxrate maximum request rate expected (integer) [default 120]
+ -s version Monitor NFS version (integer) server metrics [default 2]
+ -V verbose/diagnostic output
+
+pmview(1) options:'
+
+ _pmview_usage >>$tmp.msg
+ echo >>$tmp.msg
+ echo 'Default title is: NFS Version 2 Request Traffic for host' >>$tmp.msg
+ _pmview_info -f $tmp.msg
+}
+
+max=120
+client=2
+server=2
+type=total
+Type=Total
+verbose=false
+version=2
+
+# build WM_COMMAND X(1) property for restart after login/logout
+#
+echo -n "pmview Version 2.1 \"nfsvis\"" >$tmp.conf
+for arg
+do
+ echo -n " \"$arg\"" >>$tmp.conf
+done
+
+_pmview_args "$@"
+
+if [ -n "$otherArgs" ]
+then
+ while getopts "?c:m:s:v:V" c $otherArgs
+ do
+ case $c
+ in
+ c)
+ client=$OPTARG
+ if [ "$client" != 2 -a "$client" != 3 ]
+ then
+ _pmview_error "$prog: only NFS 2 and NFS 3 client metrics supported"
+ # NOTREACHED
+ fi
+ ;;
+ m)
+ _pmview_unsigned $c
+ max=$OPTARG
+ ;;
+ s)
+ server=$OPTARG
+ if [ "$server" != 2 -a "$server" != 3 ]
+ then
+ _pmview_error "$prog: only NFS 2 and NFS 3 server metrics supported"
+ # NOTREACHED
+ fi
+ ;;
+
+ v)
+ version=$OPTARG
+ if [ $version = "1" ]
+ then
+ _pmview_warning "$prog: pmview version 1 no longer supported, using version 2"
+ version=2
+ elif [ $version != "2" ]
+ then
+ _pmview_error "$prog: only version 2 supported for -v"
+ # NOTREACHED
+ fi
+ ;;
+
+ V)
+ verbose=true
+ ;;
+ ?)
+ _usage
+ exit 1
+ ;;
+ esac
+ done
+ set - $otherArgs
+ shift `expr $OPTIND - 1`
+ if [ $# -gt 0 ]
+ then
+ _usage
+ exit 1
+ fi
+fi
+
+if [ "$client" = "2" ]
+then
+ # NFS V2 client stats
+ #
+ if _pmview_fetch_indom nfs.client.reqs
+ then
+ :
+ else
+ _pmview_fetch_fail "get NFS Version 2 client metrics"
+ # NOTREACHED
+ fi
+else
+ # NFS V3 client stats
+ #
+ if _pmview_fetch_indom nfs3.client.reqs
+ then
+ :
+ else
+ _pmview_fetch_fail "get NFS Version 3 client metrics"
+ # NOTREACHED
+ fi
+fi
+
+# handle fsstat alias statfs
+#
+c_statfs=statfs
+grep fsstat $tmp.pmview_result >/dev/null && c_statfs=fsstat
+
+if [ "$server" = "2" ]
+then
+ # NFS V2 server stats
+ #
+ if _pmview_fetch_indom nfs.server.reqs
+ then
+ :
+ else
+ _pmview_fetch_fail "get NFS Version 2 server metrics"
+ # NOTREACHED
+ fi
+else
+ # NFS V3 server stats
+ #
+ if _pmview_fetch_indom nfs3.server.reqs
+ then
+ :
+ else
+ _pmview_fetch_fail "get NFS Verion 3 server metrics"
+ # NOTREACHED
+ fi
+fi
+
+# handle fsstat alias statfs
+#
+s_statfs=statfs
+grep fsstat $tmp.pmview_result >/dev/null && s_statfs=fsstat
+
+if [ -z "$titleArg" ]
+then
+ titleArg="SGI PCP : NFS Client V$client & Server V$server Request Traffic for host $host"
+fi
+
+
+cat << End-of-File >> $tmp.conf
+
+#
+# nfsvis
+#
+_colorlist colors (red1 green1 blue1)
+_grid hide (
+ _label 2 0 _down _large "Client"
+ _bar 0 0 _east _groupByMetric (
+ _metrics (
+End-of-File
+
+if [ "$client" = "2" ]
+then
+ cat << End-of-File >> $tmp.conf
+ nfs.client.reqs[create,remove,rename,link,symlink,mkdir,rmdir] $max "dir"
+ nfs.client.reqs[getattr,setattr,lookup,readdir,$c_statfs,root] $max "attr"
+ nfs.client.reqs[readlink,read,write,wrcache] $max "data"
+ )
+ _baseLabel "Requests by NFS2 Client\nNormalized to $max requests / second"
+End-of-File
+else
+ cat << End-of-File >> $tmp.conf
+ nfs3.client.reqs[create,remove,rename,link,symlink,mkdir,rmdir,mknod] $max "dir"
+ nfs3.client.reqs[getattr,setattr,lookup,readdir,$c_statfs,access,readdir+,fsinfo,pathconf] $max "attr"
+ nfs3.client.reqs[readlink,read,write,commit] $max "data"
+ )
+ _baseLabel "Requests by NFS3 Client\nNormalized to $max requests / second"
+End-of-File
+fi
+cat << End-of-File >> $tmp.conf
+ _colorlist colors
+ )
+ _label 2 2 _down _large "Server"
+ _bar 0 2 _east (
+ _metrics (
+End-of-File
+if [ "$server" = "2" ]
+then
+ cat << End-of-File >> $tmp.conf
+ nfs.server.reqs[create,remove,rename,link,symlink,mkdir,rmdir] $max "dir"
+ nfs.server.reqs[getattr,setattr,lookup,readdir,$s_statfs,root] $max "attr"
+ nfs.server.reqs[readlink,read,write,wrcache] $max "data"
+ )
+ _baseLabel "Requests to NFS2 Server\nNormalized to $max requests / second"
+End-of-File
+else
+ cat << End-of-File >> $tmp.conf
+ nfs3.server.reqs[create,remove,rename,link,symlink,mkdir,rmdir,mknod] $max "dir"
+ nfs3.server.reqs[getattr,setattr,lookup,readdir,$s_statfs,access,readdir+,fsinfo,pathconf] $max "attr"
+ nfs3.server.reqs[readlink,read,write,commit] $max "data"
+ )
+ _baseLabel "Requests to NFS3 Server\nNormalized to $max requests / second"
+End-of-File
+fi
+
+cat << End-of-File >> $tmp.conf
+ _colorlist colors
+ )
+)
+End-of-File
+
+$verbose && cat $tmp.conf
+
+eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" -xrm "'*iconName:nfsvis'"
+
+exit
diff --git a/src/pmview/front-ends/osvis b/src/pmview/front-ends/osvis
new file mode 100644
index 0000000..a704446
--- /dev/null
+++ b/src/pmview/front-ends/osvis
@@ -0,0 +1,651 @@
+#! /bin/sh
+# Copyright (c) 1995-2003 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+#
+# scaling parameters
+#
+
+# maximum network packets per second
+maxpack=750
+
+# maximum error packets per second
+maxerr=`expr $maxpack / 100`
+
+# maximum network bytes per second
+maxbyte=65536
+
+# maximum disk io rate (I/O operations per second)
+maxio=100
+
+# milliseconds per CPU
+maxcpu=1000
+
+# maximum disk activity
+maxdisk=30
+
+_usage()
+{
+ echo >$tmp.msg 'Usage: '$prog' [options] [interface [interface ...]]
+
+options:
+ -b bytes maximum expected network throughput [default 65536 bytes]
+ -d activity maximum expected disk activity as a percentage [default 30]
+ -i ops maximum expected I/O operations per seconds [default 100]
+ -m packets maximum expected packets sent or received per sec [default 750]
+ -V verbose/diagnostic output
+
+pmview(1) options:'
+ _pmview_usage >>$tmp.msg
+ echo >> $tmp.msg
+ echo 'Default title is: High-Level Activity for Host' >> $tmp.msg
+
+ echo >>$tmp.msg '
+ By default all network interfaces are shown, with a maximum packet rate
+ of '$maxpack' packets per second and error rate of '$maxerr' packets per second.
+
+ If given, the [interface [interface ...]] regular expressions restrict
+ the network statistics displayed to matching network interface names only.'
+
+ _pmview_info -f $tmp.msg
+}
+
+argInterfaces=""
+verbose=false
+interfaces=""
+
+# build WM_COMMAND X(1) property for restart after login/logout
+#
+echo -n "pmview Version 2.1 \"osvis\"" >$tmp.conf
+for arg
+do
+ echo -n " \"$arg\"" >>$tmp.conf
+done
+
+_pmview_args "$@"
+
+if [ -n "$otherArgs" ]
+then
+ while getopts "?b:d:i:m:r:v:V" c $otherArgs
+ do
+ case $c
+ in
+
+ b)
+ _pmview_unsigned $c
+ maxbyte=$OPTARG
+ ;;
+
+ d)
+ _pmview_unsigned $c
+ maxdisk=$OPTARG
+ ;;
+
+ i)
+ _pmview_unsigned $c
+ maxio=$OPTARG
+ ;;
+
+ m)
+ _pmview_unsigned $c
+ maxpack=$OPTARG
+ ;;
+
+ V)
+ verbose=true
+ ;;
+
+ '?')
+ _usage
+ exit 1
+ ;;
+ esac
+ done
+
+ set -- $otherArgs
+ shift `expr $OPTIND - 1`
+ if [ $# -gt 0 ]
+ then
+ argInterfaces="$*"
+ fi
+fi
+
+cat << end-of-file >> $tmp.conf
+
+#
+# osvis
+#
+end-of-file
+
+# maximum req error rate (default: 1% of packet rate)
+maxerr=`expr $maxpack / 100`
+[ "$maxerr" -eq 0 ] && maxerr=1
+
+_pmview_cache_fetch -v hinv.ncpu \
+ hinv.ndisk \
+ disk.all.avg_disk.active \
+ mem.util \
+ hinv.physmem \
+ mem.physmem \
+ kernel.all.cpu.wait.total \
+ kernel.all.cpu.intr \
+ kernel.all.cpu.nice \
+ kernel.all.cpu.sys \
+ kernel.all.cpu.user
+
+_pmview_cache_fetch -I network.interface.in.bytes \
+ disk.ctl.avg_disk.active
+
+if _pmview_fetch_values hinv.ncpu
+then
+ ncpu=`cat $tmp.pmview_result`
+ maxcpu=`expr $maxcpu \* $ncpu`
+ maxload=`expr $ncpu \* 2`
+else
+ _pmview_fetch_fail "get the number of CPUs"
+fi
+
+if [ $ncpu -eq 1 ]
+then
+ cpudesc="1 CPU"
+else
+ cpudesc="$ncpu CPUs"
+fi
+
+$verbose && echo "# $cpudesc detected" >> $tmp.conf
+
+if _pmview_fetch_indom network.interface.in.bytes
+then
+ ninterfaces=$number
+else
+ _pmview_fetch_warn "get the number of network interfaces"
+ ninterfaces=0
+fi
+
+[ $ninterfaces -gt 0 ] && sed < $tmp.pmview_result -e 's/lo[0-9]*//g' -e 's/sl[0-9]*//g' -e 's/ppp[0-9]*//g' > $tmp.list
+
+[ ! -s $tmp.list ] && ninterfaces=0
+
+if $verbose
+then
+ echo "# Available Network Interfaces: "`cat $tmp.list | tr '\012' ' '` >> $tmp.conf
+fi
+
+if [ $ninterfaces -gt 0 ]
+then
+ if [ -z "$argInterfaces" ]
+ then
+ cp $tmp.list $tmp.chosen
+ else
+ touch $tmp.chosen
+ for i in $argInterfaces
+ do
+ egrep $i $tmp.list >> $tmp.chosen
+ done
+ fi
+
+ interfaces_sp=`cat $tmp.chosen | sort | uniq`
+ interfaces=`echo $interfaces_sp | sed -e 's/ /,/g'`
+ ninterfaces=`echo $interfaces | wc -w`
+
+ if $verbose
+ then
+ echo "# Network interfaces Matching \"$argInterfaces\": $interfaces" >> $tmp.conf
+ fi
+
+ if [ $ninterfaces -eq 0 ]
+ then
+ echo "$prog: no matching network interfaces for \"$argInterfaces\"" > $tmp.msg
+ echo "Available network interfaces on host \"$host\" are: " >> $tmp.msg
+ tr < $tmp.list '\012' ' ' | fmt | sed -e "s/^/ /" >> $tmp.msg
+ _pmview_error -f $tmp.msg
+ #NOTREACHED
+ fi
+fi
+
+if _pmview_fetch_values hinv.ndisk
+then
+ ndisk=`cat $tmp.pmview_result`
+ maxdiskscale=`expr $maxdisk \* 10`
+else
+ ndisk=0
+ maxdiskscale=0
+fi
+
+if [ $ndisk -eq 1 ]
+then
+ diskdesc="1 Disk"
+else
+ diskdesc="$ndisk Disks"
+fi
+
+$verbose && echo "# $diskdesc detected" >> $tmp.conf
+
+if [ "$ndisk" -gt 0 ]
+then
+
+ if _pmview_fetch_values disk.all.avg_disk.active
+ then
+ allAvg=true
+ else
+ allAvg=false
+ fi
+
+ if _pmview_fetch_indom disk.ctl.avg_disk.active
+ then
+ nctrl=$number
+ cp $tmp.pmview_result $tmp.ctrls
+ else
+ nctrl=0
+ fi
+
+ if [ $nctrl -eq 1 ]
+ then
+ ctrldesc="1 Disk Controller"
+ else
+ ctrldesc="$nctrl Disk Controllers"
+ fi
+
+ if [ "$nctrl" -gt 0 ]
+ then
+
+ collen=`expr $ninterfaces + 3`
+ collensq=`expr $collen \* $collen`
+
+ if [ $nctrl -le $collen ]
+ then
+ ctrlcols=$nctrl
+ elif [ $nctrl -le $collensq ]
+ then
+ ctrlcols=$collen
+ else
+ ctrlcols=`echo $nctrl \
+ | $PCP_AWK_PROG '{x = sqrt($1); y = int(x); if (y < x) y++; print y }'`
+ fi
+ fi
+
+ if $verbose
+ then
+ echo "# $ctrldesc detected: "`tr < $tmp.ctrls ' ' '\012'` >> $tmp.conf
+ echo "#" >> $tmp.conf
+ fi
+fi
+
+linuxutilmem=false
+utilmem=false
+if _pmview_fetch_values mem.util.used
+then
+ linuxutilmem=true
+ if $verbose
+ then
+ echo "# Linux memory utilization metrics supported" >> $tmp.conf
+ echo "#" >> $tmp.conf
+ fi
+else
+ linuxutilmem=false
+ if _pmview_fetch_values mem.util
+ then
+ utilmem=true
+ if $verbose
+ then
+ echo "# Memory utilization metrics supported" >> $tmp.conf
+ echo "#" >> $tmp.conf
+ fi
+ else
+ utilmem=false
+ if $verbose
+ then
+ _pmview_warning "$prog: Memory utilization metrics not supported, showing free memory only"
+ echo "# Memory utilization metrics not supported, showing free memory only" >> $tmp.conf
+ echo "#" >> $tmp.conf
+ fi
+ fi
+fi
+
+# Use mem.physmem if available, otherwise hinv.physmem will do.
+if _pmview_fetch_values mem.physmem
+then
+ realmem=`cat $tmp.pmview_result`
+elif _pmview_fetch_values hinv.physmem
+then
+ realmem=`cat $tmp.pmview_result`
+ realmem=`expr $realmem \* 1024`
+else
+ realmem=0
+
+ if $utilmem
+ then
+ if $verbose
+ then
+ echo "# Unable to determine total real memory" >> $tmp.conf
+ echo "# Showing memory utilisation with free memory" >> $tmp.conf
+ fi
+ else
+ _pmview_warning "Unable to determine size of real memory on host \"$host\""
+ fi
+fi
+
+have_wait=false
+if _pmview_fetch_values kernel.all.cpu.wait.total
+then
+ have_wait=true
+fi
+
+have_intr=false
+if _pmview_fetch_values kernel.all.cpu.intr
+then
+ have_intr=true
+fi
+
+have_nice=false
+if _pmview_fetch_values kernel.all.cpu.nice
+then
+ have_nice=true
+# linux hack !!
+# these metrics are not actually supported in linux
+ have_intr=false
+ have_wait=false
+fi
+
+have_sys=false
+if _pmview_fetch_values kernel.all.cpu.sys
+then
+ have_sys=true
+fi
+
+have_user=false
+if _pmview_fetch_values kernel.all.cpu.user
+then
+ have_user=true
+fi
+
+cpucolors="("
+$have_user && cpucolors="$cpucolors blue2"
+$have_sys && cpucolors="$cpucolors red2"
+$have_nice && cpucolors="$cpucolors rgbi:0.6/1.0/0.7"
+$have_intr && cpucolors="$cpucolors yellow2"
+$have_wait && cpucolors="$cpucolors cyan2"
+cpucolors="$cpucolors )"
+
+if [ -z "$titleArg" ]
+then
+ titleArg="SGI PCP : High-Level Activity for Host $host"
+fi
+
+cat << end-of-file >> $tmp.conf
+
+_colorlist cpu_colors $cpucolors
+_colorlist disk_colors ( violet yellow )
+_colorlist ctrl_colors ( green2 )
+_colorlist network_colors ( green2 blue2 red2 )
+
+_colorlist memory_colors (
+ rgbi:1.0/1.0/0.0
+ rgbi:0.0/1.0/1.0
+ rgbi:1.0/0.0/0.0
+ rgbi:1.0/0.0/1.0
+ rgbi:0.0/0.0/1.0
+ rgbi:0.0/1.0/0.0
+)
+
+_grid hide (
+
+#
+# System level stuff
+#
+end-of-file
+
+if [ "$ndisk" -gt 0 ]
+then
+ cat << end-of-file >> $tmp.conf
+
+ _label 0 1 _down _large "Disk"
+
+ _stack 1 1 _west _cylinder (
+ _metrics (
+ disk.all.write $maxio
+ disk.all.read $maxio
+ )
+ _colorlist disk_colors
+ _baseLabel "Disk Operations\nNormalized to $maxio I/Os per second"
+ )
+end-of-file
+
+ if $allAvg
+ then
+ cat << end-of-file >> $tmp.conf
+
+ _bar 2 1 _west _cylinder (
+ _metrics (
+ disk.all.avg_disk.active $maxdiskscale
+ )
+ _colorlist ctrl_colors
+ _baseLabel "Disk Activity\nNormalized to ${maxdisk}% for $ndisk disks"
+ )
+end-of-file
+ fi
+
+ if [ "$nctrl" -gt 0 ]
+ then
+ cat << end-of-file >> $tmp.conf
+
+ _label 4 0 _west "Disk Controllers"
+
+ _bar 4 1 _west _cylinder (
+ _metrics (
+end-of-file
+
+ cat $tmp.ctrls | tr '\012' ' ' \
+ | $PCP_AWK_PROG -v cols=$ctrlcols -v scale=$maxdiskscale >> $tmp.conf '
+BEGIN { str = ""; j = 0 }
+ { for (i = 1; i <= NF; i++) {
+ if (str == "")
+ str = $i;
+ else
+ str = str "," $i
+ if (j == cols) {
+ printf(" disk.ctl.avg_disk.active[%s] %d\n", str, scale);
+ str = "";
+ j = 0;
+ }
+ else
+ j++;
+ }
+ }
+END { if (str != "")
+ printf(" disk.ctl.avg_disk.active[%s] %d\n", str, scale);
+ }'
+
+ cat << end-of-file >> $tmp.conf
+ )
+ _colorlist ctrl_colors
+ _baseLabel "Disk Controller Activity\nNormalized to ${maxdisk}% for the disks on each controller"
+ )
+end-of-file
+
+ fi
+fi
+
+cat << end-of-file >> $tmp.conf
+
+ _label 0 3 _west _down _large "Load"
+
+ _bar 1 3 2 1 _west (
+ _metrics (
+ kernel.all.load[15] $maxload
+ kernel.all.load[5] $maxload
+ kernel.all.load[1] $maxload
+ )
+ _metriclabels _away ( "15" "5" "1" )
+ _colorlist ( blue2 blue2 blue2 )
+ _baseLabel "Average System Load over the last 1, 5, and 15 minutes\nNormalized to $maxload"
+ )
+
+ _label 0 5 _west _down _large "Mem"
+
+end-of-file
+
+if [ $realmem -ne 0 ]
+then
+ if $utilmem
+ then
+ cat << end-of-file >> $tmp.conf
+ _stack 1 5 _west (
+ _metrics (
+ mem.util.kernel $realmem
+ mem.util.fs_ctl $realmem
+ mem.util.fs_dirty $realmem
+ mem.util.fs_clean $realmem
+ mem.util.user $realmem
+ )
+ _colorlist memory_colors
+ _baseLabel "Physical Memory Utilization\nNormalized to $realmem Kbytes"
+ )
+end-of-file
+ elif $linuxutilmem
+ then
+ cat << end-of-file >> $tmp.conf
+ _stack 1 5 _west (
+ _metrics (
+ mem.util.shared $realmem
+ mem.util.cached $realmem
+ mem.util.bufmem $realmem
+ mem.util.other $realmem
+ mem.util.free $realmem
+ )
+ _colorlist memory_colors
+ _baseLabel "Physical Memory Utilization\nNormalized to `expr $realmem / 1024` Kbytes"
+ )
+end-of-file
+ else
+ cat << end-of-file >> $tmp.conf
+ _stack 1 5 _west _fillmod (
+ _metrics (
+ mem.freemem $realmem
+ )
+ _colorlist ( blue2 )
+ _baseLabel "Unallocated Physical Memory"
+ _stackLabel "Used Physical Memory\nNormalized to $realmem Kbytes"
+ )
+end-of-file
+fi
+elif $utilmem
+then
+ cat << end-of-file >> $tmp.conf
+ _stack 1 5 _west _utilmod (
+ _metrics (
+ mem.util.kernel 0
+ mem.util.fs_ctl 0
+ mem.util.fs_dirty 0
+ mem.util.fs_clean 0
+ mem.util.user 0
+ mem.util.free 0
+ )
+ _colorlist memory_colors
+ _baseLabel "Physical Memory Utilization"
+ )
+end-of-file
+elif $linuxutilmem
+then
+ cat << end-of-file >> $tmp.conf
+ _stack 1 5 _west _utilmod (
+ _metrics (
+ mem.util.shared 0
+ mem.util.cached 0
+ mem.util.bufmem 0
+ mem.util.other 0
+ mem.util.free 0
+ )
+ _colorlist memory_colors
+ _baseLabel "Physical Memory Utilization"
+ )
+end-of-file
+fi
+
+cat << end-of-file >> $tmp.conf
+
+ _label 0 7 _west _down _large "CPU"
+
+ _stack 1 7 _west (
+ _metrics (
+end-of-file
+$have_user && echo " kernel.all.cpu.user $maxcpu" >> $tmp.conf
+$have_sys && echo " kernel.all.cpu.sys $maxcpu" >> $tmp.conf
+$have_nice && echo " kernel.all.cpu.nice $maxcpu" >> $tmp.conf
+$have_intr && echo " kernel.all.cpu.intr $maxcpu" >> $tmp.conf
+$have_wait && echo " kernel.all.cpu.wait.total $maxcpu" >> $tmp.conf
+cat << end-of-file >> $tmp.conf
+ )
+ _colorlist cpu_colors
+ _baseLabel "CPU Utilization\nSummed over $cpudesc"
+ )
+end-of-file
+
+if [ "$ninterfaces" -gt 0 ]
+then
+ cat << end-of-file >> $tmp.conf
+
+#
+# Network Stuff and Alarms
+#
+
+ _marginWidth 1
+
+ _grid 4 2 1 7 _nw (
+
+ _marginWidth 8
+
+ _label 0 0 _sw "Network Input"
+
+ _bar 0 1 _nw _groupByMetric (
+ _metrics (
+ network.interface.in.bytes[$interfaces] $maxbyte
+ network.interface.in.packets[$interfaces] $maxpack
+ network.interface.in.errors[$interfaces] $maxerr
+ )
+ _colorlist network_colors
+ _metricLabels _away ( "Bytes" "Packets" "Errors" )
+ _baseLabel "Input on all Network Interfaces\nNormalized to $maxbyte bytes per second and $maxpack packets per second"
+ )
+
+ _label 0 2 _sw "Network Output"
+
+ _bar 0 3 _nw (
+ _metrics (
+ network.interface.out.bytes[$interfaces] $maxbyte
+ network.interface.out.packets[$interfaces] $maxpack
+ network.interface.out.errors[$interfaces] $maxerr
+ )
+ _instlabels _away ( $interfaces_sp )
+ _metricLabels _away ( "Bytes" "Packets" "Errors" )
+ _colorlist network_colors
+ _baseLabel "Output on all Network Interfaces\nNormalized to $maxbyte bytes per second and $maxpack packets per second"
+ )
+ )
+end-of-file
+fi
+
+echo ")" >> $tmp.conf
+
+$verbose && cat $tmp.conf
+
+eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" -xrm "'*iconName:osvis'" -R $PCP_VAR_DIR/config/pmlogger/config.osvis
+
+exit
diff --git a/src/pmview/front-ends/pmview-args b/src/pmview/front-ends/pmview-args
new file mode 100644
index 0000000..31a7008
--- /dev/null
+++ b/src/pmview/front-ends/pmview-args
@@ -0,0 +1,625 @@
+# Copyright (c) 1995-2005 Silicon Graphics, Inc. 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.
+#
+
+prog=`basename $0`
+
+PMVIEW=pmview
+PMPROBE=pmprobe
+CONFIRM="$PCP_XCONFIRM_PROG"
+ECHONL="echo -n"
+_multiple_sources=false
+
+#
+# Standard usage and command-line argument parsing for pmview front ends.
+# This file should be included by pmview front end scripts to present a
+# consistent interface. See pmview(1), dkvis(1), mpvis(1) and nfsvis(1)
+# for more information on their respective interfaces.
+#
+
+#
+# The front end scripts should call _pmview_usage after their own usage
+# information in a subroutine called _usage. The _usage subroutine may be
+# called by either _pmview_note or _pmview_args.
+#
+_pmview_usage()
+{
+ if $_multiple_sources
+ then
+ echo -n '
+ -A align align sample times on natural boundaries
+ -a archive[,archive...]
+ metrics source is one or more PCP archive logs
+ -C check configuration file and exit
+ -h host[,host...] metrics source is PMCD on one or more hosts'
+
+ else
+
+ echo -n '
+ -A align align sample times on natural boundaries
+ -a archive metrics source is a PCP archive log
+ -C check configuration file and exit
+ -h host metrics source is PMCD on host'
+
+ fi
+
+ echo '
+ -n pmnsfile use an alternative PMNS
+ -O offset initial offset into the time window
+ -p port port name for connection to existing time control
+ -S starttime start of the time window
+ -T endtime end of the time window
+ -t interval sample interval [default 2.0 seconds]
+ -x version use pmlaunch(5) version [default version 2.0]
+ -z set reporting timezone to local time of metrics source
+ -Z timezone set reporting timezone
+
+ -display display-string
+ -geometry geometry-string
+ -name name-string
+ -title title-string
+ -xrm resource'
+}
+
+# Most front-end scripts can handle input from only one source, and
+# hence only one -h or -a option.
+#
+# For those than can handle multiple sources, they should call
+# _pmview_multiple_sources_are_ok before calling _pmview_args to
+# enable the following extensions to the -a and -h options:
+# -a a1 -a a2 ... multiple -a options
+# -h h1 -h h2 ... multiple -h options
+# -a a1,a2,... multiple archives with the -a option
+# -h h1,h2,... multiple hosts with the -h option
+#
+_pmview_multiple_sources_are_ok()
+{
+ _multiple_sources=true
+}
+
+# check for magic numbers in a file that indicate it is a PCP archive
+#
+# if file(1) was reliable, this would be much easier, ... sigh
+#
+# if you need to change this, make consistent changes in all these
+# places:
+# _check_file() in src/pmafm/mkaf
+# _is_archive() in src/pmafm/pmafm
+# _is_archive() in src/pmview/front-ends/pmview-args
+#
+_is_archive()
+{
+ case "$PCP_PLATFORM" in
+ irix)
+ dd ibs=1 count=7 if="$1" 2>/dev/null | od -X | $PCP_AWK_PROG '
+NR == 1 && $2 == "00000084" && $3 == "50052600" { exit 0 }
+ { exit 1 }'
+ ;;
+ linux)
+ dd ibs=1 count=7 if="$1" 2>/dev/null | od -x | $PCP_AWK_PROG '
+NR == 1 && NF == 5 && $2 == "0000" && $3 == "0084" && $4 == "5005" && $5 == "2600" { exit 0 }
+NR == 1 && NF == 5 && $2 == "0000" && $3 == "8400" && $4 == "0550" && $5 == "0026" { exit 0 }
+
+ { exit 1 }'
+ ;;
+ esac
+ return $?
+}
+
+# One of the first actions of a front end script should be to call
+# _pmview_args. It sets the following variables:
+#
+# host the first host specified with -h (if any) in the format
+# hostname
+# else the host from the first archive in the format
+# hostname (Archive archivename)
+# arch the first archive specified with -a (if any).
+# All archives are passed on to pmview with one -a
+# argument per archive via $args
+# numsource Number of metrics sources (hosts or archives)
+# args The list of args that pmview will comprehend and use.
+# otherArgs The arguments pmview will not understand and should be
+# handled by the front end script.
+# titleArg The title the user prefers. If empty, the title should be
+# provided by the front end script.
+# prog The name of the program.
+# namespace The namespace (including the flag) if specified, else empty
+# eg "-n foo"
+# msource The default metrics source, whether live or an archive,
+# including the flag. e.g. "-h blah" or "-a first_archive".
+# Taken from the first encountered -a or -h option.
+#
+# sourcelist space separated list of hosts or archives
+#
+_pmview_args()
+{
+
+_seen_host=false
+_seen_arch=false
+host=""
+arch=""
+numsource=0
+args=""
+otherArgs=""
+titleArg=""
+namespace=""
+msource=""
+
+if [ $# -eq 1 -a '$1' = '-\?' ]
+then
+ _usage
+ exit 0
+fi
+
+while [ $# -gt 0 ]
+do
+ case $1
+ in
+ -g*|-di*|-name|-xrm)
+ # assume an X11 argument
+ if [ $# -lt 2 ]
+ then
+ _pmview_note Usage-Error error "$prog: X-11 option $1 requires one argument"
+ #NOTREACHED
+ fi
+ args="$args $1 '$2'"
+ shift
+ ;;
+
+ -title)
+ # assume an X11 argument
+ if [ $# -lt 2 ]
+ then
+ _pmview_note Usage-Error error "$prog: Option $1 requires one argument"
+ #NOTREACHED
+ exit 1
+ fi
+ titleArg="$2"
+ shift
+ ;;
+
+ -A|-D|-O|-p|-S|-T|-t|-x|-Z)
+ if [ $# -lt 2 ]
+ then
+ _pmview_note Usage-Error error "$prog: Option $1 requires one argument"
+ #NOTREACHED
+ fi
+ args="$args $1 '$2'"
+ shift
+ ;;
+
+ -A*|-D*|-O*|-p*|-S*|-T*|-t*|-Z*|-C|-z)
+ args="$args $1"
+ ;;
+
+ -a)
+ if $_seen_host
+ then
+ _pmview_note Usage-Error error "$prog: Only one of the -h or -a options may be specified"
+ #NOTREACHED
+ fi
+ if [ $# -lt 2 ]
+ then
+ _pmview_note Usage-Error error "$prog: Option $1 requires one argument"
+ #NOTREACHED
+ fi
+ for _archbase in `echo "$2" | sed -e 's/,/ /g'`
+ do
+ if [ $numsource -gt 0 -a $_multiple_sources = false ]
+ then
+ _pmview_note Usage-Error error "$prog: Only one -a option may be specified"
+ # NOTREACHED
+ fi
+ if _is_archive $_archbase 2>&1
+ then
+ _archbase=`echo $_archbase | sed -e 's/\.[^.]*$//'`
+ fi
+ # at least $_archbase.0 and $_archbase.meta have to be here
+ #
+ if _is_archive $_archbase.0 && _is_archive $_archbase.meta
+ then
+ :
+ else
+ _pmview_note Error error "$prog: \"$_archbase\" is not the basename of a valid PCP archive"
+ #NOTREACHED
+ fi
+ if [ -z "$arch" ]
+ then
+ # first archive seen
+ #
+ arch=$_archbase
+ msource="-a $_archbase"
+ host=`pmdumplog -l $arch \
+ | $PCP_AWK_PROG '/^Performance/ {print $5}' \
+ | sed -e 's/,//g'`
+ [ "X$host" = X ] && host="unknown host"
+ host="$host (Archive $arch)"
+ fi
+
+ # pmview(1) can handle multiple -a options, so
+ # pass _all_ archive names back to the caller both as
+ # -a options via $args and in $sourcelist (counted by
+ # $numsource).
+ #
+ # Note: multiple -h options are handled slightly
+ # differently, see also the comments for -h below.
+ #
+
+ args="$args -a $_archbase"
+ if [ -z "$sourcelist" ]; then
+ sourcelist=$_archbase
+ else
+ sourcelist="$sourcelist $_archbase"
+ fi
+ numsource=`expr $numsource + 1`
+ done
+ _seen_arch=true
+ shift
+ ;;
+
+ -h)
+ if $_seen_arch
+ then
+ _pmview_note Usage-Error error "$prog: Only one of the -h or -a options may be specified"
+ #NOTREACHED
+ fi
+ if [ $# -lt 2 ]
+ then
+ _pmview_note Usage-Error error "$prog: Option $1 requires one argument"
+ #NOTREACHED
+ fi
+ for _host in `echo "$2" | sed -e 's/,/ /g'`
+ do
+ if [ $numsource -gt 0 -a $_multiple_sources = false ]
+ then
+ _pmview_note Usage-Error error "$prog: Only one -h option may be specified"
+ # NOTREACHED
+ fi
+ if [ -z "$host" ]
+ then
+ host=$_host
+ msource="-h $_host"
+
+ # pmview(1) can handle only one -h options, so
+ # pass the _first_ host name back to the caller as a
+ # -h option via $args and _all_ hostnames via
+ # $sourcelist (counted by $numsource).
+ #
+ # Note: multiple -a options are handled slightly
+ # differently, see also the comments for -a above.
+ #
+
+ args="$args -h $_host"
+ fi
+ if [ -z "$sourcelist" ]; then
+ sourcelist=$_host
+ else
+ sourcelist="$sourcelist $_host"
+ fi
+ numsource=`expr $numsource + 1`
+ done
+ _seen_host=true
+ shift
+ ;;
+
+ -n)
+ if [ $# -lt 2 ]
+ then
+ _pmview_note Usage-Error error "$prog: Option $1 requires one argument"
+ #NOTREACHED
+ fi
+ namespace="-n $2"
+ args="$args -n $2"
+ shift
+ ;;
+
+ *)
+ otherArgs="$otherArgs $1"
+ ;;
+
+ esac
+ shift
+
+done
+
+if [ -z "$host" ]
+then
+ host=`pmhostname`
+ msource="-h $host"
+fi
+}
+
+# standard fatal error reporting
+# Usage: _pmview_error message goes in here
+# _pmview_error -f file
+#
+_pmview_error()
+{
+ _pmview_note Error error $*
+}
+
+# standard warning
+# Usage: _pmview_warning message goes in here
+# _pmview_warning -f file
+#
+_pmview_warning()
+{
+ _pmview_note Warning warning $*
+}
+
+# standard info
+# Usage: _pmview_info message goes in here
+# _pmview_info -f file
+#
+_pmview_info()
+{
+ _pmview_note Info info $*
+}
+
+# generic notifier
+# Usage: _pmview_note tag icon args ...
+#
+_pmview_note()
+{
+ tag=$1; shift
+ icon=$1; shift
+ button=""
+ [ $tag = Error ] && button="-B Quit"
+ [ $tag = Usage-Error ] && button="-B Quit -b Usage"
+
+ [ X"$PCP_STDERR" = XDISPLAY -a -z "$DISPLAY" ] && unset PCP_STDERR
+
+ if [ $# -eq 2 -a "X$1" = X-f ]
+ then
+ case "$PCP_STDERR"
+ in
+ DISPLAY)
+ ans=`$CONFIRM -icon $icon -file $2 -useslider -header "$tag $prog" $button 2>&1`
+ ;;
+ '')
+ echo "$tag:" >&2
+ cat $2 >&2
+ ans=Quit
+ ;;
+ *)
+ echo "$tag:" >>$PCP_STDERR
+ cat $2 >>$PCP_STDERR
+ ans=Quit
+ ;;
+ esac
+ else
+ case "$PCP_STDERR"
+ in
+ DISPLAY)
+ ans=`$CONFIRM -icon $icon -t "$*" -noframe -header "$tag $prog" $button 2>&1`
+ ;;
+ '')
+ echo "$tag: $*" >&2
+ ans=Quit
+ ;;
+ *)
+ echo "$tag: $*" >>$PCP_STDERR
+ ans=Quit
+ ;;
+ esac
+ fi
+
+ if [ $tag = Usage-Error ]
+ then
+ [ $ans = Usage ] && _usage
+ tag=Error
+ fi
+
+ [ $tag = Error ] && exit 1
+}
+
+# used internally by _pmview_cache_fetch() and _pmview_fetch()
+#
+_pmview_probe()
+{
+ flag=$1
+ shift
+ ( echo $* \
+ ; echo "-----" \
+ ; ( $PMPROBE $namespace $msource $flag $* 2>$tmp.pmview_err \
+ | tee -a $tmp.pmview_fetch \
+ ) \
+ ) \
+ | tr ' ' '\012' \
+ | sed -e 's/"//g' \
+ | $PCP_AWK_PROG '
+BEGIN { last = 0 }
+$1 == "-----" { state = 1; next }
+state == 0 { metric[last] = pat[last] = $1
+ # deal with arguments that are non-terminals in the PMNS
+ # so pmprobe a.b => a.b.c a.b.c.x a.b.d etc
+ gsub("\\.", "\\.", pat[last])
+ pat[last] = "^" pat[last] "\\."
+ last++
+ next
+ }
+state > 0 { for (i = 0; i < last; i++) {
+ if (metric[i] == $1 || match($1, pat[i]) > 0) {
+ # new matching metric name
+ name=$1
+ state=2
+ next
+ }
+ }
+ }
+state == 2 { if ($1 > 0) state = 3
+ else state = 1
+ next
+ }
+state == 3 { printf("%s%s|%s\n", "'"$flag|$msource|"'",name,$1) }'
+}
+
+# Fetch metrics and cache result
+# input
+# $1 - pmprobe flag
+# $* - 1 or more metrics
+# output
+# $tmp.pmview_cache - cached values, with this format
+# pmprobe flag|metric source|metric name|pmprobe result
+#
+_pmview_cache_fetch()
+{
+ flag=$1
+ shift
+ _pmview_probe $flag $* >>$tmp.pmview_cache
+
+ return 0
+}
+
+# Fetch metrics
+#
+# input
+# $1 - pmprobe flag
+# $2 - metric name
+# output
+# $number - number of values
+# $tmp.pmview_result - values
+#
+_pmview_fetch()
+{
+ flag=$1
+ metric=$2
+ rm -f $tmp.pmview_fetch $tmp.pmview_result
+ if [ -s $tmp.pmview_cache ]
+ then
+ $PCP_AWK_PROG -F\| \
+ <$tmp.pmview_cache >$tmp.pmview_result \
+'
+$1 == "'"$flag"'" && $2 == "'"$msource"'" && $3 == "'"$metric"'" { print $4 }'
+ fi
+
+ if [ ! -s $tmp.pmview_result ]
+ then
+ # cache miss, forced to probe
+ #
+ _pmview_probe $flag $metric \
+ | $PCP_AWK_PROG -F\| >$tmp.pmview_result '{print $4}'
+ fi
+
+ if [ -s $tmp.pmview_result ]
+ then
+ number=`wc -l <$tmp.pmview_result | sed -e 's/ //g'`
+ else
+ if [ -s $tmp.pmview_fetch ]
+ then
+ check=`cut -d ' ' -f 2 $tmp.pmview_fetch`
+ if [ "$check" = "$metric" ]
+ then
+ # *.pmview_fetch looks valid, extract numval from 2nd field
+ #
+ number=`cut -d ' ' -f 2 $tmp.pmview_fetch`
+ else
+ # *.pmview_fetch exists, but does not contain
+ # pmprobe output, more than likely this is some
+ # sort of fatal error message ... but _real_ message
+ # is likely to be in *.pmview_err
+ #
+ [ -s $tmp.pmview_err ] && mv $tmp.pmview_err $tmp.pmview_fetch
+ number=-1
+ fi
+ else
+ number=-1
+ mv $tmp.pmview_err $tmp.pmview_fetch
+ fi
+ fi
+ if [ $number -le 0 ]
+ then
+ rm -f $tmp.pmview_result
+ return 1
+ fi
+
+ return 0
+}
+
+# Fetch the metric values
+#
+# input
+# $1 - metric name
+# output
+# $number - number of values
+# $tmp.pmview_result - values
+#
+_pmview_fetch_values()
+{
+ _pmview_fetch -v $1
+ return $?
+}
+
+# Fetch the metric instance list
+#
+# input
+# $1 - metric name
+# output
+# $number - number of instances
+# $tmp.pmview_result - instances
+#
+_pmview_fetch_indom()
+{
+ _pmview_fetch -I $1
+ return $?
+}
+
+# Convert pmprobe/pminfo error message into something useful and
+# consistent
+#
+_pmview_fetch_mesg()
+{
+ $PCP_AWK_PROG '
+$1 == "pmprobe:" { $1 = "'$prog':"; print; exit }
+$1 == "pminfo:" { $1 = "'$prog':"; print; exit }
+$1 == "Error:" { $1 = ":";
+ printf("%s: %s%s\n", "'$prog'", metric, $0); exit }
+$1 == "inst" { exit }
+NF == 1 { metric = $1; next }
+NF == 0 { next }
+NF == 2 && $2 == "0" { printf("%s: %s: No values available\n", "'$prog'", $1); exit}
+ { $2 = ":"; print "'$prog': " $0; exit}' \
+ | sed "s/ : /: /" \
+ | fmt
+}
+
+# Generate error metric for failed fetch
+#
+_pmview_fetch_fail()
+{
+ cat $tmp.pmview_fetch | _pmview_fetch_mesg >> $tmp.msg
+ echo "$prog: Failed to $1 from host \"$host\"" | fmt >> $tmp.msg
+ _pmview_error -f $tmp.msg
+ # NOTREACHED
+}
+
+# Generate warning message for failed fetch
+#
+_pmview_fetch_warn()
+{
+ cat $tmp.pmview_fetch | _pmview_fetch_mesg >> $tmp.msg
+ echo "$prog: Failed to $1 from host \"$host\"" | fmt >> $tmp.msg
+ _pmview_warning -f $tmp.msg
+ rm -f $tmp.msg
+}
+
+# Check that $OPTARG for option $1 is a positive integer
+# ...note the creative use of unary - to prevent leading signs
+#
+_pmview_unsigned()
+{
+ if [ "X-$OPTARG" != "X`expr 0 + -$OPTARG 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -$1 option must have a positive integral argument"
+ # NOTREACHED
+ fi
+}
diff --git a/src/pmview/front-ends/weblogvis b/src/pmview/front-ends/weblogvis
new file mode 100755
index 0000000..5b570bd
--- /dev/null
+++ b/src/pmview/front-ends/weblogvis
@@ -0,0 +1,451 @@
+#!/bin/sh
+# Copyright (c) 1995-2000 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+# default idle time
+#
+defidle=3600
+
+_usage()
+{
+ echo >$tmp.msg 'Usage: '$prog' [options] [server ...]
+
+Options
+ -b display byte rate, rather than request rate
+ -f display activity by function, rather than activity by
+ result size
+ -i show server names
+ -I time maximum expected idle time in seconds [default $defidle]
+ -m max maximum expected request rate (or maximum byte rate)
+ -V verbose/diagnostic output
+
+pmview(1) options:'
+ _pmview_usage >> $tmp.msg
+ echo '
+Default title is: Web Log Activity (request rate by result size) for Host' >> $tmp.msg
+ echo '
+ The default is to display the request rate, grouped by result size, for all
+ Web servers on the target host.' | fmt >> $tmp.msg
+ _pmview_info -f $tmp.msg
+}
+
+# --- build WM_COMMAND X(1) property for restart after login/logout ---
+#
+echo -n "pmview Version 2.1 \"$prog\"" >$tmp.pmview
+for arg
+do
+ echo -n " \"$arg\"" >>$tmp.pmview
+done
+echo >> $tmp.pmview
+
+# --- parse command line arguments ---
+#
+verbose=false
+serverList=""
+max=0
+idle=$defidle
+class=size
+show=request
+showInst=false
+
+_pmview_args "$@"
+
+if [ -n "$otherArgs" ]
+then
+ while getopts "?bfiI:m:v:V" c $otherArgs
+ do
+ case $c
+ in
+ b) # show bytes not requests
+ show=byte
+ ;;
+
+ f) # classify by function (method)
+ class=method
+ ;;
+ i)
+ showInst=true
+ ;;
+ I)
+ idle=$OPTARG
+ # and now the obscure +ve integer checking bit
+ # ...note the creative use of unary - to prevent leading signs
+ if [ "X-$idle" != "X`expr 0 + -$idle 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -I must have a positive integral argument"
+ #NOTREACHED
+ fi
+ ;;
+ m)
+ max=$OPTARG
+ # and now the obscure +ve integer checking bit
+ # ...note the creative use of unary - to prevent leading signs
+ if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -m must have a positive integral argument"
+ #NOTREACHED
+ fi
+ ;;
+ v)
+ if [ $OPTARG = "1" ]
+ then
+ _pmview_warning "$prog: pmview version 1 no longer supported, using version 2"
+ elif [ $OPTARG != "2" ]
+ then
+ _pmview_error "$prog: only version 2 supported for -v"
+ # NOTREACHED
+ fi
+ ;;
+ V)
+ verbose=true
+ ;;
+ '?')
+ _usage
+ exit 1
+ ;;
+ esac
+ done
+
+ set - $otherArgs
+ shift `expr $OPTIND - 1`
+ [ $# -gt 0 ] && serverList_sp=$* && serverList=`echo $* | sed -e 's/ /,/g'`
+fi
+[ -z "$titleArg" ] && titleArg="SGI PCP : Web Log Activity"
+
+
+if [ $max = 0 ]
+then
+ if [ $show = request ]
+ then
+ # requests per second
+ max=50
+ else
+ # bytes per second
+ max=500000
+ fi
+fi
+
+
+# maximum req error rate (default: 5% of request rate)
+#
+maxerr=`expr $max / 20`
+
+
+# if metrics source is an archive, and find out name of host
+#
+if [ "X$arch" != X ]
+then
+ host=`pmdumplog -l $arch | $PCP_AWK_PROG '/^Performance/ {print $5}' \
+ | sed -e 's/,//g'`
+ [ "X$host" = X ] && host="unknown host"
+ host="$host (Archive $arch)"
+fi
+
+
+# get perserver instances
+# in the default case use web.perserver.requests.total
+# in the -b flag case use web.perserver.bytes.total
+#
+rm -f $tmp.int
+if [ $show = request ]
+then
+ pminfo -f $msource $namespace web.perserver.requests.total \
+ > $tmp.int 2>/dev/null
+else
+ pminfo -f $msource $namespace web.perserver.bytes.total \
+ > $tmp.int 2>/dev/null
+fi
+if [ ! -s $tmp.int ]
+then
+ if [ "X$arch" != "X" ]
+ then
+ _pmview_error "$prog: weblog metrics not included in the archive \"$arch\""
+ #NOTREACHED
+ else
+ _pmview_error "$prog: weblog metrics not available for host \"$host\""
+ #NOTREACHED
+ fi
+fi
+
+sed -e 's/\]//' -e 's/"//g' $tmp.int \
+ | $PCP_AWK_PROG '$1 == "inst" {print $4}' > $tmp.list
+
+if [ ! -s $tmp.list ]
+then
+ if [ "X$arch" != X ]
+ then
+ _pmview_error "$prog: failed to get web servers from archive \"$arch\""
+ #NOTREACHED
+ else
+ _pmview_error "$prog: failed to get web servers from host \"$host\""
+ #NOTREACHED
+ fi
+fi
+
+rm -f $tmp.chosen
+if [ -z "$serverList" ]
+then
+ cp $tmp.list $tmp.chosen
+else
+ touch $tmp.chosen
+ for i in $serverList_sp
+ do
+ egrep $i $tmp.list >> $tmp.chosen
+ done
+fi
+
+servers_sp=`cat $tmp.chosen | sort | uniq`
+servers=`echo $servers_sp | sed -e 's/ /,/g'`
+nservers=`echo $servers | wc -w`
+
+if [ $nservers = 0 ]
+then
+ _usage
+ echo
+ echo "Error: $prog: no matching web servers"
+ echo " Available web servers are: " `cat $tmp.list`
+ exit 1
+fi
+
+
+if [ $show = request ]
+then
+ totalLabel="Total_Req_Rate"
+ label_sp="\"Request Rate\""
+ met="requests"
+ titleArg="$titleArg (request rate"
+else
+ totalLabel="Total_Data_Rate"
+ label_sp="\"Data Rate\""
+ met="bytes"
+ titleArg="$titleArg (data rate"
+fi
+
+#
+# strings for base plane labels
+#
+basestr_idle="Elapsed time since the last request\nNormalized to $idle seconds"
+if [ $show = request ]
+then
+ basestr_total="Total number of HTTP requests processed by server\nNormalized to $max requests per second"
+ basestr_req="HTTP request rate by response size in bytes\nNormalized to $max hits per second"
+ basestr_type="HTTP request rate by HTTP method\nNormalized to $max hits per second"
+else
+ basestr_total="Total number of bytes processed by server\nNormalized to $max bytes per second"
+ basestr_req="HTTP size rate by response size in bytes\nNormalized to $max bytes per second"
+ basestr_type="HTTP size rate by HTTP method\nNormalized to $max hits per second"
+fi
+
+
+#--- config file has already been created; continue writing to it ---
+#
+
+cat << end-of-file >>$tmp.pmview
+#
+# $prog
+#
+# Servers: $servers
+#
+end-of-file
+
+if $verbose
+then
+ if [ "X$serverList" != X ]
+ then
+ echo "# Matching servers for \"$serverList\": $servers"
+ fi
+fi
+
+if [ $class = size ]
+then
+ titleArg="$titleArg by result size)"
+else
+ titleArg="$titleArg by request type)"
+fi
+
+
+#
+# the real config starts here
+#
+cat << end-of-file >>$tmp.pmview
+
+_scale 1.2
+
+_grid _hide (
+
+ _label 2 0 1 5 _down _large $label_sp
+
+ _bar 0 0 east _col (
+ _metrics (
+ web.perserver.logidletime[$servers] $idle
+ )
+ _metriclabels ( Idle )
+ _colorList ( orange )
+ _baseLabel "$basestr_idle"
+ )
+
+end-of-file
+
+if [ $class = size ]
+then
+ cat << end-of-file >>$tmp.pmview
+
+ _bar 0 2 east _col (
+ _metrics (
+ web.perserver.$met.total[$servers] $max
+ )
+ _metriclabels ( Total )
+ _colorList ( rgbi:0.0/0.88/0.88 )
+ _baseLabel "$basestr_total"
+ )
+
+ _bar 0 4 east _col _groupbyinst (
+ _metrics (
+end-of-file
+
+ if [ $show = request ]
+ then
+ cat <<end-of-file >>$tmp.pmview
+ web.perserver.$met.size.unknown[$servers] $max
+end-of-file
+ fi
+
+ cat << end-of-file >>$tmp.pmview
+ web.perserver.$met.size.gt3m[$servers] $max
+ web.perserver.$met.size.le3m[$servers] $max
+ web.perserver.$met.size.le1m[$servers] $max
+ web.perserver.$met.size.le300k[$servers] $max
+ web.perserver.$met.size.le100k[$servers] $max
+ web.perserver.$met.size.le30k[$servers] $max
+ web.perserver.$met.size.le10k[$servers] $max
+ web.perserver.$met.size.le3k[$servers] $max
+end-of-file
+
+ if [ $show = request ]
+ then
+ cat <<end-of-file >>$tmp.pmview
+ web.perserver.$met.size.zero[$servers] $max
+ )
+ _metriclabels (
+ "?" "> 3M" "1M < 3M" "300K < 1M" "100K < 300K"
+ "30K < 100K" "10K < 30K" "3K < 10K" "0 < 3K" "0K"
+ )
+end-of-file
+ else
+ cat <<end-of-file >>$tmp.pmview
+ )
+ _metriclabels (
+ "> 3M" "1M < 3M" "300K < 1M" "100K < 300K"
+ "30K < 100K" "10K < 30K" "3K < 10K" "0 < 3K"
+ )
+end-of-file
+ fi
+
+ if $showInst
+ then
+ cat <<end-of-file >>$tmp.pmview
+ _instlabels _away ( $servers_sp )
+end-of-file
+ fi
+
+ cat << end-of-file >>$tmp.pmview
+ _colorList (
+ rgbi:1.0/0.35/0.0
+ rgbi:0.6/0.0/0.9
+ rgbi:0.0/1.0/0.0
+ rgbi:1.0/0.5/0.0
+ rgbi:0.65/0.3/1.0
+ rgbi:0.3/1.0/0.3
+ rgbi:1.0/0.65/0.3
+ rgbi:0.8/0.6/1.0
+ rgbi:0.6/1.0/0.6
+ rgbi:1.0/0.8/0.6
+
+ )
+ _baseLabel "$basestr_req"
+ )
+
+end-of-file
+
+else
+ cat << end-of-file >>$tmp.pmview
+
+ _bar 0 2 east _col (
+ _metrics (
+ web.perserver.$met.total[$servers] $max
+ )
+ _metriclabels ( Total )
+ _colorList ( rgbi:1.0/0.5/0.0 )
+ _baseLabel "$basestr_total"
+ )
+
+ _bar 0 4 east _col (
+ _metrics (
+ web.perserver.$met.get[$servers] $max
+ web.perserver.$met.head[$servers] $max
+ web.perserver.$met.post[$servers] $max
+ web.perserver.$met.other[$servers] $max
+end-of-file
+
+ if [ $show = request ]
+ then
+ cat << end-of-file >>$tmp.pmview
+ web.perserver.errors[$servers] $maxerr
+end-of-file
+ fi
+
+ cat << end-of-file >>$tmp.pmview
+ )
+ _metriclabels ( Get Head Post Other Error )
+end-of-file
+
+ if $showInst
+ then
+ cat <<end-of-file >>$tmp.pmview
+ _instlabels _away ( $servers_sp )
+end-of-file
+ fi
+
+ cat << end-of-file >>$tmp.pmview
+ _colorList (
+ rgbi:1.0/1.0/0.0
+ rgbi:0.0/1.0/1.0
+ rgbi:1.0/0.0/1.0
+ rgbi:1.0/1.0/0.6
+ rgbi:0.8/0.0/0.0
+ )
+ _baseLabel "$basestr_type"
+ )
+end-of-file
+
+fi
+
+cat << end-of-file >>$tmp.pmview
+)
+end-of-file
+
+titleArg="$titleArg for Host $host"
+
+$verbose && cat $tmp.pmview
+
+eval $PMVIEW <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'"
+
+exit
+
diff --git a/src/pmview/front-ends/weblogvis.load b/src/pmview/front-ends/weblogvis.load
new file mode 100755
index 0000000..a676124
--- /dev/null
+++ b/src/pmview/front-ends/weblogvis.load
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Copyright (c) 2001 Silicon Graphics, Inc. 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.
+#
+# 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
+
+# Load up a Web server to show off/QA weblogvis
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; killall -9 load; exit" 0 1 2 3 15
+
+i=0
+
+# specular
+#
+cat >$tmp.$i <<End-of-File
+GET http://155.11.225.108/file8k.html
+GET http://155.11.225.108/file15k.html
+End-of-File
+webping -c $tmp.$i -I0 -q &
+i=`expr $i + 1`
+
+cat >$tmp.$i <<End-of-File
+GET http://155.11.225.108/file15k.html
+End-of-File
+webping -c $tmp.$i -I0 -q &
+i=`expr $i + 1`
+
+# specular IP alias
+#
+cat >$tmp.$i <<End-of-File
+GET http://155.11.225.118/file45k.html
+End-of-File
+webping -c $tmp.$i -I0 -q &
+i=`expr $i + 1`
+
+cat >$tmp.$i <<End-of-File
+GET http://155.11.225.118/file15k.html
+GET http://155.11.225.118/file45k.html
+End-of-File
+webping -c $tmp.$i -I0 -q &
+i=`expr $i + 1`
+
+cat >$tmp.$i <<End-of-File
+GET http://155.11.225.118/file45k.html
+End-of-File
+webping -c $tmp.$i -I0 -q &
+i=`expr $i + 1`
+
+# specular proxy
+#
+cat >$tmp.$i <<End-of-File
+GET http://boing/file15k.html
+End-of-File
+webping -c $tmp.$i -I0 -q -P specular:8080 &
+i=`expr $i + 1`
+
+cat >$tmp.$i <<End-of-File
+GET http://boing/file0k.html
+GET http://boing/file0k.html
+GET http://boing/file115k.html
+End-of-File
+webping -c $tmp.$i -I0 -q -P specular:8080 &
+i=`expr $i + 1`
+
+# specular socks
+#
+cat >$tmp.$i <<End-of-File
+GET http://155.11.225.108/file500k.html
+GET http://boing/file500k.html
+End-of-File
+webping -c $tmp.$i -I0 -q -S specular:8080 &
+i=`expr $i + 1`
+
+# specular ftp-socks
+#
+cat >$tmp.$i <<End-of-File
+GET ftp://155.11.225.108/pub/README
+End-of-File
+webping -c $tmp.$i -I0 -q -S specular:8080 &
+i=`expr $i + 1`
+
+# specular ftp
+#
+cat >$tmp.$i <<End-of-File
+GET ftp://155.11.225.108/pub/README
+End-of-File
+webping -c $tmp.$i -I0 -q &
+i=`expr $i + 1`
+
+wait
diff --git a/src/pmview/front-ends/weblogvis.rgb b/src/pmview/front-ends/weblogvis.rgb
new file mode 100644
index 0000000..11c4712
--- /dev/null
+++ b/src/pmview/front-ends/weblogvis.rgb
Binary files differ
diff --git a/src/pmview/front-ends/webpingvis b/src/pmview/front-ends/webpingvis
new file mode 100644
index 0000000..a08aa81
--- /dev/null
+++ b/src/pmview/front-ends/webpingvis
@@ -0,0 +1,372 @@
+#! /bin/sh
+# Copyright (c) 1995-2001 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+_usage()
+{
+ echo >$tmp.msg 'Usage: '$prog' [options]
+
+options:
+ -i show URL names
+ -m max maximum expected total ping response time (milliseconds)
+ -V verbose/diagnostic output
+
+pmview(1) options:'
+
+ _pmview_usage >> $tmp.msg
+ echo >> $tmp.msg
+ echo 'Default title is: SGI PCP: Web PING Performance for Host' >> $tmp.msg
+ echo '
+ The "max" parameter (used with -m) should be set to the maximum
+ expected ping response time for all URLs being monitored. The default
+ is 1000 milliseconds. This governs the height of the bar showing total
+ response time (at the far right of the scene). All bars showing
+ response times use "max" for height normalization.' >> $tmp.msg
+ _pmview_info -f $tmp.msg
+}
+
+#--- build WM_COMMAND X(1) property for restart after login/logout ---
+#
+echo -n "pmview Version 2.1 \"$prog\"" > $tmp.pmview
+for arg
+do
+ echo -n " \"$arg\"" >> $tmp.pmview
+done
+echo >> $tmp.pmview
+
+# --- LOCAL FUNCTIONS : START ------------------------------------------------
+_sort_host_indom()
+{
+ sed <$1 \
+ -e 's/instance\[\([0-9][0-9]*\)]:/\1/' \
+ | $PCP_AWK_PROG '
+BEGIN { state = 0 }
+/^samples:/ { state = 1; next }
+state == 0 { next }
+/^full label/ { label[$4] = $NF; next }
+NF == 0 { state = 2; next }
+state == 2 { for (i=1; i<=NF; i++) {
+ if (label[i-1] == "")
+ label[i-1] = $i
+ }
+ state = 3
+ next
+ }
+state == 3 { for (i=1; i<=NF; i++)
+ size[i-1] = $i
+ }
+END { for (i in label) {
+ print label[i],size[i]
+ }
+ }' \
+ | sort +1n -2 +0 -1 >$tmp.tmp
+ mv $tmp.tmp $1
+}
+
+_sort_arch_indom()
+{
+metric=webping.perurl.kbytes
+indom=`pminfo -d -a $arch $metric \
+| sed -n -e '/InDom:/{
+s/.*InDom: //
+s/ .*//p
+}'`
+
+if [ "X$indom" = XPM_INDOM_NULL ]
+then
+ _pmview_error "$prog: $metric is singular"
+ #NOTREACHED
+elif [ -z "$indom" ]
+then
+ _pmview_error "$prog: cannot determine InDom for $metric"
+ #NOTREACHED
+fi
+
+pmdumplog -z -i $arch 2>&1 \
+| $PCP_AWK_PROG '
+/^InDom: '$indom'$/ { state=1; next }
+/^InDom: / { state=0; next }
+state == 1 && /^[^ ]/ { print }' \
+| while read stamp junk
+do
+ pminfo -f -a $arch -z -O "@$stamp" -f $metric
+done \
+| sed -n \
+ -e '/ value /{
+s/"] value//
+s/.*"//p
+}' \
+| sort -u >$tmp.known
+
+pmdumplog -z -i $arch 2>&1 \
+| $PCP_AWK_PROG '
+/^InDom: '$indom'$/ { state=1; next }
+/^InDom: / { state=0; next }
+state == 1 && /^[ ]/ { print }' \
+| sed -n \
+ -e '/ or /{
+s/.* or "//
+s/".*//p
+}' \
+| sort -u \
+| join -a1 - $tmp.known \
+| sort +2n -3 +1 -2 \
+| $PCP_AWK_PROG '
+NF==1 { printf("%s ?\n",$0); next }
+ { print }' > $1
+}
+# --- LOCAL FUNCTIONS : END --------------------------------------------------
+
+verbose=false
+max=1000
+showInst=false
+
+_pmview_args "$@"
+
+if [ -n "$otherArgs" ]
+then
+ while getopts "?im:v:V" c $otherArgs
+ do
+ case $c
+ in
+ i)
+ showInst=true
+ ;;
+ m)
+ max=$OPTARG
+ # and now the obscure +ve integer checking bit
+ # ...note the creative use of unary - to prevent leading signs
+ if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -m must have a positive integral argument"
+ #NOTREACHED
+ fi
+ ;;
+ v)
+ if [ $OPTARG = "1" ]
+ then
+ _pmview_warning "$prog: pmview version 1 no longer supported, using version 2"
+ elif [ $OPTARG != "2" ]
+ then
+ _pmview_error "$prog: only version 2 supported for -v"
+ # NOTREACHED
+ fi
+ ;;
+ V)
+ verbose=true
+ ;;
+ '?')
+ _usage
+ exit 1
+ ;;
+ esac
+ done
+fi
+[ -z "$titleArg" ] && titleArg="SGI PCP: Web PING Performance for Host $host"
+
+
+# check that webping metrics are available from metrics source
+#
+if pminfo $msource $namespace webping 2>&1 \
+ | grep 'webping: Unknown metric name' >/dev/null
+then
+ _pmview_error "$prog: webping metrics not defined in the name space"
+ #NOTREACHED
+fi
+#
+# do a second check to make sure that we have webping.perurl metrics
+#
+if pminfo -f $msource $namespace webping.perurl.kbytes 2>&1 \
+ | grep 'inst .* value' >/dev/null
+then
+ :
+else
+ if [ "X$arch" != "X" ]
+ then
+ _pmview_error "$prog: webping.perurl metrics not available from $arch"
+ #NOTREACHED
+ else
+ _pmview_error "$prog: webping.perurl metrics not available from $host"
+ #NOTREACHED
+ fi
+fi
+
+
+# if metrics source is an archive, and find out name of host
+# get the instance domain and sort it
+#
+if [ "X$arch" != X ]
+then
+ _sort_arch_indom $tmp.int
+ host=`pmdumplog -l $arch | $PCP_AWK_PROG '/^Performance/ {print $5}' | sed -e 's/,//g'`
+ [ "X$host" = X ] && host="unknown host"
+ host="$host (Archive $arch)"
+else
+ pmval -h $host -s 1 webping.perurl.kbytes >$tmp.int
+ _sort_host_indom $tmp.int
+fi
+
+
+urlcount=`wc -l <$tmp.int | sed -e 's/ *//g'`
+bytesmax=`tail -1 $tmp.int | $PCP_AWK_PROG '{print $2}'`
+
+if [ $urlcount -eq 0 ]
+then
+ if [ "X$arch" != "X" ]
+ then
+ _pmview_error "$prog: there were no URLs monitored in archive \"$arch\""
+ #NOTREACHED
+ else
+ _pmview_error "$prog: there are no URLs monitored on host \"$host\""
+ #NOTREACHED
+ fi
+fi
+
+
+url_list=`$PCP_AWK_PROG <$tmp.int '
+NR>1 { printf "," }
+ { printf $1 }
+END { print "" }'`
+
+url_list_sp=`$PCP_AWK_PROG <$tmp.int '
+NR>1 { printf " " }
+/^GET_.*/ { printf "\"GET %s\"",substr($1,5) }
+/^HEAD_.*/ { printf "\"HEAD %s\"",substr($1,6) }
+/^POST_.*/ { printf "\"POST %s\"",substr($1,6) }
+END { print "" }'`
+
+
+#
+# strings for base plane labels
+#
+basestr_size="URL size in kbytes\nNormalized to $bytesmax kbytes"
+basestr_urltime="Time to fetch the URL\nNormalized to $max seconds"
+basestr_tottime="Time to fetch all URLs\nNormalized to $max seconds"
+basestr_err="Webing errors by error type\nNormalized to 1"
+
+
+#--- config file has already been created ; continue writing to it ---
+#
+
+cat << end-of-file >> $tmp.pmview
+#
+# $prog
+#
+# Largest URL = $bytesmax Kbytes
+# Maximum fetch time = $max seconds
+#
+# URLs = $url_list_sp
+#
+end-of-file
+
+
+#
+# the real config starts here
+# pmview Version 2.1
+#
+cat <<end-of-file >> $tmp.pmview
+
+_scale 1.2
+
+_colorList url_colors (
+ rgbi:1.0/0.5/0.0
+ rgbi:0.9/0.9/0.0
+ rgbi:0.0/0.9/0.9
+ rgbi:0.9/0.0/0.9
+)
+
+_grid _hide (
+
+ _bar 0 0 east _col (
+ _metrics (
+ webping.perurl.kbytes[$url_list] $bytesmax
+ )
+ _metriclabels ( Size )
+ _baseLabel "$basestr_size"
+end-of-file
+
+if $showInst
+then
+ cat <<end-of-file >>$tmp.pmview
+ _instlabels _towards ( $url_list_sp )
+end-of-file
+fi
+
+cat <<end-of-file >>$tmp.pmview
+ _colorList ( rgbi:0.0/0.9/0.0 )
+ )
+
+ _bar 0 2 ne _col _groupbyinst (
+ _metrics (
+ webping.perurl.time.total[$url_list] $max
+ webping.perurl.time.body[$url_list] $max
+ webping.perurl.time.head[$url_list] $max
+ webping.perurl.time.connect[$url_list] $max
+ )
+ _metriclabels ( Total Body Head Connect )
+ _baseLabel "$basestr_urltime"
+ _colorList url_colors
+ )
+
+ _bar 0 4 east _row _groupbyrow (
+ _metrics (
+ webping.errors.sockerr 1
+ webping.errors.httperr 1
+ webping.errors.htmlerr 1
+ webping.errors.othererr 1
+ )
+ _instlabels ( Errors )
+ _baseLabel "$basestr_err"
+ _colorList ( red1 red1 red1 red1 )
+ )
+
+end-of-file
+
+#
+# Only show row totals if there is more than one URL being monitored
+#
+if [ $urlcount -gt 1 ]
+then
+ totoff=`expr $urlcount + 1`
+ cat <<end-of-file >> $tmp.pmview
+ _bar 2 2 north _col _groupbycol (
+ _metrics (
+ webping.time.total $max
+ webping.time.body $max
+ webping.time.head $max
+ webping.time.connect $max
+ )
+ _colorList url_colors
+ _baseLabel "$basestr_tottime"
+ )
+end-of-file
+
+fi
+
+cat <<end-of-file >> $tmp.pmview
+)
+end-of-file
+
+$verbose && cat $tmp.pmview
+
+#eval pmview <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'" -geometry 560x515
+eval pmview <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'"
+
+exit
diff --git a/src/pmview/front-ends/webpingvis.rgb b/src/pmview/front-ends/webpingvis.rgb
new file mode 100644
index 0000000..a444bec
--- /dev/null
+++ b/src/pmview/front-ends/webpingvis.rgb
Binary files differ
diff --git a/src/pmview/front-ends/webvis b/src/pmview/front-ends/webvis
new file mode 100755
index 0000000..7969aec
--- /dev/null
+++ b/src/pmview/front-ends/webvis
@@ -0,0 +1,707 @@
+#!/bin/sh
+# Copyright (c) 1995-2001 Silicon Graphics, Inc. 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.
+#
+
+tmp=/tmp/$$
+trap "rm -f $tmp.*; exit" 0 1 2 3 15
+rm -f $tmp.*
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmview-args
+
+# --- scaling parameters ---
+#
+
+# maximum packets per second
+max=750
+
+# maximum req rate (default: 5% of packet rate)
+maxreq=`expr $max / 20`
+
+# maximum disk io rate (I/O operations per second)
+maxio=100
+
+# maximum average disk business (percent)
+maxbusy=30
+
+# milliseconds per CPU
+maxcpu=1000
+
+# maximum TCP output queue length
+maxq=5
+
+# --- define usage message ---
+#
+_usage()
+{
+ echo >$tmp.msg 'Usage: '$prog' [options] [interface ...]
+
+options:
+ -b maxbusy maximum average disk active (percent) [default 30]
+ -i maxio maximum total I/Os per second [default 100]
+ -m max maximum expected packets sent or received per sec [default 750]
+ -r maxreq maximum expected Web requests per second [default 35]
+ -V verbose/diagnostic output
+
+pmview(1) options:'
+
+ _pmview_usage >> $tmp.msg
+ echo >> $tmp.msg
+ echo >> $tmp.msg 'Default title is: Web Server Activity for Host'
+ echo >> $tmp.msg '
+ By default all network interfaces are shown, with a maximum packet rate
+ of '$max' packets per second. The maximum request rate is 5% (of the
+ maximum packet rate) and the maximum error rate is 20% of the maximum
+ request rate.
+
+ If given, the [interface ...] regular expressions restrict
+ the network statistics displayed to matching network interface names only.'
+
+ _pmview_info -f $tmp.msg
+}
+
+# --- build WM_COMMAND X(1) property for restart after login/logout ---
+#
+echo -n "pmview Version 2.1 \"$prog\"" > $tmp.pmview
+for arg
+do
+ echo -n " \"$arg\"" >>$tmp.pmview
+done
+echo >> $tmp.pmview
+
+# --- parse command line arguments ---
+#
+verbose=false
+argInterfaces=""
+interfaces=""
+
+_pmview_args "$@"
+
+if [ -n "$otherArgs" ]
+then
+ while getopts "?b:i:m:r:v:V" c $otherArgs
+ do
+ case $c
+ in
+ b)
+ # and now the obscure +ve integer checking bit
+ # ...note the creative use of unary - to prevent leading signs
+ maxbusy=$OPTARG
+ if [ "X-$maxbusy" != "X`expr 0 + -$maxbusy 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -b must have a positive integral argument"
+ #NOTREACHED
+ fi
+ ;;
+
+ i)
+ maxio=$OPTARG
+ if [ "X-$maxio" != "X`expr 0 + -$maxio 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -i must have a positive integral argument"
+ #NOTREACHED
+ fi
+ ;;
+
+ m)
+ max=$OPTARG
+ if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -m must have a positive integral argument"
+ #NOTREACHED
+ fi
+ maxreq=`expr $max / 20`
+ ;;
+
+ r)
+ maxreq=$OPTARG
+ if [ "X-$maxreq" != "X`expr 0 + -$maxreq 2>/dev/null`" ]
+ then
+ _pmview_error "$prog: -r must have a positive integral argument"
+ #NOTREACHED
+ fi
+ ;;
+
+ v)
+ if [ $OPTARG = "1" ]
+ then
+ _pmview_warning "$prog: pmview version 1 no longer supported, using version 2"
+ elif [ $OPTARG != "2" ]
+ then
+ _pmview_error "$prog: only version 2 supported for -v"
+ # NOTREACHED
+ fi
+ ;;
+
+ V)
+ verbose=true
+ ;;
+
+ '?')
+ _usage
+ exit 1
+ ;;
+ esac
+ done
+
+ set - $otherArgs
+ shift `expr $OPTIND - 1`
+ [ $# -gt 0 ] && argInterfaces="$*"
+fi
+
+# maximum average active for disks, percent -> msec/sec
+maxactive=`expr $maxbusy \* 1000 / 100`
+
+
+# maximum req error rate (default: 20% of packet rate)
+maxerr=`expr $maxreq / 5`
+[ "$maxerr" -eq 0 ] && maxerr=1
+
+
+# --- check that web metrics are available from metrics source ---
+#
+if _pmview_fetch web.allservers.errors
+then
+ :
+else
+ _pmview_error "$prog: weblog metrics not defined in the name space"
+ #NOTREACHED
+fi
+
+
+# --- if metrics source is an archive, and find out name of host ---
+#
+if [ "X$arch" != X ]
+then
+ host=`pmdumplog -l $arch | $PCP_AWK_PROG '/^Performance/ {print $5}' | sed -e 's/,//g'`
+ [ "X$host" = X ] && host="unknown host"
+ host="$host (Archive $arch)"
+fi
+
+
+# --- get network interfaces ---
+#
+pminfo -f $msource network.interface.total.bytes >$tmp.int
+sed -e 's/\]//' -e 's/"//g' $tmp.int \
+ | $PCP_AWK_PROG '$1 == "inst" {print $4}' > $tmp.list
+if [ ! -s $tmp.list ]
+then
+ if [ "X$arch" != X ]
+ then
+ _pmview_error "$prog: failed to get network interface list from archive \"$arch\""
+ #NOTREACHED
+ else
+ _pmview_error "$prog: failed to get network interface list from host \"$host\""
+ #NOTREACHED
+ fi
+fi
+
+
+# --- pmview config file has already been created; keep writing to it ---
+#
+
+cat << end-of-file >> $tmp.pmview
+#
+# $prog
+#
+end-of-file
+
+if $verbose
+then
+ echo "# Available Network Interfaces: " `cat $tmp.list` >> $tmp.pmview
+fi
+
+if [ -z "$argInterfaces" ]
+then
+ cp $tmp.list $tmp.chosen
+else
+ touch $tmp.chosen
+ for i in $argInterfaces
+ do
+ egrep $i $tmp.list >> $tmp.chosen
+ done
+fi
+
+interfaces_sp=`cat $tmp.chosen | sort | uniq`
+loflag=false
+for iface in $interfaces_sp
+do
+ if [ "X$iface" = "Xlo0" ]
+ then
+ loflag=true
+ else
+ interfaces="$interfaces $iface"
+ fi
+done
+$loflag && interfaces="$interfaces lo0"
+ninterfaces=`echo $interfaces | wc -w`
+
+if $verbose
+then
+ echo "# Network interfaces Matching \"$argInterfaces\": $interfaces" >> $tmp.pmview
+fi
+
+if [ $ninterfaces = 0 ]
+then
+ echo "$prog: no matching network interfaces"
+ echo "Available interfaces on host \"$host\" are: " `cat $tmp.list`
+ echo ""
+ _usage
+ exit 1
+fi
+
+net_grid1=`expr $ninterfaces + 2`
+
+# --- how many CPUs on this system? ---
+#
+numcpu=`pminfo $msource -f $namespace hinv.ncpu 2>&1 | $PCP_AWK_PROG '
+BEGIN { num = 0 }
+$1 == "value" { if (NF == 2) num = $2 }
+END { print num }'`
+
+if [ $numcpu -lt 1 ]
+then
+ _pmview_fetch_indom kernel.percpu.cpu.user && numcpu=$number
+ if [ $numcpu -lt 1 ]
+ then
+ _pmview_error "$prog: Unable to determine the number of CPUs on host $host"
+ #NOTREACHED
+ fi
+fi
+
+maxcpu=`expr $maxcpu \* $numcpu`
+
+if $verbose
+then
+ if [ $numcpu = 1 ]
+ then
+ echo "# 1 CPU detected" >> $tmp.pmview
+ echo "#" >> $tmp.pmview
+ else
+ echo "# $numcpu CPUs detected" >> $tmp.pmview
+ echo "#" >> $tmp.pmview
+ fi
+fi
+
+# --- how much memory on this system? ---
+#
+realmem=0
+if pminfo -v $msource $namespace hinv.physmem > /dev/null 2>&1
+then
+ realmem=`pminfo -f $msource $namespace hinv.physmem | $PCP_AWK_PROG '/value/ { print $2 }'`
+ if [ -z "$realmem" ]
+ then
+ realmem=0
+ else
+ realmem=`expr $realmem \* 1024`
+ fi
+fi
+[ $realmem = 0 ] && echo "$prog: Warning: Unable to determine size of real memory for $host"
+
+
+# --- how many disks on this system? ---
+#
+numdisk=`pminfo $msource -f $namespace hinv.ndisk 2>&1 | $PCP_AWK_PROG '
+BEGIN { num = 0 }
+$1 == "value" { if (NF == 2) num = $2 }
+END { print num }'`
+
+if [ $numdisk -lt 0 ]
+then
+ _pmview_fetch_indom disk.dev.read && numdisk=$number
+ [ $numdisk -lt 0 ] && _pmview_warning "$prog: Unable to determine the number of disks for $host"
+fi
+
+if $verbose
+then
+ if [ $numdisk = 1 ]
+ then
+ echo "# 1 disk detected" >> $tmp.pmview
+ echo "#" >> $tmp.pmview
+ else
+ echo "# $numdisk disks detected" >> $tmp.pmview
+ echo "#" >> $tmp.pmview
+ fi
+fi
+
+
+# --- set the window title ---
+#
+if [ -z "$titleArg" ]
+then
+ titleArg="SGI PCP : Web Server Activity for Host $host"
+fi
+
+
+# --- set base strings for base plane objects ---
+#
+if [ $numcpu = 1 ]
+then
+ basestr_cpu="CPU Utilization\nSummed over 1 CPU"
+else
+ basestr_cpu="CPU Utilization\nSummed over $numcpu CPUs"
+fi
+
+basestr_mem="Physical Memory Utilization\nNormalized to `pminfo -f $msource mem.physmem | grep value | sed -e 's/ *value //'` Kbytes"
+
+basestr_disk="Read and Write activity for all Disks\nNormalized to $maxio I/Os per second"
+basestr_diskact="Average Disk Utilization\nNormalized to $maxbusy% across $numdisk disks"
+
+basestr_net="Input and Output on Network Interfaces\nPackets are normalized to $max packets per second"
+
+basestr_amem="Memory metrics which may indicate a problem\nNormalized to $maxerr events per second"
+basestr_atcp="TCP metrics which may indicate a problem\nNormalized to $maxerr events per second"
+
+basestr_size="HTTP request rate by response size in bytes\nNormalized to $maxreq hits per second"
+basestr_type="HTTP request rate by HTTP method\nNormalized to $maxreq hits per second"
+
+
+# ---- the real config starts here ---
+# pmview Version 2.1
+#
+cat << end-of-file >> $tmp.pmview
+
+_stackLength 26
+_marginWidth 8
+_marginDepth 8
+
+_colorList cpu_colors ( blue2 red2 yellow2 cyan2 )
+_colorList disk_colors ( violet yellow )
+_colorList memory_colors (
+ rgbi:1.0/1.0/0.0
+ rgbi:0.0/1.0/1.0
+ rgbi:1.0/0.0/0.0
+ rgbi:1.0/0.0/1.0
+ rgbi:0.0/0.0/1.0
+ rgbi:0.0/1.0/0.0
+)
+_colorList network_colors (
+ rgbi:0.8/0.0/0.0
+ rgbi:1.0/0.5/0.0
+ rgbi:0.0/0.8/0.0
+)
+_colorList type_colors (
+ rgbi:0.8/0.0/0.0
+ rgbi:1.0/1.0/0.6
+ rgbi:1.0/0.0/1.0
+ rgbi:0.0/1.0/1.0
+ rgbi:1.0/1.0/0.0
+)
+
+_colorList size_colors (
+ rgbi:1.0/0.35/0.0
+ rgbi:0.6/0.0/0.9
+ rgbi:0.0/1.0/0.0
+ rgbi:1.0/0.5/0.0
+ rgbi:0.65/0.3/1.0
+ rgbi:0.3/1.0/0.3
+ rgbi:1.0/0.65/0.3
+ rgbi:0.8/0.6/1.0
+ rgbi:0.6/1.0/0.6
+ rgbi:1.0/0.8/0.6
+)
+
+_grid _hide (
+
+#
+# Alarms
+#
+ _grid 1 0 6 2 south _hide (
+ _bar 0 1 6 1 west _row _groupbyrow (
+ _metrics (
+end-of-file
+
+for m in drops conndrops timeoutdrop rcvbadsum rexmttime sndrexmitpack attemptfails inerrs retranssegs
+do
+ if _pmview_fetch network.tcp.$m
+ then
+ echo " network.tcp.$m $maxerr" >> $tmp.pmview
+ fi
+done
+
+cat << end-of-file >> $tmp.pmview
+ )
+ _colorList (
+ red1 red1 red1 red1 red1 red1
+ )
+ _baseLabel "$basestr_atcp"
+ )
+ _bar 0 0 3 1 west _row _groupbyrow (
+ _metrics (
+end-of-file
+
+for m in swap.pagesout network.mbuf.failed network.mbuf.waited
+do
+ if _pmview_fetch $m
+ then
+ echo " $m $maxerr" >> $tmp.pmview
+ fi
+done
+
+cat << end-of-file >> $tmp.pmview
+ )
+ _colorList (
+ yellow rgbi:1.0/0.5/0.0 rgbi:1.0/0.5/0.0
+ )
+ _baseLabel "$basestr_amem"
+ )
+ _label 3 0 west _right _medium "Alarms"
+ )
+
+#
+# Size
+#
+ _bar 0 1 1 10 south _groupbycol (
+ _metrics (
+ web.allservers.requests.size.unknown $maxreq
+ web.allservers.requests.size.gt3m $maxreq
+ web.allservers.requests.size.le3m $maxreq
+ web.allservers.requests.size.le1m $maxreq
+ web.allservers.requests.size.le300k $maxreq
+ web.allservers.requests.size.le100k $maxreq
+ web.allservers.requests.size.le30k $maxreq
+ web.allservers.requests.size.le10k $maxreq
+ web.allservers.requests.size.le3k $maxreq
+ web.allservers.requests.size.zero $maxreq
+ )
+ _metriclabels _towards (
+ "?" ">3M" "3M" "1M" "300k"
+ "100k" "30k" "10k" "3k" "0k"
+ )
+ _colorList size_colors
+ _baseLabel "$basestr_size"
+ )
+
+ _label 0 11 northeast _right _medium "Size"
+
+#
+# Type
+#
+ _bar 1 6 1 5 south _groupbycol (
+ _metrics (
+ web.allservers.errors $maxerr
+ web.allservers.requests.other $maxreq
+ web.allservers.requests.post $maxreq
+ web.allservers.requests.head $maxreq
+ web.allservers.requests.get $maxreq
+ )
+ _colorList type_colors
+ _baseLabel "$basestr_type"
+ )
+
+ _label 1 11 north _right _medium "Type"
+
+#
+# System level stuff
+#
+ _grid 1 3 5 3 southwest (
+ _stack 0 0 (
+ _metrics (
+ kernel.all.cpu.user $maxcpu
+ kernel.all.cpu.sys $maxcpu
+ kernel.all.cpu.intr $maxcpu
+ kernel.all.cpu.wait.total $maxcpu
+ )
+ _colorList cpu_colors
+ _baseLabel "$basestr_cpu"
+ )
+ _label 0 1 north _right _medium "CPU"
+
+# 2 levels of base plane, halve the margin size and increase the height
+# for the inner one
+#
+_marginWidth 4
+_marginDepth 4
+_baseHeight 4
+
+ _grid 1 0 2 1 _show (
+ _baseColor rgbi:0.30/0.30/0.30
+ _stack 0 0 south _cylinder (
+ _metrics (
+ disk.all.write $maxio
+ disk.all.read $maxio
+ )
+ _colorList disk_colors
+ _baseLabel "$basestr_disk"
+ )
+end-of-file
+
+ # disk.all.avg_disk.active metric is not available from pcp 1.x
+ #
+ if _pmview_fetch disk.all.avg_disk.active
+ then
+ cat << end-of-file >> $tmp.pmview
+ _bar 1 0 _cylinder (
+ _metrics (
+ disk.all.avg_disk.active $maxactive
+ )
+ _colorList ( green2 )
+ _baseLabel "$basestr_diskact"
+ )
+end-of-file
+ fi
+
+ cat << end-of-file >> $tmp.pmview
+ _baseColor rgbi:0.15/0.15/0.15
+ )
+ _label 1 1 2 1 north _medium "Disk"
+
+end-of-file
+
+ if [ "X$realmem" != X0 -a "X$realmem" != X ]
+ then
+ xcoord=0
+
+ cat << end-of-file >> $tmp.pmview
+ _grid 3 0 2 1 _show (
+ _baseColor rgbi:0.30/0.30/0.30
+end-of-file
+
+ if _pmview_fetch mem.freemem
+ then
+ cat << end-of-file >> $tmp.pmview
+ _stack $xcoord 0 (
+ _metrics (
+ mem.freemem $realmem
+ )
+ _colorList ( rgbi:0.0/0.8/0.0 )
+ _baseLabel "Free memory"
+ )
+end-of-file
+ xcoord=`expr $xcoord + 1`
+ fi
+
+ if _pmview_fetch mem.util.kernel
+ then
+ cat << end-of-file >> $tmp.pmview
+
+ _stack $xcoord 0 (
+ _metrics (
+end-of-file
+ # Use all the metrics we have
+ for m in kernel fs_ctl fs_dirty fs_clean user ; do
+ if _pmview_fetch mem.util.$m
+ then
+ echo " mem.util.$m $realmem" >> $tmp.pmview
+ fi
+ done
+
+ cat << end-of-file >> $tmp.pmview
+ )
+ _colorList memory_colors
+ _baseLabel "$basestr_mem"
+ )
+end-of-file
+ xcoord=`expr $xcoord + 1`
+ fi
+
+ cat << end-of-file >> $tmp.pmview
+ _baseColor rgbi:0.15/0.15/0.15
+ )
+ _label 3 1 2 1 north _medium "Mem"
+end-of-file
+ fi
+
+ cat << end-of-file >> $tmp.pmview
+
+# restore defaults
+#
+ _marginWidth 8
+ _marginDepth 8
+ _baseHeight 2
+ )
+
+#
+# Network Stuff
+#
+ _grid 2 6 $net_grid1 5 south _hide (
+ _grid 0 0 1 2 west _hide (
+ _label 0 0 east _right _medium "In"
+ _label 0 1 east _right _medium "Out"
+ )
+# 2 levels of base plane, halve the margin size and increase the height
+# for the inner one
+#
+_marginWidth 4
+_marginDepth 4
+_baseHeight 4
+
+ _grid 1 0 $ninterfaces 2 _show (
+ _baseColor rgbi:0.30/0.30/0.30
+
+end-of-file
+
+ xcoord=0
+ yin=0
+ yout=1
+ for iface in $interfaces
+ do
+ cat << end-of-file >> $tmp.pmview
+
+ _stack $xcoord $yin (
+ _metrics (
+ network.interface.in.errors[$iface] $maxerr
+ network.interface.in.drops[$iface] $maxerr
+ network.interface.in.packets[$iface] $max
+ )
+ _colorList network_colors
+ _baseLabel "$basestr_net"
+ )
+ _stack $xcoord $yout (
+ _metrics (
+ network.interface.out.errors[$iface] $maxerr
+ network.interface.out.drops[$iface] $maxerr
+ network.interface.out.packets[$iface] $max
+ )
+ _colorList network_colors
+ _baseLabel "$basestr_net"
+ )
+end-of-file
+ xcoord=`expr $xcoord + 1`
+ done
+
+ cat << end-of-file >> $tmp.pmview
+ _baseLabel "$basestr_net"
+_baseColor rgbi:0.15/0.15/0.15
+ )
+# restore defaults
+#
+_marginWidth 8
+_marginDepth 8
+_baseHeight 2
+ _grid 1 2 $ninterfaces 2 _hide (
+end-of-file
+
+ xcoord=0
+ ylabel=0
+ for iface in $interfaces
+ do
+ cat << end-of-file >> $tmp.pmview
+ _label $xcoord $ylabel north _down _medium "$iface"
+end-of-file
+ xcoord=`expr $xcoord + 1`
+ done
+
+ cat << end-of-file >> $tmp.pmview
+ )
+ )
+ _label 3 11 northwest _right _medium "Network"
+)
+end-of-file
+
+$verbose && cat $tmp.pmview
+
+eval $PMVIEW <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'"
+
+exit
+
diff --git a/src/pmview/front-ends/webvis.rgb b/src/pmview/front-ends/webvis.rgb
new file mode 100644
index 0000000..5bd1482
--- /dev/null
+++ b/src/pmview/front-ends/webvis.rgb
Binary files differ
diff --git a/src/pmview/gram.y b/src/pmview/gram.y
new file mode 100644
index 0000000..5859f94
--- /dev/null
+++ b/src/pmview/gram.y
@@ -0,0 +1,1391 @@
+/*
+ * Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved.
+ * 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/QStack>
+
+#include "main.h"
+#include "gridobj.h"
+#include "stackobj.h"
+#include "barobj.h"
+#include "labelobj.h"
+#include "pipeobj.h"
+#include "scenefileobj.h"
+#include "link.h"
+#include "xing.h"
+
+extern void yywarn(const char *s);
+extern void yyerror(const char *s);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int yylex(void);
+#ifdef __cplusplus
+}
+#endif
+
+static DefaultObj dobj;
+static QStack<ViewObj *> objstack;
+
+ViewObj * rootObj = 0;
+
+bool theColorScaleFlag;
+int theCol;
+int theRow;
+int theNumCols;
+int theNumRows;
+int theHistory = 0;
+ViewObj::Alignment theAlignment;
+int theColorListCount = 0;
+
+%}
+
+%union {
+ char *y_str;
+ int y_int;
+ double y_real;
+ bool y_bool;
+ ViewObj::Alignment y_align;
+ ViewObj::Shape y_shape;
+ Text::Direction y_textDir;
+ Text::FontSize y_fontSize;
+ BarMod::Direction y_instDir;
+ BarObj::LabelDir y_labelDir;
+ BarMod::Modulation y_barMod;
+ StackMod::Height y_stackMod;
+ BarMod::Grouping y_barGroup;
+ ViewObj * y_object;
+}
+
+%token <y_str>
+ NAME STRING PMVIEW METRIC
+
+%token <y_int>
+ INT
+
+%token <y_real>
+ REAL
+
+%token <y_bool>
+ BOOL
+
+%token <y_align>
+ ALIGN
+
+%token <y_textDir>
+ DIRVAL
+
+%token <y_fontSize>
+ SIZ
+
+%token <y_instDir>
+ INST_DIR
+
+%token <y_barMod>
+ BAR_TYPE
+
+%token <y_shape>
+ SHAPE
+
+%token <y_stackMod>
+ STACK_TYPE
+
+%token <y_labelDir>
+ LABEL_DIR
+
+%token <y_barGroup>
+ GROUP
+
+%token SCALE BAR_HEIGHT BAR_LENGTH MARGIN_WIDTH MARGIN_DEPTH BASE_HEIGHT
+ BASE_COLOR BASE_LABEL GRID_WIDTH GRID_DEPTH GAP_LABEL GRID_SPACE
+ GAP_WIDTH GAP_DEPTH COLORLIST OPENB CLOSEB COLORSCALE GRID SHOW HIDE
+ LABEL LABEL_MARGIN LABEL_COLOR DIRECTION SIZE TEXT BAR METRICLIST
+ METRICLABEL INSTLABEL STACK STACK_LABEL UTIL AWAY TOWARDS
+ BOX SOCKET PIPE PIPE_LENGTH PIPETAG GR_LINK GR_XING HISTORY SCENE_FILE
+
+%type <y_real>
+ real
+
+%type <y_bool>
+ show_or_hide
+ hide_or_show
+
+%type <y_textDir>
+ direction_cmd
+
+%type <y_fontSize>
+ size_cmd
+
+%type <y_instDir>
+ col_or_row
+
+%type <y_barMod>
+ bar_type
+
+%type <y_shape>
+ shape_type
+
+%type <y_stackMod>
+ stack_type
+
+%type <y_labelDir>
+ away_or_towards
+
+%type <y_barGroup>
+ bar_group
+
+%type <y_object>
+ scene object grid bar stack label pipe link xing scenefile
+
+%type <y_str>
+ symname nameval colordecl linktag metricname
+%%
+
+config : header scene;
+
+header : pmview arglist
+ | pmview
+ ;
+
+pmview : PMVIEW
+ {
+ if (strcmp($1, "1.2") < 0) {
+ pmprintf("Version %s is no longer supported\n",
+ $1);
+ pmflush();
+ exit(1);
+ }
+ }
+ ;
+
+arglist : arg
+ | arglist arg
+ ;
+
+arg : STRING
+ {
+ extern char **frontend_argv;
+ extern int frontend_argc;
+
+ frontend_argv = (char **)realloc(frontend_argv,
+ (frontend_argc+1)*sizeof(char *));
+ if (frontend_argv == NULL) {
+ frontend_argc = 0;
+ } else {
+ frontend_argv[frontend_argc] =$1;
+ if (frontend_argv[frontend_argc] == NULL) {
+ frontend_argc = 0;
+ } else {
+ frontend_argc++;
+ }
+ }
+ }
+ ;
+
+scene : object { rootObj = $1; }
+ | sceneattrlist object { rootObj = $2; }
+ ;
+
+object : grid
+ | label
+ | bar
+ | pipe
+ | link
+ | xing
+ | stack
+ | scenefile
+ ;
+
+sceneattrlist : sceneattr
+ | sceneattrlist sceneattr
+ ;
+
+sceneattr : scale
+ | named_color_list
+ | named_color_scale
+ | most_opts
+ ;
+
+most_opts : mod_opts
+ | base_opts
+ | grid_opts
+ | bar_opts
+ | label_opts
+ | pipe_opts
+ ;
+
+scale : SCALE REAL
+ {
+ if ($2 <= 0.0)
+ yyerror("_scale requires a positive real number");
+ else
+ theGlobalScale = $2;
+ }
+ ;
+
+pipe_opts : PIPE_LENGTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_pipeLength requires a positive integer");
+ else if ( objstack.empty () )
+ dobj.pipeLength() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->pipeLength() = $2;
+ }
+ else
+ yyerror ("cannot change pipe length - not a grid");
+ }
+ ;
+
+mod_opts : BAR_HEIGHT INT
+ {
+ if ($2 <= 0)
+ yyerror("_barHeight requires a positive integer");
+ else if ( objstack.empty () )
+ dobj.barHeight() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->barHeight() = $2;
+ }
+ else
+ yyerror ("cannot change bar height - not a grid");
+ }
+ | BAR_LENGTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_barLength requires a positive integer");
+ else if ( objstack.empty () )
+ dobj.barLength() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->barLength() = $2;
+ }
+ else
+ yyerror ("cannot change bar length - not a grid");
+ }
+ ;
+
+base_opts : MARGIN_WIDTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_marginWidth requires a positive integer");
+ else if ( objstack.empty () )
+ dobj.baseBorderX() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->baseBorderX() = $2;
+ }
+ else
+ yyerror("cannot change width margin - not a grid");
+ }
+ | MARGIN_DEPTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_marginDepth requires a positive integer");
+ else if ( objstack.empty () )
+ dobj.baseBorderZ() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->baseBorderZ() = $2;
+ }
+ else
+ yyerror ("cannot change depth margin - not a grid");
+ }
+ | BASE_HEIGHT INT
+ {
+ if ($2 <= 0)
+ yyerror("_baseHeight requires a positive integer");
+ else if ( objstack.empty () )
+ dobj.baseHeight() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->baseHeight() = $2;
+ }
+ else
+ yyerror ("cannot change base height - not a grid");
+ }
+ | BASE_COLOR symname
+ {
+ float r, g, b;
+
+ if (ColorList::findColor($2, r, g, b) == true ) {
+ if ( objstack.empty () )
+ dobj.baseColor (r,g,b);
+ else if(objstack.top()->objbits()&ViewObj::GRIDOBJ){
+ GridObj * go =
+ static_cast<GridObj*>(objstack.top());
+
+ go->defs()->baseColor(r, g, b);
+ }
+ else
+ yyerror ("Cannot change base color - not a grid");
+
+ } else {
+ sprintf(theBuffer,
+ "unable to map _baseColor color \"%s\"",
+ $2);
+ yyerror(theBuffer);
+ }
+ }
+ | BASE_COLOR REAL REAL REAL
+ {
+ if ( $2 < 0.0 || $2 > 1.0 ||
+ $3 < 0.0 || $3 > 1.0 ||
+ $4 < 0.0 || $4 > 1.0) {
+ sprintf(theBuffer,
+ "_baseColor colors %f,%f,%f must be "
+ "between 0.0 and 1.0",
+ $2, $3, $4);
+ yyerror(theBuffer);
+ } else if ( objstack.empty () ) {
+ dobj.baseColor($2, $3, $4);
+ } else if(objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->baseColor($2, $3, $4);
+ } else {
+ yyerror("Cannot change base color - not a grid");
+ }
+ }
+ ;
+
+grid_opts : GRID_WIDTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_gridWidth requires a positive integer");
+ else if ( objstack.empty() )
+ dobj.gridMinWidth() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->gridMinWidth() = $2;
+ }
+ else
+ yyerror("Cannot change min width - not a grid");
+ }
+ | GRID_DEPTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_gridDepth requires a positive integer");
+ else if ( objstack.empty() )
+ dobj.gridMinDepth() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->gridMinDepth() = $2;
+ }
+ else
+ yyerror("Cannot change min depth - not a grid");
+ }
+ | GRID_SPACE INT
+ {
+ if ($2 <= 0) {
+ yyerror("_gridSpace requires a positive integer");
+ } else if ( objstack.empty() ) {
+ dobj.gridMinWidth() = $2;
+ dobj.gridMinDepth() = $2;
+ } else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->gridMinWidth() = $2;
+ go->defs()->gridMinDepth() = $2;
+ } else {
+ yyerror("Cannot change grid size - not a grid");
+ }
+ }
+ ;
+
+bar_opts : GAP_WIDTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_gapWidth requires a positive integer");
+ else if ( objstack.empty() )
+ dobj.barSpaceX() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->barSpaceX() = $2;
+ }
+ else
+ yyerror ("Cannot change bar width - not a grid");
+ }
+ | GAP_DEPTH INT
+ {
+ if ($2 <= 0)
+ yyerror("_gapDepth requires a positive integer");
+ else if ( objstack.empty() )
+ dobj.barSpaceZ() = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->barSpaceZ() = $2;
+ }
+ else
+ yyerror ("Cannot change bar depth - not a grid");
+ }
+ | GAP_LABEL INT
+ {
+ if ($2 <= 0)
+ yyerror("_gapLabel requires a positive integer");
+ else if ( objstack.empty() )
+ dobj.barSpaceLabel () = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->barSpaceLabel() = $2;
+ }
+ else
+ yyerror ("Cannot change label space - not a grid");
+ }
+ ;
+
+label_opts : LABEL_MARGIN INT
+ {
+ if ($2 <= 0)
+ yyerror("_labelMargin requires a positive integer");
+ else if ( objstack.empty() )
+ dobj.labelMargin () = $2;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj*>(objstack.top());
+ go->defs()->labelMargin() = $2;
+ }
+ else
+ yyerror ("Cannot change label margin - not a grid");
+ }
+ | LABEL_COLOR symname
+ {
+ float r, g, b;
+
+ if (ColorList::findColor($2, r, g, b) == true) {
+ if ( objstack.empty() )
+ dobj.labelColor(r, g, b);
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * go =
+ static_cast<GridObj*>(objstack.top());
+ go->defs()->labelColor(r, g, b);
+ }
+ else
+ yyerror ("Cannot change label color - not a grid");
+ } else {
+ sprintf(theBuffer, "unable to map color \"%s\"", $2);
+ yyerror(theBuffer);
+ }
+ }
+ | LABEL_COLOR REAL REAL REAL
+ {
+ if ($2 < 0.0 || $2 > 1.0 || $3 < 0.0 || $3 > 1.0 ||
+ $4 < 0.0 || $4 > 1.0) {
+ sprintf(theBuffer, "unable to map color %f,%f,%f",
+ $2, $3, $4);
+ yyerror(theBuffer);
+ } else {
+ if ( objstack.empty () )
+ dobj.labelColor ($2, $3, $4);
+ else if(objstack.top()->objbits()&ViewObj::GRIDOBJ){
+ GridObj * go =
+ static_cast<GridObj*>(objstack.top());
+ go->defs()->labelColor($2, $3, $4);
+ }
+ else
+ yyerror ("Cannot change label color - not a grid");
+ }
+ }
+ ;
+
+symname : NAME | STRING;
+
+named_color_list: COLORLIST NAME OPENB
+ {
+ if (theColorLists.add($2) == false) {
+ sprintf(theBuffer,
+ "Color list \"%s\" is already defined", $2);
+ yywarn(theBuffer);
+ }
+ } colors CLOSEB
+ ;
+
+colors : color
+ | colors color
+ ;
+
+color : symname
+ {
+ if (theColorLists.addColor($1) == false) {
+ sprintf(theBuffer, "Unable to map color \"%s\"", $1);
+ yywarn(theBuffer);
+ }
+ }
+ | REAL REAL REAL
+ {
+ if (theColorLists.addColor($1, $2, $3) == false) {
+ sprintf(theBuffer,
+ "Unable to map color %f,%f,%f, "
+ "values may be out of range",
+ $1, $2, $3);
+ yywarn(theBuffer);
+ }
+ }
+ ;
+
+named_color_scale: COLORSCALE NAME symname OPENB
+ {
+ if (theColorLists.list($2) == NULL) {
+ if (theColorLists.add($2, $3) == false) {
+ sprintf(theBuffer,
+ "Unable to map color \"%s\", "
+ "defaulting to blue",
+ $3);
+ }
+ theColorScaleFlag = true;
+ } else {
+ sprintf(theBuffer,
+ "Color scale \"%s\" is already defined",
+ $2);
+ yywarn(theBuffer);
+ theColorScaleFlag = false;
+ }
+ } scaled_color_list CLOSEB
+ | COLORSCALE NAME REAL REAL REAL OPENB
+ {
+ if (theColorLists.list($2) == NULL) {
+ if (theColorLists.add($2, $3, $4, $5) == false) {
+ sprintf(theBuffer,
+ "Unable to map color %f,%f,%f, "
+ "defaulting to blue",
+ $3, $4, $5);
+ }
+ theColorScaleFlag = true;
+ } else {
+ sprintf(theBuffer,
+ "Color scale \"%s\" is already defined", $2);
+ yywarn(theBuffer);
+ theColorScaleFlag = false;
+ }
+ } scaled_color_list CLOSEB
+ ;
+
+scaled_color_list : scaled_color
+ | scaled_color_list scaled_color
+ ;
+
+scaled_color : symname REAL
+ {
+ if (theColorLists.addColor($1, $2) == false) {
+ sprintf(theBuffer, "Unable to map color \"%s\"", $1);
+ yywarn(theBuffer);
+ }
+ }
+ | REAL REAL REAL REAL
+ {
+ if (theColorLists.addColor($1, $2, $3, $4) == false) {
+ sprintf(theBuffer,
+ "Unable to map color %f,%f,%f, "
+ "values may be out of range",
+ $1, $2, $3);
+ yywarn(theBuffer);
+ }
+ }
+ ;
+
+pos : grid_pos {
+ theNumCols = 1;
+ theNumRows = 1;
+ theAlignment = ViewObj::center;
+ }
+ | grid_pos grid_size {
+ theAlignment = ViewObj::center;
+ }
+ | grid_pos alignment {
+ theNumCols = 1;
+ theNumRows = 1;
+ }
+ | grid_pos grid_size alignment
+ | /* Empty position */ {
+ theCol = 0;
+ theRow = 0;
+ theNumCols = 1;
+ theNumRows = 1;
+ theAlignment = ViewObj::center;
+ }
+ ;
+
+grid_pos : INT INT
+ {
+ if ($1 < 0) {
+ sprintf(theBuffer,
+ "Column index must be positive, was %d",
+ $1);
+ yyerror(theBuffer);
+ theCol = 0;
+ } else
+ theCol = $1;
+
+ if ($2 < 0) {
+ sprintf(theBuffer,
+ "Row index must be positive, was %d",
+ $2);
+ yyerror(theBuffer);
+ theRow = 0;
+ } else
+ theRow = $2;
+ }
+ ;
+
+grid_size : INT INT
+ {
+ if ($1 < 0) {
+ sprintf(theBuffer,
+ "Number of columns must be positive, was %d",
+ $1);
+ yyerror(theBuffer);
+ theNumCols = 1;
+ } else
+ theNumCols = $1;
+ if ($2 < 0) {
+ sprintf(theBuffer,
+ "Number of rows must be positive, was %d",
+ $2);
+ yyerror(theBuffer);
+ theNumRows = 1;
+ } else
+ theNumRows = $2;
+ }
+ ;
+
+alignment : ALIGN { theAlignment = $1; };
+
+baselabelspec : BASE_LABEL symname
+ {
+ if ( objstack.empty () ) {
+ yyerror ("Syntax error - no object to label");
+ } else if(objstack.top()->objbits() & ViewObj::BASEOBJ){
+ BaseObj * bo = static_cast<BaseObj *>(objstack.top());
+ int i;
+ QString str = $2;
+
+ for (i = 0; i < str.size(); i++) {
+ if (str[i] == '\n')
+ break;
+ if (str[i] == '\\' &&
+ i + 1 < str.size() &&
+ str[i + 1] == 'n') {
+ str[i] = '\n';
+ str.remove(i+1, 1);
+ break;
+ }
+ }
+
+ if (i == str.length())
+ str.append(QChar('\n'));
+
+ bo->label() = str;
+ } else {
+ yyerror ("Syntax error - wrong object");
+ }
+ }
+ ;
+
+scenefile : scenefile_decl
+ {
+ if ( ($$ = objstack.top()) ) {
+ $$->finishedAdd();
+ }
+ objstack.pop();
+ }
+ ;
+
+scenefile_decl : SCENE_FILE pos STRING
+ {
+ const DefaultObj * dob = 0;
+
+ if ( objstack.empty() )
+ dob = & dobj;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * parent =
+ static_cast<GridObj *>(objstack.top());
+ dob = parent->defs();
+ }
+
+ if (dob) {
+ if ( SceneFileObj * so = new SceneFileObj (*dob,
+ theCol, theRow,
+ theNumCols,
+ theNumRows,
+ theAlignment) ) {
+ so->setSceneFileName($3);
+ objstack.push (so);
+ }
+ else
+ yyerror (
+ "Cannot create a scene file object - out of memory");
+ }
+ else
+ yyerror (
+ "Syntax error - Scene File inside simple object!");
+ }
+ ;
+
+pipe : pipedecl OPENB pipespec CLOSEB
+ {
+ if ( ($$ = objstack.top()) ) {
+ $$->finishedAdd();
+ }
+ objstack.pop();
+ }
+ ;
+
+pipedecl : PIPE pos
+ {
+ if ( theNumRows > 1 && theNumCols > 1 ) {
+ yyerror ("Diagonal pipes are not supported");
+ objstack.push (0); // So that we would pop grid up
+ } else {
+ const DefaultObj * dob = 0;
+
+ if ( objstack.empty() )
+ dob = & dobj;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * parent =
+ static_cast<GridObj *>(objstack.top());
+ dob = parent->defs();
+ }
+
+ if ( dob )
+ if ( PipeObj * po = new PipeObj (*dob,
+ theCol, theRow,
+ theNumCols,
+ theNumRows,
+ theAlignment) )
+ objstack.push (po);
+ else
+ yyerror (
+ "Cannot create a pipe - out of memory");
+ else
+ yyerror (
+ "Syntax error - Pipe inside simple object");
+ }
+ }
+ ;
+
+pipespec : pipeattr
+ | pipespec pipeattr
+ ;
+
+pipeattr : metric_list
+ | named_color
+ | color_list
+ | pipetag
+ ;
+
+pipetag : PIPETAG symname
+ {
+ if (objstack.empty () ||
+ ((objstack.top()->objbits() & ViewObj::PIPEOBJ) == 0)) {
+ yyerror ("No pipe to attach tag to");
+ } else {
+ PipeObj * p = static_cast<PipeObj*>(objstack.top());
+ p->setTag($2);
+ }
+ }
+ ;
+
+link : GR_LINK pos linktag
+ {
+ const DefaultObj * dob = 0;
+
+ if ( objstack.empty() )
+ dob = & dobj;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * parent =
+ static_cast<GridObj *>(objstack.top());
+ dob = parent->defs();
+ }
+
+ if ( dob )
+ if ( Link * l = new Link (*dob, theCol, theRow,
+ theNumCols, theNumRows,
+ theAlignment) ) {
+ if ( $3 != NULL ) {
+ l->setTag ($3);
+ free ($3);
+ }
+
+ l->finishedAdd ();
+ $$ = l;
+ } else {
+ yyerror ("Cannot create a link - out of memory");
+ }
+ else
+ yyerror ("Syntax error - link inside simple object");
+ }
+ ;
+
+linktag : symname { $$ = strdup ($1); }
+ | /* nothing */ { $$ = NULL; }
+ ;
+
+grid_object : object
+ {
+ if ( $1 ) {
+ if ( (! objstack.empty()) &&
+ (objstack.top()->objbits() & ViewObj::GRIDOBJ) ) {
+ GridObj * go =
+ static_cast<GridObj *>(objstack.top());
+ go->addObj ($1 , $1->col(), $1->row());
+ } else {
+ yyerror ("Syntax error - no gird to add to");
+ }
+ }
+ }
+ | most_opts
+ | baselabelspec
+ ;
+
+grid_object_list : grid_object
+ | grid_object_list grid_object
+ ;
+
+grid : griddecl grid_object_list CLOSEB
+ {
+ $$ = objstack.top();
+ $$->finishedAdd();
+ objstack.pop();
+ }
+ ;
+
+griddecl : GRID pos hide_or_show OPENB
+ {
+ const DefaultObj * dob = 0;
+
+ if ( objstack.empty() )
+ dob = & dobj;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * parent =
+ static_cast<GridObj *>(objstack.top());
+ dob = parent->defs();
+ }
+
+ if ( dob )
+ if (GridObj * go = new GridObj($3, *dob,
+ theCol, theRow,
+ theNumCols, theNumRows,
+ theAlignment)) {
+ objstack.push (go);
+ } else {
+ yyerror ("Cannot create new grid - out of memory");
+ }
+ else
+ yyerror ("Syntax error - grid inside a simple object");
+ }
+ ;
+
+hide_or_show : BOOL { $$ = $1; }
+ | { $$ = false; }
+ ;
+
+label : labeldecl OPENB label_stuff CLOSEB
+ {
+ $$ = objstack.top();
+ $$->finishedAdd();
+ objstack.pop();
+ }
+ | labeldecl direction_cmd size_cmd STRING
+ {
+ if ( ($$ = objstack.top()) ) {
+ if ( $$->objbits() & ViewObj::LABELOBJ ) {
+ LabelObj * lo = static_cast<LabelObj*>($$);
+ lo->dir() = $2;
+ lo->size() = $3;
+ lo->str() = $4;
+ lo->finishedAdd ();
+ }
+ }
+ objstack.pop();
+ }
+ ;
+
+labeldecl : LABEL pos
+ {
+ const DefaultObj * dob = 0;
+
+ if ( objstack.empty() )
+ dob = & dobj;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * parent =
+ static_cast<GridObj *>(objstack.top());
+ dob = parent->defs();
+ }
+ else
+ yyerror ("Syntax error - label inside simple object");
+
+
+ if ( dob ) {
+ if (LabelObj * lo = new LabelObj(*dob,
+ theCol, theRow,
+ theNumCols,
+ theNumRows,
+ theAlignment))
+ objstack.push (lo);
+ else {
+ yyerror ("Cannot create label - out of memory");
+ objstack.push (NULL);
+ }
+ }
+ }
+ ;
+
+
+direction_cmd : DIRVAL { $$ = $1; }
+ | { $$ = Text::right; }
+ ;
+
+size_cmd : SIZ { $$ = $1; }
+ | { $$ = Text::medium; }
+ ;
+
+label_stuff : label_item
+ | label_stuff label_item
+ ;
+
+label_item : DIRECTION DIRVAL
+ {
+ if ( objstack.empty () )
+ yyerror ("cannot change direction - no label");
+ else if (objstack.top()->objbits() & ViewObj::LABELOBJ) {
+ LabelObj * lo =
+ static_cast<LabelObj*>(objstack.top());
+ lo->dir() = $2;
+ }
+ else
+ yyerror ("Syntax error - not a label");
+ }
+ | SIZE SIZ
+ {
+ if ( objstack.empty () )
+ yyerror ("cannot set label size");
+ else if (objstack.top()->objbits() & ViewObj::LABELOBJ) {
+ LabelObj * lo =
+ static_cast<LabelObj*>(objstack.top());
+ lo->size() = $2;
+ }
+ else
+ yyerror ("Syntax error - not a label");
+ }
+ | TEXT symname
+ {
+ if ( objstack.empty () )
+ yyerror ("cannot set label text");
+ else if (objstack.top()->objbits() & ViewObj::LABELOBJ) {
+ LabelObj * lo =
+ static_cast<LabelObj*>(objstack.top());
+ lo->str() = $2;
+ }
+ else
+ yyerror ("Syntax error - not a label");
+ }
+ ;
+
+bar : bardecl bar_stuff CLOSEB
+ {
+ $$ = objstack.top();
+ $$->finishedAdd();
+ objstack.pop();
+ }
+ ;
+
+history : HISTORY INT
+ {
+ theHistory = $2;
+ }
+ |
+ ;
+
+bardecl : BAR pos col_or_row show_or_hide bar_type shape_type bar_group history OPENB
+ {
+ BarObj * bo = 0;
+
+ if ( objstack.empty () )
+ bo = new BarObj($6, $3, $5, $7, $4, dobj,
+ theCol, theRow,
+ theNumCols, theNumRows, theAlignment);
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ){
+ GridObj * go =
+ static_cast<GridObj *>(objstack.top());
+ bo = new BarObj($6, $3, $5, $7, $4, *go->defs(),
+ theCol, theRow,
+ theNumCols, theNumRows, theAlignment);
+ }
+ else
+ yyerror ("Syntax error - bar inside simple object");
+
+ if ( bo ) {
+ bo->setHistory(theHistory);
+ objstack.push (bo);
+ }
+ }
+ ;
+
+show_or_hide : BOOL { $$ = $1; }
+ | { $$ = true; }
+ ;
+
+col_or_row : INST_DIR { $$ = $1; }
+ | { $$ = BarMod::instPerCol; }
+ ;
+
+bar_type : BAR_TYPE { $$ = $1; }
+ | { $$ = BarMod::yScale; }
+ ;
+shape_type : SHAPE { $$ = $1 ; }
+ | { $$ = ViewObj::cube; }
+ ;
+
+bar_group : GROUP { $$ = $1; }
+ | { $$ = BarMod::groupByMetric; }
+ ;
+
+bar_stuff : bar_item
+ | bar_stuff bar_item
+ ;
+
+bar_item : labelled_metric_list
+ | named_color
+ | color_list
+ | metric_labels
+ | inst_labels
+ | baselabelspec
+ ;
+
+labelled_metric_list: METRICLIST OPENB labelled_metrics CLOSEB;
+
+labelled_metrics: labelled_metric
+ | labelled_metrics labelled_metric
+ ;
+
+metricname : METRIC | NAME ;
+
+labelled_metric : metric
+ | metricname real STRING
+ {
+ if ( objstack.empty() )
+ yyerror ("No object to add metrics to");
+ else if (objstack.top()->objbits() & ViewObj::BAROBJ) {
+ BarObj * bo =
+ static_cast<BarObj *>(objstack.top());
+ bo->addMetric($1, $2, $3);
+ } else {
+ yyerror ("Syntax error - not a bar object");
+ }
+ }
+ ;
+
+real : REAL { $$ = $1; }
+ | INT { $$ = (double)$1; }
+ ;
+
+colordecl : COLORLIST NAME { $$ = $2; }
+ | COLORSCALE NAME { $$ = $2; }
+ ;
+
+named_color : colordecl
+ {
+ if ( objstack.empty() )
+ yyerror ("No object to add colors to");
+ else if (objstack.top()->objbits() & ViewObj::MODOBJ) {
+ ModObj * mo =
+ static_cast<ModObj *>(objstack.top());
+ mo->setColorList ($1);
+ } else {
+ sprintf (theBuffer,
+ "Syntax error - %s cannot have colors",
+ objstack.top()->name());
+ yyerror (theBuffer);
+ }
+ }
+ ;
+
+color_list : COLORLIST OPENB
+ {
+ if ( objstack.empty() )
+ yyerror ("No object to add colors to");
+ else if (objstack.top()->objbits() & ViewObj::MODOBJ) {
+ ModObj * mo = static_cast<ModObj *>(objstack.top());
+ sprintf(theBuffer, "@tmp%d", theColorListCount++);
+ theColorLists.add(theBuffer);
+ mo->setColorList (theBuffer);
+ } else {
+ sprintf (theBuffer,
+ "Syntax error - %s cannot have colors",
+ objstack.top()->name());
+ yyerror (theBuffer);
+ }
+ } colors CLOSEB
+ | COLORSCALE symname OPENB
+ {
+ if ( objstack.empty() )
+ yyerror ("No object to add colors to");
+ else if (objstack.top()->objbits() & ViewObj::MODOBJ) {
+ ModObj * mo = static_cast<ModObj *>(objstack.top());
+ sprintf(theBuffer, "@tmp%d", theColorListCount++);
+ theColorLists.add(theBuffer, $2);
+ mo->setColorList (theBuffer);
+ } else {
+ sprintf (theBuffer,
+ "Syntax error - %s cannot have colors",
+ objstack.top()->name());
+ yyerror (theBuffer);
+ }
+ } scaled_color_list CLOSEB
+ | COLORSCALE REAL REAL REAL OPENB
+ {
+ if ( objstack.empty() )
+ yyerror ("No object to add colors to");
+ else if (objstack.top()->objbits() & ViewObj::MODOBJ) {
+ ModObj * mo = static_cast<ModObj *>(objstack.top());
+
+ sprintf(theBuffer, "@tmp%d", theColorListCount++);
+ theColorLists.add(theBuffer, $2, $3, $4);
+ mo->setColorList (theBuffer);
+ } else {
+ sprintf (theBuffer,
+ "Syntax error - %s cannot have colors",
+ objstack.top()->name());
+ yyerror (theBuffer);
+ }
+ } scaled_color_list CLOSEB
+ ;
+
+away_or_towards : LABEL_DIR { $$ = $1; }
+ | { $$ = BarObj::towards; }
+ ;
+
+metric_labels : metriclabeldecl
+ | metriclabeldecl OPENB metric_name_list CLOSEB
+ ;
+
+metriclabeldecl : METRICLABEL away_or_towards
+ {
+ if ( objstack.empty () )
+ yyerror ("No object to add metric labels to");
+ else if (objstack.top()->objbits() & ViewObj::BAROBJ) {
+ BarObj * bo = static_cast<BarObj *>(objstack.top());
+ bo->metricLabelDir() = $2;
+ }
+ else
+ yyerror ("Syntax error - not a bar object");
+ }
+ ;
+
+metric_name_list: metric_name
+ | metric_name_list metric_name
+ ;
+
+metric_name : nameval
+ {
+ if ( objstack.empty() )
+ yyerror ("No object to add metric names to");
+ else if (objstack.top()->objbits() & ViewObj::BAROBJ) {
+ BarObj * bo = static_cast<BarObj *>(objstack.top());
+ bo->addMetricLabel($1);
+ }
+ else
+ yyerror ("Syntax error - not a bar object");
+ free ($1);
+ }
+ ;
+
+nameval : symname { $$ = strdup ($1); }
+ | INT { sprintf(theBuffer,"%d",$1); $$ = strdup (theBuffer); }
+ | REAL { sprintf(theBuffer,"%f",$1); $$ = strdup (theBuffer); }
+ ;
+
+inst_labels : INSTLABEL away_or_towards OPENB inst_name_list CLOSEB
+ {
+ if ( objstack.empty () )
+ yyerror ("No object to add instance labels to");
+ else if (objstack.top()->objbits() & ViewObj::BAROBJ) {
+ BarObj * bo = static_cast<BarObj *>(objstack.top());
+ bo->instLabelDir() = $2;
+ }
+ else
+ yyerror ("Syntax error - not a bar object");
+
+ }
+ ;
+
+inst_name_list : inst_name
+ | inst_name_list inst_name
+ ;
+
+inst_name : nameval
+ {
+ if ( objstack.empty() )
+ yyerror ("No object to add instance labels to");
+ else if (objstack.top()->objbits() & ViewObj::BAROBJ) {
+ BarObj * bo = static_cast<BarObj *>(objstack.top());
+ bo->addInstLabel($1);
+ }
+ else
+ yyerror ("Syntax error - not a bar object");
+ free ($1);
+ }
+ ;
+
+stack : stackdecl stack_stuff CLOSEB
+ {
+ $$ = objstack.top();
+ $$->finishedAdd();
+ objstack.pop();
+ }
+ ;
+
+stackdecl : STACK pos show_or_hide stack_type shape_type history OPENB
+ {
+ StackObj * so = 0;
+
+ if ( objstack.empty () )
+ so = new StackObj($4, $5, $3, dobj,
+ theCol, theRow,
+ theNumCols, theNumRows,
+ theAlignment);
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj *>(objstack.top());
+ so = new StackObj($4, $5, $3, *go->defs(),
+ theCol, theRow,
+ theNumCols, theNumRows,
+ theAlignment);
+ }
+ else
+ yyerror ("Syntax error - stack inside simple object");
+
+ if ( so ) {
+ so->setHistory(theHistory);
+ objstack.push (so);
+ }
+ }
+ | UTIL pos OPENB
+ {
+ StackObj * so = 0;
+
+ if ( objstack.empty () )
+ so = new StackObj(StackMod::unfixed, ViewObj::cube,
+ false, dobj,
+ theCol, theRow,
+ theNumCols, theNumRows,
+ theAlignment);
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * go = static_cast<GridObj *>(objstack.top());
+
+ so = new StackObj(StackMod::unfixed, ViewObj::cube,
+ false, *go->defs(),
+ theCol, theRow,
+ theNumCols, theNumRows,
+ theAlignment);
+ }
+ else
+ yyerror ("Syntax error - stack inside simple object");
+
+ if ( so ) {
+ objstack.push (so);
+ }
+ }
+ ;
+
+stack_type : STACK_TYPE { $$ = $1; }
+ | { $$ = StackMod::unfixed; }
+ ;
+
+stack_stuff : stack_item
+ | stack_stuff stack_item
+ ;
+
+stack_item : metric_list
+ | named_color
+ | color_list
+ | baselabelspec
+ | STACK_LABEL symname
+ {
+ if ( objstack.empty() ) {
+ yyerror ("Syntax error - no stack to label");
+ } else if (objstack.top()->objbits() & ViewObj::STACKOBJ) {
+ StackObj * so = static_cast<StackObj*>(objstack.top());
+
+ if (so->height() == StackMod::fixed) {
+ int i;
+
+ QString str = $2;
+ for (i = 0; i < str.size(); i++) {
+ if (str[i] == '\n')
+ break;
+ if (str[i] == '\\' &&
+ i + 1 < str.size() &&
+ str[i + 1] == 'n') {
+ str[i] = '\n';
+ str.remove(i+1, 1);
+ break;
+ }
+ }
+ if (i == str.length())
+ str.append(QChar('\n'));
+ so->setFillText((const char *)str.toAscii());
+ } else {
+ yyerror("_stackLabel may only be applied to "
+ "filled stacks");
+ }
+ } else {
+ yyerror ("Syntax error - not a stack");
+ }
+ }
+ ;
+
+metric_list : METRICLIST OPENB metrics CLOSEB;
+
+metrics : metric
+ | metrics metric
+ ;
+
+metric : metricname real
+ {
+ if ( objstack.empty () )
+ yyerror ("Syntax error - no object");
+ else if (objstack.top()->objbits() & ViewObj::MODOBJ) {
+ ModObj * mo = static_cast<ModObj *>(objstack.top());
+ mo->addMetric($1, $2);
+ }
+ else
+ yyerror ("The object has no metrics");
+ }
+ ;
+
+xing : GR_XING INT INT INT INT ALIGN ALIGN ALIGN ALIGN
+ {
+ const DefaultObj * dob = 0;
+ ViewObj::Alignment c[4] = { $6, $7, $8, $9};
+
+ if ( objstack.empty() )
+ dob = & dobj;
+ else if (objstack.top()->objbits() & ViewObj::GRIDOBJ) {
+ GridObj * parent =
+ static_cast<GridObj *>(objstack.top());
+ dob = parent->defs();
+ }
+ else
+ yyerror ("Syntax error - label inside simple object");
+
+ if ( Xing * xo = new Xing (*dob, $2, $3, $4, $5, c) ) {
+ xo->finishedAdd ();
+ $$ = xo;
+ } else {
+ $$ = 0;
+ }
+ }
+ ;
+%%
diff --git a/src/pmview/gridobj.cpp b/src/pmview/gridobj.cpp
new file mode 100644
index 0000000..cd0f762
--- /dev/null
+++ b/src/pmview/gridobj.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoCube.h>
+#include "gridobj.h"
+#include "defaultobj.h"
+
+#include <iostream>
+using namespace std;
+
+GridObj::~GridObj()
+{
+}
+
+GridObj::GridObj(bool onFlag,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols, int rows,
+ GridObj::Alignment align)
+ : BaseObj(onFlag, defaults, x, y, cols, rows, align),
+ _minDepth(defaults.gridMinDepth()),
+ _minWidth(defaults.gridMinWidth()),
+ _width(_minWidth + baseWidth()),
+ _depth(_minDepth + baseDepth()),
+ _list(),
+ _rowDepth(1, _minDepth),
+ _colWidth(1, _minWidth),
+ _finished(false)
+{
+ _objtype |= GRIDOBJ;
+ _defs = defaults;
+}
+
+void
+GridObj::setTran(float xTran, float zTran, int setWidth, int setDepth)
+{
+ int i, j;
+ int totalWidth;
+ int totalDepth;
+ float xShift = width() / 2.0;
+ float zShift = depth() / 2.0;
+ QVector<int> rowPos(rows());
+ QVector<int> colPos(cols());
+
+ assert(_finished == true);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "\nGridObj(" << width() << "x" << depth() << ")@"
+ << col() << "," << row()
+ << "::setTran ("
+ << xTran << ", " << zTran << ", "
+ << setWidth << ", " << setDepth << ")" << endl;
+#endif
+
+ BaseObj::setBaseSize(width(), depth());
+ BaseObj::setTran(xTran + xShift, zTran + zShift, setWidth, setDepth);
+
+ colPos[0] = 0;
+ for (i = 1; i < cols(); i++) {
+ colPos[i] = colPos[i-1] + _colWidth[i-1];
+ }
+ rowPos[0] = 0;
+ for (i = 1; i < rows(); i++) {
+ rowPos[i] = rowPos[i-1] + _rowDepth[i-1];
+ }
+
+ for (i = 0; i < _list.size(); i++) {
+ GridItem &item = _list[i];
+ totalWidth = totalDepth = 0;
+ for (j = item._col; j < item._col + item._item->cols(); j++)
+ totalWidth += _colWidth[j];
+ for (j = item._row; j < item._row + item._item->rows(); j++)
+ totalDepth += _rowDepth[j];
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "GridObj::setTran: [" << i << "] at " << item._col
+ << ',' << item._row << ": ";
+#endif
+
+ item._item->setTran(colPos[item._col] - xShift + borderX(),
+ rowPos[item._row] - zShift + borderZ(),
+ totalWidth, totalDepth);
+ }
+}
+
+int
+addRowCols(QVector<int> & ivec, int nsize, int min)
+{
+ int extra = 0;
+
+ if (nsize > ivec.size()) {
+ extra = min * (nsize - ivec.size());
+
+ ivec.resize(nsize);
+ }
+
+ return extra;
+}
+
+void
+GridObj::addObj(ViewObj *obj, int col, int row)
+{
+ int i;
+ GridItem newItem;
+
+ for (i = 0; i < _list.size(); i++) {
+ const GridItem &item = _list[i];
+ if ((row >= item._row && row < (item._row + item._item->rows())) &&
+ (col >= item._col && col < (item._col + item._item->cols()))) {
+ pmprintf("%s: %s at %d,%d (%dx%d) collides with %s at %d,%d (%dx%d)\nThe later object will be ignored\n",
+ pmProgname, item._item->name(), item._col,
+ item._row, item._item->cols(), item._item->rows(),
+ obj->name(), col, row, obj->cols(), obj->rows());
+ return;
+ }
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::addObj: Adding item " << _list.length() << ": "
+ << obj->name() << ", size = " << obj->width() << 'x'
+ << obj->depth() << endl;
+#endif
+
+ newItem._item = obj;
+ newItem._row = row;
+ newItem._col = col;
+ _list.append(newItem);
+
+ // Add extra cols & rows as necessary
+ _width += addRowCols (_colWidth, col + obj->cols(), _minWidth);
+ _depth += addRowCols (_rowDepth, row + obj->rows(), _minDepth);
+
+
+ // Fasttrack size adjustments for simple objects
+ if (obj->cols() == 1 && _colWidth[col] < obj->width()) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::addObj: increasing col[" << col << "] from "
+ << _colWidth[col] << " to " << obj->width() << endl;
+#endif
+ _width += obj->width() - _colWidth[col];
+ _colWidth[col] = obj->width();
+ }
+
+ if (obj->rows() == 1 && _rowDepth[row] < obj->depth()) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::addObj: increasing row[" << row << "] from "
+ << _rowDepth[row] << " to " << obj->depth() << endl;
+#endif
+ _depth += obj->depth() - _rowDepth[row];
+ _rowDepth[row] = obj->depth();
+ }
+}
+
+void
+GridObj::finishedAdd()
+{
+ int i, j;
+ int size;
+ int current;
+ int adjust;
+
+ BaseObj::addBase(_root);
+
+ for (i= 0; i < _list.size(); i++) {
+ const GridItem &item = _list[i];
+ _root->addChild(item._item->root());
+ if (item._item->modObj() != NULL) {
+ BaseObj::add(item._item->modObj());
+ }
+
+ if (item._item->cols() > 1) {
+ size = item._item->width();
+ for (j = item._col, current = 0;
+ j < item._col + item._item->cols();
+ j++) {
+ current += _colWidth[j];
+ }
+
+ if (current < size) {
+ size -= current;
+ adjust = (int)((size / (float)item._item->cols()) + 0.5);
+ for (j = item._col;
+ j < item._col + item._item->cols() && adjust > 0; j++) {
+ if (adjust > size) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::finishedAdd: increasing col["
+ << j << "] from " << _colWidth[j] << " to "
+ << _colWidth[j] + size << endl;
+#endif
+ _colWidth[j] += size;
+ _width+= size;
+ adjust = 0;
+ }
+ else {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::finishedAdd: increasing col["
+ << j << "] from " << _colWidth[j] << " to "
+ << _colWidth[j] + adjust << endl;
+#endif
+ _colWidth[j] += adjust;
+ _width += adjust;
+ size -= adjust;
+ }
+ }
+ }
+ }
+
+ if (item._item->rows() > 1) {
+ size = item._item->depth();
+ for (j = item._row, current = 0;
+ j < item._row + item._item->rows();
+ j++) {
+ current += _rowDepth[j];
+ }
+
+ if (current < size) {
+ size -= current;
+ adjust = (int)((size / (float)item._item->rows()) + 0.5);
+ for (j = item._row;
+ j < item._row + item._item->rows() && adjust > 0; j++) {
+ if (adjust > size) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::finishedAdd: increasing row["
+ << j << "] from " << _rowDepth[j] << " to "
+ << _rowDepth[j] + size << endl;
+#endif
+ _rowDepth[j] += size;
+ _depth+= size;
+ adjust = 0;
+ }
+ else {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::finishedAdd: increasing row["
+ << j << "] from " << _rowDepth[j] << " to "
+ << _rowDepth[j] + adjust << endl;
+#endif
+ _rowDepth[j] += adjust;
+ _depth += adjust;
+ size -= adjust;
+ }
+ }
+ }
+ }
+ }
+
+ _finished = true;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "GridObj::finishedAdd: " << *this << endl;
+#endif
+}
+
+QTextStream&
+operator<<(QTextStream& os, GridObj const& rhs)
+{
+ rhs.display(os);
+ return os;
+}
+
+void
+GridObj::display(QTextStream& os) const
+{
+ int i;
+ int sum;
+
+ BaseObj::display(os);
+ os << ", minRowDepth = " << _minDepth << ", minColWidth = "
+ << _minWidth << ", rows = " << rows() << ", cols = " << cols()
+ << ", finishedAdd = " << (_finished == true ? "true" : "false")
+ << endl;
+
+ os << "Column widths: ";
+ for (i = 0, sum = 0; i < _colWidth.size(); i++) {
+ os << _colWidth[i] << ' ';
+ sum += _colWidth[i];
+ }
+ os << endl;
+ assert(_width == sum + baseWidth());
+
+ os << "Row depths: ";
+ for (i = 0, sum = 0; i < _rowDepth.size(); i++) {
+ os << _rowDepth[i] << ' ';
+ sum += _rowDepth[i];
+ }
+ os << endl;
+ assert(_depth == sum + baseDepth());
+
+ for (i = 0; i < _list.size(); i++)
+ os << '[' << i << "] at " << _list[i]._col << ',' << _list[i]._row
+ << ": " << *(_list[i]._item) << endl;
+}
diff --git a/src/pmview/gridobj.h b/src/pmview/gridobj.h
new file mode 100644
index 0000000..f19dbd4
--- /dev/null
+++ b/src/pmview/gridobj.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _GRIDOBJ_H_
+#define _GRIDOBJ_H_
+
+#include "baseobj.h"
+#include "defaultobj.h"
+#include <QtCore/QVector>
+
+struct GridItem
+{
+ ViewObj *_item;
+ int _row;
+ int _col;
+};
+
+typedef QList<GridItem> GridList;
+
+class GridObj : public BaseObj
+{
+protected:
+
+ int _minDepth;
+ int _minWidth;
+ int _width;
+ int _depth;
+ GridList _list;
+ QVector<int> _rowDepth;
+ QVector<int> _colWidth;
+ bool _finished;
+ DefaultObj _defs;
+
+ static int theDefRowDepth;
+ static int theDefColWidth;
+
+public:
+
+ virtual ~GridObj();
+
+ GridObj(bool onFlag,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols = 1, int rows = 1,
+ GridObj::Alignment align = GridObj::center);
+
+ DefaultObj * defs() { return & _defs; }
+
+ int numObj() const
+ { return _list.size(); }
+ int minDepth() const
+ { return _minDepth; }
+ int minWidth() const
+ { return _minWidth; }
+ int rows() const
+ { return _rowDepth.size(); }
+ int cols() const
+ { return _colWidth.size(); }
+
+ // Local changes
+ int &minDepth()
+ { return _minDepth; }
+ int &minWidth()
+ { return _minWidth; }
+
+ virtual int width() const
+ { return _width; }
+ virtual int depth() const
+ { return _depth; }
+
+ virtual void setTran(float xTran, float zTran, int width, int depth);
+
+ void addObj(ViewObj *obj, int col, int row);
+
+ virtual void finishedAdd();
+
+ // Output
+ virtual void display(QTextStream& os) const;
+
+ virtual const char* name() const
+ { return "Grid"; }
+
+ friend QTextStream& operator<<(QTextStream& os, GridObj const& rhs);
+
+protected:
+
+ void add(Modulate *mod);
+
+private:
+
+ GridObj();
+ GridObj(GridObj const &);
+ GridObj const& operator=(GridObj const &);
+};
+
+#endif /* _GRIDOBJ_H_ */
diff --git a/src/pmview/icon b/src/pmview/icon
new file mode 100644
index 0000000..e1650fb
--- /dev/null
+++ b/src/pmview/icon
Binary files differ
diff --git a/src/pmview/labelobj.cpp b/src/pmview/labelobj.cpp
new file mode 100644
index 0000000..c8ec594
--- /dev/null
+++ b/src/pmview/labelobj.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+
+#include "pmview.h"
+#include "labelobj.h"
+#include "defaultobj.h"
+
+LabelObj::~LabelObj()
+{
+ if (_text)
+ delete _text;
+}
+
+LabelObj::LabelObj(const DefaultObj &defaults,
+ int x, int y,
+ int cols, int rows,
+ ViewObj::Alignment align)
+: ViewObj(x, y, cols, rows, align),
+ _str(),
+ _text(0),
+ _dir(Text::right),
+ _fontSize(Text::medium),
+ _margin(defaults.labelMargin())
+{
+ _objtype |= LABELOBJ;
+
+ _color[0] = defaults.labelColor(0);
+ _color[1] = defaults.labelColor(1);
+ _color[2] = defaults.labelColor(2);
+}
+
+LabelObj::LabelObj(Text::Direction dir,
+ Text::FontSize fontSize,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols, int rows,
+ ViewObj::Alignment align)
+: ViewObj(x, y, cols, rows, align),
+ _str(),
+ _text(0),
+ _dir(dir),
+ _fontSize(fontSize),
+ _margin(defaults.labelMargin())
+{
+ _color[0] = defaults.labelColor(0);
+ _color[1] = defaults.labelColor(1);
+ _color[2] = defaults.labelColor(2);
+}
+
+void
+LabelObj::finishedAdd()
+{
+ _text = new Text(_str, _dir, _fontSize);
+ SoBaseColor *base = new SoBaseColor;
+ base->rgb.setValue(_color[0], _color[1], _color[2]);
+ _root->addChild(base);
+ _root->addChild(_text->root());
+}
+
+void
+LabelObj::setTran(float xTran, float zTran, int setWidth, int setDepth)
+{
+ switch(_text->dir()) {
+ case Text::right:
+ ViewObj::setTran(xTran + width() - _margin,
+ zTran + _margin,
+ setWidth, setDepth);
+ break;
+ case Text::down:
+ ViewObj::setTran(xTran + _margin,
+ zTran + depth() - _margin,
+ setWidth, setDepth);
+ break;
+ default:
+ ViewObj::setTran(xTran + _margin,
+ zTran + _margin,
+ setWidth, setDepth);
+ break;
+ }
+}
+
+QTextStream&
+operator<<(QTextStream& os, LabelObj const& rhs)
+{
+ rhs.display(os);
+ return os;
+}
+
+void
+LabelObj::display(QTextStream& os) const
+{
+ ViewObj::display(os);
+ os << ", label = \"" << _str << "\", margin = " << _margin << ", text = ";
+ if (_text == NULL)
+ os << "undefined";
+ else
+ os << *_text;
+}
+
diff --git a/src/pmview/labelobj.h b/src/pmview/labelobj.h
new file mode 100644
index 0000000..5a0f31c
--- /dev/null
+++ b/src/pmview/labelobj.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _LABELOBJ_H_
+#define _LABELOBJ_H_
+
+#include "text.h"
+#include "viewobj.h"
+
+class SoNode;
+class SoSeparator;
+class SoTranslation;
+
+class LabelObj : public ViewObj
+{
+protected:
+
+ QString _str;
+ Text *_text;
+ Text::Direction _dir;
+ Text::FontSize _fontSize;
+ int _margin;
+ float _color[3];
+
+public:
+
+ virtual ~LabelObj();
+
+ LabelObj(Text::Direction dir,
+ Text::FontSize fontSize,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols = 1, int rows = 1,
+ Alignment align = center);
+
+ LabelObj(const DefaultObj &defaults,
+ int x, int y,
+ int cols = 1, int rows = 1,
+ Alignment align = center);
+
+ const QString &str() const
+ { return _str; }
+ Text::Direction dir() const
+ { return _dir; }
+ Text::FontSize size() const
+ { return _fontSize; }
+ int margin() const
+ { return _margin; }
+ float color(int i) const
+ { return _color[i]; }
+
+ // Local Changes
+ QString &str()
+ { return _str; }
+ Text::Direction &dir()
+ { return _dir; }
+ Text::FontSize &size()
+ { return _fontSize; }
+ int &margin()
+ { return _margin; }
+ void color(float r, float g, float b)
+ { _color[0] = r; _color[1] = g; _color[2] = b; }
+
+ virtual int width() const
+ { return _text->width() + (_margin * 2); }
+ virtual int depth() const
+ { return _text->depth() + (_margin * 2); }
+
+ virtual void setTran(float xTran, float zTran, int width, int depth);
+
+ virtual void finishedAdd();
+
+ // Output
+ virtual void display(QTextStream& os) const;
+
+ virtual const char* name() const
+ { return "Label"; }
+
+ friend QTextStream& operator<<(QTextStream& os, LabelObj const& rhs);
+
+private:
+
+ LabelObj();
+ LabelObj(LabelObj const &);
+ LabelObj const& operator=(LabelObj const &);
+};
+
+#endif /* _LABELOBJ_H_ */
diff --git a/src/pmview/launch.cpp b/src/pmview/launch.cpp
new file mode 100644
index 0000000..3e2d2f6
--- /dev/null
+++ b/src/pmview/launch.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 "main.h"
+#include "launch.h"
+#include "colorscale.h"
+#include "metriclist.h"
+
+#include <iostream>
+using namespace std;
+
+#define PM_LAUNCH_VERSION1 1
+#define PM_LAUNCH_VERSION2 2
+
+const QString Launch::theVersion1Str = "pmlaunch Version 1.0\n";
+const QString Launch::theVersion2Str = "pmlaunch Version 2.0\n";
+
+Launch::~Launch()
+{
+}
+
+Launch::Launch(const QString &version)
+: _strings(),
+ _groupMetric(-1),
+ _groupCount(0),
+ _groupHint(),
+ _metricCount(0)
+{
+ if (version == "1.0")
+ _version = PM_LAUNCH_VERSION1;
+ else
+ _version = PM_LAUNCH_VERSION2;
+}
+
+Launch::Launch(const Launch &rhs)
+: _strings(rhs._strings),
+ _groupMetric(rhs._groupMetric),
+ _groupCount(rhs._groupCount),
+ _groupHint(rhs._groupHint),
+ _metricCount(rhs._metricCount),
+ _version(rhs._version)
+{
+}
+
+const Launch &
+Launch::operator=(const Launch &rhs)
+{
+ if (this != &rhs) {
+ _strings = rhs._strings;
+ _groupMetric = rhs._groupMetric;
+ _groupCount = rhs._groupCount;
+ _groupHint = rhs._groupHint;
+ _metricCount = rhs._metricCount;
+ }
+ return *this;
+}
+
+void
+Launch::setDefaultOptions(int interval,
+ int debug,
+ const char *timeport,
+ const char *starttime,
+ const char *endtime,
+ const char *offset,
+ const char *timezone,
+ const char *defsourcetype,
+ const char *defsourcename,
+ bool selected)
+{
+ addOption("interval", (interval < 0 ? -interval : interval));
+ addOption("debug", debug);
+
+ if (timeport != NULL)
+ addOption("timeport", timeport);
+ if (starttime != NULL)
+ addOption("starttime", starttime);
+ if (endtime != NULL)
+ addOption("endtime", endtime);
+ if (offset != NULL)
+ addOption("offset", offset);
+ if (timezone != NULL)
+ addOption("timezone", timezone);
+ if (defsourcetype != NULL)
+ addOption("defsourcetype", defsourcetype);
+ if (defsourcename != NULL)
+ addOption("defsourcename", defsourcename);
+ if (pmProgname != NULL)
+ addOption("progname", pmProgname);
+ addOption("pid", (int)getpid());
+
+ if (selected)
+ addOption("selected", "true");
+ else
+ addOption("selected", "false");
+}
+
+void
+Launch::addOption(const char *name, const char *value)
+{
+ QString str = "option ";
+
+ if (name == NULL)
+ return;
+
+ if (value == NULL) {
+ str.append(name).append("=\n");
+ }
+ else {
+ str.append(name).append('=').append(value).append('\n');
+ str.append('\n');
+ }
+ _strings.append(str);
+}
+
+void
+Launch::addOption(const char *name, int value)
+{
+ QString str = "option ";
+
+ if (name == NULL)
+ return;
+
+ str.append(name).append('=').setNum(value).append('\n');
+ _strings.append(str);
+}
+
+void
+Launch::addMetric(const QmcMetric &metric,
+ const SbColor &color,
+ int instance,
+ bool useSocks)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ cerr << "Launch::addMetric(1): Adding ";
+ metric.dump(cerr, true, instance);
+ cerr << " (" << _metricCount << ')' << endl;
+ }
+#endif
+
+ QmcSource source = metric.context()->source();
+ QByteArray ba;
+ ba = metric.instName(instance).toLocal8Bit();
+
+ addMetric(metric.context()->handle(), source.source(), source.host(), metric.name(),
+ metric.hasInstances() == 0 ? NULL : ba.data(),
+ metric.desc(), color, metric.scale(), useSocks);
+}
+
+void
+Launch::addMetric(const QmcMetric &metric,
+ const ColorScale &scale,
+ int instance,
+ bool useSocks)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ cerr << "Launch::addMetric(2): Adding ";
+ metric.dump(cerr, true, instance);
+ cerr << " (" << _metricCount << ')' << endl;
+ }
+#endif
+
+ QmcSource source = metric.context()->source();
+ QByteArray ba;
+ ba = metric.instName(instance).toLocal8Bit();
+
+ addMetric(metric.context()->handle(), source.source(), source.host(), metric.name(),
+ metric.hasInstances() == 0 ? NULL : ba.data(),
+ metric.desc(), scale, useSocks);
+}
+
+void
+Launch::addMetric(int context,
+ const QString &source,
+ const QString &host,
+ const QString &metric,
+ const char *instance,
+ const QmcDesc &desc,
+ const SbColor &color,
+ double scale,
+ bool useSocks)
+{
+ QString str(256);
+ QString col;
+
+ if (_groupMetric == -1) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "Launch::addMetric: Called before startGroup."
+ << " Adding a group." << endl;
+#endif
+ startGroup();
+ }
+
+ preColor(context, source, host, metric, useSocks, str);
+
+ str.append(" S ");
+ MetricList::toString(color, col);
+ str.append(col).append(',').setNum(scale).append(' ');
+
+ postColor(desc, instance, str);
+ _strings.append(str);
+}
+
+void
+Launch::addMetric(int context,
+ const QString &source,
+ const QString &host,
+ const QString &metric,
+ const char *instance,
+ const QmcDesc &desc,
+ const ColorScale &scale,
+ bool useSocks)
+{
+ int i;
+ QString str(128);
+ QString col;
+
+ if (_groupMetric == -1) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "Launch::addMetric: Called before startGroup."
+ << " Adding a group." << endl;
+#endif
+ startGroup();
+ }
+
+ preColor(context, source, host, metric, useSocks, str);
+ str.append(" D ");
+
+ MetricList::toString(scale[0].color(), col);
+ str.append(col).append(',').setNum(scale[0].min());
+ for (i = 1; i < scale.numSteps(); i++) {
+ MetricList::toString(scale[i].color(), col);
+ str.append(',').append(col).append(',');
+ str.setNum(scale[i].min());
+ }
+ str.append(' ');
+
+ postColor(desc, instance, str);
+ _strings.append(str);
+}
+
+void
+Launch::preColor(int context,
+ const QString &source,
+ const QString &host,
+ const QString &metric,
+ bool useSocks,
+ QString &str)
+{
+ str.append("metric ").setNum(_metricCount++).append(' ');
+ str.setNum(_groupCount).append(' ').append(_groupHint);
+
+ switch(context) {
+ case PM_CONTEXT_LOCAL:
+ str.append(" l ");
+ break;
+ case PM_CONTEXT_HOST:
+ str.append(" h ");
+ break;
+ case PM_CONTEXT_ARCHIVE:
+ str.append(" a ");
+ break;
+ }
+
+ str.append(source).append(' ');
+
+ if (context == PM_CONTEXT_ARCHIVE)
+ str.append(host);
+ else if (useSocks)
+ str.append("true");
+ else
+ str.append("false");
+
+ str.append(' ').append(metric);
+}
+
+void
+Launch::postColor(const QmcDesc &desc,
+ const char *instance,
+ QString &str)
+{
+ const pmDesc d = desc.desc();
+
+ if (_version == PM_LAUNCH_VERSION2) {
+ str.setNum(d.type).append(' ');
+ str.setNum(d.sem).append(' ');
+ str.setNum(d.units.scaleSpace).append(' ');
+ str.setNum(d.units.scaleTime).append(' ');
+ str.setNum(d.units.scaleCount).append(' ');
+ }
+
+ str.setNum(d.units.dimSpace).append(' ');
+ str.setNum(d.units.dimTime).append(' ');
+ str.setNum(d.units.dimCount).append(' ');
+ str.setNum((int)(d.indom)).append(" [");
+ if (instance != NULL)
+ str.append(instance);
+ str.append("]\n");
+}
+
+void
+Launch::startGroup(const char *hint)
+{
+
+ if (_groupMetric != -1)
+ cerr << "Launch::startGroup: Two groups started at once!" << endl;
+ else {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "Launch::startGroup: Starting group " << _groupCount
+ << endl;
+#endif
+
+ _groupMetric = _metricCount;
+ _groupHint = hint;
+ }
+}
+
+void
+Launch::endGroup()
+{
+ if (_groupMetric == -1)
+ cerr << "Launch::endGroup: No group to end!" << endl;
+ else if (_groupMetric == _metricCount) {
+ cerr << "Launch::endGroup: No metrics added to group "
+ << _groupCount << endl;
+ _groupMetric = -1;
+ } else {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "Launch::endGroup: ending group " << _groupCount
+ << endl;
+#endif
+
+ _groupMetric = -1;
+ _groupCount++;
+ }
+}
+
+void
+Launch::append(Launch const &rhs)
+{
+ if (rhs._groupMetric != -1) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "Launch::append: Group not finished in appended object."
+ << " Completing group" << endl;
+#endif
+
+ // Cast away const, yuk.
+ ((Launch *)(&rhs))->endGroup();
+ }
+ _strings.append(rhs._strings);
+}
+
+QTextStream&
+operator<<(QTextStream& os, Launch const& rhs)
+{
+ int i;
+ for (i = 0; i < rhs._strings.size(); i++)
+ os << rhs._strings[i];
+ return os;
+}
+
+const char *
+Launch::launchPath()
+{
+ char *env;
+ static char launch_path[MAXPATHLEN];
+
+ if ((env = getenv("PM_LAUNCH_PATH")) != NULL)
+ strncpy(launch_path, env, sizeof(launch_path));
+ else
+ snprintf(launch_path, sizeof(launch_path), "%s/config/pmlaunch", pmGetConfig("PCP_VAR_DIR"));
+ return launch_path;
+}
+
+#include <iostream>
+
+void
+Launch::output(int fd) const
+{
+ QByteArray ba;
+ int sts;
+ const char *str;
+
+ if (_version == PM_LAUNCH_VERSION2)
+ ba = theVersion2Str.toLocal8Bit();
+ else
+ ba = theVersion1Str.toLocal8Bit();
+
+ str = ba.data();
+ if ((sts = write(fd, str, strlen(str))) != (int)strlen(str)) {
+ cerr << "Launch::output: version write->" << sts
+ << " not " << strlen(str) << endl;
+ }
+
+ for (int i = 0; i < _strings.length(); i++) {
+ ba = _strings[i].toLocal8Bit();
+ str = ba.data();
+ if ((sts = write(fd, str, strlen(str))) != (int)strlen(str)) {
+ cerr << "Launch::output: string write->" << sts
+ << " not " << strlen(str)
+ << " for " << str << endl;
+ }
+ }
+}
diff --git a/src/pmview/launch.h b/src/pmview/launch.h
new file mode 100644
index 0000000..2f048b1
--- /dev/null
+++ b/src/pmview/launch.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _LAUNCH_H_
+#define _LAUNCH_H_
+
+#include "main.h"
+#include <QtCore/QStringList>
+
+class SbColor;
+class ColorScale;
+
+class Launch
+{
+private:
+
+ static const QString theVersion1Str;
+ static const QString theVersion2Str;
+
+ QStringList _strings;
+ int _groupMetric;
+ int _groupCount;
+ QString _groupHint;
+ int _metricCount;
+ int _version;
+
+public:
+
+ ~Launch();
+
+ Launch(const QString &version = ""); // defaults to version 2.0
+ Launch(const Launch &rhs);
+ const Launch &operator=(const Launch &rhs);
+
+ static const char *launchPath();
+
+ void setDefaultOptions(int interval = 5,
+ int debug = 0,
+ const char *timeport = NULL,
+ const char *starttime = NULL,
+ const char *endtime = NULL,
+ const char *offset = NULL,
+ const char *timezone = NULL,
+ const char *defsourcetype = NULL,
+ const char *defsourcename = NULL,
+ bool selected = false);
+
+ void addOption(const char *name, const char *value);
+ void addOption(const char *name, int value);
+
+ void addMetric(const QmcMetric &metric,
+ const SbColor &color,
+ int instance,
+ bool useSocks = false);
+
+ void addMetric(const QmcMetric &metric,
+ const ColorScale &scale,
+ int instance,
+ bool useSocks = false);
+
+ void addMetric(int context,
+ const QString &source,
+ const QString &host,
+ const QString &metric,
+ const char *instance,
+ const QmcDesc &desc,
+ const SbColor &color,
+ double scale,
+ bool useSocks = false);
+ // Add metric with static color and scale
+
+ void addMetric(int context,
+ const QString &source,
+ const QString &host,
+ const QString &metric,
+ const char *instance,
+ const QmcDesc &desc,
+ const ColorScale &scale,
+ bool useSocks = false);
+ // Add metric with dynamic color range
+
+ void startGroup(const char *hint = "none");
+ void endGroup();
+
+ void append(Launch const& rhs);
+
+ void output(int fd) const;
+
+ friend QTextStream& operator<<(QTextStream& os, Launch const& rhs);
+
+private:
+
+ void preColor(int context,
+ const QString &source,
+ const QString &host,
+ const QString &metric,
+ bool useSocks,
+ QString &str);
+ void postColor(const QmcDesc &desc, const char *instance, QString &str);
+};
+
+#endif /* _LAUNCH_H_ */
diff --git a/src/pmview/lex.l b/src/pmview/lex.l
new file mode 100644
index 0000000..40b9285
--- /dev/null
+++ b/src/pmview/lex.l
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 1997-2001 Silicon Graphics, Inc. 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.
+ */
+
+%{
+
+#ifdef FLEX_SCANNER
+
+int pmviewFlexInput (char * buf, int ms);
+
+#undef YY_INPUT
+#define YY_INPUT(b,r,ms) (r=pmviewFlexInput(b, ms))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int yylex (void);
+#ifdef __cplusplus
+}
+#endif
+
+#else /* AT&T Lex */
+
+#undef input
+#undef unput
+#undef yywrap
+
+char input(void);
+void unput(char);
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "viewobj.h"
+#include "barobj.h"
+#include "text.h"
+#include "stackobj.h"
+#include "gridobj.h"
+#include "gram.h"
+
+extern void yywarn(const char *);
+extern void yyerror(const char *);
+extern FILE *theAltConfig;
+
+#ifdef YYLMAX
+#undef YYLMAX
+#endif
+
+#define YYLMAX 2048
+
+#ifdef LEX_DEBUG
+#define RETURN(c) if (pmDebug & DBG_TRACE_APPL2) { pmprintf("Lex: %d\n", c); pmflush (); } return c
+#else
+#define RETURN(c) if (theAltConfig) fprintf(theAltConfig, "%s", yytext); return c
+#endif
+
+static void lexerror (const char * msg, const char * yytext);
+%}
+
+
+%%
+
+[-]?[0-9]+[\.][0-9]+ {
+ yylval.y_real = strtod(yytext, (char **)0);
+ RETURN(REAL);
+ }
+
+0[xX][0-9]+ {
+ yylval.y_int = (int)strtol(&yytext[2], (char **)0, 16);
+ RETURN(INT);
+ }
+
+[-]?[0-9]+ {
+ yylval.y_int = atoi(yytext);
+ RETURN(INT);
+ }
+
+[Pp][Mm][Vv][Ii][Ee][Ww][\t ]+[vV]ersion[\t ]+[0-9]+\.[0-9]+ {
+ yylval.y_str = strdup (yytext+15);
+ RETURN(PMVIEW);
+ }
+
+_grid { RETURN(GRID); }
+_bar { RETURN(BAR); }
+_labeledbar { RETURN(BAR); }
+_stack { RETURN(STACK); }
+_util { RETURN(UTIL); }
+_metrics { RETURN(METRICLIST); }
+_color[lL]ist { RETURN(COLORLIST); }
+_color[sS]cale { RETURN(COLORSCALE); }
+_label { RETURN(LABEL); }
+_metric[lL]abels { RETURN(METRICLABEL); }
+_inst[lL]abels { RETURN(INSTLABEL); }
+_direction { RETURN(DIRECTION); }
+_size { RETURN(SIZE); }
+_text { RETURN(TEXT); }
+_scale { RETURN(SCALE); }
+_history { RETURN(HISTORY); }
+_bar[lL]ength { RETURN(BAR_LENGTH); }
+_bar[xX][mM]argin { RETURN(MARGIN_WIDTH); }
+_bar[yY][mM]argin { RETURN(MARGIN_DEPTH); }
+_margin[wW]idth { RETURN(MARGIN_WIDTH); }
+_margin[dD]epth { RETURN(MARGIN_DEPTH); }
+_bar[hH]eight { RETURN(BAR_HEIGHT); }
+_bar[bB]ase[hH]eight { RETURN(BASE_HEIGHT); }
+_base[hH]eight { RETURN(BASE_HEIGHT); }
+_stack[lL]ength { RETURN(BAR_LENGTH); }
+_stack[xX][mM]argin { RETURN(MARGIN_WIDTH); }
+_stack[yY][mM]argin { RETURN(MARGIN_DEPTH); }
+_stack[hH]eight { RETURN(BAR_HEIGHT); }
+_stack[bB]ase[hH]eight { RETURN(BASE_HEIGHT); }
+_grid[sS]pace { RETURN(GRID_SPACE); }
+_grid[wW]idth { RETURN(GRID_WIDTH); }
+_grid[dD]epth { RETURN(GRID_DEPTH); }
+_grid[hH]eight { RETURN(BASE_HEIGHT); }
+_grid[cC]olor { RETURN(BASE_COLOR); }
+_base[cC]olor { RETURN(BASE_COLOR); }
+_gap[wW]idth { RETURN(GAP_WIDTH); }
+_gap[dD]epth { RETURN(GAP_DEPTH); }
+_gap[lL]abel { RETURN(GAP_LABEL); }
+_label[mM]argin { RETURN(LABEL_MARGIN); }
+_label[cC]olor { RETURN(LABEL_COLOR); }
+_stack[lL]abel { RETURN(STACK_LABEL); }
+_base[lL]abel { RETURN(BASE_LABEL); }
+_box { RETURN(BOX); }
+_pipe[Ll]ength { RETURN(PIPE_LENGTH); }
+_pipe { RETURN(PIPE); }
+_pipe[Tt]ag { RETURN(PIPETAG); }
+_link { RETURN(GR_LINK); }
+_xing { RETURN(GR_XING); }
+_sceneFile { RETURN(SCENE_FILE); }
+
+[_]?[nN] { yylval.y_align = ViewObj::north; RETURN(ALIGN); }
+[_]?north { yylval.y_align = ViewObj::north; RETURN(ALIGN); }
+[_]?[sS] { yylval.y_align = ViewObj::south; RETURN(ALIGN); }
+[_]?south { yylval.y_align = ViewObj::south; RETURN(ALIGN); }
+[_]?[eE] { yylval.y_align = ViewObj::east; RETURN(ALIGN); }
+[_]?east { yylval.y_align = ViewObj::east; RETURN(ALIGN); }
+[_]?[wW] { yylval.y_align = ViewObj::west; RETURN(ALIGN); }
+[_]?west { yylval.y_align = ViewObj::west; RETURN(ALIGN); }
+[_]?[nN][wW] { yylval.y_align = ViewObj::northWest; RETURN(ALIGN); }
+[_]?northwest { yylval.y_align = ViewObj::northWest; RETURN(ALIGN); }
+[_]?[nN][eE] { yylval.y_align = ViewObj::northEast; RETURN(ALIGN); }
+[_]?northeast { yylval.y_align = ViewObj::northEast; RETURN(ALIGN); }
+[_]?[sS][wW] { yylval.y_align = ViewObj::southWest; RETURN(ALIGN); }
+[_]?southwest { yylval.y_align = ViewObj::southWest; RETURN(ALIGN); }
+[_]?[sS][eE] { yylval.y_align = ViewObj::southEast; RETURN(ALIGN); }
+[_]?southeast { yylval.y_align = ViewObj::southEast; RETURN(ALIGN); }
+[_]?center { yylval.y_align = ViewObj::center; RETURN(ALIGN); }
+
+[_]?up { yylval.y_textDir = Text::up; RETURN(DIRVAL); }
+[_]?down { yylval.y_textDir = Text::down; RETURN(DIRVAL); }
+[_]?left { yylval.y_textDir = Text::left; RETURN(DIRVAL); }
+[_]?right { yylval.y_textDir = Text::right; RETURN(DIRVAL); }
+
+[_]?small { yylval.y_fontSize = Text::small; RETURN(SIZ); }
+[_]?medium { yylval.y_fontSize = Text::medium; RETURN(SIZ); }
+[_]?large { yylval.y_fontSize = Text::large; RETURN(SIZ); }
+
+[_]?show { yylval.y_bool = true; RETURN(BOOL); }
+[_]?hide { yylval.y_bool = false; RETURN(BOOL); }
+
+[_]?towards { yylval.y_labelDir = BarObj::towards; RETURN(LABEL_DIR); }
+[_]?away { yylval.y_labelDir = BarObj::away; RETURN(LABEL_DIR); }
+
+[_]?row { yylval.y_instDir = BarMod::instPerRow; RETURN(INST_DIR); }
+[_]?col { yylval.y_instDir = BarMod::instPerCol; RETURN(INST_DIR); }
+
+_cube { yylval.y_shape = ViewObj::cube; RETURN(SHAPE); }
+_cylinder { yylval.y_shape = ViewObj::cylinder; RETURN(SHAPE); }
+
+_[yY]mod { yylval.y_barMod = BarMod::yScale; RETURN(BAR_TYPE); }
+_color[mM]od { yylval.y_barMod = BarMod::color; RETURN(BAR_TYPE); }
+_color[yY][mM]od { yylval.y_barMod = BarMod::colYScale; RETURN(BAR_TYPE); }
+
+_util[mM]od { yylval.y_stackMod = StackMod::util; RETURN(STACK_TYPE); }
+_fill[mM]od { yylval.y_stackMod = StackMod::fixed; RETURN(STACK_TYPE); }
+
+_group[bB]y[rR]ow { yylval.y_barGroup = BarMod::groupByRow; RETURN(GROUP); }
+_group[bB]y[cC]ol { yylval.y_barGroup = BarMod::groupByCol; RETURN(GROUP); }
+_group[bB]y[mM]etric { yylval.y_barGroup = BarMod::groupByMetric; RETURN(GROUP); }
+_group[bB]y[iI]nst { yylval.y_barGroup = BarMod::groupByInst; RETURN(GROUP); }
+
+[A-Za-z0-9_./\-,:?=+&]+(\[[ \t]*((\"[^\"\n]*\"|[^\"\n\]]*)[ \t]*\,?[ \t]*)+[ \t]*\]) {
+ /*
+ * Metric could be in the form: name + quoted instance or
+ * name + non-quoted instance (i,e no " between the [ ] ) or
+ * just name with no instance spec. Name with no instance spec
+ * is delegated to the NAME token, the rest is handled here.
+ */
+ yylval.y_str = strdup (yytext);
+ RETURN(METRIC);
+ }
+
+[A-Za-z0-9_\.\/\-\,:\?\=\+\&]+ {
+ /*
+ * While parsing, NAME token can be used both in general context
+ * or as name for METRIC. I don't want to do context-specific
+ * lexical analisys, so NAME is restricted to the list of chars
+ * above and it cannot have opening or closing square brackets
+ */
+ yylval.y_str = strdup (yytext);
+ RETURN(NAME);
+ }
+
+\"[^\"\n][^\"\n]*\" {
+ yylval.y_str = (char *)malloc(yyleng-1);
+ strncpy(yylval.y_str, &yytext[1], yyleng-2);
+ yylval.y_str[yyleng-2] = '\0';
+ RETURN(STRING);
+ }
+
+\"[^\"\n][^\"\n]*\n {
+ lexerror("Expected closing \"", yytext);
+ /*NOTREACHED*/
+ }
+
+\( { RETURN(OPENB); }
+\) { RETURN(CLOSEB); }
+
+\#.*\n {}
+\n { if (theAltConfig) fputc('\n', theAltConfig); }
+
+[\t ]+ { if (theAltConfig) fputc(' ', theAltConfig); }
+
+. {
+ sprintf(theBuffer, "Illegal character '%c'", yytext[0]);
+ lexerror(theBuffer, yytext);
+ /*NOTREACHED*/
+ }
+%%
+
+static char *line;
+static int linepos;
+static int linelen;
+static int mark = -1;
+
+extern int lineNum;
+
+#ifdef FLEX_SCANNER
+static int in = '\0';
+
+int yywrap(void)
+{
+ return in == EOF;
+}
+
+int
+pmviewFlexInput(char *buf, int ms)
+{
+ if (in == '\n') {
+ lineNum++;
+ linepos=0;
+ }
+
+ if (linepos >= linelen - 1) {
+ if (linelen == 0)
+ linelen = 128;
+ else
+ linelen *= 2;
+ line = (char *)realloc(line, linelen * sizeof(char));
+ }
+
+ if (ms > 0) {
+ if ((in = fgetc(yyin)) != EOF) {
+ line[linepos++] = buf[0] = in & 0xFFU;
+ ms = 1;
+ } else {
+ ms = 0;
+ }
+ }
+
+ return ms;
+}
+
+void
+skipAhead(void)
+{
+ while ((in != '\n') && (in != EOF)) {
+ char c;
+ pmviewFlexInput(&c, 1);
+ }
+}
+
+char
+input(void)
+{
+ char c;
+ if (pmviewFlexInput(&c, 1))
+ return c;
+ return 0;
+}
+
+char
+lastinput(void)
+{
+ return (in & 0xFFU);
+}
+
+#else
+
+static char lastc = 'A';
+static char peekc = '\0';
+
+extern int lineNum;
+
+extern FILE *yyin;
+
+int
+yywrap(void)
+{
+ return lastc == '\0';
+}
+
+char
+input(void)
+{
+ int get;
+
+ if (peekc != '\0') {
+ lastc = peekc;
+ peekc = '\0';
+ return lastc;
+ }
+
+ if (lastc == '\n') {
+ lineNum++;
+ linepos = 0;
+ }
+ else if (lastc == '\0') {
+ linepos = 0;
+ return lastc;
+ }
+
+ if (linepos >= linelen - 1) {
+ if (linelen == 0)
+ linelen = 128;
+ else
+ linelen *= 2;
+ line = (char *)realloc(line, linelen * sizeof(char));
+ }
+
+ get = fgetc(yyin);
+
+ if (get == EOF)
+ lastc = '\0';
+ else
+ lastc = get;
+
+ line[linepos++] = (char)get;
+
+ return lastc;
+}
+
+void
+unput(char c)
+{
+ peekc = c;
+}
+
+char
+lastinput(void)
+{
+ return lastc;
+}
+
+#endif
+
+int
+markpos(void)
+{
+ mark = linepos;
+ return mark;
+}
+
+int
+locateError(void)
+{
+ int i;
+
+ if (mark < 0) {
+ pmprintf("%s: Unrecoverable internal error in locateError()\n",
+ pmProgname);
+ pmflush();
+ exit(1);
+ }
+
+ if (feof(yyin)) {
+ return 0;
+ }
+
+ for (i = 0; i < mark; i++)
+ if (line[i] == '\n' || line[i] == '\0')
+ break;
+ else
+ pmprintf("%c", line[i]);
+ pmprintf("\n");
+
+ for (i = 0; i < mark - 1; i++)
+ if (line[i] == '\n' || line[i] == '\0')
+ break;
+ else if (line[i] == '\t')
+ pmprintf("\t");
+ else
+ pmprintf(" ");
+
+ pmprintf("^ at or near here\n");
+
+ return 1;
+}
+
+/* This is 'die now' version of yyerror - static and only used for errors
+ * in lexer, i.e those, where we've got no reasonable chance to do any
+ * recovery. */
+static void
+lexerror(const char * msg, const char * yytext)
+{
+ char *pos;
+
+ if ((pos = strstr(line, yytext)) != NULL) {
+ int i;
+
+ for (i = 0; (line[i] != '\n') && (line[i] != '\0'); i++)
+ pmprintf("%c", line[i]);
+ pmprintf("\n");
+
+ for (i = 0; line+i != pos; i++) {
+ if (line[i] == '\n' || line[i] == '\0')
+ break;
+ else if (line[i] == '\t')
+ pmprintf("\t");
+ else
+ pmprintf(" ");
+ }
+ pmprintf("^ at or near here\n");
+ }
+
+ pmprintf("%s: Fatal error in configuration file at line %d:\n\t%s\n",
+ pmProgname, lineNum + 1, msg);
+
+ pmflush();
+ exit(1);
+}
diff --git a/src/pmview/link.cpp b/src/pmview/link.cpp
new file mode 100644
index 0000000..bddfb0c
--- /dev/null
+++ b/src/pmview/link.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoRotationXYZ.h>
+#include <Inventor/nodes/SoCylinder.h>
+#include <Inventor/nodes/SoSphere.h>
+#include <Inventor/nodes/SoBaseColor.h>
+
+#include "togglemod.h"
+#include "link.h"
+#include "defaultobj.h"
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * Constructor for the Link.
+ * Note that we use different alignment for the base than the one
+ * for the scene. Base is always centered and we get the visual
+ * effect by addjusting the height of the cylinder(s).
+ \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+Link::Link (const DefaultObj & defs,
+ int c, int r,
+ int colSpan, int rowSpan,
+ Alignment a)
+ : BaseObj (false, defs, c, r, colSpan, rowSpan, center)
+ , _tag ("\n")
+{
+ _objtype |= LINK;
+
+ for ( int i=0; i < 3; i++) {
+ _color[i] = defs.baseColor(i);
+ }
+
+ align = a;
+ c1 = c2 = 0;
+ cellHeight = defs.baseHeight();
+ cellDepth = defs.baseHeight();
+ cellWidth = defs.baseHeight();
+
+ _width = colSpan * cellWidth;
+ _depth = rowSpan * cellDepth;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ *
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void
+Link::finishedAdd ()
+{
+ BaseObj::addBase (_root);
+
+ SoBaseColor * color = new SoBaseColor;
+ color->rgb.setValue (_color);
+ _root->addChild (color);
+
+ float radius = cellHeight * 0.4;
+
+ SoSeparator * mainsep = new SoSeparator;
+
+ SoTranslation * toCenter = new SoTranslation;
+ toCenter->translation.setValue (_width/2.0, cellHeight/2.0, _depth/2.0);
+ mainsep->addChild (toCenter);
+
+ if ( align == northEast || align == northWest ||
+ align == southEast || align == southWest ) {
+ SoRotationXYZ * mrot = new SoRotationXYZ;
+ mrot->axis = SoRotationXYZ::Y;
+ switch (align) {
+ case northEast:
+ mrot->angle = 0;
+ break;
+
+ case northWest:
+ mrot->angle = M_PI/2;
+ break;
+
+ case southWest:
+ mrot->angle = M_PI;
+ break;
+
+ case southEast:
+ mrot->angle = -(M_PI/2);
+ break;
+
+ default:
+ break;
+ }
+ mainsep->addChild (mrot);
+
+
+ // L-shape link - could leave without a separator, but
+ // geometry calculation becomes messy, so just add one.
+ SoSeparator * sp = new SoSeparator;
+
+ SoSphere * s = new SoSphere;
+ s->radius.setValue (radius);
+ sp->addChild (s);
+
+ t2 = new SoTranslation;
+ t3 = new SoTranslation;
+
+ c1 = new SoCylinder;
+ c1->radius.setValue (radius);
+
+ c2 = new SoCylinder;
+ c2->radius.setValue (radius);
+
+ if ( align == northEast || align == southWest ) {
+ c1->height.setValue (_depth/2.0);
+ c2->height.setValue (_width/2.0);
+
+ t2->translation.setValue (0, 0, _depth/-4.0);
+ t3->translation.setValue (_width/4.0, _depth/4.0, 0);
+ } else {
+ c1->height.setValue (_width/2.0);
+ c2->height.setValue (_depth/2.0);
+
+ t2->translation.setValue (0, 0, _width/-4.0);
+ t3->translation.setValue (_depth/4.0, _width/4.0, 0);
+ }
+
+ sp->addChild (t2);
+
+ SoRotationXYZ * r1 = new SoRotationXYZ;
+ r1->axis = SoRotationXYZ::X;
+ r1->angle = M_PI/2;
+
+ sp->addChild (r1);
+ sp->addChild (c1);
+ sp->addChild (t3);
+
+ SoRotationXYZ * r2 = new SoRotationXYZ;
+ r2->axis = SoRotationXYZ::Z;
+ r2->angle = M_PI/2;
+
+ sp->addChild (r2);
+ sp->addChild (c2);
+
+ mainsep->addChild (sp);
+ } else {
+ SoRotationXYZ * r = new SoRotationXYZ;
+
+ int h;
+
+ if ( align == north || align == south ) { // Vertical pipe
+ h = rows() * cellDepth;
+
+ r->axis = SoRotationXYZ::X;
+ r->angle = M_PI/2;
+ } else { // Horizontal pipe
+ h = cols() * cellWidth;
+
+ r->axis = SoRotationXYZ::Z;
+ r->angle = M_PI/2;
+ }
+
+ mainsep->addChild (r);
+
+ c1 = new SoCylinder;
+ c1->radius.setValue (radius);
+ c1->height.setValue (h);
+ mainsep->addChild (c1);
+ }
+
+
+ ToggleMod * m = new ToggleMod (mainsep, (const char *)_tag.toAscii());
+ _root->addChild (m->root());
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * Adjust the size of the link. Note, that we don't need to change the
+ * reported width and depth of an object (Grid does not cope with such
+ * changes very well) just adjust the length of cylinder(s).
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void
+Link::setTran (float x, float z, int w, int d)
+{
+ if ( c1 && c2 ) {
+ if ( align == northEast || align == southWest ) {
+ c1->height.setValue (d/2.0);
+ c2->height.setValue (w/2.0);
+
+ t2->translation.setValue (0, 0, d/-4.0);
+ t3->translation.setValue (w/4.0, d/4.0, 0);
+ } else {
+ c1->height.setValue (w/2.0);
+ c2->height.setValue (d/2.0);
+
+ t2->translation.setValue (0, 0, w/-4.0);
+ t3->translation.setValue (d/4.0, w/4.0, 0);
+ }
+ } else {
+ c1->height.setValue ((align == north || align == south ) ? d : w );
+ }
+
+ BaseObj::setTran (x, z, w, d);
+}
+
+void
+Link::setTag (const char * s)
+{
+ _tag = s;
+
+ if ( strchr (s, '\n') == NULL ) {
+ _tag.append ("\n");
+ }
+}
diff --git a/src/pmview/link.h b/src/pmview/link.h
new file mode 100644
index 0000000..dc4270e
--- /dev/null
+++ b/src/pmview/link.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _LINK_H
+#define _LINK_H
+
+#include "baseobj.h"
+
+class SoCylinder;
+
+class Link : public BaseObj
+{
+public:
+ Link (const DefaultObj &, int, int, int, int, Alignment);
+
+ void finishedAdd ();
+ void setTran (float, float, int, int);
+ int width () const { return _width; }
+ int depth () const { return _depth; }
+ const char * name () const { return "Link"; }
+ void setTag (const char *);
+
+ virtual Modulate *modObj() { return 0; }
+
+private:
+ Link();
+ Link (Link const &);
+ Link const& operator=(Link const &);
+
+ int cellWidth, cellHeight, cellDepth;
+ int _width, _depth;
+ Alignment align;
+
+ SoCylinder * c1, * c2;
+ SoTranslation * t2, * t3;
+ QString _tag;
+
+ float _color[3];
+};
+
+#endif
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();
+}
diff --git a/src/pmview/main.h b/src/pmview/main.h
new file mode 100644
index 0000000..ccd66b0
--- /dev/null
+++ b/src/pmview/main.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+#ifndef MAIN_H
+#define MAIN_H
+
+#include "pcp/pmapi.h"
+#include "pcp/impl.h"
+
+#include "qed_app.h"
+#include "main.h"
+#include "viewobj.h"
+#include "colorlist.h"
+#include "pmview.h"
+
+class QedApp;
+class View;
+class ModList;
+class SoQtExaminerViewer;
+
+typedef void (*TermCB)(int);
+
+typedef struct {
+ // Sampling
+ double viewDelta;
+ bool viewDeltaModified;
+ double loggerDelta;
+ bool loggerDeltaModified;
+
+ // Colors
+ QColor viewBackground;
+ QString viewBackgroundName;
+ bool viewBackgroundModified;
+ QColor viewHighlight;
+ QString viewHighlightName;
+ bool viewHighlightModified;
+ QColor gridBackground;
+ QString gridBackgroundName;
+ bool gridBackgroundModified;
+
+ // Toolbar
+ int initialToolbar;
+ bool initialToolbarModified;
+ int nativeToolbar;
+ bool nativeToolbarModified;
+ int toolbarLocation;
+ int toolbarLocationModified;
+ QStringList toolbarActions;
+ bool toolbarActionsModified;
+} Settings;
+
+// TODO: old X-resources...
+// ! Background color of read-only labels
+// !PmView+*readOnlyBackground: Black
+// ! Maximum value before saturation
+// ! The default of 1.05 allows for 5% error in the time delta when
+// ! determining rates, before values are deemed saturated.
+// PmView+*saturation: 1.05
+// ! Use fast anti-aliasing
+// PmView+*antiAliasSmooth: tree
+// ! Number of anti-aliasing passes: 1-255. Only 1 pass disables antialiasing.
+// PmView+*antiAliasPasses: 1
+// ! Grid, Bar and Stack object base borders
+// PmView+*baseBorderWidth: 8
+// PmView+*baseBorderDepth: 8
+// ! Height of Grid, Bar and Stack bases
+// PmView+*baseHeight: 2
+// ! Color of base plane
+// PmView+*baseColor: rgbi:0.15/0.15/0.15
+// ! Spacing between Bar blocks
+// PmView+*barSpaceWidth: 8
+// PmView+*barSpaceDepth: 8
+// ! Spacing between Bar base and labels
+// PmView+*barSpaceLabel: 6
+// ! Width and depth of Bar blocks
+// PmView+*barLength: 28
+// PmView+*barHeight: 80
+// ! Margin around a Label
+// PmView+*labelMargin: 5
+// ! Color of labels
+// PmView+*labelColor: rgbi:1.0/1.0/1.0
+// ! Width and depth of Grid columns and rows
+// PmView+*gridMinWidth: 20
+// PmView+*gridMinDepth: 20
+
+extern Settings globalSettings;
+extern void readSettings();
+extern void writeSettings();
+extern QColor nextColor(const QString &, int *);
+
+extern int Cflag;
+extern int Lflag;
+extern char *outgeometry;
+
+extern QString theConfigName; // Configuration file name
+extern FILE *theConfigFile; // Configuration file
+extern ColorList theColorLists; // ColorLists generated while parsing config
+extern float theGlobalScale; // Scale applied to entire scene
+extern FILE *theAltConfig; // Save the config file here
+extern bool theAltConfigFlag; // True when config is saved to temporary file
+extern QString theAltConfigName; // Name of the saved configuration file
+
+class SceneGroup;
+extern SceneGroup *liveGroup;
+extern SceneGroup *archiveGroup;
+extern SceneGroup *activeGroup;
+
+class PmView;
+extern PmView *pmview;
+
+class QedTimeControl;
+extern QedTimeControl *pmtime;
+
+extern int genInventor();
+extern char lastinput();
+extern char input();
+extern int markpos();
+extern int locateError();
+
+extern ViewObj *rootObj;
+extern int errorCount;
+extern int yyparse(void);
+extern FILE *yyin;
+
+extern float theScale; // The scale controls multiplier
+extern ModList *theModList; // List of modulated objects
+extern View *theView; // Viewer coordinator
+extern QedApp *theApp; // Our application object
+extern const int theBufferLen; // Length of theBuffer
+extern char theBuffer[]; // String buffer for anything
+extern const QString theDefaultFlags;
+
+int setup(const char *appname, int *argc, char **argv,
+ void *cmdopts, int numOpts, TermCB termCB);
+
+#define _POS_ __FILE__, __LINE__
+
+int warningMsg(const char *fileName, int line, const char *msg, ...);
+int errorMsg(const char *fileName, int line, const char *msg, ...);
+int fatalMsg(const char *fileName, int line, const char *msg, ...);
+
+#endif // MAIN_H
diff --git a/src/pmview/metriclist.cpp b/src/pmview/metriclist.cpp
new file mode 100644
index 0000000..fed2e40
--- /dev/null
+++ b/src/pmview/metriclist.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 "metriclist.h"
+#include "scenegroup.h"
+#include "main.h"
+
+static bool doMetricFlag = true;
+static MetricList *currentList;
+
+MetricList::~MetricList()
+{
+ int i;
+
+ for (i = 0; i < _metrics.size(); i++)
+ delete _metrics[i];
+ for (i = 0; i < _colors.size(); i++)
+ delete _colors[i];
+}
+
+MetricList::MetricList()
+: _metrics(), _colors(), _values(0)
+{
+}
+
+void
+MetricList::toString(const SbColor &color, QString &str)
+{
+ char buf[48];
+
+ const float *values = color.getValue();
+ sprintf(buf, "rgbi:%f/%f/%f", values[0], values[1], values[2]);
+ str = buf;
+}
+
+int
+MetricList::add(char const* metric, double scale)
+{
+ QmcMetric *ptr = new QmcMetric(activeGroup, metric, scale);
+
+ if (ptr->status() >= 0) {
+ _metrics.append(ptr);
+ _values += ptr->numValues();
+ }
+
+ return ptr->status();
+}
+
+int
+MetricList::add(char const* metric, double scale, int history)
+{
+ QmcMetric *ptr = new QmcMetric(activeGroup, metric, scale, history);
+
+ if (ptr->status() >= 0) {
+ _metrics.append(ptr);
+ _values += ptr->numValues();
+ }
+
+ return ptr->status();
+}
+
+int
+MetricList::add(pmMetricSpec *metric, double scale)
+{
+ QmcMetric *ptr = new QmcMetric(activeGroup, metric, scale);
+
+ if (ptr->status() >= 0) {
+ _metrics.append(ptr);
+ _values += ptr->numValues();
+ }
+
+ return ptr->status();
+}
+
+int
+MetricList::add(pmMetricSpec *metric, double scale, int history)
+{
+ QmcMetric *ptr = new QmcMetric(activeGroup, metric, scale, history);
+
+ if (ptr->status() >= 0) {
+ _metrics.append(ptr);
+ _values += ptr->numValues();
+ }
+
+ return ptr->status();
+}
+
+void
+MetricList::add(SbColor const& color)
+{
+ SbColor *ptr = new SbColor;
+
+ ptr->setValue(color.getValue());
+ _colors.append(ptr);
+}
+
+void
+MetricList::add(int packedcol)
+{
+ float tran = 0.0;
+ SbColor *ptr = new SbColor;
+
+ ptr->setPackedValue(packedcol, tran);
+ _colors.append(ptr);
+}
+
+void
+MetricList::resolveColors(AlignColor align)
+{
+ int need = 0;
+
+ switch(align) {
+ case perMetric:
+ need = _metrics.size();
+ break;
+ case perValue:
+ need = _values;
+ break;
+ case noColors:
+ default:
+ need = 0;
+ break;
+ }
+
+ if (_metrics.size() == 0)
+ return;
+
+ if (_colors.size() == 0 && need > 0)
+ add(SbColor(0.0, 0.0, 1.0));
+
+ if (_colors.size() < need) {
+ int o = 0;
+ int n = 0;
+
+ while (n < need) {
+ for (o = 0; o < _colors.size() && n < need; o++, n++) {
+ SbColor *ptr = new SbColor;
+ ptr->setValue(((SbColor *)_colors[o])->getValue());
+ _colors.append(ptr);
+ }
+ }
+ }
+}
+
+QTextStream&
+operator<<(QTextStream &os, MetricList const &list)
+{
+ int i;
+ float r, g, b;
+
+ for (i = 0; i < list._metrics.size(); i++) {
+ os << '[' << i << "]: ";
+ if (i < list._colors.size()) {
+ list._colors[i]->getValue(r, g, b);
+ os << r << ',' << g << ',' << b << ": ";
+ }
+ os << *(list._metrics[i]) << endl;
+ }
+ return os;
+}
+
+static void
+dometric(const char *name)
+{
+ if (currentList->add(name, 0.0) < 0)
+ doMetricFlag = false;
+}
+
+int
+MetricList::traverse(const char *str)
+{
+ pmMetricSpec *theMetric;
+ QString source;
+ char *msg;
+ int type = PM_CONTEXT_HOST;
+ SceneGroup *group = liveGroup;
+ int sts = 0;
+
+ sts = pmParseMetricSpec((char *)str, 0, (char *)0, &theMetric, &msg);
+ if (sts < 0) {
+ pmprintf("%s: Error: Unable to parse metric spec:\n%s\n",
+ pmProgname, msg);
+ free(msg);
+ return sts;
+ /*NOTREACHED*/
+ }
+
+ // If the metric has instances, then it cannot be traversed
+ if (theMetric->ninst) {
+ sts = add(theMetric, 0.0);
+ }
+ else {
+ if (theMetric->isarch == 2) {
+ type = PM_CONTEXT_LOCAL;
+ }
+ else if (theMetric->source && strlen(theMetric->source) > 0) {
+ if (theMetric->isarch == 1) {
+ type = PM_CONTEXT_ARCHIVE;
+ group = archiveGroup;
+ }
+ }
+
+ currentList = this;
+ source = theMetric->source;
+ sts = group->use(type, source);
+ if (sts >= 0) {
+ sts = pmTraversePMNS(theMetric->metric, dometric);
+ if (sts >= 0 && doMetricFlag == false)
+ sts = -1;
+ else if (sts < 0)
+ pmprintf("%s: Error: %s%c%s: %s\n",
+ pmProgname,
+ group->context()->source().sourceAscii(),
+ type == PM_CONTEXT_ARCHIVE ? '/' : ':',
+ theMetric->metric,
+ pmErrStr(sts));
+ }
+ }
+
+ free(theMetric);
+
+ return sts;
+}
diff --git a/src/pmview/metriclist.h b/src/pmview/metriclist.h
new file mode 100644
index 0000000..8ef1eee
--- /dev/null
+++ b/src/pmview/metriclist.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _METRICLIST_H_
+#define _METRICLIST_H_
+
+#include <sys/types.h>
+#include <Inventor/SbColor.h>
+#include "qmc_metric.h"
+#include "qmc_source.h"
+
+typedef QList<QmcMetric *> MetricsList;
+typedef QList<SbColor *> SbColorList;
+
+class MetricList
+{
+public:
+
+ enum AlignColor { noColors, perMetric, perValue };
+
+private:
+
+ MetricsList _metrics;
+ SbColorList _colors;
+ int _values;
+
+public:
+
+ ~MetricList();
+
+ MetricList();
+
+ int numMetrics() const
+ { return _metrics.size(); }
+ int numValues() const
+ { return _values; }
+ int numColors() const
+ { return _colors.size(); }
+
+ const QmcMetric &metric(int i) const
+ { return *(_metrics[i]); }
+ QmcMetric &metric(int i)
+ { return *(_metrics[i]); }
+
+ const SbColor &color(int i) const
+ { return *(_colors[i]); }
+ SbColor &color(int i)
+ { return *(_colors[i]); }
+ void color(int i, QString &str) const;
+
+ int add(char const* metric, double scale);
+ int add(char const* metric, double scale, int history);
+ int add(pmMetricSpec *metric, double scale);
+ int add(pmMetricSpec *metric, double scale, int history);
+ int traverse(const char *metric);
+
+ void add(SbColor const& color);
+ void add(int packedcol);
+
+ void resolveColors(AlignColor align = perMetric);
+
+ static void toString(const SbColor &color, QString &str);
+
+ friend QTextStream& operator<<(QTextStream&, MetricList const &);
+
+private:
+
+ MetricList(const MetricList &);
+ const MetricList &operator=(const MetricList &);
+ // Never defined
+};
+
+#endif /* _METRICLIST_H_ */
diff --git a/src/pmview/modlist.cpp b/src/pmview/modlist.cpp
new file mode 100644
index 0000000..05a9c3d
--- /dev/null
+++ b/src/pmview/modlist.cpp
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/SoPath.h>
+#include <Inventor/SoPickedPoint.h>
+#include <Inventor/events/SoLocation2Event.h>
+#include <Inventor/nodes/SoEventCallback.h>
+#include <Inventor/nodes/SoSelection.h>
+#include <Inventor/nodes/SoIndexedFaceSet.h>
+#include <Inventor/actions/SoBoxHighlightRenderAction.h>
+#include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
+#include "modlist.h"
+
+#include <iostream>
+using namespace std;
+
+const QString ModList::theBogusId = "TOP";
+const char ModList::theModListId = 'i';
+
+ModList *theModList;
+SoNodeList elementalNodeList;
+
+ModList::~ModList()
+{
+}
+
+ModList::ModList(SoQtViewer *viewer,
+ SelCallBack selCB,
+ SelInvCallBack selInvCB,
+ SelInvCallBack deselInvCB)
+: _viewer(viewer),
+ _selCB(selCB),
+ _selInvCB(selInvCB),
+ _deselInvCB(deselInvCB),
+ _root(0),
+ _selection(0),
+ _motion(0),
+ _rendAct(0),
+ _list(),
+ _selList(),
+ _current(1),
+ _numSel(0),
+ _oneSel(0),
+ _allFlag(false),
+ _allId(0)
+{
+ QSettings modSettings;
+ modSettings.beginGroup(pmProgname);
+ QString sval = modSettings.value("saturation", QString("")).toString();
+ modSettings.endGroup();
+
+ bool ok;
+ double err = sval.toFloat(&ok);
+ if (!ok || err > 0.0)
+ theNormError = err;
+
+ _root = new SoSeparator;
+ _root->ref();
+}
+
+void
+ModList::setRoot(SoSeparator *root)
+{
+ _selection = new SoSelection;
+ _root->addChild(_selection);
+
+ _selection->policy = SoSelection::SHIFT;
+ _selection->addSelectionCallback(&ModList::selCB, this);
+ _selection->addDeselectionCallback(&ModList::deselectCB, this);
+
+ _motion = new SoEventCallback;
+ _motion->addEventCallback(SoLocation2Event::getClassTypeId(),
+ &ModList::motionCB, this);
+ _selection->addChild(_motion);
+
+ root->setName((SbName)(const char *)theBogusId.toAscii());
+ _selection->addChild(root);
+
+ SoBoxHighlightRenderAction *rendAct = new SoBoxHighlightRenderAction;
+ _viewer->setGLRenderAction(rendAct);
+ _viewer->redrawOnSelectionChange(_selection);
+}
+
+const char *
+ModList::add(Modulate *obj)
+{
+ static char buf[32];
+ int len = _list.size();
+ int zero = 0;
+
+ _list.append(obj);
+ _selList.append(zero);
+
+ if (_current >= len)
+ _current = _list.size();
+
+ sprintf(buf, "%c%d", theModListId, _list.size() - 1);
+ return buf;
+}
+
+void
+ModList::refresh(bool fetchFlag)
+{
+ for (int i = 0; i < _list.size(); i++)
+ _list[i]->refresh(fetchFlag);
+ for (int n=elementalNodeList.getLength()-1; n >= 0; n--) {
+ elementalNodeList[n]->doAction(_viewer->getGLRenderAction());
+ }
+}
+
+void
+ModList::dumpSelections(QTextStream &os) const
+{
+ int i;
+ int count = 0;
+
+ os << _numSel << " selections (SoSelections.numSelections = "
+ << _selection->getNumSelected() << "), allFlag = "
+ << (_allFlag == true ? "true" : "false") << endl;
+ for (i = 0; i < _selList.size(); i++)
+ if (_selList[i] > 0) {
+ count += _selList[i];
+ os << '[' << i << "]: ";
+ if (_numSel == 1 && _oneSel == i)
+ os << '*';
+ os << *(_list[i]) << endl;
+ }
+
+ assert(count == _numSel);
+}
+
+QTextStream &
+operator<<(QTextStream &os, const ModList &rhs)
+{
+ int i;
+
+ for (i = 0; i < rhs._list.size(); i++)
+ os << '[' << i << "]: " << rhs[i] << endl;
+ return os;
+}
+
+int
+ModList::findToken(const SoPath *path)
+{
+ SoNode *node = NULL;
+ char *str = NULL;
+ int id = -1;
+ int i;
+ char c;
+
+ for (i = path->getLength() - 1; i >= 0; --i) {
+ node = path->getNode(i);
+ str = (char *)(node->getName().getString());
+ if (strlen(str) && str[0] == theModListId) {
+ sscanf(str, "%c%d", &c, &id);
+ break;
+ }
+ }
+
+ return id;
+}
+
+void
+ModList::selCB(void *ptrToThis, SoPath *path)
+{
+ ModList *me = (ModList *)ptrToThis;
+ Modulate *obj;
+ int oldCount;
+ int id;
+
+ if (!me->_allFlag)
+ id = ModList::findToken(path);
+ else
+ id = me->_allId;
+
+ if (id < 0) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::selCB: Nothing selected" << endl;
+#endif
+
+ return;
+ /*NOTREACHED*/
+ }
+ else if (!me->_allFlag) {
+
+ obj = me->_list[id];
+ oldCount = me->_selList[id];
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::selCB: Before Selected [" << id << "] = "
+ << *obj << endl
+ << "oldCount = " << oldCount << ", _numSel = "
+ << me->_numSel << ", _allFlag = false" << endl;
+#endif
+
+ me->_selList[id] = obj->select(path);
+
+ me->_numSel += me->_selList[id] - oldCount;
+ if (me->_numSel == 1)
+ me->_oneSel = id;
+ }
+
+ if (!me->_allFlag)
+ (*(me->_selCB))(me, true);
+
+ if (me->_selInvCB != NULL)
+ (*(me->_selInvCB))(me, path);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ cerr << "ModList::selCB: After Selected [" << id << "] " << endl
+ << "oldCount = " << oldCount << ", _numSel = "
+ << me->_numSel << ", _allFlag = "
+ << (me->_allFlag == true ? "true" : "false") << ", _allId = "
+ << me->_allId << endl;
+ cerr << "ModList::selCB: selection state:" << endl;
+ me->dumpSelections(cerr);
+ }
+#endif
+}
+
+void
+ModList::deselectCB(void *ptrToThis, SoPath *path)
+{
+ ModList *me = (ModList *)ptrToThis;
+ Modulate *obj;
+ int oldCount;
+ int i;
+ int id;
+
+ id = findToken(path);
+
+ if (id < 0) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::deselectCB: Nothing deselected" << endl;
+#endif
+
+ return;
+ /*NOTREACHED*/
+ }
+
+ obj = me->_list[id];
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::deselectCB: Deselected [" << id << "] = "
+ << *obj << endl;
+#endif
+
+ oldCount = me->_selList[id];
+ me->_selList[id] = obj->remove(path);
+ me->_numSel -= oldCount - me->_selList[id];
+ if (me->_numSel == 1) {
+ for (i = 0; i < me->_selList.size(); i++)
+ if (me->_selList[i] == 1)
+ me->_oneSel = i;
+ }
+
+ if (me->_numSel == 0)
+ me->_current = me->_list.size();
+
+ if (me->_numSel < 2)
+ (*(me->_selCB))(me, true);
+
+ if (me->_deselInvCB != NULL)
+ (*(me->_deselInvCB))(me, path);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ cerr << "ModList::deselectCB: selection state:" << endl;
+ me->dumpSelections(cerr);
+ }
+#endif
+}
+
+void
+ModList::motionCB(void *ptrToThis, SoEventCallback *theEvent)
+{
+ ModList *me = (ModList *)ptrToThis;
+ const SoPickedPoint *pick = NULL;
+ SoPath *path = NULL;
+ int id = -1;
+
+ // If one item is selected, return as we aren't interested
+ if (me->_numSel == 1)
+ return;
+
+ pick = theEvent->getPickedPoint();
+ if (pick != NULL) {
+ path = pick->getPath();
+ if (path != NULL)
+ id = ModList::findToken(path);
+ }
+
+ // Nothing selected that we are interested in
+ if (id < 0) {
+ // Deselect anything selected
+ if (me->_current < me->size()) {
+ (*me)[me->_current].removeInfo(path);
+ me->_current = me->size();
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::motionCB: remove object " << id << endl;
+#endif
+ }
+ }
+ else if (me->_current != id) {
+ if (me->_current < me->size())
+ (*me)[me->_current].removeInfo(path);
+ me->_current = id;
+ (*me)[me->_current].selectInfo(path);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::motionCB: new object " << id << endl;
+#endif
+ }
+ else {
+ (*me)[me->_current].selectInfo(path);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::motionCB: same object " << id << endl;
+#endif
+ }
+
+ // Note: the call to _selCB below used to only be done if the guard
+ // if (old != me->_current)
+ // is true. But this does not work for stacked bars because
+ // the object is the same even though the mouse has moved over
+ // a different block in the same stack. Hence the metric info
+ // text window was not being updated for the mouse motion CB.
+ // Since the render method for the metricLabel only updates the
+ // text widget if the text has actually changed, it seems to me
+ // that it is safe to call the selCB unconditionally and there
+ // wont be any "flicker" problems.
+ // -- markgw 15 oct 1997
+ //
+ (*(me->_selCB))(me, false);
+}
+
+void
+ModList::infoText(QString &str) const
+{
+ if (_current >= _list.size() && _numSel != 1)
+ str = "";
+ else if (_numSel == 1)
+ _list[_oneSel]->infoText(str, true);
+ else
+ _list[_current]->infoText(str, false);
+}
+
+void
+ModList::launch(Launch &launch, bool all) const
+{
+ int i;
+
+ if (all == false && _numSel > 0) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::launch: launching for " << _numSel
+ << " objects" << endl;
+#endif
+
+ for (i = 0; i < _selList.size(); i++) {
+ if (_selList[i] > 0)
+ _list[i]->launch(launch, false);
+ }
+ }
+ else {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::launch: launching for all objects" << endl;
+#endif
+
+ for (i = 0; i < _list.size(); i++)
+ _list[i]->launch(launch, true);
+ }
+}
+
+void
+ModList::record(Record &rec) const
+{
+ int i;
+
+ for (i = 0; i < _list.size(); i++)
+ _list[i]->record(rec);
+}
+
+bool
+ModList::selections() const
+{
+ if (_numSel)
+ return true;
+
+ return false;
+}
+
+const SoPath *
+ModList::oneSelPath() const
+{
+ return (_numSel == 1 ? _selection->getPath(0) : NULL);
+}
+
+void
+ModList::deselectPath(SoPath *path)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::deselectPath:" << endl;
+#endif
+
+ _selection->deselect(path);
+ deselectCB(this, path);
+}
+
+void
+ModList::selectAllId(SoNode *node, int count)
+{
+ SoPath *path = new SoPath(node);
+
+ _allId = findToken(path);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "ModList::selectAllId: Select All on " << _allId << endl;
+#endif
+
+ if (_allId > 0) {
+ _numSel += count - _selList[_allId];
+ _selList[_allId] = count;
+ if (_numSel == 1)
+ _oneSel = _allId;
+ }
+
+ path->unref();
+}
+
+void
+ModList::selectSingle(SoNode *node)
+{
+ _selection->select(node);
+}
+
+void
+ModList::selectAllOff()
+{
+ _allFlag = false;
+ _allId = _list.size();
+ (*_selCB)(this, true);
+}
diff --git a/src/pmview/modlist.h b/src/pmview/modlist.h
new file mode 100644
index 0000000..72d2319
--- /dev/null
+++ b/src/pmview/modlist.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _MODLIST_H_
+#define _MODLIST_H_
+
+#include <Inventor/SoLists.h>
+#include "modulate.h"
+
+class SoQtViewer;
+class SoSelection;
+class SoEventCallback;
+class SoBoxHighlightRenderAction;
+class SoPath;
+class SoPickedPoint;
+class SoSeparator;
+class ModList;
+class Launch;
+class Record;
+
+typedef void (*SelCallBack)(ModList *, bool);
+typedef void (*SelInvCallBack)(ModList *, SoPath *);
+
+typedef QList<Modulate *> ModulateList;
+extern SoNodeList elementalNodeList;
+
+class ModList
+{
+private:
+
+ static const QString theBogusId;
+ static const char theModListId;
+
+ SoQtViewer *_viewer;
+ SelCallBack _selCB;
+ SelInvCallBack _selInvCB;
+ SelInvCallBack _deselInvCB;
+ SoSeparator *_root;
+ SoSelection *_selection;
+ SoEventCallback *_motion;
+ SoBoxHighlightRenderAction *_rendAct;
+
+ ModulateList _list;
+ QList<int> _selList;
+ int _current;
+ int _numSel;
+ int _oneSel;
+
+ bool _allFlag;
+ int _allId;
+
+public:
+
+ ~ModList();
+
+ ModList(SoQtViewer *viewer, SelCallBack selCB,
+ SelInvCallBack selInvCB = NULL, SelInvCallBack deselInvCB = NULL);
+
+ int size() const
+ { return _list.size(); }
+ int numSelected() const
+ { return _numSel; }
+
+ SoSeparator *root()
+ { return _root; }
+ void setRoot(SoSeparator *root);
+
+ SoSelection *selector() const
+ { return _selection; }
+
+ const char *add(Modulate *obj);
+
+ const Modulate &operator[](int i) const
+ { return *(_list[i]); }
+ Modulate &operator[](int i)
+ { return *(_list[i]); }
+
+ const Modulate &current() const
+ { return *(_list[_current]); }
+ Modulate &current()
+ { return *(_list[_current]); }
+
+ void refresh(bool fetchFlag);
+
+ void infoText(QString &str) const;
+
+ void launch(Launch &launch, bool all = false) const;
+ void record(Record &rec) const;
+
+ void dumpSelections(QTextStream &os) const;
+ bool selections() const;
+
+ void selectAllOn()
+ { _allFlag = true; _allId = _list.size(); }
+ void selectAllId(SoNode *node, int count);
+ void selectSingle(SoNode *node);
+ void selectAllOff();
+
+ friend QTextStream &operator<<(QTextStream &os, const ModList &rhs);
+
+ static void deselectCB(void *me, SoPath *path);
+
+ // Sprouting support
+
+ // Get path to single selection
+ const SoPath *oneSelPath() const;
+
+ void deselectPath(SoPath *path);
+
+private:
+
+ static void selCB(void *me, SoPath *path);
+ static void motionCB(void *me, SoEventCallback *event);
+ static int findToken(const SoPath *path);
+
+ ModList(const ModList &);
+ const ModList &operator=(const ModList &);
+ // Never defined
+};
+
+extern ModList *theModList;
+
+#endif /* _MODLIST_H_ */
diff --git a/src/pmview/modobj.h b/src/pmview/modobj.h
new file mode 100644
index 0000000..0d65f4b
--- /dev/null
+++ b/src/pmview/modobj.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _MODOBJ_H_
+#define _MODOBJ_H_
+
+#include "baseobj.h"
+
+class ModObj : public BaseObj
+{
+public:
+ ModObj(bool onFlag,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols = 1, int rows = 1,
+ BaseObj::Alignment align = BaseObj::center)
+ : BaseObj (onFlag, defaults, x, y, cols, rows, align)
+ , _history(0)
+ , _colors()
+ , _metrics ()
+ { _objtype |= MODOBJ; }
+
+ void setColorList(const char *list) { _colors = list; }
+ void addMetric(const char * m, double s) { _metrics.add(m, s, _history); }
+ void setHistory(int history) { _history = history; }
+
+protected:
+ int _history;
+ QString _colors;
+ MetricList _metrics;
+};
+#endif
diff --git a/src/pmview/modulate.cpp b/src/pmview/modulate.cpp
new file mode 100644
index 0000000..8e3fb98
--- /dev/null
+++ b/src/pmview/modulate.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoSelection.h>
+#include "modulate.h"
+#include "modlist.h"
+
+#include <iostream>
+using namespace std;
+
+double theNormError = 1.05;
+
+const QString Modulate::theErrorText = "Metric Unavailable";
+const QString Modulate::theStartText = "Metric has not been fetched from source";
+const float Modulate::theDefErrorColor[] = {0.2, 0.2, 0.2};
+const float Modulate::theDefSaturatedColor[] = {1.0, 1.0, 1.0};
+const double Modulate::theMinScale = 0.01;
+
+Modulate::~Modulate()
+{
+}
+
+Modulate::Modulate(const char *metric, double scale,
+ MetricList::AlignColor align)
+: _sts(0), _metrics(0), _root(0)
+{
+ _metrics = new MetricList();
+ _sts = _metrics->add(metric, scale);
+ if (_sts >= 0) {
+ _metrics->resolveColors(align);
+ _saturatedColor.setValue(theDefSaturatedColor);
+ }
+ _errorColor.setValue(theDefErrorColor);
+}
+
+Modulate::Modulate(const char *metric, double scale,
+ const SbColor &color,
+ MetricList::AlignColor align)
+: _sts(0), _metrics(0), _root(0)
+{
+ _metrics = new MetricList();
+ _sts = _metrics->add(metric, scale);
+ if (_sts >= 0) {
+ _metrics->add(color),
+ _metrics->resolveColors(align);
+ }
+ _saturatedColor.setValue(theDefSaturatedColor);
+ _errorColor.setValue(theDefErrorColor);
+}
+
+Modulate::Modulate(MetricList *list)
+: _sts(0), _metrics(list), _root(0)
+{
+ _saturatedColor.setValue(theDefSaturatedColor);
+ _errorColor.setValue(theDefErrorColor);
+}
+
+const char *
+Modulate::add()
+{
+ const char *str = theModList->add(this);
+ _root->setName((SbName)str);
+ return str;
+}
+
+QTextStream &
+operator<<(QTextStream & os, const Modulate &rhs)
+{
+ rhs.dump(os);
+ return os;
+}
+
+void
+Modulate::dumpState(QTextStream &os, Modulate::State state) const
+{
+ switch(state) {
+ case Modulate::start:
+ os << "Start";
+ break;
+ case Modulate::error:
+ os << "Error";
+ break;
+ case Modulate::saturated:
+ os << "Saturated";
+ break;
+ case Modulate::normal:
+ os << "Normal";
+ break;
+ default:
+ os << "Unknown";
+ break;
+ }
+}
+
+void
+Modulate::record(Record &rec) const
+{
+#if 1 // TODO
+ (void)rec;
+#else // TODO
+ int i;
+
+ if (_metrics != NULL)
+ for (i = 0; i < _metrics->numMetrics(); i++) {
+ const QmcMetric &metric = _metrics->metric(i);
+ rec.add(metric.context()->source().sourceAscii(),
+ (const char *)metric.spec(false, true).toAscii());
+ }
+#endif
+}
+
+void
+Modulate::selectAll()
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "Modulate::selectAll: selectAll for " << *this << endl;
+#endif
+
+ theModList->selectAllId(_root, 1);
+ theModList->selectSingle(_root);
+}
diff --git a/src/pmview/modulate.h b/src/pmview/modulate.h
new file mode 100644
index 0000000..b8e6b7d
--- /dev/null
+++ b/src/pmview/modulate.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _MODULATE_H_
+#define _MODULATE_H_
+
+#include <Inventor/SbString.h>
+#include "metriclist.h"
+
+class SoSeparator;
+class SoPath;
+class Launch;
+class Record;
+
+extern double theNormError;
+extern float theScale;
+
+class Modulate
+{
+public:
+
+ enum State { start, error, saturated, normal };
+
+protected:
+
+ static const QString theErrorText;
+ static const QString theStartText;
+ static const float theDefErrorColor[];
+ static const float theDefSaturatedColor[];
+ static const double theMinScale;
+
+ int _sts;
+ MetricList *_metrics;
+ SoSeparator *_root;
+ SbColor _errorColor;
+ SbColor _saturatedColor;
+
+public:
+
+ virtual ~Modulate();
+
+ Modulate(const char *metric, double scale,
+ MetricList::AlignColor align = MetricList::perMetric);
+
+ Modulate(const char *metric, double scale, const SbColor &color,
+ MetricList::AlignColor align = MetricList::perMetric);
+
+ Modulate(MetricList *list);
+
+ int status() const
+ { return _sts; }
+ const SoSeparator *root() const
+ { return _root; }
+ SoSeparator *root()
+ { return _root; }
+
+ int numValues() const
+ { return _metrics->numValues(); }
+
+ const char *add();
+
+ void setErrorColor(const SbColor &color)
+ { _errorColor.setValue(color.getValue()); }
+ void setSaturatedColor(const SbColor &color)
+ { _saturatedColor.setValue(color.getValue()); }
+
+ virtual void refresh(bool fetchFlag) = 0;
+
+ // Return the number of objects still selected
+ virtual void selectAll();
+ virtual int select(SoPath *)
+ { return 0; }
+ virtual int remove(SoPath *)
+ { return 0; }
+
+ // Should expect selectInfo calls to different paths without
+ // previous removeInfo calls
+ virtual void selectInfo(SoPath *)
+ {}
+ virtual void removeInfo(SoPath *)
+ {}
+
+ virtual void infoText(QString &str, bool selected) const = 0;
+
+ virtual void launch(Launch &launch, bool all) const = 0;
+ virtual void record(Record &rec) const;
+
+ virtual void dump(QTextStream &) const
+ {}
+ void dumpState(QTextStream &os, State state) const;
+
+ friend QTextStream &operator<<(QTextStream &os, const Modulate &rhs);
+
+protected:
+
+ static void add(Modulate *obj);
+
+private:
+
+ Modulate();
+ Modulate(const Modulate &);
+ const Modulate &operator=(const Modulate &);
+ // Never defined
+};
+
+#endif /* _MODULATE_H_ */
diff --git a/src/pmview/pcpcolor.cpp b/src/pmview/pcpcolor.cpp
new file mode 100644
index 0000000..85a313e
--- /dev/null
+++ b/src/pmview/pcpcolor.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/actions/SoCallbackAction.h>
+#include <Inventor/actions/SoGLRenderAction.h>
+#include <Inventor/bundles/SoMaterialBundle.h>
+#include <Inventor/elements/SoEmissiveColorElement.h>
+
+#include "pcpcolor.h"
+#include "scenegroup.h"
+#include "main.h"
+
+SO_NODE_SOURCE(PCPColor);
+// Initializes the PCPColor class. This is a one-time thing that is
+// done after database initialization and before any instance of
+// this class is constructed.
+void
+PCPColor::initClass()
+{
+ // Initialize type id variables. The arguments to the macro
+ // are: the name of the node class, the class this is derived
+ // from, and the name registered with the type of the parent
+ // class.
+ SO_NODE_INIT_CLASS(PCPColor, SoNode, "Node");
+}
+// Constructor
+PCPColor::PCPColor()
+{
+ // Do standard constructor tasks
+ SO_NODE_CONSTRUCTOR(PCPColor);
+
+ SO_NODE_ADD_FIELD(maxValue, (1.0));
+ SO_NODE_ADD_FIELD(color, (1.0, 1.0, 1.0));
+ SO_NODE_ADD_FIELD(metric, (""));
+
+ // SbString s = metric.getValue();
+ SbString *s = new SbString("kernel.all.cpu.user");
+
+ double scale = (double)maxValue.getValue();
+ theMetric = new QmcMetric(activeGroup, s->getString(), scale);
+ elementalNodeList.append(this);
+}
+// Destructor
+PCPColor::~PCPColor()
+{
+}
+// Implements GL render action.
+void
+PCPColor::GLRender(SoGLRenderAction *action)
+{
+ // Set the elements in the state correctly. Note that we
+ // prefix the call to doAction() with the class name. This
+ // avoids problems if someone derives a new class from the
+ // PCPColor node and inherits the GLRender() method; PCPColor's
+ // doAction() will still be called in that case.
+
+ PCPColor::doAction(action);
+
+ // For efficiency, Inventor nodes make sure that the first
+ // defined material is always in GL, so shapes do not have to
+ // send the first material each time. (This keeps caches from
+ // being dependent on material values in many cases.) The
+ // SoMaterialBundle class allows us to do this easily.
+ SoMaterialBundle mb(action);
+ mb.forceSend(0);
+}
+// Implements callback action.
+void
+PCPColor::callback(SoCallbackAction *action)
+{
+ // Set the elements in the state correctly.
+ PCPColor::doAction(action);
+}
+
+// Typical action implementation - it sets the correct element
+// in the action's traversal state. We assume that the element
+// has been enabled.
+void
+PCPColor::doAction(SoAction *action)
+{
+ theMetric->update();
+ float f = theMetric->realValue(0);
+ f /= maxValue.getValue() + 0.001;
+ emissiveColor = color.getValue() * f;
+ if (action->getState())
+ SoEmissiveColorElement::set(action->getState(), this, 1, &emissiveColor);
+
+ touch();
+}
diff --git a/src/pmview/pcpcolor.h b/src/pmview/pcpcolor.h
new file mode 100644
index 0000000..85d47df
--- /dev/null
+++ b/src/pmview/pcpcolor.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _PCPCOLOR_H_
+#define _PCPCOLOR_H_
+
+#include <Inventor/SbColor.h>
+#include <Inventor/fields/SoSFString.h>
+#include <Inventor/fields/SoSFColor.h>
+#include <Inventor/fields/SoSFFloat.h>
+#include <Inventor/nodes/SoSubNode.h>
+
+#include "main.h"
+#include "modlist.h"
+
+class PCPColor : public SoNode {
+ SO_NODE_HEADER(PCPColor);
+ public:
+ // Fields:
+ SoSFString metric; // PCP metric spec
+ SoSFFloat maxValue;
+ SoSFColor color; // Color of glow
+
+ // Initializes this class for use in scene graphs. This
+ // should be called after database initialization and before
+ // any instance of this node is constructed.
+ static void initClass();
+ // Constructor
+ PCPColor();
+ protected:
+ QmcMetric *theMetric;
+
+ // These implement supported actions. The only actions that
+ // deal with materials are the callback and GL render
+ // actions. We will inherit all other action methods from
+ // SoNode.
+ virtual void GLRender(SoGLRenderAction *action);
+ virtual void callback(SoCallbackAction *action);
+ // This implements generic traversal of PCPColor node, used in
+ // both of the above methods.
+ virtual void doAction(SoAction *action);
+
+ private:
+ // Destructor. Private to keep people from trying to delete
+ // nodes, rather than using the reference count mechanism.
+ virtual ~PCPColor();
+ SbColor emissiveColor;
+};
+
+#endif /* _PCPCOLOR_H_ */
diff --git a/src/pmview/pipeobj.cpp b/src/pmview/pipeobj.cpp
new file mode 100644
index 0000000..e6e8886
--- /dev/null
+++ b/src/pmview/pipeobj.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoRotationXYZ.h>
+#include <Inventor/nodes/SoCylinder.h>
+#include <Inventor/nodes/SoCube.h>
+#include <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoScale.h>
+
+#include "stackmod.h"
+#include "togglemod.h"
+#include "pipeobj.h"
+#include "defaultobj.h"
+#include "colorlist.h"
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * Constructor for Pipe.
+ * Note that similar to Link, pipes are always centered
+ * relative to the grid. The aligment is used to decide
+ * which end of pipe is decorated and in what direction
+ * pipe is oriented.
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+PipeObj::PipeObj (const DefaultObj & defs,
+ int c, int r,
+ int colSpan, int rowSpan,
+ BaseObj::Alignment align)
+ : ModObj (false, defs, c, r, colSpan, rowSpan, center)
+ , _align(align)
+ , _tag ("\n")
+{
+ _objtype |= PIPEOBJ;
+
+ for ( int i=0; i < 3; i++) {
+ _color[i] = defs.baseColor(i);
+ }
+
+ _cylTrans = 0;
+ _origt = 0;
+ _cyl = 0;
+ _stackHeight = defs.pipeLength();
+ cellHeight = defs.baseHeight();
+
+ if ( _align == north || _align == south ) {
+ cellWidth = defs.baseHeight();
+ cellDepth = (defs.pipeLength() < cellHeight) ?
+ cellHeight : defs.pipeLength();
+ } else {
+ cellWidth = (defs.pipeLength() < cellHeight) ?
+ cellHeight : defs.pipeLength();
+ cellDepth = defs.baseHeight();
+ }
+
+ _width = colSpan * cellWidth;
+ _depth = rowSpan * cellDepth;
+
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ *
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void
+PipeObj::finishedAdd ()
+{
+ BaseObj::addBase (_root);
+
+ int h;
+ SoSeparator * sp = new SoSeparator;
+ _root->addChild (sp);
+
+ SoTranslation * st = new SoTranslation;
+ st->translation.setValue (_width/2.0, cellHeight/2.0, _depth/2.0);
+ sp->addChild (st);
+
+ SoRotationXYZ * r = new SoRotationXYZ;
+ if ( _align == north || _align == south ) { // Vertical Pipe
+ h = _depth;
+
+ r->axis = SoRotationXYZ::X;
+ r->angle = M_PI/((_align == north) ? 2 : -2);
+ } else { // Horizontal pipe
+ h = _width;
+
+ r->axis = SoRotationXYZ::Z;
+ r->angle = M_PI/((_align == east) ? 2 : -2);
+ }
+ sp->addChild (r);
+
+ SoSeparator * sceneSp = new SoSeparator;
+ sp->addChild (sceneSp);
+
+ _origt = new SoTranslation;
+ _origt->translation.setValue (0, -h/2.0, 0);
+ sceneSp->addChild (_origt);
+
+ if (_metrics.numMetrics() ) {
+ SoSeparator * stacksp = new SoSeparator;
+ const ColorSpec * colSpec;
+ SoScale *scale = new SoScale();
+ scale->scaleFactor.setValue(cellHeight*0.8, _stackHeight,
+ cellHeight*0.8);
+ stacksp->addChild(scale);
+
+ if ((colSpec = theColorLists.list((const char *)_colors.toAscii()))) {
+ if (colSpec->_scale)
+ pmprintf(
+ "%s: Warning: Color scale cannot be applied to pipe\n",
+ pmProgname);
+ else {
+ for (int i = 0; i < colSpec->_list.size(); i++)
+ _metrics.add(*(colSpec->_list)[i]);
+ }
+ } else {
+ pmprintf("%s: Warning: No colours specified for pipe"
+ "defaulting to blue.\n", pmProgname);
+ }
+
+ _metrics.resolveColors(MetricList::perValue);
+
+ StackMod * _stack = new StackMod(&_metrics, ViewObj::object (cylinder),
+ StackMod::fixed);
+ _stack->setFillColor(_color);
+ _stack->setFillText((const char *)_tag.toAscii());
+
+ stacksp->addChild(_stack->root());
+ sceneSp->addChild(stacksp);
+
+ BaseObj::add(_stack);
+ ViewObj::theNumModObjects++;
+ } else {
+ pmprintf("%s: Error: no metrics for pipe\n", pmProgname);
+ }
+
+ SoBaseColor * color = new SoBaseColor;
+ color->rgb.setValue (_color);
+ sceneSp->addChild (color);
+
+ _cylTrans = new SoTranslation;
+ _cylTrans->translation.setValue (0, (h+_stackHeight)/2.0, 0);
+ sceneSp->addChild (_cylTrans);
+
+
+ _cyl = new SoCylinder;
+ _cyl->radius.setValue (cellHeight*0.4);
+ _cyl->height.setValue (h - _stackHeight);
+
+ // In theory, something like "StaticMod", i.e no metrics, no
+ // nothing should be provided, but togglemod seems to be
+ // working Ok, so....
+ ToggleMod * m = new ToggleMod (_cyl, (const char *)_tag.toAscii());
+ sceneSp->addChild (m->root());
+}
+
+void
+PipeObj::setTran (float x, float z, int w, int d)
+{
+ if ( _cyl ) {
+ float h = (_align == north || _align == south) ? d : w;
+
+ _cylTrans->translation.setValue (0, (h + _stackHeight)/2.0, 0);
+ _origt->translation.setValue (0, -h/2.0, 0);
+ _cyl->height.setValue (h - _stackHeight);
+ }
+
+ ModObj::setTran (x, z, w, d);
+}
+
+void
+PipeObj::setTag (const char * s)
+{
+ _tag = s;
+ if ( strchr (s, '\n' ) == NULL ) {
+ _tag.append ("\n");
+ }
+}
diff --git a/src/pmview/pipeobj.h b/src/pmview/pipeobj.h
new file mode 100644
index 0000000..1630813
--- /dev/null
+++ b/src/pmview/pipeobj.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _PIPEOBJ_H_
+#define _PIPEOBJ_H_
+
+#include "modobj.h"
+
+class SoCylinder;
+class SoTranslation;
+
+class PipeObj : public ModObj {
+public:
+ virtual ~PipeObj () {}
+ PipeObj (const DefaultObj &, int, int, int, int, Alignment);
+
+ int width () const { return _width; }
+ int depth () const { return _depth; }
+
+ const char * name() const { return "Pipe"; }
+
+ void finishedAdd ();
+ void setTran (float, float, int, int);
+ void setTag (const char *);
+
+private:
+ PipeObj ();
+ PipeObj (PipeObj const &);
+ PipeObj const& operator=(PipeObj const &);
+
+ int _width, _depth;
+ int cellWidth, cellDepth, cellHeight;
+ Alignment _align;
+ float _stackHeight;
+ QString _tag;
+
+ SoCylinder * _cyl;
+ SoTranslation * _cylTrans, * _origt;
+
+ float _color[3];
+};
+
+#endif /* _PIPEOBJ_H_ */
diff --git a/src/pmview/pmview.cpp b/src/pmview/pmview.cpp
new file mode 100644
index 0000000..2d4d1ff
--- /dev/null
+++ b/src/pmview/pmview.cpp
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2007-2009, Aconex. All Rights Reserved.
+ * Copyright (c) 2006, Ken McDonell. 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/QUrl>
+#include <QtCore/QTimer>
+#include <QtCore/QLibraryInfo>
+#include <QtGui/QDesktopServices>
+#include <QtGui/QApplication>
+#include <QtGui/QPrintDialog>
+#include <QtGui/QMessageBox>
+#include <QtGui/QWhatsThis>
+
+#include <Inventor/nodes/SoPerspectiveCamera.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTransform.h>
+#include <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoCube.h>
+
+#include <iostream>
+using namespace std;
+
+#include "barobj.h"
+#include "gridobj.h"
+#include "stackobj.h"
+#include "labelobj.h"
+#include "modlist.h"
+#include "defaultobj.h"
+#include "pcpcolor.h"
+
+#include "main.h"
+#include "pmview.h"
+#include "scenegroup.h"
+#include "qed_console.h"
+#include "qed_statusbar.h"
+#include "qed_timecontrol.h"
+#include "qed_recorddialog.h"
+
+QString theConfigName;
+QString theAltConfigName;
+FILE *theConfigFile;
+FILE *theAltConfig;
+float theGlobalScale = 1.2;
+char **frontend_argv;
+int frontend_argc;
+
+PmView::PmView() : QMainWindow(NULL)
+{
+ my.dialogsSetup = false;
+
+ setIconSize(QSize(22, 22));
+ setupUi(this);
+
+ SoQt::init(widget);
+ my.viewer = new SoQtExaminerViewer(widget);
+
+ my.statusBar = new QedStatusBar;
+ setStatusBar(my.statusBar);
+
+ toolBar->setAllowedAreas(Qt::RightToolBarArea | Qt::TopToolBarArea);
+ connect(toolBar, SIGNAL(orientationChanged(Qt::Orientation)),
+ this, SLOT(updateToolbarOrientation(Qt::Orientation)));
+ updateToolbarLocation();
+ setupEnabledActionsList();
+ if (!globalSettings.initialToolbar)
+ toolBar->hide();
+
+ my.liveHidden = true;
+ my.archiveHidden = true;
+ timeControlAction->setChecked(false);
+ my.menubarHidden = false;
+ my.toolbarHidden = !globalSettings.initialToolbar;
+ toolbarAction->setChecked(globalSettings.initialToolbar);
+ my.consoleHidden = true;
+ if (!pmDebug)
+ consoleAction->setVisible(false);
+ consoleAction->setChecked(false);
+
+ // Build Scene Graph
+ my.root = new SoSeparator;
+ my.root->ref();
+
+ SoPerspectiveCamera *camera = new SoPerspectiveCamera;
+ camera->orientation.setValue(SbVec3f(1, 0, 0), -M_PI/6.0);
+ my.root->addChild(camera);
+
+ my.drawStyle = new SoDrawStyle;
+ my.drawStyle->style.setValue(SoDrawStyle::FILLED);
+ my.root->addChild(my.drawStyle);
+
+#if 0
+ // TODO is this needed?
+ if (outfile)
+ QTimer::singleShot(0, this, SLOT(exportFile()));
+ else
+#endif
+ QTimer::singleShot(PmView::defaultTimeout(), this, SLOT(timeout()));
+
+}
+
+void PmView::languageChange()
+{
+ retranslateUi(this);
+}
+
+void PmView::init(void)
+{
+ my.statusBar->init();
+}
+
+void
+PmView::selectionCB(ModList *, bool redraw)
+{
+ RenderOptions options = PmView::metricLabel;
+
+ if (redraw)
+ options = (RenderOptions)(options | PmView::inventor);
+ pmview->render(options, 0);
+}
+
+bool PmView::view(bool showAxis,
+ float xAxis, float yAxis, float zAxis, float angle, float scale)
+{
+ if (theModList->size() == 0) {
+ warningMsg(_POS_, "No modulated objects in scene");
+ }
+
+ // Setup remainder of the scene graph
+ my.root->addChild(theModList->root());
+
+ viewer()->setSceneGraph(my.root);
+ viewer()->setAutoRedraw(true);
+ viewer()->setTitle(pmProgname);
+ if (showAxis)
+ viewer()->setFeedbackVisibility(true);
+
+ SbBool smooth = TRUE;
+ int passes = 1;
+ char *sval = NULL;
+
+#if 0 // TODO: QSettings API
+ sval = VkGetResource("antiAliasSmooth", XmRString);
+ if (sval && strcmp(sval, "default") != 0 && strcasecmp(sval, "false") == 0)
+ smooth = FALSE;
+ sval = VkGetResource("antiAliasPasses", XmRString);
+ if (sval != NULL && strcmp(sval, "default"))
+ passes = atoi(sval);
+#endif
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "PmView::view: antialiasing set to smooth = "
+ << (smooth == TRUE ? "true" : "false")
+ << ", passes = " << passes << endl;
+#endif
+
+ if (passes > 1)
+ viewer()->setAntialiasing(smooth, atoi(sval));
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "PmView::view: displaying window" << endl;
+#endif
+
+ viewer()->viewAll();
+
+ if (angle != 0.0 || scale != 0.0) {
+ SoTransform *tran = new SoTransform();
+ if (angle != 0.0)
+ tran->rotation.setValue(SbVec3f(xAxis, yAxis, zAxis), angle);
+ if (scale != 0.0)
+ tran->scaleFactor.setValue(scale, scale, scale);
+ theModList->root()->insertChild(tran, 0);
+ }
+
+ PmView::render((RenderOptions)(PmView::inventor | PmView::metricLabel), 0);
+ viewer()->saveHomePosition();
+
+ return true;
+}
+
+void PmView::render(RenderOptions options, time_t theTime)
+{
+ viewer()->setAutoRedraw(false);
+
+ if (options & PmView::metrics)
+ theModList->refresh(true);
+
+ if (options & PmView::inventor)
+ viewer()->render();
+
+ if (options & PmView::metricLabel) {
+ theModList->infoText(my.text);
+ if (my.text != my.prevText) {
+ my.prevText = my.text;
+ if (my.text.length() == 0)
+ // TODO: clear label string
+ ;
+ else {
+ // TODO: set label string to my.text
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "PmView::render: metricLabel text \"" <<
+ my.text() << "\"" << endl;
+#endif
+ }
+ }
+ }
+
+ if (options & PmView::timeLabel)
+ setDateLabel(theTime, QString::null); // TODO
+
+ viewer()->setAutoRedraw(true);
+}
+
+QMenu *PmView::createPopupMenu(void)
+{
+ QMenu *menu = QMainWindow::createPopupMenu();
+ menu->addAction(menubarAction);
+ return menu;
+}
+
+void PmView::quit()
+{
+ // End any processes we may have started and close any open dialogs
+ if (pmtime)
+ pmtime->quit();
+}
+
+void PmView::closeEvent(QCloseEvent *)
+{
+ quit();
+}
+
+void PmView::enableUi(void)
+{
+#if 0
+ recordStartAction->setEnabled(haveGadgets && haveLiveHosts && !haveLoggers);
+ recordQueryAction->setEnabled(haveLoggers);
+ recordStopAction->setEnabled(haveLoggers);
+ recordDetachAction->setEnabled(haveLoggers);
+#endif
+}
+
+void PmView::updateToolbarLocation()
+{
+#if QT_VERSION >= 0x040300
+ setUnifiedTitleAndToolBarOnMac(globalSettings.nativeToolbar);
+#endif
+ if (globalSettings.toolbarLocation)
+ addToolBar(Qt::RightToolBarArea, toolBar);
+ else
+ addToolBar(Qt::TopToolBarArea, toolBar);
+}
+
+void PmView::updateToolbarOrientation(Qt::Orientation orientation)
+{
+ (void)orientation;
+ // TODO
+}
+
+void PmView::setButtonState(QedTimeButton::State state)
+{
+ my.statusBar->timeButton()->setButtonState(state);
+}
+
+void PmView::step(bool live, QmcTime::Packet *packet)
+{
+ if (live)
+ liveGroup->step(packet);
+ else
+ archiveGroup->step(packet);
+}
+
+void PmView::VCRMode(bool live, QmcTime::Packet *packet, bool drag)
+{
+ if (live)
+ liveGroup->VCRMode(packet, drag);
+ else
+ archiveGroup->VCRMode(packet, drag);
+}
+
+void PmView::timeZone(bool live, QmcTime::Packet *packet, char *tzdata)
+{
+ if (live)
+ liveGroup->setTimezone(packet, tzdata);
+ else
+ archiveGroup->setTimezone(packet, tzdata);
+}
+
+void PmView::filePrint()
+{
+ QMessageBox::information(this, pmProgname, "Print, print, print... whirrr");
+}
+
+void PmView::fileQuit()
+{
+ QApplication::exit(0);
+}
+
+void PmView::helpManual()
+{
+ bool ok;
+ QString documents("file://");
+ QString separator = QString(__pmPathSeparator());
+ documents.append(pmGetConfig("PCP_HTML_DIR"));
+ documents.append(separator).append("index.html");
+ ok = QDesktopServices::openUrl(QUrl(documents, QUrl::TolerantMode));
+ if (!ok) {
+ documents.prepend("Failed to open:\n");
+ QMessageBox::warning(this, pmProgname, documents);
+ }
+}
+
+void PmView::helpTutorial()
+{
+ bool ok;
+ QString documents("file://");
+ QString separator = QString(__pmPathSeparator());
+ documents.append(pmGetConfig("PCP_HTML_DIR"));
+ documents.append(separator).append("tutorial.html");
+ ok = QDesktopServices::openUrl(QUrl(documents, QUrl::TolerantMode));
+ if (!ok) {
+ documents.prepend("Failed to open:\n");
+ QMessageBox::warning(this, pmProgname, documents);
+ }
+}
+
+void PmView::helpAbout()
+{
+#if 0
+ AboutDialog about(this);
+ about.exec();
+#endif
+}
+
+void PmView::helpSeeAlso()
+{
+#if 0
+ SeeAlsoDialog seealso(this);
+ seealso.exec();
+#endif
+}
+
+void PmView::whatsThis()
+{
+ QWhatsThis::enterWhatsThisMode();
+}
+
+void PmView::optionsTimeControl()
+{
+ if (activeView()->isArchiveSource()) {
+ if (my.archiveHidden)
+ pmtime->showArchiveTimeControl();
+ else
+ pmtime->hideArchiveTimeControl();
+ my.archiveHidden = !my.archiveHidden;
+ timeControlAction->setChecked(!my.archiveHidden);
+ }
+ else {
+ if (my.liveHidden)
+ pmtime->showLiveTimeControl();
+ else
+ pmtime->hideLiveTimeControl();
+ my.liveHidden = !my.liveHidden;
+ timeControlAction->setChecked(!my.liveHidden);
+ }
+}
+
+void PmView::optionsToolbar()
+{
+ if (my.toolbarHidden)
+ toolBar->show();
+ else
+ toolBar->hide();
+ my.toolbarHidden = !my.toolbarHidden;
+}
+
+void PmView::optionsMenubar()
+{
+ if (my.menubarHidden)
+ MenuBar->show();
+ else
+ MenuBar->hide();
+ my.menubarHidden = !my.menubarHidden;
+}
+
+void PmView::optionsConsole()
+{
+#if 0
+ if (pmDebug) {
+ if (my.consoleHidden)
+ console->show();
+ else
+ console->hide();
+ my.consoleHidden = !my.consoleHidden;
+ }
+#endif
+}
+
+void PmView::optionsNewPmchart()
+{
+ QProcess *buddy = new QProcess(this);
+ QStringList arguments;
+ QString port;
+
+ port.setNum(pmtime->port());
+ arguments << "-p" << port;
+ for (unsigned int i = 0; i < archiveGroup->numContexts(); i++) {
+ QmcSource source = archiveGroup->context(i)->source();
+ arguments << "-a" << source.source();
+ }
+ for (unsigned int i = 0; i < liveGroup->numContexts(); i++) {
+ QmcSource source = liveGroup->context(i)->source();
+ arguments << "-h" << source.source();
+ }
+ if (Lflag)
+ arguments << "-L";
+ buddy->start("pmview", arguments);
+}
+
+bool PmView::isViewRecording()
+{
+ return activeView()->isRecording();
+}
+
+bool PmView::isArchiveView()
+{
+ return activeView()->isArchiveSource();
+}
+
+void PmView::setDateLabel(time_t seconds, QString tz)
+{
+ char datestring[32];
+ QString label;
+
+ if (seconds) {
+ pmCtime(&seconds, datestring);
+ label = tr(datestring);
+ label.remove(10, 9);
+ label.replace(15, 1, " ");
+ label.append(tz);
+ }
+ else {
+ label = tr("");
+ }
+ my.statusBar->setDateText(label);
+}
+
+void PmView::setDateLabel(QString label)
+{
+ my.statusBar->setDateText(label);
+}
+
+void PmView::setRecordState(bool record)
+{
+ liveGroup->newButtonState(liveGroup->pmtimeState(),
+ QmcTime::NormalMode, record);
+ setButtonState(liveGroup->buttonState());
+ enableUi();
+}
+
+void PmView::recordStart()
+{
+ if (activeView()->startRecording())
+ setRecordState(true);
+}
+
+void PmView::recordStop()
+{
+ activeView()->stopRecording();
+}
+
+void PmView::recordQuery()
+{
+ activeView()->queryRecording();
+}
+
+void PmView::recordDetach()
+{
+ activeView()->detachLoggers();
+}
+
+QList<QAction*> PmView::toolbarActionsList()
+{
+ return my.toolbarActionsList;
+}
+
+QList<QAction*> PmView::enabledActionsList()
+{
+ return my.enabledActionsList;
+}
+
+void PmView::setupEnabledActionsList()
+{
+ // ToolbarActionsList is a list of all Actions available.
+ // The SeparatorsList contains Actions that are group "breaks", and
+ // which must be followed by a separator (if they are not the final
+ // action in the toolbar, of course).
+ // Finally the enabledActionsList lists the default enabled Actions.
+
+ my.toolbarActionsList << filePrintAction;
+ addSeparatorAction(); // end exported formats
+ my.toolbarActionsList << recordStartAction << recordStopAction;
+ addSeparatorAction(); // end recording group
+ //my.toolbarActionsList << editSettingsAction;
+ //addSeparatorAction(); // end settings group
+ my.toolbarActionsList << timeControlAction;
+ addSeparatorAction(); // end other processes
+ my.toolbarActionsList << helpManualAction << helpWhatsThisAction;
+
+ // needs to match pmview.ui
+ my.enabledActionsList << filePrintAction;
+
+ if (globalSettings.toolbarActions.size() > 0) {
+ setEnabledActionsList(globalSettings.toolbarActions, false);
+ updateToolbarContents();
+ }
+}
+
+void PmView::addSeparatorAction()
+{
+ int index = my.toolbarActionsList.size() - 1;
+ my.separatorsList << my.toolbarActionsList.at(index);
+}
+
+void PmView::updateToolbarContents()
+{
+ bool needSeparator = false;
+
+ toolBar->clear();
+ for (int i = 0; i < my.toolbarActionsList.size(); i++) {
+ QAction *action = my.toolbarActionsList.at(i);
+ if (my.enabledActionsList.contains(action)) {
+ toolBar->addAction(action);
+ if (needSeparator) {
+ toolBar->insertSeparator(action);
+ needSeparator = false;
+ }
+ }
+ if (my.separatorsList.contains(action))
+ needSeparator = true;
+ }
+}
+
+void PmView::setEnabledActionsList(QStringList tools, bool redisplay)
+{
+ my.enabledActionsList.clear();
+ for (int i = 0; i < my.toolbarActionsList.size(); i++) {
+ QAction *action = my.toolbarActionsList.at(i);
+ if (tools.contains(action->iconText()))
+ my.enabledActionsList.append(action);
+ }
+
+ if (redisplay) {
+ my.toolbarHidden = (my.enabledActionsList.size() == 0);
+ toolbarAction->setChecked(my.toolbarHidden);
+ if (my.toolbarHidden)
+ toolBar->hide();
+ else
+ toolBar->show();
+ }
+}
+
+void View::init(SceneGroup *group, QMenu *menu, QString title)
+{
+ my.group = group;
+ QedViewControl::init(group, menu, title, globalSettings.loggerDelta);
+}
+
+QStringList View::hostList(bool)
+{
+ // TODO
+ return QStringList();
+}
+
+QString View::pmloggerSyntax(bool)
+{
+// TODO
+#if 0
+ View *view = pmview->activeView();
+ QString configdata;
+
+ if (selectedOnly)
+ configdata.append(pmview->activeGadget()->pmloggerSyntax());
+ else
+ for (int c = 0; c < view->gadgetCount(); c++)
+ configdata.append(gadget(c)->pmloggerSyntax());
+ return configdata;
+#else
+ return NULL;
+#endif
+}
+
+bool View::saveConfig(QString filename, bool hostDynamic,
+ bool sizeDynamic, bool allViews, bool allCharts)
+{
+// TODO
+#if 0
+ return SaveViewDialog::saveView(filename,
+ hostDynamic, sizeDynamic, allViews, allCharts);
+#else
+ return false;
+#endif
+}
+
+bool View::stopRecording()
+{
+// TODO
+#if 0
+ QString errmsg;
+ bool error = ViewControl::stopRecording(errmsg);
+ QStringList archiveList = ViewControl::archiveList();
+
+ for (int i = 0; i < archiveList.size(); i++) {
+ QString archive = archiveList.at(i);
+ int sts;
+
+ console->post("View::stopRecording opening archive %s",
+ (const char *)archive.toAscii());
+ if ((sts = archiveGroup->use(PM_CONTEXT_ARCHIVE, archive)) < 0) {
+ errmsg.append(QApplication::tr("Cannot open PCP archive: "));
+ errmsg.append(archive);
+ errmsg.append("\n");
+ errmsg.append(pmErrStr(sts));
+ errmsg.append("\n");
+ error = true;
+ }
+ else {
+ archiveGroup->updateBounds();
+ QmcSource source = archiveGroup->context()->source();
+ pmtime->addArchive(source.start(), source.end(),
+ source.timezone(), source.host(), true);
+ }
+ }
+
+ // If all is well, we can now create the new "Record" View.
+ // Order of cleanup and changing Record mode state is different
+ // in the error case to non-error case, this is important for
+ // getting the window state correct (i.e. pmview->enableUi()).
+
+ if (error) {
+ cleanupRecording();
+ pmview->setRecordState(false);
+ QMessageBox::warning(NULL, pmProgname, errmsg,
+ QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
+ QMessageBox::NoButton, QMessageBox::NoButton);
+ }
+ else {
+ // Make the current View stop recording before changing Views
+ pmview->setRecordState(false);
+
+ View *view = new View;
+ console->post("View::stopRecording creating view: delta=%.2f pos=%.2f",
+ App::timevalToSeconds(*pmtime->archiveInterval()),
+ App::timevalToSeconds(*pmtime->archivePosition()));
+ // TODO: may need to update archive samples/visible?
+ view->init(archiveGroup, pmview->viewMenu(), "Record");
+ pmview->addActiveView(view);
+ OpenViewDialog::openView((const char *)ViewControl::view().toAscii());
+ cleanupRecording();
+ }
+ return error;
+#else
+ return false;
+#endif
+}
+
+bool View::queryRecording(void)
+{
+ QString errmsg;
+ bool error = QedViewControl::queryRecording(errmsg);
+
+ if (error) {
+ pmview->setRecordState(false);
+ QMessageBox::warning(NULL, pmProgname, errmsg,
+ QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
+ QMessageBox::NoButton, QMessageBox::NoButton);
+ }
+ return error;
+}
+
+bool View::detachLoggers(void)
+{
+ QString errmsg;
+ bool error = QedViewControl::detachLoggers(errmsg);
+
+ if (error) {
+ pmview->setRecordState(false);
+ QMessageBox::warning(NULL, pmProgname, errmsg,
+ QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
+ QMessageBox::NoButton, QMessageBox::NoButton);
+ }
+ else {
+ pmview->setRecordState(false);
+ cleanupRecording();
+ }
+ return error;
+}
diff --git a/src/pmview/pmview.desktop b/src/pmview/pmview.desktop
new file mode 100644
index 0000000..4129bcd
--- /dev/null
+++ b/src/pmview/pmview.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=PCP View
+Comment=3D tool for displaying Performance Co-Pilot metrics
+Exec=pmview
+Icon=pmview
+Terminal=false
+Type=Application
+Categories=System;Utility;Network;Qt;
diff --git a/src/pmview/pmview.h b/src/pmview/pmview.h
new file mode 100644
index 0000000..bd402ad
--- /dev/null
+++ b/src/pmview/pmview.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2007-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.
+ */
+#ifndef PMVIEW_H
+#define PMVIEW_H
+
+#include <Inventor/Qt/SoQt.h>
+#include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
+#include <Inventor/nodes/SoDrawStyle.h>
+
+#include "ui_pmview.h"
+
+#include "qmc_time.h"
+#include "qed_statusbar.h"
+#include "qed_viewcontrol.h"
+
+class ModList;
+class SceneGroup;
+
+class View : public QedViewControl
+{
+public:
+ View() : QedViewControl() { };
+ virtual ~View() { };
+
+ void init(SceneGroup *, QMenu *, QString);
+ SceneGroup *group() const { return my.group; }
+
+ bool saveConfig(QString, bool, bool, bool, bool);
+ QStringList hostList(bool);
+ QString pmloggerSyntax(bool);
+
+ bool stopRecording();
+ bool queryRecording();
+ bool detachLoggers();
+
+private:
+ struct {
+ SceneGroup *group;
+ } my;
+};
+
+class PmView : public QMainWindow, public Ui::PmView
+{
+ Q_OBJECT
+
+public:
+ PmView();
+
+ typedef enum {
+ nothing = 0,
+ // fetch = 0x1, -- TODO
+ metrics = 0x2,
+ inventor = 0x4,
+ metricLabel = 0x8,
+ timeLabel = 0x10,
+ all = 0xffffffff,
+ } RenderOptions;
+
+ static int defaultFontSize();
+ static double defaultViewDelta() { return 1.0; } // seconds
+ static double defaultLoggerDelta() { return 1.0; }
+ static int defaultTimeout() { return 3000; } // milliseconds
+ static int minimumPoints() { return 2; }
+ static int maximumPoints() { return 360; }
+ static int maximumLegendLength() { return 120; } // chars
+ static int minimumViewHeight() { return 80; } // pixels
+
+ bool view(bool, float, float, float, float, float);
+ void render(RenderOptions options, time_t);
+ View *activeView() { return my.viewList.at(my.activeView); }
+ bool isViewRecording();
+ bool isArchiveView();
+
+ virtual void step(bool livemode, QmcTime::Packet *pmtime);
+ virtual void VCRMode(bool livemode, QmcTime::Packet *pmtime, bool drag);
+ virtual void timeZone(bool livemode, QmcTime::Packet *pmtime, char *tzdata);
+ virtual void setDateLabel(QString label);
+ virtual void setDateLabel(time_t seconds, QString tz);
+ virtual void setButtonState(QedTimeButton::State state);
+ virtual void setRecordState(bool recording);
+
+ virtual QMenu *createPopupMenu();
+ virtual void updateToolbarContents();
+ virtual void updateToolbarLocation();
+ virtual QList<QAction*> toolbarActionsList();
+ virtual QList<QAction*> enabledActionsList();
+ virtual void setupEnabledActionsList();
+ virtual void addSeparatorAction();
+ virtual void setEnabledActionsList(QStringList tools, bool redisplay);
+
+ // Adjusted height for exporting images (without UI elements)
+ int exportHeight()
+ { return height() - menuBar()->height() - toolBar->height(); }
+
+ SoQtExaminerViewer *viewer() { return my.viewer; }
+ static void selectionCB(ModList *, bool);
+
+public slots:
+ virtual void init();
+ virtual void quit();
+ virtual void enableUi();
+ virtual void filePrint();
+ virtual void fileQuit();
+ virtual void helpManual();
+ virtual void helpTutorial();
+ virtual void helpAbout();
+ virtual void helpSeeAlso();
+ virtual void whatsThis();
+ virtual void optionsNewPmchart();
+ virtual void optionsTimeControl();
+ virtual void optionsMenubar();
+ virtual void optionsToolbar();
+ virtual void optionsConsole();
+ virtual void recordStart();
+ virtual void recordQuery();
+ virtual void recordStop();
+ virtual void recordDetach();
+ virtual void updateToolbarOrientation(Qt::Orientation);
+
+protected slots:
+ virtual void languageChange();
+ virtual void closeEvent(QCloseEvent *);
+
+private:
+ struct {
+ bool dialogsSetup;
+ bool liveHidden;
+ bool archiveHidden;
+ bool menubarHidden;
+ bool toolbarHidden;
+ bool consoleHidden;
+
+ QMenu *viewMenu;
+ QList<QAction*> separatorsList; // separator follow these
+ QList<QAction*> toolbarActionsList; // all toolbar actions
+ QList<QAction*> enabledActionsList; // currently visible actions
+
+ QList<View *>viewList;
+ int activeView;
+
+ SoSeparator *root;
+ SoDrawStyle *drawStyle;
+ SoQtExaminerViewer *viewer; // The examiner window
+
+ QString text;
+ QString prevText;
+ QedStatusBar *statusBar;
+ } my;
+};
+
+#endif // PMVIEW_H
diff --git a/src/pmview/pmview.info.in b/src/pmview/pmview.info.in
new file mode 100644
index 0000000..bfa34df
--- /dev/null
+++ b/src/pmview/pmview.info.in
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleIconFile</key>
+ <string>pmview.icns</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleGetInfoString</key>
+ <string>@pkg_version@</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleExecutable</key>
+ <string>pmview</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.aconex.pmview</string>
+</dict>
+</plist>
diff --git a/src/pmview/pmview.pro b/src/pmview/pmview.pro
new file mode 100644
index 0000000..e546eba
--- /dev/null
+++ b/src/pmview/pmview.pro
@@ -0,0 +1,34 @@
+TEMPLATE = app
+LANGUAGE = C++
+HEADERS = main.h pmview.h colorlist.h \
+ barmod.h barobj.h baseobj.h \
+ defaultobj.h gridobj.h labelobj.h stackobj.h \
+ launch.h viewobj.h pipeobj.h link.h xing.h \
+ scenefileobj.h scenegroup.h \
+ colorscalemod.h colormod.h colorscale.h \
+ metriclist.h modlist.h modulate.h \
+ scalemod.h stackmod.h togglemod.h \
+ text.h yscalemod.h pcpcolor.h
+SOURCES = main.cpp colorlist.cpp barmod.cpp barobj.cpp baseobj.cpp \
+ defaultobj.cpp gridobj.cpp labelobj.cpp stackobj.cpp \
+ launch.cpp viewobj.cpp pipeobj.cpp link.cpp xing.cpp \
+ scenefileobj.cpp scenegroup.cpp \
+ colorscalemod.cpp colormod.cpp colorscale.cpp \
+ scalemod.cpp stackmod.cpp togglemod.cpp yscalemod.cpp \
+ metricList.cpp modlist.cpp modulate.cpp pcpcolor.cpp \
+ text.cpp error.cpp gram.cpp lex.cpp pmview.cpp
+FORMS = pmview.ui
+ICON = pmview.icns
+RC_FILE = pmview.rc
+RESOURCES = pmview.qrc
+INCLUDEPATH += /usr/include/Coin2
+INCLUDEPATH += ../include ../libpcp_qmc/src ../libpcp_qed/src
+CONFIG += qt warn_on
+LIBS += -L../libpcp/src
+LIBS += -L../libpcp_qmc/src -L../libpcp_qmc/src/$$DESTDIR
+LIBS += -L../libpcp_qed/src -L../libpcp_qed/src/$$DESTDIR
+LIBS += -lpcp_qed -lpcp_qmc -lpcp -lCoin -lSoQt
+win32:LIBS += -lwsock32
+QT += network
+QMAKE_INFO_PLIST = pmview.info
+QMAKE_CXXFLAGS += $$(PCP_CFLAGS)
diff --git a/src/pmview/pmview.qrc b/src/pmview/pmview.qrc
new file mode 100644
index 0000000..9694fc1
--- /dev/null
+++ b/src/pmview/pmview.qrc
@@ -0,0 +1,23 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>images/aboutpcp.png</file>
+ <file>images/aboutqt.png</file>
+ <file>images/pmview.png</file>
+ <file>images/pmtime.png</file>
+ <file>images/whatsthis.png</file>
+ <file>images/document-print.png</file>
+ <file>images/help-browser.png</file>
+ <file>images/help-contents.png</file>
+ <file>images/play_live.png</file>
+ <file>images/stop_live.png</file>
+ <file>images/play_record.png</file>
+ <file>images/stop_record.png</file>
+ <file>images/play_archive.png</file>
+ <file>images/stop_archive.png</file>
+ <file>images/back_archive.png</file>
+ <file>images/stepfwd_archive.png</file>
+ <file>images/stepback_archive.png</file>
+ <file>images/fastfwd_archive.png</file>
+ <file>images/fastback_archive.png</file>
+</qresource>
+</RCC>
diff --git a/src/pmview/pmview.ui b/src/pmview/pmview.ui
new file mode 100644
index 0000000..ed4fafa
--- /dev/null
+++ b/src/pmview/pmview.ui
@@ -0,0 +1,386 @@
+<ui version="4.0" >
+ <class>PmView</class>
+ <widget class="QMainWindow" name="PmView" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>470</width>
+ <height>470</height>
+ </rect>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>182</width>
+ <height>196</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>PCP Viewer</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/pmview.png</normaloff>:/images/pmview.png</iconset>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>22</width>
+ <height>22</height>
+ </size>
+ </property>
+ <widget class="QWidget" name="widget" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="MenuBar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>370</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="Help" >
+ <property name="title" >
+ <string>&amp;Help</string>
+ </property>
+ <addaction name="helpManualAction" />
+ <addaction name="helpTutorialAction" />
+ <addaction name="separator" />
+ <addaction name="helpAboutAction" />
+ <addaction name="helpSeeAlsoAction" />
+ <addaction name="separator" />
+ <addaction name="helpWhatsThisAction" />
+ </widget>
+ <widget class="QMenu" name="Options" >
+ <property name="title" >
+ <string>&amp;Options</string>
+ </property>
+ <addaction name="timeControlAction" />
+ <addaction name="menubarAction" />
+ <addaction name="toolbarAction" />
+ <addaction name="consoleAction" />
+ </widget>
+ <widget class="QMenu" name="Record" >
+ <property name="title" >
+ <string>&amp;Record</string>
+ </property>
+ <addaction name="recordStartAction" />
+ <addaction name="recordQueryAction" />
+ <addaction name="recordStopAction" />
+ <addaction name="separator" />
+ <addaction name="recordDetachAction" />
+ </widget>
+ <widget class="QMenu" name="File" >
+ <property name="title" >
+ <string>&amp;File</string>
+ </property>
+ <addaction name="fileQuitAction" />
+ </widget>
+ <addaction name="File" />
+ <addaction name="Record" />
+ <addaction name="Options" />
+ <addaction name="separator" />
+ <addaction name="Help" />
+ </widget>
+ <widget class="QToolBar" name="toolBar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>24</y>
+ <width>370</width>
+ <height>36</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>Toolbar</string>
+ </property>
+ <property name="whatsThis" >
+ <string>Configurable toolbar, use the Preferences dialog to change its contents</string>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <attribute name="toolBarArea" >
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak" >
+ <bool>false</bool>
+ </attribute>
+ <addaction name="filePrintAction" />
+ </widget>
+ <action name="filePrintAction" >
+ <property name="icon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/document-print.png</normaloff>:/images/document-print.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;Print...</string>
+ </property>
+ <property name="iconText" >
+ <string>Print</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+P</string>
+ </property>
+ </action>
+ <action name="fileQuitAction" >
+ <property name="text" >
+ <string>&amp;Quit</string>
+ </property>
+ <property name="iconText" >
+ <string>Quit</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="timeControlAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="icon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/pmtime.png</normaloff>:/images/pmtime.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Time Controls</string>
+ </property>
+ </action>
+ <action name="menubarAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ <property name="text" >
+ <string>Menubar</string>
+ </property>
+ </action>
+ <action name="toolbarAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="text" >
+ <string>Toolbar</string>
+ </property>
+ </action>
+ <action name="consoleAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="text" >
+ <string>Console</string>
+ </property>
+ </action>
+ <action name="helpManualAction" >
+ <property name="icon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/help-contents.png</normaloff>:/images/help-contents.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;Manual</string>
+ </property>
+ <property name="iconText" >
+ <string>Manual</string>
+ </property>
+ <property name="shortcut" >
+ <string>F1</string>
+ </property>
+ </action>
+ <action name="helpTutorialAction" >
+ <property name="text" >
+ <string>Tutorial</string>
+ </property>
+ <property name="iconText" >
+ <string>Tutorial</string>
+ </property>
+ </action>
+ <action name="helpAboutAction" >
+ <property name="icon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/pmview.png</normaloff>:/images/pmview.png</iconset>
+ </property>
+ <property name="text" >
+ <string>About</string>
+ </property>
+ <property name="iconText" >
+ <string>About</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ </action>
+ <action name="helpSeeAlsoAction" >
+ <property name="text" >
+ <string>See Also</string>
+ </property>
+ <property name="iconText" >
+ <string>See Also</string>
+ </property>
+ </action>
+ <action name="helpWhatsThisAction" >
+ <property name="icon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/whatsthis.png</normaloff>:/images/whatsthis.png</iconset>
+ </property>
+ <property name="text" >
+ <string>What's This</string>
+ </property>
+ <property name="iconText" >
+ <string>What's This</string>
+ </property>
+ <property name="shortcut" >
+ <string>Shift+F1</string>
+ </property>
+ </action>
+ <action name="recordStartAction" >
+ <property name="icon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/camera-video.png</normaloff>:/images/camera-video.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Start...</string>
+ </property>
+ </action>
+ <action name="recordQueryAction" >
+ <property name="text" >
+ <string>Query</string>
+ </property>
+ </action>
+ <action name="recordStopAction" >
+ <property name="icon" >
+ <iconset resource="pmview.qrc" >
+ <normaloff>:/images/camera-video-close.png</normaloff>:/images/camera-video-close.png</iconset>
+ </property>
+ <property name="text" >
+ <string>Stop</string>
+ </property>
+ </action>
+ <action name="recordDetachAction" >
+ <property name="text" >
+ <string>Detach</string>
+ </property>
+ </action>
+ </widget>
+ <includes>
+ <include location="local" >qmc_time.h</include>
+ <include location="local" >qprinter.h</include>
+ <include location="local" >qed_timebutton.h</include>
+ </includes>
+ <resources>
+ <include location="pmview.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>filePrintAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>filePrint()</slot>
+ </connection>
+ <connection>
+ <sender>fileQuitAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>fileQuit()</slot>
+ </connection>
+ <connection>
+ <sender>helpTutorialAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>helpTutorial()</slot>
+ </connection>
+ <connection>
+ <sender>helpAboutAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>helpAbout()</slot>
+ </connection>
+ <connection>
+ <sender>helpSeeAlsoAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>helpSeeAlso()</slot>
+ </connection>
+ <connection>
+ <sender>helpWhatsThisAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>whatsThis()</slot>
+ </connection>
+ <connection>
+ <sender>timeControlAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>optionsTimeControl()</slot>
+ </connection>
+ <connection>
+ <sender>menubarAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>optionsMenubar()</slot>
+ </connection>
+ <connection>
+ <sender>toolbarAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>optionsToolbar()</slot>
+ </connection>
+ <connection>
+ <sender>consoleAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>optionsConsole()</slot>
+ </connection>
+ <connection>
+ <sender>helpManualAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>helpManual()</slot>
+ </connection>
+ <connection>
+ <sender>recordStartAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>recordStart()</slot>
+ </connection>
+ <connection>
+ <sender>recordQueryAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>recordQuery()</slot>
+ </connection>
+ <connection>
+ <sender>recordStopAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>recordStop()</slot>
+ </connection>
+ <connection>
+ <sender>recordDetachAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmView</receiver>
+ <slot>recordDetach()</slot>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/pmview/scalemod.cpp b/src/pmview/scalemod.cpp
new file mode 100644
index 0000000..49c7a36
--- /dev/null
+++ b/src/pmview/scalemod.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoScale.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include "main.h"
+#include "scalemod.h"
+#include "modlist.h"
+#include "launch.h"
+
+#include <iostream>
+using namespace std;
+
+ScaleMod::~ScaleMod()
+{
+}
+
+ScaleMod::ScaleMod(const char *str,
+ double scale,
+ const SbColor &color,
+ SoNode *obj,
+ float xScale,
+ float yScale,
+ float zScale)
+: Modulate(str, scale, color),
+ _state(Modulate::start),
+ _color(0),
+ _scale(0),
+ _xScale(xScale),
+ _yScale(yScale),
+ _zScale(zScale)
+{
+ _root = new SoSeparator;
+
+ _color = new SoBaseColor;
+ _color->rgb.setValue(_errorColor.getValue());
+ _root->addChild(_color);
+
+ if (_metrics->numValues() == 1 && status() >= 0) {
+
+ _scale = new SoScale;
+ _scale->scaleFactor.setValue(1.0, 1.0, 1.0);
+ _root->addChild(_scale);
+ _root->addChild(obj);
+
+ add();
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ScaleMod: Added " << str << " (Id = "
+ << _root->getName().getString() << ")" << endl;
+#endif
+ }
+
+ // Invalid metric
+ else
+ _root->addChild(obj);
+}
+
+void
+ScaleMod::refresh(bool fetchFlag)
+{
+ QmcMetric &metric = _metrics->metric(0);
+
+ if (status() < 0)
+ return;
+
+ if (fetchFlag)
+ metric.update();
+
+ if (metric.error(0) <= 0) {
+ if (_state != Modulate::error) {
+ _color->rgb.setValue(_errorColor.getValue());
+ _scale->scaleFactor.setValue((_xScale==0.0f ? 1.0 : theMinScale),
+ (_yScale==0.0f ? 1.0 : theMinScale),
+ (_zScale==0.0f ? 1.0 : theMinScale));
+ _state = Modulate::error;
+ }
+ }
+ else {
+ double value = metric.value(0) * theScale;
+ if (value > theNormError) {
+ if (_state != Modulate::saturated) {
+ _color->rgb.setValue(_saturatedColor.getValue());
+ _scale->scaleFactor.setValue(1.0, 1.0, 1.0);
+ _state = Modulate::saturated;
+ }
+ }
+ else {
+ if (_state != Modulate::normal) {
+ _color->rgb.setValue(_metrics->color(0).getValue());
+ _state = Modulate::normal;
+ }
+ if (value < Modulate::theMinScale)
+ value = Modulate::theMinScale;
+ else if (value > 1.0)
+ value = 1.0;
+ _scale->scaleFactor.setValue((_xScale==0.0f ? 1.0 : _xScale*value),
+ (_yScale==0.0f ? 1.0 : _yScale*value),
+ (_zScale==0.0f ? 1.0 : _zScale*value));
+ }
+ }
+}
+
+void
+ScaleMod::dump(QTextStream &os) const
+{
+ os << "ScaleMod: ";
+
+ if (status() < 0)
+ os << "Invalid metric";
+ else {
+ os << "state = ";
+ dumpState(os, _state);
+ os << ", scale = " << _xScale << ',' << _yScale << ',' << _zScale
+ << ": ";
+ _metrics->metric(0).dump(os, true);
+ }
+}
+
+void
+ScaleMod::infoText(QString &str, bool) const
+{
+ const QmcMetric &metric = _metrics->metric(0);
+ str = metric.spec(true, true, 0);
+ str.append(QChar('\n'));
+ if (_state == Modulate::error)
+ str.append(theErrorText);
+ else if (_state == Modulate::start)
+ str.append(theStartText);
+ else {
+ QString value;
+ str.append(value.setNum(metric.realValue(0), 'g', 4));
+ str.append(QChar(' '));
+ if (metric.desc().units().size() > 0)
+ str.append(metric.desc().units());
+ str.append(" [");
+ str.append(value.setNum(metric.value(0) * 100.0, 'g', 4));
+ str.append("% of expected max]");
+ }
+}
+
+void
+ScaleMod::launch(Launch &launch, bool) const
+{
+ if (status() < 0)
+ return;
+ launch.startGroup("point");
+ launch.addMetric(_metrics->metric(0), _metrics->color(0), 0);
+ launch.endGroup();
+}
+
+int
+ScaleMod::select(SoPath *)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ScaleMod::select: " << _metrics->metric(0) << endl;
+#endif
+ return 1;
+}
+
+int
+ScaleMod::remove(SoPath *)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ScaleMod::remove: " << _metrics->metric(0) << endl;
+#endif
+ return 0;
+}
diff --git a/src/pmview/scalemod.h b/src/pmview/scalemod.h
new file mode 100644
index 0000000..2a28adc
--- /dev/null
+++ b/src/pmview/scalemod.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _SCALEMOD_H_
+#define _SCALEMOD_H_
+
+#include "modulate.h"
+
+class SoBaseColor;
+class SoScale;
+class SoNode;
+class Launch;
+
+class ScaleMod : public Modulate
+{
+protected:
+
+ State _state;
+ SoBaseColor *_color;
+ SoScale *_scale;
+ float _xScale;
+ float _yScale;
+ float _zScale;
+
+public:
+
+ virtual ~ScaleMod();
+
+ ScaleMod(const char *metric, double scale, const SbColor &color,
+ SoNode *obj, float xScale, float yScale, float zScale);
+
+ virtual void refresh(bool fetchFlag);
+
+ virtual int select(SoPath *);
+ virtual int remove(SoPath *);
+
+ virtual void infoText(QString &str, bool) const;
+
+ virtual void launch(Launch &launch, bool) const;
+
+ virtual void dump(QTextStream &) const;
+
+private:
+
+ ScaleMod();
+ ScaleMod(const ScaleMod &);
+ const ScaleMod &operator=(const ScaleMod &);
+ // Never defined
+};
+
+#endif /* _SCALEMOD_H_ */
diff --git a/src/pmview/scenefileobj.cpp b/src/pmview/scenefileobj.cpp
new file mode 100644
index 0000000..76d7446
--- /dev/null
+++ b/src/pmview/scenefileobj.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoRotationXYZ.h>
+#include <Inventor/nodes/SoCylinder.h>
+#include <Inventor/nodes/SoCube.h>
+#include <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoScale.h>
+
+#include <ctype.h>
+#include "stackmod.h"
+#include "togglemod.h"
+#include "scenefileobj.h"
+#include "defaultobj.h"
+#include "colorlist.h"
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * Constructor for Generic Inventor Scene Object.
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+SceneFileObj::SceneFileObj (const DefaultObj & defs,
+ int c, int r,
+ int colSpan, int rowSpan,
+ BaseObj::Alignment align)
+ : ModObj (false, defs, c, r, colSpan, rowSpan, center)
+ , _align(align)
+ , _tag ("\n")
+{
+ _objtype |= SCENEFILEOBJ;
+
+ for ( int i=0; i < 3; i++) {
+ _color[i] = defs.baseColor(i);
+ }
+
+ cellHeight = defs.baseHeight();
+ _stackHeight = defs.pipeLength();
+
+ if ( _align == north || _align == south ) {
+ cellWidth = defs.baseHeight();
+ cellDepth = (defs.pipeLength() < cellHeight) ?
+ cellHeight : defs.pipeLength();
+ } else {
+ cellWidth = (defs.pipeLength() < cellHeight) ?
+ cellHeight : defs.pipeLength();
+ cellDepth = defs.baseHeight();
+ }
+
+ _width = colSpan * cellWidth;
+ _depth = rowSpan * cellDepth;
+ _sceneFileName[0] = '\0';
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ *
+\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+void
+SceneFileObj::finishedAdd ()
+{
+ SoSeparator *sp;
+
+ BaseObj::addBase (_root);
+ if ((sp = readSceneFile())) {
+ _root->addChild (sp);
+ // To make sure the viewer will display a scene with a single
+ // IV scenegraph treat all IV scenegraphs as "modulated" objects.
+ ViewObj::theNumModObjects++;
+ } else {
+ pmprintf("Warning: Failed to read scene file \"%s\"\n", _sceneFileName);
+ }
+}
+
+void
+SceneFileObj::setTag (const char * s)
+{
+ _tag = s;
+ if ( strchr (s, '\n' ) == NULL ) {
+ _tag.append ("\n");
+ }
+}
+
+SoSeparator *
+SceneFileObj::readSceneFile(void)
+{
+ SoInput input;
+ SoSeparator *s;
+ FILE *f = NULL;
+
+ if (_sceneFileName[0] == '<') {
+ char *p = _sceneFileName+1;
+
+ while (*p) {
+ if (! isdigit(*p))
+ break;
+ p++;
+ }
+
+ if (*p == '\0') {
+ int fd = atoi(_sceneFileName+1);
+
+ if ((f = fdopen(fd, "r")) == NULL) {
+ return (NULL);
+ }
+ input.setFilePointer(f);
+ }
+ }
+
+ if (f == NULL) {
+ if (!input.openFile(_sceneFileName))
+ return NULL;
+ }
+ s = SoDB::readAll(&input);
+ input.closeFile();
+
+ return s;
+}
diff --git a/src/pmview/scenefileobj.h b/src/pmview/scenefileobj.h
new file mode 100644
index 0000000..0ddb1f5
--- /dev/null
+++ b/src/pmview/scenefileobj.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _SCENEFILEOBJ_H_
+#define _SCENEFILEOBJ_H_
+
+#include <Inventor/SoLists.h>
+#include "modobj.h"
+#include "modlist.h"
+
+class SceneFileObj : public ModObj
+{
+public:
+ virtual ~SceneFileObj () {}
+ SceneFileObj(const DefaultObj &, int, int, int, int, Alignment);
+
+ int width () const { return _width; }
+ int depth () const { return _depth; }
+
+ const char * name() const { return "SceneFile"; }
+ SoSeparator *readSceneFile(void);
+ void setSceneFileName(char *fname) { strcpy(_sceneFileName, fname); };
+
+ void finishedAdd ();
+ void setTag (const char *);
+
+private:
+ SceneFileObj ();
+ SceneFileObj (SceneFileObj const &);
+ SceneFileObj const& operator=(SceneFileObj const &);
+
+ int _width, _depth;
+ int cellWidth, cellDepth, cellHeight;
+ Alignment _align;
+ float _stackHeight;
+ QString _tag;
+
+ float _color[3];
+ char _sceneFileName[MAXPATHLEN];
+};
+
+#endif /* _SCENEFILEOBJ_H_ */
diff --git a/src/pmview/scenegroup.cpp b/src/pmview/scenegroup.cpp
new file mode 100644
index 0000000..810c089
--- /dev/null
+++ b/src/pmview/scenegroup.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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 "main.h"
+#include "pmview.h"
+#include "scenegroup.h"
+#include "qed_console.h"
+#include "qed_timecontrol.h"
+
+SceneGroup::SceneGroup() : QedGroupControl()
+{
+}
+
+SceneGroup::~SceneGroup()
+{
+}
+
+void SceneGroup::init(struct timeval *interval, struct timeval *position)
+{
+ QedGroupControl::init(interval, position);
+}
+
+bool SceneGroup::isArchiveSource(void)
+{
+ // Note: We purposefully are not using QmcGroup::mode() here, as we
+ // may not have initialised any contexts yet. In such a case, live
+ // mode is always returned (default, from the QmcGroup constructor).
+
+ return this == archiveGroup;
+}
+
+bool SceneGroup::isActive(QmcTime::Packet *packet)
+{
+ return (((activeGroup == archiveGroup) &&
+ (packet->source == QmcTime::ArchiveSource)) ||
+ ((activeGroup == liveGroup) &&
+ (packet->source == QmcTime::HostSource)));
+}
+
+bool SceneGroup::isRecording(QmcTime::Packet *packet)
+{
+ (void)packet;
+ return pmview->isViewRecording();
+}
+
+void SceneGroup::setButtonState(QedTimeButton::State state)
+{
+ pmview->setButtonState(state);
+}
+
+void SceneGroup::updateTimeAxis(void)
+{
+ QString tz, otz, unused;
+
+ if (numContexts() > 0 || isArchiveSource() == false) {
+ if (numContexts() > 0)
+ defaultTZ(unused, otz);
+ else
+ otz = QmcSource::localHost;
+ tz = otz;
+ pmview->setDateLabel((int)timePosition(), tz);
+ } else {
+ pmview->setDateLabel(tr("[No open archives]"));
+ }
+
+ if (console->logLevel(QedApp::DebugProtocol)) {
+ console->post(QedApp::DebugProtocol,
+ "SceneGroup::updateTimeAxis: tz=%s",
+ (const char *)tz.toAscii());
+ }
+}
+
+void SceneGroup::updateTimeButton(void)
+{
+ pmview->setButtonState(buttonState());
+}
+
+void SceneGroup::setupWorldView()
+{
+ activeGroup->QedGroupControl::setupWorldView(
+ pmtime->archiveInterval(), pmtime->archivePosition(),
+ pmtime->archiveStart(), pmtime->archiveEnd());
+}
+
+void SceneGroup::adjustLiveWorldViewForward(QmcTime::Packet *packet)
+{
+ double position = timePosition();
+
+ console->post("Fetching data at %s", QedApp::timeString(position));
+ fetch();
+
+ setTimeState(packet->state == QmcTime::StoppedState ?
+ StandbyState : ForwardState);
+
+ QedGroupControl::adjustLiveWorldViewForward(packet);
+ pmview->render(PmView::inventor, 0);
+}
+
+void SceneGroup::adjustArchiveWorldViewForward(QmcTime::Packet *packet, bool setup)
+{
+ console->post("SceneGroup::adjustArchiveWorldViewForward");
+ setTimeState(ForwardState);
+
+ int setmode = PM_MODE_INTERP;
+ int delta = packet->delta.tv_sec;
+ if (packet->delta.tv_usec == 0) {
+ setmode |= PM_XTB_SET(PM_TIME_SEC);
+ } else {
+ delta = delta * 1000 + packet->delta.tv_usec / 1000;
+ setmode |= PM_XTB_SET(PM_TIME_MSEC);
+ }
+
+ struct timeval timeval;
+ double position = timePosition();
+ QedApp::timevalFromSeconds(timePosition(), &timeval);
+ setArchiveMode(setmode, &timeval, delta);
+ console->post("Fetching data at %s", QedApp::timeString(position));
+ fetch();
+
+ QedGroupControl::adjustArchiveWorldViewForward(packet, setup);
+ pmview->render(PmView::inventor, 0);
+}
+
+void SceneGroup::adjustArchiveWorldViewBackward(QmcTime::Packet *packet, bool setup)
+{
+ console->post("SceneGroup::adjustArchiveWorldViewBackward");
+ setTimeState(BackwardState);
+
+ int setmode = PM_MODE_INTERP;
+ int delta = packet->delta.tv_sec;
+ if (packet->delta.tv_usec == 0) {
+ setmode |= PM_XTB_SET(PM_TIME_SEC);
+ } else {
+ delta = delta * 1000 + packet->delta.tv_usec / 1000;
+ setmode |= PM_XTB_SET(PM_TIME_MSEC);
+ }
+
+ struct timeval timeval;
+ double position = timePosition();
+ QedApp::timevalFromSeconds(timePosition(), &timeval);
+ setArchiveMode(setmode, &timeval, delta);
+ console->post("Fetching data at %s", QedApp::timeString(position));
+ fetch();
+
+ QedGroupControl::adjustArchiveWorldViewBackward(packet, setup);
+ pmview->render(PmView::inventor, 0);
+}
+
+//
+// Fetch all metric values across all scenes, and update the status bar.
+//
+void SceneGroup::adjustStep(QmcTime::Packet *packet)
+{
+ (void)packet; // no-op in pmview
+}
+
+void SceneGroup::step(QmcTime::Packet *packet)
+{
+ QedGroupControl::step(packet);
+ pmview->render(PmView::inventor, 0);
+}
+
+void SceneGroup::setTimezone(QmcTime::Packet *packet, char *tz)
+{
+ QedGroupControl::setTimezone(packet, tz);
+ if (isActive(packet))
+ updateTimeAxis();
+}
diff --git a/src/pmview/scenegroup.h b/src/pmview/scenegroup.h
new file mode 100644
index 0000000..0e40697
--- /dev/null
+++ b/src/pmview/scenegroup.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+#ifndef SCENEGROUP_H
+#define SCENEGROUP_H
+
+#include <QtCore/QList>
+#include <QtGui/QColor>
+#include <QtGui/QPainter>
+#include <QtGui/QDockWidget>
+#include <QtGui/QAbstractButton>
+#include "qed_groupcontrol.h"
+#include "qmc_metric.h"
+#include "qmc_group.h"
+#include "qmc_time.h"
+
+class SceneGroup : public QedGroupControl
+{
+ Q_OBJECT
+
+public:
+ SceneGroup();
+ virtual ~SceneGroup();
+ void init(struct timeval *, struct timeval *);
+
+ bool isArchiveSource();
+ bool isActive(QmcTime::Packet *);
+ bool isRecording(QmcTime::Packet *);
+
+ void updateTimeAxis();
+ void updateTimeButton();
+
+ void setupWorldView();
+ void step(QmcTime::Packet *);
+ void setTimezone(QmcTime::Packet *, char *);
+
+protected:
+ void adjustLiveWorldViewForward(QmcTime::Packet *);
+ void adjustArchiveWorldViewForward(QmcTime::Packet *, bool);
+ void adjustArchiveWorldViewBackward(QmcTime::Packet *, bool);
+
+ void adjustStep(QmcTime::Packet *);
+ void setButtonState(QedTimeButton::State);
+
+private:
+ void refreshScenes(bool);
+
+// struct {
+// } my;
+};
+
+#endif // SCENEGROUP_H
diff --git a/src/pmview/stackmod.cpp b/src/pmview/stackmod.cpp
new file mode 100644
index 0000000..448b9bb
--- /dev/null
+++ b/src/pmview/stackmod.cpp
@@ -0,0 +1,594 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/SoPath.h>
+#include <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoScale.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoSelection.h>
+#include <Inventor/nodes/SoSwitch.h>
+#include "stackmod.h"
+#include "modlist.h"
+#include "launch.h"
+
+#include <iostream>
+using namespace std;
+
+//
+// Use debug flag LIBPMDA to trace stack refreshes
+//
+
+const float StackMod::theDefFillColor[] = { 0.35, 0.35, 0.35 };
+const char StackMod::theStackId = 's';
+
+StackMod::~StackMod()
+{
+}
+
+StackMod::StackMod(MetricList *metrics, SoNode *obj, StackMod::Height height)
+: Modulate(metrics),
+ _blocks(),
+ _switch(0),
+ _height(height),
+ _text(),
+ _selectCount(0),
+ _infoValue(0),
+ _infoMetric(0),
+ _infoInst(0)
+{
+ int numValues = _metrics->numValues();
+ int numMetrics = _metrics->numMetrics();
+ char buf[32];
+ float initScale = 0.0;
+ int m, i, v;
+
+ _root = new SoSeparator;
+
+ if (numValues > 0) {
+ m = numValues;
+ if (_height == fixed) {
+ m++;
+ _text.append(QChar('\n'));
+ }
+
+ _blocks.resize(m);
+ _infoValue = m+1;
+
+ initScale = 1.0 / (float)numValues;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "StackMod::StackMod: numValues = "
+ << numValues << ", num of blocks = " << m << endl
+ << *_metrics;
+#endif
+
+ for (m = 0, v = 0; m < numMetrics; m++) {
+ const QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ StackBlock block;
+
+ block._sep = new SoSeparator;
+ sprintf(buf, "%c%d", theStackId, v);
+ block._sep->setName((SbName)buf);
+ _root->addChild(block._sep);
+
+ block._color = new SoBaseColor;
+ block._color->rgb.setValue(_errorColor.getValue());
+ block._sep->addChild(block._color);
+
+ block._scale = new SoScale;
+ block._scale->scaleFactor.setValue(1.0, initScale, 1.0);
+ block._sep->addChild(block._scale);
+
+ block._sep->addChild(obj);
+
+ block._state = Modulate::start;
+ block._selected = false;
+
+ if (_height == fixed || v < numValues - 1) {
+ block._tran = new SoTranslation();
+ block._tran->translation.setValue(0.0, initScale, 0.0);
+ _root->addChild(block._tran);
+ }
+ else {
+ block._tran = NULL;
+ }
+ _blocks[v] = block;
+ }
+ }
+
+ if (_height == fixed) {
+ StackBlock block;
+ block._sep = new SoSeparator;
+ _root->addChild(block._sep);
+ sprintf(buf, "%c%d", theStackId, v);
+ block._sep->setName((SbName)buf);
+
+ _switch = new SoSwitch();
+ _switch->whichChild.setValue(SO_SWITCH_ALL);
+ block._sep->addChild(_switch);
+
+ block._color = new SoBaseColor;
+ block._color->rgb.setValue(theDefFillColor);
+ _switch->addChild(block._color);
+
+ block._tran = NULL;
+ block._scale = new SoScale;
+ block._scale->scaleFactor.setValue(1.0, 0.0, 1.0);
+ block._state = Modulate::start;
+ block._selected = false;
+ _switch->addChild(block._scale);
+
+ _switch->addChild(obj);
+ _blocks[v] = block;
+ }
+
+ add();
+ }
+
+ // Invalid object
+ else {
+
+ _sts = -1;
+
+ SoBaseColor *tmpColor = new SoBaseColor();
+ tmpColor->rgb.setValue(_errorColor.getValue());
+ _root->addChild(tmpColor);
+
+ _root->addChild(obj);
+ }
+}
+
+void
+StackMod::refresh(bool fetchFlag)
+{
+ int numValues = _metrics->numValues();
+ int numMetrics = _metrics->numMetrics();
+ int m, i, v;
+ double sum = 0.0;
+
+ static QVector<double> values;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LIBPMDA)
+ cerr << endl << "StackMod::refresh" << endl;
+#endif
+
+ if (status() < 0)
+ return;
+
+ if (numValues > values.size())
+ values.resize(numValues);
+
+ for (m = 0, v = 0; m < numMetrics; m++) {
+ QmcMetric &metric = _metrics->metric(m);
+ if (fetchFlag)
+ metric.update();
+ for (i = 0; i < metric.numValues(); i++, v++) {
+
+ StackBlock &block = _blocks[v];
+ double &value = values[v];
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LIBPMDA)
+ cerr << '[' << v << "] ";
+#endif
+
+ if (metric.error(i) <= 0) {
+ if (block._state != Modulate::error) {
+ block._color->rgb.setValue(_errorColor.getValue());
+ block._state = Modulate::error;
+ }
+ value = Modulate::theMinScale;
+ sum += value;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LIBPMDA)
+ cerr << "Error, value set to " << value << endl;
+#endif
+
+ }
+ else if (block._state == Modulate::error ||
+ block._state == Modulate::start) {
+ block._state = Modulate::normal;
+ if (numMetrics == 1)
+ block._color->rgb.setValue(_metrics->color(v).getValue());
+ else
+ block._color->rgb.setValue(_metrics->color(m).getValue());
+ value = metric.value(i) * theScale;
+ if (value < theMinScale)
+ value = theMinScale;
+ sum += value;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LIBPMDA)
+ cerr << "Error->Normal, value = " << value << endl;
+#endif
+
+ }
+ else {
+ value = metric.value(i) * theScale;
+ if (value < theMinScale)
+ value = theMinScale;
+ sum += value;
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LIBPMDA)
+ cerr << "Normal, value = " << value << endl;
+#endif
+
+ }
+ }
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LIBPMDA)
+ cerr << "sum = " << sum << endl;
+#endif
+
+ if (sum > theNormError && _height != util) {
+ if (_blocks[0]._state != Modulate::saturated) {
+ for (v = 0; v < numValues; v++) {
+ StackBlock &block = _blocks[v];
+ if (block._state != Modulate::error) {
+ block._color->rgb.setValue(Modulate::_saturatedColor);
+ block._state = Modulate::saturated;
+ }
+ }
+ }
+ }
+ else {
+ for (m = 0, v = 0; m < numMetrics; m++) {
+ QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ StackBlock &block = _blocks[v];
+ if (block._state == Modulate::saturated) {
+ block._state = Modulate::normal;
+ if (numMetrics == 1)
+ block._color->rgb.setValue(_metrics->color(v).getValue());
+ else
+ block._color->rgb.setValue(_metrics->color(m).getValue());
+ }
+ }
+ }
+ }
+
+ // Scale values to the range [0,1].
+ // Ensure that each block always has the minimum height to
+ // avoid planes clashing
+
+ if (sum > 1.0 || _height == util) {
+ double oldSum = sum;
+ double max = 1.0 - (theMinScale * (numValues - 1));
+ sum = 0.0;
+ for (v = 0; v < numValues; v++) {
+ double &value = values[v];
+ value /= oldSum;
+ sum += value;
+ if (sum > max) {
+ value -= sum - max;
+ sum -= sum - max;
+ }
+ if (value < theMinScale)
+ value = theMinScale;
+ max += theMinScale;
+ }
+ }
+
+ for (v = 0; v < numValues; v++) {
+
+ StackBlock &block = _blocks[v];
+ double &value = values[v];
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_LIBPMDA)
+ cerr << '[' << v << "] scale = " << value << endl;
+#endif
+
+ block._scale->scaleFactor.setValue(1.0, value, 1.0);
+
+ if (v < numValues-1 || _height == fixed)
+ block._tran->translation.setValue(0.0, value, 0.0);
+ }
+
+ if (_height == fixed) {
+ sum = 1.0 - sum;
+ if (sum >= theMinScale) {
+ _switch->whichChild.setValue(SO_SWITCH_ALL);
+ _blocks[v]._scale->scaleFactor.setValue(1.0, sum, 1.0);
+ }
+ else {
+ _switch->whichChild.setValue(SO_SWITCH_NONE);
+ _blocks[v]._scale->scaleFactor.setValue(1.0, theMinScale, 1.0);
+ }
+ }
+}
+
+void
+StackMod::dump(QTextStream &os) const
+{
+ int m, i, v;
+
+ os << "StackMod: ";
+
+ if (status() < 0)
+ os << "Invalid metrics: " << pmErrStr(status()) << endl;
+ else {
+ os << endl;
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ os << " [" << v << "]: ";
+ if (_blocks[v]._selected == true)
+ os << '*';
+ else
+ os << ' ';
+ dumpState(os, _blocks[v]._state);
+ os << ": ";
+ metric.dump(os, true, i);
+ }
+ }
+ }
+}
+
+void
+StackMod::infoText(QString &str, bool selected) const
+{
+ int m = _infoMetric;
+ int i = _infoInst;
+ int v = _infoValue;
+ bool found = false;
+
+ if (selected && _selectCount == 1) {
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ const QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++)
+ if (_blocks[v]._selected) {
+ found = true;
+ break;
+ }
+ if (found)
+ break;
+ }
+ }
+
+ if (v >= _blocks.size()) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "StackMod::infoText: infoText requested but nothing selected"
+ << endl;
+#endif
+ str = "";
+ }
+ else if (_height == fixed && v == _blocks.size() - 1) {
+ str = _text;
+ }
+ else {
+ const QmcMetric &metric = _metrics->metric(m);
+ str = metric.spec(true, true, i);
+ str.append(QChar('\n'));
+
+ if (_blocks[v]._state == Modulate::error)
+ str.append(theErrorText);
+ else if (_blocks[v]._state == Modulate::start)
+ str.append(theStartText);
+ else {
+ QString value;
+ str.append(value.setNum(metric.realValue(i), 'g', 4));
+ str.append(QChar(' '));
+ if (metric.desc().units().length() > 0)
+ str.append(metric.desc().units());
+ str.append(" [");
+ str.append(value.setNum(metric.value(i) * 100.0, 'g', 4));
+ str.append("% of expected max]");
+ }
+ }
+}
+
+void
+StackMod::launch(Launch &launch, bool all) const
+{
+ int m, i, v;
+ bool launchAll = all;
+
+ if (status() < 0)
+ return;
+
+ // If the filler block is selected, launch all metrics
+ if (!launchAll && _height == fixed &&
+ _blocks.last()._selected == true) {
+ launchAll = true;
+ }
+
+ if (_height == StackMod::util)
+ launch.startGroup("util");
+ else
+ launch.startGroup("stack");
+
+ for (m = 0, v = 0; m < _metrics->numMetrics(); m++) {
+ QmcMetric &metric = _metrics->metric(m);
+ for (i = 0; i < metric.numValues(); i++, v++) {
+ if ((_selectCount > 0 && _blocks[v]._selected == true) ||
+ _selectCount == 0 || launchAll == true) {
+
+ launch.addMetric(_metrics->metric(m),
+ _metrics->color(m),
+ i);
+ }
+ }
+ }
+
+ launch.endGroup();
+}
+
+void
+StackMod::selectAll()
+{
+ int i;
+
+ if (_selectCount == _blocks.size())
+ return;
+
+ theModList->selectAllId(_root, _blocks.size());
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "StackMod::selectAll" << endl;
+#endif
+
+ for (i = 0; i < _blocks.size(); i++) {
+ if (_blocks[i]._selected == false) {
+ _selectCount++;
+ theModList->selectSingle(_blocks[i]._sep);
+ _blocks[i]._selected = true;
+ }
+ }
+}
+
+int
+StackMod::select(SoPath *path)
+{
+ int metric, inst, value;
+
+ findBlock(path, metric, inst, value, false);
+ if (value < _blocks.size() && _blocks[value]._selected == false) {
+ _blocks[value]._selected = true;
+ _selectCount++;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "StackMod::select: value = " << value
+ << ", count = " << _selectCount << endl;
+#endif
+ }
+ return _selectCount;
+}
+
+int
+StackMod::remove(SoPath *path)
+{
+ int metric, inst, value;
+
+ findBlock(path, metric, inst, value, false);
+ if (value < _blocks.size() && _blocks[value]._selected == true) {
+ _blocks[value]._selected = false;
+ _selectCount--;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "StackMod::remove: value = " << value
+ << ", count = " << _selectCount << endl;
+#endif
+
+ }
+
+#ifdef PCP_DEBUG
+ else if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "StackMod::remove: did not remove " << value
+ << ", count = " << _selectCount << endl;
+#endif
+
+ return _selectCount;
+}
+
+void
+StackMod::selectInfo(SoPath *path)
+{
+ findBlock(path, _infoMetric, _infoInst, _infoValue);
+}
+
+void
+StackMod::removeInfo(SoPath *)
+{
+ _infoValue = _blocks.size();
+ _infoMetric = _infoInst = 0;
+}
+
+void
+StackMod::findBlock(SoPath *path, int &metric, int &inst,
+ int &value, bool idMetric)
+{
+ SoNode *node;
+ char *str;
+ int m, i, v;
+ char c;
+
+ for (i = path->getLength() - 1; i >= 0; --i) {
+ node = path->getNode(i);
+ str = (char *)(node->getName().getString());
+ if (strlen(str) && str[0] == theStackId)
+ break;
+ }
+
+ if (i >= 0) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "StackMod::findBlock: stack id = " << str << endl;
+#endif
+
+ sscanf(str, "%c%d", &c, &value);
+
+ if (value == 0 || idMetric == false) {
+ metric = 0;
+ inst = 0;
+ }
+ else {
+ m = 0;
+ v = value;
+ while (m < _metrics->numMetrics()) {
+ i = _metrics->metric(m).numValues();
+ if (v < i) {
+ metric = m;
+ inst = v;
+ break;
+ }
+ else {
+ v -= i;
+ m++;
+ }
+ }
+ }
+ }
+ else {
+ value = _blocks.size();
+ metric = inst = 0;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ cerr << "StackMod::findBlock: metric = " << metric
+ << ", inst = " << inst << ", value = " << value << endl;
+ }
+#endif
+
+ return;
+}
+
+void
+StackMod::setFillColor(const SbColor &col)
+{
+ if (_sts >= 0 && _height == fixed)
+ _blocks.last()._color->rgb.setValue(col.getValue());
+}
+
+void
+StackMod::setFillColor(int packedcol)
+{
+ SbColor col;
+ float dummy = 0;
+
+ col.setPackedValue(packedcol, dummy);
+ setFillColor(col);
+}
diff --git a/src/pmview/stackmod.h b/src/pmview/stackmod.h
new file mode 100644
index 0000000..8c0fbc5
--- /dev/null
+++ b/src/pmview/stackmod.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _STACKMOD_H_
+#define _STACKMOD_H_
+
+#include <QtCore/QVector>
+#include "modulate.h"
+
+class SoBaseColor;
+class SoTranslation;
+class SoScale;
+class SoNode;
+class SoSwitch;
+class Launch;
+
+struct StackBlock {
+ SoSeparator *_sep;
+ SoBaseColor *_color;
+ SoScale *_scale;
+ SoTranslation *_tran;
+ Modulate::State _state;
+ bool _selected;
+};
+
+typedef QVector<StackBlock> StackBlockList;
+
+class StackMod : public Modulate
+{
+public:
+
+ enum Height { unfixed, fixed, util };
+
+private:
+
+ static const float theDefFillColor[];
+ static const char theStackId;
+
+ StackBlockList _blocks;
+ SoSwitch *_switch;
+ Height _height;
+ QString _text;
+ int _selectCount;
+ int _infoValue;
+ int _infoMetric;
+ int _infoInst;
+
+public:
+
+ virtual ~StackMod();
+
+ StackMod(MetricList *metrics,
+ SoNode *obj,
+ Height height = unfixed);
+
+ void setFillColor(const SbColor &col);
+ void setFillColor(int packedcol);
+ void setFillText(const char *str)
+ { _text = str; }
+
+ virtual void refresh(bool fetchFlag);
+
+ virtual void selectAll();
+ virtual int select(SoPath *);
+ virtual int remove(SoPath *);
+
+ virtual void selectInfo(SoPath *);
+ virtual void removeInfo(SoPath *);
+
+ virtual void infoText(QString &str, bool) const;
+
+ virtual void launch(Launch &launch, bool all) const;
+
+ virtual void dump(QTextStream &) const;
+
+private:
+
+ StackMod();
+ StackMod(const StackMod &);
+ const StackMod &operator=(const StackMod &);
+ // Never defined
+
+ void findBlock(SoPath *path, int &metric, int &inst,
+ int &value, bool idMetric = true);
+};
+
+#endif /* _STACKMOD_H_ */
diff --git a/src/pmview/stackobj.cpp b/src/pmview/stackobj.cpp
new file mode 100644
index 0000000..faa8d42
--- /dev/null
+++ b/src/pmview/stackobj.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoScale.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoTransform.h>
+#include "stackobj.h"
+#include "colorlist.h"
+#include "defaultobj.h"
+
+#include <iostream>
+using namespace std;
+
+StackObj::~StackObj()
+{
+ delete _stack;
+}
+
+StackObj::StackObj(StackMod::Height height,
+ ViewObj::Shape shape,
+ bool baseFlag,
+ const DefaultObj &defaults,
+ int x, int y,
+ int cols, int rows,
+ BaseObj::Alignment align)
+: ModObj(baseFlag, defaults, x, y, cols, rows, align),
+ _width(0),
+ _depth(0),
+ _height(height),
+ _stack(0),
+ _text()
+{
+ _objtype |= STACKOBJ;
+ _shape = shape;
+}
+
+void
+StackObj::finishedAdd()
+{
+ int i;
+
+ BaseObj::addBase(_root);
+
+ if (_metrics.numMetrics() == 0) {
+ pmprintf("%s: Error: Stack object has no metrics\n",
+ pmProgname);
+ _length = 0;
+ }
+ else {
+ SoScale *blockScale = new SoScale();
+ blockScale->scaleFactor.setValue(_length, _maxHeight, _length);
+ _root->addChild(blockScale);
+
+ if (_metrics.numMetrics()) {
+ const char *colName = (const char *)_colors.toAscii();
+ const ColorSpec *colSpec = theColorLists.list(colName);
+ if (colSpec != NULL) {
+ if (colSpec->_scale)
+ pmprintf("%s: Warning: Color scale ignored for stack object.\n",
+ pmProgname);
+ else {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "StackObj::finishedAdd: Adding "
+ << colSpec->_list.length()
+ << " colors for " << _metrics.numMetrics()
+ << " metrics" << endl;
+#endif
+
+ for (i = 0; i < colSpec->_list.size(); i++)
+ _metrics.add(*(colSpec->_list)[i]);
+ }
+ }
+ else
+ pmprintf("%s: Warning: No colours specified for stack object, "
+ "defaulting to blue.\n", pmProgname);
+
+ _metrics.resolveColors(MetricList::perValue);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << "StackObj::finishedAdd: metrics: " << endl
+ << _metrics << endl;
+#endif
+
+ _stack = new StackMod(&_metrics, ViewObj::object(_shape), _height);
+ _root->addChild(_stack->root());
+
+ if (_text.length())
+ _stack->setFillText((const char *)_text.toAscii());
+
+ BaseObj::add(_stack);
+ ViewObj::theNumModObjects++;
+ }
+ else
+ _length = 0;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ cerr << name() << "has length " << _length << endl;
+#endif
+
+ _width = baseWidth() + _length;
+ _depth = baseDepth() + _length;
+}
+
+void
+StackObj::setTran(float xTran, float zTran, int setWidth, int setDepth)
+{
+ BaseObj::setBaseSize(width(), depth());
+ BaseObj::setTran(xTran + (width() / 2.0),
+ zTran + (depth() / 2.0),
+ setWidth, setDepth);
+}
+
+QTextStream&
+operator<<(QTextStream& os, StackObj const& rhs)
+{
+ rhs.display(os);
+ return os;
+}
+
+void
+StackObj::display(QTextStream& os) const
+{
+ BaseObj::display(os);
+ os << ", length = " << _length << ": ";
+ if (_stack)
+ os << *_stack << endl;
+ else
+ os << "stack undefined!" << endl;
+}
diff --git a/src/pmview/stackobj.h b/src/pmview/stackobj.h
new file mode 100644
index 0000000..76fed4a
--- /dev/null
+++ b/src/pmview/stackobj.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _STACKOBJ_H_
+#define _STACKOBJ_H_
+
+#include "modobj.h"
+#include "stackmod.h"
+
+class SoSeparator;
+
+class StackObj : public ModObj
+{
+protected:
+
+ int _width;
+ int _depth;
+ StackMod::Height _height;
+ ViewObj::Shape _shape;
+ StackMod *_stack;
+ QString _text;
+
+public:
+
+ virtual ~StackObj();
+
+ StackObj(StackMod::Height height,
+ ViewObj::Shape shape,
+ bool baseFlag,
+ const DefaultObj &defaults,
+ int x, int z,
+ int cols = 1, int rows = 1,
+ BaseObj::Alignment align = BaseObj::center);
+
+ virtual int width() const
+ { return _width; }
+ virtual int depth() const
+ { return _depth; }
+ StackMod::Height height() const
+ { return _height; }
+
+ void setFillText(const char *str)
+ { _text = str; }
+
+ virtual void finishedAdd();
+
+ virtual void setTran(float xTran, float zTran, int width, int depth);
+
+ virtual const char* name() const
+ { return "Stack"; }
+
+ virtual void display(QTextStream& os) const;
+
+ friend QTextStream& operator<<(QTextStream& os, StackObj const& rhs);
+
+ virtual void setBarHeight (int h) { _maxHeight = h; }
+
+private:
+
+ StackObj();
+ StackObj(StackObj const&);
+ StackObj const& operator=(StackObj const &);
+};
+
+#endif /* _STACKOBJ_H_ */
diff --git a/src/pmview/text.cpp b/src/pmview/text.cpp
new file mode 100644
index 0000000..f4547b4
--- /dev/null
+++ b/src/pmview/text.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/Qt/viewers/SoQtExaminerViewer.h>
+#include <Inventor/actions/SoGetBoundingBoxAction.h>
+#include <Inventor/nodes/SoPickStyle.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoRotation.h>
+#include <Inventor/nodes/SoCube.h>
+#include "main.h"
+#include "text.h"
+
+#include <iostream>
+using namespace std;
+
+const char *Text::theHeightStr = "gjpqy|_";
+
+SoFont *Text::theSmallFont = (SoFont *)0;
+SoFont *Text::theMediumFont = (SoFont *)0;
+SoFont *Text::theLargeFont = (SoFont *)0;
+
+SbVec3f Text::theColor(1.0, 1.0, 1.0);
+SoGetBoundingBoxAction *Text::theBoxAction = (SoGetBoundingBoxAction *)0;
+
+Text::~Text()
+{
+}
+
+Text::Text(const QString &theString,
+ Direction theDir,
+ FontSize theFontSize,
+ bool rightJust)
+: _width(0),
+ _depth(0),
+ _dir(theDir),
+ _fontSize(theFontSize),
+ _rightJustFlag(rightJust),
+ _root(0),
+ _translation(0)
+{
+ float x = 0.0;
+ float y = 0.0;
+ float z = 0.0;
+ int width = 0;
+ int height = 0;
+ SoRotation *rot1;
+ SoRotation *rot2;
+ SoText3 *theText;
+
+ _root = new SoSeparator;
+ _translation = new SoTranslation;
+ theText = new SoText3;
+
+ SoPickStyle *style = new SoPickStyle;
+ style->style = SoPickStyle::UNPICKABLE;
+ _root->addChild(style);
+
+ if (theSmallFont == (SoFont *)0) {
+ char * font = getenv ("PMVIEW_FONT");
+
+ theSmallFont = new SoFont;
+ theMediumFont = new SoFont;
+ theLargeFont = new SoFont;
+
+ if ( font != NULL ) {
+ theSmallFont->name.setValue(font);
+ theMediumFont->name.setValue(font);
+ theLargeFont->name.setValue(font);
+#ifdef __sgi
+ } else {
+ // On Irix we know that Helvetica-Narrow is shipped as part
+ // of x_eoe.sw.Xfonts, so we're going to use it since it's
+ // an easier font to render compared to Times.
+ theSmallFont->name.setValue("Helvetica-Narrow");
+ theMediumFont->name.setValue("Helvetica-Narrow");
+ theLargeFont->name.setValue("Helvetica-Narrow");
+#endif
+ }
+
+ theSmallFont->size.setValue(14);
+ theMediumFont->size.setValue(24);
+ theLargeFont->size.setValue(32);
+ theSmallFont->ref();
+ theMediumFont->ref();
+ theLargeFont->ref();
+ theBoxAction = new SoGetBoundingBoxAction(pmview->viewer()->getViewportRegion());
+ }
+
+ switch(_fontSize) {
+ case small:
+ _root->addChild(theSmallFont->copy());
+ break;
+ case medium:
+ _root->addChild(theMediumFont->copy());
+ break;
+ case large:
+ _root->addChild(theLargeFont->copy());
+ break;
+ default:
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "Text::Text: Illegal size specified" << endl;
+#endif
+ _fontSize = medium;
+ _root->addChild(theMediumFont->copy());
+ }
+
+ _translation->translation.setValue(0.0, 0.0, 0.0);
+ _root->addChild(_translation);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ SoSeparator *sep = new SoSeparator;
+ _root->addChild(sep);
+ SoBaseColor *col = new SoBaseColor;
+ col->rgb.setValue(1.0, 0.0, 0.0);
+ sep->addChild(col);
+ SoCube *cube = new SoCube;
+ cube->width.setValue(3);
+ cube->depth.setValue(3);
+ cube->height.setValue(20);
+ sep->addChild(cube);
+ }
+#endif
+
+ if (_dir != vertical) {
+
+ rot1 = new SoRotation;
+ rot1->rotation.setValue(SbVec3f(1,0,0), -M_PI/2);
+ _root->addChild(rot1);
+
+ switch(_dir) {
+ case left:
+ rot2 = new SoRotation;
+ rot2->rotation.setValue(SbVec3f(0,0,1), M_PI);
+ _root->addChild(rot2);
+ break;
+ case down:
+ rot2 = new SoRotation;
+ rot2->rotation.setValue(SbVec3f(0,0,1), -M_PI/2);
+ _root->addChild(rot2);
+ break;
+ case up:
+ rot2 = new SoRotation;
+ rot2->rotation.setValue(SbVec3f(0,0,1), M_PI/2);
+ _root->addChild(rot2);
+ break;
+ default:
+ break;
+ }
+
+ if (((_dir == left || _dir == up) && !_rightJustFlag) ||
+ ((_dir == right || _dir == down) && !_rightJustFlag)) {
+ theText->justification = SoText3::RIGHT;
+ }
+
+ theText->parts = SoText3::FRONT;
+ theText->string.setValue((const char *)theString.toAscii());
+ _root->addChild(theText);
+
+ _root->ref();
+ theBoxAction->apply(_root);
+ SbXfBox3f box = theBoxAction->getBoundingBox();
+ box.getSize(x, y, z);
+
+ if (x < 0.0 || y < 0.0 || z < 0.0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ cerr << "Text::Text: Bogus bounding box returned for \""
+ << theString << "\": x = " << x << ", y = " << y
+ << ", z = " << z << endl;
+ }
+#endif
+ x = 0.0;
+ y = 0.0;
+ z = 0.0;
+ }
+
+ _width = (int)ceilf(x);
+ _depth = (int)ceilf(z);
+
+ const char *hasLow = strpbrk((const char *)theString.toAscii(), theHeightStr);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ cerr << "Text::Text: " << theString << ": width = "
+ << _width << " height = " << _depth << " low = "
+ << ((hasLow != (char *)0) ? 1 : 0) << endl;
+ }
+#endif
+
+ switch(_dir) {
+ case left:
+ if (hasLow != (char *)0) {
+ _translation->translation.setValue(1, 1, _depth * 0.3);
+ _depth = (int)(_depth * 1.2);
+ }
+ else
+ _translation->translation.setValue(1, 1, 0);
+ _width += 2;
+ break;
+ case right:
+ if (hasLow != (char *)0) {
+ _translation->translation.setValue(1, 1, _depth * 0.85);
+ _depth = (int)(_depth * 1.2);
+ }
+ else
+ _translation->translation.setValue(1, 1, _depth);
+ _width += 2;
+ break;
+ case down:
+ if (hasLow != (char *)0) {
+ _translation->translation.setValue(_width * 0.3, 1, 1);
+ _width = (int)(_width * 1.2);
+ }
+ else
+ _translation->translation.setValue(0, 1, 1);
+ _depth += 2;
+ break;
+ case up:
+ if (hasLow != (char *)0) {
+ _translation->translation.setValue(_width * 0.85, 1, 1);
+ _width = (int)(_width * 1.2);
+ }
+ else
+ _translation->translation.setValue(_width, 1, 1);
+ _depth += 2;
+ break;
+ default:
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ cerr << "Text::Text: Illegal direction specified ("
+ << (int)_dir << ")" << endl;
+#endif
+ break;
+ }
+ }
+ else {
+ char c[2] = { ' ', '\0' };
+ SoSeparator *sep;
+ SoTranslation *tran;
+ SoRotation *rot;
+ width = 0;
+ height = 0;
+
+ for (int i = 0; i < theString.length(); i++) {
+ c[0] = ((const char *)theString.toAscii())[i];
+ sep = new SoSeparator;
+ tran = new SoTranslation;
+ rot = new SoRotation;
+ rot->rotation.setValue(SbVec3f(1,0,0), -M_PI/2);
+ theText->string.setValue(c);
+ theText->parts = SoText3::FRONT;
+
+ _root->addChild(sep);
+ sep->addChild(rot);
+ sep->addChild(tran);
+ sep->addChild(theText);
+
+ theBoxAction->apply(sep);
+ SbXfBox3f box = theBoxAction->getBoundingBox();
+ box.getSize(x, y, z);
+
+ width = (int)ceilf(x);
+ height = (int)ceilf(z);
+
+// TODO: This bounding box is wrong.
+
+ if (width*2 > _width)
+ _width = width*2;
+
+ _depth += (height + 2) * 2;
+
+ tran->translation.setValue(0, -_depth, 1);
+
+ if (i < theString.length() - 1) {
+ theText = new SoText3;
+ }
+ }
+ }
+}
+
+
+QTextStream&
+operator<<(QTextStream& os, Text const& rhs)
+{
+ rhs.display(os);
+ return os;
+}
+
+void
+Text::display(QTextStream& os) const
+{
+ os << "Text: dir = ";
+ switch(_dir) {
+ case left:
+ os << "left";
+ break;
+ case right:
+ os << "right";
+ break;
+ case up:
+ os << "up";
+ break;
+ case down:
+ os << "down";
+ break;
+ default:
+ break;
+ }
+ os << ", font size = ";
+ switch(_fontSize) {
+ case small:
+ os << "small";
+ break;
+ case medium:
+ os << "medium";
+ break;
+ case large:
+ os << "large";
+ break;
+ }
+}
diff --git a/src/pmview/text.h b/src/pmview/text.h
new file mode 100644
index 0000000..f9a6854
--- /dev/null
+++ b/src/pmview/text.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _TEXT_H_
+#define _TEXT_H_
+
+#include <QtCore/QTextStream>
+#include <Inventor/nodes/SoFont.h>
+#include <Inventor/nodes/SoText3.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoBaseColor.h>
+
+class Text
+{
+ public:
+
+ enum Direction { left, right, up, down, vertical };
+ enum FontSize { small, medium, large };
+
+ private:
+
+ int _width;
+ int _depth;
+ Direction _dir;
+ FontSize _fontSize;
+ bool _rightJustFlag;
+
+ SoSeparator *_root;
+ SoTranslation *_translation;
+
+ static const char *theHeightStr;
+ static SoFont *theSmallFont;
+ static SoFont *theMediumFont;
+ static SoFont *theLargeFont;
+
+ static SbVec3f theColor;
+ static SoGetBoundingBoxAction *theBoxAction;
+
+ public:
+
+ ~Text();
+
+ Text(const QString &theText,
+ Direction theDir,
+ FontSize theFontSize,
+ bool rightJust = false);
+
+ int width() const
+ { return _width; }
+ int depth() const
+ { return _depth; }
+ Direction dir() const
+ { return _dir; }
+ FontSize size() const
+ { return _fontSize; }
+
+ SoSeparator* root() const
+ { return _root; }
+
+ friend QTextStream& operator<<(QTextStream& os, Text const& rhs);
+
+ void display(QTextStream& os) const;
+
+ private:
+
+ Text();
+ Text(Text const &);
+ Text const& operator=(Text const&);
+};
+
+#endif /* _TEXT_H_ */
diff --git a/src/pmview/togglemod.cpp b/src/pmview/togglemod.cpp
new file mode 100644
index 0000000..282bbe8
--- /dev/null
+++ b/src/pmview/togglemod.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoSelection.h>
+#include <Inventor/SoPath.h>
+#include "main.h"
+#include "togglemod.h"
+
+#include <iostream>
+using namespace std;
+
+ToggleMod::~ToggleMod()
+{
+}
+
+ToggleMod::ToggleMod(SoNode *obj, const char *label)
+: Modulate(NULL),
+ _label(label)
+{
+ _root = new SoSeparator;
+ _root->addChild(obj);
+
+ if (_label.length() == 0)
+ _label = "\n";
+
+ add();
+}
+
+void
+ToggleMod::dump(QTextStream &os) const
+{
+ os << "ToggleMod: \"" << _label << "\" has " << _list.size()
+ << " objects" << endl;
+}
+
+void
+ToggleMod::selectAll()
+{
+ int i;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ToggleMod::selectAll: \"" << _label << '"' << endl;
+#endif
+
+ for (i = 0; i < _list.size(); i++) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ToggleMod::selectAll: Selecting [" << i << ']'
+ << endl;
+#endif
+
+ _list[i]->selectAll();
+ }
+}
+
+int
+ToggleMod::select(SoPath *path)
+{
+ int i;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ToggleMod::select: \"" << _label << '"' << endl;
+#endif
+
+ theModList->selectAllOn();
+
+ for (i = 0; i < _list.size(); i++) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ToggleMod::select: Selecting [" << i << ']' << endl;
+#endif
+
+ _list[i]->selectAll();
+ }
+
+ theModList->selectAllOff();
+
+ theModList->selector()->deselect(path->getNodeFromTail(0));
+
+ return 0;
+}
+
+int
+ToggleMod::remove(SoPath *)
+{
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ cerr << "ToggleMod::remove: " << _label << endl;
+#endif
+ return 0;
+}
+
diff --git a/src/pmview/togglemod.h b/src/pmview/togglemod.h
new file mode 100644
index 0000000..dafd65e
--- /dev/null
+++ b/src/pmview/togglemod.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _TOGGLEMOD_H_
+#define _TOGGLEMOD_H_
+
+#include <Inventor/SbString.h>
+#include "modulate.h"
+#include "modlist.h"
+
+class SoSeparator;
+class SoPath;
+class Launch;
+class Record;
+
+class ToggleMod : public Modulate
+{
+private:
+
+ ModulateList _list;
+ QString _label;
+
+public:
+
+ virtual ~ToggleMod();
+
+ ToggleMod(SoNode *obj, const char *label);
+
+ void addMod(Modulate *mod)
+ { _list.append(mod); }
+
+ virtual void selectAll();
+ virtual int select(SoPath *);
+ virtual int remove(SoPath *);
+
+ virtual void selectInfo(SoPath *)
+ {}
+ virtual void removeInfo(SoPath *)
+ {}
+
+ virtual void infoText(QString &str, bool) const
+ { str = _label; }
+
+ virtual void refresh(bool)
+ {}
+ virtual void launch(Launch &, bool) const
+ {}
+ virtual void record(Record &) const
+ {}
+
+ virtual void dump(QTextStream &) const;
+ void dumpState(QTextStream &os, Modulate::State state) const;
+
+ friend QTextStream &operator<<(QTextStream &os, const ToggleMod &rhs);
+
+private:
+
+ ToggleMod();
+ ToggleMod(const ToggleMod &);
+ const ToggleMod &operator=(const ToggleMod &);
+ // Never defined
+};
+
+#endif /* _TOGGLEMOD_H_ */
diff --git a/src/pmview/viewobj.cpp b/src/pmview/viewobj.cpp
new file mode 100644
index 0000000..f0e9b30
--- /dev/null
+++ b/src/pmview/viewobj.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoCube.h>
+#include <Inventor/nodes/SoCylinder.h>
+#include "pmview.h"
+#include "viewobj.h"
+
+#include <iostream>
+using namespace std;
+
+int ViewObj::theNumModObjects = 0;
+
+ViewObj::~ViewObj()
+{
+}
+
+ViewObj::ViewObj(int x, int z, int cols, int rows, Alignment align)
+ : _root(new SoSeparator)
+ , _tran(new SoTranslation)
+ , _objtype(VIEWOBJ)
+ , _col(x)
+ , _row(z)
+ , _cols(cols)
+ , _rows(rows)
+{
+ _tran->translation.setValue(0.0, 0.0, 0.0);
+ _root->addChild(_tran);
+
+ switch(align) {
+ case north:
+ _xAlign = 0.5;
+ _zAlign = 0.0;
+ break;
+ case south:
+ _xAlign = 0.5;
+ _zAlign = 1.0;
+ break;
+ case east:
+ _xAlign = 1.0;
+ _zAlign = 0.5;
+ break;
+ case west:
+ _xAlign = 0.0;
+ _zAlign = 0.5;
+ break;
+ case northEast:
+ _xAlign = 1.0;
+ _zAlign = 0.0;
+ break;
+ case northWest:
+ _xAlign = 0.0;
+ _zAlign = 0.0;
+ break;
+ case southEast:
+ _xAlign = 1.0;
+ _zAlign = 1.0;
+ break;
+ case southWest:
+ _xAlign = 0.0;
+ _zAlign = 1.0;
+ break;
+ case center:
+ default:
+ _xAlign = 0.5;
+ _zAlign = 0.5;
+ break;
+ }
+}
+
+SoNode *
+ViewObj::object(Shape shape)
+{
+ static SoSeparator *cubeSep = NULL;
+ static SoSeparator *cylSep = NULL;
+ SoNode *obj;
+
+ switch(shape) {
+ case cylinder:
+ if (cylSep == NULL) {
+ cylSep = new SoSeparator();
+ SoTranslation *cylTran = new SoTranslation;
+ cylTran->translation.setValue(0.0, 0.5, 0.0);
+ cylSep->addChild(cylTran);
+ SoCylinder *cyl = new SoCylinder;
+ cyl->radius.setValue(0.5);
+ cyl->height.setValue(1.0);
+ cylSep->addChild(cyl);
+ }
+ obj = cylSep;
+ break;
+
+ case cube:
+ default:
+ if (cubeSep == NULL) {
+ cubeSep = new SoSeparator();
+ SoTranslation *cubeTran = new SoTranslation;
+ cubeTran->translation.setValue(0.0, 0.5, 0.0);
+ cubeSep->addChild(cubeTran);
+ SoCube *cube = new SoCube;
+ cube->height = cube->width = cube->depth = 1.0;
+ cubeSep->addChild(cube);
+ }
+ obj = cubeSep;
+ break;
+ }
+
+ return obj;
+}
+
+void
+ViewObj::setTran(float xTran, float zTran, int setWidth, int setDepth)
+{
+ float x = xTran + ((setWidth - (float)width()) * _xAlign);
+ float z = zTran + ((setDepth - (float)depth()) * _zAlign);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ cerr << "ViewObj::setTran: " << name() << ":" << endl;
+ cerr << "x=" << x << ", xTran =" << xTran << ", setWidth="
+ << setWidth << ", width=" << width() << ", xAlign=" << _xAlign
+ << endl;
+ cerr << "z=" << z << ", zTran =" << zTran << ", setDepth="
+ << setDepth << ", depth=" << depth() << ", zAlign=" << _zAlign
+ << endl << endl;
+ }
+#endif
+
+ _tran->translation.setValue(x, 0.0, z);
+}
+
+QTextStream&
+operator<<(QTextStream& os, ViewObj const& rhs)
+{
+ rhs.display(os);
+ return os;
+}
+
+void
+ViewObj::display(QTextStream& os) const
+{
+ os << name() << ": size = " << width() << "x" << depth() << " ("
+ << _tran->translation.getValue()[0] << ','
+ << _tran->translation.getValue()[1] << ','
+ << _tran->translation.getValue()[2] << "), cols = " << _cols
+ << ", rows = " << _rows << ", alignment = " << _xAlign << ','
+ << _zAlign;
+}
+
+void
+ViewObj::dumpShape(QTextStream& os, ViewObj::Shape shape) const
+{
+ if (shape == ViewObj::cube)
+ os << "cube";
+ else
+ os << "cylinder";
+}
diff --git a/src/pmview/viewobj.h b/src/pmview/viewobj.h
new file mode 100644
index 0000000..f713c71
--- /dev/null
+++ b/src/pmview/viewobj.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _VIEWOBJ_H_
+#define _VIEWOBJ_H_
+
+#include <QtCore/QTextStream>
+
+class SoNode;
+class SoSeparator;
+class SoTranslation;
+class Modulate;
+class DefaultObj;
+
+class ViewObj
+{
+public:
+
+ enum Alignment { north, south, east, west,
+ northEast, northWest, southEast, southWest,
+ center };
+
+ enum Shape { cube, cylinder };
+
+ // Poor man substitution for RTTI until O32 compiler will either
+ // die or start supporting that stuff
+ enum ObjType {VIEWOBJ = 1,
+ BASEOBJ = 2,
+ LABELOBJ = 4,
+ MODOBJ = 8,
+ GRIDOBJ = 16,
+ PIPEOBJ = 32,
+ BAROBJ = 64,
+ STACKOBJ = 128,
+ LINK = 256,
+ XING = 512,
+ SCENEFILEOBJ = 1024
+ };
+
+protected:
+
+ SoSeparator *_root;
+ SoTranslation *_tran;
+
+ int _objtype;
+ int _col;
+ int _row;
+ int _cols;
+ int _rows;
+ int _maxHeight;
+ float _xAlign;
+ float _zAlign;
+
+ static int theNumModObjects;
+
+public:
+
+ virtual ~ViewObj();
+
+ ViewObj(int, int, int cols = 1, int rows = 1,
+ Alignment align = center);
+
+ // The Scene Graph Root for this object
+ SoSeparator* root()
+ { return _root; }
+
+ int objbits() const { return _objtype; }
+ int row() const { return _row; }
+ int col() const { return _col; }
+
+ int cols() const
+ { return _cols; }
+ int rows() const
+ { return _rows; }
+ int height() const
+ { return _maxHeight; }
+ int &height()
+ { return _maxHeight; }
+ float xAlign() const
+ { return _xAlign; }
+ float zAlign() const
+ { return _zAlign; }
+
+ // Set the coordinates (and the allocated size) from parent
+ virtual void setTran(float xTran, float zTran, int width, int depth);
+
+ // Size (in object coordinates). Must be the correct value before
+ // the object is added to the parent.
+ virtual int width() const = 0;
+ virtual int depth() const = 0;
+
+ static int numModObjects()
+ { return theNumModObjects; }
+
+ // Return default object
+ static SoNode *object(Shape shape);
+
+ virtual Modulate *modObj()
+ { return (Modulate *)0; }
+
+ // Inform object parsing stuff is done
+
+ virtual void finishedAdd() = 0;
+
+ // Output
+ virtual void display(QTextStream& os) const;
+
+ virtual const char* name() const = 0;
+
+ friend QTextStream& operator<<(QTextStream& os, ViewObj const& rhs);
+
+protected:
+
+ void dumpShape(QTextStream& os, ViewObj::Shape shape) const;
+
+private:
+
+ ViewObj();
+ ViewObj(ViewObj const &);
+ ViewObj const& operator=(ViewObj const &);
+ // Never defined
+};
+
+#endif /* _VIEWOBJ_H_ */
diff --git a/src/pmview/xing.cpp b/src/pmview/xing.cpp
new file mode 100644
index 0000000..c7637e0
--- /dev/null
+++ b/src/pmview/xing.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoSphere.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include <Inventor/nodes/SoTranslation.h>
+#include <Inventor/nodes/SoTransform.h>
+#include <Inventor/nodes/SoRotation.h>
+#include <Inventor/nodes/SoCylinder.h>
+#include <Inventor/nodes/SoClipPlane.h>
+#include <Inventor/nodes/SoBaseColor.h>
+
+#include "xing.h"
+#include "defaultobj.h"
+
+Xing::Xing (const DefaultObj & dobj, int c, int r,
+ int colSpan, int rowSpan,
+ Alignment corners[4])
+ : BaseObj (false, dobj, c, r, colSpan, rowSpan, center)
+{
+ int i;
+ _objtype |= XING;
+
+ for (i = 0; i < 3; i++) {
+ _color[i] = dobj.baseColor(i);
+ }
+
+ _width = colSpan * _cellWidth;
+ _depth = rowSpan * _cellDepth;
+ _cellHeight = dobj.baseHeight();
+ _cellWidth = dobj.baseHeight();
+ _cellDepth = dobj.baseHeight();
+
+ for ( i=0; i < 4; i++ ) {
+ _corner[i] = corners[i];
+ }
+}
+
+void
+Xing::finishedAdd ()
+{
+ int i;
+ float ts[12] = {
+ (float)(_cellWidth/2.0), (float)(_cellHeight/2.0), (float)(_cellDepth/2.0),
+ (float)(_width - _cellWidth), 0, 0,
+ 0, 0, (float)(_depth - _cellDepth),
+ (float)(_cellWidth - _width), 0, 0
+ };
+
+ SoBaseColor * cl = new SoBaseColor;
+ cl->rgb.setValue (_color);
+ _root->addChild (cl);
+
+ SoSeparator * scene = new SoSeparator;
+
+ for (i=0; i < 4; i++ ) {
+ SoTranslation * t = new SoTranslation;
+ t->translation.setValue (ts+i*3);
+ scene->addChild(t);
+
+ SoSphere * s = new SoSphere;
+ s->radius.setValue (_cellHeight*0.4);
+ scene->addChild (s);
+
+ SoSeparator * csep = new SoSeparator;
+
+ float ch;
+
+ ctrans[i] = new SoTransform;
+ switch ( _corner[i] ) {
+ case south:
+ ch = _cellDepth/2.0;
+ ctrans[i]->translation.setValue (0, 0, _cellDepth/4.0);
+ ctrans[i]->rotation.setValue (SbVec3f(1, 0, 0), M_PI/2);
+ break;
+
+ case east:
+ ch = _cellWidth/2.0;
+ ctrans[i]->translation.setValue (_cellWidth/4.0, 0, 0);
+ ctrans[i]->rotation.setValue (SbVec3f(0, 0, 1), M_PI/2);
+ break;
+
+ case west:
+ ch = _cellWidth/2.0;
+ ctrans[i]->translation.setValue (_cellWidth/-4.0, 0, 0);
+ ctrans[i]->rotation.setValue (SbVec3f(0, 0, 1), M_PI/2);
+ break;
+
+ case north:
+ ch = _cellDepth/2.0;
+ ctrans[i]->translation.setValue (0, 0, _cellDepth/-4.0);
+ ctrans[i]->rotation.setValue (SbVec3f(1, 0, 0), M_PI/2);
+ break;
+
+ default:
+ ch = 0.0;
+ break;
+ }
+ csep->addChild (ctrans[i]);
+
+ cyls[i] = new SoCylinder;
+ cyls[i]->radius.setValue (_cellHeight*0.4);
+ cyls[i]->height.setValue (ch);
+ csep->addChild (cyls[i]);
+
+ scene->addChild (csep);
+ }
+
+ float cilh = sqrt (_cellWidth*_cellWidth*(cols()-1)*(cols()-1) +
+ _cellDepth*_cellDepth*(rows()-1)*(rows()-1));
+
+ // We're in the bottom left corner now
+ SbVec3f axis(rows()-1, 0, cols()-1);
+ SoTransform * tr = new SoTransform;
+ tr->rotation.setValue (axis, M_PI/2);
+ tr->translation.setValue (((cols()-1)*_cellWidth)/2.0, 0,
+ ((rows()-1)*_cellDepth)/-2.0);
+
+ scene->addChild (tr);
+
+ SoCylinder * c1 = new SoCylinder;
+ c1->radius.setValue (_cellHeight*0.4);
+ c1->height.setValue (cilh);
+ scene->addChild (c1);
+
+ axis[0] = cols() - 1;
+ axis[2] = -((float)(rows()-1));
+
+ // To draw a "broken" cylinder, define two clipping planes along the
+ // "main" cylinder and draw the crossing one twice, each time enabling
+ // a different plane.
+ for (i=-1; i < 2; i += 2 ) {
+ SoSeparator * sp = new SoSeparator;
+
+ SbVec3f normal(i*((int)(rows()-1)), 0, i*((int)(cols()-1)));
+ SbPlane p (normal, _cellHeight/2.0);
+
+ SoClipPlane * c = new SoClipPlane;
+ c->on.setValue (1);
+ c->plane = p;
+
+ sp->addChild (c);
+
+ SoRotation * r = new SoRotation;
+ r->rotation.setValue (axis, atanf (axis[0]/(rows()-1))*2.0);
+ sp->addChild (r);
+ sp->addChild (c1);
+
+ scene->addChild (sp);
+ }
+
+ _root->addChild (scene);
+}
+
+void
+Xing::setTran(float x, float z, int w, int d)
+{
+ float ch;
+
+ for ( int i=0; i < 4; i++) {
+ switch ( _corner[i] ) {
+ case south:
+ ch = (d + _cellDepth - _depth)/2.0;
+ ctrans[i]->translation.setValue (0, 0, ch/2.0);
+ break;
+
+ case east:
+ ch = (w + _cellWidth - _width)/2.0;
+ ctrans[i]->translation.setValue (ch/2.0, 0, 0);
+ break;
+
+ case west:
+ ch = (w +_cellWidth - _width)/2.0;
+ ctrans[i]->translation.setValue (-ch/2.0, 0, 0);
+ break;
+
+ case north:
+ ch = (d + _cellDepth - _depth)/2.0;
+ ctrans[i]->translation.setValue (0, 0, -ch/2.0);
+ break;
+
+ default:
+ ch = 0.0;
+ break;
+ }
+
+ cyls[i]->height.setValue (ch);
+ }
+
+ BaseObj::setTran (x, z, w, d);
+}
diff --git a/src/pmview/xing.h b/src/pmview/xing.h
new file mode 100644
index 0000000..b5920bd
--- /dev/null
+++ b/src/pmview/xing.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _XING_H_
+#define _XING_H_
+
+#include "baseobj.h"
+
+class SoTransform;
+class SoCylinder;
+
+class Xing : public BaseObj
+{
+public:
+ Xing (const DefaultObj &, int, int, int, int, Alignment[4]);
+
+ void finishedAdd ();
+ void setTran (float, float, int, int);
+ int width () const { return _width; }
+ int depth () const { return _depth; }
+ const char * name () const { return "Xing"; }
+
+private:
+ Xing();
+ Xing(Xing const &);
+ Xing const & operator= (Xing const &);
+
+ int _width;
+ int _depth;
+ int _cellHeight, _cellDepth, _cellWidth;
+ float _color[3];
+ Alignment _corner[4];
+ SoTransform * ctrans[4];
+ SoCylinder * cyls[4];
+};
+
+#endif /* _XING_H_ */
diff --git a/src/pmview/yscalemod.cpp b/src/pmview/yscalemod.cpp
new file mode 100644
index 0000000..63359f5
--- /dev/null
+++ b/src/pmview/yscalemod.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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 <Inventor/nodes/SoBaseColor.h>
+#include <Inventor/nodes/SoScale.h>
+#include <Inventor/nodes/SoSeparator.h>
+#include "main.h"
+#include "yscalemod.h"
+#include "modlist.h"
+#include "launch.h"
+
+YScaleMod::~YScaleMod()
+{
+}
+
+YScaleMod::YScaleMod(const char *str, double scale,
+ const SbColor &color, SoNode *obj)
+: ScaleMod(str, scale, color, obj, 0.0, 1.0, 0.0)
+{
+}
+
+void
+YScaleMod::dump(QTextStream &os) const
+{
+ os << "YScaleMod: ";
+
+ if (status() < 0)
+ os << "Invalid metric";
+ else {
+ os << "state = ";
+ dumpState(os, _state);
+ os << ", scale = " << _scale->scaleFactor.getValue()[1] << ": ";
+ _metrics->metric(0).dump(os, true);
+ }
+}
diff --git a/src/pmview/yscalemod.h b/src/pmview/yscalemod.h
new file mode 100644
index 0000000..a0458f6
--- /dev/null
+++ b/src/pmview/yscalemod.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved.
+ * 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.
+ */
+#ifndef _YSCALEMOD_H_
+#define _YSCALEMOD_H_
+
+#include "scalemod.h"
+
+class SoBaseColor;
+class SoScale;
+class SoNode;
+class Launch;
+
+class YScaleMod : public ScaleMod
+{
+public:
+
+ virtual ~YScaleMod();
+
+ YScaleMod(const char *metric, double scale, const SbColor &color,
+ SoNode *obj);
+
+ virtual void dump(QTextStream &) const;
+
+private:
+
+ YScaleMod();
+ YScaleMod(const YScaleMod &);
+ const YScaleMod &operator=(const YScaleMod &);
+ // Never defined
+};
+
+#endif /* _YSCALEMOD_H_ */