]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/qt-console/mainwin.cpp
Change copyright as per agreement with FSFE
[bacula/bacula] / bacula / src / qt-console / mainwin.cpp
index 81deb3f3dc14f2ea9783ff0c905b7ff13c229519..27d477d9b1091ac709608a09136fd36de2a3e87e 100644 (file)
@@ -1,33 +1,23 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
-
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation and included
-   in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of John Walker.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2016 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 
 /*
- *   Version $Id$
  *
  *  Main Window control for bat (qt-console)
  *
@@ -36,6 +26,7 @@
  */ 
 
 #include "bat.h"
+#include "version.h"
 #include "joblist/joblist.h"
 #include "storage/storage.h"
 #include "fileset/fileset.h"
 #include "restore/restoretree.h"
 #include "help/help.h"
 #include "jobs/jobs.h"
+#include "medialist/mediaview.h"
+#ifdef HAVE_QWT
 #include "jobgraphs/jobplot.h"
+#endif
+#include "status/dirstat.h"
+#include "util/fmtwidgetitem.h"
 
 /* 
  * Daemon message callback
@@ -61,7 +57,11 @@ void message_callback(int /* type */, char *msg)
 
 MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
 {
+   app->setOverrideCursor(QCursor(Qt::WaitCursor));
    m_isClosing = false;
+   m_waitState = false;
+   m_doConnect = false;
+   m_treeStackTrap = false;
    m_dtformat = "yyyy-MM-dd HH:mm:ss";
    mainWin = this;
    setupUi(this);                     /* Setup UI defined by main.ui (designer) */
@@ -69,14 +69,17 @@ MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
    readPreferences();
    treeWidget->clear();
    treeWidget->setColumnCount(1);
-   treeWidget->setHeaderLabel("Select Page");
+   treeWidget->setHeaderLabel( tr("Select Page") );
    treeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
-
+   tabWidget->setTabsClosable(true);  /* wait for QT 4.5 */
    createPages();
 
-   resetFocus();
+   resetFocus(); /* lineEdit->setFocus() */
 
-   createConnections();
+#ifndef HAVE_QWT
+   actionJobPlot->setEnabled(false);
+   actionJobPlot->setVisible(false);
+#endif
 
    this->show();
 
@@ -85,13 +88,35 @@ MainWin::MainWin(QWidget *parent) : QMainWindow(parent)
    foreach(Console *console, m_consoleHash) {
       console->connect_dir();
    }
+   /* 
+    * Note, the notifier is now a global flag, although each notifier
+    *  can be individually turned on and off at a socket level.  Once
+    *  the notifier is turned off, we don't accept anything from anyone
+    *  this prevents unwanted messages from getting into the input
+    *  dialogs such as restore that read from the director and "know"
+    *  what to expect.
+    */
+   m_notify = true;
    m_currentConsole = (Console*)getFromHash(m_firstItem);
-   m_currentConsole->setCurrent();
+   QTimer::singleShot(2000, this, SLOT(popLists()));
    if (m_miscDebug) {
       QString directoryResourceName;
       m_currentConsole->getDirResName(directoryResourceName);
-      Pmsg1(000, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
+      Pmsg1(100, "Setting initial window to %s\n", directoryResourceName.toUtf8().data());
    }
+   app->restoreOverrideCursor();
+}
+
+void MainWin::popLists()
+{
+   foreach(Console *console, m_consoleHash) {
+      console->populateLists(true);
+   }
+   m_doConnect = true;
+   connectConsoleSignals();
+   connectSignals();
+   app->restoreOverrideCursor();
+   m_currentConsole->setCurrent();
 }
 
 void MainWin::createPages()
@@ -104,7 +129,7 @@ void MainWin::createPages()
    foreach_res(dir, R_DIRECTOR) {
 
       /* Create console tree stacked widget item */
-      m_currentConsole = new Console(stackedWidget);
+      m_currentConsole = new Console(tabWidget);
       m_currentConsole->setDirRes(dir);
       m_currentConsole->readSettings();
 
@@ -120,38 +145,46 @@ void MainWin::createPages()
 
       /* Create Tree Widget Item */
       item = new QTreeWidgetItem(topItem);
-      item->setText(0, "Console");
+      item->setText(0, tr("Console"));
       if (!m_firstItem){ m_firstItem = item; }
-      item->setIcon(0,QIcon(QString::fromUtf8(":images/utilities-terminal.svg")));
+      item->setIcon(0,QIcon(QString::fromUtf8(":images/utilities-terminal.png")));
 
       /* insert the cosole and tree widget item into the hashes */
       hashInsert(item, m_currentConsole);
+      m_currentConsole->dockPage();
 
       /* Set Color of treeWidgetItem for the console
       * It will be set to green in the console class if the connection is made.
       */
       QBrush redBrush(Qt::red);
       item->setForeground(0, redBrush);
-      m_currentConsole->dockPage();
 
       /*
        * Create instances in alphabetic order of the rest 
        *  of the classes that will by default exist under each Director.  
        */
-//      new bRestore();
+      new bRestore();
       new Clients();
       new FileSet();
       new Jobs();
       createPageJobList("", "", "", "", NULL);
-      new MediaList();
-      new Storage();
-      new restoreTree();
+#ifdef HAVE_QWT
       JobPlotPass pass;
       pass.use = false;
-      new JobPlot(NULL, pass);
-
+      if (m_openPlot)
+         new JobPlot(NULL, pass);
+#endif
+      new MediaList();
+      new MediaView();
+      new Storage();
+//    if (m_openBrowser) {
+//       new restoreTree();
+//    }
+      if (m_openDirStat) {
+         new DirStat();
+      }
       treeWidget->expandItem(topItem);
-      stackedWidget->setCurrentWidget(m_currentConsole);
+      tabWidget->setCurrentWidget(m_currentConsole);
    }
    UnlockRes();
 }
