diff options
Diffstat (limited to 'src/libpcp_qed')
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>&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>&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>&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 |