changeset 14766:3df7ef0080c7 gui

Added event based processing and implement exit and change directory event. * octave-event-observer.h: Implements observer part for the observer pattern. * main-window.cc: Posting events instead of emulating keypresses. * octave-event.h: Added new event types. * octave-link: Subclassed octave_event_observer and implemented events. * src.pro: Added file for tracking.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Mon, 04 Jun 2012 01:42:58 +0200
parents 572a707408b2
children 89c64340e9ab
files gui/src/m-editor/file-editor.cc gui/src/main-window.cc 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/src.pro
diffstat 7 files changed, 253 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/gui/src/m-editor/file-editor.cc
+++ b/gui/src/m-editor/file-editor.cc
@@ -284,42 +284,42 @@
   _tab_widget->setTabsClosable (true);
 
   // Theme icons with QStyle icons as fallback
-  QAction *newAction = new QAction (
+  QAction *new_action = new QAction (
         QIcon::fromTheme("document-new",style->standardIcon (QStyle::SP_FileIcon)),
         tr("&New File"), _tool_bar);
 
-  QAction *openAction = new QAction (
+  QAction *open_action = new QAction (
         QIcon::fromTheme("document-open",style->standardIcon (QStyle::SP_DirOpenIcon)),
         tr("&Open File"), _tool_bar);
 
-  QAction *saveAction = new QAction (
+  QAction *save_action = new QAction (
         QIcon::fromTheme("document-save",style->standardIcon (QStyle::SP_DriveHDIcon)),
         tr("&Save File"), _tool_bar);
 
-  QAction *saveAsAction = new QAction (
+  QAction *save_as_action = new QAction (
         QIcon::fromTheme("document-save-as",style->standardIcon (QStyle::SP_DriveFDIcon)),
         tr("Save File &As"), _tool_bar);
 
-  QAction *undoAction = new QAction (
+  QAction *undo_action = new QAction (
         QIcon::fromTheme("edit-undo",style->standardIcon (QStyle::SP_ArrowLeft)),
         tr("&Undo"), _tool_bar);
 
-  QAction *redoAction = new QAction (
+  QAction *redo_action = new QAction (
         QIcon::fromTheme("edit-redo",style->standardIcon (QStyle::SP_ArrowRight)),
         tr("&Redo"), _tool_bar);
 
   _copy_action = new QAction (QIcon::fromTheme ("edit-copy"), tr ("&Copy"), _tool_bar);
-  _cut_action = new QAction (QIcon::fromTheme ("edit-cut"), tr ("Cu&t"), _tool_bar);
+  _cut_action  = new QAction (QIcon::fromTheme ("edit-cut"), tr ("Cu&t"), _tool_bar);
 
-  QAction *pasteAction              = new QAction (QIcon::fromTheme ("edit-paste"), tr ("&Paste"),_tool_bar);
-  QAction *nextBookmarkAction       = new QAction (tr ("&Next Bookmark"),_tool_bar);
-  QAction *prevBookmarkAction       = new QAction (tr ("Pre&vious Bookmark"),_tool_bar);
-  QAction *toggleBookmarkAction     = new QAction (tr ("Toggle &Bookmark"),_tool_bar);
-  QAction *removeBookmarkAction     = new QAction (tr ("&Remove All Bookmarks"),_tool_bar);
-  QAction *commentSelectedAction    = new QAction (tr ("&Comment Selected Text"),_tool_bar);
-  QAction *uncommentSelectedAction  = new QAction (tr ("&Uncomment Selected Text"),_tool_bar);
+  QAction *paste_action               = new QAction (QIcon::fromTheme ("edit-paste"), tr ("&Paste"),_tool_bar);
+  QAction *next_bookmark_action       = new QAction (tr ("&Next Bookmark"),_tool_bar);
+  QAction *previous_bookmark_action   = new QAction (tr ("Pre&vious Bookmark"),_tool_bar);
+  QAction *toggle_bookmark_action     = new QAction (tr ("Toggle &Bookmark"),_tool_bar);
+  QAction *remove_bookmark_action     = new QAction (tr ("&Remove All Bookmarks"),_tool_bar);
+  QAction *comment_selection_action   = new QAction (tr ("&Comment Selected Text"),_tool_bar);
+  QAction *uncomment_selection_action = new QAction (tr ("&Uncomment Selected Text"),_tool_bar);
 
-  QAction *runAction = new QAction (
+  QAction *run_action = new QAction (
         QIcon::fromTheme ("media-play", style->standardIcon (QStyle::SP_MediaPlay)),
         tr("&Run File"), _tool_bar);
 
@@ -328,64 +328,79 @@
   _cut_action->setEnabled(false);
 
   // short cuts
-  newAction->setShortcut              (QKeySequence::New);
-  openAction->setShortcut             (QKeySequence::Open);
-  saveAction->setShortcut             (QKeySequence::Save);
-  saveAsAction->setShortcut           (QKeySequence::SaveAs);
-  undoAction->setShortcut             (QKeySequence::Undo);
-  redoAction->setShortcut             (QKeySequence::Redo);
-  _copy_action->setShortcut           (QKeySequence::Copy);
-  _cut_action->setShortcut            (QKeySequence::Cut);
-  pasteAction->setShortcut            (QKeySequence::Paste);
-  runAction->setShortcut              (Qt::Key_F5);
-  nextBookmarkAction->setShortcut     (Qt::Key_F2);
-  prevBookmarkAction->setShortcut     (Qt::SHIFT + Qt::Key_F2);
-  toggleBookmarkAction->setShortcut   (Qt::Key_F7);
-  commentSelectedAction->setShortcut  (Qt::CTRL + Qt::Key_R);
-  uncommentSelectedAction->setShortcut(Qt::CTRL + Qt::Key_T);
+  new_action->setShortcut                       (QKeySequence::New);
+  new_action->setShortcutContext                (Qt::WidgetShortcut);
+  open_action->setShortcut                      (QKeySequence::Open);
+  open_action->setShortcutContext               (Qt::WidgetShortcut);
+  save_action->setShortcut                      (QKeySequence::Save);
+  save_action->setShortcutContext               (Qt::WidgetShortcut);
+  save_as_action->setShortcut                   (QKeySequence::SaveAs);
+  save_as_action->setShortcutContext            (Qt::WidgetShortcut);
+  undo_action->setShortcut                      (QKeySequence::Undo);
+  undo_action->setShortcutContext               (Qt::WidgetShortcut);
+  redo_action->setShortcut                      (QKeySequence::Redo);
+  redo_action->setShortcutContext               (Qt::WidgetShortcut);
+  _copy_action->setShortcut                     (QKeySequence::Copy);
+  _copy_action->setShortcutContext              (Qt::WidgetShortcut);
+  _cut_action->setShortcut                      (QKeySequence::Cut);
+  _cut_action->setShortcutContext               (Qt::WidgetShortcut);
+  paste_action->setShortcut                     (QKeySequence::Paste);
+  paste_action->setShortcutContext              (Qt::WidgetShortcut);
+  run_action->setShortcut                       (Qt::Key_F5);
+  run_action->setShortcutContext                (Qt::WidgetShortcut);
+  next_bookmark_action->setShortcut             (Qt::Key_F2);
+  next_bookmark_action->setShortcutContext      (Qt::WidgetShortcut);
+  previous_bookmark_action->setShortcut         (Qt::SHIFT + Qt::Key_F2);
+  previous_bookmark_action->setShortcutContext  (Qt::WidgetShortcut);
+  toggle_bookmark_action->setShortcut           (Qt::Key_F7);
+  toggle_bookmark_action->setShortcutContext    (Qt::WidgetShortcut);
+  comment_selection_action->setShortcut         (Qt::CTRL + Qt::Key_R);
+  comment_selection_action->setShortcutContext  (Qt::WidgetShortcut);
+  uncomment_selection_action->setShortcut       (Qt::CTRL + Qt::Key_T);
+  uncomment_selection_action->setShortcutContext(Qt::WidgetShortcut);
 
   // toolbar
-  _tool_bar->addAction (newAction);
-  _tool_bar->addAction (openAction);
-  _tool_bar->addAction (saveAction);
-  _tool_bar->addAction (saveAsAction);
+  _tool_bar->addAction (new_action);
+  _tool_bar->addAction (open_action);
+  _tool_bar->addAction (save_action);
+  _tool_bar->addAction (save_as_action);
   _tool_bar->addSeparator ();
-  _tool_bar->addAction (undoAction);
-  _tool_bar->addAction (redoAction);
+  _tool_bar->addAction (undo_action);
+  _tool_bar->addAction (redo_action);
   _tool_bar->addAction (_copy_action);
   _tool_bar->addAction (_cut_action);
-  _tool_bar->addAction (pasteAction);
+  _tool_bar->addAction (paste_action);
   _tool_bar->addSeparator ();
-  _tool_bar->addAction (runAction);
+  _tool_bar->addAction (run_action);
 
   // menu bar
   QMenu *fileMenu = new QMenu (tr ("&File"), _menu_bar);
-  fileMenu->addAction (newAction);
-  fileMenu->addAction (openAction);
-  fileMenu->addAction (saveAction);
-  fileMenu->addAction (saveAsAction);
+  fileMenu->addAction (new_action);
+  fileMenu->addAction (open_action);
+  fileMenu->addAction (save_action);
+  fileMenu->addAction (save_as_action);
   fileMenu->addSeparator ();
   _menu_bar->addMenu (fileMenu);
 
   QMenu *editMenu = new QMenu (tr ("&Edit"), _menu_bar);
-  editMenu->addAction (undoAction);
-  editMenu->addAction (redoAction);
+  editMenu->addAction (undo_action);
+  editMenu->addAction (redo_action);
   editMenu->addSeparator ();
   editMenu->addAction (_copy_action);
   editMenu->addAction (_cut_action);
-  editMenu->addAction (pasteAction);
+  editMenu->addAction (paste_action);
   editMenu->addSeparator ();
-  editMenu->addAction (commentSelectedAction);
-  editMenu->addAction (uncommentSelectedAction);
+  editMenu->addAction (comment_selection_action);
+  editMenu->addAction (uncomment_selection_action);
   editMenu->addSeparator ();
-  editMenu->addAction (toggleBookmarkAction);
-  editMenu->addAction (nextBookmarkAction);
-  editMenu->addAction (prevBookmarkAction);
-  editMenu->addAction (removeBookmarkAction);
+  editMenu->addAction (toggle_bookmark_action);
+  editMenu->addAction (next_bookmark_action);
+  editMenu->addAction (previous_bookmark_action);
+  editMenu->addAction (remove_bookmark_action);
   _menu_bar->addMenu (editMenu);
 
   QMenu *runMenu = new QMenu (tr ("&Run"), _menu_bar);
-  runMenu->addAction (runAction);
+  runMenu->addAction (run_action);
   _menu_bar->addMenu (runMenu);
 
   QVBoxLayout *layout = new QVBoxLayout ();
@@ -396,22 +411,22 @@
   widget->setLayout (layout);
   setWidget (widget);
 
-  connect (newAction,               SIGNAL (triggered ()), this, SLOT (request_new_file ()));
-  connect (openAction,              SIGNAL (triggered ()), this, SLOT (request_open_file ()));
-  connect (undoAction,              SIGNAL (triggered ()), this, SLOT (request_undo ()));
-  connect (redoAction,              SIGNAL (triggered ()), this, SLOT (request_redo ()));
+  connect (new_action,               SIGNAL (triggered ()), this, SLOT (request_new_file ()));
+  connect (open_action,              SIGNAL (triggered ()), this, SLOT (request_open_file ()));
+  connect (undo_action,              SIGNAL (triggered ()), this, SLOT (request_undo ()));
+  connect (redo_action,              SIGNAL (triggered ()), this, SLOT (request_redo ()));
   connect (_copy_action,            SIGNAL (triggered ()), this, SLOT (request_copy ()));
   connect (_cut_action,             SIGNAL (triggered ()), this, SLOT (request_cut ()));
-  connect (pasteAction,             SIGNAL (triggered ()), this, SLOT (request_paste ()));
-  connect (saveAction,              SIGNAL (triggered ()), this, SLOT (request_save_file ()));
-  connect (saveAsAction,            SIGNAL (triggered ()), this, SLOT (request_save_file_as ()));
-  connect (runAction,               SIGNAL (triggered ()), this, SLOT (request_run_file ()));
-  connect (toggleBookmarkAction,    SIGNAL (triggered ()), this, SLOT (request_toggle_bookmark ()));
-  connect (nextBookmarkAction,      SIGNAL (triggered ()), this, SLOT (request_next_bookmark ()));
-  connect (prevBookmarkAction,      SIGNAL (triggered ()), this, SLOT (request_previous_bookmark ()));
-  connect (removeBookmarkAction,    SIGNAL (triggered ()), this, SLOT (request_remove_bookmark ()));
-  connect (commentSelectedAction,   SIGNAL (triggered ()), this, SLOT (request_comment_selected_text ()));
-  connect (uncommentSelectedAction, SIGNAL (triggered ()), this, SLOT (request_uncomment_selected_text ()));
+  connect (paste_action,             SIGNAL (triggered ()), this, SLOT (request_paste ()));
+  connect (save_action,              SIGNAL (triggered ()), this, SLOT (request_save_file ()));
+  connect (save_as_action,            SIGNAL (triggered ()), this, SLOT (request_save_file_as ()));
+  connect (run_action,               SIGNAL (triggered ()), this, SLOT (request_run_file ()));
+  connect (toggle_bookmark_action,    SIGNAL (triggered ()), this, SLOT (request_toggle_bookmark ()));
+  connect (next_bookmark_action,      SIGNAL (triggered ()), this, SLOT (request_next_bookmark ()));
+  connect (previous_bookmark_action,      SIGNAL (triggered ()), this, SLOT (request_previous_bookmark ()));
+  connect (remove_bookmark_action,    SIGNAL (triggered ()), this, SLOT (request_remove_bookmark ()));
+  connect (comment_selection_action,   SIGNAL (triggered ()), this, SLOT (request_comment_selected_text ()));
+  connect (uncomment_selection_action, SIGNAL (triggered ()), this, SLOT (request_uncomment_selected_text ()));
   connect (_tab_widget, SIGNAL (tabCloseRequested (int)), this, SLOT (handle_tab_close_request (int)));
   connect (_tab_widget, SIGNAL (currentChanged(int)), this, SLOT (active_tab_changed (int)));
 
--- a/gui/src/main-window.cc
+++ b/gui/src/main-window.cc
@@ -176,8 +176,7 @@
 void
 main_window::change_current_working_directory (QString directory)
 {
-  _terminal->sendText (QString ("cd \'%1\'\n").arg (directory));
-  _terminal->setFocus ();
+  octave_link::instance ()->request_working_directory_change (directory.toStdString ());
 }
 
 void
@@ -216,15 +215,8 @@
 main_window::closeEvent (QCloseEvent * closeEvent)
 {
   closeEvent->ignore ();
-  _terminal->sendText ("exit\n");
-    /*
-  report_status_message (tr ("Saving data and shutting down."));
-  _closing = true;  // inform editor window that whole application is closed
-  octave_link::instance ()->terminate_octave ();
-
-  QMainWindow::closeEvent (closeEvent);
-  */
-}
+  octave_link::instance ()->request_octave_exit ();
+ }
 
 void
 main_window::read_settings ()
new file mode 100644
--- /dev/null
+++ b/gui/src/octave-adapter/octave-event-observer.h
@@ -0,0 +1,39 @@
+/* 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 OCTAVEEVENTOBSERVER_H
+#define OCTAVEEVENTOBSERVER_H
+
+class octave_event;
+
+/**
+  * \class octave_event_observer
+  * \brief Implements the observer part for the observer pattern.
+  */
+class octave_event_observer
+{
+  public:
+    octave_event_observer () { }
+    virtual ~octave_event_observer () { }
+
+    virtual void event_accepted (octave_event *e) const = 0;
+    virtual void event_ignored (octave_event *e) const = 0;
+};
+
+#include "octave-event.h"
+
+#endif // OCTAVEEVENTOBSERVER_H
--- a/gui/src/octave-adapter/octave-event.h
+++ b/gui/src/octave-adapter/octave-event.h
@@ -18,6 +18,9 @@
 #ifndef OCTAVEEVENT_H
 #define OCTAVEEVENT_H
 
+#include <string>
+#include "octave-event-observer.h"
+
 /**
   * \class octave_event
   * \brief Base class for an octave event.
@@ -25,15 +28,58 @@
 class octave_event
 {
   public:
-    octave_event ()
+    enum event_type
     {
+      exit_event,
+      change_directory_event
+    };
 
-    }
+    octave_event (const octave_event_observer& o)
+      : _octave_event_observer (o)
+    { }
 
     virtual ~octave_event ()
-    {
+    { }
+
+    virtual event_type get_event_type () const = 0;
+
+    void accept ()
+    { _octave_event_observer.event_accepted (this); }
+
+    void ignore ()
+    { _octave_event_observer.event_ignored (this); }
+
+  private:
+    const octave_event_observer& _octave_event_observer;
+};
+
+class octave_exit_event : public octave_event
+{
+  public:
+    octave_exit_event (const octave_event_observer& o)
+      : octave_event (o)
+    { }
 
-    }
+    event_type get_event_type () const
+    { return octave_event::exit_event; }
+};
+
+class octave_change_directory_event : public octave_event
+{
+  public:
+    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; }
+
+  private:
+    std::string _directory;
 };
 
 #endif // OCTAVEEVENT_H
--- a/gui/src/octave-adapter/octave-link.cc
+++ b/gui/src/octave-adapter/octave-link.cc
@@ -26,6 +26,7 @@
   octave_link::instance ()->trigger_update_history_model ();
   octave_link::instance ()->build_symbol_information ();
   octave_link::instance ()->update_current_working_directory ();
+  octave_link::instance ()->process_events ();
   return 0;
 }
 
@@ -53,6 +54,7 @@
     _workspace_model, SLOT (update_from_symbol_table ()));
 
   _symbol_information_semaphore = new QSemaphore (1);
+  _event_queue_semaphore = new QSemaphore (1);
   _current_working_directory = "";
 }
 
@@ -155,3 +157,61 @@
 {
   return _workspace_model;
 }
+
+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;
+        }
+    }
+  _event_queue_semaphore->release ();
+}
+
+void
+octave_link::post_event (octave_event *e)
+{
+  if (e)
+    {
+      _event_queue_semaphore->acquire ();
+      _event_queue.push_front (e);
+      _event_queue_semaphore->release ();
+    }
+}
+
+void
+octave_link::event_accepted (octave_event *e) const
+{ delete e; }
+
+void
+octave_link::event_ignored (octave_event *e) const
+{ delete e; }
+
+void
+octave_link::request_working_directory_change (std::string directory)
+{ post_event (new octave_change_directory_event (*this, directory)); }
+
+void
+octave_link::request_octave_exit ()
+{ post_event (new octave_exit_event (*this)); }
--- a/gui/src/octave-adapter/octave-link.h
+++ b/gui/src/octave-adapter/octave-link.h
@@ -72,10 +72,12 @@
 #include <QObject>
 #include <QStringListModel>
 #include <QTimer>
+#include <QQueue>
 
 #include "workspace-model.h"
 #include "octave-main-thread.h"
 #include "octave-event.h"
+#include "octave-event-observer.h"
 #include "symbol-information.h"
 
 /**
@@ -86,7 +88,7 @@
   * buffering access operations to octave and executing them in the readline
   * even hook, which lives in the octave thread.
   */
-class octave_link : public QObject
+class octave_link : public QObject, public octave_event_observer
 {
   Q_OBJECT
 public:
@@ -129,6 +131,15 @@
     */
   const QList <symbol_information>& get_symbol_information () const;
 
+  void process_events ();
+  void post_event (octave_event *e);
+  void event_accepted (octave_event *e) const;
+  void event_ignored (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);
@@ -154,6 +165,12 @@
   /** Semaphore to lock access to the symbol information. */
   QSemaphore *_symbol_information_semaphore;
 
+  /** Semaphore to lock access to the event queue. */
+  QSemaphore *_event_queue_semaphore;
+
+  /** Buffer for queueing events until they will be processed. */
+  QQueue <octave_event *> _event_queue;
+
   /** Stores the current symbol information. */
   QList <symbol_information> _symbol_information;
 
--- a/gui/src/src.pro
+++ b/gui/src/src.pro
@@ -107,7 +107,8 @@
     welcome-wizard.h \
     workspace-model.h \
     terminal-dockwidget.h \
-    octave-adapter/octave-event.h
+    octave-adapter/octave-event.h \
+    octave-adapter/octave-event-observer.h
 
 FORMS += \
     settings-dialog.ui \