@@ -214,30 +247,126 @@ void MainWin::keyPressEvent(QKeyEvent *event)
    lineEdit->setText(m_cmd_history[m_cmd_last]);
 }
 
-void MainWin::createConnections()
+void MainWin::connectSignals()
 {
    /* Connect signals to slots */
    connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
    connect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
    connect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
-   connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, 
-           SLOT(treeItemClicked(QTreeWidgetItem *, int)));
-   connect(treeWidget, SIGNAL(
-           currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
-           this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
-   connect(stackedWidget, SIGNAL(currentChanged(int)),
-           this, SLOT(stackItemChanged(int)));
+   connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
+   connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+   connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(stackItemChanged(int)));
+   connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closePage(int)));
    connect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
    connect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
    connect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
    connect(actionEstimate, SIGNAL(triggered()), this,  SLOT(estimateButtonClicked()));
    connect(actionBrowse, SIGNAL(triggered()), this,  SLOT(browseButtonClicked()));
+   connect(actionStatusDirPage, SIGNAL(triggered()), this,  SLOT(statusPageButtonClicked()));
+#ifdef HAVE_QWT
    connect(actionJobPlot, SIGNAL(triggered()), this,  SLOT(jobPlotButtonClicked()));
+#endif
    connect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
    connect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
    connect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
-   connect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closePage()));
+   connect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closeCurrentPage()));
    connect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
