From b5d890ae837ea35d9f5077cf260bf85922259be9 Mon Sep 17 00:00:00 2001 From: dos-reis Date: Sun, 7 Apr 2013 12:37:06 +0000 Subject: gui: misc cleanup --- src/gui/conversation.cc | 55 +++++++++++++++++++++++-------------------------- src/gui/conversation.h | 42 ++++++++----------------------------- src/gui/debate.cc | 23 +++------------------ src/gui/debate.h | 8 +++---- src/gui/gui.pro.in | 2 +- src/gui/main-window.cc | 48 ++++++++++++++++++++++-------------------- src/gui/main-window.h | 7 ++++--- src/gui/server.cc | 1 - src/gui/widget.h | 51 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 123 insertions(+), 114 deletions(-) create mode 100644 src/gui/widget.h (limited to 'src') diff --git a/src/gui/conversation.cc b/src/gui/conversation.cc index cb0b82b8..4cca97df 100644 --- a/src/gui/conversation.cc +++ b/src/gui/conversation.cc @@ -119,7 +119,7 @@ namespace OpenAxiom { // -------------- // -- Question -- // -------------- - Question::Question(Exchange& e) : Base(&e), parent(&e) { + Question::Question(Exchange* e) : super(e) { setBackgroundRole(QPalette::AlternateBase); setFrame(true); } @@ -127,19 +127,19 @@ namespace OpenAxiom { void Question::focusInEvent(QFocusEvent* e) { setFrame(true); update(); - Base::focusInEvent(e); + super::focusInEvent(e); } void Question::enterEvent(QEvent* e) { setFrame(true); update(); - Base::enterEvent(e); + super::enterEvent(e); } // ------------ // -- Answer -- // ------------ - Answer::Answer(Exchange& e) : Base(&e), parent(&e) { + Answer::Answer(Exchange* e) : super(e) { setFrameStyle(StyledPanel | Raised); } @@ -170,40 +170,39 @@ namespace OpenAxiom { // Dress the query area with initial properties. static void - prepare_query_widget(Conversation& conv, Exchange* e) { + prepare_query_widget(Conversation* conv, Exchange* e) { Question* q = e->question(); q->setFrame(false); - q->setFont(conv.font()); + q->setFont(conv->font()); const int m = our_margin(e); - q->setGeometry(m, m, conv.width() - 2 * m, q->height()); + q->setGeometry(m, m, conv->width() - 2 * m, q->height()); } // Dress the reply aread with initial properties. // Place the reply widget right below the frame containing // the query widget; make both of the same width, of course. static void - prepare_reply_widget(Conversation& conv, Exchange* e) { + prepare_reply_widget(Conversation* conv, Exchange* e) { Answer* a = e->answer(); Question* q = e->question(); const QPoint pt = e->question()->geometry().bottomLeft(); const int m = our_margin(a); a->setGeometry(pt.x(), pt.y() + spacing, - conv.width() - 2 * m, q->height()); + conv->width() - 2 * m, q->height()); a->setBackgroundRole(q->backgroundRole()); a->hide(); // nothing to show yet } static void - finish_exchange_make_up(Conversation& conv, Exchange* e) { + finish_exchange_make_up(Conversation* conv, Exchange* e) { e->setAutoFillBackground(true); - e->move(conv.bottom_left()); + e->move(conv->bottom_left()); } - Exchange::Exchange(Conversation& conv, int n) - : QFrame(&conv), parent(&conv), no(n), - query(*this), reply(*this) { + Exchange::Exchange(Conversation* conv, int n) + : super(conv), no(n), query(this), reply(this) { setLineWidth(1); - setFont(conv.font()); + setFont(conv->font()); prepare_query_widget(conv, this); prepare_reply_widget(conv, this); finish_exchange_make_up(conv, this); @@ -234,7 +233,7 @@ namespace OpenAxiom { QString input = question()->text().trimmed(); if (empty_string(input)) return; - topic()->server()->input(input); + parent()->parent()->server()->input(input); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } @@ -271,14 +270,12 @@ namespace OpenAxiom { // Set a minimum preferred widget size, so no layout manager // messes with it. Indicate we can make use of more space. - Conversation::Conversation(Debate& parent, const Command& cmd) - : group(&parent), greatings(this), srv(cmd), cur_ex(), cur_out(&greatings) { + Conversation::Conversation(Debate* debate) + : super(debate), greatings(this), cur_ex(), cur_out(&greatings) { setFont(monospace_font()); setBackgroundRole(QPalette::Base); greatings.setFont(font()); - connect(server(), SIGNAL(readyReadStandardOutput()), - this, SLOT(read_reply())); - // connect(oracle(), SIGNAL(readyReadStandardError()), + // connect(parent()->server(), SIGNAL(readyReadStandardOutput()), // this, SLOT(read_reply())); } @@ -302,10 +299,10 @@ namespace OpenAxiom { } QSize Conversation::sizeHint() const { - const int view_height = debate()->viewport()->height(); const int n = length(); if (n == 0) - return round_up_height(minimum_preferred_size(this), view_height); + return minimum_preferred_size(this); + const int view_height = parent()->viewport()->height(); QSize sz = greatings.size(); for (int i = 0; i < n; ++i) sz.rheight() += children[i]->height(); @@ -313,7 +310,7 @@ namespace OpenAxiom { } void Conversation::resizeEvent(QResizeEvent* e) { - Base::resizeEvent(e); + super::resizeEvent(e); setMinimumSize(size()); const QSize sz = size(); if (e->oldSize() == sz) @@ -333,7 +330,7 @@ namespace OpenAxiom { Exchange* Conversation::new_topic() { - Exchange* w = new Exchange(*this, length() + 1); + Exchange* w = new Exchange(this, length() + 1); w->show(); children.push_back(w); adjustSize(); @@ -381,7 +378,7 @@ namespace OpenAxiom { void Conversation::read_reply() { - OracleOutput output = read_output(server()); + OracleOutput output = read_output(parent()->server()); if (empty(output)) return; if (not empty_string(output.result)) { @@ -390,16 +387,16 @@ namespace OpenAxiom { } if (length() == 0) { if (not empty_string(output.prompt)) - ensure_visibility(debate(), new_topic()); + ensure_visibility(parent(), new_topic()); } else { exchange()->adjustSize(); exchange()->update(); exchange()->updateGeometry(); if (empty_string(output.prompt)) - ensure_visibility(debate(), exchange()); + ensure_visibility(parent(), exchange()); else { - ensure_visibility(debate(), next(exchange())); + ensure_visibility(parent(), next(exchange())); QApplication::restoreOverrideCursor(); } } diff --git a/src/gui/conversation.h b/src/gui/conversation.h index 01847e6e..b9f27e0c 100644 --- a/src/gui/conversation.h +++ b/src/gui/conversation.h @@ -40,6 +40,7 @@ #include #include #include +#include "widget.h" #include "server.h" namespace OpenAxiom { @@ -74,43 +75,28 @@ namespace OpenAxiom { // -- Question -- // --------------- // A question is just a one-liner query area. - class Question : public QLineEdit { - typedef QLineEdit Base; - public: - explicit Question(Exchange&); - Exchange* exchange() const { return parent; } + struct Question : managed_by { + explicit Question(Exchange*); protected: void enterEvent(QEvent*); void focusInEvent(QFocusEvent*); - - private: - Exchange* const parent; }; // ------------ // -- Answer -- // ------------ - class Answer : public OutputTextArea { - typedef OutputTextArea Base; - public: - explicit Answer(Exchange&); - Exchange* exchange() const { return parent; } - - private: - Exchange* const parent; + struct Answer : managed_by { + explicit Answer(Exchange*); }; // -------------- // -- Exchange -- // -------------- - class Exchange : public QFrame { + class Exchange : public managed_by { Q_OBJECT; public: - Exchange(Conversation&, int); - - // Return the parent widget of this conversation topic - Conversation* topic() const { return parent; } + Exchange(Conversation*, int); // The widget holding the query area Question* question() { return &query; } @@ -130,7 +116,6 @@ namespace OpenAxiom { void resizeEvent(QResizeEvent*); private: - Conversation* const parent; const int no; Question query; Answer reply; @@ -150,11 +135,10 @@ namespace OpenAxiom { // -- We remember and number each topic so that we // -- can go back in the conversation set and reevaluate // -- queries. - class Conversation : public QWidget { + class Conversation : public managed_by { Q_OBJECT; - typedef QWidget Base; public: - explicit Conversation(Debate&, const Command&); + explicit Conversation(Debate*); ~Conversation(); // Holds if this conversation just started. @@ -177,14 +161,8 @@ namespace OpenAxiom { // of all conversations so far. QSize sizeHint() const; - // Return a pointer to the oracle in this conversation. - Server* server() { return &srv; } - // Return a pointer to the current exchange, if any. Exchange* exchange() { return cur_ex; } - - // Return the parent engine widget. - Debate* debate() const { return group; } public slots: // Return the topic following a given topic in this set of conversations @@ -199,10 +177,8 @@ namespace OpenAxiom { private: typedef std::vector Children; - Debate* group; Banner greatings; Children children; - Server srv; Exchange* cur_ex; OutputTextArea* cur_out; }; diff --git a/src/gui/debate.cc b/src/gui/debate.cc index deaed417..9cb19438 100644 --- a/src/gui/debate.cc +++ b/src/gui/debate.cc @@ -35,25 +35,15 @@ namespace OpenAxiom { - Debate::Debate(QTabWidget* parent, Command& cmd) - : QScrollArea(parent), conv(*this, cmd) { + Debate::Debate(QTabWidget* tab) + : super(tab), conv(this) { setWidget(&conv); setViewportMargins(0, 0, 0, 0); viewport()->setAutoFillBackground(true); viewport()->setBackgroundRole(conv.backgroundRole()); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - adjustSize(); - - exchanges()->server()->launch(); - // When invoked in a --role=server mode, OpenAxiom would - // wait to be pinged before displaying a prompt. This is - // an unfortunate result of a rather awkward hack. - exchanges()->server()->input(""); - - connect(exchanges()->server(), - SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(done(int))); + // adjustSize(); } Debate::~Debate() { } @@ -65,11 +55,4 @@ namespace OpenAxiom { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); } - - void Debate::done(int exit_code) { - // For the time being, shut done the whole application - // if the interpreter quits. FIXME. - QApplication::exit(exit_code); - } - } diff --git a/src/gui/debate.h b/src/gui/debate.h index 7dca347c..60749816 100644 --- a/src/gui/debate.h +++ b/src/gui/debate.h @@ -37,15 +37,16 @@ #include #include #include "open-axiom.h" +#include "widget.h" #include "conversation.h" #include "main-window.h" namespace OpenAxiom { - class Debate : public QScrollArea { + class Debate : public managed_by { Q_OBJECT; public: - explicit Debate(QTabWidget*, Command&); + explicit Debate(QTabWidget*); ~Debate(); Conversation* exchanges() { return &conv; } @@ -57,9 +58,6 @@ namespace OpenAxiom { protected: void resizeEvent(QResizeEvent*); - private slots: - void done(int); - private: Conversation conv; }; diff --git a/src/gui/gui.pro.in b/src/gui/gui.pro.in index 30e70349..491b0a9c 100644 --- a/src/gui/gui.pro.in +++ b/src/gui/gui.pro.in @@ -27,7 +27,7 @@ TARGET = gui VPATH += @srcdir@ ## Our headers -HEADERS += server.h conversation.h main-window.h debate.h +HEADERS += widget.h server.h conversation.h main-window.h debate.h INCLUDEPATH += $$OA_INC INCLUDEPATH += @srcdir@ INCLUDEPATH += @top_srcdir@/src/include diff --git a/src/gui/main-window.cc b/src/gui/main-window.cc index 9912bf41..b3063638 100644 --- a/src/gui/main-window.cc +++ b/src/gui/main-window.cc @@ -31,42 +31,46 @@ #include #include +#include +#include #include "debate.h" #include "main-window.h" namespace OpenAxiom { - - // Attempt to resize the main window so that on the first exposure - // the exchanges in this debate have the preferred geometry and the - // horizontal scroll bar is not needed. - static void - try_to_honor_widget_size(MainWindow* w, Debate* debate) { - // Force a show first, to provoke conversation size. - // That helps getting the sizes right. On the other hand, it - // makes for several resize event roundring leading to - // an awkward looking brief window showing. FIXME. - w->show(); - QSize diff = debate->exchanges()->size() - debate->viewport()->size(); - if (diff.width() < 0) - diff.setWidth(0); - if (diff.height() < 0) - diff.setHeight(0); - w->resize(w->size() + diff); - } - - MainWindow::MainWindow(Command& cmd) : fs(cmd.root_dir), srv(cmd), tabs(this) { + MainWindow::MainWindow(Command& cmd) : srv(cmd), tabs(this) { setCentralWidget(&tabs); - Debate* debate = new Debate(&tabs, cmd); + Debate* debate = new Debate(&tabs); tabs.addTab(debate, "Main Frame"); QMenu* file = menuBar()->addMenu(tr("&File")); QAction* action = new QAction(tr("Quit"), this); file->addAction(action); action->setShortcut(tr("Ctrl+Q")); connect(action, SIGNAL(triggered()), this, SLOT(close())); - try_to_honor_widget_size(this, debate); + + connect(server(), SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(done(int, QProcess::ExitStatus))); + connect(server(), SIGNAL(readyReadStandardError()), + this, SLOT(display_error())); + + server()->launch(); + // When invoked in a --role=server mode, OpenAxiom would + // wait to be pinged before displaying a prompt. This is + // an unfortunate result of a rather awkward hack. + server()->input(""); } MainWindow::~MainWindow() { } + + void MainWindow::done(int s, QProcess::ExitStatus) { + // For the time being, shut done the whole application + // if the interpreter quits. FIXME. + QApplication::exit(s); + } + + void MainWindow::display_error() { + auto s = server()->readAllStandardError(); + QMessageBox::critical(this, tr("System error"), QString(s)); + } } diff --git a/src/gui/main-window.h b/src/gui/main-window.h index 74e5effd..c16c4136 100644 --- a/src/gui/main-window.h +++ b/src/gui/main-window.h @@ -45,12 +45,13 @@ namespace OpenAxiom { MainWindow(Command&); ~MainWindow(); - // Pointer to the root file system of the OpenAxiom installation - Filesystem* filesystem() { return &fs; } Server* server() { return &srv; } + + private slots: + void done(int, QProcess::ExitStatus); + void display_error(); private: - Filesystem fs; Server srv; QTabWidget tabs; }; diff --git a/src/gui/server.cc b/src/gui/server.cc index 461c22b8..601599e9 100644 --- a/src/gui/server.cc +++ b/src/gui/server.cc @@ -34,7 +34,6 @@ namespace OpenAxiom { Server::Server(const Command& c) : cmd(c), fs(c.root_dir) { - setProcessChannelMode(QProcess::MergedChannels); } Server::~Server() { diff --git a/src/gui/widget.h b/src/gui/widget.h new file mode 100644 index 00000000..1ccf8573 --- /dev/null +++ b/src/gui/widget.h @@ -0,0 +1,51 @@ +// Copyright (C) 2013, Gabriel Dos Reis. +// All rights reserved. +// Written by Gabriel Dos Reis. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// - Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// - Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in +// the documentation and/or other materials provided with the +// distribution. +// +// - Neither the name of OpenAxiom. nor the names of its contributors +// may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef OPENAXIOM_WIDGET_included +#define OPENAXIOM_WIDGET_included + +#include + +namespace OpenAxiom { + template + struct managed_by : S { + using super = managed_by; + managed_by(T* t) : S(t) { } + T* parent() const { return qobject_cast(S::parent()); } + }; +} + +#endif // OPENAXIOM_WIDGET_included + +// Local Variables: +// mode: c++ +// End: -- cgit v1.2.3