changeset 14719:89c64340e9ab gui

Extended event based communication model. * octave-event-listener.h: New interface for event listeners. * octave-qt-event-listener: Implementation ov event listener for Qt. * main-window: Added event listener and connected signals. * octave-event-observer.h: Renamed ignore-method and added comments. * octave-event.h: Removed type information and added process method instead. * octave-link: Removed QObject subclassing. * src.pro: Added new files to project. * workspace-model: Removed QTimer, since it not in a Qt event loop anymore. * workspace-view: Added QTimer from the model temporarily.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Mon, 04 Jun 2012 16:08:44 +0200
parents 3df7ef0080c7
children cecc7da96e2a
files gui/src/main-window.cc gui/src/main-window.h gui/src/octave-adapter/octave-event-listener.h gui/src/octave-adapter/octave-event-observer.h gui/src/octave-adapter/octave-event.h gui/src/octave-adapter/octave-link.cc gui/src/octave-adapter/octave-link.h gui/src/octave-adapter/octave-main-thread.cc gui/src/octave-adapter/octave-main-thread.h gui/src/octave-qt-event-listener.cc gui/src/octave-qt-event-listener.h gui/src/src.pro gui/src/workspace-model.cc gui/src/workspace-model.h gui/src/workspace-view.cc gui/src/workspace-view.h
diffstat 16 files changed, 224 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/gui/src/main-window.cc	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/main-window.cc	Mon Jun 04 16:08:44 2012 +0200
@@ -34,6 +34,14 @@
 {
   // We have to set up all our windows, before we finally launch octave.
   construct ();
+  _octave_qt_event_listener = new octave_qt_event_listener ();
+  octave_link::instance ()->register_event_listener (_octave_qt_event_listener);
+
+  connect (_octave_qt_event_listener,
+           SIGNAL (current_directory_changed(QString)),
+           this,
+           SLOT (update_current_working_directory(QString)));
+
   octave_link::instance ()->launch_octave();
 }
 
@@ -168,8 +176,8 @@
 
   if (!selectedDirectory.isEmpty ())
     {
-      _terminal->sendText (QString ("cd \'%1\'\n").arg (selectedDirectory));
-      _terminal->setFocus ();
+      octave_link::instance ()
+          ->request_working_directory_change (selectedDirectory.toStdString ());
     }
 }
 
@@ -429,8 +437,8 @@
            _terminal,                   SLOT   (copyClipboard ()));
   connect (paste_action,                SIGNAL (triggered()),
            _terminal,                   SLOT   (pasteClipboard ()));
-  connect (octave_link::instance (),    SIGNAL (working_directory_changed (QString)),
-           this,                        SLOT (update_current_working_directory (QString)));
+//  connect (octave_link::instance (),    SIGNAL (working_directory_changed (QString)),
+//           this,                        SLOT (update_current_working_directory (QString)));
   connect (_current_directory_combo_box, SIGNAL (activated (QString)),
            this,                        SLOT (change_current_working_directory (QString)));
 
--- a/gui/src/main-window.h	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/main-window.h	Mon Jun 04 16:08:44 2012 +0200
@@ -44,6 +44,7 @@
 #include "history-dockwidget.h"
 #include "files-dockwidget.h"
 #include "terminal-dockwidget.h"
+#include "octave-qt-event-listener.h"
 
 /**
   * \class MainWindow
@@ -110,6 +111,8 @@
   QToolButton *             _current_directory_tool_button;
   QToolButton *             _current_directory_up_tool_button;
 
+  octave_qt_event_listener *_octave_qt_event_listener;
+
   // Flag for closing whole application
   bool                      _closing;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui/src/octave-adapter/octave-event-listener.h	Mon Jun 04 16:08:44 2012 +0200
@@ -0,0 +1,32 @@
+/* OctaveGUI - A graphical user interface for Octave
+ * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OCTAVEEVENTLISTENER_H
+#define OCTAVEEVENTLISTENER_H
+
+#include <string>
+
+class octave_event_listener
+{
+  public:
+    octave_event_listener () { }
+    virtual ~octave_event_listener () { }
+
+    virtual void current_directory_has_changed (std::string directory) = 0;
+};
+
+#endif // OCTAVEEVENTLISTENER_H
--- a/gui/src/octave-adapter/octave-event-observer.h	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/octave-adapter/octave-event-observer.h	Mon Jun 04 16:08:44 2012 +0200
@@ -30,8 +30,17 @@
     octave_event_observer () { }
     virtual ~octave_event_observer () { }
 
+    /**
+      * This will be called when an event has been accepted. Operations
+      * in this routine will be processed in the octave thread.
+      */
     virtual void event_accepted (octave_event *e) const = 0;
