]> git.sur5r.net Git - bacula/bacula/commitdiff
The results of running the merge command:
authorDirk H Bartley <dbartley@schupan.com>
Mon, 25 Jun 2007 19:15:34 +0000 (19:15 +0000)
committerDirk H Bartley <dbartley@schupan.com>
Mon, 25 Jun 2007 19:15:34 +0000 (19:15 +0000)
svn merge -r5003:5087 http://bacula.svn.sourceforge.net/svnroot/bacula/branches/working/qt-console .
To see the log of changes made use
svn log -r5003:5087 http://bacula.svn.sourceforge.net/svnroot/bacula/branches/working/qt-console

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@5090 91ce42f0-d328-0410-95d8-f526ca767f89

25 files changed:
bacula/src/qt-console/External-qt-console [new file with mode: 0644]
bacula/src/qt-console/README
bacula/src/qt-console/TODO
bacula/src/qt-console/bat.pro.in
bacula/src/qt-console/build-depkgs-qt-console [new file with mode: 0755]
bacula/src/qt-console/console/console.cpp
bacula/src/qt-console/console/console.h
bacula/src/qt-console/images/graph1.png [new file with mode: 0644]
bacula/src/qt-console/images/graph1.svg [new file with mode: 0644]
bacula/src/qt-console/jobgraphs/jobplot.cpp [new file with mode: 0644]
bacula/src/qt-console/jobgraphs/jobplot.h [new file with mode: 0644]
bacula/src/qt-console/jobgraphs/jobplotcontrols.ui [new file with mode: 0644]
bacula/src/qt-console/joblist/joblist.cpp
bacula/src/qt-console/joblist/joblist.h
bacula/src/qt-console/joblist/joblist.ui
bacula/src/qt-console/jobs/jobs.cpp
bacula/src/qt-console/jobs/jobs.h
bacula/src/qt-console/jobs/jobs.ui
bacula/src/qt-console/main.qrc
bacula/src/qt-console/main.ui
bacula/src/qt-console/mainwin.cpp
bacula/src/qt-console/mainwin.h
bacula/src/qt-console/qwtconfig.pri [new file with mode: 0644]
bacula/src/qt-console/run/run.cpp
bacula/src/qt-console/run/run.h

diff --git a/bacula/src/qt-console/External-qt-console b/bacula/src/qt-console/External-qt-console
new file mode 100644 (file)
index 0000000..2a49490
--- /dev/null
@@ -0,0 +1,26 @@
+# 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
index c1e02cd44e624e02fb9ca789d8fee10e2abd5b92..74b291cc226dae93ae843cc48f6211b9c9e4f4a1 100644 (file)
@@ -6,6 +6,17 @@ development.  If you want to help, please contact Kern directly.
 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
@@ -35,7 +46,7 @@ Items not implemented:
          
 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
index 5b46eb5935d6079b289a3ba2c80f2dd7b2640879..7ba0c738b38b6f624ab37c6af72adf9921701885 100644 (file)
@@ -11,9 +11,9 @@ closing would bring the previous one back.
 ========================================================
 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.
 
@@ -34,10 +34,15 @@ cancelled graphically.
 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
index ad45ffcfd7ab81b1f8a84b5e0ccc64610e559c10..ec236623a99df1bd8ca69c584dd7fb95478bbeda 100644 (file)
@@ -18,10 +18,11 @@ TEMPLATE = app
 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
@@ -42,6 +43,7 @@ FORMS += medialist/medialist.ui mediaedit/mediaedit.ui joblist/joblist.ui
 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
@@ -114,6 +116,9 @@ SOURCES += jobs/jobs.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
diff --git a/bacula/src/qt-console/build-depkgs-qt-console b/bacula/src/qt-console/build-depkgs-qt-console
new file mode 100755 (executable)
index 0000000..4c92306
--- /dev/null
@@ -0,0 +1,168 @@
+#!/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
index b722e2627049d683d9c180f96872285f9d9df751..2911e2c4a68c1b45d0dcf1a0463c79d4c798f579 100644 (file)
@@ -857,3 +857,41 @@ void Console::consoleReload()
    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 */
+}
index a5878a615e687060b92bb7ccf66b10cf0531a9c4..9c7ca74680679c3aa4d119786099f24623f27b57 100644 (file)
@@ -102,6 +102,8 @@ public:
    void getDirResName(QString &);
    void startTimer();
    void stopTimer();
+   void getVolumeList(QStringList &);
+   void getStatusList(QStringList &);
 
    QStringList job_list;
    QStringList client_list;
