GNU Octave  8.1.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 *
52 QTerminal::create (octave::base_qobject& oct_qobj, QWidget *p)
53 {
54 #if defined (Q_OS_WIN32)
55  QTerminal *terminal = new QWinTerminalImpl (oct_qobj, p);
56 #else
57  QTerminal *terminal = new QUnixTerminalImpl (oct_qobj, p);
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);
67 
68  return terminal;
69 }
70 
71 // slot for the terminal's context menu
72 void
74  {
75  QClipboard * cb = QApplication::clipboard ();
76  QString selected_text = selectedText();
77  bool has_selected_text = ! selected_text.isEmpty ();
78 
79  _edit_action->setVisible (false);
80  m_edit_selected_action->setVisible (false);
81  m_help_selected_action->setVisible (false);
82  m_doc_selected_action->setVisible (false);
83 
84 #if defined (Q_OS_WIN32)
85  // include this when in windows because there is no filter for
86  // detecting links and error messages yet
87  if (has_selected_text)
88  {
89  QRegExp file ("(?:[ \\t]+)(\\S+) at line (\\d+) column (?:\\d+)");
90 
91  int pos = file.indexIn (selected_text);
92 
93  if (pos > -1)
94  {
95  QString file_name = file.cap (1);
96  QString line = file.cap (2);
97 
98  _edit_action->setVisible (true);
99  _edit_action->setText (tr ("Edit %1 at line %2")
100  .arg (file_name).arg (line));
101 
102  QStringList data;
103  data << file_name << line;
104  _edit_action->setData (data);
105  }
106  }
107 #endif
108 
109  if (has_selected_text)
110  {
111  QRegExp expr (".*\b*(\\w+)\b*.*");
112 
113  int pos = expr.indexIn (selected_text);
114 
115  if (pos > -1)
116  {
117  QString expr_found = expr.cap (1);
118 
119  m_edit_selected_action->setVisible (true);
120  m_edit_selected_action->setText (tr ("Edit %1").arg (expr_found));
121  m_edit_selected_action->setData (expr_found);
122 
123  m_help_selected_action->setVisible (true);
124  m_help_selected_action->setText (tr ("Help on %1").arg (expr_found));
125  m_help_selected_action->setData (expr_found);
126 
127  m_doc_selected_action->setVisible (true);
128  m_doc_selected_action->setText (tr ("Documentation on %1")
129  .arg (expr_found));
130  m_doc_selected_action->setData (expr_found);
131  }
132  }
133 
134  _paste_action->setEnabled (cb->text().length() > 0);
135  _copy_action->setEnabled (has_selected_text);
136  _run_selection_action->setVisible (has_selected_text);
137 
138  // Get the actions of any hotspots the filters may have found
139  QList<QAction*> actions = get_hotspot_actions (at);
140  if (actions.length ())
141  _contextMenu->addSeparator ();
142  for (int i = 0; i < actions.length (); i++)
143  _contextMenu->addAction (actions.at(i));
144 
145  // Finally, show the context menu
146  _contextMenu->exec (mapToGlobal (at));
147 
148  // Cleaning up, remove actions of the hotspot
149  for (int i = 0; i < actions.length (); i++)
150  _contextMenu->removeAction (actions.at(i));
151  }
152 
153 // slot for running the selected code
154 void
156 {
157  QStringList commands = selectedText ().split (QRegExp ("[\r\n]"),
158 #if defined (HAVE_QT_SPLITBEHAVIOR_ENUM)
159  Qt::SkipEmptyParts);
160 #else
161  QString::SkipEmptyParts);
162 #endif
163  for (int i = 0; i < commands.size (); i++)
164  emit execute_command_in_terminal_signal (commands.at (i));
165 
166 }
167 
168 // slot for edit files in error messages
169 void
171 {
172  QString file = _edit_action->data ().toStringList ().at (0);
173  int line = _edit_action->data ().toStringList ().at (1).toInt ();
174 
175  emit edit_mfile_request (file,line);
176 }
177 
178 // slot for edit selected function names
180 {
181  QString file = m_edit_selected_action->data ().toString ();
182 
183  emit edit_mfile_request (file,0);
184 }
185 
186 // slot for showing help on selected epxression
188 {
189  QString expr = m_help_selected_action->data ().toString ();
190 
191  emit execute_command_in_terminal_signal ("help " + expr);
192 }
193 
194 // slot for showing documentation on selected epxression
196 {
197  QString expr = m_doc_selected_action->data ().toString ();
198  m_octave_qobj.show_documentation_window (expr);
199 }
200 
201 void
203 {
204  if (! settings)
205  return;
206 
207  // Set terminal font:
208  QFont term_font = QFont ();
209  term_font.setStyleHint (QFont::TypeWriter);
210  QString default_font = settings->value (global_mono_font).toString ();
211  term_font.setFamily
212  (settings->value (cs_font.key, default_font).toString ());
213  term_font.setPointSize
214  (settings->value (cs_font_size).toInt ());
215  setTerminalFont (term_font);
216 
217  QFontMetrics metrics (term_font);
218  setMinimumSize (metrics.maxWidth ()*16, metrics.height ()*3);
219 
220  QString cursor_type
221  = settings->value (cs_cursor).toString ();
222 
223  bool cursor_blinking;
224  if (settings->contains (global_cursor_blinking.key))
225  cursor_blinking = settings->value (global_cursor_blinking).toBool ();
226  else
227  cursor_blinking = settings->value (cs_cursor_blinking).toBool ();
228 
229  for (int ct = IBeamCursor; ct <= UnderlineCursor; ct++)
230  {
231  if (cursor_type.toStdString () == cs_cursor_types[ct])
232  {
233  setCursorType ((CursorType) ct, cursor_blinking);
234  break;
235  }
236  }
237 
238  bool cursorUseForegroundColor
239  = settings->value (cs_cursor_use_fgcol).toBool ();
240 
241  int mode = settings->value (cs_color_mode).toInt ();
242 
243  setForegroundColor (settings->color_value (cs_colors[0], mode));
244 
245  setBackgroundColor (settings->color_value (cs_colors[1], mode));
246 
247  setSelectionColor (settings->color_value (cs_colors[2], mode));
248 
249  setCursorColor (cursorUseForegroundColor,
250  settings->color_value (cs_colors[3], mode));
251 
252  setScrollBufferSize (settings->value (cs_hist_buffer).toInt ());
253 
254  // If the Copy shortcut is Ctrl+C, then the Copy action also emits
255  // a signal for interrupting the current code executed by the worker.
256  // If the Copy shortcut is not Ctrl+C, an extra interrupt action is
257  // set up for emitting the interrupt signal.
258 
259  QString sc = settings->sc_value (sc_main_edit_copy);
260 
261  // Dis- or enable extra interrupt action: We need an extra option when
262  // copy shortcut is not Ctrl-C or when global shortcuts (like copy) are
263  // disabled.
264  bool extra_ir_action
265  = (sc != QKeySequence (Qt::ControlModifier | Qt::Key_C).toString ())
266  || settings->value (sc_prevent_rl_conflicts).toBool ();
267 
268  _interrupt_action->setEnabled (extra_ir_action);
269  has_extra_interrupt (extra_ir_action);
270 
271  // check whether shortcut Ctrl-D is in use by the main-window
272  bool ctrld = settings->value (sc_main_ctrld).toBool ();
273  _nop_action->setEnabled (! ctrld);
274 }
275 
276 void
277 QTerminal::construct (octave::base_qobject& oct_qobj)
278 {
279  octave::resource_manager& rmgr = oct_qobj.get_resource_manager ();
280 
281  // context menu
282  setContextMenuPolicy (Qt::CustomContextMenu);
283 
284  _contextMenu = new QMenu (this);
285 
287  = _contextMenu->addAction (rmgr.icon ("edit-copy"), tr ("Copy"), this,
288  SLOT (copyClipboard ()));
289 
291  = _contextMenu->addAction (rmgr.icon ("edit-paste"), tr ("Paste"), this,
292  SLOT (pasteClipboard ()));
293 
294  _contextMenu->addSeparator ();
295 
297  = _contextMenu->addAction (tr ("Select All"), this, SLOT (selectAll ()));
298 
300  = _contextMenu->addAction (tr ("Run Selection"), this,
301  SLOT (run_selection ()));
302 
304  = _contextMenu->addAction (tr ("Edit selection"), this,
305  SLOT (edit_selected ()));
307  = _contextMenu->addAction (tr ("Help on selection"), this,
308  SLOT (help_on_expression ()));
310  = _contextMenu->addAction (tr ("Documentation on selection"), this,
311  SLOT (doc_on_expression ()));
312 
313  _edit_action = _contextMenu->addAction (tr (""), this, SLOT (edit_file ()));
314 
315  _contextMenu->addSeparator ();
316 
317  _contextMenu->addAction (tr ("Clear Window"), this,
318  SIGNAL (clear_command_window_request ()));
319 
320  connect (this, SIGNAL (customContextMenuRequested (QPoint)),
321  this, SLOT (handleCustomContextMenuRequested (QPoint)));
322 
323  // extra interrupt action
324  _interrupt_action = new QAction (this);
325  addAction (_interrupt_action);
326 
327  _interrupt_action->setShortcut
328  (QKeySequence (Qt::ControlModifier + Qt::Key_C));
329  _interrupt_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
330 
331  bool ok = connect (_interrupt_action, SIGNAL (triggered ()),
332  this, SLOT (terminal_interrupt ()));
333 
334  // dummy (nop) action catching Ctrl-D in terminal, no connection
335  _nop_action = new QAction (this);
336  addAction (_nop_action);
337 
338  _nop_action->setShortcut (QKeySequence (Qt::ControlModifier + Qt::Key_D));
339  _nop_action->setShortcutContext (Qt::WidgetWithChildrenShortcut);
340 }
void doc_on_expression(void)
Definition: QTerminal.cc:195
QAction * m_help_selected_action
Definition: QTerminal.h:165
virtual QString selectedText()=0
QAction * _edit_action
Definition: QTerminal.h:162
QAction * _paste_action
Definition: QTerminal.h:160
void run_selection(void)
Definition: QTerminal.cc:155
QAction * _run_selection_action
Definition: QTerminal.h:163
void help_on_expression(void)
Definition: QTerminal.cc:187
octave::base_qobject & m_octave_qobj
Definition: QTerminal.h:156
QMenu * _contextMenu
Definition: QTerminal.h:158
virtual void setCursorType(CursorType type, bool blinking)
Definition: QTerminal.h:79
virtual void pasteClipboard(void)=0
void construct(octave::base_qobject &oct_qobj)
Definition: QTerminal.cc:277
virtual void setBackgroundColor(const QColor &color)=0
@ IBeamCursor
Definition: QTerminal.h:74
@ UnderlineCursor
Definition: QTerminal.h:76
virtual QList< QAction * > get_hotspot_actions(const QPoint &)
Definition: QTerminal.h:69
void notice_settings(const gui_settings *settings)
Definition: QTerminal.cc:202
QAction * _interrupt_action
Definition: QTerminal.h:168
void edit_mfile_request(const QString &, int)
virtual void setSelectionColor(const QColor &color)=0
virtual void handleCustomContextMenuRequested(const QPoint &at)
Definition: QTerminal.cc:73
virtual void has_extra_interrupt(bool extra)=0
QAction * _selectall_action
Definition: QTerminal.h:161
virtual void setTerminalFont(const QFont &font)=0
QAction * _copy_action
Definition: QTerminal.h:159
virtual void setCursorColor(bool useForegroundColor, const QColor &color)=0
virtual void copyClipboard(void)=0
void terminal_interrupt(void)
Definition: QTerminal.h:133
QAction * _nop_action
Definition: QTerminal.h:169
QAction * m_doc_selected_action
Definition: QTerminal.h:166
static QTerminal * create(octave::base_qobject &oct_qobj, QWidget *xparent)
Definition: QTerminal.cc:52
void clear_command_window_request(void)
virtual void setForegroundColor(const QColor &color)=0
void execute_command_in_terminal_signal(const QString &)
void edit_file(void)
Definition: QTerminal.cc:170
QAction * m_edit_selected_action
Definition: QTerminal.h:164
virtual void setScrollBufferSize(int value=1000)=0
virtual void selectAll(void)=0
void edit_selected(void)
Definition: QTerminal.cc:179
const gui_pref cs_colors[2 *cs_colors_count]
const gui_pref cs_color_mode("terminal/color_mode", QVariant(0))
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 gui_pref sc_prevent_rl_conflicts("shortcuts/prevent_readline_conflicts", QVariant(false))
const QString key