-    virtual void event_ignored (octave_event *e) const = 0;
+
+    /**
+      * This will be called when an event has been rejected. Operations
+      * in this routine will be processed in the octave thread.
+      */
+    virtual void event_reject (octave_event *e) const = 0;
 };
 
 #include "octave-event.h"
--- a/gui/src/octave-adapter/octave-event.h	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/octave-adapter/octave-event.h	Mon Jun 04 16:08:44 2012 +0200
@@ -20,20 +20,24 @@
 
 #include <string>
 #include "octave-event-observer.h"
+#include "oct-env.h"
+#include "toplev.h"
 
 /**
   * \class octave_event
   * \brief Base class for an octave event.
+  * In order to make communication with octave threadsafe, comunication is
+  * implemented via events. An application may create events and post them,
+  * however there is no guarantee events will be processed in a given time.
+  *
+  * In order to create an event, there must be an event observer. The event
+  * observer will be given the opportunity to react on the event as soon as
+  * it has been processed in the octave thread. Accepting and ignoring takes
+  * places in the octave thread.
   */
 class octave_event
 {
   public:
-    enum event_type
-    {
-      exit_event,
-      change_directory_event
-    };
-
     octave_event (const octave_event_observer& o)
       : _octave_event_observer (o)
     { }
@@ -41,42 +45,54 @@
     virtual ~octave_event ()
     { }
 
-    virtual event_type get_event_type () const = 0;
+    /** Performs what it necessary to make this event happen.
+      * This code is thread-safe since it will be executed in the octave thread.
+      * However, you should take care to keep this code as short as possible. */
+    virtual bool perform () const = 0;
 
+    /**
+      * Accepts this event. This allows the event observer to react properly
+      * onto the event.
+      */
     void accept ()
     { _octave_event_observer.event_accepted (this); }
 
-    void ignore ()
-    { _octave_event_observer.event_ignored (this); }
+    /**
+      * Rejects this event. This allows the event observer to react properly
+      * onto the event.
+      */
+    void reject ()
+    { _octave_event_observer.event_reject (this); }
 
   private:
     const octave_event_observer& _octave_event_observer;
 };
 
+/** Implements an octave exit event. */
 class octave_exit_event : public octave_event
 {
   public:
+    /** Creates a new octave_exit_event. */
     octave_exit_event (const octave_event_observer& o)
       : octave_event (o)
     { }
 
-    event_type get_event_type () const
-    { return octave_event::exit_event; }
+    bool perform () const
+    { clean_up_and_exit (0); return true; }
 };
 