diff --git a/bacula/src/qt-console/images/graph1.png b/bacula/src/qt-console/images/graph1.png
new file mode 100644 (file)
index 0000000..9e12db0
Binary files /dev/null and b/bacula/src/qt-console/images/graph1.png differ
diff --git a/bacula/src/qt-console/images/graph1.svg b/bacula/src/qt-console/images/graph1.svg
new file mode 100644 (file)
index 0000000..ecde0e9
--- /dev/null
@@ -0,0 +1,380 @@
+<?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>
diff --git a/bacula/src/qt-console/jobgraphs/jobplot.cpp b/bacula/src/qt-console/jobgraphs/jobplot.cpp
new file mode 100644 (file)
index 0000000..2128bbc
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+   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();
+}
diff --git a/bacula/src/qt-console/jobgraphs/jobplot.h b/bacula/src/qt-console/jobgraphs/jobplot.h
new file mode 100644 (file)
index 0000000..6e27deb
--- /dev/null
@@ -0,0 +1,151 @@
+#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_ */
diff --git a/bacula/src/qt-console/jobgraphs/jobplotcontrols.ui b/bacula/src/qt-console/jobgraphs/jobplotcontrols.ui
new file mode 100644 (file)
index 0000000..39492d9
--- /dev/null
@@ -0,0 +1,329 @@
+<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>
index d472797789b074326139ba9d3bc2ae570fd637d4..a2d2747d0ea825a06760c96f2dfeed5f1390c915 100644 (file)
@@ -37,6 +37,7 @@
 #include "joblist.h"
 #include "restore.h"
 #include "joblog/joblog.h"
+#include "jobgraphs/jobplot.h"
 
 /*
  * Constructor for the class
@@ -88,26 +89,14 @@ void JobList::populateTable()
 
    /* 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);
@@ -124,27 +113,15 @@ void JobList::populateTable()
       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);
    }
 
@@ -169,9 +146,9 @@ void JobList::populateTable()
    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 + "'");
    }
@@ -230,6 +207,9 @@ void JobList::populateTable()
    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;
@@ -398,6 +378,7 @@ void JobList::createConnections()
    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 *)),
@@ -559,3 +540,25 @@ void JobList::consoleCancelJob()
    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);
+}
index d3b8e0468c8e189a555cb5750c1826d9b4db24e6..994e2dea59916b53cde3d75563eae644568ce097 100644 (file)
@@ -66,6 +66,7 @@ private slots:
    void preRestoreFromTime();
    void showLogForJob();
    void consoleCancelJob();
+   void graphTable();
 
 private:
    void createConnections();
@@ -80,6 +81,9 @@ private:
    int m_purgedIndex;
    int m_typeIndex;
    int m_statusIndex;
+   int m_startIndex;
+   int m_bytesIndex;
+   int m_filesIndex;
 };
 
 #endif /* _JOBLIST_H_ */
index 1b861a0ed4635daa72948e4b4fd5af1ba384f372..00a0ab9b942a8d16b3950670737d57275dc00f5d 100644 (file)
@@ -5,8 +5,8 @@
    <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" >
index 7f13564ccd9ccfee4688e22a30c8e9fb36dde1ad..58543a9acedafd812d5b67655e16512e4f91c544 100644 (file)
  *
  */ 
 
-//#include <QAbstractEventDispatcher>
-//#include <QMenu>
 #include "bat.h"
 #include "jobs/jobs.h"
+#include "run/run.h"
 
 Jobs::Jobs()
 {
@@ -80,6 +79,7 @@ void Jobs::populateTree()
       << "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);
@@ -144,15 +144,8 @@ void Jobs::treeItemChanged(QTreeWidgetItem *currentwidgetitem, QTreeWidgetItem *
    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);
          }
       }
 
@@ -168,6 +161,8 @@ void Jobs::treeItemChanged(QTreeWidgetItem *currentwidgetitem, QTreeWidgetItem *
          mp_treeWidget->addAction(actionConsoleDisableJob);
          mp_treeWidget->addAction(actionConsoleCancel);
          mp_treeWidget->addAction(actionJobListQuery);
+         if (currentwidgetitem->text(m_typeIndex) == "Backup")
+            mp_treeWidget->addAction(actionRunJob);
       }
    }
 }