+   connect(actionRepopLists, SIGNAL(triggered()), this,  SLOT(repopLists()));
+   connect(actionReloadRepop, SIGNAL(triggered()), this,  SLOT(reloadRepopLists()));
+}
+
+void MainWin::disconnectSignals()
+{
+   /* Connect signals to slots */
+   disconnect(lineEdit, SIGNAL(returnPressed()), this, SLOT(input_line()));
+   disconnect(actionAbout_bat, SIGNAL(triggered()), this, SLOT(about()));
+   disconnect(actionBat_Help, SIGNAL(triggered()), this, SLOT(help()));
+   disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
+   disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+   disconnect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(stackItemChanged(int)));
+   disconnect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closePage(int)));
+   disconnect(actionQuit, SIGNAL(triggered()), app, SLOT(closeAllWindows()));
+   disconnect(actionLabel, SIGNAL(triggered()), this,  SLOT(labelButtonClicked()));
+   disconnect(actionRun, SIGNAL(triggered()), this,  SLOT(runButtonClicked()));
+   disconnect(actionEstimate, SIGNAL(triggered()), this,  SLOT(estimateButtonClicked()));
+   disconnect(actionBrowse, SIGNAL(triggered()), this,  SLOT(browseButtonClicked()));
+   disconnect(actionStatusDirPage, SIGNAL(triggered()), this,  SLOT(statusPageButtonClicked()));
+#ifdef HAVE_QWT
+   disconnect(actionJobPlot, SIGNAL(triggered()), this,  SLOT(jobPlotButtonClicked()));
+#endif
+   disconnect(actionRestore, SIGNAL(triggered()), this,  SLOT(restoreButtonClicked()));
+   disconnect(actionUndock, SIGNAL(triggered()), this,  SLOT(undockWindowButton()));
+   disconnect(actionToggleDock, SIGNAL(triggered()), this,  SLOT(toggleDockContextWindow()));
+   disconnect(actionClosePage, SIGNAL(triggered()), this,  SLOT(closeCurrentPage()));
+   disconnect(actionPreferences, SIGNAL(triggered()), this,  SLOT(setPreferences()));
+   disconnect(actionRepopLists, SIGNAL(triggered()), this,  SLOT(repopLists()));
+   disconnect(actionReloadRepop, SIGNAL(triggered()), this,  SLOT(reloadRepopLists()));
+}
+
+/*
+ *  Enter wait state
+ */
+void MainWin::waitEnter()
+{
+   if (m_waitState || m_isClosing) { 
+      return;
+   }
+   m_waitState = true;
+   if (mainWin->m_connDebug) Pmsg0(000, "Entering Wait State\n");
+   app->setOverrideCursor(QCursor(Qt::WaitCursor));
+   disconnectSignals();
+   disconnectConsoleSignals(m_currentConsole);
+   m_waitTreeItem = treeWidget->currentItem();
+}
+
+/*
+ *  Leave wait state
+ */
+void MainWin::waitExit()
+{
+   if (!m_waitState || m_isClosing) {
+      return;
+   }
+   if (mainWin->m_connDebug) Pmsg0(000, "Exiting Wait State\n");
+   if (m_waitTreeItem && (m_waitTreeItem != treeWidget->currentItem())) {
+      treeWidget->setCurrentItem(m_waitTreeItem);
+   }
+   if (m_doConnect) {
+      connectSignals();
+      connectConsoleSignals();
+   }
+   app->restoreOverrideCursor();
+   m_waitState = false;
+}
+
+void MainWin::connectConsoleSignals()
+{
+   connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect_dir()));
+   connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
+   connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
+}
+
+void MainWin::disconnectConsoleSignals(Console *console)
+{
+   disconnect(actionConnect, SIGNAL(triggered()), console, SLOT(connect_dir()));
+   disconnect(actionMessages, SIGNAL(triggered()), console, SLOT(messages()));
+   disconnect(actionSelectFont, SIGNAL(triggered()), console, SLOT(set_font()));
+}
+
+
+/* 
+ * Two functions to respond to menu items to repop lists and execute reload and repopulate
+ * the lists for jobs, clients, filesets .. ..
+ */
+void MainWin::repopLists()
+{
+   m_currentConsole->populateLists(false);
+}
+void MainWin::reloadRepopLists()
+{
+   QString cmd = "reload";
+   m_currentConsole->consoleCommand(cmd);
+   m_currentConsole->populateLists(false);
 }
 
 /* 
@@ -247,14 +376,25 @@ void MainWin::closeEvent(QCloseEvent *event)
 {
    m_isClosing = true;
    writeSettings();
+   /* Remove all groups from settings for OpenOnExit so that we can start some of the status windows */
+   foreach(Console *console, m_consoleHash){
+      QSettings settings(console->m_dir->name(), "bat");
+      settings.beginGroup("OpenOnExit");
+      settings.remove("");
+      settings.endGroup();
+   }
    /* close all non console pages, this will call settings in destructors */
