summaryrefslogtreecommitdiff
path: root/src/pmtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmtime')
-rw-r--r--src/pmtime/GNUmakefile71
-rw-r--r--src/pmtime/aboutdialog.cpp29
-rw-r--r--src/pmtime/aboutdialog.h30
-rw-r--r--src/pmtime/aboutdialog.ui229
-rw-r--r--src/pmtime/console.cpp65
-rw-r--r--src/pmtime/console.h37
-rw-r--r--src/pmtime/console.ui139
-rw-r--r--src/pmtime/main.cpp124
-rw-r--r--src/pmtime/pmtime.cpp96
-rw-r--r--src/pmtime/pmtime.h48
-rw-r--r--src/pmtime/pmtime.info.in18
-rw-r--r--src/pmtime/pmtime.pro24
-rw-r--r--src/pmtime/pmtime.qrc24
-rw-r--r--src/pmtime/pmtime.rc1
-rw-r--r--src/pmtime/pmtime.sh.in2
-rw-r--r--src/pmtime/pmtimearch.cpp704
-rw-r--r--src/pmtime/pmtimearch.h101
-rw-r--r--src/pmtime/pmtimearch.ui1262
-rw-r--r--src/pmtime/pmtimelive.cpp324
-rw-r--r--src/pmtime/pmtimelive.h72
-rw-r--r--src/pmtime/pmtimelive.ui824
-rw-r--r--src/pmtime/seealsodialog.cpp24
-rw-r--r--src/pmtime/seealsodialog.h30
-rw-r--r--src/pmtime/seealsodialog.ui235
-rw-r--r--src/pmtime/showboundsdialog.cpp237
-rw-r--r--src/pmtime/showboundsdialog.h58
-rw-r--r--src/pmtime/showboundsdialog.ui303
-rw-r--r--src/pmtime/timelord.cpp395
-rw-r--r--src/pmtime/timelord.h118
-rw-r--r--src/pmtime/timezone.h52
30 files changed, 5676 insertions, 0 deletions
diff --git a/src/pmtime/GNUmakefile b/src/pmtime/GNUmakefile
new file mode 100644
index 0000000..e35c1a6
--- /dev/null
+++ b/src/pmtime/GNUmakefile
@@ -0,0 +1,71 @@
+TOPDIR = ../..
+COMMAND = pmtime
+PROJECT = $(COMMAND).pro
+include $(TOPDIR)/src/include/builddefs
+
+WRAPPER = $(COMMAND).sh
+QRCFILE = $(COMMAND).qrc
+RCFILE = $(COMMAND).rc
+ICOFILE = $(COMMAND).ico
+ICNFILE = $(COMMAND).icns
+XMLFILE = $(COMMAND).info
+UIFILES = $(shell echo *.ui)
+HEADERS = aboutdialog.h console.h pmtime.h pmtimearch.h pmtimelive.h \
+ seealsodialog.h showboundsdialog.h timelord.h timezone.h
+SOURCES = aboutdialog.cpp console.cpp pmtime.cpp pmtimearch.cpp pmtimelive.cpp \
+ seealsodialog.cpp showboundsdialog.cpp timelord.cpp main.cpp
+LSRCFILES = $(PROJECT) $(QRCFILE) $(RCFILE) $(UIFILES) $(HEADERS) \
+ $(SOURCES) $(WRAPPER).in $(XMLFILE).in
+LDIRT = $(COMMAND) $(WRAPPER) $(XMLFILE) images
+
+default: build-me
+
+include $(BUILDRULES)
+
+ifeq "$(ENABLE_QT)" "true"
+build-me: images wrappers
+ $(QTMAKE)
+ $(LNMAKE)
+
+ifeq ($(WINDOW),mac)
+PKG_MAC_DIR = /Library/PCP/$(COMMAND).app/Contents
+wrappers: $(WRAPPER) $(XMLFILE)
+else
+wrappers:
+endif
+
+$(WRAPPER): $(WRAPPER).in
+ $(SED) -e '/\# .*/b' -e 's;PKG_MAC_DIR;$(PKG_MAC_DIR);g' < $< > $@
+$(XMLFILE): $(XMLFILE).in
+ $(SED) -e 's;PACKAGE_VERSION;$(PACKAGE_VERSION);g' < $< > $@
+
+install: default
+ifneq ($(WINDOW),mac)
+ $(INSTALL) -m 755 $(BINARY) $(PCP_BIN_DIR)/$(COMMAND)
+else
+ $(INSTALL) -m 755 $(WRAPPER) $(PCP_BIN_DIR)/$(COMMAND)
+ $(call INSTALL_DIRECTORY_HIERARCHY,$(PKG_MAC_DIR),/Library)
+ $(INSTALL) -m 644 $(XMLFILE) $(PKG_MAC_DIR)/Info.plist
+ $(INSTALL) -m 644 $(MACBUILD)/PkgInfo $(PKG_MAC_DIR)/PkgInfo
+ $(INSTALL) -m 755 -d $(PKG_MAC_DIR)/MacOS
+ $(call INSTALL_QT_FRAMEWORKS,$(BINARY))
+ $(INSTALL) -m 755 $(BINARY) $(PKG_MAC_DIR)/MacOS/$(COMMAND)
+ rm $(BINARY)
+ $(INSTALL) -m 755 -d $(PKG_MAC_DIR)/Resources
+ $(INSTALL) -m 644 $(ICNFILE) $(PKG_MAC_DIR)/Resources/$(ICNFILE)
+ $(call INSTALL_QT_RESOURCES,$(PKG_MAC_DIR)/Resources)
+endif
+else
+build-me:
+install:
+endif
+
+default_pcp: default
+
+install_pcp: install
+
+images: $(ICNFILE)
+ $(LN_S) $(TOPDIR)/images images
+
+$(ICNFILE):
+ $(LN_S) $(TOPDIR)/images/$(ICNFILE) $(ICNFILE)
diff --git a/src/pmtime/aboutdialog.cpp b/src/pmtime/aboutdialog.cpp
new file mode 100644
index 0000000..37de391
--- /dev/null
+++ b/src/pmtime/aboutdialog.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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 "aboutdialog.h"
+#include <pcp/pmapi.h>
+
+AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent)
+{
+ setupUi(this);
+ QRegExp rx("\\b(VERSION)\\b");
+ QString version = versionTextLabel->text();
+ version.replace(rx, pmGetConfig("PCP_VERSION"));
+ versionTextLabel->setText(version);
+}
+
+void AboutDialog::aboutOKButton_clicked()
+{
+ done(0);
+}
diff --git a/src/pmtime/aboutdialog.h b/src/pmtime/aboutdialog.h
new file mode 100644
index 0000000..17ca543
--- /dev/null
+++ b/src/pmtime/aboutdialog.h
@@ -0,0 +1,30 @@
+/*
+ * 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 ABOUTDIALOG_H
+#define ABOUTDIALOG_H
+
+#include "ui_aboutdialog.h"
+
+class AboutDialog : public QDialog, public Ui::AboutDialog
+{
+ Q_OBJECT
+
+public:
+ AboutDialog(QWidget* parent);
+
+public slots:
+ virtual void aboutOKButton_clicked();
+};
+
+#endif // ABOUTDIALOG_H
diff --git a/src/pmtime/aboutdialog.ui b/src/pmtime/aboutdialog.ui
new file mode 100644
index 0000000..9b10993
--- /dev/null
+++ b/src/pmtime/aboutdialog.ui
@@ -0,0 +1,229 @@
+<ui version="4.0" >
+ <class>AboutDialog</class>
+ <widget class="QDialog" name="AboutDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>330</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>330</width>
+ <height>240</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>330</width>
+ <height>260</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>About</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="pmtime.qrc" >:/images/pmtime.png</iconset>
+ </property>
+ <property name="modal" >
+ <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>
+ <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="QLabel" name="aboutPixmapLabel" >
+ <property name="pixmap" >
+ <pixmap resource="pmtime.qrc" >:/images/pmtime.png</pixmap>
+ </property>
+ <property name="scaledContents" >
+ <bool>false</bool>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="versionTextLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>&lt;b>&lt;i>pmtime&lt;/i>&lt;/b>&lt;br>
+&lt;b>&lt;i>Version VERSION&lt;/i>&lt;/b></string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="authorsTextLabel" >
+ <property name="midLineWidth" >
+ <number>0</number>
+ </property>
+ <property name="text" >
+ <string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
+p, li { white-space: pre-wrap; }
+&lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+&lt;p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright 2012, Red Hat.&lt;br />Copyright 2012, Nathan Scott.&lt;br />Copyright 2006, Ken McDonell.&lt;br />Copyright 2006-2010, Aconex.&lt;br />All rights reserved.&lt;br />&lt;span style=" font-style:italic;">&lt;br />This program is licensed under the&lt;br />GNU General Public License.&lt;br />&lt;/span>&lt;/p>&lt;/body>&lt;/html></string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </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="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="aboutOKButton" >
+ <property name="focusPolicy" >
+ <enum>Qt::TabFocus</enum>
+ </property>
+ <property name="text" >
+ <string>OK</string>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="pmtime.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>aboutOKButton</sender>
+ <signal>clicked()</signal>
+ <receiver>AboutDialog</receiver>
+ <slot>aboutOKButton_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/pmtime/console.cpp b/src/pmtime/console.cpp
new file mode 100644
index 0000000..cb346b9
--- /dev/null
+++ b/src/pmtime/console.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+#include "console.h"
+#include "pmtime.h"
+#include <stdarg.h>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+
+Console *console;
+
+Console::Console() : QDialog()
+{
+ my.level = 0;
+ if (pmDebug & DBG_TRACE_APPL0)
+ my.level |= PmTime::DebugApp; // pmtime apps internals
+ if (pmDebug & DBG_TRACE_APPL1)
+ my.level |= PmTime::DebugProtocol; // trace pmtime protocol
+ setupUi(this);
+}
+
+void Console::post(const char *fmt, ...)
+{
+ static char buffer[4096];
+ va_list ap;
+
+ if (!(my.level & PmTime::DebugApp))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ fputs(buffer, stderr);
+ fputc('\n', stderr);
+ text->append(QString(buffer));
+}
+
+void Console::post(int level, const char *fmt, ...)
+{
+ static char buffer[4096];
+ va_list ap;
+
+ if (!(my.level & level))
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ fputs(buffer, stderr);
+ fputc('\n', stderr);
+ text->append(QString(buffer));
+}
diff --git a/src/pmtime/console.h b/src/pmtime/console.h
new file mode 100644
index 0000000..7776616
--- /dev/null
+++ b/src/pmtime/console.h
@@ -0,0 +1,37 @@
+/*
+ * 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 CONSOLE_H
+#define CONSOLE_H
+
+#include "ui_console.h"
+
+class Console : public QDialog, public Ui::Console
+{
+ Q_OBJECT
+
+public:
+ Console();
+ virtual void post(const char * p, ...);
+ virtual void post(int level, const char * p, ...);
+
+private:
+ struct {
+ int level;
+ } my;
+};
+
+extern Console *console;
+
+#endif // CONSOLE_H
diff --git a/src/pmtime/console.ui b/src/pmtime/console.ui
new file mode 100644
index 0000000..a3ea80f
--- /dev/null
+++ b/src/pmtime/console.ui
@@ -0,0 +1,139 @@
+<ui version="4.0" >
+ <class>Console</class>
+ <widget class="QDialog" name="Console" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>493</width>
+ <height>326</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>pmtime Console</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="pmtime.qrc" >:/images/pmtime.png</iconset>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QTextEdit" name="text" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="autoFormatting" >
+ <set>QTextEdit::AutoNone</set>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonHide" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>85</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>85</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>&amp;Hide</string>
+ </property>
+ <property name="shortcut" >
+ <string>Alt+H</string>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <resources>
+ <include location="pmtime.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonHide</sender>
+ <signal>clicked()</signal>
+ <receiver>Console</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/pmtime/main.cpp b/src/pmtime/main.cpp
new file mode 100644
index 0000000..3e85e63
--- /dev/null
+++ b/src/pmtime/main.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+#include <QtGui/QApplication>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+#include "timelord.h"
+#include "pmtime.h"
+
+static pmOptions opts;
+static pmLongOptions longopts[] = {
+ PMAPI_OPTIONS_HEADER("Options"),
+ PMOPT_GUIPORT,
+ PMOPT_VERSION,
+ PMOPT_HELP,
+ PMAPI_OPTIONS_END
+};
+
+static void setupEnvironment(void)
+{
+ char *value;
+ QString confirm = pmGetConfig("PCP_BIN_DIR");
+ confirm.prepend("PCP_XCONFIRM_PROG=");
+ confirm.append(QChar(__pmPathSeparator()));
+ confirm.append("pmquery");
+ if ((value = strdup((const char *)confirm.toAscii())) != NULL)
+ putenv(value);
+ if (getenv("PCP_STDERR") == NULL && // do not overwrite, for QA
+ ((value = strdup("PCP_STDERR=DISPLAY")) != NULL))
+ putenv(value);
+
+ QCoreApplication::setOrganizationName("PCP");
+ QCoreApplication::setApplicationName("pmtime");
+}
+
+int main(int argc, char **argv)
+{
+ int autoport = 0;
+
+ QApplication a(argc, argv);
+ setupEnvironment();
+
+ opts.short_options = "D:p:V?";
+ opts.long_options = longopts;
+ pmGetOptions(argc, argv, &opts);
+ if (opts.errors || opts.optind != argc) {
+ pmUsageMessage(&opts);
+ exit(1);
+ }
+
+ if (!opts.guiport) {
+ char *endnum, *envstr;
+
+ autoport = 1;
+ if ((envstr = getenv("PMTIME_PORT")) == NULL) {
+ opts.guiport = PmTime::BasePort;
+ } else {
+ opts.guiport = strtol(envstr, &endnum, 0);
+ if (*endnum != '\0' || opts.guiport < 0) {
+ pmprintf(
+ "%s: PMTIME_PORT must be a numeric port number (not %s)\n",
+ pmProgname, envstr);
+ pmflush();
+ exit(1);
+ }
+ }
+ }
+
+ console = new Console;
+ TimeLord tl(&a);
+ do {
+ if (tl.listen(QHostAddress::LocalHost, opts.guiport))
+ break;
+ opts.guiport++;
+ } while (autoport && (opts.guiport >= 0));
+
+ if (!opts.guiport || tl.isListening() == false) {
+ if (!autoport)
+ pmprintf("%s: cannot find an available port\n", pmProgname);
+ else
+ pmprintf("%s: cannot connect to requested port (%d)\n",
+ pmProgname, opts.guiport);
+ pmflush();
+ exit(1);
+ } else if (autoport) { /* write to stdout for client */
+ char name[32];
+ int c = snprintf(name, sizeof(name), "port=%u\n", opts.guiport);
+ if (write(fileno(stdout), name, c + 1) < 0) {
+ if (errno != EPIPE) {
+ pmprintf("%s: cannot write port for client: %s\n",
+ pmProgname, strerror(errno));
+ pmflush();
+ }
+ exit(1);
+ }
+ }
+
+ PmTimeLive hc;
+ PmTimeArch ac;
+ tl.setContext(&hc, &ac);
+
+ hc.init();
+ if (!pmDebug) hc.disableConsole();
+ else hc.popup(1);
+
+ ac.init();
+ if (!pmDebug) ac.disableConsole();
+ else ac.popup(1);
+
+ a.exec();
+ return 0;
+}
diff --git a/src/pmtime/pmtime.cpp b/src/pmtime/pmtime.cpp
new file mode 100644
index 0000000..3c586f4
--- /dev/null
+++ b/src/pmtime/pmtime.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 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 "pmtime.h"
+#include <QtCore/QUrl>
+#include <QtCore/QLibraryInfo>
+#include <QtGui/QDesktopServices>
+#include <QtGui/QWhatsThis>
+#include <QtGui/QMessageBox>
+#include <QtGui/QCloseEvent>
+#include "console.h"
+#include "aboutdialog.h"
+#include "seealsodialog.h"
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+
+PmTime::PmTime() : QMainWindow(NULL)
+{
+}
+
+void PmTime::helpAbout()
+{
+ AboutDialog about(this);
+ about.exec();
+}
+
+void PmTime::helpAboutQt()
+{
+ QApplication::aboutQt();
+}
+
+void PmTime::helpSeeAlso()
+{
+ SeeAlsoDialog about(this);
+ about.exec();
+}
+
+void PmTime::whatsThis()
+{
+ QWhatsThis::enterWhatsThisMode();
+}
+
+void PmTime::helpManual()
+{
+ bool ok;
+ QString documents("file://");
+ QString separator = QString(__pmPathSeparator());
+ documents.append(pmGetConfig("PCP_HTML_DIR"));
+ documents.append(separator).append("timecontrol.html");
+ ok = QDesktopServices::openUrl(QUrl(documents, QUrl::TolerantMode));
+ if (!ok) {
+ documents.prepend("Failed to open:\n");
+ QMessageBox::warning(this, pmProgname, documents);
+ }
+}
+
+void PmTime::hideWindow()
+{
+ if (isVisible())
+ hide();
+ else {
+ show();
+ raise();
+ }
+}
+
+void PmTime::popup(bool hello_popetts)
+{
+ if (!hello_popetts)
+ hide();
+ else {
+ show();
+ raise();
+ }
+}
+
+void PmTime::closeEvent(QCloseEvent *ce)
+{
+ hide();
+ ce->ignore();
+}
+
+void PmTime::showConsole()
+{
+ console->show();
+}
diff --git a/src/pmtime/pmtime.h b/src/pmtime/pmtime.h
new file mode 100644
index 0000000..01faee7
--- /dev/null
+++ b/src/pmtime/pmtime.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Red Hat.
+ * Copyright (c) 2006-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 PMTIME_H
+#define PMTIME_H
+
+#include <QtGui/QMainWindow>
+#include <qmc_time.h>
+
+class PmTime : public QMainWindow, public QmcTime
+{
+ Q_OBJECT
+
+public:
+ typedef enum {
+ DebugApp = 0x1,
+ DebugProtocol = 0x2,
+ } DebugOptions;
+
+public:
+ PmTime();
+ virtual void popup(bool hello_popetts);
+
+public slots:
+ virtual void helpManual();
+ virtual void helpAbout();
+ virtual void helpAboutQt();
+ virtual void helpSeeAlso();
+ virtual void whatsThis();
+ virtual void hideWindow();
+ virtual void showConsole();
+
+protected:
+ virtual void closeEvent(QCloseEvent * ce);
+};
+
+#endif // PMTIME_H
diff --git a/src/pmtime/pmtime.info.in b/src/pmtime/pmtime.info.in
new file mode 100644
index 0000000..7a0842f
--- /dev/null
+++ b/src/pmtime/pmtime.info.in
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleIconFile</key>
+ <string>pmtime.icns</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleGetInfoString</key>
+ <string>PACKAGE_VERSION</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleExecutable</key>
+ <string>pmtime</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.aconex.pmtime</string>
+</dict>
+</plist>
diff --git a/src/pmtime/pmtime.pro b/src/pmtime/pmtime.pro
new file mode 100644
index 0000000..ad3e193
--- /dev/null
+++ b/src/pmtime/pmtime.pro
@@ -0,0 +1,24 @@
+TEMPLATE = app
+LANGUAGE = C++
+HEADERS = console.h pmtime.h pmtimearch.h pmtimelive.h \
+ aboutdialog.h seealsodialog.h showboundsdialog.h \
+ timelord.h timezone.h
+SOURCES = console.cpp pmtime.cpp pmtimearch.cpp pmtimelive.cpp \
+ aboutdialog.cpp seealsodialog.cpp showboundsdialog.cpp \
+ timelord.cpp main.cpp
+FORMS = aboutdialog.ui console.ui pmtimelive.ui pmtimearch.ui \
+ seealsodialog.ui showboundsdialog.ui
+ICON = pmtime.icns
+RC_FILE = pmtime.rc
+RESOURCES = pmtime.qrc
+CONFIG += qt warn_on
+INCLUDEPATH += ../include ../libpcp_qwt/src ../libpcp_qmc/src
+release:DESTDIR = build/debug
+debug:DESTDIR = build/release
+LIBS += -L../libpcp/src
+LIBS += -L../libpcp_qwt/src -L../libpcp_qwt/src/$$DESTDIR
+LIBS += -L../libpcp_qmc/src -L../libpcp_qmc/src/$$DESTDIR
+LIBS += -lpcp_qwt -lpcp_qmc -lpcp
+win32:LIBS += -lwsock32
+QT += network
+QMAKE_INFO_PLIST = pmtime.info
diff --git a/src/pmtime/pmtime.qrc b/src/pmtime/pmtime.qrc
new file mode 100644
index 0000000..be262b0
--- /dev/null
+++ b/src/pmtime/pmtime.qrc
@@ -0,0 +1,24 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>images/play_off.png</file>
+ <file>images/play_on.png</file>
+ <file>images/fastfwd_off.png</file>
+ <file>images/fastfwd_on.png</file>
+ <file>images/fastback_off.png</file>
+ <file>images/fastback_on.png</file>
+ <file>images/back_off.png</file>
+ <file>images/back_on.png</file>
+ <file>images/stepfwd_off.png</file>
+ <file>images/stepfwd_on.png</file>
+ <file>images/stepback_off.png</file>
+ <file>images/stepback_on.png</file>
+ <file>images/stop_off.png</file>
+ <file>images/stop_on.png</file>
+ <file>images/whatsthis.png</file>
+ <file>images/edit-clear.png</file>
+ <file>images/internet-web-browser.png</file>
+ <file>images/pmtime.png</file>
+ <file>images/aboutpmtime.png</file>
+ <file>images/aboutpcp.png</file>
+</qresource>
+</RCC>
diff --git a/src/pmtime/pmtime.rc b/src/pmtime/pmtime.rc
new file mode 100644
index 0000000..61dd59a
--- /dev/null
+++ b/src/pmtime/pmtime.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "images/pmtime.ico"
diff --git a/src/pmtime/pmtime.sh.in b/src/pmtime/pmtime.sh.in
new file mode 100644
index 0000000..350504a
--- /dev/null
+++ b/src/pmtime/pmtime.sh.in
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec PKG_MAC_DIR/MacOS/pmtime "$@"
diff --git a/src/pmtime/pmtimearch.cpp b/src/pmtime/pmtimearch.cpp
new file mode 100644
index 0000000..cb14f03
--- /dev/null
+++ b/src/pmtime/pmtimearch.cpp
@@ -0,0 +1,704 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+#include "pmtimearch.h"
+
+#include <QtCore/QTimer>
+#include <QtGui/QValidator>
+#include <QtGui/QMessageBox>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+#include "aboutdialog.h"
+#include "seealsodialog.h"
+
+PmTimeArch::PmTimeArch() : PmTime()
+{
+ setupUi(this);
+#ifdef Q_OS_MAC // fixup after relocation of the MenuBar by Qt
+ QSize size = QSize(width(), height() - MenuBar->height());
+ setMinimumSize(size);
+ setMaximumSize(size);
+#endif
+}
+
+typedef struct {
+ PmTime::State state;
+ PmTime::Mode mode;
+ QIcon *back;
+ QIcon *stop;
+ QIcon *play;
+} IconStateMap;
+
+static void setup(IconStateMap *map, PmTime::State state, PmTime::Mode mode,
+ QIcon *back, QIcon *stop, QIcon *play)
+{
+ map->state = state;
+ map->mode = mode;
+ map->back = back;
+ map->stop = stop;
+ map->play = play;
+}
+
+void PmTimeArch::setControl(PmTime::State state, PmTime::Mode mode)
+{
+ static IconStateMap maps[3 * 3];
+ static int nmaps;
+
+ if (!nmaps) {
+ nmaps = sizeof(maps) / sizeof(maps[0]);
+ setup(&maps[0], PmTime::StoppedState, PmTime::NormalMode,
+ PmTime::icon(PmTime::BackwardOff),
+ PmTime::icon(PmTime::StoppedOn),
+ PmTime::icon(PmTime::ForwardOff));
+ setup(&maps[1], PmTime::ForwardState, PmTime::NormalMode,
+ PmTime::icon(PmTime::BackwardOff),
+ PmTime::icon(PmTime::StoppedOff),
+ PmTime::icon(PmTime::ForwardOn));
+ setup(&maps[2], PmTime::BackwardState, PmTime::NormalMode,
+ PmTime::icon(PmTime::BackwardOn),
+ PmTime::icon(PmTime::StoppedOff),
+ PmTime::icon(PmTime::ForwardOff));
+ setup(&maps[3], PmTime::StoppedState, PmTime::FastMode,
+ PmTime::icon(PmTime::FastBackwardOff),
+ PmTime::icon(PmTime::StoppedOn),
+ PmTime::icon(PmTime::FastForwardOff));
+ setup(&maps[4], PmTime::ForwardState, PmTime::FastMode,
+ PmTime::icon(PmTime::FastBackwardOff),
+ PmTime::icon(PmTime::StoppedOff),
+ PmTime::icon(PmTime::FastForwardOn));
+ setup(&maps[5], PmTime::BackwardState, PmTime::FastMode,
+ PmTime::icon(PmTime::FastBackwardOn),
+ PmTime::icon(PmTime::StoppedOff),
+ PmTime::icon(PmTime::FastForwardOff));
+ setup(&maps[6], PmTime::StoppedState, PmTime::StepMode,
+ PmTime::icon(PmTime::StepBackwardOff),
+ PmTime::icon(PmTime::StoppedOn),
+ PmTime::icon(PmTime::StepForwardOff));
+ setup(&maps[7], PmTime::ForwardState, PmTime::StepMode,
+ PmTime::icon(PmTime::StepBackwardOff),
+ PmTime::icon(PmTime::StoppedOff),
+ PmTime::icon(PmTime::StepForwardOn));
+ setup(&maps[8], PmTime::BackwardState, PmTime::StepMode,
+ PmTime::icon(PmTime::StepBackwardOn),
+ PmTime::icon(PmTime::StoppedOff),
+ PmTime::icon(PmTime::StepForwardOff));
+ }
+
+ if (my.pmtime.state != state || my.pmtime.mode != mode) {
+ for (int i = 0; i < nmaps; i++) {
+ if (maps[i].state == state && maps[i].mode == mode) {
+ buttonBack->setIcon(*maps[i].back);
+ buttonStop->setIcon(*maps[i].stop);
+ buttonPlay->setIcon(*maps[i].play);
+ break;
+ }
+ }
+ my.pmtime.state = state;
+ my.pmtime.mode = mode;
+ if (my.pmtime.mode == PmTime::NormalMode) {
+ buttonSpeed->setEnabled(true);
+ textLabelSpeed->setEnabled(true);
+ lineEditSpeed->setEnabled(true);
+ wheelSpeed->setEnabled(true);
+ }
+ else {
+ buttonSpeed->setEnabled(false);
+ textLabelSpeed->setEnabled(false);
+ lineEditSpeed->setEnabled(false);
+ wheelSpeed->setEnabled(false);
+ }
+ }
+}
+
+void PmTimeArch::init()
+{
+ static char UTC[] = "UTC\0Universal Coordinated Time";
+
+ console->post(PmTime::DebugApp, "Starting Archive Time Control...");
+
+ my.units = PmTime::Seconds;
+ my.first = true;
+ my.tzActions = NULL;
+
+ memset(&my.absoluteStart, 0, sizeof(struct timeval));
+ memset(&my.absoluteEnd, 0, sizeof(struct timeval));
+ memset(&my.pmtime, 0, sizeof(my.pmtime));
+ my.pmtime.source = PmTime::ArchiveSource;
+ my.pmtime.delta.tv_sec = PmTime::DefaultDelta;
+
+ my.showMilliseconds = false;
+ optionsDetailShow_MillisecondsAction->setChecked(my.showMilliseconds);
+ my.showYear = false;
+ optionsDetailShow_YearAction->setChecked(my.showYear);
+
+ my.speed = 1.0;
+ my.timer = new QTimer(this);
+ my.timer->setInterval(timerInterval());
+ my.timer->stop();
+ connect(my.timer, SIGNAL(timeout()), SLOT(timerTick()));
+
+ addTimezone(UTC);
+ displayDeltaText();
+ setControl(PmTime::StoppedState, PmTime::NormalMode);
+
+ double delta = PmTime::secondsFromTimeval(&my.pmtime.delta);
+ changeSpeed(PmTime::defaultSpeed(delta));
+ wheelSpeed->setRange(
+ PmTime::minimumSpeed(delta), PmTime::maximumSpeed(delta), 0.1);
+ wheelSpeed->setValue(PmTime::defaultSpeed(delta));
+ lineEditDelta->setAlignment(Qt::AlignRight);
+ lineEditDelta->setValidator(
+ new QDoubleValidator(0.001, INT_MAX, 3, lineEditDelta));
+ lineEditSpeed->setAlignment(Qt::AlignRight);
+ lineEditSpeed->setValidator(
+ new QDoubleValidator(0.001, INT_MAX, 1, lineEditSpeed));
+
+ my.bounds = new ShowBounds(this);
+ my.bounds->init(&my.absoluteStart, &my.pmtime.start,
+ &my.absoluteEnd, &my.pmtime.end);
+ connect(my.bounds, SIGNAL(boundsChanged()), this, SLOT(doneBounds()));
+
+ console->post("PmTimeArch::init absS=%p S=%p absE=%p E=%p\n",
+ &my.absoluteStart, &my.pmtime.start,
+ &my.absoluteEnd, &my.pmtime.end);
+}
+
+void PmTimeArch::quit()
+{
+ console->post("arch quit!\n");
+}
+
+int PmTimeArch::timerInterval()
+{
+ return (int)(((my.pmtime.delta.tv_sec * 1000) +
+ (my.pmtime.delta.tv_usec / 1000)) / my.speed);
+}
+
+void PmTimeArch::play_clicked()
+{
+ if (lineEditCtime->isModified())
+ lineEditCtime_validate();
+ if (lineEditDelta->isModified())
+ lineEditDelta_validate();
+ if (my.pmtime.state != PmTime::ForwardState ||
+ my.pmtime.mode == PmTime::StepMode)
+ play();
+}
+
+void PmTimeArch::play()
+{
+ if (addDelta()) {
+ setControl(PmTime::ForwardState, my.pmtime.mode);
+ updateTime();
+ if (my.pmtime.mode == PmTime::NormalMode)
+ my.timer->start(timerInterval());
+ else if (my.pmtime.mode == PmTime::FastMode)
+ my.timer->start(PmTime::FastModeDelay);
+ console->post(PmTime::DebugApp, "PmTimeArch::play moved time forward");
+ } else {
+ console->post(PmTime::DebugApp, "PmTimeArch::play reached archive end");
+ emit boundsPulse(&my.pmtime);
+ stop();
+ }
+}
+
+void PmTimeArch::back_clicked()
+{
+ if (lineEditCtime->isModified())
+ lineEditCtime_validate();
+ if (lineEditDelta->isModified())
+ lineEditDelta_validate();
+ if (my.pmtime.state != PmTime::BackwardState ||
+ my.pmtime.mode == PmTime::StepMode)
+ back();
+}
+
+void PmTimeArch::back()
+{
+ if (subDelta()) {
+ setControl(PmTime::BackwardState, my.pmtime.mode);
+ updateTime();
+ if (my.pmtime.mode == PmTime::NormalMode)
+ my.timer->start(timerInterval());
+ else if (my.pmtime.mode == PmTime::FastMode)
+ my.timer->start(PmTime::FastModeDelay);
+ console->post(PmTime::DebugApp, "PmTimeArch::back moved time backward");
+ } else {
+ console->post(PmTime::DebugApp, "PmTimeArch::back reached archive end");
+ emit boundsPulse(&my.pmtime);
+ stop();
+ }
+}
+
+void PmTimeArch::stop_clicked()
+{
+ if (my.pmtime.state != PmTime::StoppedState)
+ stop();
+}
+
+void PmTimeArch::stop()
+{
+ setControl(PmTime::StoppedState, my.pmtime.mode);
+ my.timer->stop();
+ emit vcrModePulse(&my.pmtime, 0);
+ console->post(PmTime::DebugApp, "PmTimeArch::stop stopped time");
+}
+
+void PmTimeArch::timerTick()
+{
+ if (my.pmtime.state == PmTime::ForwardState)
+ play();
+ else if (my.pmtime.state == PmTime::BackwardState)
+ back();
+ else
+ console->post(PmTime::DebugApp, "PmTimeArch::timerTick: dodgey state?");
+}
+
+int PmTimeArch::addDelta()
+{
+ struct timeval current = my.pmtime.position;
+
+#if DESPERATE
+ console->post(PmTime::DebugProtocol,
+ "now=%u.%u end=%u.%u start=%u.%u delta=%u.%u speed=%.3e",
+ my.pmtime.position.tv_sec, my.pmtime.position.tv_usec,
+ my.pmtime.end.tv_sec, my.pmtime.end.tv_usec, my.pmtime.start.tv_sec,
+ my.pmtime.start.tv_usec, my.pmtime.delta.tv_sec,
+ my.pmtime.delta.tv_usec, speed);
+#endif
+
+ PmTime::timevalAdd(&current, &my.pmtime.delta);
+ if (PmTime::timevalCompare(&current, &my.pmtime.end) > 0 ||
+ PmTime::timevalCompare(&current, &my.pmtime.start) < 0)
+ return 0;
+ my.pmtime.position = current;
+ return 1;
+}
+
+int PmTimeArch::subDelta()
+{
+ struct timeval current = my.pmtime.position;
+
+ PmTime::timevalSub(&current, &my.pmtime.delta);
+ if (PmTime::timevalCompare(&current, &my.pmtime.end) > 0 ||
+ PmTime::timevalCompare(&current, &my.pmtime.start) < 0)
+ return 0;
+ my.pmtime.position = current;
+ return 1;
+}
+
+void PmTimeArch::changeDelta(int value)
+{
+ my.units = (PmTime::DeltaUnits)value;
+ displayDeltaText();
+}
+
+void PmTimeArch::changeControl(int value)
+{
+ setControl(PmTime::StoppedState, (PmTime::Mode)value);
+}
+
+void PmTimeArch::updateTime()
+{
+ emit timePulse(&my.pmtime);
+ displayPositionText();
+ displayPositionSlide();
+}
+
+void PmTimeArch::displayDeltaText()
+{
+ QString text;
+ double delta = PmTime::secondsFromTimeval(&my.pmtime.delta);
+
+ delta = PmTime::secondsToUnits(delta, my.units);
+ if ((double)(int)delta == delta)
+ text.sprintf("%.2f", delta);
+ else
+ text.sprintf("%.6f", delta);
+ lineEditDelta->setText(text);
+}
+
+void PmTimeArch::displayPositionText()
+{
+ QString text;
+ char ctimebuf[32], msecbuf[5];
+
+ pmCtime(&my.pmtime.position.tv_sec, ctimebuf);
+ text = tr(ctimebuf);
+ if (my.showYear == false)
+ text.remove(19, 5);
+ if (my.showMilliseconds == true) {
+ sprintf(msecbuf, ".%03u", (uint)my.pmtime.position.tv_usec / 1000);
+ text.insert(19, msecbuf);
+ }
+ lineEditCtime->setText(text.simplified());
+}
+
+void PmTimeArch::displayPositionSlide(void)
+{
+ sliderPosition->setValue(PmTime::secondsFromTimeval(&my.pmtime.position));
+}
+
+void PmTimeArch::setPositionSlideRange(void)
+{
+ sliderPosition->setRange(PmTime::secondsFromTimeval(&my.pmtime.start),
+ PmTime::secondsFromTimeval(&my.pmtime.end));
+}
+
+void PmTimeArch::setPositionSlideDelta(void)
+{
+ sliderPosition->setStep(PmTime::secondsFromTimeval(&my.pmtime.delta));
+}
+
+void PmTimeArch::pressedPosition()
+{
+ emit vcrModePulse(&my.pmtime, 1);
+}
+
+void PmTimeArch::releasedPosition()
+{
+ emit vcrModePulse(&my.pmtime, 0);
+}
+
+void PmTimeArch::changedPosition(double value)
+{
+#if DESPERATE
+ console->post("PmTimeArch::changedPosition changing pos from %d.%d",
+ my.pmtime.position.tv_sec, my.pmtime.position.tv_usec);
+#endif
+
+ PmTime::secondsToTimeval(value, &my.pmtime.position);
+ displayPositionText();
+
+#if DESPERATE
+ console->post("PmTimeArch::changedPosition changed pos to %d.%d",
+ my.pmtime.position.tv_sec, my.pmtime.position.tv_usec);
+#endif
+}
+
+void PmTimeArch::clickShowMsec()
+{
+ if (my.showMilliseconds == true)
+ my.showMilliseconds = false;
+ else
+ my.showMilliseconds = true;
+ optionsDetailShow_MillisecondsAction->setChecked(my.showMilliseconds);
+ displayPositionText();
+}
+
+void PmTimeArch::clickShowYear()
+{
+ if (my.showYear == true)
+ my.showYear = false;
+ else
+ my.showYear = true;
+ optionsDetailShow_YearAction->setChecked(my.showYear);
+ displayPositionText();
+}
+
+void PmTimeArch::resetSpeed()
+{
+ double delta = PmTime::secondsFromTimeval(&my.pmtime.delta);
+ changeSpeed(PmTime::defaultSpeed(delta));
+}
+
+void PmTimeArch::changeSpeed(double value)
+{
+ QString text;
+ int reset = my.timer->isActive();
+ double upper, lower, delta = PmTime::secondsFromTimeval(&my.pmtime.delta);
+
+ my.timer->stop();
+
+ upper = PmTime::maximumSpeed(delta);
+ lower = PmTime::minimumSpeed(delta);
+ if (value > upper)
+ value = upper;
+ else if (value < lower)
+ value = lower;
+ text.sprintf("%.1f", value);
+ lineEditSpeed->setText(text);
+ if (wheelSpeed->value() != value)
+ wheelSpeed->setValue(value);
+
+ my.speed = value;
+ if (reset)
+ my.timer->start(timerInterval());
+
+ console->post("PmTimeArch::changeSpeed changed delta to %d.%d (%.2fs)",
+ my.pmtime.delta.tv_sec, my.pmtime.delta.tv_usec, value);
+}
+
+void PmTimeArch::showBounds()
+{
+ my.bounds->reset();
+ console->post("PmTimeArch::showBounds: absS=%p S=%p absE=%p E=%p\n",
+ &my.absoluteStart, &my.pmtime.start, &my.absoluteEnd, &my.pmtime.end);
+ my.bounds->show();
+}
+
+void PmTimeArch::doneBounds(void)
+{
+ int tellclients = 0;
+
+ console->post("PmTimeArch::doneBounds signal received\n");
+
+ my.bounds->flush();
+ if (PmTime::timevalCompare(&my.pmtime.position, &my.pmtime.start) < 0) {
+ my.pmtime.position = my.pmtime.start;
+ tellclients = 1;
+ }
+ if (PmTime::timevalCompare(&my.pmtime.position, &my.pmtime.end) > 0) {
+ my.pmtime.position = my.pmtime.end;
+ tellclients = 1;
+ }
+ sliderPosition->blockSignals(true);
+ setPositionSlideRange();
+ sliderPosition->blockSignals(false);
+ if (tellclients)
+ emit vcrModePulse(&my.pmtime, 0);
+}
+
+void PmTimeArch::disableConsole()
+{
+ optionsShowConsoleAction->setVisible(false);
+}
+
+void PmTimeArch::lineEditDelta_changed(const QString &)
+{
+ if (lineEditDelta->isModified())
+ stop_clicked();
+}
+
+void PmTimeArch::lineEditCtime_changed(const QString &)
+{
+ if (lineEditCtime->isModified())
+ stop_clicked();
+}
+
+void PmTimeArch::lineEditDelta_validate()
+{
+ double delta;
+ bool ok, reset = my.timer->isActive();
+
+ delta = lineEditDelta->text().toDouble(&ok);
+ if (!ok || delta <= 0) {
+ displayDeltaText(); // reset to previous, known-good delta
+ } else {
+ my.timer->stop();
+ delta = PmTime::unitsToSeconds(delta, my.units);
+ PmTime::secondsToTimeval(delta, &my.pmtime.delta);
+ emit vcrModePulse(&my.pmtime, 0);
+ if (reset)
+ my.timer->start(timerInterval());
+ }
+}
+
+void PmTimeArch::lineEditCtime_validate()
+{
+ struct timeval current;
+ QString input, error;
+ char *msg;
+
+ input = lineEditCtime->text().simplified();
+ if (input.length() == 0) {
+ error.sprintf("Position time has not been set.\n");
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ return;
+ }
+ if (input[0] != '@')
+ input.prepend("@");
+ if (__pmParseTime(input.toAscii(),
+ &my.pmtime.start, &my.pmtime.end, &current, &msg) < 0) {
+ error.sprintf("Invalid position date/time:\n\n%s\n", msg);
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ displayPositionText(); // reset to previous, known-good position
+ free(msg);
+ } else {
+ my.pmtime.position = current;
+ displayPositionText();
+ displayPositionSlide();
+ emit vcrModePulse(&my.pmtime, 0);
+ }
+}
+
+void PmTimeArch::lineEditSpeed_validate()
+{
+ double value, delta = PmTime::secondsFromTimeval(&my.pmtime.delta);
+ bool ok, reset = my.timer->isActive();
+
+ value = lineEditSpeed->text().toDouble(&ok);
+ if (!ok ||
+ value < PmTime::minimumSpeed(delta) ||
+ value > PmTime::maximumSpeed(delta)) {
+ wheelSpeed->setValue(my.speed); // reset to previous, known-good speed
+ } else {
+ my.speed = value;
+ wheelSpeed->setValue(my.speed);
+ if (reset) {
+ my.timer->stop();
+ my.timer->start(timerInterval());
+ }
+ }
+}
+
+void PmTimeArch::setTimezone(QAction *action)
+{
+ for (int i = 0; i < my.tzlist.size(); i++) {
+ TimeZone *tz = my.tzlist.at(i);
+ if (tz->action() == action) {
+ my.first = true; // resetting time completely
+ pmUseZone(tz->handle());
+ emit tzPulse(&my.pmtime, tz->tz(), strlen(tz->tz()) + 1,
+ tz->tzlabel(), strlen(tz->tzlabel()) + 1);
+ console->post("PmTimeArch::setTimezone sent TZ %s (%s) to clients",
+ tz->tz(), tz->tzlabel());
+ setTime(&my.pmtime, NULL); // re-display the time, no messages
+ break;
+ }
+ }
+}
+
+void PmTimeArch::addTimezone(const char *string)
+{
+ TimeZone *tmp, *tzp;
+ QAction *tzAction;
+ char *label, *tz;
+ int handle;
+
+ if ((handle = pmNewZone(string)) < 0)
+ return;
+
+ if ((tz = strdup(string)) == NULL)
+ return;
+
+ if ((label = strdup(string + strlen(string) + 1)) == NULL) {
+ free(tz);
+ return;
+ }
+
+ for (int i = 0; i < my.tzlist.size(); i++) {
+ tmp = my.tzlist.at(i);
+ if (strcmp(tmp->tzlabel(), label) == 0) {
+ free(label);
+ free(tz);
+ return;
+ }
+ }
+
+ tzAction = new QAction(this);
+ tzAction->setCheckable(true);
+ tzAction->setToolTip(tz);
+ tzAction->setText(label);
+
+ tzp = new TimeZone(tz, label, tzAction, handle);
+ my.tzlist.append(tzp);
+
+ if (!my.tzActions) {
+ my.tzActions = new QActionGroup(this);
+ connect(my.tzActions, SIGNAL(selected(QAction *)),
+ this, SLOT(setTimezone(QAction *)));
+ }
+ my.tzActions->addAction(tzAction);
+ optionsTimezoneAction->addActions(my.tzActions->actions());
+ console->post("PmTimeArch::addTimezone added tz=%s label=%s", tz, label);
+}
+
+void PmTimeArch::setTime(PmTime::Packet *k, char *tzdata)
+{
+#if DESPERATE
+ console->post(PmTime::DebugProtocol, "PmTimeArch::setTime START: "
+ "1st=%d now=%u.%u end=%u.%u start=%u.%u delta=%u.%u",
+ my.first, my.pmtime.position.tv_sec, my.pmtime.position.tv_usec,
+ my.pmtime.end.tv_sec, my.pmtime.end.tv_usec, my.pmtime.start.tv_sec,
+ my.pmtime.start.tv_usec, my.pmtime.delta.tv_sec,
+ my.pmtime.delta.tv_usec);
+#endif
+
+ if (my.first == true) {
+ my.first = false;
+ if (tzdata != NULL)
+ addTimezone(tzdata);
+ my.absoluteStart = my.pmtime.start = k->start;
+ my.absoluteEnd = my.pmtime.end = k->end;
+ my.pmtime.position = k->position;
+ my.pmtime.delta = k->delta;
+ sliderPosition->blockSignals(true);
+ setPositionSlideRange();
+ setPositionSlideDelta();
+ sliderPosition->blockSignals(false);
+ displayDeltaText();
+ displayPositionText();
+ displayPositionSlide();
+ my.bounds->reset();
+ double delta = PmTime::secondsFromTimeval(&k->delta);
+ changeSpeed(PmTime::defaultSpeed(delta));
+ } else {
+ addBound(k, tzdata);
+ }
+
+#if DESPERATE
+ console->post(PmTime::DebugProtocol, "PmTimeArch::setTime ENDED: "
+ "1st=%d now=%u.%u end=%u.%u start=%u.%u delta=%u.%u",
+ my.first, my.pmtime.position.tv_sec, my.pmtime.position.tv_usec,
+ my.pmtime.end.tv_sec, my.pmtime.end.tv_usec, my.pmtime.start.tv_sec,
+ my.pmtime.start.tv_usec, my.pmtime.delta.tv_sec,
+ my.pmtime.delta.tv_usec);
+#endif
+}
+
+void PmTimeArch::addBound(PmTime::Packet *k, char *tzdata)
+{
+ // Note: pmchart can start pmtime up without an archive
+ // so, we need to explicitly initialise some fields now
+ // that one might otherwise have expected to be setup.
+
+ bool needPulse = PmTime::timevalNonZero(&my.pmtime.position);
+
+ console->post(PmTime::DebugProtocol, "PmTimeArch::addBound START: "
+ "p?=%d now=%u.%u end=%u.%u start=%u.%u", needPulse,
+ my.pmtime.position.tv_sec, my.pmtime.position.tv_usec,
+ my.pmtime.end.tv_sec, my.pmtime.end.tv_usec,
+ my.pmtime.start.tv_sec, my.pmtime.start.tv_usec);
+
+ if (tzdata != NULL)
+ addTimezone(tzdata);
+
+ if (PmTime::timevalCompare(&k->start, &my.absoluteStart) < 0)
+ my.absoluteStart = my.pmtime.start = k->start;
+ if (PmTime::timevalCompare(&k->end, &my.absoluteEnd) > 0)
+ my.absoluteEnd = my.pmtime.end = k->end;
+ if (!needPulse) { // first-time archive initialisation
+ my.pmtime.position = k->position;
+ my.pmtime.start = k->start;
+ my.pmtime.end = k->end;
+ }
+
+ sliderPosition->blockSignals(true);
+ setPositionSlideRange();
+ sliderPosition->blockSignals(false);
+ displayPositionText();
+ displayPositionSlide();
+ my.bounds->reset();
+
+ if (needPulse)
+ emit vcrModePulse(&my.pmtime, 0);
+
+ console->post(PmTime::DebugProtocol, "PmTimeArch::addBound ENDED: "
+ "p?=%d now=%u.%u end=%u.%u start=%u.%u", needPulse,
+ my.pmtime.position.tv_sec, my.pmtime.position.tv_usec,
+ my.pmtime.end.tv_sec, my.pmtime.end.tv_usec,
+ my.pmtime.start.tv_sec, my.pmtime.start.tv_usec);
+}
diff --git a/src/pmtime/pmtimearch.h b/src/pmtime/pmtimearch.h
new file mode 100644
index 0000000..3c06043
--- /dev/null
+++ b/src/pmtime/pmtimearch.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, 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 PMTIMEARCH_H
+#define PMTIMEARCH_H
+
+#include "ui_pmtimearch.h"
+#include "pmtime.h"
+#include "console.h"
+#include "showboundsdialog.h"
+#include "timezone.h"
+
+class PmTimeArch : public PmTime, public Ui::PmTimeArch
+{
+ Q_OBJECT
+
+public:
+ PmTimeArch();
+
+ virtual void play();
+ virtual void back();
+ virtual void stop();
+ virtual int addDelta();
+ virtual int subDelta();
+ virtual int timerInterval();
+ virtual void displayDeltaText();
+ virtual void displayPositionText();
+ virtual void displayPositionSlide();
+ virtual void setPositionSlideRange();
+ virtual void setPositionSlideDelta();
+ virtual void addTimezone(const char *string);
+ virtual void setTime(PmTime::Packet *k, char *tzdata);
+ virtual void addBound(PmTime::Packet *k, char *tzdata);
+
+public slots:
+ virtual void setControl(PmTime::State newstate, PmTime::Mode newmode);
+ virtual void init();
+ virtual void quit();
+ virtual void play_clicked();
+ virtual void back_clicked();
+ virtual void stop_clicked();
+ virtual void timerTick();
+ virtual void changeDelta(int value);
+ virtual void disableConsole();
+ virtual void changeControl(int value);
+ virtual void updateTime();
+ virtual void pressedPosition();
+ virtual void releasedPosition();
+ virtual void changedPosition(double value);
+ virtual void clickShowMsec();
+ virtual void clickShowYear();
+ virtual void resetSpeed();
+ virtual void changeSpeed(double value);
+ virtual void showBounds();
+ virtual void doneBounds();
+ virtual void lineEditDelta_changed(const QString & s);
+ virtual void lineEditCtime_changed(const QString & s);
+ virtual void lineEditDelta_validate();
+ virtual void lineEditCtime_validate();
+ virtual void lineEditSpeed_validate();
+ virtual void setTimezone(QAction *action);
+
+signals:
+ void timePulse(PmTime::Packet *);
+ void boundsPulse(PmTime::Packet *);
+ void vcrModePulse(PmTime::Packet *, int);
+ void tzPulse(PmTime::Packet *, char *, int, char *, int);
+
+private:
+ struct {
+ PmTime::Packet pmtime;
+ PmTime::DeltaUnits units;
+ struct timeval absoluteStart;
+ struct timeval absoluteEnd;
+ double speed;
+
+ bool first;
+ bool showMilliseconds;
+ bool showYear;
+
+ QTimer *timer;
+ Console *console;
+ ShowBounds *bounds;
+ QActionGroup *tzActions;
+ QList<TimeZone*> tzlist;
+ } my;
+};
+
+#endif // PMTIMEARCH_H
diff --git a/src/pmtime/pmtimearch.ui b/src/pmtime/pmtimearch.ui
new file mode 100644
index 0000000..cddc526
--- /dev/null
+++ b/src/pmtime/pmtimearch.ui
@@ -0,0 +1,1262 @@
+<ui version="4.0" >
+ <class>PmTimeArch</class>
+ <widget class="QMainWindow" name="PmTimeArch" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>220</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>320</width>
+ <height>220</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>320</width>
+ <height>220</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>PCP Archive Time Control</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="pmtime.qrc" >:/images/pmtime.png</iconset>
+ </property>
+ <property name="windowIconText" >
+ <string/>
+ </property>
+ <property name="toolTip" >
+ <string/>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Archive Time Control&lt;/b>&lt;br>
+A time server, sending time related information (current time,
+metric value fetch interval, timezone) to one or more client
+programs (e.g. pmchart, pmval, etc).</string>
+ </property>
+ <widget class="QWidget" name="widget" >
+ <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>6</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="intervalLabel" >
+ <property name="toolTip" >
+ <string comment="Time interval between performance metric value samples" >Metric sampling interval</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Metric sampling interval&lt;/b>&lt;br>
+Numeric values entered into these fields will form the number of
+hours, minutes and/or seconds between PCP metric value
+samples in Time Control client programs (e.g. pmchart, pmval, etc).</string>
+ </property>
+ <property name="text" >
+ <string>Interval</string>
+ </property>
+ <property name="scaledContents" >
+ <bool>false</bool>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="positionLabel" >
+ <property name="whatsThis" >
+ <string>&lt;b>Time Position&lt;/b>&lt;br>
+This text field displays the current time position. This value is
+sent to clients (e.g. pmchart, pmval) of this Time Control
+program to synchronise them in terms of the progression of time
+and also with respect to any "play mode" changes requested.</string>
+ </property>
+ <property name="text" >
+ <string>Position</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </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="QLineEdit" name="lineEditDelta" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>95</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>95</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="toolTip" >
+ <string comment="Time interval between performance metric value samples" >Metric sampling interval</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Metric sampling interval&lt;/b>&lt;br>
+Numeric values entered into these fields will form the number of
+hours, minutes and/or seconds between PCP metric value
+samples in Time Control client programs (e.g. pmchart, pmval, etc).</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboBoxDelta" >
+ <property name="whatsThis" >
+ <string>&lt;b>Sampling interval units&lt;/b>&lt;br>
+Displays the units in which the sampling interval is entered.
+Metric values can be sampled in days, hours, minutes, seconds
+or milliseconds in Time Control client programs (e.g. pmchart,
+pmval, etc).</string>
+ </property>
+ <property name="currentIndex" >
+ <number>1</number>
+ </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>
+ <item>
+ <widget class="QLineEdit" name="lineEditCtime" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>226</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>226</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Time Position&lt;/b>&lt;br>
+This text field displays the current time position. This value is
+sent to clients (e.g. pmchart, pmval) of this Time Control
+program to synchronise them in terms of the progression of time
+and also with respect to any "play mode" changes requested.</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QwtSlider" name="sliderPosition" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>290</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>290</width>
+ <height>14</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Time Position&lt;/b>&lt;br>
+This slider modifies the current time position. This value is
+sent to clients (e.g. pmchart, pmval) of this Time Control
+program to synchronise them in terms of the progression of time
+and also with respect to any "play mode" changes requested.</string>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="backgroundStyle" >
+ <enum>QwtSlider::Groove</enum>
+ </property>
+ <property name="handleSize" >
+ <size>
+ <width>12</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="borderWidth" >
+ <number>2</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>8</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>4</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="textLabel3" >
+ <property name="text" >
+ <string>Archive Control</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboBoxSpeed" >
+ <property name="currentIndex" >
+ <number>1</number>
+ </property>
+ <item>
+ <property name="text" >
+ <string>Step</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Normal</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>Fast</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buttonBack" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>54</width>
+ <height>36</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Back/Step/Rewind&lt;/b>&lt;br>
+Pressing this button will cause time to decrease, as seen by the
+Time Control program and all of its clients (e.g. pmchart, pmval,
+etc). In Backward mode, time will decrease in decrements of the
+current Interval (subject to Speed setting). In Step mode, time
+will decrease one Interval and then wait. In Rewind mode, time
+will move backward at a very rapid rate in decrements of the current
+time Interval.</string>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>52</width>
+ <height>32</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buttonStop" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>54</width>
+ <height>36</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Stop&lt;/b>&lt;br>
+Pressing this button will stop the movement of time, as seen by
+the Time Control program and all of its clients (e.g. pmchart,
+pmval, etc). Unless stopped, time either advances/retreats in
+increments of the current Interval.</string>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>52</width>
+ <height>32</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buttonPlay" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>54</width>
+ <height>36</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Play/Step/FastFwd&lt;/b>&lt;br>
+Pressing this button will begin the advancement of time, as seen
+by the Time Control program and all of its clients (e.g. pmchart,
+pmval, etc). In Play mode, time will advance in increments of the
+current Interval (subject to Speed setting). In Step mode, time
+will advance one Interval and then wait. In Fast Forward mode, time
+will move forward at a very rapid rate in increments of the current
+time Interval.</string>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>52</width>
+ <height>32</height>
+ </size>
+ </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="textLabelSpeed" >
+ <property name="whatsThis" >
+ <string>&lt;b>Time Speed&lt;/b>&lt;br>
+The Speed at which Time clients are updated with respect to the current
+time Position can be modified here. This only affects normal play/back
+modes.</string>
+ </property>
+ <property name="text" >
+ <string>Speed</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditSpeed" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>45</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>45</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Time Speed&lt;/b>&lt;br>
+The Speed at which Time clients are updated with respect to the current
+time Position can be modified here. This only affects normal play/back
+modes.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buttonSpeed" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Speed Reset&lt;/b>&lt;br>
+The Speed at which Time clients are updated with respect to the current
+time Position can be reset (to one) here. This affects normal play/back
+modes only.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QwtWheel" name="wheelSpeed" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>155</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>155</width>
+ <height>16</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Speed Wheel&lt;/b>&lt;br>
+The Speed at which Time clients are updated with respect to the current
+time Position can be modified by rotating the wheel left (slower) and
+right (faster). This only affects normal play/back modes.</string>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="wheelBorderWidth" >
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="MenuBar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="File" >
+ <property name="title" >
+ <string>&amp;File</string>
+ </property>
+ <addaction name="fileHideAction" />
+ </widget>
+ <widget class="QMenu" name="Help" >
+ <property name="title" >
+ <string>&amp;Help</string>
+ </property>
+ <addaction name="helpManualAction" />
+ <addaction name="separator" />
+ <addaction name="helpAboutAction" />
+ <addaction name="helpAboutQtAction" />
+ <addaction name="helpSeeAlsoAction" />
+ <addaction name="separator" />
+ <addaction name="helpWhats_ThisAction" />
+ </widget>
+ <widget class="QMenu" name="Options" >
+ <property name="title" >
+ <string>&amp;Options</string>
+ </property>
+ <widget class="QMenu" name="optionsDetailAction" >
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Detail&lt;/b>&lt;br>
+Click this menu item to allow extended precision in time
+reporting to be enabled. Optionally, milliseconds and year can
+be displayed in the current time position, and days and milliseconds
+can be displayed in the current time interval.</string>
+ </property>
+ <property name="title" >
+ <string>&amp;Detail</string>
+ </property>
+ <addaction name="optionsDetailShow_MillisecondsAction" />
+ <addaction name="optionsDetailShow_YearAction" />
+ </widget>
+ <widget class="QMenu" name="optionsTimezoneAction" >
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Timezone&lt;/b>&lt;br>
+Click on this menu item to display a list of available timezones,
+from which to choose. The timezone selected will be made the
+new reporting timezone for all client programs (e.g. pmchart,
+pmval, etc) and affects the display of timestamps in the clients
+and also in the Time Control program itself.</string>
+ </property>
+ <property name="title" >
+ <string>&amp;Timezone</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/internet-web-browser.png</iconset>
+ </property>
+ </widget>
+ <addaction name="optionsTimezoneAction" />
+ <addaction name="optionsDetailAction" />
+ <addaction name="optionsShowBoundsAction" />
+ <addaction name="optionsShowConsoleAction" />
+ </widget>
+ <addaction name="File" />
+ <addaction name="Options" />
+ <addaction name="separator" />
+ <addaction name="Help" />
+ </widget>
+ <action name="helpAboutAction" >
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/pmtime.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;About</string>
+ </property>
+ <property name="iconText" >
+ <string>About pmtime</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|About&lt;/b>&lt;br>
+Click this menu option to bring up the About &lt;i>pmtime&lt;/i> dialog with version, author, and licensing information.</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ </action>
+ <action name="fileHideAction" >
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/edit-clear.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;Hide</string>
+ </property>
+ <property name="iconText" >
+ <string>Hide Archive Time Control window</string>
+ </property>
+ <property name="toolTip" >
+ <string>Hide Archive Time Control window</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>File|Hide&lt;/b>&lt;br>
+Click on this menu option to dismiss the Time Control window,
+for the time being. As the Time Control serves one or
+more client programs (which are completely reliant on the Time
+Controls), this action does not end the Time Control program.
+Rather, it simply removes the window from the visible set.&lt;br>
+The client programs will typically provide a mechanism for making
+the Time Controls visible.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+H</string>
+ </property>
+ </action>
+ <action name="optionsDetailShow_MillisecondsAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="text" >
+ <string>Show &amp;Milliseconds</string>
+ </property>
+ <property name="iconText" >
+ <string>Show Milliseconds in Time</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Detail|Milliseconds&lt;/b>&lt;br>
+Display millisecond precision (or not) in the current time interval and
+position.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+M</string>
+ </property>
+ </action>
+ <action name="optionsDetailShow_YearAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="text" >
+ <string>Show &amp;Year</string>
+ </property>
+ <property name="iconText" >
+ <string>Show Year in Position</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Detail|Year&lt;/b>&lt;br>
+Display the year (or not) in the current time position.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+Y</string>
+ </property>
+ </action>
+ <action name="optionsShowBoundsAction" >
+ <property name="text" >
+ <string>&amp;Boundaries</string>
+ </property>
+ <property name="iconText" >
+ <string>Archive Time Boundaries</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Option|Show Console&lt;/b>&lt;br>
+Click here to display the Time Boundaries dialog, which allows the
+archive time boundaries (as seen by pmtime clients, like pmval and
+pmchart) to be set.
+Initially these are set to the start and end time of the archive
+(or earliest start and latest end, if multiple archives present),
+but it can be further restricted as needed here.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+B</string>
+ </property>
+ </action>
+ <action name="optionsShowConsoleAction" >
+ <property name="text" >
+ <string>&amp;Show Console</string>
+ </property>
+ <property name="iconText" >
+ <string>Show Diagnostic Console</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Option|Show Console&lt;/b>&lt;br>
+Click here to display the diagnostic console with whatever debug
+information has been sent there. This menu option is available
+only when the -D command line option is in use, which allows a
+level of runtime verbosity to be configured (default is "none").</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+C</string>
+ </property>
+ </action>
+ <action name="helpAboutQtAction" >
+ <property name="text" >
+ <string>About Qt</string>
+ </property>
+ <property name="iconText" >
+ <string>About Qt</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|About Qt&lt;/b>&lt;br>
+Click on this menu option to bring up the See Also dialog, with author and website information about Qt - which provides software infrastructure on which this tool was built.</string>
+ </property>
+ </action>
+ <action name="helpSeeAlsoAction" >
+ <property name="text" >
+ <string>See Also</string>
+ </property>
+ <property name="iconText" >
+ <string>See Also</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|See Also&lt;/b>&lt;br>
+Click on this menu option to bring up the See Also dialog, with author and website information about PCP, Qwt, and Qt - all of which provide software infrastructure on which this tool was built.</string>
+ </property>
+ </action>
+ <action name="helpWhats_ThisAction" >
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/whatsthis.png</iconset>
+ </property>
+ <property name="text" >
+ <string>What's This?</string>
+ </property>
+ <property name="iconText" >
+ <string>"What's This?" context sensitive help</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|What's This&lt;/b>&lt;br>
+Click this menu option to invoke a small question mark that is attached to the mouse pointer. Click on a feature which you would like more information about. A popup box appears with more information about the feature.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Shift+F1</string>
+ </property>
+ </action>
+ <action name="helpManualAction" >
+ <property name="text" >
+ <string>&amp;Manual</string>
+ </property>
+ <property name="iconText" >
+ <string>Manual</string>
+ </property>
+ <property name="shortcut" >
+ <string>F1</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <customwidgets>
+ <customwidget>
+ <class>QwtSlider</class>
+ <extends>QWidget</extends>
+ <header>qwt_slider.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QwtWheel</class>
+ <extends>QWidget</extends>
+ <header>qwt_wheel.h</header>
+ </customwidget>
+ </customwidgets>
+ <includes>
+ <include location="local" >pmtime.h</include>
+ <include location="local" >console.h</include>
+ <include location="local" >timezone.h</include>
+ <include location="local" >showboundsdialog.h</include>
+ </includes>
+ <resources>
+ <include location="pmtime.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>fileHideAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>hideWindow()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>helpAboutAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>helpAbout()</slot>
+ </connection>
+ <connection>
+ <sender>helpAboutQtAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>helpAboutQt()</slot>
+ </connection>
+ <connection>
+ <sender>helpSeeAlsoAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>helpSeeAlso()</slot>
+ </connection>
+ <connection>
+ <sender>buttonBack</sender>
+ <signal>clicked()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>back_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>buttonStop</sender>
+ <signal>clicked()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>stop_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>buttonPlay</sender>
+ <signal>clicked()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>play_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>optionsDetailShow_MillisecondsAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>clickShowMsec()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>optionsDetailShow_YearAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>clickShowYear()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>comboBoxSpeed</sender>
+ <signal>activated(int)</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>changeControl(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>sliderPosition</sender>
+ <signal>sliderPressed()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>pressedPosition()</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>sliderPosition</sender>
+ <signal>sliderReleased()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>releasedPosition()</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>sliderPosition</sender>
+ <signal>valueChanged(double)</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>changedPosition(double)</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>optionsShowBoundsAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>showBounds()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>optionsShowConsoleAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>showConsole()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>lineEditCtime</sender>
+ <signal>returnPressed()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>lineEditCtime_validate()</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>lineEditCtime</sender>
+ <signal>textChanged(QString)</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>lineEditCtime_changed(QString)</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>lineEditSpeed</sender>
+ <signal>returnPressed()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>lineEditSpeed_validate()</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>lineEditSpeed</sender>
+ <signal>editingFinished()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>lineEditSpeed_validate()</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>helpWhats_ThisAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>whatsThis()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>wheelSpeed</sender>
+ <signal>valueChanged(double)</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>changeSpeed(double)</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>buttonSpeed</sender>
+ <signal>clicked()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>resetSpeed()</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>comboBoxDelta</sender>
+ <signal>activated(int)</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>changeDelta(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>lineEditDelta</sender>
+ <signal>returnPressed()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>lineEditDelta_validate()</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>lineEditDelta</sender>
+ <signal>textChanged(QString)</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>lineEditDelta_changed(QString)</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>helpManualAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeArch</receiver>
+ <slot>helpManual()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/pmtime/pmtimelive.cpp b/src/pmtime/pmtimelive.cpp
new file mode 100644
index 0000000..cc480c3
--- /dev/null
+++ b/src/pmtime/pmtimelive.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+#include "pmtimelive.h"
+
+#include <QtCore/QTimer>
+#include <QtGui/QValidator>
+#include <QtGui/QActionGroup>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+#include "pmtime.h"
+#include "aboutdialog.h"
+#include "seealsodialog.h"
+
+PmTimeLive::PmTimeLive() : PmTime()
+{
+ setupUi(this);
+#ifdef Q_OS_MAC // fixup after relocation of the MenuBar by Qt
+ QSize size = QSize(width(), height() - MenuBar->height());
+ setMinimumSize(size);
+ setMaximumSize(size);
+#endif
+}
+
+typedef struct {
+ PmTime::State state;
+ QIcon *stop;
+ QIcon *play;
+} IconStateMap;
+
+static void setup(IconStateMap *map, PmTime::State state,
+ QIcon *stop, QIcon *play)
+{
+ map->state = state;
+ map->stop = stop;
+ map->play = play;
+}
+
+void PmTimeLive::setControl(PmTime::State state)
+{
+ static IconStateMap maps[2];
+ static int nmaps;
+
+ if (!nmaps) {
+ nmaps = sizeof(maps) / sizeof(maps[0]);
+ setup(&maps[0], PmTime::StoppedState,
+ PmTime::icon(PmTime::StoppedOn),
+ PmTime::icon(PmTime::ForwardOff));
+ setup(&maps[1], PmTime::ForwardState,
+ PmTime::icon(PmTime::StoppedOff),
+ PmTime::icon(PmTime::ForwardOn));
+ }
+
+ if (my.pmtime.state != state) {
+ for (int i = 0; i < nmaps; i++) {
+ if (maps[i].state == state) {
+ buttonStop->setIcon(*maps[i].stop);
+ buttonPlay->setIcon(*maps[i].play);
+ break;
+ }
+ }
+ my.pmtime.state = state;
+ }
+}
+
+void PmTimeLive::init()
+{
+ static const char *UTC = "UTC\0Universal Coordinated Time";
+
+ console->post("Starting Live Time Control...");
+
+ my.units = PmTime::Seconds;
+ my.first = true;
+ my.tzActions = NULL;
+
+ memset(&my.pmtime, 0, sizeof(my.pmtime));
+ my.pmtime.source = PmTime::HostSource;
+ my.pmtime.delta.tv_sec = PmTime::DefaultDelta;
+
+ my.showMilliseconds = false;
+ optionsDetailShow_MillisecondsAction->setChecked(my.showMilliseconds);
+ my.showYear = false;
+ optionsDetailShow_YearAction->setChecked(my.showYear);
+
+ addTimezone(UTC);
+ displayPosition();
+ displayDeltaText();
+ setControl(PmTime::ForwardState);
+
+ my.timer = new QTimer(this);
+ connect(my.timer, SIGNAL(timeout()), SLOT(updateTime()));
+ my.timer->start(timerInterval());
+ lineEditDelta->setAlignment(Qt::AlignRight);
+ lineEditDelta->setValidator(new QDoubleValidator
+ (0.001, INT_MAX, 3, lineEditDelta));
+}
+
+void PmTimeLive::quit()
+{
+ console->post("live quit!\n");
+}
+
+int PmTimeLive::timerInterval()
+{
+ return (int)((my.pmtime.delta.tv_sec * 1000) +
+ (my.pmtime.delta.tv_usec / 1000));
+}
+
+void PmTimeLive::play_clicked()
+{
+ if (lineEditDelta->isModified())
+ lineEditDelta_validate();
+ if (my.pmtime.state != PmTime::ForwardState)
+ play();
+}
+
+void PmTimeLive::play()
+{
+ console->post("PmTimeLive::play");
+ setControl(PmTime::ForwardState);
+ __pmtimevalNow(&my.pmtime.position);
+ displayPosition();
+ emit vcrModePulse(&my.pmtime, 0);
+ if (!my.timer->isActive())
+ my.timer->start(timerInterval());
+}
+
+void PmTimeLive::stop_clicked()
+{
+ if (my.pmtime.state != PmTime::StoppedState)
+ stop();
+}
+
+void PmTimeLive::stop()
+{
+ console->post("PmTimeLive::stop stopped time");
+ setControl(PmTime::StoppedState);
+ my.timer->stop();
+ __pmtimevalNow(&my.pmtime.position);
+ emit vcrModePulse(&my.pmtime, 0);
+}
+
+void PmTimeLive::updateTime()
+{
+ __pmtimevalNow(&my.pmtime.position);
+ displayPosition();
+ emit timePulse(&my.pmtime);
+}
+
+void PmTimeLive::displayPosition()
+{
+ QString text;
+ char ctimebuf[32], msecbuf[5];
+
+ pmCtime(&my.pmtime.position.tv_sec, ctimebuf);
+ text = tr(ctimebuf);
+ if (my.showYear == false)
+ text.remove(19, 5);
+ if (my.showMilliseconds == true) {
+ sprintf(msecbuf, ".%03u", (uint)my.pmtime.position.tv_usec / 1000);
+ text.insert(19, msecbuf);
+ }
+ lineEditCtime->setText(text.simplified());
+}
+
+void PmTimeLive::clickShowMsec()
+{
+ if (my.showMilliseconds == true)
+ my.showMilliseconds = false;
+ else
+ my.showMilliseconds = true;
+ optionsDetailShow_MillisecondsAction->setChecked(my.showMilliseconds);
+ displayPosition();
+}
+
+void PmTimeLive::clickShowYear()
+{
+ if (my.showYear == true)
+ my.showYear = false;
+ else
+ my.showYear = true;
+ optionsDetailShow_YearAction->setChecked(my.showYear);
+ displayPosition();
+}
+
+void PmTimeLive::changeDelta(int value)
+{
+ my.units = (PmTime::DeltaUnits)value;
+ displayDeltaText();
+}
+
+void PmTimeLive::displayDeltaText()
+{
+ QString text;
+ double delta = PmTime::secondsFromTimeval(&my.pmtime.delta);
+
+ delta = PmTime::secondsToUnits(delta, my.units);
+ if ((double)(int)delta == delta)
+ text.sprintf("%.2f", delta);
+ else
+ text.sprintf("%.6f", delta);
+ lineEditDelta->setText(text);
+}
+
+void PmTimeLive::disableConsole()
+{
+ optionsShowConsoleAction->setVisible(false);
+}
+
+void PmTimeLive::lineEditDelta_changed(const QString &)
+{
+ if (lineEditDelta->isModified())
+ stop_clicked();
+}
+
+void PmTimeLive::lineEditDelta_validate()
+{
+ double delta;
+ bool ok, reset = my.timer->isActive();
+
+ delta = lineEditDelta->text().toDouble(&ok);
+ if (!ok || delta <= 0) {
+ displayDeltaText(); // reset to previous, known-good delta
+ } else {
+ my.timer->stop();
+ delta = PmTime::unitsToSeconds(delta, my.units);
+ PmTime::secondsToTimeval(delta, &my.pmtime.delta);
+ emit vcrModePulse(&my.pmtime, 0);
+ if (reset)
+ my.timer->start(timerInterval());
+ }
+}
+
+void PmTimeLive::setTimezone(QAction *action)
+{
+ for (int i = 0; i < my.tzlist.size(); i++) {
+ TimeZone *tz = my.tzlist.at(i);
+ if (tz->action() == action) {
+ pmUseZone(tz->handle());
+ emit tzPulse(&my.pmtime, tz->tz(), strlen(tz->tz()) + 1,
+ tz->tzlabel(), strlen(tz->tzlabel()) + 1);
+ setTime(&my.pmtime, NULL); // re-display the time, no messages
+ console->post("PmTimeLive::setTimezone sent TZ %s(%s) to clients\n",
+ tz->tz(), tz->tzlabel());
+ break;
+ }
+ }
+}
+
+void PmTimeLive::addTimezone(const char *string)
+{
+ TimeZone *tmp, *tzp;
+ QAction *tzAction;
+ char *label, *tz;
+ int handle;
+
+ if ((handle = pmNewZone(string)) < 0)
+ return;
+
+ if ((tz = strdup(string)) == NULL)
+ return;
+
+ if ((label = strdup(string + strlen(string) + 1)) == NULL) {
+ free(tz);
+ return;
+ }
+
+ for (int i = 0; i < my.tzlist.size(); i++) {
+ tmp = my.tzlist.at(i);
+ if (strcmp(tmp->tzlabel(), label) == 0) {
+ free(label);
+ free(tz);
+ return;
+ }
+ }
+
+ tzAction = new QAction(this);
+ tzAction->setCheckable(true);
+ tzAction->setToolTip(tz);
+ tzAction->setText(label);
+
+ tzp = new TimeZone(tz, label, tzAction, handle);
+ my.tzlist.append(tzp);
+
+ if (!my.tzActions) {
+ my.tzActions = new QActionGroup(this);
+ connect(my.tzActions, SIGNAL(selected(QAction *)) , this,
+ SLOT(setTimezone(QAction *)));
+ }
+ my.tzActions->addAction(tzAction);
+ optionsTimezoneAction->addActions(my.tzActions->actions());
+ console->post("PmTimeLive::addTimezone added TZ=%s label=%s", tz, label);
+}
+
+void PmTimeLive::setTime(PmTime::Packet *k, char *tzdata)
+{
+ if (tzdata != NULL)
+ addTimezone(tzdata);
+
+ if (my.first == true) {
+ bool reset = my.timer->isActive();
+
+ my.first = false;
+ my.pmtime.position = k->position;
+ my.pmtime.delta = k->delta;
+ my.timer->stop();
+ if (reset)
+ my.timer->start(timerInterval());
+ displayDeltaText();
+ displayPosition();
+ }
+}
diff --git a/src/pmtime/pmtimelive.h b/src/pmtime/pmtimelive.h
new file mode 100644
index 0000000..2a4835b
--- /dev/null
+++ b/src/pmtime/pmtimelive.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, 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 PMTIMELIVE_H
+#define PMTIMELIVE_H
+
+#include "ui_pmtimelive.h"
+#include "pmtime.h"
+#include "console.h"
+#include "timezone.h"
+
+class PmTimeLive : public PmTime, public Ui::PmTimeLive
+{
+ Q_OBJECT
+
+public:
+ PmTimeLive();
+
+ virtual void play();
+ virtual void stop();
+ virtual int timerInterval();
+ virtual void displayPosition();
+ virtual void displayDeltaText();
+ virtual void addTimezone(const char *string);
+ virtual void setTime(PmTime::Packet *k, char *tzdata);
+
+public slots:
+ virtual void setControl(PmTime::State newstate);
+ virtual void init();
+ virtual void quit();
+ virtual void play_clicked();
+ virtual void stop_clicked();
+ virtual void updateTime();
+ virtual void clickShowMsec();
+ virtual void clickShowYear();
+ virtual void changeDelta(int value);
+ virtual void disableConsole();
+ virtual void lineEditDelta_changed(const QString &s);
+ virtual void lineEditDelta_validate();
+ virtual void setTimezone(QAction * action);
+
+signals:
+ void timePulse(PmTime::Packet *);
+ void vcrModePulse(PmTime::Packet *, int);
+ void tzPulse(PmTime::Packet *, char *, int, char *, int);
+
+private:
+ struct {
+ PmTime::Packet pmtime;
+ PmTime::DeltaUnits units;
+ bool first;
+ bool showMilliseconds;
+ bool showYear;
+ QTimer *timer;
+ QActionGroup *tzActions;
+ QList<TimeZone *> tzlist;
+ } my;
+};
+
+#endif // PMTIMELIVE_H
diff --git a/src/pmtime/pmtimelive.ui b/src/pmtime/pmtimelive.ui
new file mode 100644
index 0000000..7a3b882
--- /dev/null
+++ b/src/pmtime/pmtimelive.ui
@@ -0,0 +1,824 @@
+<ui version="4.0" >
+ <class>PmTimeLive</class>
+ <widget class="QMainWindow" name="PmTimeLive" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>310</width>
+ <height>155</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>310</width>
+ <height>155</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>310</width>
+ <height>155</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>PCP Live Time Control</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="pmtime.qrc" >:/images/pmtime.png</iconset>
+ </property>
+ <property name="windowIconText" >
+ <string/>
+ </property>
+ <property name="toolTip" >
+ <string/>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Live Time Control&lt;/b>&lt;br>
+A time server, sending time related information (current time,
+metric value fetch interval, timezone) to one or more client
+programs (e.g. pmchart, pmval, etc).</string>
+ </property>
+ <widget class="QWidget" name="widget" >
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="textLabel1" >
+ <property name="whatsThis" >
+ <string>&lt;b>Sampling interval&lt;/b>&lt;br>
+Numeric values entered into these fields will form the number of
+days, hours, minutes, seconds, and/or milliseconds between PCP
+metric value samples in Time Control client programs
+(e.g. pmchart, pmval, etc).</string>
+ </property>
+ <property name="text" >
+ <string>Interval</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="textLabel2" >
+ <property name="whatsThis" >
+ <string>&lt;b>Time Position&lt;/b>&lt;br>
+This text field displays the current time position. This value is
+sent to clients (e.g. pmchart, pmval) of this Time Control
+program to synchronise them in terms of the progression of time
+and also with respect to any "play mode" changes requested.</string>
+ </property>
+ <property name="text" >
+ <string>Time</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="textLabel3" >
+ <property name="whatsThis" >
+ <string>&lt;b>Live Control&lt;/b>&lt;br>
+Pressing the Stop/Play controls will begin/block the advancement
+of time, as seen by the Time Control program and all of its clients
+(e.g. pmchart, pmval, etc). Time will advance in increments of thecurrent Interval.</string>
+ </property>
+ <property name="text" >
+ <string>Control</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </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="QLineEdit" name="lineEditDelta" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>98</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>98</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="toolTip" >
+ <string comment="Time interval between performance metric value samples" >Sampling interval</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Sampling interval&lt;/b>&lt;br>
+Numeric values entered into these fields will form the number of
+hours, minutes and/or seconds between PCP metric value
+samples in Time Control client programs (e.g. pmchart, pmval, etc).</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="comboBoxDelta" >
+ <property name="whatsThis" >
+ <string>&lt;b>Sampling interval units&lt;/b>&lt;br>
+Displays the units in which the sampling interval is entered.
+Metric values can be sampled in days, hours, minutes, seconds
+or milliseconds in Time Control client programs (e.g. pmchart,
+pmval, etc).</string>
+ </property>
+ <property name="currentIndex" >
+ <number>1</number>
+ </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>
+ <item>
+ <widget class="QLineEdit" name="lineEditCtime" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="acceptDrops" >
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" >
+ <string comment="This is the current time position as seen by all pmtime clients (e.g. pmchart, pmval, etc)" >Current date and time display</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Time Position&lt;/b>&lt;br>
+This text field displays the current time position. This value is
+sent to clients (e.g. pmchart, pmval) of this Time Control
+program to synchronise them in terms of the progression of time
+and also with respect to any "play mode" changes requested.</string>
+ </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>
+ <widget class="QToolButton" name="buttonStop" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>54</width>
+ <height>36</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Stop&lt;/b>&lt;br>
+Pressing this button will stop the advancement of time, as seen
+by the Time Control program and all of its clients (e.g. pmchart,
+pmval, etc). Unless stopped, time advances in increments of the
+current Interval.</string>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>52</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="buttonPlay" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>54</width>
+ <height>36</height>
+ </size>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Play&lt;/b>&lt;br>
+Pressing this button will begin the advancement of time, as seen
+by the Time Control program and all of its clients (e.g. pmchart,
+pmval, etc). Time will advance in increments of the current
+Interval.</string>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="iconSize" >
+ <size>
+ <width>52</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>29</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="MenuBar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>310</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="Help" >
+ <property name="title" >
+ <string>&amp;Help</string>
+ </property>
+ <addaction name="helpManualAction" />
+ <addaction name="separator" />
+ <addaction name="helpAboutAction" />
+ <addaction name="helpAboutQtAction" />
+ <addaction name="helpSeeAlsoAction" />
+ <addaction name="separator" />
+ <addaction name="helpWhats_ThisAction" />
+ </widget>
+ <widget class="QMenu" name="File" >
+ <property name="title" >
+ <string>&amp;File</string>
+ </property>
+ <addaction name="fileHideAction" />
+ </widget>
+ <widget class="QMenu" name="Options" >
+ <property name="title" >
+ <string>&amp;Options</string>
+ </property>
+ <widget class="QMenu" name="optionsDetailAction" >
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Detail&lt;/b>&lt;br>
+Click this menu item to allow extended precision in time
+reporting to be enabled. Optionally, milliseconds and year can
+be displayed in the current time position, and days and milliseconds
+can be displayed in the current time interval.</string>
+ </property>
+ <property name="title" >
+ <string>&amp;Detail</string>
+ </property>
+ <addaction name="optionsDetailShow_MillisecondsAction" />
+ <addaction name="optionsDetailShow_YearAction" />
+ </widget>
+ <widget class="QMenu" name="optionsTimezoneAction" >
+ <property name="windowIcon" >
+ <iconset resource="pmtime.qrc" >:/images/internet-web-browser.png</iconset>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Timezone&lt;/b>&lt;br>
+Click on this menu item to display a list of available timezones,
+from which to choose. The timezone selected will be made the
+new reporting timezone for all client programs (e.g. pmchart,
+pmval, etc) and affects the display of timestamps in the clients
+and also in the Time Control program itself.</string>
+ </property>
+ <property name="title" >
+ <string>&amp;Timezone</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/internet-web-browser.png</iconset>
+ </property>
+ </widget>
+ <addaction name="optionsTimezoneAction" />
+ <addaction name="optionsDetailAction" />
+ <addaction name="optionsShowConsoleAction" />
+ </widget>
+ <addaction name="File" />
+ <addaction name="Options" />
+ <addaction name="separator" />
+ <addaction name="Help" />
+ </widget>
+ <action name="helpAboutAction" >
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/pmtime.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;About</string>
+ </property>
+ <property name="iconText" >
+ <string>About pmtime</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|About&lt;/b>&lt;br>
+Click this menu option to bring up the About &lt;i>pmtime&lt;/i> dialog with version, author, and licensing information.</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ </action>
+ <action name="fileHideAction" >
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/edit-clear.png</iconset>
+ </property>
+ <property name="text" >
+ <string>&amp;Hide</string>
+ </property>
+ <property name="iconText" >
+ <string>Hide Live Time Control window</string>
+ </property>
+ <property name="toolTip" >
+ <string>Hide Live Time Control window</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>File|Hide&lt;/b>&lt;br>
+Click on this menu option to dismiss the Time Control window,
+for the time being. As the Time Control serves one or
+more client programs (which are completely reliant on the Time
+Controls), this action does not end the Time Control program.
+Rather, it simply removes the window from the visible set.&lt;br>
+The client programs will typically provide a mechanism for making
+the Time Controls visible.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+H</string>
+ </property>
+ </action>
+ <action name="optionsDetailShow_MillisecondsAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="text" >
+ <string>Show &amp;Milliseconds</string>
+ </property>
+ <property name="iconText" >
+ <string>Show Milliseconds in Time</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Detail|Milliseconds&lt;/b>&lt;br>
+Display millisecond precision (or not) in the current time interval and
+position.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+M</string>
+ </property>
+ </action>
+ <action name="optionsDetailShow_YearAction" >
+ <property name="checkable" >
+ <bool>true</bool>
+ </property>
+ <property name="text" >
+ <string>Show &amp;Year</string>
+ </property>
+ <property name="iconText" >
+ <string>Show Year in Time</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Options|Detail|Year&lt;/b>&lt;br>
+Display the year (or not) in the current time position.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+Y</string>
+ </property>
+ </action>
+ <action name="optionsShowConsoleAction" >
+ <property name="text" >
+ <string>&amp;Show Console</string>
+ </property>
+ <property name="iconText" >
+ <string>Show Diagnostic Console</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Option|Show Console&lt;/b>&lt;br>
+Click here to display the diagnostic console with whatever debug
+information has been sent there. This menu option is available
+only when the -D command line option is in use, which allows a
+level of runtime verbosity to be configured (default is "none").</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+C</string>
+ </property>
+ </action>
+ <action name="helpAboutQtAction" >
+ <property name="text" >
+ <string>About Qt</string>
+ </property>
+ <property name="iconText" >
+ <string>About Qt</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|About Qt&lt;/b>&lt;br>
+Click on this menu option to bring up the See Also dialog, with author and website information about Qt - which provides software infrastructure on which this tool was built.</string>
+ </property>
+ </action>
+ <action name="helpSeeAlsoAction" >
+ <property name="text" >
+ <string>See Also</string>
+ </property>
+ <property name="iconText" >
+ <string>See Also</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|See Also&lt;/b>&lt;br>
+Click on this menu option to bring up the See Also dialog, with author and website information about PCP, Qwt, and Qt - all of which provide software infrastructure on which this tool was built.</string>
+ </property>
+ </action>
+ <action name="helpWhats_ThisAction" >
+ <property name="icon" >
+ <iconset resource="pmtime.qrc" >:/images/whatsthis.png</iconset>
+ </property>
+ <property name="text" >
+ <string>What's This?</string>
+ </property>
+ <property name="iconText" >
+ <string>"What's This?" context sensitive help</string>
+ </property>
+ <property name="whatsThis" >
+ <string>&lt;b>Help|What's This&lt;/b>&lt;br>
+Click this menu option to invoke a small question mark that is attached to the mouse pointer. Click on a feature which you would like more information about. A popup box appears with more information about the feature.</string>
+ </property>
+ <property name="shortcut" >
+ <string>Shift+F1</string>
+ </property>
+ </action>
+ <action name="helpManualAction" >
+ <property name="text" >
+ <string>&amp;Manual</string>
+ </property>
+ <property name="iconText" >
+ <string>Manual</string>
+ </property>
+ <property name="shortcut" >
+ <string>F1</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <includes>
+ <include location="local" >pmtime.h</include>
+ <include location="local" >console.h</include>
+ <include location="local" >timezone.h</include>
+ </includes>
+ <resources>
+ <include location="pmtime.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>fileHideAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>hideWindow()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>helpAboutAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>helpAbout()</slot>
+ </connection>
+ <connection>
+ <sender>helpAboutQtAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>helpAboutQt()</slot>
+ </connection>
+ <connection>
+ <sender>helpSeeAlsoAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>helpSeeAlso()</slot>
+ </connection>
+ <connection>
+ <sender>buttonPlay</sender>
+ <signal>clicked()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>play_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>buttonStop</sender>
+ <signal>clicked()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>stop_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>optionsDetailShow_MillisecondsAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>clickShowMsec()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>optionsDetailShow_YearAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>clickShowYear()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>optionsShowConsoleAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>showConsole()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>comboBoxDelta</sender>
+ <signal>activated(int)</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>changeDelta(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>helpWhats_ThisAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>whatsThis()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>lineEditDelta</sender>
+ <signal>returnPressed()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>lineEditDelta_validate()</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>lineEditDelta</sender>
+ <signal>textChanged(QString)</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>lineEditDelta_changed(QString)</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>helpManualAction</sender>
+ <signal>triggered()</signal>
+ <receiver>PmTimeLive</receiver>
+ <slot>helpManual()</slot>
+ <hints>
+ <hint type="sourcelabel" >
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel" >
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/pmtime/seealsodialog.cpp b/src/pmtime/seealsodialog.cpp
new file mode 100644
index 0000000..ae663e8
--- /dev/null
+++ b/src/pmtime/seealsodialog.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 "seealsodialog.h"
+
+SeeAlsoDialog::SeeAlsoDialog(QWidget* parent) : QDialog(parent)
+{
+ setupUi(this);
+}
+
+void SeeAlsoDialog::seeAlsoOKButton_clicked()
+{
+ done(0);
+}
diff --git a/src/pmtime/seealsodialog.h b/src/pmtime/seealsodialog.h
new file mode 100644
index 0000000..b5465b6
--- /dev/null
+++ b/src/pmtime/seealsodialog.h
@@ -0,0 +1,30 @@
+/*
+ * 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 SEEALSODIALOG_H
+#define SEEALSODIALOG_H
+
+#include "ui_seealsodialog.h"
+
+class SeeAlsoDialog : public QDialog, public Ui::SeeAlsoDialog
+{
+ Q_OBJECT
+
+public:
+ SeeAlsoDialog(QWidget* parent);
+
+public slots:
+ virtual void seeAlsoOKButton_clicked();
+};
+
+#endif // SEEALSODIALOG_H
diff --git a/src/pmtime/seealsodialog.ui b/src/pmtime/seealsodialog.ui
new file mode 100644
index 0000000..9b81af8
--- /dev/null
+++ b/src/pmtime/seealsodialog.ui
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SeeAlsoDialog</class>
+ <widget class="QDialog" name="SeeAlsoDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>410</width>
+ <height>250</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>410</width>
+ <height>250</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Acknowledgements</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="pmtime.qrc">
+ <normaloff>:/images/pmtime.png</normaloff>:/images/pmtime.png</iconset>
+ </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="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="seeAlsoPCPPixmapLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>76</width>
+ <height>82</height>
+ </size>
+ </property>
+ <property name="pixmap">
+ <pixmap resource="pmtime.qrc">:/images/aboutpcp.png</pixmap>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>51</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="versionPCPTextLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;&lt;i&gt;Performance Co-Pilot (PCP)&lt;/i&gt;&lt;/b&gt;&lt;br&gt;
+Copyright (c) 2010-2012 Red Hat&lt;br&gt;
+Copyright (c) 2006-2012 Aconex&lt;br&gt;
+Copyright (c) 1995-2007 SGI&lt;br&gt;
+... and many, many others!&lt;br&gt;
+&lt;i&gt;http://oss.sgi.com/projects/pcp&lt;/i&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="versionQwtTextLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;b&gt;&lt;i&gt;Qt Widgets for Technical Apps (Qwt)&lt;/i&gt;&lt;/b&gt;&lt;br&gt;
+Copyright (c) 1997 Josef Wilgen&lt;br&gt;
+Copyright (c) 2002 Uwe Rathmann&lt;br&gt;
+&lt;i&gt;http://qwt.sourceforge.net/&lt;/i&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="seeAlsoOKButton">
+ <property name="focusPolicy">
+ <enum>Qt::TabFocus</enum>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="pmtime.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>seeAlsoOKButton</sender>
+ <signal>clicked()</signal>
+ <receiver>SeeAlsoDialog</receiver>
+ <slot>seeAlsoOKButton_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/pmtime/showboundsdialog.cpp b/src/pmtime/showboundsdialog.cpp
new file mode 100644
index 0000000..6d982b3
--- /dev/null
+++ b/src/pmtime/showboundsdialog.cpp
@@ -0,0 +1,237 @@
+/*
+ * 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 "showboundsdialog.h"
+#include <QtGui/QMessageBox>
+#include <pcp/pmapi.h>
+#include <pcp/impl.h>
+#include "pmtime.h"
+
+ShowBounds::ShowBounds(QWidget* parent) : QDialog(parent)
+{
+ setupUi(this);
+}
+
+void ShowBounds::init(
+ struct timeval *absoluteStart, struct timeval *currentStart,
+ struct timeval *absoluteEnd, struct timeval *currentEnd)
+{
+ my.absoluteStart = absoluteStart;
+ my.currentStart = currentStart;
+ my.absoluteEnd = absoluteEnd;
+ my.currentEnd = currentEnd;
+ reset();
+}
+
+void ShowBounds::reset()
+{
+ my.localAbsoluteStart = PmTime::secondsFromTimeval(my.absoluteStart);
+ my.localCurrentStart = PmTime::secondsFromTimeval(my.currentStart);
+ my.localAbsoluteEnd = PmTime::secondsFromTimeval(my.absoluteEnd);
+ my.localCurrentEnd = PmTime::secondsFromTimeval(my.currentEnd);
+
+#ifdef DESPERATE
+ console->post(PmTime::DebugProtocol, "ShowBounds::reset START: "
+ "end=%u.%u(%.3f) start=%u.%u(%.3f) lend=%u.%u(%.3f) lstart=%u.%u(%.3f)",
+ my.absoluteEnd->tv_sec, my.absoluteEnd->tv_usec, my.localAbsoluteEnd,
+ my.absoluteStart->tv_sec, my.absoluteStart->tv_usec,
+ my.localAbsoluteStart,
+ my.currentEnd->tv_sec, my.currentEnd->tv_usec, my.localCurrentEnd,
+ my.currentStart->tv_sec, my.currentStart->tv_usec,
+ my.localCurrentStart);
+#endif
+
+ displayStartSlider();
+ displayEndSlider();
+ displayStartText();
+ displayEndText();
+
+#ifdef DESPERATE
+ console->post(PmTime::DebugProtocol, "ShowBounds::reset ENDED: "
+ "end=%u.%u(%.3f) start=%u.%u(%.3f) lend=%u.%u(%.3f) lstart=%u.%u(%.3f)",
+ my.absoluteEnd->tv_sec, my.absoluteEnd->tv_usec, my.localAbsoluteEnd,
+ my.absoluteStart->tv_sec, my.absoluteStart->tv_usec,
+ my.localAbsoluteStart,
+ my.currentEnd->tv_sec, my.currentEnd->tv_usec, my.localCurrentEnd,
+ my.currentStart->tv_sec, my.currentStart->tv_usec,
+ my.localCurrentStart);
+#endif
+}
+
+void ShowBounds::displayStartSlider()
+{
+ sliderStart->blockSignals(true);
+ sliderStart->setRange(my.localAbsoluteStart, my.localAbsoluteEnd);
+ sliderStart->setValue(my.localCurrentStart);
+ sliderStart->blockSignals(false);
+}
+
+void ShowBounds::displayEndSlider()
+{
+ sliderEnd->blockSignals(true);
+ sliderEnd->setRange(my.localAbsoluteStart, my.localAbsoluteEnd);
+ sliderEnd->setValue(my.localCurrentEnd);
+ sliderEnd->blockSignals(false);
+}
+
+void ShowBounds::displayStartText()
+{
+ time_t clock = (time_t)my.localCurrentStart;
+ char ctimebuf[32];
+
+ pmCtime(&clock, ctimebuf);
+ lineEditStart->setText(tr(ctimebuf).simplified());
+
+ console->post("ShowBounds::displayStartText clock=%.3f - %s",
+ my.localCurrentStart,
+ (const char *)lineEditStart->text().toAscii());
+}
+
+void ShowBounds::displayEndText()
+{
+ time_t clock = (time_t)my.localCurrentEnd;
+ char ctimebuf[32];
+
+ pmCtime(&clock, ctimebuf);
+ lineEditEnd->setText(tr(ctimebuf).simplified());
+}
+
+void ShowBounds::changedStart(double value)
+{
+ if (value != my.localCurrentStart) {
+ console->post("ShowBounds::changedStart: %.3f -> %.3f",
+ my.localCurrentStart, value);
+ my.localCurrentStart = value;
+ displayStartSlider();
+ displayStartText();
+ if (my.localCurrentStart > my.localCurrentEnd)
+ sliderEnd->setValue(value);
+ }
+}
+
+void ShowBounds::changedEnd(double value)
+{
+ if (value != my.localCurrentEnd) {
+ console->post("ShowBounds::changedEnd %.3f -> %.3f", __func__,
+ my.localCurrentEnd, value);
+ my.localCurrentEnd = value;
+ displayEndSlider();
+ displayEndText();
+ if (my.localCurrentStart > my.localCurrentEnd)
+ sliderStart->setValue(value);
+ }
+}
+
+//
+// This routine just verifies that input from the user is correct,
+// before allowing the window to be closed. If theres invalid date
+// strings in start/end text boxes, we must deny the "OK" press.
+// Actual work of updating pmtime is done in flush().
+//
+void ShowBounds::accept()
+{
+ struct timeval current, start, end;
+ QString error, input;
+ char *msg;
+
+ console->post("ShowBounds::accept: OK pressed");
+
+ PmTime::secondsToTimeval(my.localAbsoluteStart, &start);
+ PmTime::secondsToTimeval(my.localAbsoluteEnd, &end);
+
+ if (lineEditStart->isModified()) {
+ input = lineEditStart->text().simplified();
+ if (input.length() == 0) {
+ error.sprintf("Start time has not been set.\n");
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ return;
+ }
+ if (input[0] != '@')
+ input.prepend("@");
+ if (__pmParseTime(input.toAscii(), &start, &end, &current, &msg) < 0) {
+ error.sprintf("Invalid start date/time:\n\n%s\n", msg);
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ free(msg);
+ return;
+ } else if (PmTime::timevalCompare(&current, &start) < 0 ||
+ PmTime::timevalCompare(&current, &end) > 0) {
+ error.sprintf("Start time is outside archive boundaries\n");
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ return;
+ }
+ my.localCurrentStart = PmTime::secondsFromTimeval(&current);
+ console->post("ShowBounds::accept start=%.2f (abs=%.2f-%.2f)",
+ my.localCurrentStart, my.localAbsoluteStart,
+ my.localAbsoluteEnd);
+ }
+
+ if (lineEditEnd->isModified()) {
+ input = lineEditEnd->text().simplified();
+ if (input.length() == 0) {
+ error.sprintf("End time has not been set.\n");
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ return;
+ }
+ if (input[0] != '@')
+ input.prepend("@");
+ if (__pmParseTime(input.toAscii(), &start, &end, &current, &msg) < 0) {
+ error.sprintf("Invalid end date/time:\n%s\n\n", msg);
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ free(msg);
+ return;
+ } else if (PmTime::timevalCompare(&current, &start) < 0 ||
+ PmTime::timevalCompare(&current, &end) > 0) {
+ error.sprintf("End time is outside the archive boundaries\n");
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ return;
+ }
+ my.localCurrentEnd = PmTime::secondsFromTimeval(&current);
+ console->post("ShowBounds::accept end=%.2f (abs=%.2f-%.2f)",
+ my.localCurrentEnd, my.localAbsoluteStart, my.localAbsoluteEnd);
+ }
+
+ if (my.localCurrentStart > my.localCurrentEnd) {
+ error.sprintf("Start time must be less than end time.\n");
+ QMessageBox::warning(0, tr("Warning"), error, tr("Quit"));
+ return;
+ }
+
+ emit boundsChanged();
+ done(0);
+}
+
+void ShowBounds::reject()
+{
+ done(1);
+}
+
+//
+// Inform parent pmtime window of accepted changes (start/end),
+// via the pointers-to-struct-timevals we were initially given.
+//
+void ShowBounds::flush()
+{
+ struct timeval start, end;
+
+ PmTime::secondsToTimeval(my.localCurrentStart, &start);
+ PmTime::secondsToTimeval(my.localCurrentEnd, &end);
+
+ console->post("ShowBounds::flush updating bounds to %.2f->%.2f",
+ PmTime::secondsFromTimeval(&start),
+ PmTime::secondsFromTimeval(&end));
+
+ if (PmTime::timevalCompare(&start, my.currentStart) != 0)
+ *my.currentStart = start;
+ if (PmTime::timevalCompare(&end, my.currentEnd) != 0)
+ *my.currentEnd = end;
+}
diff --git a/src/pmtime/showboundsdialog.h b/src/pmtime/showboundsdialog.h
new file mode 100644
index 0000000..da080c8
--- /dev/null
+++ b/src/pmtime/showboundsdialog.h
@@ -0,0 +1,58 @@
+/*
+ * 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 SHOWBOUNDS_H
+#define SHOWBOUNDS_H
+
+#include "ui_showboundsdialog.h"
+#include "console.h"
+
+class ShowBounds : public QDialog, public Ui::ShowBounds
+{
+ Q_OBJECT
+
+public:
+ ShowBounds(QWidget* parent);
+
+ virtual void init(struct timeval *, struct timeval *,
+ struct timeval *, struct timeval *);
+ virtual void reset();
+ virtual void flush();
+ virtual void displayStartText();
+ virtual void displayEndText();
+ virtual void displayStartSlider();
+ virtual void displayEndSlider();
+
+public slots:
+ virtual void changedStart(double value);
+ virtual void changedEnd(double value);
+ virtual void accept();
+ virtual void reject();
+
+signals:
+ void boundsChanged();
+
+private:
+ struct {
+ double localCurrentStart;
+ double localCurrentEnd;
+ double localAbsoluteStart;
+ double localAbsoluteEnd;
+ struct timeval *currentStart;
+ struct timeval *currentEnd;
+ struct timeval *absoluteStart;
+ struct timeval *absoluteEnd;
+ } my;
+};
+
+#endif // SHOWBOUNDS_H
diff --git a/src/pmtime/showboundsdialog.ui b/src/pmtime/showboundsdialog.ui
new file mode 100644
index 0000000..8459921
--- /dev/null
+++ b/src/pmtime/showboundsdialog.ui
@@ -0,0 +1,303 @@
+<ui version="4.0" >
+ <class>ShowBounds</class>
+ <widget class="QDialog" name="ShowBounds" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>324</width>
+ <height>181</height>
+ </rect>
+ </property>
+ <property name="acceptDrops" >
+ <bool>false</bool>
+ </property>
+ <property name="windowTitle" >
+ <string>Archive Time Bounds</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="pmtime.qrc" >:/images/pmtime.png</iconset>
+ </property>
+ <property name="whatsThis" >
+ <string>The Archive Bounds dialog displays and allows modifications
+to the start and end time of a (set of) PCP data archive(s).
+This effectively restricts all pmtime clients (e.g. pmval, pmchart)
+to a subset of the available performance data.</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>false</bool>
+ </property>
+ <property name="modal" >
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>7</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>4</number>
+ </property>
+ <item>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="3" column="0" colspan="2" >
+ <widget class="QwtSlider" name="sliderEnd" >
+ <property name="whatsThis" >
+ <string>Modify the archive end time as seen by all&lt;br>
+pmtime clients (e.g. pmval, pmchart).&lt;br>&lt;br>
+This cannot be set before the start time of the&lt;br>
+archive with the earliest start time, nor beyond&lt;br>
+of the archive with the latest end time.&lt;br>
+It also cannot be less than the current start&lt;br>
+time.</string>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="backgroundStyle" >
+ <enum>QwtSlider::Groove</enum>
+ </property>
+ <property name="handleSize" >
+ <size>
+ <width>12</width>
+ <height>16</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="endLabel" >
+ <property name="text" >
+ <string>End</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="startLabel" >
+ <property name="text" >
+ <string>Start</string>
+ </property>
+ <property name="wordWrap" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="lineEditStart" >
+ <property name="whatsThis" >
+ <string>Modify the archive start time as seen by all&lt;br>
+pmtime clients (e.g. pmval, pmchart).&lt;br>&lt;br>
+This cannot be set before the start time of the&lt;br>
+archive with the earliest start time, nor beyond&lt;br>
+of the archive with the latest end time.&lt;br>
+It also cannot be greater than the current end&lt;br>
+time.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QwtSlider" name="sliderStart" >
+ <property name="whatsThis" >
+ <string>Modify the archive start time as seen by all&lt;br>
+pmtime clients (e.g. pmval, pmchart).&lt;br>&lt;br>
+This cannot be set before the start time of the&lt;br>
+archive with the earliest start time, nor beyond&lt;br>
+of the archive with the latest end time.&lt;br>
+It also cannot be greater than the current end&lt;br>
+time.</string>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="backgroundStyle" >
+ <enum>QwtSlider::Groove</enum>
+ </property>
+ <property name="handleSize" >
+ <size>
+ <width>12</width>
+ <height>16</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="lineEditEnd" >
+ <property name="whatsThis" >
+ <string>Modify the archive end time as seen by all&lt;br>
+pmtime clients (e.g. pmval, pmchart).&lt;br>&lt;br>
+This cannot be set before the start time of the&lt;br>
+archive with the earliest start time, nor beyond&lt;br>
+of the archive with the latest end time.&lt;br>
+It also cannot be less than the current start&lt;br>
+time.</string>
+ </property>
+ </widget>
+ </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>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonOK" >
+ <property name="text" >
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel" >
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <customwidgets>
+ <customwidget>
+ <class>QwtSlider</class>
+ <extends>QWidget</extends>
+ <header>qwt_slider.h</header>
+ </customwidget>
+ </customwidgets>
+ <includes>
+ <include location="local" >console.h</include>
+ </includes>
+ <resources>
+ <include location="pmtime.qrc" />
+ </resources>
+ <connections>
+ <connection>
+ <sender>buttonOK</sender>
+ <signal>clicked()</signal>
+ <receiver>ShowBounds</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>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>ShowBounds</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>sliderStart</sender>
+ <signal>valueChanged(double)</signal>
+ <receiver>ShowBounds</receiver>
+ <slot>changedStart(double)</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>sliderEnd</sender>
+ <signal>valueChanged(double)</signal>
+ <receiver>ShowBounds</receiver>
+ <slot>changedEnd(double)</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/pmtime/timelord.cpp b/src/pmtime/timelord.cpp
new file mode 100644
index 0000000..64ebcf0
--- /dev/null
+++ b/src/pmtime/timelord.cpp
@@ -0,0 +1,395 @@
+/*
+ * 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 "timelord.h"
+#include <stdlib.h>
+
+TimeClient::TimeClient(QTcpSocket *s, QObject *p) : QObject(p)
+{
+ my.ac = NULL;
+ my.hc = NULL;
+ my.socket = s;
+ my.state = TimeClient::Disconnected;
+ my.source = PmTime::NoSource;
+ memset(&my.acktime, 0, sizeof(my.acktime));
+ console->post(PmTime::DebugProtocol, "TimeClient initialised");
+ connect(my.socket, SIGNAL(readyRead()), SLOT(readClient()));
+ connect(my.socket, SIGNAL(disconnected()), SLOT(disconnectClient()));
+}
+
+TimeClient::~TimeClient()
+{
+ console->post(PmTime::DebugProtocol, "Destroying client %p", this);
+ my.state = TimeClient::Disconnected;
+ my.source = PmTime::NoSource;
+ emit endConnect(this);
+}
+
+static char *stateString(int state)
+{
+ static char buffer[32];
+
+ if (state == TimeClient::Disconnected)
+ strcpy(buffer, "Disconnected State");
+ else if (state == TimeClient::ClientConnectSET)
+ strcpy(buffer, "ClientConnectSET State");
+ else if (state == TimeClient::ServerConnectACK)
+ strcpy(buffer, "ServerConnectACK State");
+ else if (state == TimeClient::ServerNeedACK)
+ strcpy(buffer, "ServerNeedACK State");
+ else if (state == TimeClient::ClientReady)
+ strcpy(buffer, "ClientReady State");
+ else
+ strcpy(buffer, "Unknown State");
+ return buffer;
+}
+
+void TimeClient::disconnectClient()
+{
+ console->post(PmTime::DebugProtocol, "TimeClient::disconnectClient");
+ delete this;
+}
+
+bool TimeClient::writeClient(PmTime::Packet *packet,
+ char *tz, int tzlen, char *label, int llen)
+{
+ if (packet->source != my.source)
+ return true;
+
+ switch (my.state) {
+ case TimeClient::Disconnected:
+ return true;
+ case TimeClient::ClientConnectSET:
+ if (packet->command == PmTime::ACK) {
+ my.state = TimeClient::ServerConnectACK;
+ break;
+ }
+ return true;
+ case TimeClient::ServerConnectACK:
+ break;
+ case TimeClient::ClientReady:
+ if (packet->command == PmTime::Step) {
+ my.state = TimeClient::ServerNeedACK;
+ my.acktime = packet->position;
+ }
+ else {
+ my.state = TimeClient::ClientReady;
+ memset(&my.acktime, 0, sizeof(my.acktime));
+ }
+ break;
+ case TimeClient::ServerNeedACK:
+ if (packet->command != PmTime::Step) {
+ my.state = TimeClient::ClientReady; // clear NEED_ACK
+ memset(&my.acktime, 0, sizeof(my.acktime));
+ break;
+ }
+ console->post(PmTime::DebugProtocol, "TimeClient::writeClient "
+ "SKIP STEP to pos=%u.%u when client %p in NEED_ACK",
+ packet->position.tv_sec,packet->position.tv_usec, this);
+ return false;
+ }
+
+ int len = my.socket->write((const char *)packet, sizeof(PmTime::Packet));
+ if (len != sizeof(PmTime::Packet)) {
+ console->post(PmTime::DebugProtocol, "TimeCient::writeClient "
+ "wrote %d bytes not %d (%x command)",
+ len, packet->length, packet->command);
+ my.state = TimeClient::Disconnected;
+ endConnect(this);
+ } else {
+ console->post(PmTime::DebugProtocol, "TimeClient::writeClient "
+ "wrote %d bytes command=%x state=%u",
+ len, packet->command, my.state);
+ }
+ if (tzlen > 0 && len > 0 &&
+ (len = my.socket->write(tz, tzlen)) != tzlen) {
+ console->post(PmTime::DebugProtocol, "TimeClient::writeClient "
+ "wrote %d bytes not %d (timezone)", len, tzlen);
+ my.state = TimeClient::Disconnected;
+ endConnect(this);
+ } else if (tzlen) {
+ console->post(PmTime::DebugProtocol, "TimeClient::writeClient "
+ "wrote %d bytes of timezone successfully", len);
+ }
+ if (llen > 0 && len > 0 &&
+ (len = my.socket->write(label, llen)) != llen) {
+ console->post(PmTime::DebugProtocol, "TimeClient::writeClient "
+ "wrote %d bytes not %d (tz label)", len, llen);
+ my.state = TimeClient::Disconnected;
+ endConnect(this);
+ } else if (llen) {
+ console->post(PmTime::DebugProtocol, "TimeClient::writeClient "
+ "wrote %d bytes of tz label successfully", len);
+ }
+ return true;
+}
+
+void TimeClient::readClient(void)
+{
+ PmTime::Packet packet;
+ char *payload = NULL;
+ int bad = 0, len, sz;
+
+ console->post(PmTime::DebugProtocol, "Reading data from client %p", this);
+
+ len = my.socket->read((char *)&packet, sizeof(PmTime::Packet));
+ if (len < 0) {
+ console->post(PmTime::DebugProtocol, "Read error on client %p", this);
+ bad = 1;
+ } else if (packet.magic != PmTime::Magic) {
+ console->post(PmTime::DebugProtocol, "Bad magic (%x) from client %p",
+ packet.magic, this);
+ bad = 1;
+ } else if (len != sizeof(PmTime::Packet)) {
+ console->post(PmTime::DebugProtocol,
+ "Bad 1st read (want %d, got %d) on client %p",
+ len, sizeof(PmTime::Packet), this);
+ bad = 1;
+ } else if (packet.length > sizeof(PmTime::Packet)) {
+ sz = packet.length - sizeof(PmTime::Packet);
+ payload = (char *)malloc(sz);
+ if (payload == NULL) {
+ console->post(PmTime::DebugProtocol,
+ "No memory (%d) for second read on client %p",
+ sz, len, this);
+ bad = 1;
+ } else if ((len = my.socket->read(payload, sz)) != sz) {
+ console->post(PmTime::DebugProtocol,
+ "Bad 2nd read (want %d, got %d) on client %p",
+ sz, len, this);
+ bad = 1;
+ }
+ console->post(PmTime::DebugProtocol, "+%d message from client %p",
+ sz, this);
+ } else {
+ console->post(PmTime::DebugProtocol, "good message from client %p",
+ this);
+ }
+
+ if (!bad) {
+ console->post(PmTime::DebugProtocol, "state %s message %d",
+ stateString(my.state), packet.command);
+ switch(my.state) {
+ case TimeClient::Disconnected:
+ if (packet.command == PmTime::Set)
+ console->post(PmTime::DebugProtocol,
+ "%s got new SET from client %p",
+ __func__, this);
+ if (packet.source == PmTime::HostSource) {
+ my.source = PmTime::HostSource;
+ my.hc->setTime(&packet, payload);
+ } else {
+ my.source = PmTime::ArchiveSource;
+ my.ac->setTime(&packet, payload);
+ }
+ my.state = TimeClient::ClientConnectSET;
+ packet.command = PmTime::ACK;
+ packet.length = sizeof(PmTime::Packet);
+ writeClient(&packet);
+ return;
+
+ case TimeClient::ClientConnectSET:
+ console->post(PmTime::DebugProtocol, "TimeClient::readClient "
+ "bad client %p command %d in ConnectSET state",
+ this, packet.command);
+ break;
+
+ case TimeClient::ServerConnectACK:
+ if (packet.command == PmTime::ACK)
+ my.state = TimeClient::ClientReady;
+ break;
+
+ case TimeClient::ServerNeedACK:
+ if (packet.command != PmTime::ACK)
+ break;
+ if (packet.position.tv_sec == my.acktime.tv_sec &&
+ packet.position.tv_usec == my.acktime.tv_usec) {
+ console->post(PmTime::DebugProtocol, "TimeClient::readClient "
+ "good ACK client=%p (%u.%u)", this,
+ my.acktime.tv_sec, my.acktime.tv_usec);
+ my.state = TimeClient::ClientReady;
+ break;
+ }
+ console->post(PmTime::DebugProtocol, "TimeClient::readClient "
+ "BAD ACK client=%p (got %u.%u vs %u.%u)", this,
+ packet.position.tv_sec, packet.position.tv_usec,
+ my.acktime.tv_sec, my.acktime.tv_usec);
+ bad = 1;
+ break;
+
+ case TimeClient::ClientReady:
+ if (packet.command == PmTime::ACK) {
+ console->post(PmTime::DebugProtocol, "TimeClient:: readClient "
+ "unexpected client %p ACK in Ready state", this);
+ }
+ break;
+ }
+
+ switch(packet.command) {
+ case PmTime::GUIHide:
+ case PmTime::GUIShow:
+ console->post(PmTime::DebugProtocol, "TimeClient::readClient "
+ "HIDE/SHOW from client %p", this);
+ if (my.source == PmTime::HostSource)
+ my.hc->popup(packet.command == PmTime::GUIShow);
+ if (my.source == PmTime::ArchiveSource)
+ my.ac->popup(packet.command == PmTime::GUIShow);
+ break;
+ case PmTime::Bounds:
+ console->post(PmTime::DebugProtocol, "TimeClient::readClient "
+ "BOUNDS from client %p", this);
+ my.ac->addBound(&packet, payload);
+ break;
+ case PmTime::ACK:
+ break;
+ default:
+ console->post(PmTime::DebugProtocol, "TimeClient::readClient "
+ "unknown command %d from client %p",
+ packet.command, this);
+ bad = 1;
+ }
+ }
+
+ if (bad)
+ reset();
+}
+
+void TimeClient::reset()
+{
+ console->post(PmTime::DebugProtocol, "TimeClient::reset");
+#if 0
+ if (my.source == PmTime::HostSource)
+ my.hc->stop();
+ else
+ my.ac->stop();
+#endif
+}
+
+TimeLord::TimeLord(QApplication *app)
+{
+ my.ac = NULL;
+ my.hc = NULL;
+ connect(this, SIGNAL(lastClientExit()), app, SLOT(quit()));
+ connect(this, SIGNAL(lastClientExit()), this, SLOT(quit()));
+ connect(this, SIGNAL(newConnection()), SLOT(newConnection()));
+ console->post(PmTime::DebugProtocol, "TimeLord initialised");
+}
+
+void TimeLord::quit()
+{
+ if (my.ac)
+ my.ac->quit();
+ if (my.hc)
+ my.hc->quit();
+}
+
+void TimeLord::setContext(PmTimeLive *live, PmTimeArch *arch)
+{
+ my.hc = live;
+ connect(live, SIGNAL(timePulse(PmTime::Packet *)),
+ SLOT(timePulse(PmTime::Packet *)));
+ connect(live, SIGNAL(vcrModePulse(PmTime::Packet *, int)),
+ SLOT(vcrModePulse(PmTime::Packet *, int)));
+ connect(live, SIGNAL(tzPulse(PmTime::Packet *, char *, int, char *, int)),
+ SLOT(tzPulse(PmTime::Packet *, char *, int, char *, int)));
+ my.ac = arch;
+ connect(arch, SIGNAL(timePulse(PmTime::Packet *)),
+ SLOT(timePulse(PmTime::Packet *)));
+ connect(arch, SIGNAL(boundsPulse(PmTime::Packet *)),
+ SLOT(boundsPulse(PmTime::Packet *)));
+ connect(arch, SIGNAL(vcrModePulse(PmTime::Packet *, int)),
+ SLOT(vcrModePulse(PmTime::Packet *, int)));
+ connect(arch, SIGNAL(tzPulse(PmTime::Packet *, char *, int, char *, int)),
+ SLOT(tzPulse(PmTime::Packet *, char *, int, char *, int)));
+}
+
+void TimeLord::newConnection(void)
+{
+ TimeClient *c = new TimeClient(nextPendingConnection(), this);
+
+ console->post(PmTime::DebugProtocol, "Adding new client %p", c);
+ c->setContext(my.ac, my.hc);
+ connect(c, SIGNAL(endConnect(TimeClient *)),
+ SLOT(endConnect(TimeClient *)));
+ my.clientlist.append(c);
+}
+
+void TimeLord::endConnect(TimeClient *client)
+{
+ console->post(PmTime::DebugProtocol, "Removing client %p", client);
+ my.clientlist.removeAll(client);
+ if (my.clientlist.isEmpty()) {
+ console->post(PmTime::DebugProtocol, "No clients remain, exiting");
+ emit lastClientExit();
+ }
+}
+
+void TimeLord::timePulse(PmTime::Packet *packet)
+{
+ QList<TimeClient*> overrunClients;
+
+#if DESPERATE
+ static int sequence;
+ int localSequence = sequence++;
+ console->post(PmTime::DebugProtocol, "TimeLord::timePulse %d (%d clients)",
+ localSequence, my.clientlist.count());
+#endif
+
+ packet->magic = PmTime::Magic;
+ packet->length = sizeof(PmTime::Packet);
+ packet->command = PmTime::Step;
+ for (int i = 0; i < my.clientlist.size(); i++)
+ if (my.clientlist.at(i)->writeClient(packet) == false)
+ overrunClients.append(my.clientlist.at(i));
+ for (int i = 0; i < overrunClients.size(); i++)
+ overrunClients.at(i)->reset();
+
+#if DESPERATE
+ console->post(PmTime::DebugProtocol, "TimeLord::timePulse ended %d (%d)",
+ localSequence, overrunClients.size());
+#endif
+}
+
+void TimeLord::boundsPulse(PmTime::Packet *packet)
+{
+ console->post(PmTime::DebugProtocol, "TimeLord::boundsPulse (%d clients)",
+ my.clientlist.count());
+ packet->magic = PmTime::Magic;
+ packet->length = sizeof(PmTime::Packet);
+ packet->command = PmTime::Bounds;
+ for (int i = 0; i < my.clientlist.size(); i++)
+ my.clientlist.at(i)->writeClient(packet);
+}
+
+void TimeLord::vcrModePulse(PmTime::Packet *packet, int drag)
+{
+ console->post(PmTime::DebugProtocol, "TimeLord::vcrModePulse (%d clients)"
+ " %d", my.clientlist.count(), drag);
+ packet->magic = PmTime::Magic;
+ packet->length = sizeof(PmTime::Packet);
+ packet->command = drag ? PmTime::VCRModeDrag : PmTime::VCRMode;
+ for (int i = 0; i < my.clientlist.size(); i++)
+ my.clientlist.at(i)->writeClient(packet);
+}
+
+void TimeLord::tzPulse(PmTime::Packet *packet,
+ char *tz, int tzlen, char *l, int llen)
+{
+ console->post(PmTime::DebugProtocol, "TimeLord::tzPulse (%d clients)"
+ " - %s/%d/%d", my.clientlist.count(), tz, tzlen, llen);
+ packet->magic = PmTime::Magic;
+ packet->length = sizeof(PmTime::Packet) + tzlen + llen;
+ packet->command = PmTime::TZ;
+ for (int i = 0; i < my.clientlist.size(); i++)
+ my.clientlist.at(i)->writeClient(packet, tz, tzlen, l, llen);
+}
diff --git a/src/pmtime/timelord.h b/src/pmtime/timelord.h
new file mode 100644
index 0000000..31fedf9
--- /dev/null
+++ b/src/pmtime/timelord.h
@@ -0,0 +1,118 @@
+/*
+ * 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 TIMELORD_H
+#define TIMELORD_H
+
+#include <QtCore/QVariant>
+#include <QtCore/QTimer>
+#include <QtCore/QList>
+#include <QtCore/QTextStream>
+#include <QtNetwork/QTcpSocket>
+#include <QtNetwork/QTcpServer>
+#include <QtGui/QApplication>
+
+#include "console.h"
+#include "pmtimelive.h"
+#include "pmtimearch.h"
+
+// The TimeClient class provides a socket that is connected with a client.
+// For every client that connects to the server, the server creates a new
+// instance of this class.
+//
+class TimeClient : public QObject
+{
+ Q_OBJECT
+
+public:
+ // State transitions for a pmtime client. Basic SET/ACK protocol is:
+ // - client connects and sends initial (global) SET
+ // - server responds with ACK (beware live mode, with timers SETs here)
+ // - server now sends SETs with optional ACKs, until first ACK recv'd
+ // - after first ACK recv'd by server, all subsequent SETs must be ACK'd.
+ // The other messages can be sent/recv'd any time after the server has
+ // ACK'd the initial connection.
+ //
+ typedef enum {
+ Disconnected = 1,
+ ClientConnectSET,
+ ServerConnectACK,
+ ServerNeedACK,
+ ClientReady,
+ } State;
+
+public:
+ TimeClient(QTcpSocket *socket, QObject *parent);
+ ~TimeClient();
+ void reset();
+
+ void setContext(PmTimeArch *ac, PmTimeLive *hc) { my.ac = ac; my.hc = hc; }
+ bool writeClient(PmTime::Packet *k, char *tz = NULL, int tzlen = 0,
+ char *label = NULL, int llen = 0);
+
+signals:
+ void endConnect(TimeClient *);
+
+public slots:
+ void readClient();
+ void disconnectClient();
+
+private:
+ struct {
+ QTcpSocket *socket;
+ TimeClient::State state;
+ PmTime::Source source;
+ struct timeval acktime; // time position @ last STEP
+ PmTimeLive *hc;
+ PmTimeArch *ac;
+ } my;
+};
+
+// The TimeLord class is a QTcpServer which randomly travels the space-
+// time continuim, servicing and connecting up clients with the server;
+// it also hooks up logging of the action to the wide-screen console in
+// the Tardis.
+//
+// For each client that connects it creates a new TimeClient (maintained
+// in a QList) - the new instance is responsible for communication with
+// that TCP client.
+//
+class TimeLord : public QTcpServer
+{
+ Q_OBJECT
+
+public:
+ TimeLord(QApplication *app);
+ void setContext(PmTimeLive *live, PmTimeArch *archive);
+
+signals:
+ void lastClientExit();
+
+public slots:
+ void quit();
+ void newConnection();
+ void endConnect(TimeClient *client);
+ void timePulse(PmTime::Packet *k);
+ void boundsPulse(PmTime::Packet *k);
+ void vcrModePulse(PmTime::Packet *k, int drag);
+ void tzPulse(PmTime::Packet *k, char *t, int tlen, char *l, int llen);
+
+private:
+ struct {
+ PmTimeLive *hc;
+ PmTimeArch *ac;
+ QList<TimeClient*> clientlist;
+ } my;
+};
+
+#endif // TIMELORD_H
diff --git a/src/pmtime/timezone.h b/src/pmtime/timezone.h
new file mode 100644
index 0000000..2b8ea32
--- /dev/null
+++ b/src/pmtime/timezone.h
@@ -0,0 +1,52 @@
+/*
+ * 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 TIMEZONE_H
+#define TIMEZONE_H
+
+#include <string.h>
+#include <QtGui/QAction>
+
+class TimeZone
+{
+public:
+ TimeZone(char *name, char *label, QAction *action, int handle)
+ {
+ my.name = name;
+ my.label = label;
+ my.action = action;
+ my.handle = handle;
+ }
+
+ ~TimeZone()
+ {
+ if (my.name) free(my.name);
+ if (my.label) free(my.label);
+ if (my.action) delete my.action;
+ }
+
+ char *tz(void) { return my.name; }
+ char *tzlabel(void) { return my.label; }
+ int handle(void) { return my.handle; }
+ QAction *action(void) { return my.action; }
+
+private:
+ struct {
+ char *name;
+ char *label;
+ int handle;
+ QAction *action;
+ } my;
+};
+
+#endif // TIMEZONE_H