GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
octave-qscintilla.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2013-2017 Torsten
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 // Author: Torsten <ttl@justmail.de>
24 
25 #if defined (HAVE_CONFIG_H)
26 # include "config.h"
27 #endif
28 
29 #if defined (HAVE_QSCINTILLA)
30 
31 #include <Qsci/qscilexer.h>
32 #include <Qsci/qscicommandset.h>
33 #include <QShortcut>
34 #include <QMessageBox>
35 
36 #include "octave-qscintilla.h"
37 #include "file-editor-tab.h"
38 #include "shortcut-manager.h"
39 
41  : QsciScintilla (p)
42 {
43  connect (this, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
44 
45  // clear scintilla edit shortcuts that are handled by the editor
46  QsciCommandSet *cmd_set = standardCommands ();
47 
48 #if defined (HAVE_QSCI_VERSION_2_6_0)
49  // find () was added in QScintilla 2.6
50  cmd_set->find (QsciCommand::SelectionCopy)->setKey (0);
51  cmd_set->find (QsciCommand::SelectionCut)->setKey (0);
52  cmd_set->find (QsciCommand::Paste)->setKey (0);
53  cmd_set->find (QsciCommand::SelectAll)->setKey (0);
54  cmd_set->find (QsciCommand::SelectionDuplicate)->setKey (0);
55  cmd_set->find (QsciCommand::LineTranspose)->setKey (0);
56  cmd_set->find (QsciCommand::Undo)->setKey (0);
57  cmd_set->find (QsciCommand::Redo)->setKey (0);
58  cmd_set->find (QsciCommand::SelectionUpperCase)->setKey (0);
59  cmd_set->find (QsciCommand::SelectionLowerCase)->setKey (0);
60  cmd_set->find (QsciCommand::ZoomIn)->setKey (0);
61  cmd_set->find (QsciCommand::ZoomOut)->setKey (0);
62  cmd_set->find (QsciCommand::DeleteWordLeft)->setKey (0);
63  cmd_set->find (QsciCommand::DeleteWordRight)->setKey (0);
64  cmd_set->find (QsciCommand::DeleteLineLeft)->setKey (0);
65  cmd_set->find (QsciCommand::DeleteLineRight)->setKey (0);
66  cmd_set->find (QsciCommand::LineDelete)->setKey (0);
67  cmd_set->find (QsciCommand::LineCut)->setKey (0);
68  cmd_set->find (QsciCommand::LineCopy)->setKey (0);
69 #else
70  // find commands via its default key (tricky way without find ())
71  QList< QsciCommand * > cmd_list = cmd_set->commands ();
72  for (int i = 0; i < cmd_list.length (); i++)
73  {
74  int cmd_key = cmd_list.at (i)->key ();
75  switch (cmd_key)
76  {
77  case Qt::Key_C | Qt::CTRL : // SelectionCopy
78  case Qt::Key_X | Qt::CTRL : // SelectionCut
79  case Qt::Key_V | Qt::CTRL : // Paste
80  case Qt::Key_A | Qt::CTRL : // SelectAll
81  case Qt::Key_D | Qt::CTRL : // SelectionDuplicate
82  case Qt::Key_T | Qt::CTRL : // LineTranspose
83  case Qt::Key_Z | Qt::CTRL : // Undo
84  case Qt::Key_Y | Qt::CTRL : // Redo
85  case Qt::Key_Z | Qt::CTRL | Qt::SHIFT : // Redo
86  case Qt::Key_U | Qt::CTRL : // SelectionLowerCase
87  case Qt::Key_U | Qt::CTRL | Qt::SHIFT : // SelectionUpperCase
88  case Qt::Key_Plus | Qt::CTRL : // ZoomIn
89  case Qt::Key_Minus | Qt::CTRL : // ZoomOut
90  case Qt::Key_Backspace | Qt::CTRL | Qt::SHIFT : // DeleteLineLeft
91  case Qt::Key_Delete | Qt::CTRL | Qt::SHIFT : // DeleteLineRight
92  case Qt::Key_K | Qt::META : // DeleteLineRight
93  case Qt::Key_Backspace | Qt::CTRL : // DeleteWordLeft
94  case Qt::Key_Delete | Qt::CTRL : // DeleteWordRight
95  case Qt::Key_L | Qt::CTRL | Qt::SHIFT : // LineDelete
96  case Qt::Key_L | Qt::CTRL : // LineCut
97  case Qt::Key_T | Qt::CTRL | Qt::SHIFT : // LineCopy
98  cmd_list.at (i)->setKey (0);
99  }
100  }
101 #endif
102 
103 #if defined (Q_OS_MAC)
104  // Octave interprets Cmd key as Meta whereas Qscintilla interprets it
105  // as Ctrl. We thus invert Meta/Ctrl in Qscintilla's shortcuts list.
106  QList< QsciCommand * > cmd_list_mac = cmd_set->commands ();
107  for (int i = 0; i < cmd_list_mac.length (); i++)
108  {
109  // Primary key
110  int key = cmd_list_mac.at (i)->key ();
111 
112  if (static_cast<int> (key | Qt::META) == key &&
113  static_cast<int> (key | Qt::CTRL) != key)
114  key = (key ^ Qt::META) | Qt::CTRL;
115  else if (static_cast<int> (key | Qt::CTRL) == key)
116  key = (key ^ Qt::CTRL) | Qt::META;
117 
118  cmd_list_mac.at (i)->setKey (key);
119 
120  // Alternate key
121  key = cmd_list_mac.at (i)->alternateKey ();
122 
123  if (static_cast<int> (key | Qt::META) == key &&
124  static_cast<int> (key | Qt::CTRL) != key)
125  key = (key ^ Qt::META) | Qt::CTRL;
126  else if (static_cast<int> (key | Qt::CTRL) == key)
127  key = (key ^ Qt::CTRL) | Qt::META;
128 
129  cmd_list_mac.at (i)->setAlternateKey (key);
130  }
131 #endif
132 
133  // init state of undo/redo action for this tab
134  emit status_update (isUndoAvailable (), isRedoAvailable ());
135 }
136 
138 { }
139 
140 void
142  QPoint *local_pos)
143 {
144  long position = SendScintilla (SCI_GETCURRENTPOS);
145  long point_x = SendScintilla
146  (SCI_POINTXFROMPOSITION,0,position);
147  long point_y = SendScintilla
148  (SCI_POINTYFROMPOSITION,0,position);
149  *local_pos = QPoint (point_x,point_y); // local cursor position
150  *global_pos = mapToGlobal (*local_pos); // global position of cursor
151 }
152 
153 // determine the actual word and whether we are in an octave or matlab script
154 bool
156 {
157  QPoint global_pos, local_pos;
158  get_global_textcursor_pos (&global_pos, &local_pos);
159  _word_at_cursor = wordAtPoint (local_pos);
160  QString lexer_name = lexer ()->lexer ();
161  return ((lexer_name == "octave" || lexer_name == "matlab")
162  && ! _word_at_cursor.isEmpty ());
163 }
164 
165 // call documentation or help on the current word
166 void
168 {
169  if (get_actual_word ())
170  contextmenu_help_doc (documentation);
171 }
172 
173 // call edit the function related to the current word
174 void
176 {
177  if (get_actual_word ())
178  contextmenu_edit (true);
179 }
180 
181 // call edit the function related to the current word
182 void
184 {
185  if (hasSelectedText ())
186  contextmenu_run (true);
187 }
188 
189 // context menu requested
190 void
192 {
193 #if defined (HAVE_QSCI_VERSION_2_6_0)
194  QPoint global_pos, local_pos; // the menu's position
195  QMenu *context_menu = createStandardContextMenu (); // standard menu
196 
197  bool in_left_margin = false;
198 
199  // determine position depending on mouse or keyboard event
200  if (e->reason () == QContextMenuEvent::Mouse)
201  {
202  // context menu by mouse
203  global_pos = e->globalPos (); // global mouse position
204  local_pos = e->pos (); // local mouse position
205  if (e->x () < marginWidth (1) + marginWidth (2))
206  in_left_margin = true;
207  }
208  else
209  {
210  // context menu by keyboard or other: get point of text cursor
211  get_global_textcursor_pos (&global_pos, &local_pos);
212  QRect editor_rect = geometry (); // editor rect mapped to global
213  editor_rect.moveTopLeft
214  (parentWidget ()->mapToGlobal (editor_rect.topLeft ()));
215  if (! editor_rect.contains (global_pos)) // is cursor outside editor?
216  global_pos = editor_rect.topLeft (); // yes, take top left corner
217  }
218 
219 #if defined (HAVE_QSCI_VERSION_2_6_0)
220  if (! in_left_margin)
221 #endif
222  {
223  // fill context menu with editor's standard actions
224  emit create_context_menu_signal (context_menu);
225 
226  // additional custom entries of the context menu
227  context_menu->addSeparator (); // separator before custom entries
228 
229  // help menu: get the position of the mouse or the text cursor
230  // (only for octave files)
231  QString lexer_name = lexer ()->lexer ();
232  if (lexer_name == "octave" || lexer_name == "matlab")
233  {
234  _word_at_cursor = wordAtPoint (local_pos);
235  if (! _word_at_cursor.isEmpty ())
236  {
237  context_menu->addAction (tr ("Help on") + " " + _word_at_cursor,
238  this, SLOT (contextmenu_help (bool)));
239  context_menu->addAction (tr ("Documentation on")
240  + " " + _word_at_cursor,
241  this, SLOT (contextmenu_doc (bool)));
242  context_menu->addAction (tr ("Edit") + " " + _word_at_cursor,
243  this, SLOT (contextmenu_edit (bool)));
244  }
245  }
246  }
247 #if defined (HAVE_QSCI_VERSION_2_6_0)
248  else
249  {
250  // remove all standard actions from scintilla
251  QList<QAction *> all_actions = context_menu->actions ();
252  QAction* a;
253 
254  foreach (a, all_actions)
255  context_menu->removeAction (a);
256 
257  a = context_menu->addAction (tr ("dbstop if ..."), this,
258  SLOT (contextmenu_break_condition (bool)));
259  a->setData (local_pos);
260  }
261 #endif
262 
263  // finaly show the menu
264  context_menu->exec (global_pos);
265 #endif
266 }
267 
268 // handle the menu entry for calling help or doc
269 void
271 {
272  contextmenu_help_doc (true);
273 }
274 void
276 {
277  contextmenu_help_doc (false);
278 }
279 
280 // common function with flag for documentation
281 void
283 {
284  if (documentation)
286  else
288 }
289 
290 void
292 {
294 }
295 
296 void
298 {
299  QStringList commands = selectedText ().split (QRegExp("[\r\n]"),
300  QString::SkipEmptyParts);
301  for (int i = 0; i < commands.size (); i++)
302  emit execute_command_in_terminal_signal (commands.at (i));
303 }
304 
305 // wrappers for dbstop related context menu items
306 
307 // FIXME: Why can't the data be sent as the argument to the function???
308 void
310 {
311 #if defined (HAVE_QSCI_VERSION_2_6_0)
312  QAction *action = qobject_cast<QAction *>(sender());
313  QPoint local_pos = action->data ().value<QPoint> ();
314 
315  // pick point just right of margins, so lineAt doesn't give -1
316  int margins = marginWidth (1) + marginWidth (2) + marginWidth (3);
317  local_pos = QPoint (margins + 1, local_pos.y ());
318 
319  emit context_menu_break_condition_signal (lineAt (local_pos));
320 #endif
321 }
322 
323 void
325 {
326 #if defined (HAVE_QSCI_VERSION_2_6_0)
327  emit context_menu_break_once (lineAt (local_pos));
328 #endif
329 }
330 
331 void
333 {
334  emit status_update (isUndoAvailable (), isRedoAvailable ());
335 }
336 
337 // when edit area gets focus update information on undo/redo actions
338 void octave_qscintilla::focusInEvent(QFocusEvent *focusEvent)
339 {
340  emit status_update (isUndoAvailable (), isRedoAvailable ());
341 
342  QsciScintilla::focusInEvent(focusEvent);
343 }
344 
345 #endif
void contextmenu_help_doc(bool)
void context_menu_break_condition_signal(int)
void context_menu_edit_signal(const QString &)
virtual void contextMenuEvent(QContextMenuEvent *e)
#define CTRL(x)
Definition: kpty.cpp:143
void status_update(bool, bool)
void contextmenu_break_once(const QPoint &)
void show_doc_signal(const QString &)
i e
Definition: data.cc:2724
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
#define lexer
Definition: oct-parse.cc:152
void create_context_menu_signal(QMenu *)
octave_qscintilla(QWidget *p)
void execute_command_in_terminal_signal(const QString &)
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
void focusInEvent(QFocusEvent *focusEvent)
void contextmenu_break_condition(bool)
void get_global_textcursor_pos(QPoint *global_pos, QPoint *local_pos)
to define functions rather than attempting to enter them directly on the command line The block of commands is executed as soon as you exit the editor To avoid executing any commands
Definition: oct-hist.cc:587