X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fqt-console%2Fconsole%2Fconsole.cpp;h=b0bde34df22f1b80cdcf558e37aec1eb4a9e5b4d;hb=fd18c27a531b11fcfe67c17fa0ff818c11bef3e7;hp=eeff11fc95ca6ffbe5f4084b01d1bf991f970e6b;hpb=32cd9c1c5134e0fef86e6d3f5c8016f6d6e1fc9a;p=bacula%2Fbacula diff --git a/bacula/src/qt-console/console/console.cpp b/bacula/src/qt-console/console/console.cpp index eeff11fc95..b0bde34df2 100644 --- a/bacula/src/qt-console/console/console.cpp +++ b/bacula/src/qt-console/console/console.cpp @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + 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. @@ -25,63 +25,106 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ - /* + * Version $Id$ + * * Console Class * - * Kern Sibbald, January MMVI + * Kern Sibbald, January MMVII * */ +#include #include "bat.h" #include "console.h" -Console::Console() +Console::Console(QStackedWidget *parent) { + QFont font; QTreeWidgetItem *item, *topItem; QTreeWidget *treeWidget = mainWin->treeWidget; - m_textEdit = mainWin->textEdit; /* our console screen */ + setupUi(this); + parent->addWidget(this); + m_sock = NULL; + m_at_prompt = false; + m_textEdit = textEdit; /* our console screen */ + m_cursor = new QTextCursor(m_textEdit->document()); + mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png"))); + + bRestore *brestore = new bRestore(parent); + brestore->setupUi(brestore); + parent->addWidget(brestore); /* Just take the first Director */ LockRes(); m_dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL); UnlockRes(); - /* Dummy setup of treeWidget */ + /* ***FIXME*** Dummy setup of treeWidget */ treeWidget->clear(); treeWidget->setColumnCount(1); treeWidget->setHeaderLabel("Selection"); topItem = new QTreeWidgetItem(treeWidget); topItem->setText(0, m_dir->name()); + topItem->setIcon(0, QIcon(QString::fromUtf8("images/server.png"))); item = new QTreeWidgetItem(topItem); + m_consoleItem = item; item->setText(0, "Console"); item->setText(1, "0"); + QBrush redBrush(Qt::red); + item->setForeground(0, redBrush); item = new QTreeWidgetItem(topItem); - item->setText(0, "Restore"); + item->setText(0, "brestore"); item->setText(1, "1"); treeWidget->expandItem(topItem); + + readSettings(); + /* Check for messages every 5 seconds */ +// m_timer = new QTimer(this); +// QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages())); +// m_timer->start(5000); + +} + +void Console::poll_messages() +{ + m_messages_pending = true; +} + +/* Terminate any open socket */ +void Console::terminate() +{ + if (m_sock) { + m_sock->close(); + m_sock = NULL; + } + m_timer->stop(); } /* * Connect to Director. If there are more than one, put up * a modal dialog so that the user chooses one. */ -bool Console::connect() +void Console::connect() { JCR jcr; - m_textEdit = mainWin->textEdit; /* our console screen */ + m_textEdit = textEdit; /* our console screen */ - - if (!m_dir) { - return false; + if (!m_dir) { + mainWin->set_status("No Director found."); + return; + } + if (m_sock) { + mainWin->set_status("Already connected."); + return; } memset(&jcr, 0, sizeof(jcr)); - set_statusf(_(" Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport); - set_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport); + mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport); + display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport); /* Give GUI a chance */ app->processEvents(); @@ -94,56 +137,222 @@ bool Console::connect() m_sock = bnet_connect(NULL, 5, 15, _("Director daemon"), m_dir->address, NULL, m_dir->DIRport, 0); if (m_sock == NULL) { - return false; + mainWin->set_status("Connection failed"); + return; + } else { + /* Update page selector to green to indicate that Console is connected */ + mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/connected.png"))); + QBrush greenBrush(Qt::green); + m_consoleItem->setForeground(0, greenBrush); } jcr.dir_bsock = m_sock; if (!authenticate_director(&jcr, m_dir, cons)) { - set_text(m_sock->msg); - return false; + display_text(m_sock->msg); + return; } /* Give GUI a chance */ app->processEvents(); - set_status(_(" Initializing ...")); + mainWin->set_status(_("Initializing ...")); - bnet_fsend(m_sock, "autodisplay on"); + /* Set up input notifier */ + m_notifier = new QSocketNotifier(m_sock->fd, QSocketNotifier::Read, 0); + QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int))); - /* Read and display all initial messages */ - while (bnet_recv(m_sock) > 0) { - set_text(m_sock->msg); - } + write(".api"); + discardToPrompt(); - /* Give GUI a chance */ - app->processEvents(); + beginNewCommand(); + job_list = get_list(".jobs"); + client_list = get_list(".clients"); + fileset_list = get_list(".filesets"); + messages_list = get_list(".messages"); + pool_list = get_list(".pools"); + storage_list = get_list(".storage"); + type_list = get_list(".types"); + level_list = get_list(".levels"); + + mainWin->set_status(_("Connected")); + return; +} - /* Query Directory for .jobs, .clients, .filesets, .msgs, - * .pools, .storage, .types, .levels, ... - */ - set_status(_(" Connected")); +/* + * Send a command to the director, and read all the resulting + * output into a list. + */ +QStringList Console::get_list(char *cmd) +{ + QStringList list; + int stat; + + setEnabled(false); + write(cmd); + while ((stat = read()) > 0) { + strip_trailing_junk(msg()); + list << msg(); + } + setEnabled(true); +// list.sort(); + return list; +} + +/* + * Send a job name to the director, and read all the resulting + * defaults. + */ +bool Console::get_job_defaults(struct job_defaults &job_defs) +{ + QString scmd; + char cmd[1000]; + int stat; + char *def; + + setEnabled(false); + beginNewCommand(); + scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name); + write(scmd); + while ((stat = read()) > 0) { + def = strchr(msg(), '='); + if (!def) { + continue; + } + /* Pointer to default value */ + *def++ = 0; + strip_trailing_junk(def); + + if (strcmp(msg(), "job") == 0) { + if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0) { + goto bail_out; + } + continue; + } + if (strcmp(msg(), "pool") == 0) { + job_defs.pool_name = def; + continue; + } + if (strcmp(msg(), "messages") == 0) { + job_defs.messages_name = def; + continue; + } + if (strcmp(msg(), "client") == 0) { + job_defs.client_name = def; + continue; + } + if (strcmp(msg(), "storage") == 0) { + job_defs.store_name = def; + continue; + } + if (strcmp(msg(), "where") == 0) { + job_defs.where = def; + continue; + } + if (strcmp(msg(), "level") == 0) { + job_defs.level = def; + continue; + } + if (strcmp(msg(), "type") == 0) { + job_defs.type = def; + continue; + } + if (strcmp(msg(), "fileset") == 0) { + job_defs.fileset_name = def; + continue; + } + if (strcmp(msg(), "catalog") == 0) { + job_defs.catalog_name = def; + continue; + } + if (strcmp(msg(), "enabled") == 0) { + job_defs.enabled = *def == '1' ? true : false; + continue; + } + } + bsnprintf(cmd, sizeof(cmd), "job=%s pool=%s client=%s storage=%s where=%s\n" + "level=%s type=%s fileset=%s catalog=%s enabled=%d\n", + job_defs.job_name.toUtf8().data(), job_defs.pool_name.toUtf8().data(), + job_defs.client_name.toUtf8().data(), + job_defs.pool_name.toUtf8().data(), job_defs.messages_name.toUtf8().data(), + job_defs.store_name.toUtf8().data(), + job_defs.where.toUtf8().data(), job_defs.level.toUtf8().data(), + job_defs.type.toUtf8().data(), job_defs.fileset_name.toUtf8().data(), + job_defs.catalog_name.toUtf8().data(), job_defs.enabled); + + setEnabled(true); return true; + +bail_out: + setEnabled(true); + return false; } -void Console::set_textf(const char *fmt, ...) + +/* + * Save user settings associated with this console + */ +void Console::writeSettings() { - va_list arg_ptr; - char buf[1000]; - int len; - va_start(arg_ptr, fmt); - len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr); - va_end(arg_ptr); - m_textEdit->append(buf); + QFont font = get_font(); + + QSettings settings("bacula.org", "bat"); + /* ***FIXME*** make console name unique */ + settings.beginGroup("Console"); + settings.setValue("consoleFont", font.family()); + settings.setValue("consolePointSize", font.pointSize()); + settings.setValue("consoleFixedPitch", font.fixedPitch()); + settings.endGroup(); +} + +/* + * Read and restore user settings associated with this console + */ +void Console::readSettings() +{ + QFont font = get_font(); + + QSettings settings("bacula.org", "bat"); + settings.beginGroup("Console"); + font.setFamily(settings.value("consoleFont", "Courier").value()); + font.setPointSize(settings.value("consolePointSize", 10).toInt()); + font.setFixedPitch(settings.value("consoleFixedPitch", true).toBool()); + settings.endGroup(); + m_textEdit->setFont(font); +} + +/* + * Set the console textEdit font + */ +void Console::set_font() +{ + bool ok; + QFont font = QFontDialog::getFont(&ok, QFont(m_textEdit->font()), this); + if (ok) { + m_textEdit->setFont(font); + } +} + +/* + * Get the console text edit font + */ +const QFont Console::get_font() +{ + return m_textEdit->font(); } -void Console::set_text(const char *buf) + +void Console::status_dir() { - m_textEdit->append(buf); + write_dir("status dir\n"); + displayToPrompt(); } -void Console::set_statusf(const char *fmt, ...) +/* + * Put text into the console window + */ +void Console::display_textf(const char *fmt, ...) { va_list arg_ptr; char buf[1000]; @@ -151,88 +360,202 @@ void Console::set_statusf(const char *fmt, ...) va_start(arg_ptr, fmt); len = bvsnprintf(buf, sizeof(buf), fmt, arg_ptr); va_end(arg_ptr); - set_status(buf); + display_text(buf); } -void Console::set_status_ready() +void Console::display_text(const QString buf) { - mainWin->statusBar()->showMessage("Ready"); -// ready = true; + m_cursor->movePosition(QTextCursor::End); + m_cursor->insertText(buf); } -void Console::set_status(const char *buf) + +void Console::display_text(const char *buf) { - mainWin->statusBar()->showMessage(buf); -// ready = false; + m_cursor->movePosition(QTextCursor::End); + m_cursor->insertText(buf); } +/* Position cursor to end of screen */ +void Console::update_cursor() +{ + QApplication::restoreOverrideCursor(); + m_textEdit->moveCursor(QTextCursor::End); + m_textEdit->ensureCursorVisible(); +} -#ifdef xxx -void write_director(const gchar *msg) +/* + * This should be moved into a bSocket class + */ +char *Console::msg() { - if (UA_sock) { - at_prompt = false; - set_status(_(" Processing command ...")); - UA_sock->msglen = strlen(msg); - pm_strcpy(&UA_sock->msg, msg); - bnet_send(UA_sock); + if (m_sock) { + return m_sock->msg; } - if (strcmp(msg, ".quit") == 0 || strcmp(msg, ".exit") == 0) { - disconnect_from_director((gpointer)NULL); - gtk_main_quit(); + return NULL; +} + +/* Send a command to the Director */ +void Console::write_dir(const char *msg) +{ + if (m_sock) { + mainWin->set_status(_("Processing command ...")); + QApplication::setOverrideCursor(Qt::WaitCursor); + write(msg); + } else { + mainWin->set_status(" Director not connected. Click on connect button."); + mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png"))); + QBrush redBrush(Qt::red); + m_consoleItem->setForeground(0, redBrush); } } -extern "C" -void read_director(gpointer data, gint fd, GdkInputCondition condition) +int Console::write(const QString msg) { - int stat; + return write(msg.toUtf8().data()); +} - if (!UA_sock || UA_sock->fd != fd) { - return; +int Console::write(const char *msg) +{ + m_sock->msglen = strlen(msg); + pm_strcpy(&m_sock->msg, msg); + m_at_prompt = false; + if (commDebug) Pmsg1(000, "send: %s\n", msg); + return m_sock->send(); +} + +/* + * Get to main command prompt + */ +void Console::beginNewCommand() +{ + write(".\n"); + while (read() > 0) { } - stat = bnet_recv(UA_sock); - if (stat >= 0) { - if (at_prompt) { - set_text("\n", 1); - at_prompt = false; - } - set_text(UA_sock->msg, UA_sock->msglen); - return; + write(".\n"); + while (read() > 0) { } - if (is_bnet_stop(UA_sock)) { /* error or term request */ - gtk_main_quit(); - return; + write(".\n"); + while (read() > 0) { } - /* Must be a signal -- either do something or ignore it */ - if (UA_sock->msglen == BNET_PROMPT) { - at_prompt = true; - set_status(_(" At prompt waiting for input ...")); + display_text("\n"); +} + +void Console::displayToPrompt() +{ + int stat; + if (commDebug) Pmsg0(000, "DisplaytoPrompt\n"); + m_notifier->setEnabled(false); + while ((stat = read()) > 0) { + display_text(msg()); } - if (UA_sock->msglen == BNET_EOD) { - set_status_ready(); + if (commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat); + m_notifier->setEnabled(true); +} + +void Console::discardToPrompt() +{ + int stat; + if (commDebug) Pmsg0(000, "discardToPrompt\n"); + m_notifier->setEnabled(false); + while ((stat = read()) > 0) { } - return; + if (commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat); + m_notifier->setEnabled(true); } -static gint tag; -void start_director_reader(gpointer data) +/* + * Blocking read from director + */ +int Console::read() { + int stat = BNET_HARDEOF; + while (m_sock) { + for (;;) { + stat = bnet_wait_data_intr(m_sock, 1); + if (stat > 0) { + break; + } + app->processEvents(); +// if (m_api_set && m_messages_pending) { +// write_dir(".messages"); +// m_messages_pending = false; +// } + } + stat = m_sock->recv(); + if (stat >= 0) { + if (m_at_prompt) { + display_text("\n"); + m_at_prompt = false; + } + if (commDebug) Pmsg1(000, "got: %s", m_sock->msg); - if (director_reader_running || !UA_sock) { - return; - } - tag = gdk_input_add(UA_sock->fd, GDK_INPUT_READ, read_director, NULL); - director_reader_running = true; + } + switch (m_sock->msglen) { + case BNET_SERVER_READY: +// if (m_api_set && m_messages_pending) { +// write_dir(".messages"); +// m_messages_pending = false; +// } + m_at_prompt = true; + continue; + case BNET_MESSAGES_PENDING: + m_messages_pending = true; + continue; + case BNET_CMD_BEGIN: + m_at_prompt = false; + continue; + case BNET_PROMPT: + case BNET_CMD_OK: + if (commDebug) Pmsg0(000, "CMD OK/PROMPT\n"); + m_at_prompt = true; + mainWin->set_status(_("At prompt waiting for input ...")); + update_cursor(); + QApplication::restoreOverrideCursor(); + break; + case BNET_CMD_FAILED: + if (commDebug) Pmsg0(000, "CMD FAIL\n"); + m_at_prompt = true; + mainWin->set_status(_("Command failed. At prompt waiting for input ...")); + update_cursor(); + QApplication::restoreOverrideCursor(); + break; + case BNET_EOD: + if (commDebug) Pmsg0(000, "EOD\n"); + mainWin->set_status_ready(); + update_cursor(); + QApplication::restoreOverrideCursor(); + if (!m_api_set) { + break; + } + continue; + } + if (is_bnet_stop(m_sock)) { /* error or term request */ + m_sock->close(); + m_sock = NULL; + mainWin->actionConnect->setIcon(QIcon(QString::fromUtf8("images/disconnected.png"))); + QBrush redBrush(Qt::red); + m_consoleItem->setForeground(0, redBrush); + m_notifier->setEnabled(false); + delete m_notifier; + m_notifier = NULL; + mainWin->set_status(_("Director disconnected.")); + QApplication::restoreOverrideCursor(); + } + break; + } + return stat; } -void stop_director_reader(gpointer data) +/* Called by signal when the Director has output for us */ +void Console::read_dir(int fd) { - if (!director_reader_running) { - return; + int stat; + (void)fd; + + if (commDebug) Pmsg0(000, "read_dir\n"); + while ((stat = read()) >= 0) { + display_text(msg()); } - gdk_input_remove(tag); - director_reader_running = false; } -#endif