GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
qt-interpreter-events.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2011-2023 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 (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <iostream>
31 #include <sstream>
32 
33 #include <QDialog>
34 #include <QDir>
35 #include <QIcon>
36 #include <QMetaType>
37 #include <QPushButton>
38 #include <QStringList>
39 
40 #include "dialog.h"
41 #include "gui-preferences-ed.h"
42 #include "octave-qobject.h"
43 #include "qt-interpreter-events.h"
44 #include "qt-utils.h"
45 
46 #include "localcharset-wrapper.h"
47 #include "oct-env.h"
48 #include "str-vec.h"
49 
50 #include "builtin-defun-decls.h"
51 #include "error.h"
52 #include "interpreter-private.h"
53 #include "load-path.h"
54 #include "oct-map.h"
55 #include "octave.h"
56 #include "ov.h"
57 #include "syminfo.h"
58 #include "utils.h"
59 
60 Q_DECLARE_METATYPE (octave_value)
61 Q_DECLARE_METATYPE (octave::symbol_info_list)
62 Q_DECLARE_METATYPE (octave::fcn_callback)
63 Q_DECLARE_METATYPE (octave::meth_callback)
64 
66 
67 static QStringList
68 make_qstring_list (const std::list<std::string>& lst)
69 {
70  QStringList retval;
71 
72  for (const auto& s : lst)
73  retval.append (QString::fromStdString (s));
74 
75  return retval;
76 }
77 
78 static QStringList
80 {
81  QStringList retval;
82 
83  // We have pairs of data, first being the list of extensions
84  // exta;exb;extc etc second the name to use as filter name
85  // (optional). Qt wants a list of filters in the format of
86  // 'FilterName (space separated exts)'.
87 
88  for (const auto& ext_name : lst)
89  {
90  QString ext = QString::fromStdString (ext_name.first);
91  QString name = QString::fromStdString (ext_name.second);
92 
93  // Strip out extensions from name and replace ';' with spaces in list.
94 
95  name.replace (QRegExp (R"(\‍(.*\))"), "");
96  ext.replace (";", " ");
97 
98  if (name.isEmpty ())
99  {
100  // No name field. Build one from the extensions.
101  name = ext.toUpper () + " Files";
102  }
103 
104  retval.append (name + " (" + ext + ')');
105  }
106 
107  return retval;
108 }
109 
111  : interpreter_events (), m_octave_qobj (oct_qobj),
112  m_uiwidget_creator (oct_qobj), m_result (), m_mutex (),
113  m_waitcondition ()
114 {
115  qRegisterMetaType<QIntList> ("QIntList");
116  qRegisterMetaType<QFloatList> ("QFloatList");
117 
118  qRegisterMetaType<octave_value> ("octave_value");
119  qRegisterMetaType<symbol_info_list> ("symbol_info_list");
120 
121  qRegisterMetaType<fcn_callback> ("fcn_callback");
122  qRegisterMetaType<meth_callback> ("meth_callback");
123 
126 
129 
132 }
133 
135 {
137  emit start_gui_signal (gui_app);
138 }
139 
141 {
143  emit close_gui_signal ();
144 }
145 
146 std::list<std::string>
148  const std::string& title,
149  const std::string& filename,
150  const std::string& dirname,
151  const std::string& multimode)
152 {
153  QStringList lst
155  QString::fromStdString (title),
156  QString::fromStdString (filename),
158  QString::fromStdString (multimode));
159 
160  std::list<std::string> retval;
161 
162  for (const auto& s : lst)
163  retval.push_back (s.toStdString ());
164 
165  return retval;
166 }
167 
168 std::list<std::string>
169 qt_interpreter_events::input_dialog (const std::list<std::string>& prompt,
170  const std::string& title,
171  const std::list<float>& nr,
172  const std::list<float>& nc,
173  const std::list<std::string>& defaults)
174 {
175  QStringList lst
177  QString::fromStdString (title),
178  std_list_to_qt_list<float> (nr),
179  std_list_to_qt_list<float> (nc),
180  make_qstring_list (defaults));
181  std::list<std::string> retval;
182 
183  for (const auto& s : lst)
184  retval.push_back (s.toStdString ());
185 
186  return retval;
187 }
188 
189 std::pair<std::list<int>, int>
190 qt_interpreter_events::list_dialog (const std::list<std::string>& list,
191  const std::string& mode,
192  int width, int height,
193  const std::list<int>& initial,
194  const std::string& name,
195  const std::list<std::string>& prompt,
196  const std::string& ok_string,
197  const std::string& cancel_string)
198 {
199  QPair<QIntList, int> result
201  QString::fromStdString (mode),
202  width, height,
203  std_list_to_qt_list<int> (initial),
204  QString::fromStdString (name),
205  make_qstring_list (prompt),
206  QString::fromStdString (ok_string),
207  QString::fromStdString (cancel_string));
208 
209  QIntList& lst = result.first;
210  return std::pair<std::list<int>, int> (std::list<int> (lst.begin (),
211  lst.end ()),
212  result.second);
213 }
214 
215 std::string
217  const std::string& title,
218  const std::string& btn1,
219  const std::string& btn2,
220  const std::string& btn3,
221  const std::string& btndef)
222 {
223  QString icon = "quest";
224  QStringList buttons;
225  QStringList role;
226 
227  // Must use ResetRole which is left-aligned for all OS and WM.
228  role << "ResetRole" << "ResetRole" << "ResetRole";
229 
230  buttons << QString::fromStdString (btn1);
231  if (btn2 == "")
232  role.removeAt (0);
233  else
234  buttons << QString::fromStdString (btn2);
235  buttons << QString::fromStdString (btn3);
236 
237  QString answer
239  QString::fromStdString (title),
240  icon, buttons,
241  QString::fromStdString (btndef),
242  role);
243 
244  return answer.toStdString ();
245 }
246 
248 {
250 }
251 
253 {
254  emit show_preferences_signal ();
255 }
256 
258 {
259  emit apply_new_settings ();
260 }
261 
263 {
265 }
266 
267 bool qt_interpreter_events::show_documentation (const std::string& file)
268 {
270 
271  return true;
272 }
273 
275 {
276  emit show_file_browser_signal ();
277 }
278 
280 {
282 }
283 
285 {
286  emit show_workspace_signal ();
287 }
288 
290 {
291  emit show_community_news_signal (serial);
292 }
293 
295 {
297 }
298 
299 bool qt_interpreter_events::edit_file (const std::string& file)
300 {
302 
303  return true;
304 }
305 
306 void qt_interpreter_events::edit_variable (const std::string& expr,
307  const octave_value& val)
308 {
309  emit edit_variable_signal (QString::fromStdString (expr), val);
310 }
311 
313 {
314  QMutexLocker autolock (&m_mutex);
315 
316  emit confirm_shutdown_signal ();
317 
318  // Wait for result.
319  wait ();
320 
321  return m_result.toBool ();
322 }
323 
324 bool qt_interpreter_events::prompt_new_edit_file (const std::string& file)
325 {
328 
329  if (! settings || settings->value (ed_create_new_file).toBool ())
330  return true;
331 
332  std::string abs_fname = sys::env::make_absolute (file);
333 
334  QStringList btn;
335  QStringList role;
336  role << "YesRole" << "RejectRole";
337  btn << tr ("Create") << tr ("Cancel");
338 
339  QString answer = m_uiwidget_creator.message_dialog
340  (tr ("File\n%1\ndoes not exist. Do you want to create it?").
341  arg (QString::fromStdString (abs_fname)),
342  tr ("Octave Editor"), "quest", btn, tr ("Create"), role);
343 
344  return (answer == tr ("Create"));
345 }
346 
347 // Prompt to allow file to be run by setting cwd (or if
348 // addpath_option==true, alternatively setting the path).
349 
350 int
352  const std::string& dir,
353  bool addpath_option)
354 {
355  int retval = -1;
356 
357  QString qdir = QString::fromStdString (dir);
358  QString qfile = QString::fromStdString (file);
359  QString msg
360  = (addpath_option
361  ? tr ("The file %1 does not exist in the load path. To run or debug the function you are editing, you must either change to the directory %2 or add that directory to the load path.").arg (qfile).arg (qdir)
362  : tr ("The file %1 is shadowed by a file with the same name in the load path. To run or debug the function you are editing, change to the directory %2.").arg (qfile).arg (qdir));
363 
364  QString title = tr ("Change Directory or Add Directory to Load Path");
365 
366  QString cd_txt = tr ("&Change Directory");
367  QString addpath_txt = tr ("&Add Directory to Load Path");
368  QString cancel_txt = tr ("Cancel");
369 
370  QStringList btn;
371  QStringList role;
372  btn << cd_txt;
373  role << "YesRole";
374  if (addpath_option)
375  {
376  btn << addpath_txt;
377  role << "AcceptRole";
378  }
379  btn << cancel_txt;
380  role << "RejectRole";
381 
382  QString result
383  = m_uiwidget_creator.message_dialog (msg, title, "quest", btn,
384  cancel_txt, role);
385 
386  if (result == cd_txt)
387  retval = 1;
388  else if (result == addpath_txt)
389  retval = 2;
390 
391  return retval;
392 }
393 
395 {
396  QMutexLocker autolock (&m_mutex);
397 
399 
400  // Wait for result.
401  wait ();
402 
403  uint8NDArray empty_img;
404 
405  QIcon icon = m_result.value<QIcon> ();
406 
407  if (icon.isNull ())
408  return empty_img;
409 
410  QImage img = icon.pixmap (QSize (32, 32)).toImage ();
411 
412  if (img.format () != QImage::Format_ARGB32_Premultiplied)
413  return empty_img;
414 
415  dim_vector dims (img.height (), img.width (), 4);
416 
417  uint8NDArray retval (dims, 0);
418 
419  uint8_t *bits = img.bits ();
420 
421  for (int i = 0; i < img.height (); i++)
422  {
423  for (int j = 0; j < img.width (); j++)
424  {
425  retval(i, j, 2) = bits[0];
426  retval(i, j, 1) = bits[1];
427  retval(i, j, 0) = bits[2];
428  retval(i, j, 3) = bits[3];
429 
430  bits += 4;
431  }
432  }
433 
434  return retval;
435 }
436 
438 {
439  QMutexLocker autolock (&m_mutex);
440 
442  m_result = QVariant::fromValue (rmgr.icon (name));
443 
444  wake_all ();
445 }
446 
447 std::string
449  const std::string& value)
450 {
451  QString pref_value;
452 
453  QMutexLocker autolock (&m_mutex);
454 
455  // Emit the signal for changing or getting a preference
457  QString::fromStdString (value));
458 
459  // Wait for response (pref_value).
460  wait ();
461 
462  QString pref = m_result.toString ();
463 
464  return pref.toStdString ();
465 }
466 
468 {
470 
471  return true;
472 }
473 
474 void qt_interpreter_events::focus_window (const std::string win_name)
475 {
477 }
478 
480 (const std::string& command)
481 {
483 }
484 
485 void qt_interpreter_events::register_documentation (const std::string& file)
486 {
488 }
489 
491 {
493 }
494 
495 void qt_interpreter_events::interpreter_output (const std::string& msg)
496 {
500  else
501  {
502  // FIXME: is this the correct thing to do?
503  std::cout << msg;
504  }
505 }
506 
508  bool beep)
509 {
512  {
513  // Output the exception message
514  std::ostringstream buf;
515  ee.display (buf);
517  // Create w new command line
518  emit new_command_line_signal ();
519  }
520  else
521  {
522  if (beep)
523  std::cerr << "\a";
524 
525  ee.display (std::cerr);
526  }
527 }
528 
529 void qt_interpreter_events::gui_status_update (const std::string& feature,
530  const std::string& status)
531 {
533  QString::fromStdString (status));
534 }
535 
537 {
538  emit update_gui_lexer_signal (true);
539 }
540 
541 void qt_interpreter_events::directory_changed (const std::string& dir)
542 {
544 }
545 
546 void qt_interpreter_events::file_remove (const std::string& old_name,
547  const std::string& new_name)
548 {
549  QMutexLocker autolock (&m_mutex);
550 
551  // Emit the signal for the editor for closing the file if it is open
553  QString::fromStdString (new_name));
554 
555  // Wait for file removal to complete before continuing.
556  wait ();
557 }
558 
560 {
561  emit file_renamed_signal (load_new);
562 }
563 
564 void qt_interpreter_events::set_workspace (bool top_level, bool debug,
565  const symbol_info_list& syminfo,
566  bool update_variable_editor)
567 {
568  if (! top_level && ! debug)
569  return;
570 
571  emit set_workspace_signal (top_level, debug, syminfo);
572 
573  if (update_variable_editor)
575 }
576 
578 {
579  emit clear_workspace_signal ();
580 }
581 
582 void qt_interpreter_events::update_prompt (const std::string& prompt)
583 {
585 }
586 
588 {
589  QStringList qt_hist;
590 
591  for (octave_idx_type i = 0; i < hist.numel (); i++)
592  qt_hist.append (QString::fromStdString (hist[i]));
593 
594  emit set_history_signal (qt_hist);
595 }
596 
597 void qt_interpreter_events::append_history (const std::string& hist_entry)
598 {
599  emit append_history_signal (QString::fromStdString (hist_entry));
600 }
601 
603 {
604  emit clear_history_signal ();
605 }
606 
608 { }
609 
611 { }
612 
613 void qt_interpreter_events::enter_debugger_event (const std::string& /*fcn_name*/,
614  const std::string& fcn_file_name,
615  int line)
616 {
617  if (fcn_file_name.empty ())
618  return;
619 
620  insert_debugger_pointer (fcn_file_name, line);
621 
622  emit enter_debugger_signal ();
623 }
624 
625 void
627  int line)
628 {
629  delete_debugger_pointer (file, line);
630 }
631 
633 {
634  emit exit_debugger_signal ();
635 }
636 
637 // Display (if @insert true) or remove the appropriate symbol for a breakpoint
638 // in @file at @line with condition @cond.
640  const std::string& file,
641  int line,
642  const std::string& cond)
643 {
645  line, QString::fromStdString (cond));
646 }
647 
648 void
649 qt_interpreter_events::insert_debugger_pointer (const std::string& file,
650  int line)
651 {
653 }
654 
655 void
656 qt_interpreter_events::delete_debugger_pointer (const std::string& file,
657  int line)
658 {
660 }
661 
662 void
664 {
665  QMutexLocker autolock (&m_mutex);
666 
668 
669  wake_all ();
670 }
671 
672 // If VALUE is empty, return current value of preference named by KEY.
673 //
674 // If VALUE is not empty, set preference named by KEY to VALUE return
675 // previous value.
676 //
677 // FIXME: should we have separate get and set functions? With only
678 // one, we don't allow a preference value to be set to the empty
679 // string.
680 
681 void
683  const QString& value)
684 {
685  QMutexLocker autolock (&m_mutex);
686 
689 
690  QString read_value = settings->value (key).toString ();
691 
692  // Some preferences need extra handling
693  QString adjusted_value = gui_preference_adjust (key, value);
694 
695  if (! adjusted_value.isEmpty () && (read_value != adjusted_value))
696  {
697  // Change settings only for new, non-empty values
698  settings->setValue (key, QVariant (adjusted_value));
699 
700  emit settings_changed (settings, true); // true: changed by worker
701  }
702 
704 
705  wake_all ();
706 }
707 
708 QString
710  const QString& value)
711 {
712  // Immediately return if no new value is given.
713 
714  if (value.isEmpty ())
715  return value;
716 
717  QString adjusted_value = value;
718 
719  // Not all encodings are available. Encodings are uppercase and do
720  // not use CPxxx but IBMxxx or WINDOWS-xxx.
721 
722  if (key == ed_default_enc.key)
723  {
724  adjusted_value = adjusted_value.toUpper ();
725 
726  QStringList codecs;
728  rmgr.get_codecs (&codecs);
729 
730  QRegExp re ("^CP(\\d+)$");
731 
732  if (adjusted_value == "SYSTEM")
733  adjusted_value =
734  QString ("SYSTEM (") +
735  QString (octave_locale_charset_wrapper ()).toUpper () +
736  QString (")");
737  else if (re.indexIn (adjusted_value) > -1)
738  {
739  if (codecs.contains ("IBM" + re.cap (1)))
740  adjusted_value = "IBM" + re.cap (1);
741  else if (codecs.contains ("WINDOWS-" + re.cap (1)))
742  adjusted_value = "WINDOWS-" + re.cap (1);
743  else
744  adjusted_value.clear ();
745  }
746  else if (! codecs.contains (adjusted_value))
747  adjusted_value.clear ();
748  }
749 
750  return adjusted_value;
751 }
752 
OCTAVE_END_NAMESPACE(octave)
QString message_dialog(const QString &message, const QString &title, const QString &icon, const QStringList &button, const QString &defbutton, const QStringList &role)
Definition: dialog.cc:74
QPair< QIntList, int > list_dialog(const QStringList &list, const QString &mode, int wd, int ht, const QList< int > &initial, const QString &name, const QStringList &prompt, const QString &ok_string, const QString &cancel_string)
Definition: dialog.cc:107
QStringList input_dialog(const QStringList &prompt, const QString &title, const QFloatList &nr, const QFloatList &nc, const QStringList &defaults)
Definition: dialog.cc:132
QStringList file_dialog(const QStringList &filters, const QString &title, const QString &filename, const QString &dirname, const QString &multimode)
Definition: dialog.cc:152
Base class for Octave interfaces that use Qt.
virtual bool confirm_shutdown(void)
bool experimental_terminal_widget(void) const
resource_manager & get_resource_manager(void)
bool have_terminal_window(void) const
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
std::list< std::pair< std::string, std::string > > filter_list
std::list< std::pair< std::string, std::string > > filter_list
void edit_file_signal(const QString &file)
void focus_window_signal(const QString &win_name)
bool edit_file(const std::string &file)
void confirm_shutdown_signal(void)
bool copy_image_to_clipboard(const std::string &file)
void interpreter_output(const std::string &msg)
void gui_status_update(const std::string &feature, const std::string &status)
void enter_debugger_signal(void)
void show_file_browser_signal(void)
void close_gui_signal(void)
void focus_window(const std::string win_name)
uint8NDArray get_named_icon(const std::string &icon_name)
void confirm_shutdown_octave(void)
void update_prompt(const std::string &prompt)
void update_breakpoint(bool insert, const std::string &file, int line, const std::string &cond)
void set_workspace(bool top_level, bool debug, const symbol_info_list &syminfo, bool update_variable_editor)
void unregister_documentation_signal(const QString &file)
void update_breakpoint_marker_signal(bool insert, const QString &file, int line, const QString &cond)
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 enter_debugger_event(const std::string &fcn_name, const std::string &fcn_file_name, int line)
std::list< std::string > file_dialog(const filter_list &filter, const std::string &title, const std::string &filename, const std::string &pathname, const std::string &multimode)
void file_remove(const std::string &old_name, const std::string &new_name)
void insert_debugger_pointer_signal(const QString &, int)
int debug_cd_or_addpath_error(const std::string &file, const std::string &dir, bool addpath_option)
void gui_preference_signal(const QString &key, const QString &value)
void set_workspace_signal(bool top_level, bool debug, const symbol_info_list &syminfo)
bool prompt_new_edit_file(const std::string &file)
std::string gui_preference(const std::string &key, const std::string &value)
void append_history(const std::string &hist_entry)
void delete_debugger_pointer(const std::string &file, int line)
qt_interpreter_events(base_qobject &oct_qobj)
void interpreter_output_signal(const QString &msg)
void edit_variable(const std::string &name, const octave_value &val)
void unregister_documentation(const std::string &file)
void directory_changed_signal(const QString &dir)
void file_remove_signal(const QString &old_name, const QString &new_name)
void directory_changed(const std::string &dir)
void apply_new_settings(void)
void register_documentation_signal(const QString &file)
void clear_workspace_signal(void)
void set_history_signal(const QStringList &hist)
void insert_debugger_pointer(const std::string &file, int line)
void copy_image_to_clipboard_signal(const QString &file, bool remove_file)
void execute_command_in_terminal_signal(const QString &command)
void new_command_line_signal(const QString &msg=QString())
void register_documentation(const std::string &file)
void append_history_signal(const QString &hist_entry)
void get_named_icon_slot(const QString &name)
void edit_variable_signal(const QString &name, const octave_value &val)
void show_terminal_window_signal(void)
void settings_changed(const gui_settings *, bool)
void file_renamed(bool load_new=true)
void file_renamed_signal(bool load_new)
void get_named_icon_signal(const QString &name)
void show_command_history_signal(void)
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)
void start_gui(bool gui_app=false)
QString gui_preference_adjust(const QString &key, const QString &value)
void clear_history_signal(void)
void gui_preference_slot(const QString &key, const QString &value)
void show_preferences_signal(void)
void display_exception(const execution_exception &ee, bool beep)
void refresh_variable_editor_signal(void)
QUIWidgetCreator m_uiwidget_creator
void update_prompt_signal(const QString &prompt)
bool show_documentation(const std::string &file)
void show_release_notes_signal(void)
void show_community_news_signal(int serial)
void show_workspace_signal(void)
void set_history(const string_vector &hist)
void execute_command_in_terminal(const std::string &command)
void start_gui_signal(bool gui_app)
void exit_debugger_signal(void)
void show_documentation_signal(const QString &file)
void execute_in_debugger_event(const std::string &file, int line)
void gui_status_update_signal(const QString &feature, const QString &status)
void delete_debugger_pointer_signal(const QString &, int)
void update_gui_lexer_signal(bool update_apis_only)
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)
void show_community_news(int serial)
void update_path_dialog_signal(void)
gui_settings * get_settings(void) const
void get_codecs(QStringList *codecs)
QIcon icon(const QString &icon_name, bool octave_only=false, const QString &icon_alt_name=QString())
octave_idx_type numel(void) const
Definition: str-vec.h:100
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
QList< int > QIntList
Definition: dialog.h:40
std::function< void(void)> fcn_callback
Definition: event-manager.h:43
std::function< void(interpreter &)> meth_callback
Definition: event-manager.h:48
std::string dirname(const std::string &path)
Definition: file-ops.cc:360
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition: filter.cc:48
const gui_pref ed_create_new_file("editor/create_new_file", QVariant(false))
const gui_pref ed_default_enc("editor/default_encoding", QVariant("UTF-8"))
T read_value(std::istream &is)
Definition: lo-utils.cc:183
const char * octave_locale_charset_wrapper(void)
QString fromStdString(const std::string &s)
static QStringList make_qstring_list(const std::list< std::string > &lst)
static QStringList make_filter_list(const event_manager::filter_list &lst)
const QString key
static string_vector make_absolute(const string_vector &sv)
Definition: utils.cc:536