--- /dev/null
+# This file provides information about the External dependencies required by
+# Bacula.
+#
+# There are four fields delimited by |. Only the first two fields are
+# required. The other two are used when the top level directory of the
+# archive is not the same as the file name with any suffixes removed.
+#
+# Field 1 is the name of the dependency. It is used to define the
+# name of the three variables which are assigned the values of fields 2 to 4.
+#
+# Field 2 is the URL of the archive. It is assigned to the variable
+# URL_[field1].
+#
+# Field 3 is the top directory of the archive or the name of a directory that
+# must be created and the archive extracted into it. It is assigned to the
+# variable DIR_[field1].
+#
+# Field 4 indicates if the directory specified in field 3 must be created
+# first and the archive extracted into it. It is assigned to the variable
+# MKD_[field1]
+#
+QWT|http://www.bacula.org/depkgs/qwt-5.0.2.tar.bz2|qwt-5.0.2|1
+#
+# Original location
+#
+#QWT|http://superb-west.dl.sourceforge.net/sourceforge/qwt/qwt-5.0.2.tar.bz2|qwt-5.0.2|1
If you want to build it, you need Qt4 loaded and setup as your
default Qt or with the appropriate Qt Environment variables set.
+6/24/07
+There is now one dependancy, it is qwt. It compiles just fine with
+either qwt-5.0.2 or qwt-5.0.1. If you run the command
+
+ ./build-depkgs-qt-console
+
+It should download and run the appropriate commands to build and install qwt
+for you. The script will download the package into a subdirectory named
+depkgs. Then it will configure, make and install qwt. The installation will
+go into a subdirectory named qwt in the main qt-console directory.
+
To build bat, you simply enter:
qmake
Design decisions:
- If possible all code for a particular component will be kept in
- and appropriate subdirectory.
+ an appropriate subdirectory.
- All private class variables are named "m_xxx" this makes it very
clear if one is referencing a class variable or a local.
- All signal/slots are connected by explict code (most all are
========================================================
This release or next:
-A window showing a list of schedule resources.
+A page showing a list of schedule resources.
-A list of message resources??
+A page list of message resources??
Kern discussed windows showing statistics like web based interfaces.
Add a status client window. Keep updating showing what file is being
processed.
+Documentation, Documentation, Documentaion. Help. Add help documentation.
+Have context sensitve help.
+
bRestore add code to get working.
May be in brestore, find a file by name, find a directory by name
+Interfaces to commands like bextract, bscan, bcopy, btape?????
+
Is there a way to query the director/database for whether a storage is currently
mounted so I am not presenting both mount and unmount to the user??
Yes, but it requires being able to directly connect to the SD (at least
TARGET = bat
DEPENDPATH += .
INCLUDEPATH += . ./console ./restore ./select
-INCLUDEPATH += ..
-LIBS += -L../lib
+INCLUDEPATH += .. ./qwt/include
+LIBS += -L../lib
LIBS += -lbac
LIBS += -lssl -lcrypto
+LIBS += -L./qwt/lib -lqwt
RESOURCES = main.qrc
MOC_DIR = moc
OBJECTS_DIR = obj
FORMS += clients/clients.ui storage/storage.ui fileset/fileset.ui
FORMS += joblog/joblog.ui jobs/jobs.ui
FORMS += help/help.ui
+FORMS += jobgraphs/jobplotcontrols.ui
HEADERS += mainwin.h bat.h bat_conf.h qstd.h
SOURCES += main.cpp bat_conf.cpp mainwin.cpp qstd.cpp
HEADERS += restore/restoretree.h
SOURCES += restore/restoretree.cpp
+## Job Step Graphs
+HEADERS += jobgraphs/jobplot.h
+SOURCES += jobgraphs/jobplot.cpp
# Help dialog
HEADERS += help/help.h
--- /dev/null
+#!/bin/sh
+#
+# This file is driven by the parameters that are defined in
+# the file External-qt-console
+#
+
+usage()
+{
+ echo "usage: $0 [-h] [-C] [<dependency 1>] [<dependency 2>] ..."
+ echo " -h Displays this usage"
+ echo " -C Clobbers (overwrites) the source code by "
+ echo " reextracting the archive and reapplying the"
+ echo " patches."
+ echo ""
+ echo "<dependency N> Optional dependency, If none are given then all"
+ echo " of them will be built."
+ echo ""
+ echo "Valid dependencies are:"
+ grep -v '^#' < External-qt-console | cut -d'|' -f1 | cut -d'_' -f1 | tr A-Z a-z | sort -u | awk '{ print " " $1 }'
+}
+
+CLOBBER_SOURCE=
+
+while getopts "hHC" opt; do
+ case ${opt} in
+ H|h|\?) usage;exit 1;;
+ C) CLOBBER_SOURCE=true;;
+ esac
+done
+
+[ ${OPTIND} -gt 1 ] && shift `expr ${OPTIND} - 1`
+
+cwd=`pwd`
+cd `dirname $0`
+SCRIPT_DIR=`pwd`
+
+TOP_DIR=`pwd`
+
+[ ! -e ${TOP_DIR}/depkgs ] && mkdir ${TOP_DIR}/depkgs
+cd ${TOP_DIR}/depkgs
+DEPPKG_DIR=`pwd`
+
+OLD_IFS=${IFS};IFS="|";
+while read package url dir mkd; do
+ case ${package} in
+ \#*) ;;
+ *) eval "URL_${package}=${url};DIR_${package}=${dir};MKD_${package}=${mkd}";;
+ esac
+done < ${SCRIPT_DIR}/External-qt-console
+IFS=${OLD_IFS};unset OLD_IFS
+
+get_source()
+{
+ URL=$1
+ SRC_DIR=$2
+ MAKE_DIR=$3
+ ARCHIVE=`basename ${URL}`
+echo "in get_source URL is $URL SRC_DIR is $SRC_DIR MAKE_DIR is $MAKE_DIR ARCHIVE is $ARCHIVE"
+
+ case ${ARCHIVE} in
+ *.tar.gz) ARCHIVER="tar xzf"; [ -z "${SRC_DIR}" ] && SRC_DIR=`expr "${ARCHIVE}" : '\(.*\)\.tar\.gz'`;;
+ *.tar.bz2) ARCHIVER="tar xjf"; [ -z "${SRC_DIR}" ] && SRC_DIR=`expr "${ARCHIVE}" : '\(.*\)\.tar\.bz2'`;;
+ *.zip) ARCHIVER="unzip -q"; [ -z "${SRC_DIR}" ] && SRC_DIR=`expr "${ARCHIVE}" : '\(.*\)\.zip'`;;
+ *.exe) ARCHIVER=""; [ -z "${SRC_DIR}" ] && SRC_DIR=`expr "${ARCHIVE}" : '\(.*\)\.zip'`;;
+ *) echo "Unsupported archive type - $ARCHIVE"; exit 1;;
+ esac
+
+ cd ${DEPPKG_DIR}/src
+
+ if [ ! -e "${ARCHIVE}" ]
+ then
+ echo "Downloading ${URL}"
+ if wget --passive-ftp "${URL}"
+ then
+ :
+ else
+ echo "Unable to download ${ARCHIVE}"
+ exit 1
+ fi
+ fi
+
+ [ -z "${ARCHIVER}" ] && return 0
+
+ if [ ! -e "${SRC_DIR}" -o "${CLOBBER_SOURCE}" = "true" ]
+ then
+ rm -rf ${SRC_DIR}
+ echo "Extracting ${ARCHIVE}"
+ if [ "${MAKE_DIR}" = "true" ]
+ then
+ mkdir ${SRC_DIR}
+ cd ${SRC_DIR}
+ ${ARCHIVER} ../${ARCHIVE} > ../${ARCHIVE}.log 2>&1
+ else
+ ${ARCHIVER} ${ARCHIVE} > ${ARCHIVE}.log 2>&1
+ cd ${SRC_DIR}
+ fi
+ return 0
+ fi
+
+ cd ${SRC_DIR}
+ return 1
+}
+
+parse_output()
+{
+ sed -ne '/\\$/N' -e 's/\\\n//' -e 's/\t\+/ /g' -e 's/ \+/ /g' \
+ -e '/ error: /p' \
+ -e "s%.*Entering directory[ ]\\+.${DEPPKG_DIR}/\\([^ ]\+\).%Entering \\1%p" \
+ -e "s%.*Leaving directory[ ]\\+.${DEPPKG_DIR}/\\([^ ]\+.\).%Leaving \\1%p" \
+ -e '/gcc \|g\+\+ \|ar /!d' \
+ -e 's/ \(\.\.\/\)\+/ /g' \
+ -e 's/.* \([^ ]\+\(\.c\|\.cpp\|\.cc\|\.cxx\)\)\( .*\|\)$/Compiling \1/p' \
+ -e 's/.* \([^ ]\+\.s\)\( .*\|\)$/Assembling \1/p' \
+ -e 's/.*ar [^ ]\+ \([^ ]\+\)\(\( [^ ]\+\.o\)\+\)/Updating \1 -\2/p' \
+ -e 's/.* -o \([^ ]\+\)\( .*\|\)$/Linking \1/p'
+}
+
+do_patch()
+{
+ PATCH_FILE=${SCRIPT_DIR}/patches/$1; shift
+
+ if patch -f -p0 "$@" >>patch.log < ${PATCH_FILE}
+ then
+ :
+ else
+ echo "Patch failed - Check `pwd`/patch.log" > /dev/tty
+ exit 1
+ fi
+}
+
+do_make()
+{
+ if make -f "$@" 2>&1
+ then
+ :
+ else
+ echo "Make failed - Check `pwd`/make.log" > /dev/tty
+ exit 1
+ fi | tee -a make.log #| parse_output
+}
+
+process_qwt()
+{
+ get_source "${URL_QWT}" "${DIR_QWT}" "${MKD_QWT}"
+ echo "Building qwt"
+ echo "${DEPPKG_DIR}"
+ pwd
+ > make.log
+ echo "unix {" >${TOP_DIR}/depkgs/qwt-5.0.2/qwtconfig.pri
+ echo " INSTALLBASE = ${TOP_DIR}/qwt" >>${TOP_DIR}/depkgs/qwt-5.0.2/qwtconfig.pri
+ echo "}" >>${TOP_DIR}/depkgs/qwt-5.0.2/qwtconfig.pri
+ cat ${TOP_DIR}/qwtconfig.pri >>${TOP_DIR}/depkgs/qwt-5.0.2/qwtconfig.pri
+ qmake
+ do_make Makefile
+ echo "Installing"
+ do_make Makefile install
+}
+
+if [ "$#" -eq 0 ]
+then
+ process_qwt
+else
+ for dependency in "$@"
+ do
+ eval "process_${dependency}"
+ done
+
+fi
QString cmd("reload");
consoleCommand(cmd);
}
+
+/* Function to get a list of volumes */
+void Console::getVolumeList(QStringList &volumeList)
+{
+ QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
+ if (mainWin->m_sqlDebug) {
+ Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
+ }
+ QStringList results;
+ if (sql_cmd(query, results)) {
+ QString field;
+ QStringList fieldlist;
+ /* Iterate through the lines of results. */
+ foreach (QString resultline, results) {
+ fieldlist = resultline.split("\t");
+ volumeList.append(fieldlist[0]);
+ } /* foreach resultline */
+ } /* if results from query */
+}
+
+/* Function to get a list of volumes */
+void Console::getStatusList(QStringList &statusLongList)
+{
+ QString statusQuery("SELECT JobStatusLong FROM Status");
+ if (mainWin->m_sqlDebug) {
+ Pmsg1(000, "Query cmd : %s\n",statusQuery.toUtf8().data());
+ }
+ QStringList statusResults;
+ if (sql_cmd(statusQuery, statusResults)) {
+ QString field;
+ QStringList fieldlist;
+ /* Iterate through the lines of results. */
+ foreach (QString resultline, statusResults) {
+ fieldlist = resultline.split("\t");
+ statusLongList.append(fieldlist[0]);
+ } /* foreach resultline */
+ } /* if results from statusquery */
+}
void getDirResName(QString &);
void startTimer();
void stopTimer();
+ void getVolumeList(QStringList &);
+ void getStatusList(QStringList &);
QStringList job_list;
QStringList client_list;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg1306"
+ sodipodi:version="0.32"
+ inkscape:version="0.43"
+ sodipodi:docbase="/home/dbartley/src/bacula/src/qt-console/images"
+ sodipodi:docname="graph1.svg"
+ inkscape:export-filename="/home/dbartley/src/bacula/src/qt-console/images/graph1.png"
+ inkscape:export-xdpi="60"
+ inkscape:export-ydpi="60">
+ <defs
+ id="defs1308">
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5031"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5060">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5062" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5064" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5029"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ id="linearGradient5048">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop5050" />
+ <stop
+ id="stop5056"
+ offset="0.5"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5052" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5048"
+ id="linearGradient5027"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
+ x1="302.85715"
+ y1="366.64789"
+ x2="302.85715"
+ y2="609.50507" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2223">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2225" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2229" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2222">
+ <stop
+ style="stop-color:#5187d6;stop-opacity:1;"
+ offset="0"
+ id="stop2224" />
+ <stop
+ style="stop-color:#1e4580;stop-opacity:1;"
+ offset="1"
+ id="stop2227" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3090">
+ <stop
+ style="stop-color:#626c07;stop-opacity:1;"
+ offset="0"
+ id="stop3092" />
+ <stop
+ style="stop-color:#313603;stop-opacity:1;"
+ offset="1"
+ id="stop3094" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2238">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2240" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2242" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2224">
+ <stop
+ style="stop-color:#32342f;stop-opacity:0.54639173;"
+ offset="0.0000000"
+ id="stop2226" />
+ <stop
+ style="stop-color:#32342f;stop-opacity:0;"
+ offset="1"
+ id="stop2228" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2214">
+ <stop
+ style="stop-color:#a9aaa7;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2216" />
+ <stop
+ style="stop-color:#676964;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2218" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2206">
+ <stop
+ style="stop-color:#c3c6c0;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2208" />
+ <stop
+ style="stop-color:#e8eae6;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2210" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2198">
+ <stop
+ style="stop-color:#32342f;stop-opacity:1;"
+ offset="0"
+ id="stop2200" />
+ <stop
+ style="stop-color:#171816;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2202" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2180">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2182" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2184" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2206"
+ id="linearGradient2212"
+ x1="25.861118"
+ y1="26.133587"
+ x2="18.300278"
+ y2="19.567596"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.952387,0.000000,0.000000,1.018339,1.142599,-1.941627)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2214"
+ id="linearGradient2220"
+ x1="0.0012142062"
+ y1="24.012266"
+ x2="47.998765"
+ y2="24.012266"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.952387,0.000000,0.000000,1.018339,1.142599,-1.941627)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2224"
+ id="radialGradient2230"
+ cx="24.041630"
+ cy="42.242130"
+ fx="24.041630"
+ fy="42.242130"
+ r="17.576654"
+ gradientTransform="matrix(1.000000,0.000000,0.000000,0.304598,-5.757924e-16,29.37527)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2238"
+ id="linearGradient2244"
+ x1="20.338758"
+ y1="19.636894"
+ x2="46.092255"
+ y2="39.708324"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.952387,0.000000,0.000000,1.015657,1.142599,-0.876325)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2180"
+ id="linearGradient1340"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.809547,0.000000,0.000000,1.750325,-16.00036,-15.78719)"
+ x1="8.8207808"
+ y1="12.53757"
+ x2="12.499243"
+ y2="24.238262" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2222"
+ id="radialGradient2229"
+ cx="23.994133"
+ cy="32.266911"
+ fx="23.994133"
+ fy="32.266911"
+ r="19.088932"
+ gradientTransform="matrix(2.15837,-3.097402e-23,1.894086e-23,2.190642,-27.7082,-31.42032)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2223"
+ id="linearGradient2231"
+ x1="35.694206"
+ y1="37.333858"
+ x2="15.044075"
+ y2="5.9588566"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.021281,0,0,1.303897,-8.127563e-2,-1.256846)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2180"
+ id="linearGradient1378"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.809547,0,0,1.750325,-16.00036,-15.78719)"
+ x1="8.8207808"
+ y1="12.53757"
+ x2="12.499243"
+ y2="24.238262" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.25490196"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.645833"
+ inkscape:cx="24"
+ inkscape:cy="23.64158"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1064"
+ inkscape:window-height="724"
+ inkscape:window-x="55"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false"
+ fill="#204a87" />
+ <metadata
+ id="metadata1311">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>System Monitor</dc:title>
+ <dc:date>2005-10-10</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>system</rdf:li>
+ <rdf:li>monitor</rdf:li>
+ <rdf:li>performance</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <rect
+ style="opacity:1;fill:url(#radialGradient2229);fill-opacity:1;fill-rule:evenodd;stroke:#173562;stroke-width:1.38827848;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect1314"
+ width="45.370602"
+ height="45.727844"
+ x="1.3947006"
+ y="1.3883106"
+ rx="1.6946707"
+ ry="1.694671" />
+ <g
+ id="g1372"
+ transform="matrix(1,0,0,1.49637,0,-5.262305)">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccc"
+ id="path2188"
+ d="M 12.390689,20.935247 L 6.3688614,20.935247 L 6.3688614,22.152253 L 14.087646,22.152253 L 15.493568,16.239132 L 18.956082,29.936652 L 22.164804,19.116952 L 25.059348,25.028755 L 28.946308,21.516786 L 41.654736,21.516786 L 41.654736,19.457141 L 28.505235,19.457141 L 25.335019,22.596741 L 22.059557,15.937588 L 19.049723,24.112486 L 15.78119,11.248712 L 12.390689,20.935247 z "
+ style="opacity:1;fill:#ecffd9;fill-opacity:1;fill-rule:evenodd;stroke:#c3ea9b;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:0.41618497" />
+ <g
+ id="g1366">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccc"
+ id="path3088"
+ d="M 11.515689,20.012278 L 6.3688614,20.012278 L 6.3688614,23.061029 L 14.962646,22.936029 L 15.618568,19.893387 L 18.963229,32.601726 L 22.539804,21.135091 L 25.059348,26.551191 L 29.321308,22.442609 L 41.654736,22.317609 L 40.904736,18.408071 L 28.505235,18.283071 L 25.460019,21.456026 L 22.059557,13.665616 L 19.424723,20.604266 L 15.90619,8.333659 L 11.515689,20.012278 z "
+ style="opacity:0.38068183;fill:#ecffd9;fill-opacity:1;fill-rule:evenodd;stroke:#c3ea9b;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.41618497" />
+ <path
+ style="opacity:0.43181817;fill:url(#linearGradient1378);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="M 6.84375,6.96875 L 6.84375,15.795073 C 10.513653,16.483179 14.582567,16.875 18.875,16.875 C 27.810295,16.875 35.812258,15.21019 41.15625,12.596829 L 41.15625,6.96875 L 6.84375,6.96875 z "
+ id="rect2178"
+ sodipodi:nodetypes="ccsccc" />
+ </g>
+ </g>
+ <rect
+ ry="2.5696716"
+ rx="2.5696716"
+ y="4.7877154"
+ x="4.3298464"
+ height="39.959457"
+ width="40.187263"
+ id="rect2221"
+ style="opacity:0.57386361;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2231);stroke-width:1.15396917;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ </g>
+</svg>
--- /dev/null
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+
+ The main author of Bacula is Kern Sibbald, with contributions from
+ many others, a complete list can be found in the file AUTHORS.
+ This program is Free Software; you can redistribute it and/or
+ modify it under the terms of version two of the GNU General Public
+ License as published by the Free Software Foundation and included
+ in the file LICENSE.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Bacula® is a registered trademark of John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
+
+/*
+ * Version $Id: jobplot.cpp 4230 2007-02-21 20:07:37Z kerns $
+ *
+ * JobPlots Class
+ *
+ * Dirk Bartley, March 2007
+ *
+ */
+
+#include <QtGui>
+#include "bat.h"
+#include "jobgraphs/jobplot.h"
+
+
+JobPlotPass::JobPlotPass()
+{
+ use = false;
+}
+
+JobPlotPass& JobPlotPass::operator=(const JobPlotPass &cp)
+{
+ use = cp.use;
+ recordLimitCheck = cp.recordLimitCheck;
+ daysLimitCheck = cp.daysLimitCheck;
+ recordLimitSpin = cp.recordLimitSpin;
+ daysLimitSpin = cp.daysLimitSpin;
+ jobCombo = cp.jobCombo;
+ clientCombo = cp.clientCombo;
+ volumeCombo = cp.volumeCombo;
+ fileSetCombo = cp.fileSetCombo;
+ purgedCombo = cp.purgedCombo;
+ levelCombo = cp.levelCombo;
+ statusCombo = cp.statusCombo;
+ return *this;
+}
+
+/*
+ * Constructor for the controls class which inherits QScrollArea and a ui header
+ */
+JobPlotControls::JobPlotControls()
+{
+ setupUi(this);
+}
+
+/*
+ * Constructor, this class does not inherit anything but pages.
+ */
+JobPlot::JobPlot(QTreeWidgetItem *parentTreeWidgetItem, JobPlotPass &passVals)
+{
+ setupUserInterface();
+ m_name = "Job Plot";
+ pgInitialize(parentTreeWidgetItem);
+ readSplitterSettings();
+ QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
+ thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/graph1.png")));
+ m_drawn = false;
+
+ /* this invokes the pass values = operator function */
+ m_pass = passVals;
+ m_closeable = true;
+ dockPage();
+ /* If the values of the controls are predetermined (from joblist), then set
+ * this class as current window at the front of the stack */
+ if (m_pass.use)
+ setCurrent();
+ m_jobPlot->replot();
+}
+
+/*
+ * Kill, crush Destroy
+ */
+JobPlot::~JobPlot()
+{
+ writeSettings();
+ m_pjd.clear();
+}
+
+/*
+ * This is called when the page selector has this page selected
+ */
+void JobPlot::currentStackItem()
+{
+ if (!m_drawn) {
+ setupControls();
+ reGraph();
+ m_drawn=true;
+ }
+
+}
+
+/*
+ * Slot for the refrehs push button, also called from constructor.
+ */
+void JobPlot::reGraph()
+{
+ /* clear m_pjd */
+ m_pjd.clear();
+ runQuery();
+ m_jobPlot->clear();
+ addCurve();
+ m_jobPlot->replot();
+}
+
+/*
+ * Setup the control widgets for the graph, this are the objects from JobPlotControls
+ */
+void JobPlot::setupControls()
+{
+ QStringList graphType = QStringList() << /* "Fitted" <<*/ "Sticks" << "Lines" << "Steps" << "None";
+ controls->plotTypeCombo->addItems(graphType);
+ QStringList symbolType = QStringList() << "Ellipse" << "Rect" << "Diamond" << "Triangle"
+ << "DTrianle" << "UTriangle" << "LTriangle" << "RTriangle" << "Cross" << "XCross"
+ << "HLine" << "Vline" << "Star1" << "Star2" << "Hexagon" << "None";
+ controls->fileSymbolTypeCombo->addItems(symbolType);
+ controls->byteSymbolTypeCombo->addItems(symbolType);
+ readControlSettings();
+
+ controls->fileCheck->setCheckState(Qt::Checked);
+ controls->byteCheck->setCheckState(Qt::Checked);
+ connect(controls->plotTypeCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(setPlotType(QString)));
+ connect(controls->fileSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setFileSymbolType(int)));
+ connect(controls->byteSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setByteSymbolType(int)));
+ connect(controls->fileCheck, SIGNAL(stateChanged(int)), this, SLOT(fileCheckChanged(int)));
+ connect(controls->byteCheck, SIGNAL(stateChanged(int)), this, SLOT(byteCheckChanged(int)));
+ connect(controls->refreshButton, SIGNAL(pressed()), this, SLOT(reGraph()));
+
+ controls->clientComboBox->addItem("Any");
+ controls->clientComboBox->addItems(m_console->client_list);
+
+ QStringList volumeList;
+ m_console->getVolumeList(volumeList);
+ controls->volumeComboBox->addItem("Any");
+ controls->volumeComboBox->addItems(volumeList);
+ controls->jobComboBox->addItem("Any");
+ controls->jobComboBox->addItems(m_console->job_list);
+ controls->levelComboBox->addItem("Any");
+ controls->levelComboBox->addItems( QStringList() << "F" << "D" << "I");
+ controls->purgedComboBox->addItem("Any");
+ controls->purgedComboBox->addItems( QStringList() << "0" << "1");
+ controls->fileSetComboBox->addItem("Any");
+ controls->fileSetComboBox->addItems(m_console->fileset_list);
+ QStringList statusLongList;
+ m_console->getStatusList(statusLongList);
+ controls->statusComboBox->addItem("Any");
+ controls->statusComboBox->addItems(statusLongList);
+
+ if (m_pass.use) {
+ controls->limitCheckBox->setCheckState(m_pass.recordLimitCheck);
+ controls->limitSpinBox->setValue(m_pass.recordLimitSpin);
+ controls->daysCheckBox->setCheckState(m_pass.daysLimitCheck);
+ controls->daysSpinBox->setValue(m_pass.daysLimitSpin);
+ int jobIndex = controls->jobComboBox->findText(m_pass.jobCombo, Qt::MatchExactly);
+ if (jobIndex != -1)
+ controls->jobComboBox->setCurrentIndex(jobIndex);
+ int clientIndex = controls->clientComboBox->findText(m_pass.clientCombo, Qt::MatchExactly);
+ if (clientIndex != -1)
+ controls->clientComboBox->setCurrentIndex(clientIndex);
+ int volumeIndex = controls->volumeComboBox->findText(m_pass.volumeCombo, Qt::MatchExactly);
+ if (volumeIndex != -1)
+ controls->volumeComboBox->setCurrentIndex(volumeIndex);
+ int filesetIndex = controls->fileSetComboBox->findText(m_pass.fileSetCombo, Qt::MatchExactly);
+ if (filesetIndex != -1)
+ controls->fileSetComboBox->setCurrentIndex(filesetIndex);
+ int purgedIndex = controls->purgedComboBox->findText(m_pass.purgedCombo, Qt::MatchExactly);
+ if (purgedIndex != -1)
+ controls->purgedComboBox->setCurrentIndex(purgedIndex);
+ int levelIndex = controls->levelComboBox->findText(m_pass.levelCombo, Qt::MatchExactly);
+ if (levelIndex != -1)
+ controls->levelComboBox->setCurrentIndex(levelIndex);
+ int statusIndex = controls->statusComboBox->findText(m_pass.statusCombo, Qt::MatchExactly);
+ if (statusIndex != -1)
+ controls->statusComboBox->setCurrentIndex(statusIndex);
+ } else {
+ /* Set Defaults for check and spin for limits */
+ controls->limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
+ controls->limitSpinBox->setValue(mainWin->m_recordLimitVal);
+ controls->daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
+ controls->daysSpinBox->setValue(mainWin->m_daysLimitVal);
+ }
+}
+
+/*
+ * Setup the control widgets for the graph, this are the objects from JobPlotControls
+ */
+void JobPlot::runQuery()
+{
+ /* Set up query */
+ QString query("");
+ query += "SELECT DISTINCT "
+ " Job.Starttime AS JobStart,"
+ " Job.Jobfiles AS FileCount,"
+ " Job.JobBytes AS Bytes,"
+ " Job.JobId AS JobId"
+ " FROM Job"
+ " LEFT OUTER JOIN Client ON (Client.ClientId=Job.ClientId)"
+ " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId)"
+ " LEFT OUTER JOIN Status ON (Job.JobStatus=Status.JobStatus)"
+ " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId)"
+ " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId)";
+ QStringList conditions;
+ int jobIndex = controls->jobComboBox->currentIndex();
+ if ((jobIndex != -1) && (controls->jobComboBox->itemText(jobIndex) != "Any"))
+ conditions.append("Job.Name='" + controls->jobComboBox->itemText(jobIndex) + "'");
+ int clientIndex = controls->clientComboBox->currentIndex();
+ if ((clientIndex != -1) && (controls->clientComboBox->itemText(clientIndex) != "Any"))
+ conditions.append("Client.Name='" + controls->clientComboBox->itemText(clientIndex) + "'");
+ int volumeIndex = controls->volumeComboBox->currentIndex();
+ if ((volumeIndex != -1) && (controls->volumeComboBox->itemText(volumeIndex) != "Any"))
+ conditions.append("Media.VolumeName='" + controls->volumeComboBox->itemText(volumeIndex) + "'");
+ int fileSetIndex = controls->fileSetComboBox->currentIndex();
+ if ((fileSetIndex != -1) && (controls->fileSetComboBox->itemText(fileSetIndex) != "Any"))
+ conditions.append("FileSet.FileSet='" + controls->fileSetComboBox->itemText(fileSetIndex) + "'");
+ int purgedIndex = controls->purgedComboBox->currentIndex();
+ if ((purgedIndex != -1) && (controls->purgedComboBox->itemText(purgedIndex) != "Any"))
+ conditions.append("Job.PurgedFiles='" + controls->purgedComboBox->itemText(purgedIndex) + "'");
+ int levelIndex = controls->levelComboBox->currentIndex();
+ if ((levelIndex != -1) && (controls->levelComboBox->itemText(levelIndex) != "Any"))
+ conditions.append("Job.Level='" + controls->levelComboBox->itemText(levelIndex) + "'");
+ int statusIndex = controls->statusComboBox->currentIndex();
+ if ((statusIndex != -1) && (controls->statusComboBox->itemText(statusIndex) != "Any"))
+ conditions.append("Status.JobStatusLong='" + controls->statusComboBox->itemText(statusIndex) + "'");
+ /* If Limit check box For limit by days is checked */
+ if (controls->daysCheckBox->checkState() == Qt::Checked) {
+ QDateTime stamp = QDateTime::currentDateTime().addDays(-controls->daysSpinBox->value());
+ QString since = stamp.toString(Qt::ISODate);
+ conditions.append("Job.Starttime>'" + since + "'");
+ }
+ bool first = true;
+ foreach (QString condition, conditions) {
+ if (first) {
+ query += " WHERE " + condition;
+ first = false;
+ } else {
+ query += " AND " + condition;
+ }
+ }
+ /* Descending */
+ query += " ORDER BY Job.Starttime DESC, Job.JobId DESC";
+ /* If Limit check box for limit records returned is checked */
+ if (controls->limitCheckBox->checkState() == Qt::Checked) {
+ QString limit;
+ limit.setNum(controls->limitSpinBox->value());
+ query += " LIMIT " + limit;
+ }
+
+ if (mainWin->m_sqlDebug) {
+ Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
+ }
+ QString resultline;
+ QStringList results;
+ if (m_console->sql_cmd(query, results)) {
+
+ QString field;
+ QStringList fieldlist;
+
+ int row = 0;
+ /* Iterate through the record returned from the query */
+ foreach (resultline, results) {
+ PlotJobData *plotJobData = new PlotJobData();
+ fieldlist = resultline.split("\t");
+ int column = 0;
+ QString statusCode("");
+ /* Iterate through fields in the record */
+ foreach (field, fieldlist) {
+ field = field.trimmed(); /* strip leading & trailing spaces */
+ if (column == 0) {
+ plotJobData->dt = QDateTime::fromString(field, mainWin->m_dtformat);
+ } else if (column == 1) {
+ plotJobData->files = field.toDouble();
+ } else if (column == 2) {
+ plotJobData->bytes = field.toDouble();
+ }
+ column++;
+ m_pjd.prepend(plotJobData);
+ }
+ row++;
+ }
+ }
+ if ((controls->volumeComboBox->itemText(volumeIndex) != "Any") && (results.count() == 0)){
+ /* for context sensitive searches, let the user know if there were no
+ * * results */
+ QMessageBox::warning(this, tr("Bat"),
+ tr("The Jobs query returned no results.\n"
+ "Press OK to continue?"), QMessageBox::Ok );
+ }
+}
+
+/*
+ * The user interface that used to be in the ui header. I wanted to have a
+ * scroll area which is not in designer.
+ */
+void JobPlot::setupUserInterface()
+{
+ QSizePolicy sizePolicy(static_cast<QSizePolicy::Policy>(1), static_cast<QSizePolicy::Policy>(5));
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setVerticalPolicy(QSizePolicy::Ignored);
+ sizePolicy.setHorizontalPolicy(QSizePolicy::Ignored);
+ m_gridLayout = new QGridLayout(this);
+ m_gridLayout->setSpacing(6);
+ m_gridLayout->setMargin(9);
+ m_gridLayout->setObjectName(QString::fromUtf8("m_gridLayout"));
+ m_splitter = new QSplitter(this);
+ m_splitter->setObjectName(QString::fromUtf8("m_splitter"));
+ m_splitter->setOrientation(Qt::Horizontal);
+ m_jobPlot = new QwtPlot(m_splitter);
+ m_jobPlot->setObjectName(QString::fromUtf8("m_jobPlot"));
+ m_jobPlot->setSizePolicy(sizePolicy);
+ m_jobPlot->setMinimumSize(QSize(0, 0));
+ QScrollArea *area = new QScrollArea(m_splitter);
+ area->setObjectName(QString::fromUtf8("area"));
+ controls = new JobPlotControls();
+ area->setWidget(controls);
+
+ m_splitter->addWidget(m_jobPlot);
+ m_splitter->addWidget(area);
+
+ m_gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
+}
+
+/*
+ * Add the curves to the plot
+ */
+void JobPlot::addCurve()
+{
+ m_jobPlot->setTitle("Files and Bytes backed up");
+ m_jobPlot->insertLegend(new QwtLegend(), QwtPlot::RightLegend);
+
+ // Set axis titles
+ m_jobPlot->enableAxis(QwtPlot::yRight);
+ m_jobPlot->setAxisTitle(QwtPlot::yRight, "<-- Bytes Kb");
+ m_jobPlot->setAxisTitle(m_jobPlot->xBottom, "date of backup -->");
+ m_jobPlot->setAxisTitle(m_jobPlot->yLeft, "Number of Files -->");
+ m_jobPlot->setAxisScaleDraw(QwtPlot::xBottom, new DateTimeScaleDraw());
+
+ // Insert new curves
+ m_fileCurve = new QwtPlotCurve("Files");
+ m_fileCurve->setPen(QPen(Qt::red));
+ m_fileCurve->setCurveType(m_fileCurve->Yfx);
+ m_fileCurve->setYAxis(QwtPlot::yLeft);
+
+ m_byteCurve = new QwtPlotCurve("Bytes");
+ m_byteCurve->setPen(QPen(Qt::blue));
+ m_byteCurve->setCurveType(m_byteCurve->Yfx);
+ m_byteCurve->setYAxis(QwtPlot::yRight);
+ setPlotType(controls->plotTypeCombo->currentText());
+ setFileSymbolType(controls->fileSymbolTypeCombo->currentIndex());
+ setByteSymbolType(controls->byteSymbolTypeCombo->currentIndex());
+
+ m_fileCurve->attach(m_jobPlot);
+ m_byteCurve->attach(m_jobPlot);
+
+ // attach data
+ int size = m_pjd.count();
+ double tval[size];
+ double fval[size];
+ double bval[size];
+ int j = 0;
+ foreach (PlotJobData* plotJobData, m_pjd) {
+// printf("%.0f %.0f %s\n", plotJobData->bytes, plotJobData->files,
+// plotJobData->dt.toString(mainWin->m_dtformat).toUtf8().data());
+ fval[j] = plotJobData->files;
+ bval[j] = plotJobData->bytes / 1024;
+ tval[j] = plotJobData->dt.toTime_t();
+// printf("%i %.0f %.0f %.0f\n", j, tval[j], fval[j], bval[j]);
+ j++;
+ }
+ m_fileCurve->setData(tval,fval,size);
+ m_byteCurve->setData(tval,bval,size);
+
+ for (int year=2000; year<2010; year++) {
+ for (int month=1; month<=12; month++) {
+ QString monthBegin;
+ if (month > 9) {
+ QTextStream(&monthBegin) << year << "-" << month << "-01 00:00:00";
+ } else {
+ QTextStream(&monthBegin) << year << "-0" << month << "-01 00:00:00";
+ }
+ QDateTime mdt = QDateTime::fromString(monthBegin, mainWin->m_dtformat);
+ double monbeg = mdt.toTime_t();
+
+ // ...a vertical line at the first of each month
+ QwtPlotMarker *mX = new QwtPlotMarker();
+ mX->setLabel(mdt.toString("MMM-d"));
+ mX->setLabelAlignment(Qt::AlignRight|Qt::AlignTop);
+ mX->setLineStyle(QwtPlotMarker::VLine);
+ QPen pen(Qt::darkGray);
+ pen.setStyle(Qt::DashDotDotLine);
+ mX->setLinePen(pen);
+ mX->setXValue(monbeg);
+ mX->attach(m_jobPlot);
+ }
+ }
+}
+
+/*
+ * slot to respond to the plot type combo changing
+ */
+void JobPlot::setPlotType(QString currentText)
+{
+ QwtPlotCurve::CurveStyle style;
+ if (currentText == "Fitted") {
+ style = QwtPlotCurve::Lines;
+ m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
+ m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
+ } else if (currentText == "Sticks") {
+ style = QwtPlotCurve::Sticks;
+ } else if (currentText == "Lines") {
+ style = QwtPlotCurve::Lines;
+ m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
+ m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
+ } else if (currentText == "Steps") {
+ style = QwtPlotCurve::Steps;
+ } else if (currentText == "None") {
+ style = QwtPlotCurve::NoCurve;
+ }
+ m_fileCurve->setStyle(style);
+ m_byteCurve->setStyle(style);
+ m_jobPlot->replot();
+}
+
+/*
+ * slot to respond to the symbol type combo changing
+ */
+void JobPlot::setFileSymbolType(int index)
+{
+ setSymbolType(index, 0);
+}
+
+void JobPlot::setByteSymbolType(int index)
+{
+ setSymbolType(index, 1);
+}
+void JobPlot::setSymbolType(int index, int type)
+{
+ QwtSymbol sym;
+ sym.setPen(QColor(Qt::black));
+ sym.setSize(7);
+ if (index == 0) {
+ sym.setStyle(QwtSymbol::Ellipse);
+ } else if (index == 1) {
+ sym.setStyle(QwtSymbol::Rect);
+ } else if (index == 2) {
+ sym.setStyle(QwtSymbol::Diamond);
+ } else if (index == 3) {
+ sym.setStyle(QwtSymbol::Triangle);
+ } else if (index == 4) {
+ sym.setStyle(QwtSymbol::DTriangle);
+ } else if (index == 5) {
+ sym.setStyle(QwtSymbol::UTriangle);
+ } else if (index == 6) {
+ sym.setStyle(QwtSymbol::LTriangle);
+ } else if (index == 7) {
+ sym.setStyle(QwtSymbol::RTriangle);
+ } else if (index == 8) {
+ sym.setStyle(QwtSymbol::Cross);
+ } else if (index == 9) {
+ sym.setStyle(QwtSymbol::XCross);
+ } else if (index == 10) {
+ sym.setStyle(QwtSymbol::HLine);
+ } else if (index == 11) {
+ sym.setStyle(QwtSymbol::VLine);
+ } else if (index == 12) {
+ sym.setStyle(QwtSymbol::Star1);
+ } else if (index == 13) {
+ sym.setStyle(QwtSymbol::Star2);
+ } else if (index == 14) {
+ sym.setStyle(QwtSymbol::Hexagon);
+ }
+ if (type == 0) {
+ sym.setBrush(QColor(Qt::yellow));
+ m_fileCurve->setSymbol(sym);
+ }
+ if (type == 1) {
+ sym.setBrush(QColor(Qt::blue));
+ m_byteCurve->setSymbol(sym);
+ }
+ m_jobPlot->replot();
+}
+
+/*
+ * slot to respond to the file check box changing state
+ */
+void JobPlot::fileCheckChanged(int newstate)
+{
+ if (newstate == Qt::Unchecked) {
+ m_fileCurve->detach();
+ m_jobPlot->enableAxis(QwtPlot::yLeft, false);
+ } else {
+ m_fileCurve->attach(m_jobPlot);
+ m_jobPlot->enableAxis(QwtPlot::yLeft);
+ }
+ m_jobPlot->replot();
+}
+
+/*
+ * slot to respond to the byte check box changing state
+ */
+void JobPlot::byteCheckChanged(int newstate)
+{
+ if (newstate == Qt::Unchecked) {
+ m_byteCurve->detach();
+ m_jobPlot->enableAxis(QwtPlot::yRight, false);
+ } else {
+ m_byteCurve->attach(m_jobPlot);
+ m_jobPlot->enableAxis(QwtPlot::yRight);
+ }
+ m_jobPlot->replot();
+}
+
+/*
+ * Save user settings associated with this page
+ */
+void JobPlot::writeSettings()
+{
+ QSettings settings(m_console->m_dir->name(), "bat");
+ settings.beginGroup("JobPlot");
+ settings.setValue("m_splitterSizes", m_splitter->saveState());
+ settings.setValue("fileSymbolTypeCombo", controls->fileSymbolTypeCombo->currentText());
+ settings.setValue("byteSymbolTypeCombo", controls->byteSymbolTypeCombo->currentText());
+ settings.setValue("plotTypeCombo", controls->plotTypeCombo->currentText());
+ settings.endGroup();
+}
+
+/*
+ * Read settings values for Controls
+ */
+void JobPlot::readControlSettings()
+{
+ QSettings settings(m_console->m_dir->name(), "bat");
+ settings.beginGroup("JobPlot");
+ int fileSymbolTypeIndex = controls->fileSymbolTypeCombo->findText(settings.value("fileSymbolTypeCombo").toString(), Qt::MatchExactly);
+ if (fileSymbolTypeIndex == -1) fileSymbolTypeIndex = 2;
+ controls->fileSymbolTypeCombo->setCurrentIndex(fileSymbolTypeIndex);
+ int byteSymbolTypeIndex = controls->byteSymbolTypeCombo->findText(settings.value("byteSymbolTypeCombo").toString(), Qt::MatchExactly);
+ if (byteSymbolTypeIndex == -1) byteSymbolTypeIndex = 3;
+ controls->byteSymbolTypeCombo->setCurrentIndex(byteSymbolTypeIndex);
+ int plotTypeIndex = controls->plotTypeCombo->findText(settings.value("plotTypeCombo").toString(), Qt::MatchExactly);
+ if (plotTypeIndex == -1) plotTypeIndex = 2;
+ controls->plotTypeCombo->setCurrentIndex(plotTypeIndex);
+ settings.endGroup();
+}
+
+/*
+ * Read and restore user settings associated with this page
+ */
+void JobPlot::readSplitterSettings()
+{
+ QSettings settings(m_console->m_dir->name(), "bat");
+ settings.beginGroup("JobPlot");
+ m_splitter->restoreState(settings.value("m_splitterSizes").toByteArray());
+ settings.endGroup();
+}
--- /dev/null
+#ifndef _JOBPLOT_H_
+#define _JOBPLOT_H_
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+
+ The main author of Bacula is Kern Sibbald, with contributions from
+ many others, a complete list can be found in the file AUTHORS.
+ This program is Free Software; you can redistribute it and/or
+ modify it under the terms of version two of the GNU General Public
+ License as published by the Free Software Foundation and included
+ in the file LICENSE.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Bacula® is a registered trademark of John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
+/*
+ * Version $Id: jobstep.h 4992 2007-06-07 14:46:43Z kerns $
+ *
+ * Dirk Bartley, March 2007
+ */
+
+#include <QtGui>
+#include "pages.h"
+#include "ui_jobplotcontrols.h"
+#include <qwt_data.h>
+#include <qwt_legend.h>
+#include <qwt_plot_curve.h>
+#include <qwt_plot.h>
+#include <qwt_plot_marker.h>
+#include <qwt_plot_curve.h>
+#include <qwt_symbol.h>
+#include <qwt_scale_map.h>
+#include <qwt_scale_draw.h>
+#include <qwt_text.h>
+
+/*
+ * Structure to hold data items of jobs when and how much.
+ * If I worked at it I could eliminate this. It's just the way it evolved.
+ */
+struct PlotJobData
+{
+ double files;
+ double bytes;
+ QDateTime dt;
+};
+
+/*
+ * Class for the purpose of having a single object to pass data to the JobPlot
+ * Constructor. The other option was a constructor with this many passed
+ * values or some sort of code to parse a list. I liked this best at the time.
+ */
+class JobPlotPass
+{
+public:
+ JobPlotPass();
+ JobPlotPass& operator=(const JobPlotPass&);
+ bool use;
+ Qt::CheckState recordLimitCheck;
+ Qt::CheckState daysLimitCheck;
+ int recordLimitSpin;
+ int daysLimitSpin;
+ QString jobCombo;
+ QString clientCombo;
+ QString volumeCombo;
+ QString fileSetCombo;
+ QString purgedCombo;
+ QString levelCombo;
+ QString statusCombo;
+};
+
+/*
+ *Class to Change the display of the time scale to display dates.
+ */
+class DateTimeScaleDraw : public QwtScaleDraw
+{
+public:
+ virtual QwtText label(double v) const
+ {
+ QDateTime dtlabel(QDateTime::fromTime_t((uint)v));
+ return dtlabel.toString("M-d-yy");
+ }
+};
+
+/*
+ * These are the user interface control widgets as a separate class.
+ * Separately for the purpos of having the controls in a Scroll Area.
+ */
+class JobPlotControls : public QWidget, public Ui::JobPlotControlsForm
+{
+ Q_OBJECT
+
+public:
+ JobPlotControls();
+};
+
+/*
+ * The main class
+ */
+class JobPlot : public Pages
+{
+ Q_OBJECT
+
+public:
+ JobPlot(QTreeWidgetItem *parentTreeWidgetItem, JobPlotPass &);
+ ~JobPlot();
+ virtual void currentStackItem();
+
+private slots:
+ void setPlotType(QString);
+ void setFileSymbolType(int);
+ void setByteSymbolType(int);
+ void fileCheckChanged(int);
+ void byteCheckChanged(int);
+ void reGraph();
+
+private:
+ void setSymbolType(int, int type);
+ void addCurve();
+ void writeSettings();
+ void readSplitterSettings();
+ void readControlSettings();
+ void setupControls();
+ void runQuery();
+ bool m_drawn;
+ JobPlotPass m_pass;
+ JobPlotControls* controls;
+ QList<PlotJobData *> m_pjd;
+ QwtPlotCurve *m_fileCurve;
+ QwtPlotCurve *m_byteCurve;
+ /* from the user interface before using scroll area */
+ void setupUserInterface();
+ QGridLayout *m_gridLayout;
+ QSplitter *m_splitter;
+ QwtPlot *m_jobPlot;
+};
+
+#endif /* _JOBPLOT_H_ */
--- /dev/null
+<ui version="4.0" >
+ <class>JobPlotControlsForm</class>
+ <widget class="QWidget" name="JobPlotControlsForm" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>254</width>
+ <height>422</height>
+ </rect>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="14" column="0" colspan="2" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>236</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0" colspan="2" >
+ <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>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="fileCheck" >
+ <property name="text" >
+ <string>File Data</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="byteCheck" >
+ <property name="text" >
+ <string>By te Data</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="13" column="0" colspan="2" >
+ <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="refreshButton" >
+ <property name="maximumSize" >
+ <size>
+ <width>65</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Refresh</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="../main.qrc" >:/images/view-refresh.svg</iconset>
+ </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 row="9" column="1" >
+ <widget class="QComboBox" name="fileSetComboBox" />
+ </item>
+ <item row="10" column="1" >
+ <widget class="QComboBox" name="purgedComboBox" />
+ </item>
+ <item row="8" column="1" >
+ <widget class="QComboBox" name="volumeComboBox" />
+ </item>
+ <item row="7" column="1" >
+ <widget class="QComboBox" name="clientComboBox" />
+ </item>
+ <item row="11" column="1" >
+ <widget class="QComboBox" name="levelComboBox" />
+ </item>
+ <item row="12" column="1" >
+ <widget class="QComboBox" name="statusComboBox" />
+ </item>
+ <item row="6" column="1" >
+ <widget class="QComboBox" name="jobComboBox" />
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="plotTypeCombo" />
+ </item>
+ <item row="5" column="1" >
+ <widget class="QSpinBox" name="daysSpinBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="singleStep" >
+ <number>7</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QSpinBox" name="limitSpinBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum" >
+ <number>10000</number>
+ </property>
+ <property name="minimum" >
+ <number>1</number>
+ </property>
+ <property name="singleStep" >
+ <number>25</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="fileSymbolTypeCombo" />
+ </item>
+ <item row="3" column="1" >
+ <widget class="QComboBox" name="byteSymbolTypeCombo" />
+ </item>
+ <item row="12" column="0" >
+ <widget class="QLabel" name="statusLabel" >
+ <property name="text" >
+ <string>Status</string>
+ </property>
+ </widget>
+ </item>
+ <item row="11" column="0" >
+ <widget class="QLabel" name="levelLabel" >
+ <property name="text" >
+ <string>Level</string>
+ </property>
+ </widget>
+ </item>
+ <item row="10" column="0" >
+ <widget class="QLabel" name="purgedLabel" >
+ <property name="text" >
+ <string>Purged</string>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="0" >
+ <widget class="QLabel" name="fileSetLabel" >
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>FileSet</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0" >
+ <widget class="QLabel" name="volumeLabel" >
+ <property name="text" >
+ <string>Volume</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0" >
+ <widget class="QLabel" name="clientsLabel" >
+ <property name="text" >
+ <string>Client</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0" >
+ <widget class="QLabel" name="jobLabel" >
+ <property name="text" >
+ <string>Job</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QCheckBox" name="daysCheckBox" >
+ <property name="text" >
+ <string>Days Limit</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QCheckBox" name="limitCheckBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Record Limit</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Byte Symbol Type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>File Symbol Type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Graph Type</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
#include "joblist.h"
#include "restore.h"
#include "joblog/joblog.h"
+#include "jobgraphs/jobplot.h"
/*
* Constructor for the class
/* Can't do this in constructor because not neccesarily conected in constructor */
if (!m_populated) {
- clientsComboBox->addItem("Any");
- clientsComboBox->addItems(m_console->client_list);
- int clientIndex = clientsComboBox->findText(m_clientName, Qt::MatchExactly);
+ clientComboBox->addItem("Any");
+ clientComboBox->addItems(m_console->client_list);
+ int clientIndex = clientComboBox->findText(m_clientName, Qt::MatchExactly);
if (clientIndex != -1)
- clientsComboBox->setCurrentIndex(clientIndex);
+ clientComboBox->setCurrentIndex(clientIndex);
- QString query("SELECT VolumeName AS Media FROM Media ORDER BY Media");
- if (mainWin->m_sqlDebug) {
- Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
- }
- QStringList results, volumeList;
- if (m_console->sql_cmd(query, results)) {
- QString field;
- QStringList fieldlist;
- /* Iterate through the lines of results. */
- foreach (QString resultline, results) {
- fieldlist = resultline.split("\t");
- volumeList.append(fieldlist[0]);
- } /* foreach resultline */
- } /* if results from query */
+ QStringList volumeList;
+ m_console->getVolumeList(volumeList);
volumeComboBox->addItem("Any");
volumeComboBox->addItems(volumeList);
int volumeIndex = volumeComboBox->findText(m_mediaName, Qt::MatchExactly);
levelComboBox->addItems( QStringList() << "F" << "D" << "I");
purgedComboBox->addItem("Any");
purgedComboBox->addItems( QStringList() << "0" << "1");
- statusComboBox->addItem("Any");
fileSetComboBox->addItem("Any");
fileSetComboBox->addItems(m_console->fileset_list);
int filesetIndex = fileSetComboBox->findText(m_filesetName, Qt::MatchExactly);
if (filesetIndex != -1) {
fileSetComboBox->setCurrentIndex(filesetIndex);
}
- QString statusQuery("SELECT JobStatusLong FROM Status");
- if (mainWin->m_sqlDebug) {
- Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
- }
- QStringList statusResults, statusLongList;
- if (m_console->sql_cmd(statusQuery, statusResults)) {
- QString field;
- QStringList fieldlist;
- /* Iterate through the lines of results. */
- foreach (QString resultline, statusResults) {
- fieldlist = resultline.split("\t");
- statusLongList.append(fieldlist[0]);
- } /* foreach resultline */
- } /* if results from statusquery */
+ QStringList statusLongList;
+ m_console->getStatusList(statusLongList);
+ statusComboBox->addItem("Any");
statusComboBox->addItems(statusLongList);
}
if (m_mediaName != "Any") {
conditions.append("Media.VolumeName='" + m_mediaName + "'");
}
- int clientIndex = clientsComboBox->currentIndex();
+ int clientIndex = clientComboBox->currentIndex();
if (clientIndex != -1)
- m_clientName = clientsComboBox->itemText(clientIndex);
+ m_clientName = clientComboBox->itemText(clientIndex);
if (m_clientName != "Any") {
conditions.append("Client.Name='" + m_clientName + "'");
}
m_purgedIndex = headerlist.indexOf("Purged");
m_typeIndex = headerlist.indexOf("Job Type");
m_statusIndex = headerlist.indexOf("Job Status");
+ m_startIndex = headerlist.indexOf("Job Starttime");
+ m_filesIndex = headerlist.indexOf("Job Files");
+ m_bytesIndex = headerlist.indexOf("Job Bytes");
/* Initialize the QTableWidget */
m_checkCurrentWidget = false;
connect(actionRefreshJobList, SIGNAL(triggered()), this,
SLOT(populateTable()));
connect(refreshButton, SIGNAL(pressed()), this, SLOT(populateTable()));
+ connect(graphButton, SIGNAL(pressed()), this, SLOT(graphTable()));
/* for the tableItemChanged to maintain m_currentJob */
connect(mp_tableWidget, SIGNAL(
currentItemChanged(QTableWidgetItem *, QTableWidgetItem *)),
cmd += m_currentJob;
consoleCommand(cmd);
}
+
+/*
+ * Graph this table
+ */
+void JobList::graphTable()
+{
+ JobPlotPass pass;
+ pass.recordLimitCheck = limitCheckBox->checkState();
+ pass.daysLimitCheck = daysCheckBox->checkState();
+ pass.recordLimitSpin = limitSpinBox->value();
+ pass.daysLimitSpin = daysSpinBox->value();
+ pass.jobCombo = jobComboBox->currentText();
+ pass.clientCombo = clientComboBox->currentText();
+ pass.volumeCombo = volumeComboBox->currentText();
+ pass.fileSetCombo = fileSetComboBox->currentText();
+ pass.purgedCombo = purgedComboBox->currentText();
+ pass.levelCombo = levelComboBox->currentText();
+ pass.statusCombo = statusComboBox->currentText();
+ pass.use = true;
+ QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
+ new JobPlot(pageSelectorTreeWidgetItem, pass);
+}
void preRestoreFromTime();
void showLogForJob();
void consoleCancelJob();
+ void graphTable();
private:
void createConnections();
int m_purgedIndex;
int m_typeIndex;
int m_statusIndex;
+ int m_startIndex;
+ int m_bytesIndex;
+ int m_filesIndex;
};
#endif /* _JOBLIST_H_ */
<rect>
<x>0</x>
<y>0</y>
- <width>607</width>
- <height>390</height>
+ <width>545</width>
+ <height>276</height>
</rect>
</property>
<property name="windowTitle" >
<property name="spacing" >
<number>6</number>
</property>
- <item rowspan="2" row="0" column="1" >
+ <item row="1" column="4" >
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="0" column="0" >
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <property name="spacing" >
+ <number>3</number>
+ </property>
+ <item row="0" column="0" >
+ <widget class="QPushButton" name="refreshButton" >
+ <property name="maximumSize" >
+ <size>
+ <width>65</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Refresh</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="../main.qrc" >:/images/view-refresh.svg</iconset>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QPushButton" name="graphButton" >
+ <property name="maximumSize" >
+ <size>
+ <width>65</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Graph</string>
+ </property>
+ <property name="icon" >
+ <iconset resource="../main.qrc" >:/images/graph1.png</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::Ignored</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item rowspan="2" row="0" column="3" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
<number>6</number>
</property>
<item>
- <widget class="QLabel" name="clientsLabel" >
+ <widget class="QLabel" name="statusLabel" >
<property name="text" >
- <string>Clients</string>
+ <string>Status</string>
</property>
</widget>
</item>
<item>
- <widget class="QComboBox" name="clientsComboBox" />
+ <widget class="QComboBox" name="statusComboBox" />
</item>
</layout>
</item>
<number>6</number>
</property>
<item>
- <widget class="QLabel" name="volumeLabel" >
+ <widget class="QLabel" name="purgedLabel" >
<property name="text" >
- <string>Volume</string>
+ <string>Purged</string>
</property>
</widget>
</item>
<item>
- <widget class="QComboBox" name="volumeComboBox" />
+ <widget class="QComboBox" name="purgedComboBox" />
</item>
</layout>
</item>
</property>
<item>
<widget class="QLabel" name="fileSetLabel" >
+ <property name="maximumSize" >
+ <size>
+ <width>16777215</width>
+ <height>20</height>
+ </size>
+ </property>
<property name="text" >
<string>FileSet</string>
</property>
</item>
</layout>
</item>
- <item rowspan="2" row="0" column="3" >
+ <item rowspan="2" row="0" column="1" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
<number>6</number>
</property>
<item>
- <widget class="QLabel" name="statusLabel" >
+ <widget class="QLabel" name="clientsLabel" >
<property name="text" >
- <string>Status</string>
+ <string>Clients</string>
</property>
</widget>
</item>
<item>
- <widget class="QComboBox" name="statusComboBox" />
+ <widget class="QComboBox" name="clientComboBox" />
</item>
</layout>
</item>
<number>6</number>
</property>
<item>
- <widget class="QLabel" name="purgedLabel" >
+ <widget class="QLabel" name="volumeLabel" >
<property name="text" >
- <string>Purged</string>
+ <string>Volume</string>
</property>
</widget>
</item>
<item>
- <widget class="QComboBox" name="purgedComboBox" />
+ <widget class="QComboBox" name="volumeComboBox" />
</item>
</layout>
</item>
</item>
</layout>
</item>
- <item row="1" column="4" >
- <layout class="QGridLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <property name="spacing" >
- <number>6</number>
- </property>
- <item row="0" column="0" >
- <widget class="QPushButton" name="refreshButton" >
- <property name="maximumSize" >
- <size>
- <width>65</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="text" >
- <string>Refresh</string>
- </property>
- <property name="icon" >
- <iconset resource="../main.qrc" >:/images/view-refresh.svg</iconset>
- </property>
- </widget>
- </item>
- <item row="0" column="1" >
- <spacer>
- <property name="orientation" >
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType" >
- <enum>QSizePolicy::Ignored</enum>
- </property>
- <property name="sizeHint" >
- <size>
- <width>16</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item row="1" column="0" >
- <spacer>
- <property name="orientation" >
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType" >
- <enum>QSizePolicy::Ignored</enum>
- </property>
- <property name="sizeHint" >
- <size>
- <width>20</width>
- <height>16</height>
- </size>
- </property>
- </spacer>
- </item>
- </layout>
- </item>
</layout>
</item>
<item row="0" column="0" >
*
*/
-//#include <QAbstractEventDispatcher>
-//#include <QMenu>
#include "bat.h"
#include "jobs/jobs.h"
+#include "run/run.h"
Jobs::Jobs()
{
<< "Client" << "Storage" << "Where" << "Level" << "Type" << "FileSet"
<< "Catalog" << "Enabled");
+ m_typeIndex = headerlist.indexOf("Type");
topItem = new QTreeWidgetItem(mp_treeWidget);
topItem->setText(0, "Jobs");
topItem->setData(0, Qt::UserRole, 0);
if (m_checkcurwidget) {
/* The Previous item */
if (previouswidgetitem) { /* avoid a segfault if first time */
- int treedepth = previouswidgetitem->data(0, Qt::UserRole).toInt();
- if (treedepth == 1){
- mp_treeWidget->removeAction(actionConsoleListFiles);
- mp_treeWidget->removeAction(actionConsoleListVolumes);
- mp_treeWidget->removeAction(actionConsoleListNextVolume);
- mp_treeWidget->removeAction(actionConsoleEnableJob);
- mp_treeWidget->removeAction(actionConsoleDisableJob);
- mp_treeWidget->removeAction(actionConsoleCancel);
- mp_treeWidget->removeAction(actionJobListQuery);
+ foreach(QAction* jobAction, mp_treeWidget->actions()) {
+ mp_treeWidget->removeAction(jobAction);
}
}
mp_treeWidget->addAction(actionConsoleDisableJob);
mp_treeWidget->addAction(actionConsoleCancel);
mp_treeWidget->addAction(actionJobListQuery);
+ if (currentwidgetitem->text(m_typeIndex) == "Backup")
+ mp_treeWidget->addAction(actionRunJob);
}
}
}
connect(actionConsoleDisableJob, SIGNAL(triggered()), this, SLOT(consoleDisable()));
connect(actionConsoleCancel, SIGNAL(triggered()), this, SLOT(consoleCancel()));
connect(actionJobListQuery, SIGNAL(triggered()), this, SLOT(listJobs()));
+ connect(actionRunJob, SIGNAL(triggered()), this, SLOT(runJob()));
}
/*
QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
mainWin->createPageJobList("", "", m_currentlyselected, "", parentItem);
}
+
+/*
+ * Open a new job run page with the currentley selected "Backup" job
+ * defaulted In
+ */
+void Jobs::runJob()
+{
+ new runPage(m_currentlyselected);
+}
void consoleDisable();
void consoleCancel();
void listJobs();
+ void runJob();
private:
void createContextMenu();
QString m_currentlyselected;
bool m_populated;
bool m_checkcurwidget;
+ int m_typeIndex;
};
#endif /* _JOBS_H_ */
<string>Cancel Job Command</string>
</property>
</action>
+ <action name="actionRunJob" >
+ <property name="icon" >
+ <iconset resource="../main.qrc" >:/images/run.png</iconset>
+ </property>
+ <property name="text" >
+ <string>RunJob</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="../main.qrc" />
<file>images/estimate-job.svg</file>
<file>images/folder.png</file>
<file>images/folder.svg</file>
+ <file>images/graph1.png</file>
<file>images/help-browser.svg</file>
<file>images/home.png</file>
<file>images/joblog.png</file>
<addaction name="actionLabel" />
<addaction name="actionRestore" />
<addaction name="actionRun" />
- <addaction name="actionUndock" />
<addaction name="actionEstimate" />
<addaction name="actionBrowse" />
+ <addaction name="actionJobPlot" />
+ <addaction name="actionUndock" />
</widget>
<widget class="QDockWidget" name="dockWidget" >
<property name="sizePolicy" >
<string>Browse</string>
</property>
</action>
+ <action name="actionJobPlot" >
+ <property name="icon" >
+ <iconset resource="main.qrc" >:/images/graph1.png</iconset>
+ </property>
+ <property name="text" >
+ <string>JobPlot</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="main.qrc" />
#include "restore/restoretree.h"
#include "help/help.h"
#include "jobs/jobs.h"
+#include "jobgraphs/jobplot.h"
/*
* Daemon message callback
MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
{
+ m_isClosing = false;
m_dtformat = "yyyy-MM-dd HH:mm:ss";
mainWin = this;
setupUi(this); /* Setup UI defined by main.ui (designer) */
new MediaList();
new Storage();
new restoreTree();
+ JobPlotPass pass;
+ pass.use = false;
+ new JobPlot(NULL, pass);
treeWidget->expandItem(topItem);
stackedWidget->setCurrentWidget(m_currentConsole);
connect(actionRun, SIGNAL(triggered()), this, SLOT(runButtonClicked()));
connect(actionEstimate, SIGNAL(triggered()), this, SLOT(estimateButtonClicked()));
connect(actionBrowse, SIGNAL(triggered()), this, SLOT(browseButtonClicked()));
+ connect(actionJobPlot, SIGNAL(triggered()), this, SLOT(jobPlotButtonClicked()));
connect(actionRestore, SIGNAL(triggered()), this, SLOT(restoreButtonClicked()));
connect(actionUndock, SIGNAL(triggered()), this, SLOT(undockWindowButton()));
connect(actionToggleDock, SIGNAL(triggered()), this, SLOT(toggleDockContextWindow()));
*/
void MainWin::closeEvent(QCloseEvent *event)
{
+ m_isClosing = true;
writeSettings();
+ /* close all non console pages, this will call settings in destructors */
+ foreach(Pages *page, m_pagehash) {
+ if (page != page->console()) {
+ page->console()->setCurrent();
+ page->closeStackPage();
+ }
+ }
+ /* close the console pages and terminate connection */
foreach(Console *console, m_consoleHash){
console->writeSettings();
console->terminate();
+ console->closeStackPage();
}
event->accept();
- foreach(Pages *page, m_pagehash) {
- if (!page->isDocked())
- page->close();
- }
}
void MainWin::writeSettings()
*/
void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
{
+ if (m_isClosing) return; /* if closing the application, do nothing here */
+
Pages *previousPage, *nextPage;
Console *previousConsole, *nextConsole;
void MainWin::runButtonClicked()
{
- new runPage();
+ new runPage("");
}
void MainWin::estimateButtonClicked()
new prerestorePage();
}
+void MainWin::jobPlotButtonClicked()
+{
+ JobPlotPass pass;
+ pass.use = false;
+ new JobPlot(NULL, pass);
+}
+
/*
* The user just finished typing a line in the command line edit box
*/
*/
void MainWin::stackItemChanged(int)
{
+ if (m_isClosing) return; /* if closing the application, do nothing here */
Pages* page = (Pages*)stackedWidget->currentWidget();
/* run the virtual function in case this class overrides it */
page->currentStackItem();
void runButtonClicked();
void estimateButtonClicked();
void browseButtonClicked();
+ void jobPlotButtonClicked();
void restoreButtonClicked();
void undockWindowButton();
void treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *);
QStringList m_cmd_history;
int m_cmd_last;
QTreeWidgetItem *m_firstItem;
+ bool m_isClosing;
};
#include "ui_prefs.h"
--- /dev/null
+
+#
+# Inserted by build script
+#
+# unix {
+# INSTALLBASE = /usr
+#}
+#
+#win32 {
+# INSTALLBASE = C:/Qwt-5.0.2
+#}
+
+target.path = $$INSTALLBASE/lib
+headers.path = $$INSTALLBASE/include
+# doc.path = $$INSTALLBASE/doc
+
+######################################################################
+# qmake internal options
+######################################################################
+
+CONFIG += qt # Also for Qtopia Core!
+CONFIG += warn_on
+CONFIG += thread
+
+######################################################################
+# release/debug mode
+# The designer plugin is always built in release mode.
+# If want to change this, you have to edit designer/designer.pro.
+######################################################################
+
+CONFIG += release # release/debug
+
+######################################################################
+# Build the static/shared libraries.
+# If QwtDll is enabled, a shared library is built, otherwise
+# it will be a static library.
+######################################################################
+
+# CONFIG += QwtDll
+
+######################################################################
+# QwtPlot enables all classes, that are needed to use the QwtPlot
+# widget.
+######################################################################
+
+CONFIG += QwtPlot
+
+######################################################################
+# QwtWidgets enables all classes, that are needed to use the all other
+# widgets (sliders, dials, ...), beside QwtPlot.
+######################################################################
+
+# CONFIG += QwtWidgets
+
+######################################################################
+# If you want to display svg imageson the plot canvas, enable the
+# line below. Note that Qwt needs the svg+xml, when enabling
+# QwtSVGItem.
+######################################################################
+
+#CONFIG += QwtSVGItem
+
+######################################################################
+# If you have a commercial license you can use the MathML renderer
+# of the Qt solutions package to enable MathML support in Qwt.
+# So if you want this, copy qtmmlwidget.h + qtmmlwidget.cpp to
+# textengines/mathml and enable the line below.
+######################################################################
+
+#CONFIG += QwtMathML
+
+######################################################################
+# If you want to build the Qwt designer plugin,
+# enable the line below.
+# Otherwise you have to build it from the designer directory.
+######################################################################
+
+# CONFIG += QwtDesigner
+
+######################################################################
+# If you want to auto build the examples, enable the line below
+# Otherwise you have to build them from the examples directory.
+######################################################################
+
+# CONFIG += QwtExamples
+unix {
+ INSTALLBASE = /home/kern/bacula/x/src/qt-console/qwt
+}
/*
* Setup all the combo boxes and display the dialog
*/
-runPage::runPage()
+runPage::runPage(const QString &defJob)
{
QDateTime dt;
dockPage();
setCurrent();
this->show();
+ if (defJob != "")
+ jobCombo->setCurrentIndex(jobCombo->findText(defJob, Qt::MatchExactly));
}
void runPage::okButtonPushed()
Q_OBJECT
public:
- runPage();
+ runPage(const QString &defJob);
public slots:
void okButtonPushed();