aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gui/conversation.C170
-rw-r--r--src/gui/conversation.h62
-rw-r--r--src/gui/debate.C8
3 files changed, 193 insertions, 47 deletions
diff --git a/src/gui/conversation.C b/src/gui/conversation.C
index 22d9dea7..0c5ec778 100644
--- a/src/gui/conversation.C
+++ b/src/gui/conversation.C
@@ -39,32 +39,67 @@
#include "debate.h"
namespace OpenAxiom {
- static void debug_size(const char* s, const QSize& sz) {
- std::cerr << s << " == "
- << sz.width() << ", " << sz.height() << std::endl;
- }
-
// Measurement in pixel of the em unit in the given font `f'.
static QSize em_metrics(const QWidget* w) {
const QFontMetrics fm = w->fontMetrics();
return QSize(fm.width(QLatin1Char('m')), fm.height());
}
- // -- Question --
- Question::Question(Exchange& e) : Base(&e), parent(&e) { }
+ // --------------------
+ // -- OutputTextArea --
+ // --------------------
+ OutputTextArea::OutputTextArea(QWidget* p)
+ : Base(p) {
+ setFont(p->font());
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ setLineWidth(1);
+ }
- void Question::enterEvent(QEvent* e) {
- Base::enterEvent(e);
- setFocus(Qt::OtherFocusReason);
+ // Concatenate two paragraphs.
+ static QString
+ accumulate_paragaphs(const QString& before, const QString& after) {
+ if (before.isNull() or before.isEmpty())
+ return after;
+ return before + "\n" + after;
+ }
+
+ void OutputTextArea::add_paragraph(const QString& s) {
+ setText(accumulate_paragaphs(text(), s));
+ adjustSize();
+ const int w = parentWidget()->width() - 2 * frameWidth();
+ if (w > width())
+ resize(w, height());
+ show();
+ updateGeometry();
+ }
+
+ void OutputTextArea::add_text(const QString& s) {
+ setText(text() + s);
+ adjustSize();
+ const int w = parentWidget()->width();
+ if (w < width())
+ resize(w, height());
+ show();
+ updateGeometry();
}
+ // --------------
+ // -- Question --
+ // --------------
+ Question::Question(Exchange& e) : Base(&e), parent(&e) {
+ setBackgroundRole(QPalette::AlternateBase);
+ }
+
+ // ------------
// -- Answer --
+ // ------------
Answer::Answer(Exchange& e) : Base(&e), parent(&e) {
- setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
- setFrameStyle(StyledPanel | Plain);
+ setFrameStyle(StyledPanel | Sunken);
}
+ // --------------
// -- Exchange --
+ // --------------
// Amount of pixel spacing between the query and reply areas.
const int spacing = 0;
@@ -75,8 +110,9 @@ namespace OpenAxiom {
return f;
}
- static int margin(const Exchange*e) {
- return 2 + e->frameWidth();
+ // Return a resonable margin for this frame.
+ static int margin(const QFrame* f) {
+ return 2 + f->frameWidth();
}
// The layout within an exchange is as follows:
@@ -117,12 +153,13 @@ namespace OpenAxiom {
static void
finish_exchange_make_up(Conversation& conv, Exchange* e) {
e->setAutoFillBackground(true);
- e->setBackgroundRole(e->question()->backgroundRole());
+ //e->setBackgroundRole(e->question()->backgroundRole());
e->move(conv.bottom_left());
}
Exchange::Exchange(Conversation& conv, int n)
- : QFrame(&conv), parent(&conv), no(n), query(*this), reply(*this) {
+ : QFrame(&conv), parent(&conv), no(n),
+ query(*this), reply(*this) {
setLineWidth(1);
setFont(conv.font());
prepare_query_widget(conv, this);
@@ -132,13 +169,6 @@ namespace OpenAxiom {
this, SLOT(reply_to_query()));
}
- static QString
- parenthesize(int n) {
- std::ostringstream os;
- os << '(' << n << ')';
- return QString::fromStdString(os.str());
- }
-
static void ensure_visibility(Debate* debate, Exchange* e) {
const int y = e->y() + e->height();
QScrollBar* vbar = debate->verticalScrollBar();
@@ -156,13 +186,8 @@ namespace OpenAxiom {
QString input = question()->text().trimmed();
if (input.isEmpty())
return;
- QString ans = parenthesize(number()) + " " + input;
- answer()->show();
- answer()->setText(ans);
- adjustSize();
- update();
- updateGeometry();
- ensure_visibility(conversation()->debate(), conversation()->next(this));
+ topic()->oracle()->write(input.toAscii());
+ topic()->oracle()->write("\n");
}
void Exchange::resizeEvent(QResizeEvent* e) {
@@ -174,6 +199,14 @@ namespace OpenAxiom {
}
}
+ // ------------
+ // -- Banner --
+ // ------------
+ Banner::Banner(Conversation* conv) : Base(conv) {
+ setFrameStyle(StyledPanel | Raised);
+ setBackgroundRole(QPalette::Base);
+ }
+
// ------------------
// -- Conversation --
// -------------------
@@ -190,21 +223,32 @@ 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) : group(parent) {
+ Conversation::Conversation(Debate& parent)
+ : group(parent), greatings(this), cur_ex(), cur_out(&greatings) {
+ setBackgroundRole(QPalette::Base);
setFont(monospace_font());
// setMinimumSize(minimum_preferred_size(this));
// setSizePolicy(QSizePolicy::MinimumExpanding,
// QSizePolicy::MinimumExpanding);
+ oracle()->setProcessChannelMode(QProcess::MergedChannels);
+ connect(oracle(), SIGNAL(readyReadStandardOutput()),
+ this, SLOT(read_reply()));
+ // connect(oracle(), SIGNAL(readyReadStandardError()),
+ // this, SLOT(read_reply()));
+ // connect(oracle(), SIGNAL(started()),
+ // this, SLOT(read_reply()));
}
Conversation::~Conversation() {
for (int i = children.size() -1 ; i >= 0; --i)
delete children[i];
+ if (oracle()->state() == QProcess::Running)
+ oracle()->terminate();
}
QPoint Conversation::bottom_left() const {
if (length() == 0)
- return QPoint(0, 0);
+ return greatings.geometry().bottomLeft();
return children.back()->geometry().bottomLeft();
}
@@ -221,8 +265,8 @@ namespace OpenAxiom {
const int n = length();
if (n == 0)
return round_up_height(minimum_preferred_size(this), view_height);
- QSize sz = children.front()->size();
- for (int i = 1; i < n; ++i)
+ QSize sz = greatings.size();
+ for (int i = 0; i < n; ++i)
sz.rheight() += children[i]->height();
return round_up_height(sz, view_height);
}
@@ -233,6 +277,7 @@ namespace OpenAxiom {
const QSize sz = size();
if (e->oldSize() == sz)
return;
+ greatings.resize(sz.width(), greatings.height());
for (int i = 0; i < length(); ++i) {
Exchange* e = children[i];
e->resize(sz.width(), e->height());
@@ -242,7 +287,7 @@ namespace OpenAxiom {
void Conversation::paintEvent(QPaintEvent* e) {
QWidget::paintEvent(e);
if (length() == 0)
- new_topic();
+ greatings.update();
}
Exchange*
@@ -252,13 +297,64 @@ namespace OpenAxiom {
children.push_back(w);
adjustSize();
updateGeometry();
- return w;
+ cur_out = w->answer();
+ return cur_ex = w;
}
Exchange*
Conversation::next(Exchange* w) {
if (w == 0 or w->number() == length())
return new_topic();
- return children[w->number()];
+ return cur_ex = children[w->number()];
+ }
+
+ struct OracleOutput {
+ QString result;
+ QString prompt;
+ };
+
+ static bool
+ empty_string(const QString& s) {
+ return s.isNull() or s.isEmpty();
+ }
+
+ static OracleOutput
+ read_output(QProcess& proc) {
+ OracleOutput output;
+ QStringList strs = QString::fromLocal8Bit(proc.readAll()).split('\n');
+ QStringList new_list;
+ QRegExp rx("\\(\\d+\\)\\s->");
+ while (not strs.isEmpty()) {
+ QString s = strs.takeFirst();
+ if (empty_string(s))
+ continue;
+ if (rx.indexIn(s) != -1) {
+ output.prompt = s;
+ break;
+ }
+ new_list.append(s);
+ }
+ output.result =new_list.join("\n");
+ return output;
+ }
+
+ void
+ Conversation::read_reply() {
+ OracleOutput output = read_output(proc);
+ if (empty_string(output.result))
+ return;
+ std::cerr << output.result.toStdString() << std::endl;
+ cur_out->add_paragraph(output.result);
+ if (length() == 0) {
+ if (not empty_string(output.prompt))
+ ensure_visibility(debate(), new_topic());
+ }
+ else {
+ exchange()->adjustSize();
+ exchange()->update();
+ exchange()->updateGeometry();
+ if (not empty_string(output.prompt))
+ ensure_visibility(debate(), next(exchange()));
+ }
}
}
diff --git a/src/gui/conversation.h b/src/gui/conversation.h
index bed717cd..374dda16 100644
--- a/src/gui/conversation.h
+++ b/src/gui/conversation.h
@@ -40,6 +40,7 @@
#include <QEvent>
#include <QResizeEvent>
#include <QPaintEvent>
+#include <QProcess>
namespace OpenAxiom {
// A conversation is a set of exchanges. An exchange is a question
@@ -51,23 +52,41 @@ namespace OpenAxiom {
class Question;
class Answer;
- // -- A question is just a one-liner query.
+ // --------------------
+ // -- OutputTextArea --
+ // --------------------
+ // An output text area is a widget where we output text.
+ // The texts are accumulated, as opposed to overwritten.
+ class OutputTextArea : public QLabel {
+ typedef QLabel Base;
+ public:
+ explicit OutputTextArea(QWidget*);
+ // Add a new paragraph to existing texts. Paragraghs are
+ // separated by the newline character.
+ void add_paragraph(const QString&);
+ // Add accumulate new text.
+ void add_text(const QString&);
+ };
+
+ // ---------------
+ // -- 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; }
- protected:
- // Automatically grab focus when mouse moves into this widget
- void enterEvent(QEvent*);
-
private:
Exchange* const parent;
};
- class Answer : public QLabel {
- typedef QLabel Base;
+ // ------------
+ // -- Answer --
+ // ------------
+ class Answer : public OutputTextArea {
+ typedef OutputTextArea Base;
public:
explicit Answer(Exchange&);
Exchange* exchange() const { return parent; }
@@ -75,14 +94,17 @@ namespace OpenAxiom {
private:
Exchange* const parent;
};
-
+
+ // --------------
+ // -- Exchange --
+ // --------------
class Exchange : public QFrame {
Q_OBJECT;
public:
Exchange(Conversation&, int);
// Return the parent widget of this conversation topic
- Conversation* conversation() const { return parent; }
+ Conversation* topic() const { return parent; }
// The widget holding the query area
Question* question() { return &query; }
@@ -111,6 +133,13 @@ namespace OpenAxiom {
void reply_to_query();
};
+ // Conversation banner, welcome greatings.
+ class Banner : public OutputTextArea {
+ typedef OutputTextArea Base;
+ public:
+ explicit Banner(Conversation*);
+ };
+
// -- Set of conversations that make up a session.
// -- We remember and number each topic so that we
// -- can go back in the conversation set and reevaluate
@@ -137,11 +166,17 @@ namespace OpenAxiom {
// Start a new conversation topic.
Exchange* new_topic();
-
+
// Override QWidegt::sizeHint. Return the cumulative sizes
// of all conversations so far.
QSize sizeHint() const;
+ // Return a pointer to the oracle in this conversation.
+ QProcess* oracle() { return &proc; }
+
+ // Return a pointer to the current exchange, if any.
+ Exchange* exchange() { return cur_ex; }
+
// Return the parent engine widget.
Debate* debate() const { return const_cast<Debate*>(&group); }
@@ -153,10 +188,17 @@ namespace OpenAxiom {
void resizeEvent(QResizeEvent*);
void paintEvent(QPaintEvent*);
+ private slots:
+ void read_reply();
+
private:
typedef std::vector<Exchange*> Children;
Debate& group;
+ Banner greatings;
Children children;
+ QProcess proc;
+ Exchange* cur_ex;
+ OutputTextArea* cur_out;
};
}
diff --git a/src/gui/debate.C b/src/gui/debate.C
index 50c6891a..ba58c522 100644
--- a/src/gui/debate.C
+++ b/src/gui/debate.C
@@ -35,6 +35,13 @@
namespace OpenAxiom {
+ static void
+ start_interpreter(Conversation* conv) {
+ QStringList args;
+ args << "--no-server" << "--role=slave";
+ conv->oracle()->start("open-axiom",args);
+ }
+
Debate::Debate(QWidget* parent)
: QScrollArea(parent), conv(*this) {
setWidget(&conv);
@@ -44,6 +51,7 @@ namespace OpenAxiom {
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
adjustSize();
+ start_interpreter(exchanges());
}
Debate::~Debate() { }