GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
QTerminal.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2012-2019 Michael Goffioul.
4 Copyright (C) 2012-2019 Jacob Dawid.
5 
6 This file is part of QTerminal.
7 
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program. If not,
20 see <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <QKeySequence>
29 #include <QWidget>
30 #include <QStringList>
31 #include <QColor>
32 #include <QList>
33 #include <QMenu>
34 #include <QClipboard>
35 #include <QApplication>
36 #include <QAction>
37 
38 #include "gui-preferences-global.h"
39 #include "gui-preferences-cs.h"
40 #include "gui-preferences-sc.h"
41 #include "octave-qobject.h"
42 #include "resource-manager.h"
43 
44 #include "QTerminal.h"
45 #if defined (Q_OS_WIN32)
46 # include "win32/QWinTerminalImpl.h"
47 #else
48 # include "unix/QUnixTerminalImpl.h"
49 #endif
50 
51 QTerminal *
53 {
54 #if defined (Q_OS_WIN32)
55  QTerminal *terminal = new QWinTerminalImpl (xparent);
56 #else
57  QTerminal *terminal = new QUnixTerminalImpl (xparent);
58 #endif
59 
60  // FIXME: this function should probably be called from or part of the
61  // QTerminal constructor, but I think that would mean some major
62  // surgery because then the constructor for QTerminal and the derived
63  // Unix- and Windows-specific versions would need access to the
64  // base_qobject object, or the design would have to change significantly.
65 
66  terminal->construct (oct_qobj, xparent);
67 
68  return terminal;
69 }
70 
71 // slot for disabling the interrupt action when terminal loses focus
72 void
74  {
75  if (focus_out)
76  {
77  _interrupt_action->setShortcut (QKeySequence ());
78  _nop_action->setShortcut (QKeySequence ());
79  }
80  else
81  {
82  _interrupt_action->setShortcut
83  (QKeySequence (Qt::ControlModifier | Qt::Key_C));
84 
85  _nop_action->setShortcut
86  (QKeySequence (Qt::ControlModifier | Qt::Key_D));
87  }
88  }
89 
90 // slot for the terminal's context menu
91 void
93  {
94  QClipboard * cb = QApplication::clipboard ();
95  QString selected_text = selectedText();
96  bool has_selected_text = ! selected_text.isEmpty ();
97 
98  _edit_action->setVisible (false);
99  m_edit_selected_action->setVisible (false);
100  m_help_selected_action->setVisible (false);
101  m_doc_selected_action->setVisible (false);
102 
103 #if defined (Q_OS_WIN32)
104  // include this when in windows because there is no filter for
105  // detecting links and error messages yet
106  if (has_selected_text)
107  {
108  QRegExp file ("(?:[ \\t]+)(\\S+) at line (\\d+) column (?:\\d+)");
109 
110  int pos = file.indexIn (selected_text);
111 
112  if (pos > -1)
113  {
114  QString file_name = file.cap (1);
115  QString line = file.cap (2);
116 
117  _edit_action->setVisible (true);
118  _edit_action->setText (tr ("Edit %1 at line %2")
119  .arg (file_name).arg (line));
120 
121  QStringList data;
122  data << file_name << line;
123  _edit_action->setData (data);
124  }
125  }
126 #endif
127 
128  if (has_selected_text)
129  {
130  QRegExp expr (".*\b*(\\w+)\b*.*");
131 
132  int pos = expr.indexIn (selected_text);
133 
134  if (pos > -1)
135  {
136  QString expr_found = expr.cap (1);
137 
138  m_edit_selected_action->setVisible (true);
139  m_edit_selected_action->setText (tr ("Edit %1").arg (expr_found));
140  m_edit_selected_action->setData (expr_found);
141 
142  m_help_selected_action->setVisible (true);
143  m_help_selected_action->setText (tr ("Help on %1").arg (expr_found));
144  m_help_selected_action->setData (expr_found);
145 
146  m_doc_selected_action->setVisible (true);
147  m_doc_selected_action->setText (tr ("Documentation on %1")
148  .arg (expr_found));
149  m_doc_selected_action->setData (expr_found);
150  }
151  }
152 
153  _paste_action->setEnabled (cb->text().length() > 0);
154  _copy_action->setEnabled (has_selected_text);
155  _run_selection_action->setVisible (has_selected_text);
156 
157  // Get the actions of any hotspots the filters may have found
158  QList<QAction*> actions = get_hotspot_actions (at);
159  if (actions.length ())
160  _contextMenu->addSeparator ();
161  for (int i = 0; i < actions.length (); i++)
162  _contextMenu->addAction (actions.at(i));
163 
164  // Finally, show the context menu
165  _contextMenu->exec (mapToGlobal (at));
166 
167  // Cleaning up, remove actions of the hotspot
168  for (int i = 0; i < actions.length (); i++)
169  _contextMenu->removeAction (actions.at(i));
170  }
171 
172 // slot for running the selected code
173 void
175 {
176  QStringList commands = selectedText ().split (QRegExp ("[\r\n]"),
177 #if defined (HAVE_QT_SPLITBEHAVIOR_ENUM)
178  Qt::SkipEmptyParts);
179 #else
180  QString::SkipEmptyParts);
181 #endif
182  for (int i = 0; i < commands.size (); i++)
183  emit execute_command_in_terminal_signal (commands.at (i));
184 
185 }
186 
187 // slot for edit files in error messages
188 void
190 {
191  QString file = _edit_action->data ().toStringList ().at (0);
192  int line = _edit_action->data ().toStringList ().at (1).toInt ();
193 
194  emit edit_mfile_request (file,line);
195 }
196 
197 // slot for edit selected function names
199 {
200  QString file = m_edit_selected_action->data ().toString ();
201 
202  emit edit_mfile_request (file,0);
203 }
204 
205 // slot for showing help on selected epxression
207 {
208  QString expr = m_help_selected_action->data ().toString ();
209 
210  emit execute_command_in_terminal_signal ("help " + expr);
211 }
212 
213 // slot for showing documentation on selected epxression
215 {
216  QString expr = m_doc_selected_action->data ().toString ();
217 
218  emit show_doc_signal (expr);
219 }
220 
221 void
223 {
224  if (! settings)
225  return;
226 
227  // Set terminal font:
228  QFont term_font = QFont ();
229  term_font.setStyleHint (QFont::TypeWriter);
230  QString default_font = settings->value (global_mono_font).toString ();
231  term_font.setFamily
232  (settings->value (cs_font.key, default_font).toString ());
233  term_font.setPointSize
234  (settings->value (cs_font_size).toInt ());
235  setTerminalFont (term_font);
236 
237  QFontMetrics metrics (term_font);
238  setMinimumSize (metrics.maxWidth ()*16, metrics.height ()*3);
239 
240  QString cursor_type
241  = settings->value (cs_cursor).toString ();
242 
243  bool cursor_blinking;
244  if (settings->contains (global_cursor_blinking.key))
245  cursor_blinking = settings->value (global_cursor_blinking).toBool ();
246  else
247  cursor_blinking = settings->value (cs_cursor_blinking).toBool ();
248 
249  for (int ct = IBeamCursor; ct <= UnderlineCursor; ct++)
250  {
251  if (cursor_type.toStdString () == cs_cursor_types[ct])
252  {
253  setCursorType ((CursorType) ct, cursor_blinking);
254  break;
255  }
256  }
257 
258  bool cursorUseForegroundColor
259  = settings->value (cs_cursor_use_fgcol).toBool ();
260 
262  (settings->value (cs_colors[0].key, cs_colors[0].def).value<QColor> ());
263 
265  (settings->value (cs_colors[1].key, cs_colors[1].def).value<QColor> ());
266 
268  (settings->value (cs_colors[2].key, cs_colors[2].def).value<QColor> ());
269 
270  setCursorColor (cursorUseForegroundColor,
271  settings->value (cs_colors[3].key, cs_colors[3].def).value<QColor> ());
272 
273  setScrollBufferSize (settings->value (cs_hist_buffer).toInt ());
274 
275  // If the Copy shortcut is Ctrl+C, then the Copy action also emits
276  // a signal for interrupting the current code executed by the worker.
277  // If the Copy shortcut is not Ctrl+C, an extra interrupt action is
278  // set up for emitting the interrupt signal.
279 
280  QString sc = settings->sc_value (sc_main_edit_copy);
281 
282  // Dis- or enable extra interrupt action depending on the Copy shortcut
283  bool extra_ir_action
284  = (sc != QKeySequence (Qt::ControlModifier | Qt::Key_C).toString ());
285 
286  _interrupt_action->setEnabled (extra_ir_action);
287  has_extra_interrupt (extra_ir_action);
288 
289  // check whether shortcut Ctrl-D is in use by the main-window
290  bool ctrld = settings->value (sc_main_ctrld).toBool ();
291  _nop_action->setEnabled (! ctrld);
292 }
293 
294 void
296 {
298 
299  // context menu
300  setContextMenuPolicy (Qt::CustomContextMenu);
301 
302  _contextMenu = new QMenu (this);
303 
305  = _contextMenu->addAction (rmgr.icon ("edit-copy"), tr ("Copy"), this,
306  SLOT (copyClipboard ()));
307 
309  = _contextMenu->addAction (rmgr.icon ("edit-paste"), tr ("Paste"), this,
310  SLOT (pasteClipboard ()));
311 
312  _contextMenu->addSeparator ();
313 
315  = _contextMenu->addAction (tr ("Select All"), this, SLOT (selectAll ()));
316 
318  = _contextMenu->addAction (tr ("Run Selection"), this,
319  SLOT (run_selection ()));
320 
322  = _contextMenu->addAction (tr ("Edit selection"), this,
323  SLOT (edit_selected ()));
325  = _contextMenu->addAction (tr ("Help on selection"), this,
326  SLOT (help_on_expression ()));
328  = _contextMenu->addAction (tr ("Documentation on selection"), this,
329  SLOT (doc_on_expression ()));
330 
331  _edit_action = _contextMenu->addAction (tr (""), this, SLOT (edit_file ()));
332 
333  _contextMenu->addSeparator ();
334 
335  _contextMenu->addAction (tr ("Clear Window"), parent (),
336  SLOT (handle_clear_command_window_request ()));
337 
338  connect (this, SIGNAL (customContextMenuRequested (QPoint)),
339  this, SLOT (handleCustomContextMenuRequested (QPoint)));
340 
341  connect (this, SIGNAL (report_status_message (const QString&)),
342  xparent, SLOT (report_status_message (const QString&)));
343 
344  connect (this, SIGNAL (show_doc_signal (const QString&)),
345  xparent, SLOT (handle_show_doc (const QString&)));
346 
347  connect (this, SIGNAL (edit_mfile_request (const QString&, int)),
348  xparent, SLOT (edit_mfile (const QString&, int)));
349 
350  connect (this, SIGNAL (execute_command_in_terminal_signal (const QString&)),
351  xparent, SLOT (execute_command_in_terminal (const QString&)));
352 
353  connect (xparent, SIGNAL (settings_changed (const gui_settings *)),
354  this, SLOT (notice_settings (const gui_settings *)));
355 
356  connect (xparent, SIGNAL (init_terminal_size_signal ()),
357  this, SLOT (init_terminal_size ()));
358 
359  connect (xparent, SIGNAL (copyClipboard_signal ()),
360  this, SLOT (copyClipboard ()));
361 
362  connect (xparent, SIGNAL (pasteClipboard_signal ()),
363  this, SLOT (pasteClipboard ()));
364 
365  connect (xparent, SIGNAL (selectAll_signal ()),
366  this, SLOT (selectAll ()));
367 
368  // extra interrupt action
369  _interrupt_action = new QAction (this);
370  addAction (_interrupt_action);
371 
372  _interrupt_action->setShortcut
373  (QKeySequence (Qt::ControlModifier + Qt::Key_C));
374 
375  connect (_interrupt_action, SIGNAL (triggered ()),
376  this, SLOT (terminal_interrupt ()));
377 
378  // dummy (nop) action catching Ctrl-D in terminal, no connection
379  _nop_action = new QAction (this);
380  addAction (_nop_action);
381 
382  _nop_action->setShortcut (QKeySequence (Qt::ControlModifier + Qt::Key_D));
383 }
void doc_on_expression(void)
Definition: QTerminal.cc:214
void report_status_message(const QString &)
QAction * m_help_selected_action
Definition: QTerminal.h:155
virtual QString selectedText()=0
QAction * _edit_action
Definition: QTerminal.h:152
QAction * _paste_action
Definition: QTerminal.h:150
void run_selection(void)
Definition: QTerminal.cc:174
QAction * _run_selection_action
Definition: QTerminal.h:153
void help_on_expression(void)
Definition: QTerminal.cc:206
QMenu * _contextMenu
Definition: QTerminal.h:148
virtual void setCursorType(CursorType type, bool blinking)
Definition: QTerminal.h:78
virtual void pasteClipboard(void)=0
virtual void setBackgroundColor(const QColor &color)=0
@ IBeamCursor
Definition: QTerminal.h:73
@ UnderlineCursor
Definition: QTerminal.h:75
virtual QList< QAction * > get_hotspot_actions(const QPoint &)
Definition: QTerminal.h:68
void notice_settings(const gui_settings *settings)
Definition: QTerminal.cc:222
virtual void init_terminal_size(void)
Definition: QTerminal.h:122
QAction * _interrupt_action
Definition: QTerminal.h:158
void edit_mfile_request(const QString &, int)
virtual void setSelectionColor(const QColor &color)=0
virtual void handleCustomContextMenuRequested(const QPoint &at)
Definition: QTerminal.cc:92
virtual void has_extra_interrupt(bool extra)=0
QAction * _selectall_action
Definition: QTerminal.h:151
virtual void setTerminalFont(const QFont &font)=0
QAction * _copy_action
Definition: QTerminal.h:149
void set_global_shortcuts(bool focus_out)
Definition: QTerminal.cc:73
virtual void setCursorColor(bool useForegroundColor, const QColor &color)=0
virtual void copyClipboard(void)=0
void terminal_interrupt(void)
Definition: QTerminal.h:124
QAction * _nop_action
Definition: QTerminal.h:159
QAction * m_doc_selected_action
Definition: QTerminal.h:156
virtual void setForegroundColor(const QColor &color)=0
void construct(octave::base_qobject &oct_qobj, QWidget *xparent)
Definition: QTerminal.cc:295
void execute_command_in_terminal_signal(const QString &)
void edit_file(void)
Definition: QTerminal.cc:189
QAction * m_edit_selected_action
Definition: QTerminal.h:154
virtual void setScrollBufferSize(int value=1000)=0
void show_doc_signal(const QString &)
virtual void selectAll(void)=0
void edit_selected(void)
Definition: QTerminal.cc:198
static QTerminal * create(octave::base_qobject &oct_qobj, QWidget *xparent=nullptr)
Definition: QTerminal.cc:52
Base class for Octave interfaces that use Qt.
resource_manager & get_resource_manager(void)
QVariant value(const gui_pref &pref) const
Definition: gui-settings.h:63
QString sc_value(const sc_pref &pref) const
Definition: gui-settings.cc:37
QIcon icon(const QString &icon_name, bool fallback=true)
const gui_pref cs_colors[cs_colors_count]
const gui_pref cs_hist_buffer("terminal/history_buffer", QVariant(1000))
const gui_pref cs_font_size("terminal/fontSize", QVariant(10))
const std::vector< std::string > cs_cursor_types
const gui_pref cs_cursor("terminal/cursorType", QVariant("ibeam"))
const gui_pref cs_cursor_use_fgcol("terminal/cursorUseForegroundColor", QVariant(true))
const gui_pref cs_font("terminal/fontName", QVariant())
const gui_pref cs_cursor_blinking("terminal/cursorBlinking", QVariant(true))
const gui_pref global_mono_font("monospace_font", global_font_family)
const gui_pref global_cursor_blinking("cursor_blinking", QVariant(true))
const gui_pref sc_main_ctrld("shortcuts/main_ctrld", QVariant(false))
const sc_pref sc_main_edit_copy(sc_main_edit+":copy", QKeySequence::Copy)
const QString key
const QVariant def