+/** Implements a change directory events. */
 class octave_change_directory_event : public octave_event
 {
   public:
+    /** Creates a new octave_change_directory_event. */
     octave_change_directory_event (const octave_event_observer& o,
                                    std::string directory)
       : octave_event (o)
     { _directory = directory; }
 
-    event_type get_event_type () const
-    { return octave_event::change_directory_event; }
-
-    std::string get_directory () const
-    { return _directory; }
+    bool perform () const
+    { return octave_env::chdir (_directory); }
 
   private:
     std::string _directory;
--- a/gui/src/octave-adapter/octave-link.cc	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/octave-adapter/octave-link.cc	Mon Jun 04 16:08:44 2012 +0200
@@ -17,7 +17,6 @@
 
 #include "octave-link.h"
 #include "load-path.h"
-#include "oct-env.h"
 #include <QDir>
 #include <QApplication>
 
@@ -25,7 +24,8 @@
 {
   octave_link::instance ()->trigger_update_history_model ();
   octave_link::instance ()->build_symbol_information ();
-  octave_link::instance ()->update_current_working_directory ();
+
+  octave_link::instance ()->generate_events ();
   octave_link::instance ()->process_events ();
   return 0;
 }
@@ -33,29 +33,18 @@
 void octave_exit_hook (int status)
 {
   Q_UNUSED (status);
-  octave_link::instance ()->terminate_octave ();
+  qApp->quit ();
 }
 
 octave_link octave_link::_singleton;
 
-octave_link::octave_link ():QObject ()
+octave_link::octave_link ()
 {
-  _history_model = new QStringListModel (this);
-  _workspace_model = new workspace_model (this);
-
-  _workspace_model->insert_top_level_item(0, new tree_item ("Local"));
-  _workspace_model->insert_top_level_item(1, new tree_item ("Global"));
-  _workspace_model->insert_top_level_item(2, new tree_item ("Persistent"));
-  _workspace_model->insert_top_level_item(3, new tree_item ("Hidden"));
-
-  _update_workspace_model_timer.setInterval (1000);
-  _update_workspace_model_timer.setSingleShot (false);
-  connect(&_update_workspace_model_timer, SIGNAL (timeout ()),
-    _workspace_model, SLOT (update_from_symbol_table ()));
-
+  _history_model = new QStringListModel ();
+  _workspace_model = new workspace_model (qApp);
   _symbol_information_semaphore = new QSemaphore (1);
   _event_queue_semaphore = new QSemaphore (1);
-  _current_working_directory = "";
+  _last_working_directory = "";
 }
 
 octave_link::~octave_link ()
@@ -66,19 +55,12 @@
 octave_link::launch_octave ()
 {
   // Create both threads.
-  _octave_main_thread = new octave_main_thread (this);
+  _octave_main_thread = new octave_main_thread ();
   command_editor::add_event_hook (octave_readline_hook);
   octave_exit = octave_exit_hook;
 
   // Start the first one.
   _octave_main_thread->start ();
-  _update_workspace_model_timer.start ();
-}
-
-void
-octave_link::terminate_octave ()
-{
-  qApp->quit ();
 }
 
 void
@@ -100,18 +82,6 @@
 }
 
 void
-octave_link::update_current_working_directory ()
-{
-  QString _queriedWorkingDirectory = octave_env::get_current_directory ().c_str();
-  if (_current_working_directory != _queriedWorkingDirectory)
-    {
-      _current_working_directory = _queriedWorkingDirectory;
-      QDir::setCurrent (_current_working_directory);
-      emit working_directory_changed (_current_working_directory);
-    }
-}
-
-void
 octave_link::acquire_symbol_information ()
 {
   _symbol_information_semaphore->acquire (1);
@@ -146,6 +116,10 @@
   return _symbol_information;
 }
 
+void
+octave_link::register_event_listener (octave_event_listener *oel)
+{ _octave_event_listener = oel; }
+
 QStringListModel *
 octave_link::get_history_model ()
 {
@@ -159,32 +133,30 @@
 }
 
 void
+octave_link::generate_events ()
+{
+  std::string current_working_directory = octave_env::get_current_directory ();
+  if (current_working_directory != _last_working_directory)
+    {
+      _last_working_directory = current_working_directory;
+      if (_octave_event_listener)
+        _octave_event_listener
+            ->current_directory_has_changed (_last_working_directory);
+    }
+}
+
+void
 octave_link::process_events ()
 {
   _event_queue_semaphore->acquire ();
   while (_event_queue.size () > 0)
     {
-      octave_event * e = _event_queue.takeFirst ();
-      switch (e->get_event_type ())
-        {
-          case octave_event::exit_event:
-            clean_up_and_exit (0);
-            e->accept ();
-            break;
-
-          case octave_event::change_directory_event:
-            octave_change_directory_event * cde
-                = dynamic_cast <octave_change_directory_event *> (e);
-            if (cde)
-              {
-                std::string directory = cde->get_directory ();
-                if (octave_env::chdir (directory))
-                  e->accept ();
-                else
-                  e->ignore ();
-              }
-            break;
-        }
+      octave_event * e = _event_queue.front ();
+      _event_queue.pop ();
+      if (e->perform ())
+        e->accept ();
+      else
+        e->reject ();
     }
   _event_queue_semaphore->release ();
 }
@@ -195,7 +167,7 @@
   if (e)
     {
       _event_queue_semaphore->acquire ();
-      _event_queue.push_front (e);
+      _event_queue.push (e);
       _event_queue_semaphore->release ();
     }
 }
@@ -205,7 +177,7 @@
 { delete e; }
 
 void
-octave_link::event_ignored (octave_event *e) const
+octave_link::event_reject (octave_event *e) const
 { delete e; }
 
 void
--- a/gui/src/octave-adapter/octave-link.h	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/octave-adapter/octave-link.h	Mon Jun 04 16:08:44 2012 +0200
@@ -59,6 +59,7 @@
 #include <string>
 #include <vector>
 #include <readline/readline.h>