@@ -194,6 +189,7 @@ void Jobs::createContextMenu()
    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()));
 }
 
 /*
@@ -260,3 +256,12 @@ void Jobs::listJobs()
    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);
+}
index bbcc97240cc910fe7e895f7f74f21c27738ccdb1..8c32859e8faf23e7e27731db0c4b3ad1513544fa 100644 (file)
@@ -60,12 +60,14 @@ private slots:
    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_ */
index 8b0af20e68f769e8b1d5826ecb94a5ece9a87cda..21d25d83d06ab41e713646551d32c7bf50bfde58 100644 (file)
     <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" />
index fee1c35f52d7db7f5d20d611340979064b8ba53d..500943e3f85052dbe4652d4e1a1ffed4c6fef723 100644 (file)
@@ -18,6 +18,7 @@
         <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>
index 42775e77039761e93efdab57d4e7d1d95617171f..83b05f83482fa306a34d0065714c61537b9948e8 100644 (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" />
index 0dcf4f60158fba25f555548e476938437ba313ae..81deb3f3dc14f2ea9783ff0c905b7ff13c229519 100644 (file)
@@ -49,6 +49,7 @@
 #include "restore/restoretree.h"
 #include "help/help.h"
 #include "jobs/jobs.h"
+#include "jobgraphs/jobplot.h"
 
 /* 
  * Daemon message callback
@@ -60,6 +61,7 @@ void message_callback(int /* type */, char *msg)
 
 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) */
@@ -144,6 +146,9 @@ void MainWin::createPages()
       new MediaList();
       new Storage();
       new restoreTree();
+      JobPlotPass pass;
+      pass.use = false;
+      new JobPlot(NULL, pass);
 
       treeWidget->expandItem(topItem);
       stackedWidget->setCurrentWidget(m_currentConsole);
@@ -227,6 +232,7 @@ void MainWin::createConnections()
    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()));
@@ -239,16 +245,22 @@ void MainWin::createConnections()
  */
 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()
@@ -297,6 +309,8 @@ void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
  */
 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
 {
+   if (m_isClosing) return; /* if closing the application, do nothing here */
+
    Pages *previousPage, *nextPage;
    Console *previousConsole, *nextConsole;
 
@@ -396,7 +410,7 @@ void MainWin::labelButtonClicked()
 
 void MainWin::runButtonClicked() 
 {
-   new runPage();
+   new runPage("");
 }
 
 void MainWin::estimateButtonClicked() 
@@ -414,6 +428,13 @@ void MainWin::restoreButtonClicked()
    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
  */
@@ -501,6 +522,7 @@ void MainWin::toggleDockContextWindow()
  */
 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();
index c8682237ab75edbc4b72fa578854b764457af3c8..ddeb55497d21f84d3f13bef4a43fb1f57b2437f0 100644 (file)
@@ -94,6 +94,7 @@ public slots:
    void runButtonClicked();
    void estimateButtonClicked();
    void browseButtonClicked();
+   void jobPlotButtonClicked();
    void restoreButtonClicked();
    void undockWindowButton();
    void treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *);
@@ -118,6 +119,7 @@ private:
    QStringList m_cmd_history;
    int m_cmd_last;
    QTreeWidgetItem *m_firstItem;
+   bool m_isClosing;
 };
 
 #include "ui_prefs.h"
diff --git a/bacula/src/qt-console/qwtconfig.pri b/bacula/src/qt-console/qwtconfig.pri
new file mode 100644 (file)
index 0000000..7422712
--- /dev/null
@@ -0,0 +1,88 @@
+
+# 
+# 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
+}
index 0ea27f91dc99cc2989e971a2a2f6d50b7a6e267a..6365b3494dce560f28e7d97c5a79af0fafacf1de 100644 (file)
@@ -40,7 +40,7 @@
 /*
  * Setup all the combo boxes and display the dialog
  */
-runPage::runPage()
+runPage::runPage(const QString &defJob)
 {
    QDateTime dt;
 
@@ -74,6 +74,8 @@ runPage::runPage()
    dockPage();
    setCurrent();
    this->show();
+   if (defJob != "")
+      jobCombo->setCurrentIndex(jobCombo->findText(defJob, Qt::MatchExactly));
 }
 
 void runPage::okButtonPushed()
index 91273cca250536606f19d22339e375898c3c4fef..ac949c04006d26f60bb93f1805ee1f3ad78ebea4 100644 (file)
@@ -14,7 +14,7 @@ class runPage : public Pages, public Ui::runForm
    Q_OBJECT 
 
 public:
-   runPage();
+   runPage(const QString &defJob);
 
 public slots:
    void okButtonPushed();