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 many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
22 * Dirk Bartley, March 2007
28 #include "util/comboutil.h"
29 #include "jobgraphs/jobplot.h"
32 JobPlotPass::JobPlotPass()
37 JobPlotPass& JobPlotPass::operator=(const JobPlotPass &cp)
40 recordLimitCheck = cp.recordLimitCheck;
41 daysLimitCheck = cp.daysLimitCheck;
42 recordLimitSpin = cp.recordLimitSpin;
43 daysLimitSpin = cp.daysLimitSpin;
44 jobCombo = cp.jobCombo;
45 clientCombo = cp.clientCombo;
46 volumeCombo = cp.volumeCombo;
47 fileSetCombo = cp.fileSetCombo;
48 purgedCombo = cp.purgedCombo;
49 levelCombo = cp.levelCombo;
50 statusCombo = cp.statusCombo;
55 * Constructor for the controls class which inherits QScrollArea and a ui header
57 JobPlotControls::JobPlotControls()
63 * Constructor, this class does not inherit anything but pages.
65 JobPlot::JobPlot(QTreeWidgetItem *parentTreeWidgetItem, JobPlotPass &passVals)
69 pgInitialize(tr("JobPlot"), parentTreeWidgetItem);
70 readSplitterSettings();
71 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
72 thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/applications-graphics.png")));
75 /* this invokes the pass values = operator function */
78 /* If the values of the controls are predetermined (from joblist), then set
79 * this class as current window at the front of the stack */
96 * This is called when the page selector has this page selected
98 void JobPlot::currentStackItem()
108 * Slot for the refresh push button, also called from constructor.
110 void JobPlot::reGraph()
121 * Setup the control widgets for the graph, this are the objects from JobPlotControls
123 void JobPlot::setupControls()
125 QStringList graphType = QStringList() << /* tr("Fitted") <<*/ tr("Sticks")
126 << tr("Lines") << tr("Steps") << tr("None");
127 controls->plotTypeCombo->addItems(graphType);
129 fillSymbolCombo(controls->fileSymbolTypeCombo);
130 fillSymbolCombo(controls->byteSymbolTypeCombo);
132 readControlSettings();
134 controls->fileCheck->setCheckState(Qt::Checked);
135 controls->byteCheck->setCheckState(Qt::Checked);
136 connect(controls->plotTypeCombo, SIGNAL(currentIndexChanged(QString)), this, SLOT(setPlotType(QString)));
137 connect(controls->fileSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setFileSymbolType(int)));
138 connect(controls->byteSymbolTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setByteSymbolType(int)));
139 connect(controls->fileCheck, SIGNAL(stateChanged(int)), this, SLOT(fileCheckChanged(int)));
140 connect(controls->byteCheck, SIGNAL(stateChanged(int)), this, SLOT(byteCheckChanged(int)));
141 connect(controls->refreshButton, SIGNAL(pressed()), this, SLOT(reGraph()));
143 controls->clientComboBox->addItem(tr("Any"));
144 controls->clientComboBox->addItems(m_console->client_list);
146 QStringList volumeList;
147 getVolumeList(volumeList);
148 controls->volumeComboBox->addItem(tr("Any"));
149 controls->volumeComboBox->addItems(volumeList);
150 controls->jobComboBox->addItem(tr("Any"));
151 controls->jobComboBox->addItems(m_console->job_list);
153 levelComboFill(controls->levelComboBox);
155 boolComboFill(controls->purgedComboBox);
157 controls->fileSetComboBox->addItem(tr("Any"));
158 controls->fileSetComboBox->addItems(m_console->fileset_list);
159 QStringList statusLongList;
160 getStatusList(statusLongList);
161 controls->statusComboBox->addItem(tr("Any"));
162 controls->statusComboBox->addItems(statusLongList);
165 controls->limitCheckBox->setCheckState(m_pass.recordLimitCheck);
166 controls->limitSpinBox->setValue(m_pass.recordLimitSpin);
167 controls->daysCheckBox->setCheckState(m_pass.daysLimitCheck);
168 controls->daysSpinBox->setValue(m_pass.daysLimitSpin);
170 comboSel(controls->jobComboBox, m_pass.jobCombo);
171 comboSel(controls->clientComboBox, m_pass.clientCombo);
172 comboSel(controls->volumeComboBox, m_pass.volumeCombo);
173 comboSel(controls->fileSetComboBox, m_pass.fileSetCombo);
174 comboSel(controls->purgedComboBox, m_pass.purgedCombo);
175 comboSel(controls->levelComboBox, m_pass.levelCombo);
176 comboSel(controls->statusComboBox, m_pass.statusCombo);
179 /* Set Defaults for check and spin for limits */
180 controls->limitCheckBox->setCheckState(mainWin->m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
181 controls->limitSpinBox->setValue(mainWin->m_recordLimitVal);
182 controls->daysCheckBox->setCheckState(mainWin->m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
183 controls->daysSpinBox->setValue(mainWin->m_daysLimitVal);
188 * Setup the control widgets for the graph, this are the objects from JobPlotControls
190 void JobPlot::runQuery()
194 query += "SELECT DISTINCT "
195 " Job.Starttime AS JobStart,"
196 " Job.Jobfiles AS FileCount,"
197 " Job.JobBytes AS Bytes,"
198 " Job.JobId AS JobId"
200 " JOIN Client ON (Client.ClientId=Job.ClientId)"
201 " JOIN Status ON (Job.JobStatus=Status.JobStatus)"
202 " LEFT OUTER JOIN FileSet ON (FileSet.FileSetId=Job.FileSetId)";
204 QStringList conditions;
205 comboCond(conditions, controls->jobComboBox, "Job.Name");
206 comboCond(conditions, controls->clientComboBox, "Client.Name");
207 int volumeIndex = controls->volumeComboBox->currentIndex();
208 if ((volumeIndex != -1) && (controls->volumeComboBox->itemText(volumeIndex) != tr("Any"))) {
209 query += " LEFT OUTER JOIN JobMedia ON (JobMedia.JobId=Job.JobId)"
210 " LEFT OUTER JOIN Media ON (JobMedia.MediaId=Media.MediaId)";
211 conditions.append("Media.VolumeName='" + controls->volumeComboBox->itemText(volumeIndex) + "'");
213 comboCond(conditions, controls->fileSetComboBox, "FileSet.FileSet");
214 boolComboCond(conditions, controls->purgedComboBox, "Job.PurgedFiles");
215 levelComboCond(conditions, controls->levelComboBox, "Job.Level");
216 comboCond(conditions, controls->statusComboBox, "Status.JobStatusLong");
218 /* If Limit check box For limit by days is checked */
219 if (controls->daysCheckBox->checkState() == Qt::Checked) {
220 QDateTime stamp = QDateTime::currentDateTime().addDays(-controls->daysSpinBox->value());
221 QString since = stamp.toString(Qt::ISODate);
222 conditions.append("Job.Starttime>'" + since + "'");
225 foreach (QString condition, conditions) {
227 query += " WHERE " + condition;
230 query += " AND " + condition;
234 query += " ORDER BY Job.Starttime DESC, Job.JobId DESC";
235 /* If Limit check box for limit records returned is checked */
236 if (controls->limitCheckBox->checkState() == Qt::Checked) {
238 limit.setNum(controls->limitSpinBox->value());
239 query += " LIMIT " + limit;
242 if (mainWin->m_sqlDebug) {
243 Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
247 if (m_console->sql_cmd(query, results)) {
250 QStringList fieldlist;
253 /* Iterate through the record returned from the query */
254 foreach (resultline, results) {
255 PlotJobData *plotJobData = new PlotJobData();
256 fieldlist = resultline.split("\t");
258 QString statusCode("");
259 /* Iterate through fields in the record */
260 foreach (field, fieldlist) {
261 field = field.trimmed(); /* strip leading & trailing spaces */
263 plotJobData->dt = QDateTime::fromString(field, mainWin->m_dtformat);
264 } else if (column == 1) {
265 plotJobData->files = field.toDouble();
266 } else if (column == 2) {
267 plotJobData->bytes = field.toDouble();
270 m_pjd.prepend(plotJobData);
275 if ((controls->volumeComboBox->itemText(volumeIndex) != tr("Any")) && (results.count() == 0)){
276 /* for context sensitive searches, let the user know if there were no
278 QMessageBox::warning(this, "Bat",
279 tr("The Jobs query returned no results.\n"
280 "Press OK to continue?"), QMessageBox::Ok );
285 * The user interface that used to be in the ui header. I wanted to have a
286 * scroll area which is not in designer.
288 void JobPlot::setupUserInterface()
290 QSizePolicy sizePolicy(static_cast<QSizePolicy::Policy>(1), static_cast<QSizePolicy::Policy>(5));
291 sizePolicy.setHorizontalStretch(0);
292 sizePolicy.setVerticalStretch(0);
293 sizePolicy.setVerticalStretch(0);
294 sizePolicy.setVerticalPolicy(QSizePolicy::Ignored);
295 sizePolicy.setHorizontalPolicy(QSizePolicy::Ignored);
296 m_gridLayout = new QGridLayout(this);
297 m_gridLayout->setSpacing(6);
298 m_gridLayout->setMargin(9);
299 m_gridLayout->setObjectName(QString::fromUtf8("m_gridLayout"));
300 m_splitter = new QSplitter(this);
301 m_splitter->setObjectName(QString::fromUtf8("m_splitter"));
302 m_splitter->setOrientation(Qt::Horizontal);
303 m_jobPlot = new QwtPlot(m_splitter);
304 m_jobPlot->setObjectName(QString::fromUtf8("m_jobPlot"));
305 m_jobPlot->setSizePolicy(sizePolicy);
306 m_jobPlot->setMinimumSize(QSize(0, 0));
307 QScrollArea *area = new QScrollArea(m_splitter);
308 area->setObjectName(QString::fromUtf8("area"));
309 controls = new JobPlotControls();
310 area->setWidget(controls);
312 m_splitter->addWidget(m_jobPlot);
313 m_splitter->addWidget(area);
315 m_gridLayout->addWidget(m_splitter, 0, 0, 1, 1);
319 * Add the curves to the plot
321 void JobPlot::addCurve()
323 m_jobPlot->setTitle(tr("Files and Bytes backed up"));
324 m_jobPlot->insertLegend(new QwtLegend(), QwtPlot::RightLegend);
327 m_jobPlot->enableAxis(QwtPlot::yRight);
328 m_jobPlot->setAxisTitle(QwtPlot::yRight, tr("<-- Bytes Kb"));
329 m_jobPlot->setAxisTitle(m_jobPlot->xBottom, tr("date of backup -->"));
330 m_jobPlot->setAxisTitle(m_jobPlot->yLeft, tr("Number of Files -->"));
331 m_jobPlot->setAxisScaleDraw(QwtPlot::xBottom, new DateTimeScaleDraw());
334 m_fileCurve = new QwtPlotCurve( tr("Files") );
335 m_fileCurve->setPen(QPen(Qt::red));
336 m_fileCurve->setCurveType(m_fileCurve->Yfx);
337 m_fileCurve->setYAxis(QwtPlot::yLeft);
339 m_byteCurve = new QwtPlotCurve(tr("Bytes"));
340 m_byteCurve->setPen(QPen(Qt::blue));
341 m_byteCurve->setCurveType(m_byteCurve->Yfx);
342 m_byteCurve->setYAxis(QwtPlot::yRight);
343 setPlotType(controls->plotTypeCombo->currentText());
344 setFileSymbolType(controls->fileSymbolTypeCombo->currentIndex());
345 setByteSymbolType(controls->byteSymbolTypeCombo->currentIndex());
347 m_fileCurve->attach(m_jobPlot);
348 m_byteCurve->attach(m_jobPlot);
351 int size = m_pjd.count();
362 tval = (double *)malloc(size * sizeof(double));
363 fval = (double *)malloc(size * sizeof(double));
364 bval = (double *)malloc(size * sizeof(double));
367 foreach (PlotJobData* plotJobData, m_pjd) {
368 // printf("%.0f %.0f %s\n", plotJobData->bytes, plotJobData->files,
369 // plotJobData->dt.toString(mainWin->m_dtformat).toUtf8().data());
370 fval[j] = plotJobData->files;
371 bval[j] = plotJobData->bytes / 1024;
372 tval[j] = plotJobData->dt.toTime_t();
373 // printf("%i %.0f %.0f %.0f\n", j, tval[j], fval[j], bval[j]);
376 m_fileCurve->setData(tval,fval,size);
377 m_byteCurve->setData(tval,bval,size);
379 for (int year=2000; year<2010; year++) {
380 for (int month=1; month<=12; month++) {
383 QTextStream(&monthBegin) << year << "-" << month << "-01 00:00:00";
385 QTextStream(&monthBegin) << year << "-0" << month << "-01 00:00:00";
387 QDateTime mdt = QDateTime::fromString(monthBegin, mainWin->m_dtformat);
388 double monbeg = mdt.toTime_t();
390 // ...a vertical line at the first of each month
391 QwtPlotMarker *mX = new QwtPlotMarker();
392 mX->setLabel(mdt.toString("MMM-d"));
393 mX->setLabelAlignment(Qt::AlignRight|Qt::AlignTop);
394 mX->setLineStyle(QwtPlotMarker::VLine);
395 QPen pen(Qt::darkGray);
396 pen.setStyle(Qt::DashDotDotLine);
398 mX->setXValue(monbeg);
399 mX->attach(m_jobPlot);
403 #if !defined(__GNU_C)
411 * slot to respond to the plot type combo changing
413 void JobPlot::setPlotType(QString currentText)
415 QwtPlotCurve::CurveStyle style = QwtPlotCurve::NoCurve;
416 if (currentText == tr("Fitted")) {
417 style = QwtPlotCurve::Lines;
418 m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
419 m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
420 } else if (currentText == tr("Sticks")) {
421 style = QwtPlotCurve::Sticks;
422 } else if (currentText == tr("Lines")) {
423 style = QwtPlotCurve::Lines;
424 m_fileCurve->setCurveAttribute(QwtPlotCurve::Fitted);
425 m_byteCurve->setCurveAttribute(QwtPlotCurve::Fitted);
426 } else if (currentText == tr("Steps")) {
427 style = QwtPlotCurve::Steps;
428 } else if (currentText == tr("None")) {
429 style = QwtPlotCurve::NoCurve;
431 m_fileCurve->setStyle(style);
432 m_byteCurve->setStyle(style);
436 void JobPlot::fillSymbolCombo(QComboBox *q)
438 q->addItem( tr("Ellipse"), (int)QwtSymbol::Ellipse);
439 q->addItem( tr("Rect"), (int)QwtSymbol::Rect);
440 q->addItem( tr("Diamond"), (int)QwtSymbol::Diamond);
441 q->addItem( tr("Triangle"), (int)QwtSymbol::Triangle);
442 q->addItem( tr("DTrianle"), (int)QwtSymbol::DTriangle);
443 q->addItem( tr("UTriangle"), (int)QwtSymbol::UTriangle);
444 q->addItem( tr("LTriangle"), (int)QwtSymbol::LTriangle);
445 q->addItem( tr("RTriangle"), (int)QwtSymbol::RTriangle);
446 q->addItem( tr("Cross"), (int)QwtSymbol::Cross);
447 q->addItem( tr("XCross"), (int)QwtSymbol::XCross);
448 q->addItem( tr("HLine"), (int)QwtSymbol::HLine);
449 q->addItem( tr("Vline"), (int)QwtSymbol::VLine);
450 q->addItem( tr("Star1"), (int)QwtSymbol::Star1);
451 q->addItem( tr("Star2"), (int)QwtSymbol::Star2);
452 q->addItem( tr("Hexagon"), (int)QwtSymbol::Hexagon);
453 q->addItem( tr("None"), (int)QwtSymbol::NoSymbol);
458 * slot to respond to the symbol type combo changing
460 void JobPlot::setFileSymbolType(int index)
462 setSymbolType(index, 0);
465 void JobPlot::setByteSymbolType(int index)
467 setSymbolType(index, 1);
469 void JobPlot::setSymbolType(int index, int type)
472 sym.setPen(QColor(Qt::black));
477 style = controls->fileSymbolTypeCombo->itemData(index);
478 sym.setStyle( (QwtSymbol::Style)style.toInt() );
479 sym.setBrush(QColor(Qt::yellow));
480 m_fileCurve->setSymbol(sym);
483 style = controls->byteSymbolTypeCombo->itemData(index);
484 sym.setStyle( (QwtSymbol::Style)style.toInt() );
485 sym.setBrush(QColor(Qt::blue));
486 m_byteCurve->setSymbol(sym);
493 * slot to respond to the file check box changing state
495 void JobPlot::fileCheckChanged(int newstate)
497 if (newstate == Qt::Unchecked) {
498 m_fileCurve->detach();
499 m_jobPlot->enableAxis(QwtPlot::yLeft, false);
501 m_fileCurve->attach(m_jobPlot);
502 m_jobPlot->enableAxis(QwtPlot::yLeft);
508 * slot to respond to the byte check box changing state
510 void JobPlot::byteCheckChanged(int newstate)
512 if (newstate == Qt::Unchecked) {
513 m_byteCurve->detach();
514 m_jobPlot->enableAxis(QwtPlot::yRight, false);
516 m_byteCurve->attach(m_jobPlot);
517 m_jobPlot->enableAxis(QwtPlot::yRight);
523 * Save user settings associated with this page
525 void JobPlot::writeSettings()
527 QSettings settings(m_console->m_dir->name(), "bat");
528 settings.beginGroup("JobPlot");
529 settings.setValue("m_splitterSizes", m_splitter->saveState());
530 settings.setValue("fileSymbolTypeCombo", controls->fileSymbolTypeCombo->currentText());
531 settings.setValue("byteSymbolTypeCombo", controls->byteSymbolTypeCombo->currentText());
532 settings.setValue("plotTypeCombo", controls->plotTypeCombo->currentText());
537 * Read settings values for Controls
539 void JobPlot::readControlSettings()
541 QSettings settings(m_console->m_dir->name(), "bat");
542 settings.beginGroup("JobPlot");
543 int fileSymbolTypeIndex = controls->fileSymbolTypeCombo->findText(settings.value("fileSymbolTypeCombo").toString(), Qt::MatchExactly);
544 if (fileSymbolTypeIndex == -1) fileSymbolTypeIndex = 2;
545 controls->fileSymbolTypeCombo->setCurrentIndex(fileSymbolTypeIndex);
546 int byteSymbolTypeIndex = controls->byteSymbolTypeCombo->findText(settings.value("byteSymbolTypeCombo").toString(), Qt::MatchExactly);
547 if (byteSymbolTypeIndex == -1) byteSymbolTypeIndex = 3;
548 controls->byteSymbolTypeCombo->setCurrentIndex(byteSymbolTypeIndex);
549 int plotTypeIndex = controls->plotTypeCombo->findText(settings.value("plotTypeCombo").toString(), Qt::MatchExactly);
550 if (plotTypeIndex == -1) plotTypeIndex = 2;
551 controls->plotTypeCombo->setCurrentIndex(plotTypeIndex);
556 * Read and restore user settings associated with this page
558 void JobPlot::readSplitterSettings()
560 QSettings settings(m_console->m_dir->name(), "bat");
561 settings.beginGroup("JobPlot");
562 if (settings.contains("m_splitterSizes")) {
563 m_splitter->restoreState(settings.value("m_splitterSizes").toByteArray());