+#include <queue>
 
 // Qt includes
 #include <QMutexLocker>
@@ -69,7 +70,6 @@
 #include <QStringList>
 #include <QVector>
 #include <QSemaphore>
-#include <QObject>
 #include <QStringListModel>
 #include <QTimer>
 #include <QQueue>
@@ -78,6 +78,7 @@
 #include "octave-main-thread.h"
 #include "octave-event.h"
 #include "octave-event-observer.h"
+#include "octave-event-listener.h"
 #include "symbol-information.h"
 
 /**
@@ -86,11 +87,10 @@
   * \author Jacob Dawid
   * This class is a wrapper around octave and provides threadsafety by
   * buffering access operations to octave and executing them in the readline
-  * even hook, which lives in the octave thread.
+  * event hook, which lives in the octave thread.
   */
-class octave_link : public QObject, public octave_event_observer
+class octave_link : public octave_event_observer
 {
-  Q_OBJECT
 public:
   /** Provides a way to access the unique octave_link object. */
   static octave_link *
@@ -99,9 +99,6 @@
   /** Starts octave. */
   void launch_octave ();
 
-  /** Attempts to close octave. */
-  void terminate_octave ();
-
   /** Returns the current history model. */
   QStringListModel *get_history_model ();
 
@@ -111,9 +108,6 @@
   /** Triggers an update of the history model. */
   void trigger_update_history_model ();
 
-  /** Updates the current working directory. */
-  void update_current_working_directory ();
-
   /** Acquires the symbol information. You need to acquire that before
     * actually accessing it. Make sure that you release it properly in order
     * to avoid deadlocks. */
@@ -131,24 +125,24 @@
     */
   const QList <symbol_information>& get_symbol_information () const;
 
+  void register_event_listener (octave_event_listener *oel);
+
+  void generate_events ();
   void process_events ();
   void post_event (octave_event *e);
   void event_accepted (octave_event *e) const;
-  void event_ignored (octave_event *e) const;
-
+  void event_reject (octave_event *e) const;
 
   void request_working_directory_change (std::string directory);
   void request_octave_exit ();
 
-signals:
-  /** Emitted, whenever the working directory of octave changed. */
-  void working_directory_changed (QString directory);
-
 private:
   /** Singleton. */
   octave_link ();
   ~octave_link ();
 
+  octave_event_listener *_octave_event_listener;
+
   /** Stores the current history_model. */
   QStringListModel *_history_model;
 
@@ -158,10 +152,6 @@
   /** Thread running octave_main. */
   octave_main_thread *_octave_main_thread;
 
-  /** Timer for periodically updating the workspace model from the current
-    * symbol information. */
-  QTimer _update_workspace_model_timer;
-
   /** Semaphore to lock access to the symbol information. */
   QSemaphore *_symbol_information_semaphore;
 
@@ -169,13 +159,13 @@
   QSemaphore *_event_queue_semaphore;
 
   /** Buffer for queueing events until they will be processed. */
-  QQueue <octave_event *> _event_queue;
+  std::queue <octave_event *> _event_queue;
 
   /** Stores the current symbol information. */
   QList <symbol_information> _symbol_information;
 
   /** Stores the last known current working directory of octave. */
-  QString _current_working_directory;
+  std::string _last_working_directory;
 
   /** Unique instance. Singelton! */
   static octave_link _singleton;
--- a/gui/src/octave-adapter/octave-main-thread.cc	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/octave-adapter/octave-main-thread.cc	Mon Jun 04 16:08:44 2012 +0200
@@ -18,7 +18,7 @@
 #include "octave-main-thread.h"
 #include "octave-link.h"
 
-octave_main_thread::octave_main_thread (QObject * parent):QThread (parent)
+octave_main_thread::octave_main_thread () : QThread ()
 {
 }
 
--- a/gui/src/octave-adapter/octave-main-thread.h	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/octave-adapter/octave-main-thread.h	Mon Jun 04 16:08:44 2012 +0200
@@ -30,7 +30,7 @@
   Q_OBJECT
 public:
   /** Creates a new thread running octave_main. */
-  octave_main_thread (QObject * parent);
+  octave_main_thread ();
 
 signals:
   /** This signal will be emitted when the thread is about to actually run octave_main. */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui/src/octave-qt-event-listener.cc	Mon Jun 04 16:08:44 2012 +0200
@@ -0,0 +1,27 @@
+/* OctaveGUI - A graphical user interface for Octave
+ * Copyright (C) 2012 Jacob Dawid (jacob.dawid@googlemail.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "octave-qt-event-listener.h"
+
+octave_qt_event_listener::octave_qt_event_listener (QObject *parent)
+  : QObject (parent), octave_event_listener ()
+{
+}
+
+void
+octave_qt_event_listener::current_directory_has_changed (std::string directory)
+{ emit current_directory_changed (QString::fromStdString (directory)); }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui/src/octave-qt-event-listener.h	Mon Jun 04 16:08:44 2012 +0200
@@ -0,0 +1,38 @@
+/* OctaveGUI - A graphical user interface for Octave
+ * Copyright (C) 2012 Jacob Dawid (jacob.dawid@googlemail.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OCTAVEQTEVENTLISTENER_H
+#define OCTAVEQTEVENTLISTENER_H
+
+#include <QObject>
+#include <QString>
+#include "octave-event-listener.h"
+
+class octave_qt_event_listener
+    : public QObject, public octave_event_listener
+{
+    Q_OBJECT
+  public:
+    octave_qt_event_listener (QObject *parent = 0);
+
+    void current_directory_has_changed (std::string directory);
+
+  signals:
+    void current_directory_changed (QString directory);
+};
+
+#endif // OCTAVEQTEVENTLISTENER_H
--- a/gui/src/src.pro	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/src.pro	Mon Jun 04 16:08:44 2012 +0200
@@ -88,7 +88,8 @@
     resource-manager.cc \
     welcome-wizard.cc \
     workspace-model.cc \
-    terminal-dockwidget.cc
+    terminal-dockwidget.cc \
+    octave-qt-event-listener.cc
 
 HEADERS += \
     octave-adapter/octave-link.h \
@@ -108,7 +109,9 @@
     workspace-model.h \
     terminal-dockwidget.h \
     octave-adapter/octave-event.h \
-    octave-adapter/octave-event-observer.h
+    octave-adapter/octave-event-observer.h \
+    octave-adapter/octave-event-listener.h \
+    octave-qt-event-listener.h
 
 FORMS += \
     settings-dialog.ui \
--- a/gui/src/workspace-model.cc	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/workspace-model.cc	Mon Jun 04 16:08:44 2012 +0200
@@ -26,6 +26,11 @@
   QList<QVariant> rootData;
   rootData << tr ("Name") << tr ("Type") << tr ("Value");
   _rootItem = new tree_item(rootData);
+
+  insert_top_level_item(0, new tree_item ("Local"));
+  insert_top_level_item(1, new tree_item ("Global"));
+  insert_top_level_item(2, new tree_item ("Persistent"));
+  insert_top_level_item(3, new tree_item ("Hidden"));
 }
 
 workspace_model::~workspace_model()
--- a/gui/src/workspace-model.h	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/workspace-model.h	Mon Jun 04 16:08:44 2012 +0200
@@ -22,6 +22,7 @@
 #include <QAbstractItemModel>
 #include <QVector>
 #include <QSemaphore>
+#include <QTimer>
 
 class tree_item
 {
@@ -130,7 +131,6 @@
   void expand_request();
 
 private:
-
   tree_item *_rootItem;
 };
 
--- a/gui/src/workspace-view.cc	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/workspace-view.cc	Mon Jun 04 16:08:44 2012 +0200
@@ -43,6 +43,14 @@
 
   connect (octave_link::instance()->get_workspace_model(), SIGNAL(expand_request()),
            _workspace_tree_view, SLOT(expandAll()));
+
+  connect(&_update_workspace_model_timer, SIGNAL (timeout ()),
+    octave_link::instance()->get_workspace_model(),
+          SLOT (update_from_symbol_table ()));
+
+  _update_workspace_model_timer.setInterval (1000);
+  _update_workspace_model_timer.setSingleShot (false);
+  _update_workspace_model_timer.start ();
 }
 
 void
--- a/gui/src/workspace-view.h	Mon Jun 04 01:42:58 2012 +0200
+++ b/gui/src/workspace-view.h	Mon Jun 04 16:08:44 2012 +0200
@@ -41,6 +41,10 @@
 
 private:
   QTreeView *_workspace_tree_view;
+
+  /** Timer for periodically updating the workspace model from the current
+    * symbol information. */
+  QTimer _update_workspace_model_timer;
 };
 
 #endif // WORKSPACEVIEW_H