summaryrefslogtreecommitdiff
path: root/src/libpcp_qed
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpcp_qed')
-rw-r--r--src/libpcp_qed/GNUmakefile27
-rw-r--r--src/libpcp_qed/src/GNUmakefile24
-rw-r--r--src/libpcp_qed/src/libpcp_qed.pro51
-rw-r--r--src/libpcp_qed/src/qed.h28
-rw-r--r--src/libpcp_qed/src/qed_actionlist.cpp52
-rw-r--r--src/libpcp_qed/src/qed_actionlist.h40
-rw-r--r--src/libpcp_qed/src/qed_app.cpp256
-rw-r--r--src/libpcp_qed/src/qed_app.h82
-rw-r--r--src/libpcp_qed/src/qed_bar.cpp95
-rw-r--r--src/libpcp_qed/src/qed_bar.h66
-rw-r--r--src/libpcp_qed/src/qed_colorlist.cpp38
-rw-r--r--src/libpcp_qed/src/qed_colorlist.h33
-rw-r--r--src/libpcp_qed/src/qed_colorpicker.cpp306
-rw-r--r--src/libpcp_qed/src/qed_colorpicker.h170
-rw-r--r--src/libpcp_qed/src/qed_console.cpp96
-rw-r--r--src/libpcp_qed/src/qed_console.h41
-rw-r--r--src/libpcp_qed/src/qed_console.ui132
-rw-r--r--src/libpcp_qed/src/qed_fileiconprovider.cpp140
-rw-r--r--src/libpcp_qed/src/qed_fileiconprovider.h53
-rw-r--r--src/libpcp_qed/src/qed_gadget.cpp26
-rw-r--r--src/libpcp_qed/src/qed_gadget.h33
-rw-r--r--src/libpcp_qed/src/qed_groupcontrol.cpp260
-rw-r--r--src/libpcp_qed/src/qed_groupcontrol.h89
-rw-r--r--src/libpcp_qed/src/qed_label.cpp28
-rw-r--r--src/libpcp_qed/src/qed_label.h38
-rw-r--r--src/libpcp_qed/src/qed_led.cpp155
-rw-r--r--src/libpcp_qed/src/qed_led.h65
-rw-r--r--src/libpcp_qed/src/qed_legend.cpp53
-rw-r--r--src/libpcp_qed/src/qed_legend.h55
-rw-r--r--src/libpcp_qed/src/qed_line.cpp92
-rw-r--r--src/libpcp_qed/src/qed_line.h44
-rw-r--r--src/libpcp_qed/src/qed_recorddialog.cpp327
-rw-r--r--src/libpcp_qed/src/qed_recorddialog.h94
-rw-r--r--src/libpcp_qed/src/qed_recorddialog.ui540
-rw-r--r--src/libpcp_qed/src/qed_statusbar.cpp106
-rw-r--r--src/libpcp_qed/src/qed_statusbar.h62
-rw-r--r--src/libpcp_qed/src/qed_timebutton.cpp79
-rw-r--r--src/libpcp_qed/src/qed_timebutton.h61
-rw-r--r--src/libpcp_qed/src/qed_timecontrol.cpp442
-rw-r--r--src/libpcp_qed/src/qed_timecontrol.h111
-rw-r--r--src/libpcp_qed/src/qed_viewcontrol.cpp165
-rw-r--r--src/libpcp_qed/src/qed_viewcontrol.h71
42 files changed, 4726 insertions, 0 deletions
diff --git a/src/libpcp_qed/GNUmakefile b/src/libpcp_qed/GNUmakefile
new file mode 100644
index 0000000..552118e
--- /dev/null
+++ b/src/libpcp_qed/GNUmakefile
@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This library 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 Lesser General Public
+# License for more details.
+#
+
+TOPDIR = ../..
+include $(TOPDIR)/src/include/builddefs
+
+SUBDIRS = src
+
+default install : $(SUBDIRS)
+ $(SUBDIRS_MAKERULE)
+
+include $(BUILDRULES)
+
+default_pcp : default
+
+install_pcp : install
diff --git a/src/libpcp_qed/src/GNUmakefile b/src/libpcp_qed/src/GNUmakefile
new file mode 100644
index 0000000..e11a2cf
--- /dev/null
+++ b/src/libpcp_qed/src/GNUmakefile
@@ -0,0 +1,24 @@
+TOPDIR = ../../..
+LIBRARY = libpcp_qed
+PROJECT = $(LIBRARY).pro
+include $(TOPDIR)/src/include/builddefs
+
+HEADERS = $(shell echo *.h)
+SOURCES = $(shell echo *.cpp)
+
+default: build-me
+
+ifeq "$(ENABLE_QT)" "true"
+build-me: $(PROJECT)
+ $(QTMAKE)
+else
+build-me:
+endif
+
+include $(BUILDRULES)
+
+install: default
+
+default_pcp: default
+
+install_pcp: install
diff --git a/src/libpcp_qed/src/libpcp_qed.pro b/src/libpcp_qed/src/libpcp_qed.pro
new file mode 100644
index 0000000..294a66a
--- /dev/null
+++ b/src/libpcp_qed/src/libpcp_qed.pro
@@ -0,0 +1,51 @@
+TARGET = pcp_qed
+TEMPLATE = lib
+VERSION = 1.0.0
+CONFIG += qt staticlib warn_on
+INCLUDEPATH += ../../include ../../libpcp_qmc/src
+QT = core gui network svg
+
+HEADERS = qed.h \
+ qed_actionlist.h \
+ qed_app.h \
+ qed_bar.h \
+ qed_colorlist.h \
+ qed_colorpicker.h \
+ qed_console.h \
+ qed_fileiconprovider.h \
+ qed_gadget.h \
+ qed_groupcontrol.h \
+ qed_label.h \
+ qed_led.h \
+ qed_legend.h \
+ qed_line.h \
+ qed_recorddialog.h \
+ qed_statusbar.h \
+ qed_timebutton.h \
+ qed_timecontrol.h \
+ qed_viewcontrol.h \
+
+SOURCES = \
+ qed_actionlist.cpp \
+ qed_app.cpp \
+ qed_bar.cpp \
+ qed_colorlist.cpp \
+ qed_colorpicker.cpp \
+ qed_console.cpp \
+ qed_fileiconprovider.cpp \
+ qed_gadget.cpp \
+ qed_groupcontrol.cpp \
+ qed_label.cpp \
+ qed_led.cpp \
+ qed_legend.cpp \
+ qed_line.cpp \
+ qed_recorddialog.cpp \
+ qed_statusbar.cpp \
+ qed_timebutton.cpp \
+ qed_timecontrol.cpp \
+ qed_viewcontrol.cpp \
+
+FORMS = \
+ qed_console.ui \
+ qed_recorddialog.ui \
+
diff --git a/src/libpcp_qed/src/qed.h b/src/libpcp_qed/src/qed.h
new file mode 100644
index 0000000..36a3155
--- /dev/null
+++ b/src/libpcp_qed/src/qed.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef QED_H
+#define QED_H
+
+//
+// Qt Extensions and Doodads Library
+// doodad: An un-namable gadget of some sort, possibly highly technical.
+//
+
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+
+class QedLED;
+class QedLine;
+class QedLabel;
+class QedLegend;
+class QedGadget;
+class QedColorList;
+class QedActionList;
+
+#endif // QED_H
diff --git a/src/libpcp_qed/src/qed_actionlist.cpp b/src/libpcp_qed/src/qed_actionlist.cpp
new file mode 100644
index 0000000..a371b64
--- /dev/null
+++ b/src/libpcp_qed/src/qed_actionlist.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 "qed_actionlist.h"
+
+QedActionList::QedActionList(const char *id) : QString(id)
+{
+ my.defaultPos = -1;
+}
+
+const char *
+QedActionList::identity(void) const
+{
+ return this->toAscii();
+}
+
+void
+QedActionList::addName(const char *name)
+{
+ my.names << QString(name);
+}
+
+void
+QedActionList::addAction(const char *act)
+{
+ my.actions << QString(act);
+}
+
+// QMenu &QedActionList::menu() { }
+
+int
+QedActionList::defaultPos(void)
+{
+ return my.defaultPos;
+}
+
+void
+QedActionList::setDefaultPos(unsigned int pos)
+{
+ my.defaultPos = (int)pos;
+}
diff --git a/src/libpcp_qed/src/qed_actionlist.h b/src/libpcp_qed/src/qed_actionlist.h
new file mode 100644
index 0000000..fb78cbe
--- /dev/null
+++ b/src/libpcp_qed/src/qed_actionlist.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_ACTIONLIST_H
+#define QED_ACTIONLIST_H
+
+#include <QtGui>
+
+class QedActionList : public QString
+{
+public:
+ QedActionList(const char *id);
+ const char *identity() const;
+
+ void addName(const char *name);
+ void addAction(const char *act);
+ // QMenu &menu() { /* TODO: construct a real QMenu */ }
+
+ int defaultPos(void);
+ void setDefaultPos(unsigned int pos);
+
+private:
+ struct {
+ QStringList names; // menu names
+ QStringList actions; // commands to enact
+ int defaultPos; // position of default action in list
+ } my;
+};
+
+#endif // QED_ACTIONLIST_H
diff --git a/src/libpcp_qed/src/qed_app.cpp b/src/libpcp_qed/src/qed_app.cpp
new file mode 100644
index 0000000..7aa3268
--- /dev/null
+++ b/src/libpcp_qed/src/qed_app.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2014 Red Hat.
+ * 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.
+ */
+
+#include <math.h>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+#include "qed_app.h"
+#include "qed_console.h"
+
+QedApp::QedApp(int &argc, char **argv) : QApplication(argc, argv)
+{
+ // TODO: rewrite with pmOptions
+ __pmSetProgname(argv[0]);
+ my.argc = argc;
+ my.argv = argv;
+ my.pmnsfile = NULL;
+ my.Lflag = 0;
+ my.Sflag = NULL;
+ my.Tflag = NULL;
+ my.Aflag = NULL;
+ my.Oflag = NULL;
+ my.zflag = 0;
+ my.tz = NULL;
+ my.port = -1;
+
+ QCoreApplication::setOrganizationName("PCP");
+ QCoreApplication::setApplicationName(pmProgname);
+ QCoreApplication::setApplicationVersion(pmGetConfig("PCP_VERSION"));
+ QString confirm = pmGetConfig("PCP_BIN_DIR");
+ confirm.prepend("PCP_XCONFIRM_PROG=");
+ confirm.append("/pmquery");
+ putenv(strdup((const char *)confirm.toAscii()));
+ if (getenv("PCP_STDERR") == NULL) // do not overwrite, for QA
+ putenv(strdup("PCP_STDERR=DISPLAY"));
+}
+
+QFont *QedApp::globalFont()
+{
+ static QFont *globalFont;
+ if (!globalFont)
+ globalFont = new QFont("Sans Serif", QedApp::globalFontSize());
+ return globalFont;
+}
+
+int QedApp::globalFontSize()
+{
+#ifdef IS_DARWIN
+ return 9;
+#else
+ return 7;
+#endif
+}
+
+int QedApp::getopts(const char *options)
+{
+ int unknown = 0;
+ int c, sts, errflg = 0;
+ char *endnum, *msg;
+
+ do {
+ switch ((c = getopt(my.argc, my.argv, options))) {
+
+ case 'A': /* sample alignment */
+ my.Aflag = optarg;
+ continue;
+
+ case 'a':
+ my.archives.append(optarg);
+ break;
+
+ case 'D':
+ sts = __pmParseDebug(optarg);
+ if (sts < 0) {
+ pmprintf("%s: unrecognized debug flag specification (%s)\n",
+ pmProgname, optarg);
+ errflg++;
+ } else
+ pmDebug |= sts;
+ break;
+
+ case 'h':
+ my.hosts.append(optarg);
+ break;
+
+ case 'L': /* local context */
+ my.Lflag = 1;
+ break;
+
+ case 'n': /* alternative PMNS */
+ my.pmnsfile = optarg;
+ break;
+
+ case 'O': /* sample offset */
+ my.Oflag = optarg;
+ break;
+
+ case 'p': /* existing pmtime port */
+ my.port = (int)strtol(optarg, &endnum, 10);
+ if (*endnum != '\0' || c < 0) {
+ pmprintf("%s: -p requires a numeric argument\n", pmProgname);
+ errflg++;
+ }
+ break;
+
+ case 'S': /* start run time */
+ my.Sflag = optarg;
+ break;
+
+ case 't': /* sampling interval */
+ if (pmParseInterval(optarg, &my.delta, &msg) < 0) {
+ pmprintf("%s: cannot parse interval\n%s", pmProgname, msg);
+ free(msg);
+ errflg++;
+ }
+ continue;
+
+ case 'T': /* run time */
+ my.Tflag = optarg;
+ break;
+
+ case 'V': /* version */
+ printf("%s %s\n", pmProgname, pmGetConfig("PCP_VERSION"));
+ exit(0);
+
+ case 'z': /* timezone from host */
+ if (my.tz != NULL) {
+ pmprintf("%s: at most one of -Z and/or -z allowed\n",
+ pmProgname);
+ errflg++;
+ }
+ my.zflag++;
+ break;
+
+ case 'Z': /* $TZ timezone */
+ if (my.zflag) {
+ pmprintf("%s: at most one of -Z and/or -z allowed\n",
+ pmProgname);
+ errflg++;
+ }
+ my.tz = optarg;
+ break;
+
+ default:
+ unknown = 1;
+ break;
+ }
+ } while (!unknown);
+
+ return c;
+}
+
+// a := a + b for struct timevals
+void QedApp::timevalAdd(struct timeval *a, struct timeval *b)
+{
+ a->tv_usec += b->tv_usec;
+ if (a->tv_usec > 1000000) {
+ a->tv_usec -= 1000000;
+ a->tv_sec++;
+ }
+ a->tv_sec += b->tv_sec;
+}
+
+//
+// a : b for struct timevals ... <0 for a<b, ==0 for a==b, >0 for a>b
+//
+int QedApp::timevalCmp(struct timeval *a, struct timeval *b)
+{
+ int res = (int)(a->tv_sec - b->tv_sec);
+ if (res == 0)
+ res = (int)(a->tv_usec - b->tv_usec);
+ return res;
+}
+
+// convert timeval to seconds
+double QedApp::timevalToSeconds(struct timeval t)
+{
+ return t.tv_sec + (t.tv_usec / 1000000.0);
+}
+
+// conversion from seconds (double precision) to struct timeval
+void QedApp::timevalFromSeconds(double value, struct timeval *tv)
+{
+ tv->tv_sec = (time_t)value;
+ tv->tv_usec = (long)(((value - (double)tv->tv_sec) * 1000000.0));
+}
+
+// debugging, display seconds-since-epoch in human readable format
+char *QedApp::timeString(double seconds)
+{
+ static char string[32];
+ time_t secs = (time_t)seconds;
+ char *s;
+
+ s = pmCtime(&secs, string);
+ s[strlen(s)-1] = '\0';
+ return s;
+}
+
+// return a string containing hour and milliseconds
+char *QedApp::timeHiResString(double time)
+{
+ static char s[16];
+ char m[8];
+ time_t secs = (time_t)time;
+ struct tm t;
+
+ sprintf(m, "%.3f", time - floor(time));
+ pmLocaltime(&secs, &t);
+ sprintf(s, "%02d:%02d:%02d.%s", t.tm_hour, t.tm_min, t.tm_sec, m+2);
+ s[strlen(s)-1] = '\0';
+ return s;
+}
+
+void QedApp::nomem(void)
+{
+ // no point trying to report anything ... dump core is the best bet
+ abort();
+}
+
+QPixmap QedApp::cached(const QString &image)
+{
+ if (QPixmap *p = QPixmapCache::find(image))
+ return *p;
+
+ QPixmap pm;
+ pm = QPixmap::fromImage(QImage(image),
+ Qt::OrderedDither | Qt::OrderedAlphaDither);
+ if (pm.isNull())
+ return QPixmap();
+
+ QPixmapCache::insert(image, pm);
+ return pm;
+}
+
+// call startconsole() after command line args processed so pmDebug
+// has a chance to be set
+//
+void QedApp::startconsole(void)
+{
+ struct timeval origin;
+
+ gettimeofday(&origin, NULL);
+ console = new QedConsole(origin);
+}
diff --git a/src/libpcp_qed/src/qed_app.h b/src/libpcp_qed/src/qed_app.h
new file mode 100644
index 0000000..bb3859b
--- /dev/null
+++ b/src/libpcp_qed/src/qed_app.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * 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 QED_APP_H
+#define QED_APP_H
+
+#include <QtGui/QApplication>
+#include <QtGui/QPixmapCache>
+#include <QtGui/QFont>
+
+class QedApp : public QApplication
+{
+ Q_OBJECT
+
+public:
+ typedef enum {
+ DebugApp = 0x1,
+ DebugUi = 0x1,
+ DebugProtocol = 0x2,
+ DebugView = 0x4,
+ DebugTimeless = 0x8,
+ DebugForce = 0x10,
+ } DebugOptions;
+
+ QedApp(int &, char **);
+ virtual ~QedApp() { }
+ int getopts(const char *options);
+ void startconsole(void);
+
+ static QFont *globalFont();
+ static int globalFontSize();
+
+ static void nomem(void);
+ static QPixmap cached(const QString &);
+
+ static void timevalAdd(struct timeval *, struct timeval *);
+ static int timevalCmp(struct timeval *, struct timeval *);
+ static double timevalToSeconds(struct timeval);
+ static void timevalFromSeconds(double, struct timeval *);
+ static char *timeString(double);
+ static char *timeHiResString(double);
+
+ struct {
+ int argc;
+ char **argv;
+
+ char *pmnsfile; /* local namespace file */
+ int Lflag; /* local context mode */
+ char *Sflag; /* argument of -S flag */
+ char *Tflag; /* argument of -T flag */
+ char *Aflag; /* argument of -A flag */
+ char *Oflag; /* argument of -O flag */
+ int zflag; /* for -z (source zone) */
+ char *tz; /* for -Z timezone */
+ int port; /* pmtime port number */
+
+ struct timeval delta;
+ struct timeval logStartTime;
+ struct timeval logEndTime;
+ struct timeval realStartTime;
+ struct timeval realEndTime;
+ struct timeval position;
+
+ QStringList hosts;
+ QStringList archives;
+ QString tzLabel;
+ QString tzString;
+ } my;
+};
+
+#endif // QED_APP_H
diff --git a/src/libpcp_qed/src/qed_bar.cpp b/src/libpcp_qed/src/qed_bar.cpp
new file mode 100644
index 0000000..72b7a96
--- /dev/null
+++ b/src/libpcp_qed/src/qed_bar.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 "qed_bar.h"
+
+QedBar::QedBar(QWidget *parent, int x, int y, int w, int h) : QedGadget(parent)
+{
+ (void)x;
+ (void)y;
+ (void)w;
+ (void)h;
+}
+
+void
+QedBar::setMinimum(double minimum)
+{
+ (void)minimum;
+}
+
+void
+QedBar::setMaximum(double maximum)
+{
+ (void)maximum;
+}
+
+void
+QedBar::setColor(const char *color)
+{
+ (void)color;
+}
+
+void
+QedBar::setOrientation(Qt::Orientation o)
+{
+ (void)o;
+}
+
+void
+QedBar::setScaleRange(int range)
+{
+ (void)range;
+}
+
+void
+QedBar::paintEvent(QPaintEvent *event)
+{
+ (void)event;
+}
+
+void
+QedBar::resizeEvent(QResizeEvent *event)
+{
+ (void)event;
+}
+
+QedMultiBar::QedMultiBar(QWidget *parent, int x, int y, int w, int h,
+ QedColorList *l, int history) : QedBar(parent, x, y, w, h)
+{
+ (void)history;
+ (void)l;
+}
+
+void
+QedMultiBar::setOutline(bool on)
+{
+ (void)on;
+}
+
+void
+QedMultiBar::setMaximum(double maximum, bool on)
+{
+ (void)maximum;
+ (void)on;
+}
+
+QedBarGraph::QedBarGraph(QWidget *parent, int x, int y, int w, int h, int history)
+ : QedBar(parent, x, y, w, h)
+{
+ (void)history;
+}
+
+void
+QedBarGraph::clipRange(void)
+{
+}
diff --git a/src/libpcp_qed/src/qed_bar.h b/src/libpcp_qed/src/qed_bar.h
new file mode 100644
index 0000000..8aafe36
--- /dev/null
+++ b/src/libpcp_qed/src/qed_bar.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_BAR_H
+#define QED_BAR_H
+
+#include <QtGui>
+#include "qed_gadget.h"
+#include "qed_colorlist.h"
+
+class QedBar : public QedGadget
+{
+ Q_OBJECT
+
+public:
+ QedBar(QWidget *parent, int x, int y, int w, int h);
+ void setMinimum(double min);
+ void setMaximum(double max);
+ void setColor(const char *color);
+ void setOrientation(Qt::Orientation);
+ void setScaleRange(int range);
+
+protected:
+ virtual void paintEvent(QPaintEvent *);
+ virtual void resizeEvent(QResizeEvent *);
+
+ struct {
+ QColor color;
+ Qt::Orientation oriented;
+ int scaleRange;
+ double minimum;
+ double maximum;
+ } my;
+};
+
+class QedMultiBar : public QedBar
+{
+ Q_OBJECT
+
+public:
+ QedMultiBar(QWidget *parent, int x, int y, int w, int h,
+ QedColorList *l, int history);
+ void setOutline(bool);
+ void setMaximum(double, bool);
+};
+
+class QedBarGraph : public QedBar
+{
+ Q_OBJECT
+
+public:
+ QedBarGraph(QWidget *parent, int x, int y, int w, int h, int history);
+ void clipRange();
+};
+
+#endif // QED_BAR_H
diff --git a/src/libpcp_qed/src/qed_colorlist.cpp b/src/libpcp_qed/src/qed_colorlist.cpp
new file mode 100644
index 0000000..cb008f0
--- /dev/null
+++ b/src/libpcp_qed/src/qed_colorlist.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 "qed_colorlist.h"
+
+QedColorList::QedColorList(const char *id) : QString(id)
+{
+ // TODO
+}
+
+const char *
+QedColorList::identity(void) const
+{
+ return this->toAscii();
+}
+
+void
+QedColorList::addColor(const char *name)
+{
+ my.names << QString(name);
+}
+
+unsigned int
+QedColorList::length(void)
+{
+ return my.names.length();
+}
diff --git a/src/libpcp_qed/src/qed_colorlist.h b/src/libpcp_qed/src/qed_colorlist.h
new file mode 100644
index 0000000..b918773
--- /dev/null
+++ b/src/libpcp_qed/src/qed_colorlist.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_COLORLIST_H
+#define QED_COLORLIST_H
+
+#include <QtGui>
+
+class QedColorList : public QString
+{
+public:
+ QedColorList(const char *id);
+ void addColor(const char *name);
+ const char *identity() const;
+ unsigned int length();
+
+private:
+ struct {
+ QStringList names; // color names
+ } my;
+};
+
+#endif // QED_COLORLIST_H
diff --git a/src/libpcp_qed/src/qed_colorpicker.cpp b/src/libpcp_qed/src/qed_colorpicker.cpp
new file mode 100644
index 0000000..f4a5405
--- /dev/null
+++ b/src/libpcp_qed/src/qed_colorpicker.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2014 Red Hat.
+ * Copyright (C) 1999-2005 Trolltech AS. All rights reserved.
+ *
+ * This file was derived from the QT QColorDialog class
+ *
+ * This file may be distributed under the terms of the Q Public License
+ * as defined by Trolltech AS of Norway and appearing in the file
+ * LICENSE.QPL included in the packaging of this file.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+ * licenses may use this file in accordance with the Qt Commercial License
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <QApplication>
+#include <QPainter>
+#include "qed_colorpicker.h"
+
+static int pWidth = 172;
+static int pHeight = 172;
+
+int QedColorLuminancePicker::y2val(int y)
+{
+ int d = height() - 2*coff - 1;
+ return 255 - (y - coff)*255/d;
+}
+
+int QedColorLuminancePicker::val2y(int v)
+{
+ int d = height() - 2*coff - 1;
+ return coff + (255-v)*d/255;
+}
+
+QedColorLuminancePicker::QedColorLuminancePicker(QWidget* parent)
+ :QWidget(parent)
+{
+ hue = 100; val = 100; sat = 100;
+ pix = 0;
+ // setAtribute(QA_NoErase, true);
+}
+
+QedColorLuminancePicker::~QedColorLuminancePicker()
+{
+ delete pix;
+}
+
+void QedColorLuminancePicker::mouseMoveEvent(QMouseEvent *m)
+{
+ setVal(y2val(m->y()));
+}
+void QedColorLuminancePicker::mousePressEvent( QMouseEvent *m )
+{
+ setVal(y2val(m->y()));
+}
+
+void QedColorLuminancePicker::setVal(int v)
+{
+ if (val == v)
+ return;
+ val = qMax(0, qMin(v,255));
+ delete pix; pix=0;
+ repaint();
+ Q_EMIT newHsv(hue, sat, val);
+}
+
+//receives from a hue,sat chooser and relays.
+void QedColorLuminancePicker::setCol(int h, int s)
+{
+ setCol(h, s, val);
+ Q_EMIT newHsv(h, s, val);
+}
+
+void QedColorLuminancePicker::paintEvent(QPaintEvent *)
+{
+ int w = width() - 5;
+
+ QRect r(0, foff, w, height() - 2*foff);
+ int wi = r.width() - 2;
+ int hi = r.height() - 2;
+ if (!pix || pix->height() != hi || pix->width() != wi) {
+ delete pix;
+ QImage img(wi, hi, QImage::Format_RGB32);
+ int y;
+ for (y = 0; y < hi; y++) {
+ QColor c;
+ c.setHsv(hue, sat, y2val(y+coff));
+ QRgb r = c.rgb();
+ int x;
+ for (x = 0; x < wi; x++)
+ img.setPixel(x, y, r);
+ }
+ pix = new QPixmap(QPixmap::fromImage(img));
+ }
+ QPainter p(this);
+ p.drawPixmap(1, coff, *pix);
+ const QPalette &g = palette();
+ qDrawShadePanel(&p, r, g, true);
+ p.setPen(g.foreground().color());
+ p.setBrush(g.foreground());
+ QPolygon a;
+ int y = val2y(val);
+ a.setPoints(3, w, y, w+5, y+5, w+5, y-5);
+ p.eraseRect(w, 0, 5, height());
+ p.drawPolygon(a);
+}
+
+void QedColorLuminancePicker::setCol( int h, int s , int v )
+{
+ val = v;
+ hue = h;
+ sat = s;
+ delete pix; pix=0;
+ repaint();
+}
+
+QPoint QedColorPicker::colPt()
+{ return QPoint((360-hue)*(pWidth-1)/360, (255-sat)*(pHeight-1)/255); }
+
+int QedColorPicker::huePt(const QPoint &pt)
+{ return 360 - pt.x()*360/(pWidth-1); }
+
+int QedColorPicker::satPt(const QPoint &pt)
+{ return 255 - pt.y()*255/(pHeight-1) ; }
+
+void QedColorPicker::setCol(const QPoint &pt)
+{ setCol(huePt(pt), satPt(pt)); }
+
+QedColorPicker::QedColorPicker(QWidget* parent)
+ : QFrame(parent)
+{
+ hue = 0; sat = 0;
+ setCol(150, 255);
+
+ QImage img(pWidth, pHeight, QImage::Format_RGB32);
+ int x,y;
+ for (y = 0; y < pHeight; y++)
+ for (x = 0; x < pWidth; x++) {
+ QPoint p(x, y);
+ QColor c;
+ c.setHsv(huePt(p), satPt(p), 200);
+ img.setPixel(x, y, c.rgb());
+ }
+ pix = new QPixmap(QPixmap::fromImage(img));
+ setAttribute(Qt::WA_NoSystemBackground);
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
+}
+
+QedColorPicker::~QedColorPicker()
+{
+ delete pix;
+}
+
+QSize QedColorPicker::sizeHint() const
+{
+ return QSize(pWidth + 2*frameWidth(), pHeight + 2*frameWidth());
+}
+
+void QedColorPicker::setCol(int h, int s)
+{
+ int nhue = qMin(qMax(0,h), 359);
+ int nsat = qMin(qMax(0,s), 255);
+ if (nhue == hue && nsat == sat)
+ return;
+ QRect r(colPt(), QSize(20,20));
+ hue = nhue; sat = nsat;
+ r = r.unite(QRect(colPt(), QSize(20,20)));
+ r.translate(contentsRect().x()-9, contentsRect().y()-9);
+ // update(r);
+ repaint(r);
+}
+
+void QedColorPicker::mouseMoveEvent(QMouseEvent *m)
+{
+ QPoint p = m->pos() - contentsRect().topLeft();
+ setCol(p);
+ Q_EMIT newCol(hue, sat);
+}
+
+void QedColorPicker::mousePressEvent(QMouseEvent *m)
+{
+ QPoint p = m->pos() - contentsRect().topLeft();
+ setCol(p);
+ Q_EMIT newCol(hue, sat);
+}
+
+void QedColorPicker::paintEvent(QPaintEvent *e)
+{
+ QFrame::paintEvent(e);
+ QPainter p(this);
+ QRect r = contentsRect();
+
+ p.drawPixmap(r.topLeft(), *pix);
+ QPoint pt = colPt() + r.topLeft();
+ p.setPen(Qt::black);
+
+ p.fillRect(pt.x()-9, pt.y(), 20, 2, Qt::black);
+ p.fillRect(pt.x(), pt.y()-9, 2, 20, Qt::black);
+}
+
+void QedColorShowLabel::paintEvent(QPaintEvent *e)
+{
+ QFrame::paintEvent(e);
+ QPainter p(this);
+ p.fillRect(contentsRect()&e->rect(), col);
+}
+
+void QedColorShowLabel::mousePressEvent(QMouseEvent *e)
+{
+ mousePressed = true;
+ pressPos = e->pos();
+}
+
+void QedColorShowLabel::mouseMoveEvent(QMouseEvent *e)
+{
+#ifdef QT_NO_DRAGANDDROP
+ Q_UNUSED(e);
+#else
+ if (!mousePressed)
+ return;
+ if ((pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
+ QMimeData *mime = new QMimeData;
+ mime->setColorData(col);
+ QPixmap pix(30, 20);
+ pix.fill(col);
+ QPainter p(&pix);
+ p.drawRect(0, 0, pix.width(), pix.height());
+ p.end();
+ QDrag *drg = new QDrag(this);
+ drg->setMimeData(mime);
+ drg->setPixmap(pix);
+ mousePressed = false;
+ drg->start();
+ }
+#endif
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QedColorShowLabel::dragEnterEvent(QDragEnterEvent *e)
+{
+ if (qvariant_cast<QColor>(e->mimeData()->colorData()).isValid())
+ e->accept();
+ else
+ e->ignore();
+}
+
+void QedColorShowLabel::dragLeaveEvent(QDragLeaveEvent *)
+{
+}
+
+void QedColorShowLabel::dropEvent(QDropEvent *e)
+{
+ QColor color = qvariant_cast<QColor>(e->mimeData()->colorData());
+ if (color.isValid()) {
+ col = color;
+ repaint();
+ Q_EMIT colorDropped(col.rgb());
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+#endif // QT_NO_DRAGANDDROP
+
+void QedColorShowLabel::mouseReleaseEvent( QMouseEvent * )
+{
+ if (!mousePressed)
+ return;
+ mousePressed = false;
+}
+
+QedColLineEdit::QedColLineEdit(QWidget *parent) : QLineEdit(parent)
+{
+ connect(this, SIGNAL(textEdited(const QString&)),
+ this, SLOT(textEdited(const QString&)));
+}
+
+void QedColLineEdit::textEdited(const QString &text)
+{
+ QColor c;
+ c.setNamedColor(text);
+ if (c.isValid()) {
+ setColor(c);
+ Q_EMIT newColor(c);
+ }
+}
+
+void QedColLineEdit::setColor(QColor c)
+{
+ col = c;
+ setText(col.name());
+}
+
+void QedColLineEdit::setCol(int h, int s, int v)
+{
+ col.setHsv(h, s, v);
+ setText(col.name());
+}
diff --git a/src/libpcp_qed/src/qed_colorpicker.h b/src/libpcp_qed/src/qed_colorpicker.h
new file mode 100644
index 0000000..2b804b1
--- /dev/null
+++ b/src/libpcp_qed/src/qed_colorpicker.h
@@ -0,0 +1,170 @@
+/*
+** Copyright (C) 2014 Red Hat.
+** Copyright (C) 1999-2007 Trolltech AS. All rights reserved.
+**
+** This file is derived from part of the QtGui module of the Qt Toolkit.
+**
+** This file may be used under the terms of the GNU General Public
+** License version 2.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of
+** this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+** http://www.trolltech.com/products/qt/opensource.html
+**
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://www.trolltech.com/products/qt/licensing.html or contact the
+** sales department at sales@trolltech.com.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**/
+#ifndef QED_COLORPICKER_H
+#define QED_COLORPICKER_H
+
+#include <QFrame>
+#include <QLabel>
+#include <QSpinBox>
+#include <QLineEdit>
+#include <QValidator>
+#include <QDragEnterEvent>
+#include <QDropEvent>
+#include <QMouseEvent>
+#include <QPaintEvent>
+#include <QDragLeaveEvent>
+
+static inline void rgb2hsv(QRgb rgb, int &h, int &s, int &v)
+{
+ QColor c;
+ c.setRgb(rgb);
+ c.getHsv(&h, &s, &v);
+}
+
+class QedColorPicker : public QFrame
+{
+ Q_OBJECT
+public:
+ QedColorPicker(QWidget* parent);
+ ~QedColorPicker();
+
+public slots:
+ void setCol(int h, int s);
+
+Q_SIGNALS:
+ void newCol(int h, int s);
+
+protected:
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+
+private:
+ int hue;
+ int sat;
+
+ QPoint colPt();
+ int huePt(const QPoint &pt);
+ int satPt(const QPoint &pt);
+ void setCol(const QPoint &pt);
+
+ QPixmap *pix;
+};
+
+class QedColorLuminancePicker : public QWidget
+{
+ Q_OBJECT
+public:
+ QedColorLuminancePicker(QWidget* parent);
+ ~QedColorLuminancePicker();
+
+public slots:
+ void setCol(int h, int s, int v);
+ void setCol(int h, int s);
+
+Q_SIGNALS:
+ void newHsv(int h, int s, int v);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+
+private:
+ enum { foff = 3, coff = 4 }; //frame and contents offset
+ int val;
+ int hue;
+ int sat;
+
+ int y2val(int y);
+ int val2y(int val);
+ void setVal(int v);
+
+ QPixmap *pix;
+};
+
+class QedColSpinBox : public QSpinBox
+{
+public:
+ QedColSpinBox(QWidget *parent)
+ : QSpinBox(parent) { setRange(0, 255); }
+ void setValue(int i) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ QSpinBox::setValue(i);
+ blockSignals(block);
+ }
+};
+
+class QedColLineEdit : public QLineEdit
+{
+ Q_OBJECT
+
+public:
+ QedColLineEdit(QWidget *parent);
+
+public slots:
+ void setColor(QColor c);
+ void setCol(int h, int s, int v);
+ void textEdited(const QString &text);
+
+Q_SIGNALS:
+ void newColor(QColor c);
+
+private:
+ QColor col;
+};
+
+class QedColorShowLabel : public QFrame
+{
+ Q_OBJECT
+
+public:
+ QedColorShowLabel(QWidget *parent) : QFrame(parent) {
+ setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ setAcceptDrops(true);
+ mousePressed = false;
+ }
+ void setColor(QColor c) { col = c; update(); }
+
+Q_SIGNALS:
+ void colorDropped(QRgb);
+
+protected:
+ void paintEvent(QPaintEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *e);
+ void dragLeaveEvent(QDragLeaveEvent *e);
+ void dropEvent(QDropEvent *e);
+#endif
+
+private:
+ QColor col;
+ bool mousePressed;
+ QPoint pressPos;
+};
+
+#endif /* QED_COLORPICKER_H */
diff --git a/src/libpcp_qed/src/qed_console.cpp b/src/libpcp_qed/src/qed_console.cpp
new file mode 100644
index 0000000..30492aa
--- /dev/null
+++ b/src/libpcp_qed/src/qed_console.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2006, Ken McDonell. All Rights Reserved.
+ * Copyright (c) 2007, 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 <stdarg.h>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+#include "qed_console.h"
+
+QedConsole *console;
+
+QedConsole::QedConsole(struct timeval origin) : QDialog()
+{
+ my.level = 0;
+ if (pmDebug & DBG_TRACE_APPL0) {
+ my.level |= QedApp::DebugApp; // general and UI tracing
+ my.level |= QedApp::DebugUi;
+ }
+ if (pmDebug & DBG_TRACE_APPL1)
+ my.level |= QedApp::DebugProtocol; // trace time protocol
+ if (pmDebug & DBG_TRACE_APPL2) {
+ my.level |= QedApp::DebugView; // config files, for QA
+ my.level |= QedApp::DebugTimeless;
+ }
+ setupUi(this);
+
+ my.origin = QedApp::timevalToSeconds(origin);
+ post("Console available");
+}
+
+void QedConsole::post(const char *fmt, ...)
+{
+ static char buffer[4096];
+ struct timeval now;
+ va_list ap;
+ int offset = 0;
+
+ if (!(my.level & QedApp::DebugApp))
+ return;
+
+ if (!(my.level & QedApp::DebugTimeless)) {
+ gettimeofday(&now, NULL);
+ sprintf(buffer, "%6.2f: ", QedApp::timevalToSeconds(now) - my.origin);
+ offset = 8;
+ }
+
+ va_start(ap, fmt);
+ vsnprintf(buffer+offset, sizeof(buffer)-offset, fmt, ap);
+ va_end(ap);
+
+ fputs(buffer, stderr);
+ fputc('\n', stderr);
+ text->append(QString(buffer));
+}
+
+bool QedConsole::logLevel(int level)
+{
+ if (!(my.level & level))
+ return false;
+ return true;
+}
+
+void QedConsole::post(int level, const char *fmt, ...)
+{
+ static char buffer[4096];
+ struct timeval now;
+ va_list ap;
+ int offset = 0;
+
+ if (!(my.level & level) && !(level & QedApp::DebugForce))
+ return;
+
+ if (!(my.level & QedApp::DebugTimeless)) {
+ gettimeofday(&now, NULL);
+ sprintf(buffer, "%6.2f: ", QedApp::timevalToSeconds(now) - my.origin);
+ offset = 8;
+ }
+
+ va_start(ap, fmt);
+ vsnprintf(buffer+offset, sizeof(buffer)-offset, fmt, ap);
+ va_end(ap);
+
+ fputs(buffer, stderr);
+ fputc('\n', stderr);
+ text->append(QString(buffer));
+}
diff --git a/src/libpcp_qed/src/qed_console.h b/src/libpcp_qed/src/qed_console.h
new file mode 100644
index 0000000..f1425e5
--- /dev/null
+++ b/src/libpcp_qed/src/qed_console.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2006, Ken McDonell. All Rights Reserved.
+ * Copyright (c) 2006-2007, 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 QED_CONSOLE_H
+#define QED_CONSOLE_H
+
+#include "ui_qed_console.h"
+#include "qed_app.h"
+
+class QedConsole : public QDialog, public Ui::QedConsole
+{
+ Q_OBJECT
+
+public:
+ QedConsole(struct timeval);
+ void post(const char *p, ...);
+ void post(int level, const char *p, ...);
+ bool logLevel(int level = QedApp::DebugApp);
+
+private:
+ struct {
+ int level;
+ double origin;
+ } my;
+};
+
+extern QedConsole *console;
+
+#endif // QED_CONSOLE_H
diff --git a/src/libpcp_qed/src/qed_console.ui b/src/libpcp_qed/src/qed_console.ui
new file mode 100644
index 0000000..b6d571f
--- /dev/null
+++ b/src/libpcp_qed/src/qed_console.ui
@@ -0,0 +1,132 @@
+<ui version="4.0" >
+ <class>QedConsole</class>
+ <widget class="QDialog" name="QedConsole" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>493</width>
+ <height>326</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>PCP GUI Console</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QTextEdit" name="text" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="autoFormatting" >
+ <set>QTextEdit::AutoNone</set>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonHide" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>85</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>85</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>&amp;Hide</string>
+ </property>
+ <property name="shortcut" >
+ <string>Alt+H</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <connections>
+ <connection>
+ <sender>buttonHide</sender>
+ <signal>clicked()</signal>
+ <receiver>QedConsole</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/libpcp_qed/src/qed_fileiconprovider.cpp b/src/libpcp_qed/src/qed_fileiconprovider.cpp
new file mode 100644
index 0000000..7c3d939
--- /dev/null
+++ b/src/libpcp_qed/src/qed_fileiconprovider.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2007, 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 "qed_fileiconprovider.h"
+#include "qed_console.h"
+
+#define DESPERATE 0
+
+QedFileIconProvider *fileIconProvider;
+
+QedFileIconProvider::QedFileIconProvider() : QFileIconProvider()
+{
+ // generic Qt QFileIconProvider types
+ my.file = QIcon(":/images/filegeneric.png");
+ my.folder = QIcon(":/images/filefolder.png");
+ my.computer = QIcon(":/images/computer.png");
+
+ // PCP GUI specific images
+ my.fileView = QIcon(":/images/fileview.png");
+ my.fileFolio = QIcon(":/images/filefolio.png");
+ my.fileArchive = QIcon(":/images/filearchive.png");
+
+ // images for several other common file types
+ my.fileHtml = QIcon(":/images/filehtml.png");
+ my.fileImage = QIcon(":/images/fileimage.png");
+ my.filePackage = QIcon(":/images/filepackage.png");
+ my.fileSpreadSheet = QIcon(":/images/filespreadsheet.png");
+ my.fileWordProcessor = QIcon(":/images/filewordprocessor.png");
+}
+
+QIcon QedFileIconProvider::icon(FileIconType type) const
+{
+ console->post("QedFileIconProvider::icon extended types");
+ switch (type) {
+ case View:
+ return my.fileView;
+ case Folio:
+ return my.fileFolio;
+ case Archive:
+ return my.fileArchive;
+ case Html:
+ return my.fileHtml;
+ case Image:
+ return my.fileImage;
+ case Package:
+ return my.filePackage;
+ case SpreadSheet:
+ return my.fileSpreadSheet;
+ case WordProcessor:
+ return my.fileWordProcessor;
+ default:
+ break;
+ }
+ return my.file;
+}
+
+QIcon QedFileIconProvider::icon(IconType type) const
+{
+ console->post("QedFileIconProvider::icon type");
+ switch (type) {
+ case File:
+ return my.file;
+ case Folder:
+ return my.folder;
+ case Computer:
+ return my.computer;
+ default:
+ break;
+ }
+ return QFileIconProvider::icon(type);
+}
+
+QString QedFileIconProvider::type(const QFileInfo &fi) const
+{
+ console->post("QedFileIconProvider::type string");
+ return QFileIconProvider::type(fi);
+}
+
+QIcon QedFileIconProvider::icon(const QFileInfo &fi) const
+{
+#if DESPERATE
+ console->post("QedFileIconProvider::icon - %s",
+ (const char *)fi.filePath().toAscii());
+#endif
+
+ if (fi.isFile()) {
+ QFile file(fi.filePath());
+ file.open(QIODevice::ReadOnly);
+ char block[9];
+ int count = file.read(block, sizeof(block)-1);
+ if (count == sizeof(block)-1) {
+ static const char *viewmagic[] = { "#kmchart", "#pmchart" };
+ static char foliomagic[] = "PCPFolio";
+ static char archmagic[] = "\0\0\0\204\120\5\46\2"; //PM_LOG_MAGIC|V2
+
+ if (memcmp(viewmagic[0], block, sizeof(block)-1) == 0)
+ return my.fileView;
+ if (memcmp(viewmagic[1], block, sizeof(block)-1) == 0)
+ return my.fileView;
+ if (memcmp(foliomagic, block, sizeof(block)-1) == 0)
+ return my.fileFolio;
+ if (memcmp(archmagic, block, sizeof(block)-1) == 0)
+ return my.fileArchive;
+ }
+#if DESPERATE
+ console->post(" Got %d bytes from %s: \"%c%c%c%c%c%c%c%c\"", count,
+ (const char *) fi.filePath().toAscii(), block[0], block[1],
+ block[2], block[3], block[4], block[5], block[6], block[7]);
+#endif
+ QString ext = fi.suffix();
+ if (ext == "htm" || ext == "html")
+ return my.fileHtml;
+ if (ext == "svg" || ext == "gif" || ext == "jpg" || ext == "jpeg" ||
+ ext == "png" || ext == "xpm" || ext == "odg" /* ... */ )
+ return my.fileImage;
+ if (ext == "tar" || ext == "tgz" || ext == "deb" || ext == "rpm" ||
+ ext == "zip" || ext == "bz2" || ext == "gz" || ext == "xz")
+ return my.filePackage;
+ if (ext == "ods" || ext == "xls")
+ return my.fileSpreadSheet;
+ if (ext == "odp" || ext == "doc")
+ return my.fileWordProcessor;
+ return my.file; // catch-all for every other regular file
+ }
+ else if (fi.isDir()) {
+ return my.folder;
+ }
+ return QFileIconProvider::icon(fi);
+}
diff --git a/src/libpcp_qed/src/qed_fileiconprovider.h b/src/libpcp_qed/src/qed_fileiconprovider.h
new file mode 100644
index 0000000..1fc7e41
--- /dev/null
+++ b/src/libpcp_qed/src/qed_fileiconprovider.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2007, 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 QED_FILEICONPROVIDER_H
+#define QED_FILEICONPROVIDER_H
+
+#include <QtGui/QApplication>
+#include <QtGui/QFileIconProvider>
+
+class QedFileIconProvider : public QFileIconProvider
+{
+public:
+ QedFileIconProvider();
+
+ typedef enum { View, Folio, Archive, Html, Image, // IconType++
+ Package, SpreadSheet, WordProcessor } FileIconType;
+ QIcon icon(FileIconType type) const;
+
+ QIcon icon(IconType type) const;
+ QIcon icon(const QFileInfo &info) const;
+ QString type(const QFileInfo &info) const;
+
+private:
+ struct {
+ QIcon file;
+ QIcon folder;
+ QIcon computer;
+
+ QIcon fileView; // pmchart view
+ QIcon fileFolio; // PCP folio
+ QIcon fileArchive; // PCP archive
+ QIcon fileHtml;
+ QIcon fileImage;
+ QIcon filePackage;
+ QIcon fileSpreadSheet;
+ QIcon fileWordProcessor;
+ } my;
+};
+
+extern QedFileIconProvider *fileIconProvider;
+
+#endif // QED_FILEICONPROVIDER_H
diff --git a/src/libpcp_qed/src/qed_gadget.cpp b/src/libpcp_qed/src/qed_gadget.cpp
new file mode 100644
index 0000000..beee4b9
--- /dev/null
+++ b/src/libpcp_qed/src/qed_gadget.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 "qed_gadget.h"
+
+QedGadget::QedGadget(QWidget *parent) : QWidget(parent)
+{
+ my.depth = -1;
+}
+
+void
+QedGadget::dump(FILE *f)
+{
+ fprintf(f, " depth=%d\n", my.depth);
+}
diff --git a/src/libpcp_qed/src/qed_gadget.h b/src/libpcp_qed/src/qed_gadget.h
new file mode 100644
index 0000000..4b3e66b
--- /dev/null
+++ b/src/libpcp_qed/src/qed_gadget.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_GADGET_H
+#define QED_GADGET_H
+
+#include <QtGui>
+
+class QedGadget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QedGadget(QWidget *parent);
+ void dump(FILE *f);
+
+private:
+ struct {
+ int depth; // z-axis setting for rendering
+ } my;
+};
+
+#endif // QED_GADGET_H
diff --git a/src/libpcp_qed/src/qed_groupcontrol.cpp b/src/libpcp_qed/src/qed_groupcontrol.cpp
new file mode 100644
index 0000000..c42e83c
--- /dev/null
+++ b/src/libpcp_qed/src/qed_groupcontrol.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * 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 "qed_groupcontrol.h"
+#include "qed_console.h"
+#include "qed_app.h"
+
+QedGroupControl::QedGroupControl()
+{
+ my.realDelta = 0;
+ my.realPosition = 0;
+ my.timeState = StartState;
+ my.buttonState = QedTimeButton::Timeless;
+ my.pmtimeState = QmcTime::StoppedState;
+ memset(&my.delta, 0, sizeof(struct timeval));
+ memset(&my.position, 0, sizeof(struct timeval));
+}
+
+void QedGroupControl::init(struct timeval *interval, struct timeval *position)
+{
+ if (isArchiveSource()) {
+ my.pmtimeState = QmcTime::StoppedState;
+ my.buttonState = QedTimeButton::StoppedArchive;
+ }
+ else {
+ my.pmtimeState = QmcTime::ForwardState;
+ my.buttonState = QedTimeButton::ForwardLive;
+ }
+ my.delta = *interval;
+ my.position = *position;
+ my.realDelta = QedApp::timevalToSeconds(*interval);
+ my.realPosition = QedApp::timevalToSeconds(*position);
+}
+
+QmcTime::State QedGroupControl::pmtimeState(void)
+{
+ return my.pmtimeState;
+}
+
+char *QedGroupControl::timeState()
+{
+ static char buf[16];
+
+ switch (my.timeState) {
+ case StartState: strcpy(buf, "Start"); break;
+ case ForwardState: strcpy(buf, "Forward"); break;
+ case BackwardState: strcpy(buf, "Backward"); break;
+ case EndLogState: strcpy(buf, "EndLog"); break;
+ case StandbyState: strcpy(buf, "Standby"); break;
+ default: strcpy(buf, "Dodgey"); break;
+ }
+ return buf;
+}
+
+//
+// Setup the initial data needed after opening a view.
+// All of the work is in archive mode; in live mode we have
+// not yet got any historical data that we can display...
+//
+void QedGroupControl::setupWorldView(struct timeval *interval,
+ struct timeval *position, struct timeval *start, struct timeval *end)
+{
+ if (isArchiveSource() == false)
+ return;
+
+ QmcTime::Packet packet;
+ packet.source = QmcTime::ArchiveSource;
+ packet.state = QmcTime::ForwardState;
+ packet.mode = QmcTime::NormalMode;
+ memcpy(&packet.delta, interval, sizeof(packet.delta));
+ memcpy(&packet.position, position, sizeof(packet.position));
+ memcpy(&packet.start, start, sizeof(packet.start));
+ memcpy(&packet.end, end, sizeof(packet.end));
+ adjustWorldView(&packet, true);
+}
+
+//
+// Received a Set or a VCRMode requiring us to adjust our state
+// and possibly rethink everything. This can result from a time
+// control position change, delta change, direction change, etc.
+//
+void QedGroupControl::adjustWorldView(QmcTime::Packet *packet, bool vcrMode)
+{
+ my.delta = packet->delta;
+ my.position = packet->position;
+ my.realDelta = QedApp::timevalToSeconds(packet->delta);
+ my.realPosition = QedApp::timevalToSeconds(packet->position);
+
+ console->post("QedGroupControl::adjustWorldView: "
+ "delta=%.2f position=%.2f (%s) state=%s",
+ my.realDelta, my.realPosition,
+ QedApp::timeString(my.realPosition), timeState());
+
+ QmcTime::State state = packet->state;
+ if (isArchiveSource()) {
+ if (packet->state == QmcTime::ForwardState)
+ adjustArchiveWorldViewForward(packet, vcrMode);
+ else if (packet->state == QmcTime::BackwardState)
+ adjustArchiveWorldViewBackward(packet, vcrMode);
+ else
+ adjustArchiveWorldViewStopped(packet, vcrMode);
+ }
+ else if (state != QmcTime::StoppedState)
+ adjustLiveWorldViewForward(packet);
+ else
+ adjustLiveWorldViewStopped(packet);
+}
+
+void QedGroupControl::adjustLiveWorldViewStopped(QmcTime::Packet *packet)
+{
+ if (isActive(packet)) {
+ newButtonState(packet->state, packet->mode, isRecording(packet));
+ updateTimeButton();
+ }
+}
+
+void QedGroupControl::adjustLiveWorldViewForward(QmcTime::Packet *packet)
+{
+ console->post("QedGroupControl::adjustLiveWorldViewForward");
+
+ if (isActive(packet))
+ newButtonState(packet->state, packet->mode, isRecording(packet));
+}
+
+void QedGroupControl::adjustArchiveWorldViewForward(QmcTime::Packet *packet, bool setup)
+{
+ console->post("QedGroupControl::adjustArchiveWorldViewForward");
+
+ if (setup)
+ packet->state = QmcTime::StoppedState;
+ if (isActive(packet))
+ newButtonState(packet->state, packet->mode, isRecording(packet));
+}
+
+void QedGroupControl::adjustArchiveWorldViewBackward(QmcTime::Packet *packet, bool setup)
+{
+ console->post("QedGroupControl::adjustArchiveWorldViewBackward");
+
+ if (setup)
+ packet->state = QmcTime::StoppedState;
+ if (isActive(packet))
+ newButtonState(packet->state, packet->mode, isRecording(packet));
+}
+
+void QedGroupControl::adjustArchiveWorldViewStopped(QmcTime::Packet *packet, bool needFetch)
+{
+ if (needFetch) { // stopped, but VCR reposition event occurred
+ adjustArchiveWorldViewForward(packet, needFetch);
+ return;
+ }
+ my.timeState = StandbyState;
+ packet->state = QmcTime::StoppedState;
+ newButtonState(packet->state, packet->mode, isRecording(packet));
+ updateTimeButton();
+}
+
+bool QedGroupControl::fuzzyTimeMatch(double a, double b, double tolerance)
+{
+ // a matches b if the difference is within 1% of the delta (tolerance)
+ return (a == b ||
+ (b > a && a + tolerance > b) ||
+ (b < a && a - tolerance < b));
+}
+
+//
+// Catch the situation where we get a larger than expected increase
+// in position. This happens when we restart after a stop in live
+// mode (both with and without a change in the delta).
+//
+static bool sideStep(double n, double o, double interval)
+{
+ // tolerance set to 5% of the sample interval:
+ return QedGroupControl::fuzzyTimeMatch(o + interval, n, interval/20.0) == false;
+}
+
+void QedGroupControl::step(QmcTime::Packet *packet)
+{
+ double stepPosition = QedApp::timevalToSeconds(packet->position);
+
+ console->post(QedApp::DebugProtocol,
+ "GroupControl::step: stepping to time %.2f, delta=%.2f, state=%s",
+ stepPosition, my.realDelta, timeState());
+
+ if ((packet->source == QmcTime::ArchiveSource &&
+ ((packet->state == QmcTime::ForwardState &&
+ my.timeState != ForwardState) ||
+ (packet->state == QmcTime::BackwardState &&
+ my.timeState != BackwardState))) ||
+ sideStep(stepPosition, my.realPosition, my.realDelta))
+ return adjustWorldView(packet, false);
+
+ my.pmtimeState = packet->state;
+ my.position = packet->position;
+ my.realPosition = stepPosition;
+
+ adjustStep(packet);
+ fetch();
+
+ if (isActive(packet))
+ newButtonState(packet->state, packet->mode, isRecording(packet));
+}
+
+void QedGroupControl::VCRMode(QmcTime::Packet *packet, bool dragMode)
+{
+ if (!dragMode)
+ adjustWorldView(packet, true);
+}
+
+void QedGroupControl::setTimezone(QmcTime::Packet *packet, char *tz)
+{
+ console->post(QedApp::DebugProtocol, "GroupControl::setTimezone %s", tz);
+ useTZ(QString(tz));
+ (void)packet;
+}
+
+void QedGroupControl::newButtonState(QmcTime::State s, QmcTime::Mode m, bool record)
+{
+ if (isArchiveSource() == false) {
+ if (s == QmcTime::StoppedState)
+ my.buttonState = record ?
+ QedTimeButton::StoppedRecord : QedTimeButton::StoppedLive;
+ else
+ my.buttonState = record ?
+ QedTimeButton::ForwardRecord : QedTimeButton::ForwardLive;
+ }
+ else if (m == QmcTime::StepMode) {
+ if (s == QmcTime::ForwardState)
+ my.buttonState = QedTimeButton::StepForwardArchive;
+ else if (s == QmcTime::BackwardState)
+ my.buttonState = QedTimeButton::StepBackwardArchive;
+ else
+ my.buttonState = QedTimeButton::StoppedArchive;
+ }
+ else if (m == QmcTime::FastMode) {
+ if (s == QmcTime::ForwardState)
+ my.buttonState = QedTimeButton::FastForwardArchive;
+ else if (s == QmcTime::BackwardState)
+ my.buttonState = QedTimeButton::FastBackwardArchive;
+ else
+ my.buttonState = QedTimeButton::StoppedArchive;
+ }
+ else if (s == QmcTime::ForwardState)
+ my.buttonState = QedTimeButton::ForwardArchive;
+ else if (s == QmcTime::BackwardState)
+ my.buttonState = QedTimeButton::BackwardArchive;
+ else
+ my.buttonState = QedTimeButton::StoppedArchive;
+}
diff --git a/src/libpcp_qed/src/qed_groupcontrol.h b/src/libpcp_qed/src/qed_groupcontrol.h
new file mode 100644
index 0000000..c9825bf
--- /dev/null
+++ b/src/libpcp_qed/src/qed_groupcontrol.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2006-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.
+ */
+#ifndef QED_GROUPCONTROL_H
+#define QED_GROUPCONTROL_H
+
+#include <QtCore/QList>
+#include <qmc_group.h>
+#include <qmc_time.h>
+#include "qed_timebutton.h"
+
+class QedGroupControl : public QObject, public QmcGroup
+{
+ Q_OBJECT
+
+public:
+ QedGroupControl();
+ void init(struct timeval *, struct timeval *);
+
+ virtual bool isArchiveSource() = 0;
+
+ double timeInterval() const { return my.realDelta; }
+ double timePosition() const { return my.realPosition; }
+
+ virtual void step(QmcTime::Packet *);
+ virtual void VCRMode(QmcTime::Packet *, bool);
+ virtual void setTimezone(QmcTime::Packet *, char *);
+
+ virtual void adjustStep(QmcTime::Packet *) = 0;
+ virtual void updateTimeButton() = 0;
+ virtual void updateTimeAxis(void) = 0;
+
+ virtual void setupWorldView(struct timeval *, struct timeval *,
+ struct timeval *, struct timeval *);
+ static bool fuzzyTimeMatch(double, double, double);
+
+ QedTimeButton::State buttonState() { return my.buttonState; }
+ QmcTime::State pmtimeState();
+ void newButtonState(QmcTime::State, QmcTime::Mode, bool);
+ bool isStateBackward() { return my.timeState == BackwardState; }
+
+protected:
+ typedef enum {
+ StartState,
+ ForwardState,
+ BackwardState,
+ EndLogState,
+ StandbyState,
+ } QedTimeState;
+
+ char *timeState();
+ void setTimeState(QedTimeState state) { my.timeState = state; }
+ virtual void setButtonState(QedTimeButton::State) = 0;
+
+ virtual bool isActive(QmcTime::Packet *) = 0;
+ virtual bool isRecording(QmcTime::Packet *) = 0;
+ virtual void adjustWorldView(QmcTime::Packet *, bool);
+ virtual void adjustLiveWorldViewForward(QmcTime::Packet *);
+ virtual void adjustLiveWorldViewStopped(QmcTime::Packet *);
+ virtual void adjustArchiveWorldViewForward(QmcTime::Packet *, bool);
+ virtual void adjustArchiveWorldViewStopped(QmcTime::Packet *, bool);
+ virtual void adjustArchiveWorldViewBackward(QmcTime::Packet *, bool);
+
+ struct {
+ double realDelta; // current update interval
+ double realPosition; // current time position
+ struct timeval delta;
+ struct timeval position;
+
+ QedTimeButton::State buttonState;
+ QmcTime::Source pmtimeSource; // reliable archive/host test
+ QmcTime::State pmtimeState;
+ QedTimeState timeState;
+ } my;
+};
+
+#endif // QED_GROUPCONTROL_H
diff --git a/src/libpcp_qed/src/qed_label.cpp b/src/libpcp_qed/src/qed_label.cpp
new file mode 100644
index 0000000..874b607
--- /dev/null
+++ b/src/libpcp_qed/src/qed_label.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 "qed_label.h"
+
+QedLabel::QedLabel(QWidget *parent) : QedGadget(parent)
+{
+}
+
+QedLabel::QedLabel(QWidget *parent, int x, int y, const char *t, const char *font) : QedGadget(parent)
+{
+ (void)x;
+ (void)y;
+ (void)t;
+ (void)font;
+}
+
diff --git a/src/libpcp_qed/src/qed_label.h b/src/libpcp_qed/src/qed_label.h
new file mode 100644
index 0000000..b26b5aa
--- /dev/null
+++ b/src/libpcp_qed/src/qed_label.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_LABEL_H
+#define QED_LABEL_H
+
+#include <QtGui>
+#include "qed_gadget.h"
+
+class QedLabel : public QedGadget
+{
+ Q_OBJECT
+
+public:
+ QedLabel(QWidget *parent);
+ QedLabel(QWidget *parent, int x, int y, const char *t, const char *font);
+
+ void setOrientation(Qt::Orientation o) { my.oriented = o; }
+
+private:
+ struct {
+ QString text;
+ QString font;
+ Qt::Orientation oriented;
+ } my;
+};
+
+#endif // QED_LABEL_H
diff --git a/src/libpcp_qed/src/qed_led.cpp b/src/libpcp_qed/src/qed_led.cpp
new file mode 100644
index 0000000..9beb47a
--- /dev/null
+++ b/src/libpcp_qed/src/qed_led.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 <QWidget>
+#include "qed_led.h"
+
+QedLED::QedLED(QWidget *parent, QColor color) : QedGadget(parent)
+{
+ const qreal baseBound = 32.0;
+ const int iBaseBound = (int)(baseBound+0.5);
+
+ my.color = color;
+ my.bound = baseBound;
+ setMinimumSize(iBaseBound, iBaseBound);
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+}
+
+QedLED::QedLED(QWidget *parent, int x, int y, int w, int h, QedLegend *color) : QedGadget(parent)
+{
+ // TODO
+ (void)x;
+ (void)y;
+ (void)w;
+ (void)h;
+ (void)color;
+}
+
+void QedLED::resizeEvent(QResizeEvent *event)
+{
+ QSize size = event->size();
+ my.bound = qMin(size.height(), size.width());
+}
+
+void QedRoundLED::paintEvent(QPaintEvent *event)
+{
+ qreal lowerInset, upperInset;
+ (void)event;
+
+ QPainterPath baseCirclePath;
+ QRectF baseBox(0.0, 0.0, my.bound, my.bound);
+ baseCirclePath.arcTo(baseBox, 0.0, 360.0);
+ baseCirclePath.closeSubpath();
+ QLinearGradient baseGradient(0, 0, 0, 1.33846 * my.bound);
+ baseGradient.setColorAt(0.0, Qt::lightGray);
+ baseGradient.setColorAt(1.0, Qt::white);
+
+ QPainterPath seatCirclePath;
+ lowerInset = 0.06666 * my.bound;
+ upperInset = my.bound - (lowerInset * 2.0);
+ QRectF seatBox(lowerInset, lowerInset, upperInset, upperInset);
+ seatCirclePath.arcTo(seatBox, 0.0, 360.0);
+ seatCirclePath.closeSubpath();
+ QLinearGradient seatGradient(0, 0, 0, 0.7692 * my.bound);
+ seatGradient.setColorAt(0.0, Qt::lightGray);
+ seatGradient.setColorAt(1.0, Qt::darkGray);
+
+ QPainterPath mainCirclePath;
+ lowerInset = 0.1 * my.bound;
+ upperInset = my.bound - (lowerInset * 2.0);
+ QRectF mainBox(lowerInset, lowerInset, upperInset, upperInset);
+ mainCirclePath.arcTo(mainBox, 0.0, 360.0);
+ mainCirclePath.closeSubpath();
+ QLinearGradient mainGradient(0, 0, 0, 1.23076 * my.bound);
+ mainGradient.setColorAt(0.0, my.color);
+ mainGradient.setColorAt(1.0, Qt::white);
+
+ QPainterPath reflectCirclePath;
+ QRectF reflectBox(0.18538 * my.bound, 0.12969 * my.bound,
+ 0.61384 * my.bound, 0.48615 * my.bound);
+ reflectCirclePath.arcTo(reflectBox, 0.0, 360.0);
+ reflectCirclePath.closeSubpath();
+ QLinearGradient reflectGradient(0, 0, 0, 1.22953 * my.bound);
+ reflectGradient.setColorAt(0.0, Qt::white);
+ reflectGradient.setColorAt(1.0, my.color);
+
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setPen(Qt::NoPen);
+
+ painter.setBrush(baseGradient);
+ painter.drawPath(baseCirclePath);
+ painter.setBrush(seatGradient);
+ painter.drawPath(seatCirclePath);
+ painter.setBrush(mainGradient);
+ painter.drawPath(mainCirclePath);
+ painter.setBrush(reflectGradient);
+ painter.drawPath(reflectCirclePath);
+}
+
+void QedSquareLED::paintEvent(QPaintEvent *event)
+{
+ qreal lowerInset, upperInset, radius = my.bound / 16.0;
+ (void)event;
+
+ QPainterPath baseSquarePath;
+ QRectF baseBox(0.0, 0.0, my.bound, my.bound);
+ baseSquarePath.addRoundedRect(baseBox, radius, radius);
+ baseSquarePath.closeSubpath();
+ QLinearGradient baseGradient(0, 0, 0, 1.33846 * my.bound);
+ baseGradient.setColorAt(0.0, Qt::lightGray);
+ baseGradient.setColorAt(1.0, Qt::white);
+
+ QPainterPath seatSquarePath;
+ lowerInset = 0.06666 * my.bound;
+ upperInset = my.bound - (lowerInset * 2.0);
+ QRectF seatBox(lowerInset, lowerInset, upperInset, upperInset);
+ seatSquarePath.addRoundedRect(seatBox, radius, radius);
+ seatSquarePath.closeSubpath();
+ QLinearGradient seatGradient(0, 0, 0, 0.7692 * my.bound);
+ seatGradient.setColorAt(0.0, Qt::lightGray);
+ seatGradient.setColorAt(1.0, Qt::darkGray);
+
+ QPainterPath mainSquarePath;
+ lowerInset = 0.1 * my.bound;
+ upperInset = my.bound - (lowerInset * 2.0);
+ QRectF mainBox(lowerInset, lowerInset, upperInset, upperInset);
+ mainSquarePath.addRoundedRect(mainBox, radius, radius);
+ mainSquarePath.closeSubpath();
+ QLinearGradient mainGradient(0, 0, 0, 1.23076 * my.bound);
+ mainGradient.setColorAt(0.0, my.color);
+ mainGradient.setColorAt(1.0, Qt::white);
+
+ QPainterPath reflectSquarePath;
+ QRectF reflectBox(0.13538 * my.bound, 0.12969 * my.bound,
+ 0.73084 * my.bound, 0.48615 * my.bound);
+ reflectSquarePath.addRoundedRect(reflectBox, radius, radius);
+ reflectSquarePath.closeSubpath();
+ QLinearGradient reflectGradient(0, 0, 0, 1.22953 * my.bound);
+ reflectGradient.setColorAt(0.0, Qt::white);
+ reflectGradient.setColorAt(1.0, my.color);
+
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setPen(Qt::NoPen);
+
+ painter.setBrush(baseGradient);
+ painter.drawPath(baseSquarePath);
+ painter.setBrush(seatGradient);
+ painter.drawPath(seatSquarePath);
+ painter.setBrush(mainGradient);
+ painter.drawPath(mainSquarePath);
+ painter.setBrush(reflectGradient);
+ painter.drawPath(reflectSquarePath);
+}
diff --git a/src/libpcp_qed/src/qed_led.h b/src/libpcp_qed/src/qed_led.h
new file mode 100644
index 0000000..067f92b
--- /dev/null
+++ b/src/libpcp_qed/src/qed_led.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_LED_H
+#define QED_LED_H
+
+#include <QtGui>
+#include "qed_gadget.h"
+#include "qed_legend.h"
+
+class QedLED : public QedGadget
+{
+ Q_OBJECT
+
+public:
+ QedLED(QWidget *parent, QColor color);
+ QedLED(QWidget *parent, int x, int y, int w, int h, QedLegend *color);
+
+protected:
+ virtual void paintEvent(QPaintEvent *) = 0;
+ virtual void resizeEvent(QResizeEvent *);
+
+ struct {
+ QColor color;
+ qreal bound;
+ } my;
+};
+
+class QedRoundLED : public QedLED
+{
+ Q_OBJECT
+
+public:
+ QedRoundLED(QWidget *parent, QColor color) : QedLED(parent, color) { }
+ QedRoundLED(QWidget *parent, int x, int y, int w, int h, QedLegend *l)
+ : QedLED(parent, x, y, w, h, l) { }
+
+private:
+ void paintEvent(QPaintEvent *);
+};
+
+class QedSquareLED : public QedLED
+{
+ Q_OBJECT
+
+public:
+ QedSquareLED(QWidget *parent, QColor color) : QedLED(parent, color) { }
+ QedSquareLED(QWidget *parent, int x, int y, int w, int h, QedLegend *l)
+ : QedLED(parent, x, y, w, h, l) { }
+
+private:
+ void paintEvent(QPaintEvent *);
+};
+
+#endif // QED_LED_H
diff --git a/src/libpcp_qed/src/qed_legend.cpp b/src/libpcp_qed/src/qed_legend.cpp
new file mode 100644
index 0000000..a885b73
--- /dev/null
+++ b/src/libpcp_qed/src/qed_legend.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 "qed_legend.h"
+
+QedLegend::QedLegend()
+{
+ // default is white when no _default appears in the legend ...
+ my.defaultColor = Qt::white;
+}
+
+QedLegend::QedLegend(const char *name) : QString(name)
+{
+ QedLegend();
+}
+
+const char *
+QedLegend::identity(void) const
+{
+ return this->toAscii();
+}
+
+void
+QedLegend::setDefaultColor(const char *color)
+{
+ my.defaultColor = QColor(color);
+}
+
+void
+QedLegend::setThresholds(QStringList &tl)
+{
+ // TODO: iterate over tl and build my.thresholds
+ (void)tl;
+}
+
+void
+QedLegend::addThreshold(double value, const char *color)
+{
+ // TODO: append to my.thresholds
+ (void)value;
+ (void)color;
+}
diff --git a/src/libpcp_qed/src/qed_legend.h b/src/libpcp_qed/src/qed_legend.h
new file mode 100644
index 0000000..c70e872
--- /dev/null
+++ b/src/libpcp_qed/src/qed_legend.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_LEGEND_H
+#define QED_LEGEND_H
+
+#include <QtGui>
+
+class QedThreshold
+{
+public:
+ QedThreshold(double value, const QColor &color)
+ { my.value = value; my.color = color; }
+
+ double value() const { return my.value; }
+ QColor color() const { return my.color; }
+
+private:
+ struct {
+ double value; // maximum value for range
+ QColor color;
+ } my;
+};
+
+// Simple legend - a named list of value ranges,
+// with colors associated with each value range.
+//
+class QedLegend : public QString
+{
+public:
+ QedLegend();
+ QedLegend(const char *legend);
+ const char *identity() const;
+ void setDefaultColor(const char *color);
+ void addThreshold(double value, const char *color);
+ void setThresholds(QStringList &tl);
+
+private:
+ struct {
+ QColor defaultColor;
+ QList<QedThreshold> thresholds;
+ } my;
+};
+
+#endif // QED_LEGEND_H
diff --git a/src/libpcp_qed/src/qed_line.cpp b/src/libpcp_qed/src/qed_line.cpp
new file mode 100644
index 0000000..51e8573
--- /dev/null
+++ b/src/libpcp_qed/src/qed_line.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 <QWidget>
+#include "qed_line.h"
+
+QedLine::QedLine(QWidget *parent, qreal length) : QedGadget(parent)
+{
+ setup();
+ my.box = QRect(0, 0, length, 1);
+ my.length = length * 1.0;
+}
+
+QedLine::QedLine(QWidget *parent, int x, int y, int w, int h) : QedGadget(parent)
+{
+ setup();
+ my.box = QRect(x, y, w, h);
+ my.length = QLineF(QLine(x, y, w, h)).length();
+}
+
+QedLine::QedLine(QWidget *parent, int length, Qt::Orientation oriented) : QedGadget(parent)
+{
+ setup();
+ my.oriented = oriented;
+ my.box = QRect(0, 0, length, 1);
+ my.length = 1.0 * length;
+}
+
+void
+QedLine::setup(void)
+{
+ const qreal baseBound = 32.0;
+ const int iBaseBound = (int)(baseBound+0.5);
+ my.oriented = Qt::Horizontal;
+ my.bound = baseBound;
+ setMinimumSize(iBaseBound, iBaseBound);
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+}
+
+void
+QedLine::resizeEvent(QResizeEvent *event)
+{
+ QSize size = event->size();
+ my.bound = qMin(size.height(), size.width());
+}
+
+void
+QedLine::paintEvent(QPaintEvent *event)
+{
+ qreal lowerInset, upperInset, radius = my.bound / 16.0;
+ (void)event;
+
+ QPainterPath mainSquarePath;
+ lowerInset = 0.3 * my.bound;
+ upperInset = (my.bound * my.length) - (lowerInset * 2.0);
+ QRectF mainBox(lowerInset, lowerInset,
+ upperInset, my.bound - (lowerInset * 2.0));
+ mainSquarePath.addRoundedRect(mainBox, radius, radius);
+ mainSquarePath.closeSubpath();
+ QLinearGradient mainGradient(0, 0, 0, 1.0 * my.bound);
+ mainGradient.setColorAt(0.0, Qt::lightGray);
+ mainGradient.setColorAt(1.0, Qt::darkGray);
+
+ QPainterPath reflectSquarePath;
+ QRectF reflectBox(0.13538 * my.bound, 0.12969 * my.bound,
+ 0.73084 * my.bound, 0.48615 * my.bound);
+ reflectSquarePath.addRoundedRect(reflectBox, radius, radius);
+ reflectSquarePath.closeSubpath();
+ QLinearGradient reflectGradient(0, 0, 0, 1.22953 * my.bound);
+ reflectGradient.setColorAt(0.0, Qt::white);
+ reflectGradient.setColorAt(1.0, Qt::gray);
+
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setPen(Qt::NoPen);
+
+ painter.setBrush(mainGradient);
+ painter.drawPath(mainSquarePath);
+ painter.setBrush(reflectGradient);
+ painter.drawPath(reflectSquarePath);
+}
diff --git a/src/libpcp_qed/src/qed_line.h b/src/libpcp_qed/src/qed_line.h
new file mode 100644
index 0000000..3444c9e
--- /dev/null
+++ b/src/libpcp_qed/src/qed_line.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013-2014, Red Hat.
+ *
+ * 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 QED_LINE_H
+#define QED_LINE_H
+
+#include <QtGui>
+#include "qed_gadget.h"
+
+class QedLine : public QedGadget
+{
+ Q_OBJECT
+
+public:
+ QedLine(QWidget *parent, qreal length);
+ QedLine(QWidget *parent, int length, Qt::Orientation o);
+ QedLine(QWidget *parent, int x, int y, int w, int h);
+
+ void setOrientation(Qt::Orientation o) { my.oriented = o; }
+
+private:
+ void setup(void);
+ virtual void paintEvent(QPaintEvent *);
+ virtual void resizeEvent(QResizeEvent *);
+
+ struct {
+ QRect box;
+ qreal bound;
+ qreal length;
+ enum Qt::Orientation oriented;
+ } my;
+};
+
+#endif // QED_LINE_H
diff --git a/src/libpcp_qed/src/qed_recorddialog.cpp b/src/libpcp_qed/src/qed_recorddialog.cpp
new file mode 100644
index 0000000..24f977b
--- /dev/null
+++ b/src/libpcp_qed/src/qed_recorddialog.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * 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.
+ */
+#include "qed_recorddialog.h"
+#include <QtCore/QDateTime>
+#include <QtCore/QTextStream>
+#include <QtGui/QMessageBox>
+#include <QtGui/QDoubleValidator>
+
+#include "qed_app.h"
+#include "qed_console.h"
+#include "qed_viewcontrol.h"
+#include "qed_fileiconprovider.h"
+
+QedRecordDialog::QedRecordDialog() : QDialog()
+{
+ setupUi(this);
+ deltaLineEdit->setValidator(
+ new QDoubleValidator(0.001, INT_MAX, 3, deltaLineEdit));
+}
+
+void QedRecordDialog::languageChange()
+{
+ retranslateUi(this);
+}
+
+void QedRecordDialog::init(QedViewControl *view, double userDelta)
+{
+ QString pmlogger = "~/.pcp/pmlogger/";
+ QString viewName, folioName, archiveName;
+
+ viewName = folioName = archiveName = pmlogger;
+
+ viewName.append(tr("[date].view"));
+ viewLineEdit->setText(viewName);
+ folioName.append(tr("[date].folio"));
+ folioLineEdit->setText(folioName);
+ archiveName.append(tr("[host]/[date]"));
+ archiveLineEdit->setText(archiveName);
+
+ my.view = view;
+ my.userDelta = userDelta;
+ my.units = QmcTime::Seconds;
+ deltaLineEdit->setText(QmcTime::deltaString(userDelta, my.units));
+
+ selectedRadioButton->setChecked(false);
+ allGadgetsRadioButton->setChecked(true);
+}
+
+void QedRecordDialog::selectedRadioButton_clicked()
+{
+ selectedRadioButton->setChecked(true);
+ allGadgetsRadioButton->setChecked(false);
+}
+
+void QedRecordDialog::allGadgetsRadioButton_clicked()
+{
+ selectedRadioButton->setChecked(false);
+ allGadgetsRadioButton->setChecked(true);
+}
+
+void QedRecordDialog::deltaUnitsComboBox_activated(int value)
+{
+ my.userDelta = QmcTime::deltaValue(deltaLineEdit->text(), my.units);
+ my.units = (QmcTime::DeltaUnits)value;
+ deltaLineEdit->setText(QmcTime::deltaString(my.userDelta, my.units));
+}
+
+void QedRecordDialog::viewPushButton_clicked()
+{
+ QedRecordFileDialog view(this);
+
+ view.setDirectory(QDir::homePath().append("/.pcp/pmlogger/"));
+ if (view.exec() == QDialog::Accepted)
+ viewLineEdit->setText(view.selectedFiles().at(0));
+}
+
+void QedRecordDialog::folioPushButton_clicked()
+{
+ QedRecordFileDialog folio(this);
+
+ folio.setDirectory(QDir::homePath().append("/.pcp/pmlogger/"));
+ if (folio.exec() == QDialog::Accepted)
+ folioLineEdit->setText(folio.selectedFiles().at(0));
+}
+
+void QedRecordDialog::archivePushButton_clicked()
+{
+ QedRecordFileDialog archive(this);
+
+ archive.setDirectory(QDir::homePath().append("/.pcp/pmlogger/"));
+ if (archive.exec() == QDialog::Accepted)
+ archiveLineEdit->setText(archive.selectedFiles().at(0));
+}
+
+bool QedRecordDialog::saveFolio(QString folioName, QString viewName)
+{
+ QFile folio(folioName);
+
+ if (!folio.open(QIODevice::WriteOnly)) {
+ QString msg = tr("Cannot open file: ");
+ msg.append(folioName);
+ msg.append("\n");
+ msg.append(folio.errorString());
+ QMessageBox::warning(this, pmProgname, msg);
+ return false;
+ }
+
+ QTextStream stream(&folio);
+ QString datetime;
+
+ datetime = QDateTime::currentDateTime().toString("ddd MMM d hh:mm:ss yyyy");
+ stream << "PCPFolio\n";
+ stream << "Version: 1\n";
+ stream << "# use pmafm(1) to process this PCP archive folio\n" << "#\n";
+ stream << "Created: on " << QmcSource::localHost;
+ stream << " at " << datetime << "\n";
+ stream << "Creator: pmchart " << viewName << "\n";
+ stream << "#\t\tHost\t\tBasename\n";
+
+ for (int i = 0; i < my.hosts.size(); i++) {
+ QString host = my.hosts.at(i);
+ QString archive = my.archives.at(i);
+ QFileInfo logFile(archive);
+ QDir logDir = logFile.dir();
+ logDir.mkpath(logDir.absolutePath());
+ stream << "Archive:\t" << my.hosts.at(i) << "\t\t" << archive << "\n";
+ }
+ return true;
+}
+
+bool QedRecordDialog::saveConfig(QString configfile, QString configdata)
+{
+ QFile config(configfile);
+
+ if (!config.open(QIODevice::WriteOnly)) {
+ QString msg = tr("Cannot open file: ");
+ msg.append(configfile);
+ msg.append("\n");
+ msg.append(config.errorString());
+ QMessageBox::warning(this, pmProgname, msg);
+ return false;
+ }
+
+ QTextStream stream(&config);
+ stream << configdata;
+ return true;
+}
+
+PmLogger::PmLogger(QObject *parent) : QProcess(parent)
+{
+ connect(this, SIGNAL(finished(int, QProcess::ExitStatus)),
+ this, SLOT(finished(int, QProcess::ExitStatus)));
+}
+
+void PmLogger::init(QedViewControl *view, QString host, QString logfile)
+{
+ my.view = view;
+ my.host = host;
+ my.logfile = logfile;
+ my.terminating = false;
+}
+
+void PmLogger::terminate()
+{
+ my.terminating = true;
+}
+
+void PmLogger::finished(int, QProcess::ExitStatus)
+{
+ QString msg;
+
+ if (my.terminating == false) {
+ my.terminating = true;
+ if (my.view->stopRecording(msg) == 0) {
+ msg = "Recording process (pmlogger) exited unexpectedly\n";
+ msg.append("for host ");
+ msg.append(my.host);
+ msg.append(".\n\n");
+ msg.append("Additional diagnostics may be available in the log:\n");
+ msg.append(my.logfile);
+ }
+ QMessageBox::warning(NULL, pmProgname, msg);
+ }
+}
+
+void QedRecordDialog::buttonOk_clicked()
+{
+ if (deltaLineEdit->isModified()) {
+ // convert to seconds, make sure its still in range 0.001-INT_MAX
+ double input = QmcTime::deltaValue(deltaLineEdit->text(), my.units);
+ if (input < 0.001 || input > INT_MAX) {
+ QString msg = tr("Record Sampling Interval is invalid.\n");
+ msg.append(deltaLineEdit->text());
+ msg.append(" is out of range (0.001 to 0x7fffffff seconds)\n");
+ QMessageBox::warning(this, pmProgname, msg);
+ return;
+ }
+ }
+
+ QString today = QDateTime::currentDateTime().toString("yyyyMMdd.hh.mm.ss");
+
+ QString viewName = viewLineEdit->text().trimmed();
+ viewName.replace(QRegExp("^~"), QDir::homePath());
+ viewName.replace(QRegExp("\\[date\\]"), today);
+ viewName.replace(QRegExp("\\[host\\]"), QmcSource::localHost);
+ QFileInfo viewFile(viewName);
+ QDir viewDir = viewFile.dir();
+ if (viewDir.mkpath(viewDir.absolutePath()) == false) {
+ QString msg = tr("Failed to create path for view:\n");
+ msg.append(viewName);
+ msg.append("\n");
+ QMessageBox::warning(this, pmProgname, msg);
+ return;
+ }
+
+ QString folioName = folioLineEdit->text().trimmed();
+ folioName.replace(QRegExp("^~"), QDir::homePath());
+ folioName.replace(QRegExp("\\[date\\]"), today);
+ folioName.replace(QRegExp("\\[host\\]"), QmcSource::localHost);
+ QFileInfo folioFile(folioName);
+ QDir folioDir = folioFile.dir();
+ if (folioDir.mkpath(folioDir.absolutePath()) == false) {
+ QString msg = tr("Failed to create path for folio:\n");
+ msg.append(folioName);
+ msg.append("\n");
+ QMessageBox::warning(this, pmProgname, msg);
+ return;
+ }
+
+ console->post("RecordDialog verifying paths view=%s folio=%s",
+ (const char *)folioName.toAscii(), (const char *)viewName.toAscii());
+
+ my.viewName = viewName;
+ my.folioName = folioName;
+ my.delta.setNum(QmcTime::deltaValue(deltaLineEdit->text(), my.units), 'f');
+
+ my.hosts = my.view->hostList(selectedRadioButton->isChecked());
+ for (int h = 0; h < my.hosts.count(); h++) {
+ QString archive = archiveLineEdit->text().trimmed();
+ archive.replace(QRegExp("^~"), QDir::homePath());
+ archive.replace(QRegExp("\\[host\\]"), my.hosts.at(h));
+ archive.replace(QRegExp("\\[date\\]"), today);
+ my.archives.append(archive);
+ }
+
+ if (my.view->saveConfig(viewName, false, false, false, true) == false)
+ return;
+ if (saveFolio(folioName, viewName) == false)
+ return;
+ QDialog::accept();
+}
+
+//
+// write pmlogger, pmchart and pmafm configs, then start pmloggers.
+//
+void QedRecordDialog::startLoggers()
+{
+ QString pmlogger = pmGetConfig("PCP_BINADM_DIR");
+ pmlogger.append("/pmlogger");
+
+ QString regex = "^";
+ regex.append(QDir::homePath());
+ my.folioName.replace(QRegExp(regex), "~");
+
+ my.view->addFolio(my.folioName, my.viewName);
+
+ for (int i = 0; i < my.hosts.size(); i++) {
+ PmLogger *process = new PmLogger(this);
+ QString archive = my.archives.at(i);
+ QString host = my.hosts.at(i);
+ QString logfile, configfile;
+
+ configfile = archive;
+ configfile.append(".config");
+ logfile = archive;
+ logfile.append(".log");
+
+ process->init(my.view, host, logfile);
+
+ QStringList arguments;
+ arguments << "-r" << "-c" << configfile << "-h" << host << "-x0";
+ arguments << "-l" << logfile << "-t" << my.delta << archive;
+
+ QString data("#pmlogger Version 1\n\n"); // header for file(1)
+ data.append(my.view->pmloggerSyntax(selectedRadioButton->isChecked()));
+ saveConfig(configfile, data);
+
+ process->start(pmlogger, arguments);
+ my.view->addLogger(process, archive);
+
+ // Send initial control messages to pmlogger
+ QStringList control;
+ control << "V0\n";
+ control << "F" << my.folioName << "\n";
+ control << "Ppmchart\n" << "R\n";
+ for (int i = 0; i < control.size(); i++)
+ process->write(control.at(i).toAscii());
+ }
+}
+
+// RecordFileDialog is the one which is displayed when you click
+// on one of the file selection push buttons (view/logfile/folio).
+
+QedRecordFileDialog::QedRecordFileDialog(QWidget *parent) : QFileDialog(parent)
+{
+ setAcceptMode(QFileDialog::AcceptSave);
+ setFileMode(QFileDialog::AnyFile);
+ setIconProvider(fileIconProvider);
+ setConfirmOverwrite(true);
+}
+
+void QedRecordFileDialog::setFileName(QString path)
+{
+ selectFile(path);
+}
diff --git a/src/libpcp_qed/src/qed_recorddialog.h b/src/libpcp_qed/src/qed_recorddialog.h
new file mode 100644
index 0000000..b76db6b
--- /dev/null
+++ b/src/libpcp_qed/src/qed_recorddialog.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2007, 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 QED_RECORDDIALOG_H
+#define QED_RECORDDIALOG_H
+
+#include "ui_qed_recorddialog.h"
+#include <QtCore/QProcess>
+#include <QtGui/QFileDialog>
+#include "qmc_time.h"
+
+class QedViewControl;
+
+class QedRecordDialog : public QDialog, public Ui::QedRecordDialog
+{
+ Q_OBJECT
+
+public:
+ QedRecordDialog();
+
+ virtual void init(QedViewControl *, double);
+ virtual bool saveFolio(QString, QString);
+ virtual bool saveConfig(QString, QString);
+ virtual void startLoggers();
+
+public slots:
+ virtual void deltaUnitsComboBox_activated(int);
+ virtual void selectedRadioButton_clicked();
+ virtual void allGadgetsRadioButton_clicked();
+ virtual void viewPushButton_clicked();
+ virtual void folioPushButton_clicked();
+ virtual void archivePushButton_clicked();
+ virtual void buttonOk_clicked();
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ struct {
+ QedViewControl *view;
+ QString delta;
+ double userDelta;
+ QmcTime::DeltaUnits units;
+
+ QString viewName;
+ QString folioName;
+ QStringList hosts;
+ QStringList archives;
+ } my;
+};
+
+class PmLogger : public QProcess
+{
+ Q_OBJECT
+
+public:
+ PmLogger(QObject *);
+ void init(QedViewControl *view, QString host, QString log);
+ QString host() { return my.host; }
+
+public slots:
+ void terminate();
+ void finished(int, QProcess::ExitStatus);
+
+private:
+ struct {
+ QedViewControl *view;
+ QString host;
+ QString logfile;
+ bool terminating;
+ } my;
+};
+
+class QedRecordFileDialog : public QFileDialog, public Ui::QedRecordDialog
+{
+ Q_OBJECT
+
+public:
+ QedRecordFileDialog(QWidget* parent);
+ void setFileName(QString);
+};
+
+#endif // QED_RECORDDIALOG_H
diff --git a/src/libpcp_qed/src/qed_recorddialog.ui b/src/libpcp_qed/src/qed_recorddialog.ui
new file mode 100644
index 0000000..627381e
--- /dev/null
+++ b/src/libpcp_qed/src/qed_recorddialog.ui
@@ -0,0 +1,540 @@
+<ui version="4.0" >
+ <class>QedRecordDialog</class>
+ <widget class="QDialog" name="QedRecordDialog" >
+ <property name="windowModality" >
+ <enum>Qt::WindowModal</enum>
+ </property>
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>410</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>410</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>Record</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="libapp.qrc" >:/images/archive.png</iconset>
+ </property>
+ <property name="toolTip" >
+ <string/>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="allGadgetsRadioButton" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>All Charts in Tab</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="selectedRadioButton" >
+ <property name="text" >
+ <string>Selected Chart Only</string>
+ </property>
+ <property name="checked" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="deltaLabel" >
+ <property name="text" >
+ <string>Logging Interval:</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLineEdit" name="deltaLineEdit" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="deltaUnitsComboBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="currentIndex" >
+ <number>1</number>
+ </property>
+ <property name="maxCount" >
+ <number>6</number>
+ </property>
+ <property name="insertPolicy" >
+ <enum>QComboBox::NoInsert</enum>
+ </property>
+ <property name="duplicatesEnabled" >
+ <bool>false</bool>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Milliseconds</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Seconds</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Minutes</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Hours</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Days</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Weeks</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="folioTextLabel" >
+ <property name="text" >
+ <string>Folio</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="folioLineEdit" />
+ </item>
+ <item>
+ <widget class="QPushButton" name="folioPushButton" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="libapp.qrc" >:/images/folio.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="viewTextLabel" >
+ <property name="text" >
+ <string>View</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="viewLineEdit" />
+ </item>
+ <item>
+ <widget class="QPushButton" name="viewPushButton" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="libapp.qrc" >:/images/view.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="archiveTextLabel" >
+ <property name="text" >
+ <string>Archive</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="archiveLineEdit" />
+ </item>
+ <item>
+ <widget class="QPushButton" name="archivePushButton" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="libapp.qrc" >:/images/archive.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonOk" >
+ <property name="text" >
+ <string>&amp;OK</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel" >
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="libapp.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>buttonOk_clicked()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>selectedRadioButton</sender>
+ <signal>clicked()</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>selectedRadioButton_clicked()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>allGadgetsRadioButton</sender>
+ <signal>clicked()</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>allGadgetsRadioButton_clicked()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>deltaUnitsComboBox</sender>
+ <signal>activated(int)</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>deltaUnitsComboBox_activated(int)</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>viewPushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>viewPushButton_clicked()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>folioPushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>folioPushButton_clicked()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>archivePushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>QedRecordDialog</receiver>
+ <slot>archivePushButton_clicked()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/libpcp_qed/src/qed_statusbar.cpp b/src/libpcp_qed/src/qed_statusbar.cpp
new file mode 100644
index 0000000..2d669cc
--- /dev/null
+++ b/src/libpcp_qed/src/qed_statusbar.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2008, 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 <QtGui>
+#include <QHBoxLayout>
+#include "qed_statusbar.h"
+#include "qed_app.h"
+
+QedStatusBar::QedStatusBar()
+{
+ QFont *font = QedApp::globalFont();
+
+ setFont(*font);
+ setFixedHeight(buttonSize());
+ setSizeGripEnabled(false);
+
+ my.timeButton = new QedTimeButton(this);
+ my.timeButton->setFixedSize(QSize(buttonSize(), buttonSize()));
+ my.timeButton->setWhatsThis(QApplication::translate("PmChart",
+ "VCR state button, also used to display the time control window.",
+ 0, QApplication::UnicodeUTF8));
+ my.timeFrame = new QToolButton(this);
+ my.timeFrame->setMinimumSize(QSize(buttonSize(), buttonSize()));
+ my.timeFrame->setSizePolicy(
+ QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ my.timeFrame->setWhatsThis(QApplication::translate("PmChart",
+ "Unified time axis, displaying the current time position at the "
+ "rightmost point, and either status information or the timeframe "
+ "covering all Visible Points to the left",
+ 0, QApplication::UnicodeUTF8));
+
+ delete layout();
+ QHBoxLayout *box = new QHBoxLayout;
+ box->setMargin(0);
+ box->setSpacing(1);
+ box->addWidget(my.timeButton);
+ box->addWidget(my.timeFrame);
+ setLayout(box);
+
+ my.gadgetLabel = new QLabel(my.timeFrame);
+ my.gadgetLabel->setFont(*font);
+ my.gadgetLabel->hide(); // shown with gadget Views
+
+ my.dateLabel = new QLabel(my.timeFrame);
+ my.dateLabel->setIndent(8);
+ my.dateLabel->setFont(*font);
+ my.dateLabel->setAlignment(Qt::AlignRight | Qt::AlignBottom);
+
+ my.labelSpacer = new QSpacerItem(10, 0,
+ QSizePolicy::Fixed, QSizePolicy::Minimum);
+ my.rightSpacer = new QSpacerItem(0, 0,
+ QSizePolicy::Fixed, QSizePolicy::Minimum);
+
+ my.valueLabel = new QLabel(my.timeFrame);
+ my.valueLabel->setIndent(8);
+ my.valueLabel->setFont(*font);
+ my.valueLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom);
+
+ my.grid = new QGridLayout; // Grid of [5 x 3] cells
+ my.grid->setMargin(0);
+ my.grid->setSpacing(0);
+ my.grid->addWidget(my.gadgetLabel, 0, 0, 1, 3);
+ my.grid->addWidget(my.dateLabel, 2, 2, 1, 1); // bottom row, last two cols
+ my.grid->addItem(my.labelSpacer, 2, 1, 1, 1); // bottom row, second column
+ my.grid->addWidget(my.valueLabel, 2, 0, 1, 1); // bottom row, first column.
+ my.grid->addItem(my.rightSpacer, 0, 4, 2, 1); // all rows, in final column
+ my.timeFrame->setLayout(my.grid);
+}
+
+void QedStatusBar::init()
+{
+}
+
+bool QedStatusBar::event(QEvent *e)
+{
+ if (e->type() == QEvent::Show)
+ my.grid->update();
+ return QStatusBar::event(e);
+}
+
+void QedStatusBar::resizeEvent(QResizeEvent *e)
+{
+ my.timeFrame->resize(e->size().width()-1 - buttonSize(), buttonSize());
+}
+
+void QedStatusBar::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QStyleOption opt(0);
+
+ opt.rect.setRect(buttonSize()+2, 0, width()-buttonSize()-2, buttonSize());
+ opt.palette = palette();
+ opt.state = QStyle::State_None;
+ style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &p, my.timeFrame);
+}
diff --git a/src/libpcp_qed/src/qed_statusbar.h b/src/libpcp_qed/src/qed_statusbar.h
new file mode 100644
index 0000000..6ec070f
--- /dev/null
+++ b/src/libpcp_qed/src/qed_statusbar.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2008, 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 QED_STATUSBAR_H
+#define QED_STATUSBAR_H
+
+#include <QtGui/QLabel>
+#include <QtGui/QStatusBar>
+#include <QtGui/QGridLayout>
+#include "qed_timebutton.h"
+
+class QedStatusBar : public QStatusBar
+{
+ Q_OBJECT
+
+public:
+ QedStatusBar();
+ virtual ~QedStatusBar() { }
+ virtual void init();
+
+ static int buttonSize() { return 56; } // pixels
+
+ QLabel *dateLabel() { return my.dateLabel; }
+ QToolButton *timeFrame() { return my.timeFrame; }
+ QedTimeButton *timeButton() { return my.timeButton; }
+
+ QString dateText() { return my.dateLabel->text(); }
+ void setDateText(QString &s) { my.dateLabel->setText(s); }
+ void setValueText(QString &s) { my.valueLabel->setText(s); }
+ void clearValueText() { my.valueLabel->clear(); }
+
+ void setTimeAxisRightAlignment(int w);
+
+protected:
+ bool event(QEvent *);
+ void paintEvent(QPaintEvent *);
+ void resizeEvent(QResizeEvent *);
+
+ struct {
+ QGridLayout *grid;
+ QSpacerItem *labelSpacer; // spacer between date/value labels
+ QSpacerItem *rightSpacer; // spacer at right edge for toolbar
+ QToolButton *timeFrame;
+ QedTimeButton *timeButton;
+ QLabel *gadgetLabel;
+ QLabel *valueLabel;
+ QLabel *dateLabel;
+ } my;
+};
+
+#endif // QED_STATUSBAR_H
diff --git a/src/libpcp_qed/src/qed_timebutton.cpp b/src/libpcp_qed/src/qed_timebutton.cpp
new file mode 100644
index 0000000..0d50af6
--- /dev/null
+++ b/src/libpcp_qed/src/qed_timebutton.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2007, 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 "qed_timebutton.h"
+#include "qed_console.h"
+
+QedTimeButton::QedTimeButton(QWidget *parent) : QToolButton(parent)
+{
+ my.state = Timeless;
+ setIconSize(QSize(52, 52));
+ setFocusPolicy(Qt::NoFocus);
+ my.forwardLiveIcon = QIcon(":/images/play_live.png");
+ my.stoppedLiveIcon = QIcon(":/images/stop_live.png");
+ my.forwardRecordIcon = QIcon(":/images/play_record.png");
+ my.stoppedRecordIcon = QIcon(":/images/stop_record.png");
+ my.forwardArchiveIcon = QIcon(":/images/play_archive.png");
+ my.stoppedArchiveIcon = QIcon(":/images/stop_archive.png");
+ my.backwardArchiveIcon = QIcon(":/images/back_archive.png");
+ my.stepForwardArchiveIcon = QIcon(":/images/stepfwd_archive.png");
+ my.stepBackwardArchiveIcon = QIcon(":/images/stepback_archive.png");
+ my.fastForwardArchiveIcon = QIcon(":/images/fastfwd_archive.png");
+ my.fastBackwardArchiveIcon = QIcon(":/images/fastback_archive.png");
+ console->post(QedApp::DebugUi, "Time button resources loaded");
+}
+
+void QedTimeButton::setButtonState(QedTimeButton::State state)
+{
+ if (my.state == state)
+ return;
+ switch (state) {
+ case QedTimeButton::ForwardLive:
+ setIcon(my.forwardLiveIcon);
+ break;
+ case QedTimeButton::StoppedLive:
+ setIcon(my.stoppedLiveIcon);
+ break;
+ case QedTimeButton::ForwardRecord:
+ setIcon(my.forwardRecordIcon);
+ break;
+ case QedTimeButton::StoppedRecord:
+ setIcon(my.stoppedRecordIcon);
+ break;
+ case QedTimeButton::ForwardArchive:
+ setIcon(my.forwardArchiveIcon);
+ break;
+ case QedTimeButton::StoppedArchive:
+ setIcon(my.stoppedArchiveIcon);
+ break;
+ case QedTimeButton::BackwardArchive:
+ setIcon(my.backwardArchiveIcon);
+ break;
+ case QedTimeButton::StepForwardArchive:
+ setIcon(my.stepForwardArchiveIcon);
+ break;
+ case QedTimeButton::StepBackwardArchive:
+ setIcon(my.stepBackwardArchiveIcon);
+ break;
+ case QedTimeButton::FastForwardArchive:
+ setIcon(my.fastForwardArchiveIcon);
+ break;
+ case QedTimeButton::FastBackwardArchive:
+ setIcon(my.fastBackwardArchiveIcon);
+ break;
+ default:
+ abort();
+ }
+ my.state = state;
+}
diff --git a/src/libpcp_qed/src/qed_timebutton.h b/src/libpcp_qed/src/qed_timebutton.h
new file mode 100644
index 0000000..8b37f8d
--- /dev/null
+++ b/src/libpcp_qed/src/qed_timebutton.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2007, 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 QED_TIMEBUTTON_H
+#define QED_TIMEBUTTON_H
+
+#include <QtGui/QIcon>
+#include <QtGui/QToolButton>
+
+class QedTimeButton : public QToolButton
+{
+ Q_OBJECT
+
+public:
+ typedef enum {
+ Timeless = 1,
+ ForwardLive = 2,
+ StoppedLive = 3,
+ ForwardRecord = 4,
+ StoppedRecord = 5,
+ ForwardArchive = 6,
+ StoppedArchive = 7,
+ BackwardArchive = 8,
+ StepForwardArchive = 9,
+ StepBackwardArchive = 10,
+ FastForwardArchive = 11,
+ FastBackwardArchive = 12,
+ } State;
+
+ QedTimeButton(QWidget *);
+ void setButtonState(State state);
+
+private:
+ struct {
+ State state;
+ QIcon forwardLiveIcon;
+ QIcon stoppedLiveIcon;
+ QIcon forwardRecordIcon;
+ QIcon stoppedRecordIcon;
+ QIcon forwardArchiveIcon;
+ QIcon stoppedArchiveIcon;
+ QIcon backwardArchiveIcon;
+ QIcon stepForwardArchiveIcon;
+ QIcon stepBackwardArchiveIcon;
+ QIcon fastForwardArchiveIcon;
+ QIcon fastBackwardArchiveIcon;
+ } my;
+};
+
+#endif // QED_TIMEBUTTON_H
diff --git a/src/libpcp_qed/src/qed_timecontrol.cpp b/src/libpcp_qed/src/qed_timecontrol.cpp
new file mode 100644
index 0000000..a3de69e
--- /dev/null
+++ b/src/libpcp_qed/src/qed_timecontrol.cpp
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2006-2007, 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 <QtGui/QMessageBox>
+#include <QtGui/QApplication>
+#include <QtNetwork/QHostAddress>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+
+#include "qed_timecontrol.h"
+#include "qed_console.h"
+#include "qed_app.h"
+
+QedTimeControl::QedTimeControl() : QProcess(NULL)
+{
+ my.tcpPort = -1;
+ my.tzLength = 0;
+ my.tzData = NULL;
+ my.bufferLength = sizeof(QmcTime::Packet);
+
+ console->post("TimeControl::TimeControl: created");
+ my.buffer = (char *)malloc(my.bufferLength);
+ my.livePacket = (QmcTime::Packet *)malloc(sizeof(QmcTime::Packet));
+ my.archivePacket = (QmcTime::Packet *)malloc(sizeof(QmcTime::Packet));
+ if (!my.buffer || !my.livePacket || !my.archivePacket)
+ QedApp::nomem();
+ my.livePacket->magic = QmcTime::Magic;
+ my.livePacket->source = QmcTime::HostSource;
+ my.liveState = QedTimeControl::Disconnected;
+ my.liveSocket = new QTcpSocket(this);
+ connect(my.liveSocket, SIGNAL(connected()),
+ SLOT(liveSocketConnected()));
+ connect(my.liveSocket, SIGNAL(disconnected()),
+ SLOT(liveCloseConnection()));
+ connect(my.liveSocket, SIGNAL(readyRead()),
+ SLOT(liveProtocolMessage()));
+
+ my.archivePacket->magic = QmcTime::Magic;
+ my.archivePacket->source = QmcTime::ArchiveSource;
+ my.archiveState = QedTimeControl::Disconnected;
+ my.archiveSocket = new QTcpSocket(this);
+ connect(my.archiveSocket, SIGNAL(connected()),
+ SLOT(archiveSocketConnected()));
+ connect(my.archiveSocket, SIGNAL(disconnected()),
+ SLOT(archiveCloseConnection()));
+ connect(my.archiveSocket, SIGNAL(readyRead()),
+ SLOT(archiveProtocolMessage()));
+}
+
+void QedTimeControl::quit()
+{
+ disconnect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this,
+ SLOT(endTimeControl()));
+ if (my.liveSocket) {
+ my.liveSocket->close();
+ my.liveSocket = NULL;
+ }
+ if (my.archiveSocket) {
+ my.archiveSocket->close();
+ my.archiveSocket = NULL;
+ }
+ terminate();
+}
+
+void QedTimeControl::init(int port, bool live,
+ struct timeval *interval, struct timeval *position,
+ struct timeval *starttime, struct timeval *endtime,
+ QString tzstring, QString tzlabel)
+{
+ struct timeval now;
+ int tzlen = tzstring.length(), lablen = tzlabel.length();
+
+ my.tzLength = tzlen+1 + lablen+1;
+ my.tzData = (char *)realloc(my.tzData, my.tzLength);
+ if (!my.tzData)
+ QedApp::nomem();
+
+ my.livePacket->length = my.archivePacket->length =
+ sizeof(QmcTime::Packet) + my.tzLength;
+ my.livePacket->command = my.archivePacket->command = QmcTime::Set;
+ my.livePacket->delta = my.archivePacket->delta = *interval;
+ if (live) {
+ my.livePacket->position = *position;
+ my.livePacket->start = *starttime;
+ my.livePacket->end = *endtime;
+ memset(&my.archivePacket->position, 0, sizeof(struct timeval));
+ memset(&my.archivePacket->start, 0, sizeof(struct timeval));
+ memset(&my.archivePacket->end, 0, sizeof(struct timeval));
+ } else {
+ gettimeofday(&now, NULL);
+ my.archivePacket->position = *position;
+ my.archivePacket->start = *starttime;
+ my.archivePacket->end = *endtime;
+ my.livePacket->position = now;
+ my.livePacket->start = now;
+ my.livePacket->end = now;
+ }
+ strncpy(my.tzData, (const char *)tzstring.toAscii(), tzlen+1);
+ strncpy(my.tzData + tzlen+1, (const char *)tzlabel.toAscii(), lablen+1);
+
+ if (port < 0) {
+ startTimeServer();
+ } else {
+ my.tcpPort = port;
+ liveConnect();
+ archiveConnect();
+ }
+}
+
+void QedTimeControl::addArchive(
+ struct timeval starttime, struct timeval endtime,
+ QString tzstring, QString tzlabel, bool atEnd)
+{
+ QmcTime::Packet *message;
+ int tzlen = tzstring.length(), lablen = tzlabel.length();
+ int sz = sizeof(QmcTime::Packet) + tzlen + 1 + lablen + 1;
+
+ if (my.archivePacket->position.tv_sec == 0) { // first archive
+ my.archivePacket->position = atEnd ? endtime : starttime;
+ my.archivePacket->start = starttime;
+ my.archivePacket->end = endtime;
+ }
+
+ if ((message = (QmcTime::Packet *)malloc(sz)) == NULL)
+ QedApp::nomem();
+ *message = *my.archivePacket;
+ message->command = QmcTime::Bounds;
+ message->length = sz;
+ message->start = starttime;
+ message->end = endtime;
+ strncpy((char *)message->data, (const char *)tzstring.toAscii(), tzlen+1);
+ strncpy((char *)message->data + tzlen+1,
+ (const char *)tzlabel.toAscii(), lablen+1);
+ if (my.archiveSocket->write((const char *)message, sz) < 0)
+ QMessageBox::warning(0,
+ QApplication::tr("Error"),
+ QApplication::tr("Cannot update pmtime boundaries."),
+ QApplication::tr("Quit") );
+ free(message);
+}
+
+void QedTimeControl::liveConnect()
+{
+ console->post("Connecting to pmtime, live source");
+ my.liveSocket->connectToHost(QHostAddress::LocalHost, my.tcpPort);
+}
+
+void QedTimeControl::archiveConnect()
+{
+ console->post("Connecting to pmtime, archive source");
+ my.archiveSocket->connectToHost(QHostAddress::LocalHost, my.tcpPort);
+}
+
+void QedTimeControl::showLiveTimeControl(void)
+{
+ my.livePacket->command = QmcTime::GUIShow;
+ my.livePacket->length = sizeof(QmcTime::Packet);
+ if (my.liveSocket->write((const char *)my.livePacket,
+ sizeof(QmcTime::Packet)) < 0)
+ QMessageBox::warning(0,
+ QApplication::tr("Error"),
+ QApplication::tr("Cannot get pmtime to show itself."),
+ QApplication::tr("Quit") );
+}
+
+void QedTimeControl::showArchiveTimeControl(void)
+{
+ my.archivePacket->command = QmcTime::GUIShow;
+ my.archivePacket->length = sizeof(QmcTime::Packet);
+ if (my.archiveSocket->write((const char *)my.archivePacket,
+ sizeof(QmcTime::Packet)) < 0)
+ QMessageBox::warning(0,
+ QApplication::tr("Error"),
+ QApplication::tr("Cannot get pmtime to show itself."),
+ QApplication::tr("Quit") );
+}
+
+void QedTimeControl::hideLiveTimeControl()
+{
+ my.livePacket->command = QmcTime::GUIHide;
+ my.livePacket->length = sizeof(QmcTime::Packet);
+ if (my.liveSocket->write((const char *)my.livePacket,
+ sizeof(QmcTime::Packet)) < 0)
+ QMessageBox::warning(0,
+ QApplication::tr("Error"),
+ QApplication::tr("Cannot get pmtime to hide itself."),
+ QApplication::tr("Quit") );
+}
+
+void QedTimeControl::hideArchiveTimeControl()
+{
+ my.archivePacket->command = QmcTime::GUIHide;
+ my.archivePacket->length = sizeof(QmcTime::Packet);
+ if (my.archiveSocket->write((const char *)my.archivePacket,
+ sizeof(QmcTime::Packet)) < 0)
+ QMessageBox::warning(0,
+ QApplication::tr("Error"),
+ QApplication::tr("Cannot get pmtime to hide itself."),
+ QApplication::tr("Quit") );
+}
+
+void QedTimeControl::endTimeControl(void)
+{
+ QMessageBox::warning(0,
+ QApplication::tr("Error"),
+ QApplication::tr("Time Control process pmtime has exited."),
+ QApplication::tr("Quit") );
+ exit(-1);
+}
+
+void QedTimeControl::liveCloseConnection()
+{
+ my.liveSocket->close();
+ my.liveSocket = NULL;
+ emit done();
+ exit(0);
+}
+
+void QedTimeControl::archiveCloseConnection()
+{
+ my.archiveSocket->close();
+ my.archiveSocket = NULL;
+ emit done();
+ exit(0);
+}
+
+void QedTimeControl::liveSocketConnected()
+{
+ if (my.liveSocket->write((const char *)my.livePacket,
+ sizeof(QmcTime::Packet)) < 0) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr(
+ "Failed socket write in live pmtime negotiation."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ if (my.liveSocket->write((const char *)my.tzData, my.tzLength) < 0) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr(
+ "Failed to send timezone in live pmtime negotiation."),
+ QApplication::tr("Quit"));
+ exit(1);
+ }
+ my.liveState = QedTimeControl::AwaitingACK;
+}
+
+void QedTimeControl::archiveSocketConnected()
+{
+ if (my.archiveSocket->write((const char *)my.archivePacket,
+ sizeof(QmcTime::Packet)) < 0) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr(
+ "Failed socket write in archive pmtime negotiation."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ if (my.archiveSocket->write((const char *)my.tzData, my.tzLength) < 0) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr(
+ "Failed timezone send in archive pmtime negotiation."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ my.archiveState = QedTimeControl::AwaitingACK;
+}
+
+//
+// Start a shiny new pmtime process.
+// The one process serves time for all (live and archive) tabs.
+// We do have to specify which form will be used first, however.
+//
+void QedTimeControl::startTimeServer()
+{
+ QStringList arguments;
+
+ if (pmDebug & DBG_TRACE_TIMECONTROL)
+ arguments << "-D" << "all";
+ connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this,
+ SLOT(endTimeControl()));
+ connect(this, SIGNAL(readyReadStandardOutput()), this,
+ SLOT(readPortFromStdout()));
+ start("pmtime", arguments);
+}
+
+//
+// When pmtime starts in "port probe" mode, port# is written to
+// stdout. We can only complete negotiation once we have that...
+//
+void QedTimeControl::readPortFromStdout(void)
+{
+ bool ok;
+ QString data = readAllStandardOutput();
+
+ my.tcpPort = data.remove("port=").toInt(&ok, 10);
+ if (!ok) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr("Bad port number from pmtime program."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+
+ liveConnect();
+ archiveConnect();
+}
+
+void QedTimeControl::protocolMessage(bool live,
+ QmcTime::Packet *packet, QTcpSocket *socket, QedProtocolState *state)
+{
+ int sts, need = sizeof(QmcTime::Packet), offset = 0;
+ QmcTime::Packet *msg;
+
+ // Read one pmtime packet, handling both small reads and large packets
+ for (;;) {
+ sts = socket->read(my.buffer + offset, need);
+ if (sts < 0) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr("Failed socket read in pmtime transfer."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ else if (sts != need) {
+ need -= sts;
+ offset += sts;
+ continue;
+ }
+
+ msg = (QmcTime::Packet *)my.buffer;
+ if (msg->magic != QmcTime::Magic) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr("Bad client message magic number."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ if (msg->length > my.bufferLength) {
+ my.bufferLength = msg->length;
+ my.buffer = (char *)realloc(my.buffer, my.bufferLength);
+ if (!my.buffer)
+ QedApp::nomem();
+ msg = (QmcTime::Packet *)my.buffer;
+ }
+ if (msg->length > (uint)offset + sts) {
+ offset += sts;
+ need = msg->length - offset;
+ continue;
+ }
+ break;
+ }
+
+#if DESPERATE
+ console->post(QedConsole::DebugProtocol,
+ "QedTimeControl::protocolMessage: recv pos=%s state=%d",
+ timeString(tosec(packet->position)), *state);
+#endif
+
+ switch (*state) {
+ case QedTimeControl::AwaitingACK:
+ if (msg->command != QmcTime::ACK) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr("Initial ACK not received from pmtime."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ if (msg->source != packet->source) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr("pmtime not serving same metric source."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ *state = QedTimeControl::ClientReady;
+ if (msg->length > packet->length) {
+ packet = (QmcTime::Packet *)realloc(packet, msg->length);
+ if (!packet)
+ QedApp::nomem();
+ }
+ //
+ // Note: we drive the local state from the time control values,
+ // and _not_ from the values that we initially sent to it.
+ //
+ memcpy(packet, msg, msg->length);
+ emit VCRMode(live, msg, true);
+ break;
+
+ case QedTimeControl::ClientReady:
+ if (msg->command == QmcTime::Step) {
+ emit step(live, msg);
+ msg->command = QmcTime::ACK;
+ msg->length = sizeof(QmcTime::Packet);
+ sts = socket->write((const char *)msg, msg->length);
+ if (sts < 0 || sts != (int)msg->length) {
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr("Failed pmtime write for STEP ACK."),
+ QApplication::tr("Quit") );
+ exit(1);
+ }
+ } else if (msg->command == QmcTime::VCRMode ||
+ msg->command == QmcTime::VCRModeDrag ||
+ msg->command == QmcTime::Bounds) {
+ emit VCRMode(live, msg, msg->command == QmcTime::VCRModeDrag);
+ } else if (msg->command == QmcTime::TZ) {
+ emit timeZone(live, msg, (char *)msg->data);
+ }
+ break;
+
+ default:
+ QMessageBox::critical(0,
+ QApplication::tr("Fatal error"),
+ QApplication::tr("Protocol error with pmtime."),
+ QApplication::tr("Quit") );
+ // fall through
+ case QedTimeControl::Disconnected:
+ exit(1);
+ }
+}
+
+void QedTimeControl::protocolMessageLoop(bool live,
+ QmcTime::Packet *packet, QTcpSocket *socket, QedProtocolState *state)
+{
+ do {
+ protocolMessage(live, packet, socket, state);
+ } while (socket->bytesAvailable() >= (int)sizeof(QmcTime::Packet));
+}
diff --git a/src/libpcp_qed/src/qed_timecontrol.h b/src/libpcp_qed/src/qed_timecontrol.h
new file mode 100644
index 0000000..599ec88
--- /dev/null
+++ b/src/libpcp_qed/src/qed_timecontrol.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2006-2007, 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 QED_TIMECONTROL_H
+#define QED_TIMECONTROL_H
+
+#include <QtCore/QString>
+#include <QtCore/QProcess>
+#include <QtNetwork/QTcpSocket>
+#include <qmc_time.h>
+
+class QedTimeControl : public QProcess
+{
+ Q_OBJECT
+
+public:
+ QedTimeControl();
+
+ void init(int port, bool livemode,
+ struct timeval *interval, struct timeval *position,
+ struct timeval *starttime, struct timeval *endtime,
+ QString tzstring, QString tzlabel);
+ void quit();
+
+ void addArchive(struct timeval starttime, struct timeval endtime,
+ QString tzstring, QString tzlabel, bool atEnd);
+
+ void liveConnect();
+ void archiveConnect();
+
+ int port() { return my.tcpPort; }
+ struct timeval *liveInterval() { return &my.livePacket->delta; }
+ struct timeval *livePosition() { return &my.livePacket->position; }
+ struct timeval *archiveInterval() { return &my.archivePacket->delta; }
+ struct timeval *archivePosition() { return &my.archivePacket->position; }
+ struct timeval *archiveStart() { return &my.archivePacket->start; }
+ struct timeval *archiveEnd() { return &my.archivePacket->end; }
+
+signals:
+ void done();
+ void step(bool, QmcTime::Packet *);
+ void VCRMode(bool, QmcTime::Packet *, bool);
+ void timeZone(bool, QmcTime::Packet *, char *);
+
+public slots:
+ void showLiveTimeControl();
+ void hideLiveTimeControl();
+ void showArchiveTimeControl();
+ void hideArchiveTimeControl();
+ void endTimeControl();
+
+ void readPortFromStdout();
+
+ void liveCloseConnection();
+ void liveSocketConnected();
+ void liveProtocolMessage()
+ {
+ protocolMessageLoop(true, my.livePacket, my.liveSocket, &my.liveState);
+ }
+
+ void archiveCloseConnection();
+ void archiveSocketConnected();
+ void archiveProtocolMessage()
+ {
+ protocolMessageLoop(false, my.archivePacket, my.archiveSocket,
+ &my.archiveState);
+ }
+
+private:
+ typedef enum {
+ Disconnected = 1,
+ AwaitingACK = 2,
+ ClientReady = 3,
+ } QedProtocolState;
+
+ void startTimeServer();
+ void protocolMessage(bool live, QmcTime::Packet *pmtime,
+ QTcpSocket *socket, QedProtocolState *state);
+ void protocolMessageLoop(bool live, QmcTime::Packet *pmtime,
+ QTcpSocket *socket, QedProtocolState *state);
+
+ struct {
+ int tcpPort;
+ int tzLength;
+ char *tzData;
+
+ unsigned int bufferLength;
+ char *buffer;
+
+ QTcpSocket *liveSocket;
+ QmcTime::Packet *livePacket;
+ QedProtocolState liveState;
+
+ QTcpSocket *archiveSocket;
+ QmcTime::Packet *archivePacket;
+ QedProtocolState archiveState;
+ } my;
+};
+
+#endif // QED_TIMECONTROL_H
diff --git a/src/libpcp_qed/src/qed_viewcontrol.cpp b/src/libpcp_qed/src/qed_viewcontrol.cpp
new file mode 100644
index 0000000..3f5ff17
--- /dev/null
+++ b/src/libpcp_qed/src/qed_viewcontrol.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * 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 <QtGui/QMenu>
+#include <QtGui/QMessageBox>
+#include "qed_console.h"
+#include "qed_viewcontrol.h"
+#include "qed_recorddialog.h"
+
+QedViewControl::QedViewControl()
+{
+ my.recording = false;
+ my.action = NULL;
+ my.group = NULL;
+}
+
+QedViewControl::~QedViewControl()
+{
+ if (my.action)
+ delete my.action;
+}
+
+void QedViewControl::init(QedGroupControl *group, QMenu *menu, QString title, double delta)
+{
+ my.delta = delta;
+ my.title = title;
+ my.group = group;
+ my.action = new QAction(title, menu);
+}
+
+bool QedViewControl::isArchiveSource(void)
+{
+ return my.group->isArchiveSource();
+}
+
+bool QedViewControl::isRecording(void)
+{
+ return my.recording;
+}
+
+void QedViewControl::addFolio(QString folio, QString view)
+{
+ my.view = view;
+ my.folio = folio;
+}
+
+void QedViewControl::addLogger(PmLogger *pmlogger, QString archive)
+{
+ my.loggerList.append(pmlogger);
+ my.archiveList.append(archive);
+}
+
+bool QedViewControl::startRecording(void)
+{
+ QedRecordDialog record;
+
+ console->post("QedView::startRecording");
+ record.init(this, my.delta);
+ if (record.exec() != QDialog::Accepted)
+ my.recording = false;
+ else { // write pmlogger/pmchart/pmafm configs and start up loggers.
+ console->post("QedView::startRecording starting loggers");
+ record.startLoggers();
+ my.recording = true;
+ }
+ return my.recording;
+}
+
+bool QedViewControl::stopRecording(QString &errmsg)
+{
+ QString msg = "Q\n";
+ int count = my.loggerList.size();
+ bool error = false;
+
+ console->post("QedView::stopRecording stopping %d logger(s)", count);
+ for (int i = 0; i < count; i++) {
+ if (my.loggerList.at(i)->state() == QProcess::NotRunning) {
+ errmsg.append(QApplication::tr(
+ "Record process (pmlogger) failed for host: "));
+ errmsg.append(my.loggerList.at(i)->host());
+ errmsg.append("\n");
+ error = true;
+ }
+ else {
+ my.loggerList.at(i)->write(msg.toAscii());
+ my.loggerList.at(i)->terminate();
+ }
+ }
+ return error;
+}
+
+void QedViewControl::cleanupRecording(void)
+{
+ my.recording = false;
+ my.loggerList.clear();
+ my.archiveList.clear();
+ my.view = QString::null;
+ my.folio = QString::null;
+}
+
+bool QedViewControl::queryRecording(QString &errmsg)
+{
+ QString msg = "?\n";
+ bool error = false;
+ int i, count = my.loggerList.size();
+
+ console->post("QedView::stopRecording querying %d logger(s)", count);
+ for (i = 0; i < count; i++) {
+ if (my.loggerList.at(i)->state() == QProcess::NotRunning) {
+ errmsg.append(QApplication::tr(
+ "Record process (pmlogger) failed for host: "));
+ errmsg.append(my.loggerList.at(i)->host());
+ errmsg.append("\n");
+ error = true;
+ }
+ else {
+ my.loggerList.at(i)->write(msg.toAscii());
+ }
+ }
+
+ if (error) {
+ msg = "Q\n"; // if one fails, we shut down all loggers
+ for (i = 0; i < count; i++)
+ my.loggerList.at(i)->write(msg.toAscii());
+ cleanupRecording();
+ }
+
+ return error;
+}
+
+bool QedViewControl::detachLoggers(QString &errmsg)
+{
+ QString msg = "D\n";
+ bool error = false;
+ int count = my.loggerList.size();
+
+ console->post("QedView::detachLoggers detaching %d logger(s)", count);
+ for (int i = 0; i < count; i++) {
+ if (my.loggerList.at(i)->state() == QProcess::NotRunning) {
+ errmsg.append(QApplication::tr(
+ "Record process (pmlogger) failed for host: "));
+ errmsg.append(my.loggerList.at(i)->host());
+ errmsg.append("\n");
+ error = true;
+ }
+ else {
+ my.loggerList.at(i)->write(msg.toAscii());
+ }
+ }
+ if (error)
+ cleanupRecording();
+ return error;
+}
diff --git a/src/libpcp_qed/src/qed_viewcontrol.h b/src/libpcp_qed/src/qed_viewcontrol.h
new file mode 100644
index 0000000..4d84cb4
--- /dev/null
+++ b/src/libpcp_qed/src/qed_viewcontrol.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, Red Hat.
+ * Copyright (c) 2006-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.
+ */
+#ifndef QED_VIEWCONTROL_H
+#define QED_VIEWCONTROL_H
+
+#include <QtCore/QList>
+#include <QtGui/QAction>
+#include "qed_groupcontrol.h"
+
+class PmLogger;
+
+class QedViewControl
+{
+public:
+ QedViewControl();
+ virtual ~QedViewControl();
+
+ void init(QedGroupControl *, QMenu *, QString, double);
+ QedGroupControl *group() const { return my.group; }
+ bool isArchiveSource(); // query if tab is for archives
+
+ QAction *action() const { return my.action; }
+
+ QString view() const { return my.view; }
+ QString title() const { return my.title; }
+ void setTitle(QString &text) { my.title = text; my.action->setText(text); }
+
+ void addFolio(QString, QString);
+ void addLogger(PmLogger *, QString);
+ QStringList &archiveList() { return my.archiveList; }
+
+ virtual QStringList hostList(bool) = 0;
+ virtual QString pmloggerSyntax(bool) = 0;
+ virtual bool saveConfig(QString, bool, bool, bool, bool) = 0;
+
+ bool isRecording();
+ bool startRecording();
+ void cleanupRecording();
+ bool queryRecording(QString &);
+ bool stopRecording(QString &);
+ bool detachLoggers(QString &);
+
+private:
+ struct {
+ double delta; // default recording interval
+ QString title;
+ QAction *action;
+ QedGroupControl *group;
+
+ bool recording; // running any pmlogger's?
+ QString view;
+ QString folio;
+ QStringList archiveList; // list of archive names
+ QList<PmLogger*> loggerList; // list of pmloggers for our View
+ } my;
+};
+
+#endif // QED_VIEWCONTROL_H