]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/jobgraphs/jobplot.cpp
Change some icons around to make a little more senese with a status
[bacula/bacula] / bacula / src / qt-console / jobgraphs / jobplot.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28  
29 /*
30  *   Version $Id$
31  *
32  *  JobPlots Class
33  *
34  *   Dirk Bartley, March 2007
35  *
36  */ 
37
38 #include <QtGui>
39 #include "bat.h"
40 #include "jobgraphs/jobplot.h"
41
42
43 JobPlotPass::JobPlotPass()
44 {
45    use = false;
46 }
47
48 JobPlotPass& JobPlotPass::operator=(const JobPlotPass &cp)
49 {
50    use = cp.use;
51    recordLimitCheck = cp.recordLimitCheck;
52    daysLimitCheck = cp.daysLimitCheck;
53    recordLimitSpin = cp.recordLimitSpin;
54    daysLimitSpin = cp.daysLimitSpin;
55    jobCombo = cp.jobCombo;
56    clientCombo = cp.clientCombo;
57    volumeCombo = cp.volumeCombo;
58    fileSetCombo = cp.fileSetCombo;
59    purgedCombo = cp.purgedCombo;
60    levelCombo = cp.levelCombo;
61    statusCombo = cp.statusCombo;
62    return *this;
63 }
64
65 /*
66  * Constructor for the controls class which inherits QScrollArea and a ui header
67  */
68 JobPlotControls::JobPlotControls()
69 {
70    setupUi(this);
71 }
72
73 /*
74  * Constructor, this class does not inherit anything but pages.
75  */
76 JobPlot::JobPlot(QTreeWidgetItem *parentTreeWidgetItem, JobPlotPass &passVals)
77 {
78    setupUserInterface();
79    m_name = "JobPlot";
80    pgInitialize(parentTreeWidgetItem);
81    readSplitterSettings();
82    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
83    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/applications-graphics.png")));
84    m_drawn = false;
85
86    /* this invokes the pass values = operator function */
87    m_pass = passVals;
88    m_closeable = true;
89    dockPage();
90    /* If the values of the controls are predetermined (from joblist), then set
91     * this class as current window at the front of the stack */
92    if (m_pass.use)
93       setCurrent();
94    m_jobPlot->replot();
95 }
96
97 /*
98  * Kill, crush Destroy
99  */
100 JobPlot::~JobPlot()
101 {
102    if (m_drawn)
103       writeSettings();
104    m_pjd.clear();
105 }
106
107 /*
108  * This is called when the page selector has this page selected
109  */
110 void JobPlot::currentStackItem()
111 {
112    if (!m_drawn) {
113       setupControls();
114       reGraph();
115       m_drawn=true;
116    }
117 }
118
119 /*
120  * Slot for the refresh push button, also called from constructor.
121  */
122 void JobPlot::reGraph()
123 {
124    /* clear m_pjd */
125    m_pjd.clear();
126    runQuery();
127    m_jobPlot->clear();
128    addCurve();
129    m_jobPlot->replot();
130 }
131
132 /*
133  * Setup the control widgets for the graph, this are the objects from JobPlotControls
134  */
135 void JobPlot::setupControls()
136 {
137    QStringList graphType = QStringList() << /* "Fitted" <<*/ "Sticks" << "Lines" << "Steps" << "None";
138    controls->plotTypeCombo->addItems(graphType);
139    QStringList symbolType = QStringList() << "Ellipse" << "Rect" << "Diamond" << "Triangle"
140             << "DTrianle" << "UTriangle" << "LTriangle" << "RTriangle" << "Cross" << "XCross"
141             << "HLine" << "Vline" << "Star1" << "Star2" << "Hexagon" << "None";
142    controls->fileSymbolTypeCombo->addItems(symbolType);
143    controls->byteSymbolTypeCombo->addItems(symbolType);
144    readControlSettings();
145
146    controls->fileCheck->setCheckState(Qt::Checked);
147    controls->byteCheck->setCheckState(Qt::Checked);
148    connect(controls->plotTypeCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(setPlotType(QString)));
149    connect(controls->fileSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setFileSymbolType(int)));
150    connect(controls->byteSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setByteSymbolType(int)));
151    connect(controls->fileCheck, SIGNAL(stateChanged(int)), this, SLOT(fileCheckChanged(int)));
152    connect(controls->byteCheck, SIGNAL(stateChanged(int)), this, SLOT(byteCheckChanged(int)));
153    connect(controls->refreshButton, SIGNAL(pressed()), this, SLOT(reGraph()));
154
155    controls->clientComboBox->addItem("Any");
156    controls->clientComboBox->addItems(m_console->client_list);
157
158    QStringList volumeList;
159    m_console->getVolumeList(volumeList);
160    controls->volumeComboBox->addItem("Any");
161    controls->volumeComboBox->addItems(volumeList);
162    controls->jobComboBox->addItem("Any");
163    controls->jobComboBox->addItems(m_console->job_list);
164    controls->levelComboBox->addItem("Any");
165    controls->levelComboBox->addItems( QStringList() << "F" << "D" << "I");
166    controls->purgedComboBox->addItem("Any");
167    controls->purgedComboBox->addItems( QStringList() << "0" << "1");
168    controls->fileSetComboBox->addItem("Any");
169    controls->fileSetComboBox->addItems(m_console->fileset_list);
170    QStringList statusLongList;
171    m_console->getStatusList(statusLongList);
172    controls->statusComboBox->addItem("Any");
173    controls->statusComboBox->addItems(statusLongList);
174
175    if (m_pass.use) {
176       controls->limitCheckBox->setCheckState(m_pass.recordLimitCheck);
177       controls->limitSpinBox->setValue(m_pass.recordLimitSpin);
178       controls->daysCheckBox->setCheckState(m_pass.daysLimitCheck);
179       controls->daysSpinBox->setValue(m_pass.daysLimitSpin);
180       int jobIndex = controls->jobComboBox->findText(m_pass.jobCombo, Qt::MatchExactly); 
181       if (jobIndex != -1)
182          controls->jobComboBox->setCurrentIndex(jobIndex);
183       int clientIndex = controls->clientComboBox->findText(m_pass.clientCombo, Qt::MatchExactly);
184       if (clientIndex != -1)
185          controls->clientComboBox->setCurrentIndex(clientIndex);
186       int volumeIndex = controls->volumeComboBox->findText(m_pass.volumeCombo, Qt::MatchExactly);
187       if (volumeIndex != -1)
188          controls->volumeComboBox->setCurrentIndex(volumeIndex);
189       int filesetIndex = controls->fileSetComboBox->findText(m_pass.fileSetCombo, Qt::MatchExactly);
190       if (filesetIndex != -1)
191          controls->fileSetComboBox->setCurrentIndex(filesetIndex);
192       int purgedIndex = controls->purgedComboBox->findText(m_pass.purgedCombo, Qt::MatchExactly); 
193       if (purgedIndex != -1)
194          controls->purgedComboBox->setCurrentIndex(purgedIndex);
195       int levelIndex = controls->levelComboBox->findText(m_pass.levelCombo, Qt::MatchExactly); 
196       if (levelIndex != -1)
197          controls->levelComboBox->setCurrentIndex(levelIndex);
198       int statusIndex = controls->statusComboBox->findText(m_pass.statusCombo, Qt::MatchExactly); 
199       if (statusIndex != -1)
200          controls->statusComboBox->setCurrentIndex(statusIndex);
201    } else {
202       /* Set Defaults for check and spin for limits */
203       controls->limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
204       controls->limitSpinBox->setValue(mainWin->m_recordLimitVal);
205       controls->daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
206       controls->daysSpinBox->setValue(mainWin->m_daysLimitVal);
207    } 
208 }
209
210 /*
211  * Setup the control widgets for the graph, this are the objects from JobPlotControls
212  */
213 void JobPlot::runQuery()
214 {
215    /* Set up query */
216    QString query("");
217    query += "SELECT DISTINCT "
218             " Job.Starttime AS JobStart,"
219             " Job.Jobfiles AS FileCount,"
220             " Job.JobBytes AS Bytes,"
221             " Job.JobId AS JobId"
222             " FROM Job"
223             " JOIN Client ON (Client.ClientId=Job.ClientId)"
224             " JOIN Status ON (Job.JobStatus=Status.JobStatus)"
225             " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId)";
226
227    QStringList conditions;
228    int jobIndex = controls->jobComboBox->currentIndex();
229    if ((jobIndex != -1) && (controls->jobComboBox->itemText(jobIndex) != "Any"))
230       conditions.append("Job.Name='" + controls->jobComboBox->itemText(jobIndex) + "'");
231    int clientIndex = controls->clientComboBox->currentIndex();
232    if ((clientIndex != -1) && (controls->clientComboBox->itemText(clientIndex) != "Any"))
233       conditions.append("Client.Name='" + controls->clientComboBox->itemText(clientIndex) + "'");
234    int volumeIndex = controls->volumeComboBox->currentIndex();
235    if ((volumeIndex != -1) && (controls->volumeComboBox->itemText(volumeIndex) != "Any")) {
236       query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId)"
237                " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId)";
238       conditions.append("Media.VolumeName='" + controls->volumeComboBox->itemText(volumeIndex) + "'");
239    }
240    int fileSetIndex = controls->fileSetComboBox->currentIndex();
241    if ((fileSetIndex != -1) && (controls->fileSetComboBox->itemText(fileSetIndex) != "Any"))
242       conditions.append("FileSet.FileSet='" + controls->fileSetComboBox->itemText(fileSetIndex) + "'");
243    int purgedIndex = controls->purgedComboBox->currentIndex();
244    if ((purgedIndex != -1) && (controls->purgedComboBox->itemText(purgedIndex) != "Any"))
245       conditions.append("Job.PurgedFiles='" + controls->purgedComboBox->itemText(purgedIndex) + "'");
246    int levelIndex = controls->levelComboBox->currentIndex();
247    if ((levelIndex != -1) && (controls->levelComboBox->itemText(levelIndex) != "Any"))
248       conditions.append("Job.Level='" + controls->levelComboBox->itemText(levelIndex) + "'");
249    int statusIndex = controls->statusComboBox->currentIndex();
250    if ((statusIndex != -1) && (controls->statusComboBox->itemText(statusIndex) != "Any"))
251       conditions.append("Status.JobStatusLong='" + controls->statusComboBox->itemText(statusIndex) + "'");
252    /* If Limit check box For limit by days is checked  */
253    if (controls->daysCheckBox->checkState() == Qt::Checked) {
254       QDateTime stamp = QDateTime::currentDateTime().addDays(-controls->daysSpinBox->value());
255       QString since = stamp.toString(Qt::ISODate);
256       conditions.append("Job.Starttime>'" + since + "'");
257    }
258    bool first = true;
259    foreach (QString condition, conditions) {
260       if (first) {
261          query += " WHERE " + condition;
262          first = false;
263       } else {
264          query += " AND " + condition;
265       }
266    }
267    /* Descending */
268    query += " ORDER BY Job.Starttime DESC, Job.JobId DESC";
269    /* If Limit check box for limit records returned is checked  */
270    if (controls->limitCheckBox->checkState() == Qt::Checked) {
271       QString limit;
272       limit.setNum(controls->limitSpinBox->value());
273       query += " LIMIT " + limit;
274    }
275
276    if (mainWin->m_sqlDebug) {
277       Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
278    }
279    QString resultline;
280    QStringList results;
281    if (m_console->sql_cmd(query, results)) {
282
283       QString field;
284       QStringList fieldlist;
285    
286       int row = 0;
287       /* Iterate through the record returned from the query */
288       foreach (resultline, results) {
289          PlotJobData *plotJobData = new PlotJobData();
290          fieldlist = resultline.split("\t");
291          int column = 0;
292          QString statusCode("");
293          /* Iterate through fields in the record */
294          foreach (field, fieldlist) {
295             field = field.trimmed();  /* strip leading & trailing spaces */
296             if (column == 0) {
297                plotJobData->dt = QDateTime::fromString(field, mainWin->m_dtformat);
298             } else if (column == 1) {
299                plotJobData->files = field.toDouble();
300             } else if (column == 2) {
301                plotJobData->bytes = field.toDouble();
302             }
303             column++;
304             m_pjd.prepend(plotJobData);
305          }
306          row++;
307       }
308    } 
309    if ((controls->volumeComboBox->itemText(volumeIndex) != "Any") && (results.count() == 0)){
310       /* for context sensitive searches, let the user know if there were no
311        *        * results */
312       QMessageBox::warning(this, tr("Bat"),
313           tr("The Jobs query returned no results.\n"
314          "Press OK to continue?"), QMessageBox::Ok );
315    }
316 }
317
318 /*
319  * The user interface that used to be in the ui header.  I wanted to have a
320  * scroll area which is not in designer.
321  */
322 void JobPlot::setupUserInterface()
323 {
324    QSizePolicy sizePolicy(static_cast<QSizePolicy::Policy>(1), static_cast<QSizePolicy::Policy>(5));
325    sizePolicy.setHorizontalStretch(0);
326    sizePolicy.setVerticalStretch(0);
327    sizePolicy.setVerticalStretch(0);
328    sizePolicy.setVerticalPolicy(QSizePolicy::Ignored);
329    sizePolicy.setHorizontalPolicy(QSizePolicy::Ignored);
330    m_gridLayout = new QGridLayout(this);
331    m_gridLayout->setSpacing(6);
332    m_gridLayout->setMargin(9);
333    m_gridLayout->setObjectName(QString::fromUtf8("m_gridLayout"));
334    m_splitter = new QSplitter(this);
335    m_splitter->setObjectName(QString::fromUtf8("m_splitter"));
336    m_splitter->setOrientation(Qt::Horizontal);
337    m_jobPlot = new QwtPlot(m_splitter);
338    m_jobPlot->setObjectName(QString::fromUtf8("m_jobPlot"));
339    m_jobPlot->setSizePolicy(sizePolicy);
340    m_jobPlot->setMinimumSize(QSize(0, 0));
341    QScrollArea *area = new QScrollArea(m_splitter);
342    area->setObjectName(QString::fromUtf8("area"));
343    controls = new JobPlotControls();
344    area->setWidget(controls);
345    
346    m_splitter->addWidget(m_jobPlot);
347    m_splitter->addWidget(area);
348
349    m_gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
350 }
351
352 /*
353  * Add the curves to the plot
354  */
355 void JobPlot::addCurve()
356 {
357    m_jobPlot->setTitle("Files and Bytes backed up");
358    m_jobPlot->insertLegend(new QwtLegend(), QwtPlot::RightLegend);
359
360    // Set axis titles
361    m_jobPlot->enableAxis(QwtPlot::yRight);
362    m_jobPlot->setAxisTitle(QwtPlot::yRight, "<-- Bytes Kb");
363    m_jobPlot->setAxisTitle(m_jobPlot->xBottom, "date of backup -->");
364    m_jobPlot->setAxisTitle(m_jobPlot->yLeft, "Number of Files -->");
365    m_jobPlot->setAxisScaleDraw(QwtPlot::xBottom, new DateTimeScaleDraw());
366
367    // Insert new curves
368    m_fileCurve = new QwtPlotCurve("Files");
369    m_fileCurve->setPen(QPen(Qt::red));
370    m_fileCurve->setCurveType(m_fileCurve->Yfx);
371    m_fileCurve->setYAxis(QwtPlot::yLeft);
372
373    m_byteCurve = new QwtPlotCurve("Bytes");
374    m_byteCurve->setPen(QPen(Qt::blue));
375    m_byteCurve->setCurveType(m_byteCurve->Yfx);
376    m_byteCurve->setYAxis(QwtPlot::yRight);
377    setPlotType(controls->plotTypeCombo->currentText());
378    setFileSymbolType(controls->fileSymbolTypeCombo->currentIndex());
379    setByteSymbolType(controls->byteSymbolTypeCombo->currentIndex());
380
381    m_fileCurve->attach(m_jobPlot);
382    m_byteCurve->attach(m_jobPlot);
383
384    // attach data
385    int size = m_pjd.count();
386    double tval[size];
387    double fval[size];
388    double bval[size];
389    int j = 0;
390    foreach (PlotJobData* plotJobData, m_pjd) {
391 //      printf("%.0f %.0f %s\n", plotJobData->bytes, plotJobData->files,
392 //              plotJobData->dt.toString(mainWin->m_dtformat).toUtf8().data());
393       fval[j] = plotJobData->files;
394       bval[j] = plotJobData->bytes / 1024;
395       tval[j] = plotJobData->dt.toTime_t();
396 //      printf("%i %.0f %.0f %.0f\n", j, tval[j], fval[j], bval[j]);
397       j++;
398    }
399    m_fileCurve->setData(tval,fval,size);
400    m_byteCurve->setData(tval,bval,size);
401
402    for (int year=2000; year<2010; year++) {
403       for (int month=1; month<=12; month++) {
404          QString monthBegin;
405          if (month > 9) {
406             QTextStream(&monthBegin) << year << "-" << month << "-01 00:00:00";
407          } else {
408             QTextStream(&monthBegin) << year << "-0" << month << "-01 00:00:00";
409          }
410          QDateTime mdt = QDateTime::fromString(monthBegin, mainWin->m_dtformat);
411          double monbeg = mdt.toTime_t();
412    
413          //  ...a vertical line at the first of each month
414          QwtPlotMarker *mX = new QwtPlotMarker();
415          mX->setLabel(mdt.toString("MMM-d"));
416          mX->setLabelAlignment(Qt::AlignRight|Qt::AlignTop);
417          mX->setLineStyle(QwtPlotMarker::VLine);
418          QPen pen(Qt::darkGray);
419          pen.setStyle(Qt::DashDotDotLine);
420          mX->setLinePen(pen);
421          mX->setXValue(monbeg);
422          mX->attach(m_jobPlot);
423       }
424    }
425 }
426
427 /*
428  * slot to respond to the plot type combo changing
429  */
430 void JobPlot::setPlotType(QString currentText)
431 {
432    QwtPlotCurve::CurveStyle style = QwtPlotCurve::NoCurve;
433    if (currentText == "Fitted") {
434       style = QwtPlotCurve::Lines;
435       m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
436       m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
437    } else if (currentText == "Sticks") {
438       style = QwtPlotCurve::Sticks;
439    } else if (currentText == "Lines") {
440       style = QwtPlotCurve::Lines;
441       m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
442       m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
443    } else if (currentText == "Steps") {
444       style = QwtPlotCurve::Steps;
445    } else if (currentText == "None") {
446       style = QwtPlotCurve::NoCurve;
447    }
448    m_fileCurve->setStyle(style);
449    m_byteCurve->setStyle(style);
450    m_jobPlot->replot();
451 }
452
453 /*
454  * slot to respond to the symbol type combo changing
455  */
456 void JobPlot::setFileSymbolType(int index)
457 {
458    setSymbolType(index, 0);
459 }
460
461 void JobPlot::setByteSymbolType(int index)
462 {
463    setSymbolType(index, 1);
464 }
465 void JobPlot::setSymbolType(int index, int type)
466 {
467    QwtSymbol sym;
468    sym.setPen(QColor(Qt::black));
469    sym.setSize(7);
470    if (index == 0) {
471       sym.setStyle(QwtSymbol::Ellipse);
472    } else if (index == 1) {
473       sym.setStyle(QwtSymbol::Rect);
474    } else if (index == 2) {
475       sym.setStyle(QwtSymbol::Diamond);
476    } else if (index == 3) {
477       sym.setStyle(QwtSymbol::Triangle);
478    } else if (index == 4) {
479       sym.setStyle(QwtSymbol::DTriangle);
480    } else if (index == 5) {
481       sym.setStyle(QwtSymbol::UTriangle);
482    } else if (index == 6) {
483       sym.setStyle(QwtSymbol::LTriangle);
484    } else if (index == 7) {
485       sym.setStyle(QwtSymbol::RTriangle);
486    } else if (index == 8) {
487       sym.setStyle(QwtSymbol::Cross);
488    } else if (index == 9) {
489       sym.setStyle(QwtSymbol::XCross);
490    } else if (index == 10) {
491       sym.setStyle(QwtSymbol::HLine);
492    } else if (index == 11) {
493       sym.setStyle(QwtSymbol::VLine);
494    } else if (index == 12) {
495       sym.setStyle(QwtSymbol::Star1);
496    } else if (index == 13) {
497       sym.setStyle(QwtSymbol::Star2);
498    } else if (index == 14) {
499       sym.setStyle(QwtSymbol::Hexagon);
500    }
501    if (type == 0) {
502       sym.setBrush(QColor(Qt::yellow));
503       m_fileCurve->setSymbol(sym);
504    }
505    if (type == 1) {
506       sym.setBrush(QColor(Qt::blue));
507       m_byteCurve->setSymbol(sym);
508    }
509    m_jobPlot->replot();
510 }
511
512 /*
513  * slot to respond to the file check box changing state
514  */
515 void JobPlot::fileCheckChanged(int newstate)
516 {
517    if (newstate == Qt::Unchecked) {
518       m_fileCurve->detach();
519       m_jobPlot->enableAxis(QwtPlot::yLeft, false);
520    } else {
521       m_fileCurve->attach(m_jobPlot);
522       m_jobPlot->enableAxis(QwtPlot::yLeft);
523    }
524    m_jobPlot->replot();
525 }
526
527 /*
528  * slot to respond to the byte check box changing state
529  */
530 void JobPlot::byteCheckChanged(int newstate)
531 {
532    if (newstate == Qt::Unchecked) {
533       m_byteCurve->detach();
534       m_jobPlot->enableAxis(QwtPlot::yRight, false);
535    } else {
536       m_byteCurve->attach(m_jobPlot);
537       m_jobPlot->enableAxis(QwtPlot::yRight);
538    }
539    m_jobPlot->replot();
540 }
541
542 /*
543  * Save user settings associated with this page
544  */
545 void JobPlot::writeSettings()
546 {
547    QSettings settings(m_console->m_dir->name(), "bat");
548    settings.beginGroup("JobPlot");
549    settings.setValue("m_splitterSizes", m_splitter->saveState());
550    settings.setValue("fileSymbolTypeCombo", controls->fileSymbolTypeCombo->currentText());
551    settings.setValue("byteSymbolTypeCombo", controls->byteSymbolTypeCombo->currentText());
552    settings.setValue("plotTypeCombo", controls->plotTypeCombo->currentText());
553    settings.endGroup();
554 }
555
556 /* 
557  * Read settings values for Controls
558  */
559 void JobPlot::readControlSettings()
560 {
561    QSettings settings(m_console->m_dir->name(), "bat");
562    settings.beginGroup("JobPlot");
563    int fileSymbolTypeIndex = controls->fileSymbolTypeCombo->findText(settings.value("fileSymbolTypeCombo").toString(), Qt::MatchExactly);
564    if (fileSymbolTypeIndex == -1) fileSymbolTypeIndex = 2;
565       controls->fileSymbolTypeCombo->setCurrentIndex(fileSymbolTypeIndex);
566    int byteSymbolTypeIndex = controls->byteSymbolTypeCombo->findText(settings.value("byteSymbolTypeCombo").toString(), Qt::MatchExactly);
567    if (byteSymbolTypeIndex == -1) byteSymbolTypeIndex = 3;
568       controls->byteSymbolTypeCombo->setCurrentIndex(byteSymbolTypeIndex);
569    int plotTypeIndex = controls->plotTypeCombo->findText(settings.value("plotTypeCombo").toString(), Qt::MatchExactly);
570    if (plotTypeIndex == -1) plotTypeIndex = 2;
571       controls->plotTypeCombo->setCurrentIndex(plotTypeIndex);
572    settings.endGroup();
573 }
574
575 /*
576  * Read and restore user settings associated with this page
577  */
578 void JobPlot::readSplitterSettings()
579 {
580    QSettings settings(m_console->m_dir->name(), "bat");
581    settings.beginGroup("JobPlot");
582    m_splitter->restoreState(settings.value("m_splitterSizes").toByteArray());
583    settings.endGroup();
584 }