2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
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
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.
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
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.
34 * Dirk Bartley, March 2007
40 #include "util/comboutil.h"
41 #include "jobgraphs/jobplot.h"
44 JobPlotPass::JobPlotPass()
49 JobPlotPass& JobPlotPass::operator=(const JobPlotPass &cp)
52 recordLimitCheck = cp.recordLimitCheck;
53 daysLimitCheck = cp.daysLimitCheck;
54 recordLimitSpin = cp.recordLimitSpin;
55 daysLimitSpin = cp.daysLimitSpin;
56 jobCombo = cp.jobCombo;
57 clientCombo = cp.clientCombo;
58 volumeCombo = cp.volumeCombo;
59 fileSetCombo = cp.fileSetCombo;
60 purgedCombo = cp.purgedCombo;
61 levelCombo = cp.levelCombo;
62 statusCombo = cp.statusCombo;
67 * Constructor for the controls class which inherits QScrollArea and a ui header
69 JobPlotControls::JobPlotControls()
75 * Constructor, this class does not inherit anything but pages.
77 JobPlot::JobPlot(QTreeWidgetItem *parentTreeWidgetItem, JobPlotPass &passVals)
80 m_name = tr("JobPlot");
81 pgInitialize(parentTreeWidgetItem);
82 readSplitterSettings();
83 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
84 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/applications-graphics.png")));
87 /* this invokes the pass values = operator function */
91 /* If the values of the controls are predetermined (from joblist), then set
92 * this class as current window at the front of the stack */
109 * This is called when the page selector has this page selected
111 void JobPlot::currentStackItem()
121 * Slot for the refresh push button, also called from constructor.
123 void JobPlot::reGraph()
134 * Setup the control widgets for the graph, this are the objects from JobPlotControls
136 void JobPlot::setupControls()
138 QStringList graphType = QStringList() << /* tr("Fitted") <<*/ tr("Sticks")
139 << tr("Lines") << tr("Steps") << tr("None");
140 controls->plotTypeCombo->addItems(graphType);
142 fillSymbolCombo(controls->fileSymbolTypeCombo);
143 fillSymbolCombo(controls->byteSymbolTypeCombo);
145 readControlSettings();
147 controls->fileCheck->setCheckState(Qt::Checked);
148 controls->byteCheck->setCheckState(Qt::Checked);
149 connect(controls->plotTypeCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(setPlotType(QString)));
150 connect(controls->fileSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setFileSymbolType(int)));
151 connect(controls->byteSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setByteSymbolType(int)));
152 connect(controls->fileCheck, SIGNAL(stateChanged(int)), this, SLOT(fileCheckChanged(int)));
153 connect(controls->byteCheck, SIGNAL(stateChanged(int)), this, SLOT(byteCheckChanged(int)));
154 connect(controls->refreshButton, SIGNAL(pressed()), this, SLOT(reGraph()));
156 controls->clientComboBox->addItem(tr("Any"));
157 controls->clientComboBox->addItems(m_console->client_list);
159 QStringList volumeList;
160 m_console->getVolumeList(volumeList);
161 controls->volumeComboBox->addItem(tr("Any"));
162 controls->volumeComboBox->addItems(volumeList);
163 controls->jobComboBox->addItem(tr("Any"));
164 controls->jobComboBox->addItems(m_console->job_list);
166 levelComboFill(controls->levelComboBox);
168 boolComboFill(controls->purgedComboBox);
170 controls->fileSetComboBox->addItem(tr("Any"));
171 controls->fileSetComboBox->addItems(m_console->fileset_list);
172 QStringList statusLongList;
173 m_console->getStatusList(statusLongList);
174 controls->statusComboBox->addItem(tr("Any"));
175 controls->statusComboBox->addItems(statusLongList);
178 controls->limitCheckBox->setCheckState(m_pass.recordLimitCheck);
179 controls->limitSpinBox->setValue(m_pass.recordLimitSpin);
180 controls->daysCheckBox->setCheckState(m_pass.daysLimitCheck);
181 controls->daysSpinBox->setValue(m_pass.daysLimitSpin);
183 comboSel(controls->jobComboBox, m_pass.jobCombo);
184 comboSel(controls->clientComboBox, m_pass.clientCombo);
185 comboSel(controls->volumeComboBox, m_pass.volumeCombo);
186 comboSel(controls->fileSetComboBox, m_pass.fileSetCombo);
187 comboSel(controls->purgedComboBox, m_pass.purgedCombo);
188 comboSel(controls->levelComboBox, m_pass.levelCombo);
189 comboSel(controls->statusComboBox, m_pass.statusCombo);
192 /* Set Defaults for check and spin for limits */
193 controls->limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
194 controls->limitSpinBox->setValue(mainWin->m_recordLimitVal);
195 controls->daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
196 controls->daysSpinBox->setValue(mainWin->m_daysLimitVal);
201 * Setup the control widgets for the graph, this are the objects from JobPlotControls
203 void JobPlot::runQuery()
207 query += "SELECT DISTINCT "
208 " Job.Starttime AS JobStart,"
209 " Job.Jobfiles AS FileCount,"
210 " Job.JobBytes AS Bytes,"
211 " Job.JobId AS JobId"
213 " JOIN Client ON (Client.ClientId=Job.ClientId)"
214 " JOIN Status ON (Job.JobStatus=Status.JobStatus)"
215 " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId)";
217 QStringList conditions;
218 comboCond(conditions, controls->jobComboBox, "Job.Name");
219 comboCond(conditions, controls->clientComboBox, "Client.Name");
220 int volumeIndex = controls->volumeComboBox->currentIndex();
221 if ((volumeIndex != -1) && (controls->volumeComboBox->itemText(volumeIndex) != tr("Any"))) {
222 query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId)"
223 " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId)";
224 conditions.append("Media.VolumeName='" + controls->volumeComboBox->itemText(volumeIndex) + "'");
226 comboCond(conditions, controls->fileSetComboBox, "FileSet.FileSet");
227 boolComboCond(conditions, controls->purgedComboBox, "Job.PurgedFiles");
228 levelComboCond(conditions, controls->levelComboBox, "Job.Level");
229 comboCond(conditions, controls->statusComboBox, "Status.JobStatusLong");
231 /* If Limit check box For limit by days is checked */
232 if (controls->daysCheckBox->checkState() == Qt::Checked) {
233 QDateTime stamp = QDateTime::currentDateTime().addDays(-controls->daysSpinBox->value());
234 QString since = stamp.toString(Qt::ISODate);
235 conditions.append("Job.Starttime>'" + since + "'");
238 foreach (QString condition, conditions) {
240 query += " WHERE " + condition;
243 query += " AND " + condition;
247 query += " ORDER BY Job.Starttime DESC, Job.JobId DESC";
248 /* If Limit check box for limit records returned is checked */
249 if (controls->limitCheckBox->checkState() == Qt::Checked) {
251 limit.setNum(controls->limitSpinBox->value());
252 query += " LIMIT " + limit;
255 if (mainWin->m_sqlDebug) {
256 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
260 if (m_console->sql_cmd(query, results)) {
263 QStringList fieldlist;
266 /* Iterate through the record returned from the query */
267 foreach (resultline, results) {
268 PlotJobData *plotJobData = new PlotJobData();
269 fieldlist = resultline.split("\t");
271 QString statusCode("");
272 /* Iterate through fields in the record */
273 foreach (field, fieldlist) {
274 field = field.trimmed(); /* strip leading & trailing spaces */
276 plotJobData->dt = QDateTime::fromString(field, mainWin->m_dtformat);
277 } else if (column == 1) {
278 plotJobData->files = field.toDouble();
279 } else if (column == 2) {
280 plotJobData->bytes = field.toDouble();
283 m_pjd.prepend(plotJobData);
288 if ((controls->volumeComboBox->itemText(volumeIndex) != tr("Any")) && (results.count() == 0)){
289 /* for context sensitive searches, let the user know if there were no
291 QMessageBox::warning(this, "Bat",
292 tr("The Jobs query returned no results.\n"
293 "Press OK to continue?"), QMessageBox::Ok );
298 * The user interface that used to be in the ui header. I wanted to have a
299 * scroll area which is not in designer.
301 void JobPlot::setupUserInterface()
303 QSizePolicy sizePolicy(static_cast<QSizePolicy::Policy>(1), static_cast<QSizePolicy::Policy>(5));
304 sizePolicy.setHorizontalStretch(0);
305 sizePolicy.setVerticalStretch(0);
306 sizePolicy.setVerticalStretch(0);
307 sizePolicy.setVerticalPolicy(QSizePolicy::Ignored);
308 sizePolicy.setHorizontalPolicy(QSizePolicy::Ignored);
309 m_gridLayout = new QGridLayout(this);
310 m_gridLayout->setSpacing(6);
311 m_gridLayout->setMargin(9);
312 m_gridLayout->setObjectName(QString::fromUtf8("m_gridLayout"));
313 m_splitter = new QSplitter(this);
314 m_splitter->setObjectName(QString::fromUtf8("m_splitter"));
315 m_splitter->setOrientation(Qt::Horizontal);
316 m_jobPlot = new QwtPlot(m_splitter);
317 m_jobPlot->setObjectName(QString::fromUtf8("m_jobPlot"));
318 m_jobPlot->setSizePolicy(sizePolicy);
319 m_jobPlot->setMinimumSize(QSize(0, 0));
320 QScrollArea *area = new QScrollArea(m_splitter);
321 area->setObjectName(QString::fromUtf8("area"));
322 controls = new JobPlotControls();
323 area->setWidget(controls);
325 m_splitter->addWidget(m_jobPlot);
326 m_splitter->addWidget(area);
328 m_gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
332 * Add the curves to the plot
334 void JobPlot::addCurve()
336 m_jobPlot->setTitle(tr("Files and Bytes backed up"));
337 m_jobPlot->insertLegend(new QwtLegend(), QwtPlot::RightLegend);
340 m_jobPlot->enableAxis(QwtPlot::yRight);
341 m_jobPlot->setAxisTitle(QwtPlot::yRight, tr("<-- Bytes Kb"));
342 m_jobPlot->setAxisTitle(m_jobPlot->xBottom, tr("date of backup -->"));
343 m_jobPlot->setAxisTitle(m_jobPlot->yLeft, tr("Number of Files -->"));
344 m_jobPlot->setAxisScaleDraw(QwtPlot::xBottom, new DateTimeScaleDraw());
347 m_fileCurve = new QwtPlotCurve( tr("Files") );
348 m_fileCurve->setPen(QPen(Qt::red));
349 m_fileCurve->setCurveType(m_fileCurve->Yfx);
350 m_fileCurve->setYAxis(QwtPlot::yLeft);
352 m_byteCurve = new QwtPlotCurve(tr("Bytes"));
353 m_byteCurve->setPen(QPen(Qt::blue));
354 m_byteCurve->setCurveType(m_byteCurve->Yfx);
355 m_byteCurve->setYAxis(QwtPlot::yRight);
356 setPlotType(controls->plotTypeCombo->currentText());
357 setFileSymbolType(controls->fileSymbolTypeCombo->currentIndex());
358 setByteSymbolType(controls->byteSymbolTypeCombo->currentIndex());
360 m_fileCurve->attach(m_jobPlot);
361 m_byteCurve->attach(m_jobPlot);
364 int size = m_pjd.count();
369 foreach (PlotJobData* plotJobData, m_pjd) {
370 // printf("%.0f %.0f %s\n", plotJobData->bytes, plotJobData->files,
371 // plotJobData->dt.toString(mainWin->m_dtformat).toUtf8().data());
372 fval[j] = plotJobData->files;
373 bval[j] = plotJobData->bytes / 1024;
374 tval[j] = plotJobData->dt.toTime_t();
375 // printf("%i %.0f %.0f %.0f\n", j, tval[j], fval[j], bval[j]);
378 m_fileCurve->setData(tval,fval,size);
379 m_byteCurve->setData(tval,bval,size);
381 for (int year=2000; year<2010; year++) {
382 for (int month=1; month<=12; month++) {
385 QTextStream(&monthBegin) << year << "-" << month << "-01 00:00:00";
387 QTextStream(&monthBegin) << year << "-0" << month << "-01 00:00:00";
389 QDateTime mdt = QDateTime::fromString(monthBegin, mainWin->m_dtformat);
390 double monbeg = mdt.toTime_t();
392 // ...a vertical line at the first of each month
393 QwtPlotMarker *mX = new QwtPlotMarker();
394 mX->setLabel(mdt.toString("MMM-d"));
395 mX->setLabelAlignment(Qt::AlignRight|Qt::AlignTop);
396 mX->setLineStyle(QwtPlotMarker::VLine);
397 QPen pen(Qt::darkGray);
398 pen.setStyle(Qt::DashDotDotLine);
400 mX->setXValue(monbeg);
401 mX->attach(m_jobPlot);
407 * slot to respond to the plot type combo changing
409 void JobPlot::setPlotType(QString currentText)
411 QwtPlotCurve::CurveStyle style = QwtPlotCurve::NoCurve;
412 if (currentText == tr("Fitted")) {
413 style = QwtPlotCurve::Lines;
414 m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
415 m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
416 } else if (currentText == tr("Sticks")) {
417 style = QwtPlotCurve::Sticks;
418 } else if (currentText == tr("Lines")) {
419 style = QwtPlotCurve::Lines;
420 m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
421 m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
422 } else if (currentText == tr("Steps")) {
423 style = QwtPlotCurve::Steps;
424 } else if (currentText == tr("None")) {
425 style = QwtPlotCurve::NoCurve;
427 m_fileCurve->setStyle(style);
428 m_byteCurve->setStyle(style);
432 void JobPlot::fillSymbolCombo(QComboBox *q)
434 q->addItem( tr("Ellipse"), (int)QwtSymbol::Ellipse);
435 q->addItem( tr("Rect"), (int)QwtSymbol::Rect);
436 q->addItem( tr("Diamond"), (int)QwtSymbol::Diamond);
437 q->addItem( tr("Triangle"), (int)QwtSymbol::Triangle);
438 q->addItem( tr("DTrianle"), (int)QwtSymbol::DTriangle);
439 q->addItem( tr("UTriangle"), (int)QwtSymbol::UTriangle);
440 q->addItem( tr("LTriangle"), (int)QwtSymbol::LTriangle);
441 q->addItem( tr("RTriangle"), (int)QwtSymbol::RTriangle);
442 q->addItem( tr("Cross"), (int)QwtSymbol::Cross);
443 q->addItem( tr("XCross"), (int)QwtSymbol::XCross);
444 q->addItem( tr("HLine"), (int)QwtSymbol::HLine);
445 q->addItem( tr("Vline"), (int)QwtSymbol::VLine);
446 q->addItem( tr("Star1"), (int)QwtSymbol::Star1);
447 q->addItem( tr("Star2"), (int)QwtSymbol::Star2);
448 q->addItem( tr("Hexagon"), (int)QwtSymbol::Hexagon);
449 q->addItem( tr("None"), (int)QwtSymbol::NoSymbol);
454 * slot to respond to the symbol type combo changing
456 void JobPlot::setFileSymbolType(int index)
458 setSymbolType(index, 0);
461 void JobPlot::setByteSymbolType(int index)
463 setSymbolType(index, 1);
465 void JobPlot::setSymbolType(int index, int type)
468 sym.setPen(QColor(Qt::black));
473 style = controls->fileSymbolTypeCombo->itemData(index);
474 sym.setStyle( (QwtSymbol::Style)style.toInt() );
475 sym.setBrush(QColor(Qt::yellow));
476 m_fileCurve->setSymbol(sym);
479 style = controls->byteSymbolTypeCombo->itemData(index);
480 sym.setStyle( (QwtSymbol::Style)style.toInt() );
481 sym.setBrush(QColor(Qt::blue));
482 m_byteCurve->setSymbol(sym);
489 * slot to respond to the file check box changing state
491 void JobPlot::fileCheckChanged(int newstate)
493 if (newstate == Qt::Unchecked) {
494 m_fileCurve->detach();
495 m_jobPlot->enableAxis(QwtPlot::yLeft, false);
497 m_fileCurve->attach(m_jobPlot);
498 m_jobPlot->enableAxis(QwtPlot::yLeft);
504 * slot to respond to the byte check box changing state
506 void JobPlot::byteCheckChanged(int newstate)
508 if (newstate == Qt::Unchecked) {
509 m_byteCurve->detach();
510 m_jobPlot->enableAxis(QwtPlot::yRight, false);
512 m_byteCurve->attach(m_jobPlot);
513 m_jobPlot->enableAxis(QwtPlot::yRight);
519 * Save user settings associated with this page
521 void JobPlot::writeSettings()
523 QSettings settings(m_console->m_dir->name(), "bat");
524 settings.beginGroup("JobPlot");
525 settings.setValue("m_splitterSizes", m_splitter->saveState());
526 settings.setValue("fileSymbolTypeCombo", controls->fileSymbolTypeCombo->currentText());
527 settings.setValue("byteSymbolTypeCombo", controls->byteSymbolTypeCombo->currentText());
528 settings.setValue("plotTypeCombo", controls->plotTypeCombo->currentText());
533 * Read settings values for Controls
535 void JobPlot::readControlSettings()
537 QSettings settings(m_console->m_dir->name(), "bat");
538 settings.beginGroup("JobPlot");
539 int fileSymbolTypeIndex = controls->fileSymbolTypeCombo->findText(settings.value("fileSymbolTypeCombo").toString(), Qt::MatchExactly);
540 if (fileSymbolTypeIndex == -1) fileSymbolTypeIndex = 2;
541 controls->fileSymbolTypeCombo->setCurrentIndex(fileSymbolTypeIndex);
542 int byteSymbolTypeIndex = controls->byteSymbolTypeCombo->findText(settings.value("byteSymbolTypeCombo").toString(), Qt::MatchExactly);
543 if (byteSymbolTypeIndex == -1) byteSymbolTypeIndex = 3;
544 controls->byteSymbolTypeCombo->setCurrentIndex(byteSymbolTypeIndex);
545 int plotTypeIndex = controls->plotTypeCombo->findText(settings.value("plotTypeCombo").toString(), Qt::MatchExactly);
546 if (plotTypeIndex == -1) plotTypeIndex = 2;
547 controls->plotTypeCombo->setCurrentIndex(plotTypeIndex);
552 * Read and restore user settings associated with this page
554 void JobPlot::readSplitterSettings()
556 QSettings settings(m_console->m_dir->name(), "bat");
557 settings.beginGroup("JobPlot");
558 m_splitter->restoreState(settings.value("m_splitterSizes").toByteArray());