]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/job/job.cpp
5c8568ba1e2c632f2bd2185725d350cf634c6ad8
[bacula/bacula] / bacula / src / qt-console / job / job.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2009 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 Kern Sibbald.
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  *  Job Class
33  *
34  *   Dirk Bartley, March 2007
35  *
36  */ 
37
38 #include "bat.h"
39 #include "job.h"
40 #include "util/fmtwidgetitem.h"
41
42 Job::Job(QString &jobId, QTreeWidgetItem *parentTreeWidgetItem)
43 {
44    setupUi(this);
45    m_closeable = true;
46    pgInitialize(tr("Job"), parentTreeWidgetItem);
47    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
48    thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/joblog.png")));
49    m_cursor = new QTextCursor(textJobLog->document());
50
51    m_jobId = jobId;
52    getFont();
53
54    connect(pbRefresh, SIGNAL(clicked()), this, SLOT(populateAll()));
55    connect(pbDelete, SIGNAL(clicked()), this, SLOT(deleteJob()));
56
57    populateAll();
58    dockPage();
59    setCurrent();
60 }
61
62 void Job::deleteJob()
63 {
64    if (QMessageBox::warning(this, "Bat",
65       tr("Are you sure you want to delete??  !!!.\n"
66 "This delete command is used to delete a Job record and all associated catalog"
67 " records that were created. This command operates only on the Catalog"
68 " database and has no effect on the actual data written to a Volume. This"
69 " command can be dangerous and we strongly recommend that you do not use"
70 " it unless you know what you are doing.  The Job and all its associated"
71 " records (File and JobMedia) will be deleted from the catalog."
72       "Press OK to proceed with delete operation.?"),
73       QMessageBox::Ok | QMessageBox::Cancel)
74       == QMessageBox::Cancel) { return; }
75
76    QString cmd("delete job jobid=");
77    cmd += m_jobId;
78    consoleCommand(cmd, false);
79    closeStackPage();
80 }
81
82 void Job::getFont()
83 {
84    QFont font = textJobLog->font();
85
86    QString dirname;
87    m_console->getDirResName(dirname);
88    QSettings settings(dirname, "bat");
89    settings.beginGroup("Console");
90    font.setFamily(settings.value("consoleFont", "Courier").value<QString>());
91    font.setPointSize(settings.value("consolePointSize", 10).toInt());
92    font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool());
93    settings.endGroup();
94    textJobLog->setFont(font);
95 }
96
97 void Job::populateAll()
98 {
99    Pmsg0(0, "populateAll()\n");
100    populateText();
101    populateForm();
102    populateVolumes();
103 }
104
105 /*
106  * Populate the text in the window
107  */
108 void Job::populateText()
109 {
110    textJobLog->clear();
111    QString query;
112    query = "SELECT Time, LogText FROM Log WHERE JobId='" + m_jobId + "' order by Time";
113
114    /* This could be a log item */
115    if (mainWin->m_sqlDebug) {
116       Pmsg1(000, "Log query cmd : %s\n", query.toUtf8().data());
117    }
118   
119    QStringList results;
120    if (m_console->sql_cmd(query, results)) {
121
122       if (!results.size()) {
123          QMessageBox::warning(this, tr("Bat"),
124             tr("There were no results!\n"
125                "It is possible you may need to add \"catalog = all\" "
126                "to the Messages resource for this job.\n"), QMessageBox::Ok);
127          return;
128       } 
129
130       QString jobstr("JobId "); /* FIXME: should this be translated ? */
131       jobstr += m_jobId;
132
133       QString htmlbuf("<html><body><pre>");
134   
135       /* Iterate through the lines of results. */
136       QString field;
137       QStringList fieldlist;
138       QString lastTime;
139       QString lastSvc;
140       foreach (QString resultline, results) {
141          fieldlist = resultline.split("\t");
142          
143          if (fieldlist.size() < 2)
144             continue;
145
146          QString curTime = fieldlist[0].trimmed();
147
148          field = fieldlist[1].trimmed();
149          int colon = field.indexOf(":");
150          if (colon > 0) {
151             /* string is like <service> <jobId xxxx>: ..." 
152              * we split at ':' then remove the jobId xxxx string (always the same) */ 
153             QString curSvc(field.left(colon).replace(jobstr,"").trimmed());
154             if (curSvc == lastSvc  && curTime == lastTime) {
155                curTime.clear();
156                curSvc.clear(); 
157             } else {
158                lastTime = curTime;
159                lastSvc = curSvc;
160             }
161 //          htmlbuf += "<td>" + curTime + "</td>";
162             htmlbuf += "\n" + curSvc + " ";
163
164             /* rest of string is marked as pre-formatted (here trimming should
165              * be avoided, to preserve original formatting) */
166             QString msg(field.mid(colon+2));
167             if (msg.startsWith( tr("Error:")) ) { /* FIXME: should really be translated ? */
168                /* error msg, use a specific class */
169                htmlbuf += "</pre><pre class=err>" + msg + "</pre><pre>";
170             } else {
171                htmlbuf += msg ;
172             }
173          } else {
174             /* non standard string, place as-is */
175             if (curTime == lastTime) {
176                curTime.clear();
177             } else {
178                lastTime = curTime;
179             }
180 //          htmlbuf += "<td>" + curTime + "</td>";
181             htmlbuf += "\n" + field ;
182          }
183   
184       } /* foreach resultline */
185
186       htmlbuf += "</pre></body></html>";
187
188       /* full text ready. Here a custom sheet is used to align columns */
189       QString logSheet(".err {color:#FF0000;}");
190       textJobLog->document()->setDefaultStyleSheet(logSheet);
191       textJobLog->document()->setHtml(htmlbuf); 
192       textJobLog->moveCursor(QTextCursor::Start);
193
194    } /* if results from query */
195   
196 }
197
198 // Need to use the fmtwidgetitem helper instead
199 QString convertBytesSI(qint64 qfld)
200 {
201    static const qint64 KB = Q_INT64_C(1000);
202    static const qint64 MB = (KB * KB);
203    static const qint64 GB = (MB * KB);
204    static const qint64 TB = (GB * KB);
205    static const qint64 PB = (TB * KB);
206    static const qint64 EB = (PB * KB);
207
208    /* note: division is integer, so to have some decimals we divide for a
209       smaller unit (e.g. GB for a TB number and so on) */
210    char suffix;
211    if (qfld >= EB) {
212       qfld /= PB; 
213       suffix = 'E';
214    }
215    else if (qfld >= PB) {
216       qfld /= TB; 
217       suffix = 'P';
218    }
219    else if (qfld >= TB) {
220       qfld /= GB; 
221       suffix = 'T';
222    }
223    else if (qfld >= GB) {
224       qfld /= MB;
225       suffix = 'G';
226    }
227    else if (qfld >= MB) {
228       qfld /= KB;
229       suffix = 'M';
230    }
231    else if (qfld >= KB) {
232       suffix = 'k'; /* SI uses lowercase k */
233    }
234    else  {
235       /* plain bytes, no need to reformat */
236       return QString("%1 B").arg(qfld); 
237    }
238
239    /* having divided for a smaller unit, now we can safely convert to double and
240       use the extra room for decimals */
241    return QString("%1 %2B").arg(qfld / 1000.0, 0, 'f', 2).arg(suffix);
242 }
243
244 /*
245  * Populate the text in the window
246  */
247 void Job::populateForm()
248 {
249    QString stat;
250    char buf[256];
251    QString query = 
252       "SELECT JobId, Job.Name, Level, Client.Name, Pool.Name, FileSet, SchedTime, StartTime, EndTime, "
253       "EndTime - StartTime AS Duration, JobBytes, JobFiles, JobErrors, JobStatus, PurgedFiles "
254       "FROM Job JOIN Client USING (ClientId) LEFT JOIN Pool USING (PoolId) "
255       "LEFT JOIN FileSet USING (FileSetId)"
256       "WHERE JobId=" + m_jobId; 
257    QStringList results;
258    if (m_console->sql_cmd(query, results)) {
259       QString resultline;
260       QStringList fieldlist;
261
262       foreach (resultline, results) { // should have only one result
263          fieldlist = resultline.split("\t");
264          QStringListIterator fld(fieldlist);
265          label_JobId->setText(fld.next());
266          label_Name->setText(fld.next());
267          
268          label_Level->setText(job_level_to_str(fld.next()[0].toAscii()));
269
270          label_Client->setText(fld.next());
271          label_Pool->setText(fld.next());
272          label_FileSet->setText(fld.next());
273          label_SchedTime->setText(fld.next());
274          label_StartTime->setText(fld.next());
275          label_EndTime->setText(fld.next());
276          label_Duration->setText(fld.next());
277
278          label_JobBytes->setText(convertBytesSI(fld.next().toULongLong()));
279          label_JobFiles->setText(fld.next());
280          label_JobErrors->setText(fld.next());
281
282          stat=fld.next();
283          label_JobStatus->setPixmap(QPixmap(":/images/" + stat + ".png"));
284          jobstatus_to_ascii_gui(stat[0].toAscii(), buf, sizeof(buf));
285          stat = buf;
286          label_JobStatus->setToolTip(stat);
287
288          chkbox_PurgedFiles->setCheckState(fld.next().toInt()?Qt::Checked:Qt::Unchecked);
289       }
290    }
291 }
292   
293 void Job::populateVolumes()
294 {
295
296    QString query = 
297       "SELECT DISTINCT VolumeName, InChanger, Slot "
298       "FROM Job JOIN JobMedia USING (JobId) JOIN Media USING (MediaId) "
299       "WHERE JobId=" + m_jobId + " ORDER BY VolumeName "; 
300    Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
301          
302
303    QStringList results;
304    if (m_console->sql_cmd(query, results)) {
305       QString resultline;
306       QStringList fieldlist;
307       list_Volume->clear();
308       foreach (resultline, results) { // should have only one result
309          fieldlist = resultline.split("\t");
310          QStringListIterator fld(fieldlist);
311 //         QListWidgetItem(QIcon(":/images/inchanger" + fld.next() + ".png"), 
312 //                         fld.next(), list_Volume);
313          list_Volume->addItem(fld.next());
314       }
315    }
316 }
317
318 //QListWidgetItem ( const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type )