GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
event-manager.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2011-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_event_manager_h)
27 #define octave_event_manager_h 1
28 
29 #include "octave-config.h"
30 
31 #include <functional>
32 #include <list>
33 #include <memory>
34 #include <string>
35 
36 #include "oct-mutex.h"
37 #include "octave.h"
38 #include "event-queue.h"
39 #include "uint8NDArray.h"
40 
41 class octave_value;
42 class string_vector;
43 
44 namespace octave
45 {
46  typedef std::function<void (void)> fcn_callback;
47  typedef std::function<void (octave::interpreter&)> meth_callback;
48 
49  class symbol_info_list;
50 
51  // The methods in this class provide a way to pass signals to the GUI
52  // thread. A GUI that wishes to act on these events should derive
53  // from this class and perform actions in a thread-safe way. In
54  // Octave's Qt-based GUI, for example, these functions are all
55  // implemented as wrappers around Qt signals that trigger actions in
56  // the GUI. The Qt signal/slot mechanism ensures that the actions are
57  // properly queued for execution when the objects corresponding to the
58  // signal and slot belong to different threads.
59  //
60  // These functions should not be called directly. Instead all
61  // requests from the interpreter for GUI actions should be done
62  // through the event_manager class. That class checks to ensure that
63  // the GUI is connected and enabled before calling these virtual
64  // functions.
65 
66  // FIXME: it would be nice if instead of requiring the GUI to derive
67  // from this class, it could subscribe to individual events, possibly
68  // multiple times. In that way, it would be more flexible and
69  // decentralized, similar to the Qt signal/slot connection mechanism
70  // and would allow the GUI to connect multiple signals to a single
71  // action or multiple actions to a single signal.
72 
73  // FIXME: audit this list of functions and determine whether they are
74  // all necessary and whether there might be better names for them.
75 
77  {
78  public:
79 
80  interpreter_events (void) = default;
81 
83 
85 
86  virtual ~interpreter_events (void) = default;
87 
88  // Dialogs.
89 
90  typedef std::list<std::pair<std::string, std::string>> filter_list;
91 
92  virtual std::list<std::string>
93  file_dialog (const filter_list& /*filter*/,
94  const std::string& /*title*/,
95  const std::string& /*filename*/,
96  const std::string& /*dirname*/,
97  const std::string& /*multimode*/)
98  {
99  return std::list<std::string> ();
100  }
101 
102  virtual std::list<std::string>
103  input_dialog (const std::list<std::string>& /*prompt*/,
104  const std::string& /*title*/,
105  const std::list<float>& /*nr*/,
106  const std::list<float>& /*nc*/,
107  const std::list<std::string>& /*defaults*/)
108  {
109  return std::list<std::string> ();
110  }
111 
112  virtual std::pair<std::list<int>, int>
113  list_dialog (const std::list<std::string>& /*list*/,
114  const std::string& /*mode*/, int /*width*/, int /*height*/,
115  const std::list<int>& /*initial_value*/,
116  const std::string& /*name*/,
117  const std::list<std::string>& /*prompt*/,
118  const std::string& /*ok_string*/,
119  const std::string& /*cancel_string*/)
120  {
121  return std::pair<std::list<int>, int> ();
122  }
123 
124  virtual std::string
125  question_dialog (const std::string& /*msg*/, const std::string& /*title*/,
126  const std::string& /*btn1*/, const std::string& /*btn2*/,
127  const std::string& /*btn3*/, const std::string& /*btndef*/)
128  {
129  return "";
130  }
131 
132  virtual void update_path_dialog (void) { }
133 
134  virtual void show_preferences (void) { }
135 
136  virtual void apply_preferences (void) { }
137 
138  virtual void show_doc (const std::string& /*file*/) { }
139 
140  virtual bool edit_file (const std::string& /*file*/) { return false; }
141 
142  virtual void
143  edit_variable (const std::string& /*name*/, const octave_value& /*val*/)
144  { }
145 
146  // Other requests for user interaction, usually some kind of
147  // confirmation before another action. Could these be reformulated
148  // using the question_dialog action?
149 
150  virtual bool confirm_shutdown (void) { return false; }
151 
152  virtual bool prompt_new_edit_file (const std::string& /*file*/)
153  {
154  return false;
155  }
156 
157  virtual int
158  debug_cd_or_addpath_error (const std::string& /*file*/,
159  const std::string& /*dir*/,
160  bool /*addpath_option*/)
161  {
162  return -1;
163  }
164 
165  // Requests for information normally stored in the GUI.
166 
167  virtual uint8NDArray get_named_icon (const std::string& /*icon_name*/)
168  {
169  return uint8NDArray ();
170  }
171 
172  virtual std::string gui_preference (const std::string& /*key*/,
173  const std::string& /*value*/)
174  {
175  return "";
176  }
177 
178  // Requests for GUI action that do not require user interaction.
179  // These are different from other notifications in that they are not
180  // associated with changes in the interpreter state (like a change
181  // in the current working directory or command history).
182 
183  virtual bool copy_image_to_clipboard (const std::string& /*file*/)
184  {
185  return false;
186  }
187 
188  virtual void focus_window (const std::string /*win_name*/)
189  { }
190 
191  virtual void
192  execute_command_in_terminal (const std::string& /*command*/) { }
193 
194  virtual void register_doc (const std::string& /*file*/) { }
195 
196  virtual void unregister_doc (const std::string& /*file*/) { }
197 
198  // Notifications of events in the interpreter that a GUI will
199  // normally wish to respond to.
200 
201  virtual void directory_changed (const std::string& /*dir*/) { }
202 
203  virtual void
204  file_remove (const std::string& /*old_nm*/, const std::string& /*new_nm*/)
205  { }
206 
207  virtual void file_renamed (bool) { }
208 
209  virtual void
210  set_workspace (bool /*top_level*/, bool /*debug*/,
211  const octave::symbol_info_list& /*syminfo*/,
212  bool /*update_variable_editor*/)
213  { }
214 
215  virtual void clear_workspace (void) { }
216 
217  virtual void set_history (const string_vector& /*hist*/) { }
218 
219  virtual void append_history (const std::string& /*hist_entry*/) { }
220 
221  virtual void clear_history (void) { }
222 
223  virtual void pre_input_event (void) { }
224 
225  virtual void post_input_event (void) { }
226 
227  virtual void
228  enter_debugger_event (const std::string& /*fcn_name*/,
229  const std::string& /*fcn_file_name*/,
230  int /*line*/)
231  { }
232 
233  virtual void
234  execute_in_debugger_event (const std::string& /*file*/, int /*line*/) { }
235 
236  virtual void exit_debugger_event (void) { }
237 
238  virtual void
239  update_breakpoint (bool /*insert*/, const std::string& /*file*/,
240  int /*line*/, const std::string& /*cond*/)
241  { }
242  };
243 
244  //! Provides threadsafe access to octave.
245  //!
246  //! This class provides thread-safe communication between the
247  //! interpreter and a GUI.
248 
250  {
251  public:
252 
253  event_manager (interpreter& interp);
254 
255  // No copying!
256 
257  event_manager (const event_manager&) = delete;
258 
260  operator = (const event_manager&) = delete;
261 
262  virtual ~event_manager (void);
263 
264  // OBJ should be an object of a class that is derived from the base
265  // class interpreter_events, or nullptr to disconnect and delete the
266  // previous link.
267 
268  void connect_link (const std::shared_ptr<interpreter_events>& obj);
269 
270  bool enable (void);
271 
272  bool disable (void)
273  {
274  bool retval = link_enabled;
275  link_enabled = false;
276  return retval;
277  }
278 
279  bool enabled (void) const
280  {
281  return link_enabled;
282  }
283 
284  // If disable is TRUE, then no additional events will be processed
285  // other than exit.
286 
287  void process_events (bool disable = false);
288 
289  void discard_events (void);
290 
291  // The post_event and post_exception functions provide a thread-safe
292  // way for the GUI to queue interpreter functions for execution.
293  // The queued functions are executed when the interpreter is
294  // otherwise idle.
295 
296  void post_event (const fcn_callback& fcn)
297  {
298  if (enabled ())
299  gui_event_queue.add (fcn);
300  }
301 
302  void post_event (const meth_callback& meth)
303  {
304  if (enabled ())
305  gui_event_queue.add (std::bind (meth, std::ref (m_interpreter)));
306  }
307 
308  // The following functions correspond to the virtual fuunctions in
309  // the interpreter_events class. They provide a way for the
310  // interpreter to notify the GUI that some event has occurred
311  // (directory or workspace changed, for example) or to request the
312  // GUI to perform some action (display a dialog, for example).
313 
314  // Please keep this list of declarations in the same order as the
315  // ones above in the interpreter_events class.
316 
317  typedef std::list<std::pair<std::string, std::string>> filter_list;
318 
319  std::list<std::string>
320  file_dialog (const filter_list& filter, const std::string& title,
321  const std::string& filename, const std::string& dirname,
322  const std::string& multimode)
323  {
324  return (enabled ()
325  ? instance->file_dialog (filter, title, filename, dirname,
326  multimode)
327  : std::list<std::string> ());
328  }
329 
330  std::list<std::string>
331  input_dialog (const std::list<std::string>& prompt,
332  const std::string& title,
333  const std::list<float>& nr,
334  const std::list<float>& nc,
335  const std::list<std::string>& defaults)
336  {
337  return (enabled ()
338  ? instance->input_dialog (prompt, title, nr, nc, defaults)
339  : std::list<std::string> ());
340  }
341 
342  std::pair<std::list<int>, int>
343  list_dialog (const std::list<std::string>& list,
344  const std::string& mode,
345  int width, int height,
346  const std::list<int>& initial_value,
347  const std::string& name,
348  const std::list<std::string>& prompt,
349  const std::string& ok_string,
350  const std::string& cancel_string)
351  {
352  return (enabled ()
353  ? instance->list_dialog (list, mode, width, height,
354  initial_value, name, prompt,
355  ok_string, cancel_string)
356  : std::pair<std::list<int>, int> ());
357  }
358 
359  std::string
360  question_dialog (const std::string& msg, const std::string& title,
361  const std::string& btn1, const std::string& btn2,
362  const std::string& btn3, const std::string& btndef)
363  {
364  return (enabled ()
365  ? instance->question_dialog (msg, title, btn1,
366  btn2, btn3, btndef)
367  : "");
368  }
369 
370  void update_path_dialog (void)
371  {
373  instance->update_path_dialog ();
374  }
375 
376  bool show_preferences (void)
377  {
378  if (enabled ())
379  {
380  instance->show_preferences ();
381  return true;
382  }
383  else
384  return false;
385  }
386 
387  bool apply_preferences (void)
388  {
389  if (enabled ())
390  {
391  instance->apply_preferences ();
392  return true;
393  }
394  else
395  return false;
396  }
397 
398  bool show_doc (const std::string& file)
399  {
400  if (enabled ())
401  {
402  instance->show_doc (file);
403  return true;
404  }
405  else
406  return false;
407  }
408 
409  bool edit_file (const std::string& file)
410  {
411  return enabled () ? instance->edit_file (file) : false;
412  }
413 
414  bool edit_variable (const std::string& name, const octave_value& val)
415  {
416  if (enabled ())
417  {
418  instance->edit_variable (name, val);
419  return true;
420  }
421  else
422  return false;
423  }
424 
425  bool confirm_shutdown (void)
426  {
427  bool retval = true;
428 
429  if (enabled ())
430  retval = instance->confirm_shutdown ();
431 
432  return retval;
433  }
434 
435  bool prompt_new_edit_file (const std::string& file)
436  {
437  return enabled () ? instance->prompt_new_edit_file (file) : false;
438  }
439 
440  int debug_cd_or_addpath_error (const std::string& file,
441  const std::string& dir, bool addpath_option)
442  {
443  return (enabled ()
444  ? instance->debug_cd_or_addpath_error (file, dir, addpath_option)
445  : 0);
446  }
447 
448  uint8NDArray get_named_icon (const std::string& icon_name)
449  {
450  return (enabled ()
451  ? instance->get_named_icon (icon_name) : uint8NDArray ());
452  }
453 
454  std::string gui_preference (const std::string& key,
455  const std::string& value)
456  {
457  return enabled () ? instance->gui_preference (key, value) : "";
458  }
459 
460  bool copy_image_to_clipboard (const std::string& file)
461  {
462  return enabled () ? instance->copy_image_to_clipboard (file) : false;
463  }
464 
465  virtual void focus_window (const std::string win_name)
466  {
467  if (enabled ())
468  instance->focus_window (win_name);
469  }
470 
471  // Preserves pending input.
472  void execute_command_in_terminal (const std::string& command)
473  {
474  if (enabled ())
475  instance->execute_command_in_terminal (command);
476  }
477 
478  bool register_doc (const std::string& file)
479  {
480  if (enabled ())
481  {
482  instance->register_doc (file);
483  return true;
484  }
485  else
486  return false;
487  }
488 
489  bool unregister_doc (const std::string& file)
490  {
491  if (enabled ())
492  {
493  instance->unregister_doc (file);
494  return true;
495  }
496  else
497  return false;
498 
499  }
500 
501  void directory_changed (const std::string& dir)
502  {
503  if (enabled ())
504  instance->directory_changed (dir);
505  }
506 
507  // Methods for removing/renaming files which might be open in editor
508  void file_remove (const std::string& old_name, const std::string& new_name)
509  {
511  instance->file_remove (old_name, new_name);
512  }
513 
514  void file_renamed (bool load_new)
515  {
517  instance->file_renamed (load_new);
518  }
519 
520  void set_workspace (void);
521 
522  void set_workspace (bool top_level, const octave::symbol_info_list& syminfo,
523  bool update_variable_editor = true)
524  {
525  if (enabled ())
526  instance->set_workspace (top_level, debugging, syminfo,
527  update_variable_editor);
528  }
529 
530  void clear_workspace (void)
531  {
532  if (enabled ())
533  instance->clear_workspace ();
534  }
535 
536  void set_history (const string_vector& hist)
537  {
538  if (enabled ())
539  instance->set_history (hist);
540  }
541 
542  void append_history (const std::string& hist_entry)
543  {
544  if (enabled ())
545  instance->append_history (hist_entry);
546  }
547 
548  void clear_history (void)
549  {
550  if (enabled ())
551  instance->clear_history ();
552  }
553 
554  void pre_input_event (void)
555  {
556  if (enabled ())
557  instance->pre_input_event ();
558  }
559 
560  void post_input_event (void)
561  {
562  if (enabled ())
563  instance->post_input_event ();
564  }
565 
566  void enter_debugger_event (const std::string& fcn_name,
567  const std::string& fcn_file_name, int line)
568  {
569  if (enabled ())
570  {
571  debugging = true;
572 
573  instance->enter_debugger_event (fcn_name, fcn_file_name, line);
574  }
575  }
576 
577  void execute_in_debugger_event (const std::string& file, int line)
578  {
579  if (enabled ())
580  instance->execute_in_debugger_event (file, line);
581  }
582 
584  {
585  if (enabled () && debugging)
586  {
587  debugging = false;
588 
589  instance->exit_debugger_event ();
590  }
591  }
592 
593  void update_breakpoint (bool insert, const std::string& file,
594  int line, const std::string& cond = "")
595  {
596  if (enabled ())
597  instance->update_breakpoint (insert, file, line, cond);
598  }
599 
600  private:
601 
603 
604  // Using a shared_ptr to manage the link_events object ensures that it
605  // will be valid until it is no longer needed.
606 
607  std::shared_ptr<interpreter_events> instance;
608 
609  protected:
610 
611  // Semaphore to lock access to the event queue.
613 
614  // Event Queue.
616 
617  bool debugging;
619  };
620 }
621 
622 #endif
void add(F &&fcn, Args &&... args)
static bool is_gui_running(void)
Definition: octave.h:303
Provides threadsafe access to octave.
void file_renamed(bool load_new)
std::string gui_preference(const std::string &key, const std::string &value)
std::list< std::pair< std::string, std::string > > filter_list
octave::event_queue gui_event_queue
void set_workspace(bool top_level, const octave::symbol_info_list &syminfo, bool update_variable_editor=true)
bool copy_image_to_clipboard(const std::string &file)
bool show_doc(const std::string &file)
std::list< std::string > file_dialog(const filter_list &filter, const std::string &title, const std::string &filename, const std::string &dirname, const std::string &multimode)
bool unregister_doc(const std::string &file)
void post_event(const fcn_callback &fcn)
int debug_cd_or_addpath_error(const std::string &file, const std::string &dir, bool addpath_option)
bool enabled(void) const
uint8NDArray get_named_icon(const std::string &icon_name)
event_manager(interpreter &interp)
event_manager & operator=(const event_manager &)=delete
virtual void focus_window(const std::string win_name)
bool edit_variable(const std::string &name, const octave_value &val)
void directory_changed(const std::string &dir)
bool show_preferences(void)
bool register_doc(const std::string &file)
void post_event(const meth_callback &meth)
bool prompt_new_edit_file(const std::string &file)
bool confirm_shutdown(void)
void post_input_event(void)
event_manager(const event_manager &)=delete
bool apply_preferences(void)
void exit_debugger_event(void)
void file_remove(const std::string &old_name, const std::string &new_name)
void enter_debugger_event(const std::string &fcn_name, const std::string &fcn_file_name, int line)
void set_history(const string_vector &hist)
std::pair< std::list< int >, int > list_dialog(const std::list< std::string > &list, const std::string &mode, int width, int height, const std::list< int > &initial_value, const std::string &name, const std::list< std::string > &prompt, const std::string &ok_string, const std::string &cancel_string)
void clear_workspace(void)
void update_path_dialog(void)
virtual ~event_manager(void)
void pre_input_event(void)
void execute_in_debugger_event(const std::string &file, int line)
std::string question_dialog(const std::string &msg, const std::string &title, const std::string &btn1, const std::string &btn2, const std::string &btn3, const std::string &btndef)
interpreter & m_interpreter
void execute_command_in_terminal(const std::string &command)
void connect_link(const std::shared_ptr< interpreter_events > &obj)
void update_breakpoint(bool insert, const std::string &file, int line, const std::string &cond="")
octave::mutex * event_queue_mutex
std::list< std::string > input_dialog(const std::list< std::string > &prompt, const std::string &title, const std::list< float > &nr, const std::list< float > &nc, const std::list< std::string > &defaults)
bool edit_file(const std::string &file)
void append_history(const std::string &hist_entry)
std::shared_ptr< interpreter_events > instance
void process_events(bool disable=false)
virtual void clear_history(void)
virtual std::string gui_preference(const std::string &, const std::string &)
virtual void enter_debugger_event(const std::string &, const std::string &, int)
virtual void register_doc(const std::string &)
virtual void directory_changed(const std::string &)
virtual void exit_debugger_event(void)
virtual std::string question_dialog(const std::string &, const std::string &, const std::string &, const std::string &, const std::string &, const std::string &)
virtual void focus_window(const std::string)
std::list< std::pair< std::string, std::string > > filter_list
Definition: event-manager.h:90
virtual bool prompt_new_edit_file(const std::string &)
virtual void update_breakpoint(bool, const std::string &, int, const std::string &)
interpreter_events(const interpreter_events &)=default
virtual void execute_command_in_terminal(const std::string &)
virtual bool copy_image_to_clipboard(const std::string &)
virtual void set_workspace(bool, bool, const octave::symbol_info_list &, bool)
virtual void file_remove(const std::string &, const std::string &)
virtual void edit_variable(const std::string &, const octave_value &)
virtual std::pair< std::list< int >, int > list_dialog(const std::list< std::string > &, const std::string &, int, int, const std::list< int > &, const std::string &, const std::list< std::string > &, const std::string &, const std::string &)
virtual void unregister_doc(const std::string &)
virtual std::list< std::string > input_dialog(const std::list< std::string > &, const std::string &, const std::list< float > &, const std::list< float > &, const std::list< std::string > &)
virtual ~interpreter_events(void)=default
virtual bool edit_file(const std::string &)
interpreter_events(void)=default
virtual void post_input_event(void)
virtual void set_history(const string_vector &)
virtual void update_path_dialog(void)
virtual void execute_in_debugger_event(const std::string &, int)
virtual void file_renamed(bool)
virtual uint8NDArray get_named_icon(const std::string &)
virtual void append_history(const std::string &)
virtual bool confirm_shutdown(void)
interpreter_events & operator=(const interpreter_events &)=default
virtual int debug_cd_or_addpath_error(const std::string &, const std::string &, bool)
virtual void clear_workspace(void)
virtual void apply_preferences(void)
virtual void pre_input_event(void)
virtual std::list< std::string > file_dialog(const filter_list &, const std::string &, const std::string &, const std::string &, const std::string &)
Definition: event-manager.h:93
virtual void show_doc(const std::string &)
virtual void show_preferences(void)
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition: filter.cc:46
QString name
std::string dirname(const std::string &path)
Definition: file-ops.cc:363
std::function< void(octave::interpreter &)> meth_callback
Definition: event-manager.h:47
std::function< void(void)> fcn_callback
Definition: event-manager.h:46
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
intNDArray< octave_uint8 > uint8NDArray
Definition: uint8NDArray.h:36