]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/mainwin.cpp
0dcf4f60158fba25f555548e476938437ba313ae
[bacula/bacula] / bacula / src / qt-console / mainwin.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  *  Main Window control for bat (qt-console)
33  *
34  *   Kern Sibbald, January MMVII
35  *
36  */ 
37
38 #include "bat.h"
39 #include "joblist/joblist.h"
40 #include "storage/storage.h"
41 #include "fileset/fileset.h"
42 #include "label/label.h"
43 #include "run/run.h"
44 #include "pages.h"
45 #include "restore/restore.h"
46 #include "medialist/medialist.h"
47 #include "joblist/joblist.h"
48 #include "clients/clients.h"
49 #include "restore/restoretree.h"
50 #include "help/help.h"
51 #include "jobs/jobs.h"
52
53 /* 
54  * Daemon message callback
55  */
56 void message_callback(int /* type */, char *msg)
57 {
58    QMessageBox::warning(mainWin, "Bat", msg, QMessageBox::Ok);
59 }
60
61 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
62 {
63    m_dtformat = "yyyy-MM-dd HH:mm:ss";
64    mainWin = this;
65    setupUi(this);                     /* Setup UI defined by main.ui (designer) */
66    register_message_callback(message_callback);
67    readPreferences();
68    treeWidget->clear();
69    treeWidget->setColumnCount(1);
70    treeWidget->setHeaderLabel("Select Page");
71    treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
72
73    createPages();
74
75    resetFocus();
76
77    createConnections();
78
79    this->show();
80
81    readSettings();
82
83    foreach(Console *console, m_consoleHash) {
84       console->connect_dir();
85    }
86    m_currentConsole = (Console*)getFromHash(m_firstItem);
87    m_currentConsole->setCurrent();
88    if (m_miscDebug) {
89       QString directoryResourceName;
90       m_currentConsole->getDirResName(directoryResourceName);
91       Pmsg1(000, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
92    }
93 }
94
95 void MainWin::createPages()
96 {
97    DIRRES *dir;
98    QTreeWidgetItem *item, *topItem;
99    m_firstItem = NULL;
100
101    LockRes();
102    foreach_res(dir, R_DIRECTOR) {
103
104       /* Create console tree stacked widget item */
105       m_currentConsole = new Console(stackedWidget);
106       m_currentConsole->setDirRes(dir);
107       m_currentConsole->readSettings();
108
109       /* The top tree item representing the director */
110       topItem = new QTreeWidgetItem(treeWidget);
111       topItem->setText(0, dir->name());
112       topItem->setIcon(0, QIcon(":images/server.png"));
113       /* Set background to grey for ease of identification of inactive Director */
114       QBrush greyBrush(Qt::lightGray);
115       topItem->setBackground(0, greyBrush);
116       m_currentConsole->setDirectorTreeItem(topItem);
117       m_consoleHash.insert(topItem, m_currentConsole);
118
119       /* Create Tree Widget Item */
120       item = new QTreeWidgetItem(topItem);
121       item->setText(0, "Console");
122       if (!m_firstItem){ m_firstItem = item; }
123       item->setIcon(0,QIcon(QString::fromUtf8(":images/utilities-terminal.svg")));
124
125       /* insert the cosole and tree widget item into the hashes */
126       hashInsert(item, m_currentConsole);
127
128       /* Set Color of treeWidgetItem for the console
129       * It will be set to green in the console class if the connection is made.
130       */
131       QBrush redBrush(Qt::red);
132       item->setForeground(0, redBrush);
133       m_currentConsole->dockPage();
134
135       /*
136        * Create instances in alphabetic order of the rest 
137        *  of the classes that will by default exist under each Director.  
138        */
139 //      new bRestore();
140       new Clients();
141       new FileSet();
142       new Jobs();
143       createPageJobList("", "", "", "", NULL);
144       new MediaList();
145       new Storage();
146       new restoreTree();
147
148       treeWidget->expandItem(topItem);
149       stackedWidget->setCurrentWidget(m_currentConsole);
150    }
151    UnlockRes();
152 }
153
154 /*
155  * create an instance of the the joblist class on the stack
156  */
157 void MainWin::createPageJobList(const QString &media, const QString &client,
158               const QString &job, const QString &fileset, QTreeWidgetItem *parentTreeWidgetItem)
159 {
160    QTreeWidgetItem *holdItem;
161
162    /* save current tree widget item in case query produces no results */
163    holdItem = treeWidget->currentItem();
164    JobList* joblist = new JobList(media, client, job, fileset, parentTreeWidgetItem);
165    /* If this is a query of jobs on a specific media */
166    if ((media != "") || (client != "") || (job != "") || (fileset != "")) {
167       joblist->setCurrent();
168       /* did query produce results, if not close window and set back to hold */
169       if (joblist->m_resultCount == 0) {
170          joblist->closeStackPage();
171          treeWidget->setCurrentItem(holdItem);
172       }
173    }
174 }
175
176 /*
177  * Handle up and down arrow keys for the command line
178  *  history.
179  */
180 void MainWin::keyPressEvent(QKeyEvent *event)
181 {
182    if (m_cmd_history.size() == 0) {
183       event->ignore();
184       return;
185    }
186    switch (event->key()) {
187    case Qt::Key_Down:
188       if (m_cmd_last < 0 || m_cmd_last >= (m_cmd_history.size()-1)) {
189          event->ignore();
190          return;
191       }
192       m_cmd_last++;
193       break;
194    case Qt::Key_Up:
195       if (m_cmd_last == 0) {
196          event->ignore();
197          return;
198       }
199       if (m_cmd_last < 0 || m_cmd_last > (m_cmd_history.size()-1)) {
200          m_cmd_last = m_cmd_history.size() - 1;
201       } else {
202          m_cmd_last--;
203       }
204       break;
205    default:
206       event->ignore();
207       return;
208    }
209    lineEdit->setText(m_cmd_history[m_cmd_last]);
210 }
211
212 void MainWin::createConnections()
213 {
214    /* Connect signals to slots */
215    connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
216    connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
217    connect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
218    connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, 
219            SLOT(treeItemClicked(QTreeWidgetItem *, int)));
220    connect(treeWidget, SIGNAL(
221            currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
222            this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
223    connect(stackedWidget, SIGNAL(currentChanged(int)),
224            this, SLOT(stackItemChanged(int)));
225    connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
226    connect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
227    connect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
228    connect(actionEstimate, SIGNAL(triggered()), this,  SLOT(estimateButtonClicked()));
229    connect(actionBrowse, SIGNAL(triggered()), this,  SLOT(browseButtonClicked()));
230    connect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
231    connect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
232    connect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
233    connect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closePage()));
234    connect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
235 }
236
237 /* 
238  * Reimplementation of QWidget closeEvent virtual function   
239  */
240 void MainWin::closeEvent(QCloseEvent *event)
241 {
242    writeSettings();
243    foreach(Console *console, m_consoleHash){
244       console->writeSettings();
245       console->terminate();
246    }
247    event->accept();
248    foreach(Pages *page, m_pagehash) {
249       if (!page->isDocked())
250          page->close();
251    }
252 }
253
254 void MainWin::writeSettings()
255 {
256    QSettings settings("bacula.org", "bat");
257
258    settings.beginGroup("MainWin");
259    settings.setValue("winSize", size());
260    settings.setValue("winPos", pos());
261    settings.setValue("state", saveState());
262    settings.endGroup();
263 }
264
265 void MainWin::readSettings()
266
267    QSettings settings("bacula.org", "bat");
268
269    settings.beginGroup("MainWin");
270    resize(settings.value("winSize", QSize(1041, 801)).toSize());
271    move(settings.value("winPos", QPoint(200, 150)).toPoint());
272    restoreState(settings.value("state").toByteArray());
273    settings.endGroup();
274 }
275
276 /*
277  * This subroutine is called with an item in the Page Selection window
278  *   is clicked 
279  */
280 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
281 {
282    /* Is this a page that has been inserted into the hash  */
283    if (getFromHash(item)) {
284       Pages* page = getFromHash(item);
285       int stackindex=stackedWidget->indexOf(page);
286
287       if (stackindex >= 0) {
288          stackedWidget->setCurrentWidget(page);
289       }
290       /* run the virtual function in case this class overrides it */
291       page->PgSeltreeWidgetClicked();
292    }
293 }
294
295 /*
296  * Called with a change of the highlighed tree widget item in the page selector.
297  */
298 void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *previousitem)
299 {
300    Pages *previousPage, *nextPage;
301    Console *previousConsole, *nextConsole;
302
303    /* remove all actions before adding actions appropriate for new page */
304    foreach(QAction* pageAction, treeWidget->actions()) {
305       treeWidget->removeAction(pageAction);
306    }
307
308    /* first determine the next item */
309
310    /* knowing the treeWidgetItem, get the page from the hash */
311    nextPage = getFromHash(currentitem);
312    nextConsole = m_consoleHash.value(currentitem);
313    /* Is this a page that has been inserted into the hash  */
314    if (nextPage) {
315       nextConsole = nextPage->console();
316       /* then is it a treeWidgetItem representing a director */
317    } else if (nextConsole) {
318       /* let the next page BE the console */
319       nextPage = nextConsole;
320    } else {
321       /* Should never get here */
322       nextPage = NULL;
323       nextConsole = NULL;
324    }
325           
326    /* The Previous item */
327
328    /* this condition prevents a segfault.  The first time there is no previousitem*/
329    if (previousitem) {
330       /* knowing the treeWidgetItem, get the page from the hash */
331       previousPage = getFromHash(previousitem);
332       previousConsole = m_consoleHash.value(previousitem);
333       if (previousPage) {
334          previousConsole = previousPage->console();
335       } else if (previousConsole) {
336          previousPage = previousConsole;
337       }
338       if ((previousPage) || (previousConsole)) {
339          if (nextConsole != previousConsole) {
340             /* remove connections to the current console */
341             disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect_dir()));
342             disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
343             disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
344             disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
345             QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
346             QBrush greyBrush(Qt::lightGray);
347             dirItem->setBackground(0, greyBrush);
348          }
349       }
350    }
351
352    /* process the current (next) item */
353    
354    if ((nextPage) || (nextConsole)) {
355       if (nextConsole != previousConsole) {
356          /* make connections to the current console */
357          m_currentConsole = nextConsole;
358          connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect_dir()));
359          connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
360          connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
361          connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
362          /* Set director's tree widget background to magenta for ease of identification */
363          QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
364          QBrush magentaBrush(Qt::magenta);
365          dirItem->setBackground(0, magentaBrush);
366       }
367       /* set the value for the currently active console */
368       int stackindex = stackedWidget->indexOf(nextPage);
369    
370       /* Is this page currently on the stack or is it undocked */
371       if (stackindex >= 0) {
372          /* put this page on the top of the stack */
373          stackedWidget->setCurrentIndex(stackindex);
374       } else {
375          /* it is undocked, raise it to the front */
376          nextPage->raise();
377       }
378       /* for the page selectors menu action to dock or undock, set the text */
379       nextPage->setContextMenuDockText();
380
381       treeWidget->addAction(actionToggleDock);
382       /* if this page is closeable, and it has no childern, then add that action */
383       if ((nextPage->isCloseable()) && (currentitem->child(0) == NULL))
384          treeWidget->addAction(actionClosePage);
385
386       /* Add the actions to the Page Selectors tree widget that are part of the
387        * current items list of desired actions regardless of whether on top of stack*/
388       treeWidget->addActions(nextPage->m_contextActions);
389    }
390 }
391
392 void MainWin::labelButtonClicked() 
393 {
394    new labelPage();
395 }
396
397 void MainWin::runButtonClicked() 
398 {
399    new runPage();
400 }
401
402 void MainWin::estimateButtonClicked() 
403 {
404    new estimatePage();
405 }
406
407 void MainWin::browseButtonClicked() 
408 {
409    new restoreTree();
410 }
411
412 void MainWin::restoreButtonClicked() 
413 {
414    new prerestorePage();
415 }
416
417 /*
418  * The user just finished typing a line in the command line edit box
419  */
420 void MainWin::input_line()
421 {
422    QString cmdStr = lineEdit->text();    /* Get the text */
423    lineEdit->clear();                    /* clear the lineEdit box */
424    if (m_currentConsole->is_connected()) {
425       /* Use consoleInput to allow typing anything */
426       m_currentConsole->consoleInput(cmdStr);
427    } else {
428       set_status("Director not connected. Click on connect button.");
429    }
430    m_cmd_history.append(cmdStr);
431    m_cmd_last = -1;
432    if (treeWidget->currentItem() != getFromHash(m_currentConsole))
433       m_currentConsole->setCurrent();
434 }
435
436
437 void MainWin::about()
438 {
439    QMessageBox::about(this, tr("About bat"),
440       tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
441          "<p>Copyright &copy; " BYEAR " Free Software Foundation Europe e.V."
442          "<p>The <b>bat</b> is an administrative console"
443          " interface to the Director."));
444 }
445
446 void MainWin::help()
447 {
448    Help::displayFile("index.html");
449 }
450
451 void MainWin::set_statusf(const char *fmt, ...)
452 {
453    va_list arg_ptr;
454    char buf[1000];
455    int len;
456    va_start(arg_ptr, fmt);
457    len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
458    va_end(arg_ptr);
459    set_status(buf);
460 }
461
462 void MainWin::set_status_ready()
463 {
464    set_status(" Ready");
465 }
466
467 void MainWin::set_status(const char *buf)
468 {
469    statusBar()->showMessage(buf);
470 }
471
472 /*
473  * Function to respond to the button bar button to undock
474  */
475 void MainWin::undockWindowButton()
476 {
477    Pages* page = (Pages*)stackedWidget->currentWidget();
478    page->togglePageDocking();
479 }
480
481 /*
482  * Function to respond to action on page selector context menu to toggle the 
483  * dock status of the window associated with the page selectors current
484  * tree widget item.
485  */
486 void MainWin::toggleDockContextWindow()
487 {
488    QTreeWidgetItem *currentitem = treeWidget->currentItem();
489    
490    /* Is this a page that has been inserted into the hash  */
491    if (getFromHash(currentitem)) {
492       Pages* page = getFromHash(currentitem);
493       page->togglePageDocking();
494    }
495 }
496
497 /*
498  * This function is called when the stack item is changed.  Call
499  * the virtual function here.  Avoids a window being undocked leaving
500  * a window at the top of the stack unpopulated.
501  */
502 void MainWin::stackItemChanged(int)
503 {
504    Pages* page = (Pages*)stackedWidget->currentWidget();
505    /* run the virtual function in case this class overrides it */
506    page->currentStackItem();
507 }
508
509 /*
510  * Function to simplify insertion of QTreeWidgetItem <-> Page association
511  * into a double direction hash.
512  */
513 void MainWin::hashInsert(QTreeWidgetItem *item, Pages *page)
514 {
515    m_pagehash.insert(item, page);
516    m_widgethash.insert(page, item);
517 }
518
519 /*
520  * Function to simplify removal of QTreeWidgetItem <-> Page association
521  * into a double direction hash.
522  */
523 void MainWin::hashRemove(QTreeWidgetItem *item, Pages *page)
524 {
525    /* I had all sorts of return status checking code here.  Do we have a log
526     * level capability in bat.  I would have left it in but it used printf's
527     * and it should really be some kind of log level facility ???
528     * ******FIXME********/
529    m_pagehash.remove(item);
530    m_widgethash.remove(page);
531 }
532
533 /*
534  * Function to retrieve a Page* when the item in the page selector's tree is
535  * known.
536  */
537 Pages* MainWin::getFromHash(QTreeWidgetItem *item)
538 {
539    return m_pagehash.value(item);
540 }
541
542 /*
543  * Function to retrieve the page selectors tree widget item when the page is
544  * known.
545  */
546 QTreeWidgetItem* MainWin::getFromHash(Pages *page)
547 {
548    return m_widgethash.value(page);
549 }
550
551 /*
552  * Function to respond to action on page selector context menu to close the
553  * current window.
554  */
555 void MainWin::closePage()
556 {
557    QTreeWidgetItem *currentitem = treeWidget->currentItem();
558    
559    /* Is this a page that has been inserted into the hash  */
560    if (getFromHash(currentitem)) {
561       Pages* page = getFromHash(currentitem);
562       if (page->isCloseable()) {
563          page->closeStackPage();
564       }
565    }
566 }
567
568 /* Quick function to return the current console */
569 Console *MainWin::currentConsole()
570 {
571    return m_currentConsole;
572 }
573 /* Quick function to return the tree item for the director */
574 QTreeWidgetItem *MainWin::currentTopItem()
575 {
576    return m_currentConsole->directorTreeItem();
577 }
578
579 /* Preferences menu item clicked */
580 void MainWin::setPreferences()
581 {
582    prefsDialog prefs;
583    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
584    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
585    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
586    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
587    prefs.miscDebug->setCheckState(m_miscDebug ? Qt::Checked : Qt::Unchecked);
588    prefs.recordLimit->setCheckState(m_recordLimitCheck ? Qt::Checked : Qt::Unchecked);
589    prefs.recordSpinBox->setValue(m_recordLimitVal);
590    prefs.daysLimit->setCheckState(m_daysLimitCheck ? Qt::Checked : Qt::Unchecked);
591    prefs.daysSpinBox->setValue(m_daysLimitVal);
592    prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
593    prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
594    prefs.executeLongCheckBox->setCheckState(m_longList ? Qt::Checked : Qt::Unchecked);
595
596    prefs.exec();
597 }
598
599 /* Preferences dialog */
600 prefsDialog::prefsDialog()
601 {
602    setupUi(this);
603 }
604
605 void prefsDialog::accept()
606 {
607    this->hide();
608    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
609    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
610    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
611    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
612    mainWin->m_miscDebug = this->miscDebug->checkState() == Qt::Checked;
613    mainWin->m_recordLimitCheck = this->recordLimit->checkState() == Qt::Checked;
614    mainWin->m_recordLimitVal = this->recordSpinBox->value();
615    mainWin->m_daysLimitCheck = this->daysLimit->checkState() == Qt::Checked;
616    mainWin->m_daysLimitVal = this->daysSpinBox->value();
617    mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
618    mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
619    mainWin->m_longList = this->executeLongCheckBox->checkState() == Qt::Checked;
620    QSettings settings("www.bacula.org", "bat");
621    settings.beginGroup("Debug");
622    settings.setValue("commDebug", mainWin->m_commDebug);
623    settings.setValue("displayAll", mainWin->m_displayAll);
624    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
625    settings.setValue("commandDebug", mainWin->m_commandDebug);
626    settings.setValue("miscDebug", mainWin->m_miscDebug);
627    settings.endGroup();
628    settings.beginGroup("JobList");
629    settings.setValue("recordLimitCheck", mainWin->m_recordLimitCheck);
630    settings.setValue("recordLimitVal", mainWin->m_recordLimitVal);
631    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
632    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
633    settings.endGroup();
634    settings.beginGroup("Messages");
635    settings.setValue("checkMessages", mainWin->m_checkMessages);
636    settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
637    settings.endGroup();
638    settings.beginGroup("Misc");
639    settings.setValue("longList", mainWin->m_longList);
640    settings.endGroup();
641    foreach(Console *console, mainWin->m_consoleHash) {
642       console->startTimer();
643    }
644 }
645
646 void prefsDialog::reject()
647 {
648    this->hide();
649    mainWin->set_status("Canceled");
650 }
651
652 /* read preferences for the prefences dialog box */
653 void MainWin::readPreferences()
654 {
655    QSettings settings("www.bacula.org", "bat");
656    settings.beginGroup("Debug");
657    m_commDebug = settings.value("commDebug", false).toBool();
658    m_displayAll = settings.value("displayAll", false).toBool();
659    m_sqlDebug = settings.value("sqlDebug", false).toBool();
660    m_commandDebug = settings.value("commandDebug", false).toBool();
661    m_miscDebug = settings.value("miscDebug", false).toBool();
662    settings.endGroup();
663    settings.beginGroup("JobList");
664    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
665    m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
666    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
667    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
668    settings.endGroup();
669    settings.beginGroup("Messages");
670    m_checkMessages = settings.value("checkMessages", false).toBool();
671    m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();
672    settings.endGroup();
673    settings.beginGroup("Misc");
674    m_longList = settings.value("longList", false).toBool();
675    settings.endGroup();
676 }