# HG changeset patch # User Jacob Dawid # Date 1338818924 -7200 # Node ID 89c64340e9abd94cd98fdb96f8bf4d9cf4682124 # Parent 3df7ef0080c76d1696a0e6681b2505513c5e63eb 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. diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/main-window.cc --- 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))); diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/main-window.h --- 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; }; diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-adapter/octave-event-listener.h --- /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 . + */ + +#ifndef OCTAVEEVENTLISTENER_H +#define OCTAVEEVENTLISTENER_H + +#include + +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 diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-adapter/octave-event-observer.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" diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-adapter/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 #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; diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-adapter/octave-link.cc --- 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 #include @@ -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 (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 diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-adapter/octave-link.h --- 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 #include #include +#include // Qt includes #include @@ -69,7 +70,6 @@ #include #include #include -#include #include #include #include @@ -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 & 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 _event_queue; + std::queue _event_queue; /** Stores the current symbol information. */ QList _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; diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-adapter/octave-main-thread.cc --- 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 () { } diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-adapter/octave-main-thread.h --- 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. */ diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-qt-event-listener.cc --- /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 . + */ + +#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)); } diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/octave-qt-event-listener.h --- /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 . + */ + +#ifndef OCTAVEQTEVENTLISTENER_H +#define OCTAVEQTEVENTLISTENER_H + +#include +#include +#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 diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/src.pro --- 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 \ diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/workspace-model.cc --- 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 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() diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/workspace-model.h --- 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 #include #include +#include class tree_item { @@ -130,7 +131,6 @@ void expand_request(); private: - tree_item *_rootItem; }; diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/workspace-view.cc --- 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 diff -r 3df7ef0080c7 -r 89c64340e9ab gui/src/workspace-view.h --- 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