-   foreach(Pages *page, m_pagehash) {
-      if (page !=  page->console()) {
-         page->console()->setCurrent();
-         page->closeStackPage();
+   while (m_consoleHash.count() < m_pagehash.count()) {
+      foreach(Pages *page, m_pagehash) {
+         if (page !=  page->console()) {
+            QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(page);
+            if (pageSelectorTreeWidgetItem->childCount() == 0) {
+               page->console()->setCurrent();
+               page->closeStackPage();
+            }
+         }
       }
    }
-   /* close the console pages and terminate connection */
    foreach(Console *console, m_consoleHash){
       console->writeSettings();
       console->terminate();
@@ -272,6 +412,7 @@ void MainWin::writeSettings()
    settings.setValue("winPos", pos());
    settings.setValue("state", saveState());
    settings.endGroup();
+
 }
 
 void MainWin::readSettings()
@@ -292,15 +433,18 @@ void MainWin::readSettings()
 void MainWin::treeItemClicked(QTreeWidgetItem *item, int /*column*/)
 {
    /* Is this a page that has been inserted into the hash  */
-   if (getFromHash(item)) {
-      Pages* page = getFromHash(item);
-      int stackindex=stackedWidget->indexOf(page);
+   Pages* page = getFromHash(item);
+   if (page) {
+      int stackindex = tabWidget->indexOf(page);
 
       if (stackindex >= 0) {
-         stackedWidget->setCurrentWidget(page);
+         tabWidget->setCurrentWidget(page);
       }
+      page->dockPage();
       /* run the virtual function in case this class overrides it */
       page->PgSeltreeWidgetClicked();
+   } else {
+      Dmsg0(000, "Page not in hash");
    }
 }
 
@@ -312,7 +456,8 @@ void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *pre
    if (m_isClosing) return; /* if closing the application, do nothing here */
 
    Pages *previousPage, *nextPage;
-   Console *previousConsole, *nextConsole;
+   Console *previousConsole = NULL;
+   Console *nextConsole;
 
    /* remove all actions before adding actions appropriate for new page */
    foreach(QAction* pageAction, treeWidget->actions()) {
@@ -341,6 +486,9 @@ void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *pre
 
    /* this condition prevents a segfault.  The first time there is no previousitem*/
    if (previousitem) {
+      if (m_treeStackTrap == false) { /* keep track of previous items for going Back */
+         m_treeWidgetStack.append(previousitem);
+      }
       /* knowing the treeWidgetItem, get the page from the hash */
       previousPage = getFromHash(previousitem);
       previousConsole = m_consoleHash.value(previousitem);
@@ -352,10 +500,7 @@ void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *pre
       if ((previousPage) || (previousConsole)) {
          if (nextConsole != previousConsole) {
             /* remove connections to the current console */
-            disconnect(actionConnect, SIGNAL(triggered()), previousConsole, SLOT(connect_dir()));
-            disconnect(actionStatusDir, SIGNAL(triggered()), previousConsole, SLOT(status_dir()));
-            disconnect(actionMessages, SIGNAL(triggered()), previousConsole, SLOT(messages()));
-            disconnect(actionSelectFont, SIGNAL(triggered()), previousConsole, SLOT(set_font()));
+            disconnectConsoleSignals(previousConsole);
             QTreeWidgetItem *dirItem = previousConsole->directorTreeItem();
             QBrush greyBrush(Qt::lightGray);
             dirItem->setBackground(0, greyBrush);
@@ -369,22 +514,21 @@ void MainWin::treeItemChanged(QTreeWidgetItem *currentitem, QTreeWidgetItem *pre
       if (nextConsole != previousConsole) {
          /* make connections to the current console */
          m_currentConsole = nextConsole;
-         connect(actionConnect, SIGNAL(triggered()), m_currentConsole, SLOT(connect_dir()));
-         connect(actionSelectFont, SIGNAL(triggered()), m_currentConsole, SLOT(set_font()));
-         connect(actionStatusDir, SIGNAL(triggered()), m_currentConsole, SLOT(status_dir()));
-         connect(actionMessages, SIGNAL(triggered()), m_currentConsole, SLOT(messages()));
+         connectConsoleSignals();
+         setMessageIcon();
          /* Set director's tree widget background to magenta for ease of identification */
          QTreeWidgetItem *dirItem = m_currentConsole->directorTreeItem();
          QBrush magentaBrush(Qt::magenta);
          dirItem->setBackground(0, magentaBrush);
       }
       /* set the value for the currently active console */
-      int stackindex = stackedWidget->indexOf(nextPage);
+      int stackindex = tabWidget->indexOf(nextPage);
+      nextPage->firstUseDock();
    
       /* Is this page currently on the stack or is it undocked */
       if (stackindex >= 0) {
          /* put this page on the top of the stack */
-         stackedWidget->setCurrentIndex(stackindex);
+         tabWidget->setCurrentIndex(stackindex);
       } else {
          /* it is undocked, raise it to the front */
          nextPage->raise();
@@ -420,19 +564,39 @@ void MainWin::estimateButtonClicked()
 
 void MainWin::browseButtonClicked() 
 {
-   new restoreTree();
+//   new restoreTree();
+}
+
+void MainWin::statusPageButtonClicked()
+{
+   /* if one exists, then just set it current */
+   bool found = false;
+   foreach(Pages *page, m_pagehash) {
+      if (m_currentConsole == page->console()) {
+         if (page->name() == tr("Director Status")) {
+            found = true;
+            page->setCurrent();
+         }
+      }
+   }
+   if (!found) {
+      new DirStat();
+   }
 }
 
 void MainWin::restoreButtonClicked() 
 {
    new prerestorePage();
+   if (mainWin->m_miscDebug) Pmsg0(000, "in restoreButtonClicked after prerestorePage\n");
 }
 
 void MainWin::jobPlotButtonClicked()
 {
+#ifdef HAVE_QWT
    JobPlotPass pass;
    pass.use = false;
    new JobPlot(NULL, pass);
+#endif
 }
 
 /*
@@ -440,13 +604,18 @@ void MainWin::jobPlotButtonClicked()
  */
 void MainWin::input_line()
 {
+   int conn;
    QString cmdStr = lineEdit->text();    /* Get the text */
    lineEdit->clear();                    /* clear the lineEdit box */
    if (m_currentConsole->is_connected()) {
-      /* Use consoleInput to allow typing anything */
-      m_currentConsole->consoleInput(cmdStr);
+      if (m_currentConsole->findDirComm(conn)) {
+         m_currentConsole->consoleCommand(cmdStr, conn);
+      } else {
+         /* Use consoleCommand to allow typing anything */
+         m_currentConsole->consoleCommand(cmdStr);
+      }
    } else {
-      set_status("Director not connected. Click on connect button.");
+      set_status(tr("Director not connected. Click on connect button."));
    }
    m_cmd_history.append(cmdStr);
    m_cmd_last = -1;
@@ -458,10 +627,10 @@ void MainWin::input_line()
 void MainWin::about()
 {
    QMessageBox::about(this, tr("About bat"),
-      tr("<br><h2>bat 1.0, by Dirk H Bartley and Kern Sibbald</h2>"
-         "<p>Copyright &copy; " BYEAR " Free Software Foundation Europe e.V."
+      tr("<br><h2>Bacula Bat %1 (%2)</h2>"
+         "<p>Copyright &copy; 2007-%3 Kern Sibbald"
          "<p>The <b>bat</b> is an administrative console"
-         " interface to the Director."));
+         " interface to the Director.").arg(VERSION).arg(BDATE).arg(BYEAR));
 }
 
 void MainWin::help()
@@ -473,16 +642,20 @@ void MainWin::set_statusf(const char *fmt, ...)
 {
    va_list arg_ptr;
    char buf[1000];
-   int len;
    va_start(arg_ptr, fmt);
-   len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
+   bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
    va_end(arg_ptr);
    set_status(buf);
 }
 
 void MainWin::set_status_ready()
 {
-   set_status(" Ready");
+   set_status(tr(" Ready"));
+}
+
+void MainWin::set_status(const QString &str)
+{
+   statusBar()->showMessage(str);
 }
 
 void MainWin::set_status(const char *buf)
@@ -495,8 +668,10 @@ void MainWin::set_status(const char *buf)
  */
 void MainWin::undockWindowButton()
 {
-   Pages* page = (Pages*)stackedWidget->currentWidget();
-   page->togglePageDocking();
+   Pages* page = (Pages*)tabWidget->currentWidget();
+   if (page) {
+      page->togglePageDocking();
+   }
 }
 
 /*
@@ -511,7 +686,9 @@ void MainWin::toggleDockContextWindow()
    /* Is this a page that has been inserted into the hash  */
    if (getFromHash(currentitem)) {
       Pages* page = getFromHash(currentitem);
-      page->togglePageDocking();
+      if (page) {
+         page->togglePageDocking();
+      }
    }
 }
 
@@ -523,9 +700,18 @@ void MainWin::toggleDockContextWindow()
 void MainWin::stackItemChanged(int)
 {
    if (m_isClosing) return; /* if closing the application, do nothing here */
-   Pages* page = (Pages*)stackedWidget->currentWidget();
+   Pages* page = (Pages*)tabWidget->currentWidget();
    /* run the virtual function in case this class overrides it */
-   page->currentStackItem();
+   if (page) {
+      page->currentStackItem();
+   }
+   if (!m_waitState) {
+      disconnect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
+      disconnect(treeWidget, SIGNAL( currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+      treeWidget->setCurrentItem(getFromHash(page));
+      connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(treeItemClicked(QTreeWidgetItem *, int)));
+      connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+   }
 }
 
 /*
@@ -570,19 +756,35 @@ QTreeWidgetItem* MainWin::getFromHash(Pages *page)
    return m_widgethash.value(page);
 }
 
+void MainWin::closeCurrentPage()
+{
+   closePage(-1);
+}
+
 /*
  * Function to respond to action on page selector context menu to close the
  * current window.
  */
-void MainWin::closePage()
+void MainWin::closePage(int item)
 {
-   QTreeWidgetItem *currentitem = treeWidget->currentItem();
+   QTreeWidgetItem *currentitem;
+   Pages *page = NULL;
+
+   if (item >= 0) {
+     page = (Pages *)tabWidget->widget(item);
+   } else {
+      currentitem = treeWidget->currentItem();
+      /* Is this a page that has been inserted into the hash  */
+      if (getFromHash(currentitem)) {
+         page = getFromHash(currentitem);
+      }
+   }   
    
-   /* Is this a page that has been inserted into the hash  */
-   if (getFromHash(currentitem)) {
-      Pages* page = getFromHash(currentitem);
+   if (page) {
       if (page->isCloseable()) {
          page->closeStackPage();
+      } else {
+         page->hidePage();
       }
    }
 }
@@ -592,6 +794,7 @@ Console *MainWin::currentConsole()
 {
    return m_currentConsole;
 }
+
 /* Quick function to return the tree item for the director */
 QTreeWidgetItem *MainWin::currentTopItem()
 {
@@ -603,6 +806,7 @@ void MainWin::setPreferences()
 {
    prefsDialog prefs;
    prefs.commDebug->setCheckState(m_commDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.connDebug->setCheckState(m_connDebug ? Qt::Checked : Qt::Unchecked);
    prefs.displayAll->setCheckState(m_displayAll ? Qt::Checked : Qt::Unchecked);
    prefs.sqlDebug->setCheckState(m_sqlDebug ? Qt::Checked : Qt::Unchecked);
    prefs.commandDebug->setCheckState(m_commandDebug ? Qt::Checked : Qt::Unchecked);
@@ -614,12 +818,40 @@ void MainWin::setPreferences()
    prefs.checkMessages->setCheckState(m_checkMessages ? Qt::Checked : Qt::Unchecked);
    prefs.checkMessagesSpin->setValue(m_checkMessagesInterval);
    prefs.executeLongCheckBox->setCheckState(m_longList ? Qt::Checked : Qt::Unchecked);
-
+   prefs.rtPopDirCheckBox->setCheckState(m_rtPopDirDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtDirCurICCheckBox->setCheckState(m_rtDirCurICDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtDirICCheckBox->setCheckState(m_rtDirICDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtFileTabICCheckBox->setCheckState(m_rtFileTabICDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtVerTabICCheckBox->setCheckState(m_rtVerTabICDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtUpdateFTCheckBox->setCheckState(m_rtUpdateFTDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtUpdateVTCheckBox->setCheckState(m_rtUpdateVTDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtChecksCheckBox->setCheckState(m_rtChecksDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtIconStateCheckBox->setCheckState(m_rtIconStateDebug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtRestore1CheckBox->setCheckState(m_rtRestore1Debug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtRestore2CheckBox->setCheckState(m_rtRestore2Debug ? Qt::Checked : Qt::Unchecked);
+   prefs.rtRestore3CheckBox->setCheckState(m_rtRestore3Debug ? Qt::Checked : Qt::Unchecked);
+   switch (ItemFormatterBase::getBytesConversion()) {
+   case ItemFormatterBase::BYTES_CONVERSION_NONE:
+      prefs.radioConvertOff->setChecked(Qt::Checked);
+      break;
+   case ItemFormatterBase::BYTES_CONVERSION_IEC:
+      prefs.radioConvertIEC->setChecked(Qt::Checked);
+      break;
+   default:
+      prefs.radioConvertStandard->setChecked(Qt::Checked);
+      break;
+   }
+   prefs.openPlotCheckBox->setCheckState(m_openPlot ? Qt::Checked : Qt::Unchecked);
+#ifndef HAVE_QWT
+   prefs.openPlotCheckBox->setVisible(false);
+#endif
+   prefs.openBrowserCheckBox->setCheckState(m_openBrowser ? Qt::Checked : Qt::Unchecked);
+   prefs.openDirStatCheckBox->setCheckState(m_openDirStat ? Qt::Checked : Qt::Unchecked);
    prefs.exec();
 }
 
 /* Preferences dialog */
-prefsDialog::prefsDialog()
+prefsDialog::prefsDialog() : QDialog()
 {
    setupUi(this);
 }
@@ -628,6 +860,7 @@ void prefsDialog::accept()
 {
    this->hide();
    mainWin->m_commDebug = this->commDebug->checkState() == Qt::Checked;
+   mainWin->m_connDebug = this->connDebug->checkState() == Qt::Checked;
    mainWin->m_displayAll = this->displayAll->checkState() == Qt::Checked;
    mainWin->m_sqlDebug = this->sqlDebug->checkState() == Qt::Checked;
    mainWin->m_commandDebug = this->commandDebug->checkState() == Qt::Checked;
@@ -639,9 +872,34 @@ void prefsDialog::accept()
    mainWin->m_checkMessages = this->checkMessages->checkState() == Qt::Checked;
    mainWin->m_checkMessagesInterval = this->checkMessagesSpin->value();
    mainWin->m_longList = this->executeLongCheckBox->checkState() == Qt::Checked;
+
+   mainWin->m_rtPopDirDebug = this->rtPopDirCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtDirCurICDebug = this->rtDirCurICCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtDirICDebug = this->rtDirICCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtFileTabICDebug = this->rtFileTabICCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtVerTabICDebug = this->rtVerTabICCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtUpdateFTDebug = this->rtUpdateFTCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtUpdateVTDebug = this->rtUpdateVTCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtChecksDebug = this->rtChecksCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtIconStateDebug = this->rtIconStateCheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtRestore1Debug = this->rtRestore1CheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtRestore2Debug = this->rtRestore2CheckBox->checkState() == Qt::Checked;
+   mainWin->m_rtRestore3Debug = this->rtRestore3CheckBox->checkState() == Qt::Checked;
+   if (this->radioConvertOff->isChecked()) {
+      ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_NONE);
+   } else if (this->radioConvertIEC->isChecked()){
+      ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_IEC);
+   } else {
+      ItemFormatterBase::setBytesConversion(ItemFormatterBase::BYTES_CONVERSION_SI);
+   }
+   mainWin->m_openPlot = this->openPlotCheckBox->checkState() == Qt::Checked;
+   mainWin->m_openBrowser = this->openBrowserCheckBox->checkState() == Qt::Checked;
+   mainWin->m_openDirStat = this->openDirStatCheckBox->checkState() == Qt::Checked;
+
    QSettings settings("www.bacula.org", "bat");
    settings.beginGroup("Debug");
    settings.setValue("commDebug", mainWin->m_commDebug);
+   settings.setValue("connDebug", mainWin->m_connDebug);
    settings.setValue("displayAll", mainWin->m_displayAll);
    settings.setValue("sqlDebug", mainWin->m_sqlDebug);
    settings.setValue("commandDebug", mainWin->m_commandDebug);
@@ -653,22 +911,37 @@ void prefsDialog::accept()
    settings.setValue("daysLimitCheck", mainWin->m_daysLimitCheck);
    settings.setValue("daysLimitVal", mainWin->m_daysLimitVal);
    settings.endGroup();
-   settings.beginGroup("Messages");
+   settings.beginGroup("Timers");
    settings.setValue("checkMessages", mainWin->m_checkMessages);
    settings.setValue("checkMessagesInterval", mainWin->m_checkMessagesInterval);
    settings.endGroup();
    settings.beginGroup("Misc");
    settings.setValue("longList", mainWin->m_longList);
+   settings.setValue("byteConvert", ItemFormatterBase::getBytesConversion());
+   settings.setValue("openplot", mainWin->m_openPlot);
+   settings.setValue("openbrowser", mainWin->m_openBrowser);
+   settings.setValue("opendirstat", mainWin->m_openDirStat);
+   settings.endGroup();
+   settings.beginGroup("RestoreTree");
+   settings.setValue("rtPopDirDebug", mainWin->m_rtPopDirDebug);
+   settings.setValue("rtDirCurICDebug", mainWin->m_rtDirCurICDebug);
+   settings.setValue("rtDirCurICRetDebug", mainWin->m_rtDirICDebug);
+   settings.setValue("rtFileTabICDebug", mainWin->m_rtFileTabICDebug);
+   settings.setValue("rtVerTabICDebug", mainWin->m_rtVerTabICDebug);
+   settings.setValue("rtUpdateFTDebug", mainWin->m_rtUpdateFTDebug);
+   settings.setValue("rtUpdateVTDebug", mainWin->m_rtUpdateVTDebug);
+   settings.setValue("rtChecksDebug", mainWin->m_rtChecksDebug);
+   settings.setValue("rtIconStateDebug", mainWin->m_rtIconStateDebug);
+   settings.setValue("rtRestore1Debug", mainWin->m_rtRestore1Debug);
+   settings.setValue("rtRestore2Debug", mainWin->m_rtRestore2Debug);
+   settings.setValue("rtRestore3Debug", mainWin->m_rtRestore3Debug);
    settings.endGroup();
-   foreach(Console *console, mainWin->m_consoleHash) {
-      console->startTimer();
-   }
 }
 
 void prefsDialog::reject()
 {
    this->hide();
-   mainWin->set_status("Canceled");
+   mainWin->set_status(tr("Canceled"));
 }
 
 /* read preferences for the prefences dialog box */
@@ -677,6 +950,7 @@ void MainWin::readPreferences()
    QSettings settings("www.bacula.org", "bat");
    settings.beginGroup("Debug");
    m_commDebug = settings.value("commDebug", false).toBool();
+   m_connDebug = settings.value("connDebug", false).toBool();
    m_displayAll = settings.value("displayAll", false).toBool();
    m_sqlDebug = settings.value("sqlDebug", false).toBool();
    m_commandDebug = settings.value("commandDebug", false).toBool();
@@ -684,15 +958,70 @@ void MainWin::readPreferences()
    settings.endGroup();
    settings.beginGroup("JobList");
    m_recordLimitCheck = settings.value("recordLimitCheck", true).toBool();
-   m_recordLimitVal = settings.value("recordLimitVal", 150).toInt();
+   m_recordLimitVal = settings.value("recordLimitVal", 50).toInt();
    m_daysLimitCheck = settings.value("daysLimitCheck", false).toBool();
    m_daysLimitVal = settings.value("daysLimitVal", 28).toInt();
    settings.endGroup();
-   settings.beginGroup("Messages");
+   settings.beginGroup("Timers");
    m_checkMessages = settings.value("checkMessages", false).toBool();
    m_checkMessagesInterval = settings.value("checkMessagesInterval", 28).toInt();
    settings.endGroup();
    settings.beginGroup("Misc");
    m_longList = settings.value("longList", false).toBool();
+   ItemFormatterBase::setBytesConversion(
+         (ItemFormatterBase::BYTES_CONVERSION) settings.value("byteConvert", 
+         ItemFormatterBase::BYTES_CONVERSION_IEC).toInt());
+   m_openPlot = settings.value("openplot", false).toBool();
+   m_openBrowser = settings.value("openbrowser", false).toBool();
+   m_openDirStat = settings.value("opendirstat", false).toBool();
+   settings.endGroup();
+   settings.beginGroup("RestoreTree");
+   m_rtPopDirDebug = settings.value("rtPopDirDebug", false).toBool();
+   m_rtDirCurICDebug = settings.value("rtDirCurICDebug", false).toBool();
+   m_rtDirICDebug = settings.value("rtDirCurICRetDebug", false).toBool();
+   m_rtFileTabICDebug = settings.value("rtFileTabICDebug", false).toBool();
+   m_rtVerTabICDebug = settings.value("rtVerTabICDebug", false).toBool();
+   m_rtUpdateFTDebug = settings.value("rtUpdateFTDebug", false).toBool();
+   m_rtUpdateVTDebug = settings.value("rtUpdateVTDebug", false).toBool();
+   m_rtChecksDebug = settings.value("rtChecksDebug", false).toBool();
+   m_rtIconStateDebug = settings.value("rtIconStateDebug", false).toBool();
+   m_rtRestore1Debug = settings.value("rtRestore1Debug", false).toBool();
+   m_rtRestore2Debug = settings.value("rtRestore2Debug", false).toBool();
+   m_rtRestore3Debug = settings.value("rtRestore3Debug", false).toBool();
    settings.endGroup();
 }
+
+void MainWin::setMessageIcon()
+{
+   if (m_currentConsole->is_messagesPending())
+      actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-pending.png")));
+   else
+      actionMessages->setIcon(QIcon(QString::fromUtf8(":/images/mail-message-new.png")));
+}
+
+void MainWin::goToPreviousPage()
+{
+   m_treeStackTrap = true;
+   bool done = false;
+   while (!done) {
+      /* If stack list is emtpty, then done */
+      if (m_treeWidgetStack.isEmpty()) {
+         done = true;
+      } else {
+         QTreeWidgetItem* testItem = m_treeWidgetStack.takeLast();
+         QTreeWidgetItemIterator it(treeWidget);
+         /* lets avoid a segfault by setting an item current that no longer exists */
+         while (*it) {
+            if (*it == testItem) {
+               if (testItem != treeWidget->currentItem()) {
+                  treeWidget->setCurrentItem(testItem);
+                  done = true;
+               }
+               break;
+            }
+            ++it;
+         }
+      }
+   }
+   m_treeStackTrap = false;
+}