GNU Octave  6.2.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-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 (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <QDialog>
31 #include <QDir>
32 #include <QIcon>
33 #include <QMetaType>
34 #include <QPushButton>
35 #include <QStringList>
36 
37 #include "dialog.h"
38 #include "gui-preferences-ed.h"
39 #include "octave-qobject.h"
40 #include "qt-interpreter-events.h"
41 #include "qt-utils.h"
42 
43 #include "localcharset-wrapper.h"
44 #include "oct-env.h"
45 #include "str-vec.h"
46 
47 #include "builtin-defun-decls.h"
48 #include "error.h"
49 #include "interpreter-private.h"
50 #include "load-path.h"
51 #include "oct-map.h"
52 #include "octave.h"
53 #include "ov.h"
54 #include "syminfo.h"
55 #include "utils.h"
56 
57 Q_DECLARE_METATYPE (octave_value)
58 Q_DECLARE_METATYPE (octave::symbol_info_list)
59 Q_DECLARE_METATYPE (octave::fcn_callback)
60 Q_DECLARE_METATYPE (octave::meth_callback)
61 
62 namespace octave
63 {
64  static QStringList
65  make_qstring_list (const std::list<std::string>& lst)
66  {
67  QStringList retval;
68 
69  for (const auto& s : lst)
70  retval.append (QString::fromStdString (s));
71 
72  return retval;
73  }
74 
75  static QStringList
76  make_filter_list (const event_manager::filter_list& lst)
77  {
78  QStringList retval;
79 
80  // We have pairs of data, first being the list of extensions
81  // exta;exb;extc etc second the name to use as filter name
82  // (optional). Qt wants a list of filters in the format of
83  // 'FilterName (space separated exts)'.
84 
85  for (const auto& ext_name : lst)
86  {
87  QString ext = QString::fromStdString (ext_name.first);
88  QString name = QString::fromStdString (ext_name.second);
89 
90  // Strip out extensions from name and replace ';' with spaces in list.
91 
92  name.replace (QRegExp (R"(\‍(.*\))"), "");
93  ext.replace (";", " ");
94 
95  if (name.isEmpty ())
96  {
97  // No name field. Build one from the extensions.
98  name = ext.toUpper () + " Files";
99  }
100 
101  retval.append (name + " (" + ext + ')');
102  }
103 
104  return retval;
105  }
106 
107  qt_interpreter_events::qt_interpreter_events (base_qobject& oct_qobj)
108  : interpreter_events (), m_octave_qobj (oct_qobj),
109  m_uiwidget_creator (oct_qobj), m_result (), m_mutex (),
110  m_waitcondition ()
111  {
112  qRegisterMetaType<QIntList> ("QIntList");
113  qRegisterMetaType<QFloatList> ("QFloatList");
114 
115  qRegisterMetaType<octave_value> ("octave_value");
116  qRegisterMetaType<symbol_info_list> ("symbol_info_list");
117 
118  qRegisterMetaType<fcn_callback> ("fcn_callback");
119  qRegisterMetaType<meth_callback> ("meth_callback");
120 
121  connect (this, SIGNAL (confirm_shutdown_signal (void)),
122  this, SLOT (confirm_shutdown_octave (void)));
123 
124  connect (this, SIGNAL (get_named_icon_signal (const QString&)),
125  this, SLOT (get_named_icon_slot (const QString&)));
126 
127  connect (this,
128  SIGNAL (gui_preference_signal (const QString&, const QString&)),
129  this,
130  SLOT (gui_preference_slot (const QString&, const QString&)));
131  }
132 
133  std::list<std::string>
134  qt_interpreter_events::file_dialog (const filter_list& filter,
135  const std::string& title,
136  const std::string& filename,
137  const std::string& dirname,
138  const std::string& multimode)
139  {
140  QStringList lst
141  = m_uiwidget_creator.file_dialog (make_filter_list (filter),
142  QString::fromStdString (title),
143  QString::fromStdString (filename),
145  QString::fromStdString (multimode));
146 
147  std::list<std::string> retval;
148 
149  for (const auto& s : lst)
150  retval.push_back (s.toStdString ());
151 
152  return retval;
153  }
154 
155  std::list<std::string>
156  qt_interpreter_events::input_dialog (const std::list<std::string>& prompt,
157  const std::string& title,
158  const std::list<float>& nr,
159  const std::list<float>& nc,
160  const std::list<std::string>& defaults)
161  {
162  QStringList lst
163  = m_uiwidget_creator.input_dialog (make_qstring_list (prompt),
164  QString::fromStdString (title),
165  std_list_to_qt_list<float> (nr),
166  std_list_to_qt_list<float> (nc),
167  make_qstring_list (defaults));
168  std::list<std::string> retval;
169 
170  for (const auto& s : lst)
171  retval.push_back (s.toStdString ());
172 
173  return retval;
174  }
175 
176  std::pair<std::list<int>, int>
177  qt_interpreter_events::list_dialog (const std::list<std::string>& list,
178  const std::string& mode,
179  int width, int height,
180  const std::list<int>& initial,
181  const std::string& name,
182  const std::list<std::string>& prompt,
183  const std::string& ok_string,
184  const std::string& cancel_string)
185  {
186  QPair<QIntList, int> result
187  = m_uiwidget_creator.list_dialog (make_qstring_list (list),
188  QString::fromStdString (mode),
189  width, height,
190  std_list_to_qt_list<int> (initial),
192  make_qstring_list (prompt),
193  QString::fromStdString (ok_string),
194  QString::fromStdString (cancel_string));
195 
196  QIntList& lst = result.first;
197  return std::pair<std::list<int>, int> (std::list<int> (lst.begin (),
198  lst.end ()),
199  result.second);
200  }
201 
202  std::string
203  qt_interpreter_events::question_dialog (const std::string& msg,
204  const std::string& title,
205  const std::string& btn1,
206  const std::string& btn2,
207  const std::string& btn3,
208  const std::string& btndef)
209  {
210  QString icon = "quest";
211  QStringList buttons;
212  QStringList role;
213 
214  // Must use ResetRole which is left-aligned for all OS and WM.
215  role << "ResetRole" << "ResetRole" << "ResetRole";
216 
217  buttons << QString::fromStdString (btn1);
218  if (btn2 == "")
219  role.removeAt (0);
220  else
221  buttons << QString::fromStdString (btn2);
222  buttons << QString::fromStdString (btn3);
223 
224  QString answer
225  = m_uiwidget_creator.message_dialog (QString::fromStdString (msg),
226  QString::fromStdString (title),
227  icon, buttons,
228  QString::fromStdString (btndef),
229  role);
230 
231  return answer.toStdString ();
232  }
233 
234  void qt_interpreter_events::update_path_dialog (void)
235  {
236  emit update_path_dialog_signal ();
237  }
238 
239  void qt_interpreter_events::show_preferences (void)
240  {
241  emit show_preferences_signal ();
242  }
243 
244  void qt_interpreter_events::apply_preferences (void)
245  {
246  emit apply_new_settings ();
247  }
248 
249  void qt_interpreter_events::show_doc (const std::string& file)
250  {
251  emit show_doc_signal (QString::fromStdString (file));
252  }
253 
254  bool qt_interpreter_events::edit_file (const std::string& file)
255  {
256  emit edit_file_signal (QString::fromStdString (file));
257 
258  return true;
259  }
260 
261  void qt_interpreter_events::edit_variable (const std::string& expr,
262  const octave_value& val)
263  {
264  emit edit_variable_signal (QString::fromStdString (expr), val);
265  }
266 
267  bool qt_interpreter_events::confirm_shutdown (void)
268  {
269  QMutexLocker autolock (&m_mutex);
270 
271  emit confirm_shutdown_signal ();
272 
273  // Wait for result.
274  wait ();
275 
276  return m_result.toBool ();
277  }
278 
279  bool qt_interpreter_events::prompt_new_edit_file (const std::string& file)
280  {
281  resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
282  gui_settings *settings = rmgr.get_settings ();
283 
284  if (! settings || settings->value (ed_create_new_file).toBool ())
285  return true;
286 
287  std::string abs_fname = sys::env::make_absolute (file);
288 
289  QStringList btn;
290  QStringList role;
291  role << "YesRole" << "RejectRole";
292  btn << tr ("Create") << tr ("Cancel");
293 
294  QString answer = m_uiwidget_creator.message_dialog
295  (tr ("File\n%1\ndoes not exist. Do you want to create it?").
296  arg (QString::fromStdString (abs_fname)),
297  tr ("Octave Editor"), "quest", btn, tr ("Create"), role);
298 
299  return (answer == tr ("Create"));
300  }
301 
302  // Prompt to allow file to be run by setting cwd (or if
303  // addpath_option==true, alternatively setting the path).
304 
305  int
306  qt_interpreter_events::debug_cd_or_addpath_error (const std::string& file,
307  const std::string& dir,
308  bool addpath_option)
309  {
310  int retval = -1;
311 
312  QString qdir = QString::fromStdString (dir);
313  QString qfile = QString::fromStdString (file);
314  QString msg
315  = (addpath_option
316  ? 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)
317  : 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));
318 
319  QString title = tr ("Change Directory or Add Directory to Load Path");
320 
321  QString cd_txt = tr ("&Change Directory");
322  QString addpath_txt = tr ("&Add Directory to Load Path");
323  QString cancel_txt = tr ("Cancel");
324 
325  QStringList btn;
326  QStringList role;
327  btn << cd_txt;
328  role << "YesRole";
329  if (addpath_option)
330  {
331  btn << addpath_txt;
332  role << "AcceptRole";
333  }
334  btn << cancel_txt;
335  role << "RejectRole";
336 
337  QString result
338  = m_uiwidget_creator.message_dialog (msg, title, "quest", btn,
339  cancel_txt, role);
340 
341  if (result == cd_txt)
342  retval = 1;
343  else if (result == addpath_txt)
344  retval = 2;
345 
346  return retval;
347  }
348 
349  uint8NDArray qt_interpreter_events::get_named_icon (const std::string& name)
350  {
351  QMutexLocker autolock (&m_mutex);
352 
353  emit get_named_icon_signal (QString::fromStdString (name));
354 
355  // Wait for result.
356  wait ();
357 
358  uint8NDArray empty_img;
359 
360  QIcon icon = m_result.value<QIcon> ();
361 
362  if (icon.isNull ())
363  return empty_img;
364 
365  QImage img = icon.pixmap (QSize (32, 32)).toImage ();
366 
367  if (img.format () != QImage::Format_ARGB32_Premultiplied)
368  return empty_img;
369 
370  dim_vector dims (img.height (), img.width (), 4);
371 
372  uint8NDArray retval (dims, 0);
373 
374  uint8_t *bits = img.bits ();
375 
376  for (int i = 0; i < img.height (); i++)
377  {
378  for (int j = 0; j < img.width (); j++)
379  {
380  retval(i,j,2) = bits[0];
381  retval(i,j,1) = bits[1];
382  retval(i,j,0) = bits[2];
383  retval(i,j,3) = bits[3];
384 
385  bits += 4;
386  }
387  }
388 
389  return retval;
390  }
391 
392  void qt_interpreter_events::get_named_icon_slot (const QString& name)
393  {
394  QMutexLocker autolock (&m_mutex);
395 
396  resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
397  m_result = QVariant::fromValue (rmgr.icon (name));
398 
399  wake_all ();
400  }
401 
402  std::string
403  qt_interpreter_events::gui_preference (const std::string& key,
404  const std::string& value)
405  {
406  QString pref_value;
407 
408  QMutexLocker autolock (&m_mutex);
409 
410  // Emit the signal for changing or getting a preference
411  emit gui_preference_signal (QString::fromStdString (key),
412  QString::fromStdString (value));
413 
414  // Wait for response (pref_value).
415  wait ();
416 
417  QString pref = m_result.toString ();
418 
419  return pref.toStdString ();
420  }
421 
422  bool qt_interpreter_events::copy_image_to_clipboard (const std::string& file)
423  {
424  emit copy_image_to_clipboard_signal (QString::fromStdString (file), true);
425 
426  return true;
427  }
428 
429  void qt_interpreter_events::focus_window (const std::string win_name)
430  {
431  emit focus_window_signal (QString::fromStdString (win_name));
432  }
433 
434  void qt_interpreter_events::execute_command_in_terminal
435  (const std::string& command)
436  {
437  emit execute_command_in_terminal_signal (QString::fromStdString (command));
438  }
439 
440  void qt_interpreter_events::register_doc (const std::string& file)
441  {
442  emit register_doc_signal (QString::fromStdString (file));
443  }
444 
445  void qt_interpreter_events::unregister_doc (const std::string& file)
446  {
447  emit unregister_doc_signal (QString::fromStdString (file));
448  }
449 
450  void qt_interpreter_events::directory_changed (const std::string& dir)
451  {
452  emit directory_changed_signal (QString::fromStdString (dir));
453  }
454 
455  void qt_interpreter_events::file_remove (const std::string& old_name,
456  const std::string& new_name)
457  {
458  QMutexLocker autolock (&m_mutex);
459 
460  // Emit the signal for the editor for closing the file if it is open
461  emit file_remove_signal (QString::fromStdString (old_name),
462  QString::fromStdString (new_name));
463 
464  // Wait for file removal to complete before continuing.
465  wait ();
466  }
467 
468  void qt_interpreter_events::file_renamed (bool load_new)
469  {
470  emit file_renamed_signal (load_new);
471  }
472 
473  void qt_interpreter_events::set_workspace (bool top_level, bool debug,
474  const symbol_info_list& syminfo,
475  bool update_variable_editor)
476  {
477  if (! top_level && ! debug)
478  return;
479 
480  emit set_workspace_signal (top_level, debug, syminfo);
481 
482  if (update_variable_editor)
483  emit refresh_variable_editor_signal ();
484  }
485 
486  void qt_interpreter_events::clear_workspace (void)
487  {
488  emit clear_workspace_signal ();
489  }
490 
491  void qt_interpreter_events::set_history (const string_vector& hist)
492  {
493  QStringList qt_hist;
494 
495  for (octave_idx_type i = 0; i < hist.numel (); i++)
496  qt_hist.append (QString::fromStdString (hist[i]));
497 
498  emit set_history_signal (qt_hist);
499  }
500 
501  void qt_interpreter_events::append_history (const std::string& hist_entry)
502  {
503  emit append_history_signal (QString::fromStdString (hist_entry));
504  }
505 
506  void qt_interpreter_events::clear_history (void)
507  {
508  emit clear_history_signal ();
509  }
510 
511  void qt_interpreter_events::pre_input_event (void)
512  { }
513 
514  void qt_interpreter_events::post_input_event (void)
515  { }
516 
517  void qt_interpreter_events::enter_debugger_event (const std::string& /*fcn_name*/,
518  const std::string& fcn_file_name,
519  int line)
520  {
521  if (fcn_file_name.empty ())
522  return;
523 
524  insert_debugger_pointer (fcn_file_name, line);
525 
526  emit enter_debugger_signal ();
527  }
528 
529  void
530  qt_interpreter_events::execute_in_debugger_event (const std::string& file,
531  int line)
532  {
533  delete_debugger_pointer (file, line);
534  }
535 
536  void qt_interpreter_events::exit_debugger_event (void)
537  {
538  emit exit_debugger_signal ();
539  }
540 
541  // Display (if @insert true) or remove the appropriate symbol for a breakpoint
542  // in @file at @line with condition @cond.
543  void qt_interpreter_events::update_breakpoint (bool insert,
544  const std::string& file,
545  int line,
546  const std::string& cond)
547  {
548  emit update_breakpoint_marker_signal (insert, QString::fromStdString (file),
549  line, QString::fromStdString (cond));
550  }
551 
552  void
553  qt_interpreter_events::insert_debugger_pointer (const std::string& file,
554  int line)
555  {
556  emit insert_debugger_pointer_signal (QString::fromStdString (file), line);
557  }
558 
559  void
560  qt_interpreter_events::delete_debugger_pointer (const std::string& file,
561  int line)
562  {
563  emit delete_debugger_pointer_signal (QString::fromStdString (file), line);
564  }
565 
566  void
567  qt_interpreter_events::confirm_shutdown_octave (void)
568  {
569  QMutexLocker autolock (&m_mutex);
570 
571  m_result = m_octave_qobj.confirm_shutdown ();
572 
573  wake_all ();
574  }
575 
576  // If VALUE is empty, return current value of preference named by KEY.
577  //
578  // If VALUE is not empty, set preference named by KEY to VALUE return
579  // previous value.
580  //
581  // FIXME: should we have separate get and set functions? With only
582  // one, we don't allow a preference value to be set to the empty
583  // string.
584 
585  void
586  qt_interpreter_events::gui_preference_slot (const QString& key,
587  const QString& value)
588  {
589  QMutexLocker autolock (&m_mutex);
590 
591  resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
592  gui_settings *settings = rmgr.get_settings ();
593 
594  QString read_value = settings->value (key).toString ();
595 
596  // Some preferences need extra handling
597  QString adjusted_value = gui_preference_adjust (key, value);
598 
599  if (! adjusted_value.isEmpty () && (read_value != adjusted_value))
600  {
601  // Change settings only for new, non-empty values
602  settings->setValue (key, QVariant (adjusted_value));
603 
604  emit settings_changed (settings, true); // true: changed by worker
605  }
606 
607  m_result = read_value;
608 
609  wake_all ();
610  }
611 
612  QString
613  qt_interpreter_events::gui_preference_adjust (const QString& key,
614  const QString& value)
615  {
616  // Immediately return if no new value is given.
617 
618  if (value.isEmpty ())
619  return value;
620 
621  QString adjusted_value = value;
622 
623  // Not all encodings are available. Encodings are uppercase and do
624  // not use CPxxx but IBMxxx or WINDOWS-xxx.
625 
626  if (key == ed_default_enc.key)
627  {
628  adjusted_value = adjusted_value.toUpper ();
629 
630  QStringList codecs;
631  resource_manager& rmgr = m_octave_qobj.get_resource_manager ();
632  rmgr.get_codecs (&codecs);
633 
634  QRegExp re ("^CP(\\d+)$");
635 
636  if (adjusted_value == "SYSTEM")
637  adjusted_value =
638  QString ("SYSTEM (") +
639  QString (octave_locale_charset_wrapper ()).toUpper () +
640  QString (")");
641  else if (re.indexIn (adjusted_value) > -1)
642  {
643  if (codecs.contains ("IBM" + re.cap (1)))
644  adjusted_value = "IBM" + re.cap (1);
645  else if (codecs.contains ("WINDOWS-" + re.cap (1)))
646  adjusted_value = "WINDOWS-" + re.cap (1);
647  else
648  adjusted_value.clear ();
649  }
650  else if (! codecs.contains (adjusted_value))
651  adjusted_value.clear ();
652  }
653 
654  return adjusted_value;
655  }
656 }
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
std::list< std::pair< std::string, std::string > > filter_list
qt_interpreter_events(base_qobject &oct_qobj)
octave_idx_type numel(void) const
Definition: str-vec.h:100
QList< int > QIntList
Definition: dialog.h:40
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition: filter.cc:46
QString name
const gui_pref ed_create_new_file("editor/create_new_file", QVariant(false))
const gui_pref ed_default_enc("editor/default_encoding", QVariant(QString("SYSTEM (")+QString(octave_locale_charset_wrapper()).toUpper()+QString(")")))
const char * octave_locale_charset_wrapper(void)
static bool debug
QString fromStdString(const std::string &s)
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
static string_vector make_absolute(const string_vector &sv)
Definition: utils.cc:385
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
const QString key