GNU Octave  3.8.0
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
file-editor.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2011-2013 Jacob Dawid
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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #ifdef HAVE_QSCINTILLA
28 
29 #include "file-editor.h"
30 #include "resource-manager.h"
31 #include <QVBoxLayout>
32 #include <QApplication>
33 #include <QFile>
34 #include <QFont>
35 #include <QFileDialog>
36 #include <QMessageBox>
37 #include <QStyle>
38 #include <QTextStream>
39 #include <QProcess>
40 #include <QInputDialog>
41 
42 #include "octave-link.h"
43 #include "utils.h"
44 
47 {
48  // Set current editing directory before construct because loaded
49  // files will change ced accordingly.
50  ced = QDir::currentPath ();
51 
52  construct ();
53 
54  setVisible (false);
55 }
56 
58 {
59  QSettings *settings = resource_manager::get_settings ();
60 
61  // Have all file editor tabs signal what their file names are.
62  editor_tab_map.clear ();
63  emit fetab_file_name_query (0);
64 
65  // save file names (even if last session will not be restored next time)
66  QStringList fetFileNames;
68  p != editor_tab_map.end (); p++)
69  {
70  QString file_name = p->first;
71  if (!file_name.isEmpty () && file_name.at (file_name.size () - 1) != '/')
72  fetFileNames.append (p->first); // do not append unnamed files
73  }
74 
75  settings->setValue ("editor/savedSessionTabs", fetFileNames);
76  settings->sync ();
77 
78  for (int index = _tab_widget->count ()-1; index >= 0; index--)
79  {
80  // true: app closing
81  emit fetab_close_request (_tab_widget->widget (index), true);
82  }
83 
84  if (_mru_file_menu)
85  delete _mru_file_menu;
86 }
87 
88 void
89 file_editor::focus (void)
90 {
91  set_focus ();
92 }
93 
94 // set focus to editor and its current tab
95 void
97 {
98  if (!isVisible ())
99  setVisible (true);
100  setFocus ();
101  activateWindow ();
102  raise ();
103  QWidget *fileEditorTab = _tab_widget->currentWidget ();
104  if (fileEditorTab)
105  emit fetab_set_focus (fileEditorTab);
106 }
107 
108 QMenu *
110 {
111  return _debug_menu;
112 }
113 
114 QToolBar *
116 {
117  return _tool_bar;
118 }
119 
120 void
122 {
123  _run_action->setEnabled (false);
124 }
125 
126 void
128 {
129  _run_action->setEnabled (true);
130 }
131 
132 void
133 file_editor::request_new_file (const QString& commands)
134 {
135  // Custom editor? If yes, we can only call the editor without passing
136  // some initial contents and even without being sure a new file is opened
137  if (call_custom_editor ())
138  return;
139 
140  // New file isn't a file_editor_tab function since the file
141  // editor tab has yet to be created and there is no object to
142  // pass a signal to. Hence, functionality is here.
143 
144  file_editor_tab *fileEditorTab = new file_editor_tab (ced);
145  if (fileEditorTab)
146  {
147  add_file_editor_tab (fileEditorTab, ""); // new tab with empty title
148  fileEditorTab->new_file (commands); // title is updated here
149  set_focus (); // focus editor and new tab
150  }
151 }
152 
153 void
154 file_editor::request_new_script (const QString& commands)
155 {
156  request_new_file (commands);
157 }
158 
159 void
161 {
162  bool ok;
163  // get the name of the new function
164  QString new_name = QInputDialog::getText (this, tr ("New Function"),
165  tr ("New function name:\n"), QLineEdit::Normal, "", &ok);
166  if (ok && new_name.length () > 0)
167  {
168  // append suffix if it not already exists
169  if (new_name.rightRef (2) != ".m")
170  new_name.append (".m");
171  // check whether new files are created without prompt
172  QSettings *settings = resource_manager::get_settings ();
173  if (! settings->value ("editor/create_new_file",false).toBool ())
174  {
175  // no, so enable this settings and wait for end of new file loading
176  settings->setValue ("editor/create_new_file",true);
177  connect (this, SIGNAL (file_loaded_signal ()),
178  this, SLOT (restore_create_file_setting ()));
179  }
180  // start the edit command
181  emit execute_command_in_terminal_signal ("edit " + new_name);
182  }
183 }
184 
185 void
187 {
188  // restore the new files creation setting
189  QSettings *settings = resource_manager::get_settings ();
190  settings->setValue ("editor/create_new_file",false);
191  disconnect (this, SIGNAL (file_loaded_signal ()),
192  this, SLOT (restore_create_file_setting ()));
193 }
194 
195 void
197 {
198  // Open file isn't a file_editor_tab function since the file
199  // editor tab has yet to be created and there is no object to
200  // pass a signal to. Hence, functionality is here.
201 
202  // Create a NonModal message.
203  QFileDialog *fileDialog = new QFileDialog (this);
204  fileDialog->setNameFilter (tr ("Octave Files (*.m);;All Files (*)"));
205 
206  // Giving trouble under KDE (problem is related to Qt signal handling on unix,
207  // see https://bugs.kde.org/show_bug.cgi?id=260719 ,
208  // it had/has no effect on Windows, though)
209  fileDialog->setOption(QFileDialog::DontUseNativeDialog, true);
210 
211  fileDialog->setAcceptMode (QFileDialog::AcceptOpen);
212  fileDialog->setViewMode (QFileDialog::Detail);
213  fileDialog->setDirectory (ced);
214 
215  connect (fileDialog, SIGNAL (fileSelected (const QString&)),
216  this, SLOT (request_open_file (const QString&)));
217 
218  fileDialog->setWindowModality (Qt::NonModal);
219  fileDialog->setAttribute (Qt::WA_DeleteOnClose);
220  fileDialog->show ();
221 }
222 
223 // Check whether this file is already open in the editor.
224 QWidget *
225 file_editor::find_tab_widget (const QString& file) const
226 {
227  QWidget *retval = 0;
228 
230  p != editor_tab_map.end (); p++)
231  {
232  QString tab_file = p->first;
233 
234  if (same_file (file.toStdString (), tab_file.toStdString ()))
235  {
236  retval = p->second;
237  break;
238  }
239  }
240 
241  return retval;
242 }
243 
244 bool
245 file_editor::call_custom_editor (const QString& file_name, int line)
246 {
247  // Check if the user wants to use a custom file editor.
248  QSettings *settings = resource_manager::get_settings ();
249 
250  if (settings->value ("useCustomFileEditor").toBool ())
251  {
252  QString editor = settings->value ("customFileEditor").toString ();
253  editor.replace ("%f", file_name);
254  editor.replace ("%l", QString::number (line));
255 
256  QProcess::startDetached (editor);
257 
258  if (line < 0 && ! file_name.isEmpty ())
259  handle_mru_add_file (QFileInfo (file_name).canonicalFilePath ());
260 
261  return true;
262  }
263 
264  return false;
265 }
266 
267 void
268 file_editor::request_open_file (const QString& openFileName, int line,
269  bool debug_pointer,
270  bool breakpoint_marker, bool insert)
271 {
272  if (call_custom_editor (openFileName, line))
273  return; // custom editor called
274 
275  if (openFileName.isEmpty ())
276  {
277  // This happens if edit is calles without an argument
278  // Open eitor with empty edit area instead (as new file would do)
279  request_new_file ("");
280  }
281  else
282  {
283  // Have all file editor tabs signal what their file names are.
284  editor_tab_map.clear ();
285  emit fetab_file_name_query (0);
286 
287  // Check whether this file is already open in the editor.
288  QWidget *tab = find_tab_widget (openFileName);
289 
290  if (tab)
291  {
292  _tab_widget->setCurrentWidget (tab);
293 
294  if (line > 0)
295  {
296  emit fetab_goto_line (tab, line);
297 
298  if (debug_pointer)
299  emit fetab_insert_debugger_pointer (tab, line);
300 
301  if (breakpoint_marker)
302  emit fetab_do_breakpoint_marker (insert, tab, line);
303  }
304 
305  emit fetab_set_focus (tab);
306  set_focus ();
307  }
308  else
309  {
310  file_editor_tab *fileEditorTab = new file_editor_tab ();
311  if (fileEditorTab)
312  {
313  QString result = fileEditorTab->load_file (openFileName);
314  if (result == "")
315  {
316  // Supply empty title then have the file_editor_tab update
317  // with full or short name.
318  add_file_editor_tab (fileEditorTab, "");
319  fileEditorTab->update_window_title (false);
320  // file already loaded, add file to mru list here
321  QFileInfo file_info = QFileInfo (openFileName);
322  handle_mru_add_file (file_info.canonicalFilePath ());
323 
324  if (line > 0)
325  {
326  emit fetab_goto_line (fileEditorTab, line);
327 
328  if (debug_pointer)
329  emit fetab_insert_debugger_pointer (fileEditorTab,
330  line);
331  if (breakpoint_marker)
332  emit fetab_do_breakpoint_marker (insert, fileEditorTab,
333  line);
334  }
335  }
336  else
337  {
338  delete fileEditorTab;
339 
340  if (QFile::exists (openFileName))
341  {
342  // File not readable:
343  // create a NonModal message about error.
344  QMessageBox *msgBox
345  = new QMessageBox (QMessageBox::Critical,
346  tr ("Octave Editor"),
347  tr ("Could not open file\n%1\nfor read: %2.").
348  arg (openFileName).arg (result),
349  QMessageBox::Ok, this);
350 
351  msgBox->setWindowModality (Qt::NonModal);
352  msgBox->setAttribute (Qt::WA_DeleteOnClose);
353  msgBox->show ();
354  }
355  else
356  {
357  // File does not exist, should it be crated?
358  QMessageBox *msgBox;
359  int answer;
360  QSettings *settings = resource_manager::get_settings ();
361  if (settings->value ("editor/create_new_file", false).toBool ())
362  {
363  answer = QMessageBox::Yes;
364  }
365  else
366  {
367  msgBox = new QMessageBox (QMessageBox::Question,
368  tr ("Octave Editor"),
369  tr ("File\n%1\ndoes not exist. "
370  "Do you want to create it?").arg (openFileName),
371  QMessageBox::Yes
372  | QMessageBox::No, this);
373 
374  msgBox->setAttribute (Qt::WA_DeleteOnClose);
375  answer = msgBox->exec ();
376  }
377 
378  if (answer == QMessageBox::Yes)
379  {
380  // create the file and call the editor again
381  QFile file (openFileName);
382  if (!file.open (QIODevice::WriteOnly))
383  {
384  // error opening the file
385  msgBox = new QMessageBox (QMessageBox::Critical,
386  tr ("Octave Editor"),
387  tr ("Could not open file\n%1\nfor write: %2.").
388  arg (openFileName).arg (file.errorString ()),
389  QMessageBox::Ok, this);
390 
391  msgBox->setWindowModality (Qt::NonModal);
392  msgBox->setAttribute (Qt::WA_DeleteOnClose);
393  msgBox->show ();
394  }
395  else
396  {
397  file.close ();
398  request_open_file (openFileName);
399  }
400  }
401  }
402  }
403  }
404 
405  // really show editor and the current editor tab
406  set_focus ();
407  emit file_loaded_signal ();
408  }
409  }
410 }
411 
412 // open a file from the mru list
413 void
414 file_editor::request_mru_open_file (QAction *action)
415 {
416  if (action)
417  {
418  request_open_file (action->data ().toString ());
419  }
420 }
421 
422 
423 void
424 file_editor::check_conflict_save (const QString& saveFileName,
425  bool remove_on_success)
426 {
427  // Have all file editor tabs signal what their file names are.
428  editor_tab_map.clear ();
429  emit fetab_file_name_query (0);
430 
431  // Check whether this file is already open in the editor.
432  QWidget *tab = find_tab_widget (saveFileName);
433 
434  if (tab)
435  {
436  // Note: to overwrite the contents of some other file editor tab
437  // with the same name requires identifying which file editor tab
438  // that is (not too difficult) then close that tab. Of course,
439  // that could trigger another dialog box if the file editor tab
440  // with the same name has modifications in it. This could become
441  // somewhat confusing to the user. For now, opt to do nothing.
442 
443  // Create a NonModal message about error.
444  QMessageBox *msgBox
445  = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"),
446  tr ("File not saved! A file with the selected name\n%1\n"
447  "is already open in the editor").
448  arg (saveFileName),
449  QMessageBox::Ok, 0);
450 
451  msgBox->setWindowModality (Qt::NonModal);
452  msgBox->setAttribute (Qt::WA_DeleteOnClose);
453  msgBox->show ();
454 
455  return;
456  }
457 
458  QObject *saveFileObject = sender ();
459  QWidget *saveFileWidget = 0;
460 
461  for (int i = 0; i < _tab_widget->count (); i++)
462  {
463  if (_tab_widget->widget (i) == saveFileObject)
464  {
465  saveFileWidget = _tab_widget->widget (i);
466  break;
467  }
468  }
469  if (!saveFileWidget)
470  {
471  // Create a NonModal message about error.
472  QMessageBox *msgBox
473  = new QMessageBox (QMessageBox::Critical, tr ("Octave Editor"),
474  tr ("The associated file editor tab has disappeared. It was likely closed by some means."),
475  QMessageBox::Ok, 0);
476 
477  msgBox->setWindowModality (Qt::NonModal);
478  msgBox->setAttribute (Qt::WA_DeleteOnClose);
479  msgBox->show ();
480 
481  return;
482  }
483 
484  // Can save without conflict, have the file editor tab do so.
485  emit fetab_save_file (saveFileWidget, saveFileName, remove_on_success);
486 }
487 
488 void
490  int line)
491 {
492  request_open_file (file, line, true);
493 }
494 
495 void
497  int line)
498 {
499  if (! file.isEmpty ())
500  {
501  // Have all file editor tabs signal what their file names are.
502  editor_tab_map.clear ();
503  emit fetab_file_name_query (0);
504 
505  // Check whether this file is already open in the editor.
506  QWidget *tab = find_tab_widget (file);
507 
508  if (tab)
509  {
510  _tab_widget->setCurrentWidget (tab);
511 
512  if (line > 0)
513  emit fetab_delete_debugger_pointer (tab, line);
514 
515  emit fetab_set_focus (tab);
516  }
517  }
518 }
519 
520 void
522  const QString& file,
523  int line)
524 {
525  request_open_file (file, line, false, true, insert);
526 }
527 
528 void
529 file_editor::handle_edit_file_request (const QString& file)
530 {
531  request_open_file (file);
532 }
533 
534 void
536 {
537  emit fetab_undo (_tab_widget->currentWidget ());
538 }
539 
540 void
542 {
543  emit fetab_redo (_tab_widget->currentWidget ());
544 }
545 
546 void
548 {
549  emit fetab_copy (_tab_widget->currentWidget ());
550 }
551 
552 void
554 {
555  emit fetab_cut (_tab_widget->currentWidget ());
556 }
557 
558 void
560 {
561  emit fetab_paste (_tab_widget->currentWidget ());
562 }
563 
564 void
566 {
567  emit fetab_context_help (_tab_widget->currentWidget (), false);
568 }
569 void
571 {
572  emit fetab_context_help (_tab_widget->currentWidget (), true);
573 }
574 
575 void
577 {
578  emit fetab_context_edit (_tab_widget->currentWidget ());
579 }
580 
581 void
583 {
584  emit fetab_save_file (_tab_widget->currentWidget ());
585 }
586 
587 void
589 {
590  emit fetab_save_file_as (_tab_widget->currentWidget ());
591 }
592 
593 void
595 {
596  emit fetab_print_file (_tab_widget->currentWidget ());
597 }
598 
599 
600 void
602 {
603  emit fetab_run_file (_tab_widget->currentWidget ());
604 }
605 
606 void
608 {
609  emit fetab_context_run (_tab_widget->currentWidget ());
610 }
611 
612 void
614 {
615  emit fetab_toggle_bookmark (_tab_widget->currentWidget ());
616 }
617 
618 void
620 {
621  emit fetab_next_bookmark (_tab_widget->currentWidget ());
622 }
623 
624 void
626 {
627  emit fetab_previous_bookmark (_tab_widget->currentWidget ());
628 }
629 
630 void
632 {
633  emit fetab_remove_bookmark (_tab_widget->currentWidget ());
634 }
635 
636 void
638 {
639  emit fetab_toggle_breakpoint (_tab_widget->currentWidget ());
640 }
641 
642 void
644 {
645  emit fetab_next_breakpoint (_tab_widget->currentWidget ());
646 }
647 
648 void
650 {
651  emit fetab_previous_breakpoint (_tab_widget->currentWidget ());
652 }
653 
654 void
656 {
657  emit fetab_remove_all_breakpoints (_tab_widget->currentWidget ());
658 }
659 
660 void
662 {
663  emit fetab_comment_selected_text (_tab_widget->currentWidget ());
664 }
665 
666 void
668 {
669  emit fetab_uncomment_selected_text (_tab_widget->currentWidget ());
670 }
671 
672 void
674 {
675  emit fetab_find (_tab_widget->currentWidget ());
676 }
677 
678 void
680 {
681  emit fetab_goto_line (_tab_widget->currentWidget ());
682 }
683 
684 
685 void
686 file_editor::handle_mru_add_file (const QString& file_name)
687 {
688  _mru_files.removeAll (file_name);
689  _mru_files.prepend (file_name);
690  mru_menu_update ();
691 }
692 
693 void
695 {
696  int num_files = qMin (_mru_files.size (), int (MaxMRUFiles));
697 
698  // configure and show active actions of mru-menu
699  for (int i = 0; i < num_files; ++i)
700  {
701  QString text = tr ("&%1 %2").
702  arg ((i+1) % int (MaxMRUFiles)).arg (_mru_files.at (i));
703  _mru_file_actions[i]->setText (text);
704  _mru_file_actions[i]->setData (_mru_files.at (i));
705  _mru_file_actions[i]->setVisible (true);
706  }
707 
708  // hide unused mru-menu entries
709  for (int j = num_files; j < MaxMRUFiles; ++j)
710  _mru_file_actions[j]->setVisible (false);
711 
712  // delete entries in string-list beyond MaxMRUFiles
713  while (_mru_files.size () > MaxMRUFiles)
714  _mru_files.removeLast ();
715 
716  // save actual mru-list in settings
717  QSettings *settings = resource_manager::get_settings ();
718 
719  // FIXME: what should happen if settings is 0?
720  settings->setValue ("editor/mru_file_list", _mru_files);
721  settings->sync ();
722 }
723 
724 void
725 file_editor::handle_file_name_changed (const QString& fname,
726  const QString& tip)
727 {
728  QObject *fileEditorTab = sender ();
729  if (fileEditorTab)
730  {
731  for (int i = 0; i < _tab_widget->count (); i++)
732  {
733  if (_tab_widget->widget (i) == fileEditorTab)
734  {
735  _tab_widget->setTabText (i, fname);
736  _tab_widget->setTabToolTip (i, tip);
737  }
738  }
739  }
740 }
741 
742 void
744 {
745  emit fetab_close_request (_tab_widget->currentWidget ());
746 }
747 
748 void
750 {
751  // loop over all tabs starting from last one otherwise deletion changes index
752  for (int index = _tab_widget->count ()-1; index >= 0; index--)
753  emit fetab_close_request (_tab_widget->widget (index));
754 }
755 
756 void
758 {
759  QWidget *tabID = _tab_widget->currentWidget ();
760  // loop over all tabs starting from last one otherwise deletion changes index
761  for (int index = _tab_widget->count ()-1; index >= 0; index--)
762  {
763  if (tabID != _tab_widget->widget (index))
764  emit fetab_close_request (_tab_widget->widget (index));
765  }
766 }
767 
768 
769 void
771 {
772  // Signal to the tabs a request to close whomever matches the identifying
773  // tag (i.e., unique widget pointer). The reason for this indirection is
774  // that it will enable a file editor widget to toss up a non-static
775  // dialog box and later signal that it wants to be removed.
776  QWidget *tabID = _tab_widget->widget (index);
777  emit fetab_close_request (tabID);
778 }
779 
780 void
782 {
783  QObject *fileEditorTab = sender ();
784  if (fileEditorTab)
785  {
786  for (int i = 0; i < _tab_widget->count (); i++)
787  {
788  if (_tab_widget->widget (i) == fileEditorTab)
789  {
790  _tab_widget->removeTab (i);
791  delete fileEditorTab;
792  break;
793  }
794  }
795  }
796  check_actions ();
797 }
798 
799 void
800 file_editor::handle_add_filename_to_list (const QString& fileName, QWidget *ID)
801 {
802  // Should we allow multiple tabs for a single file?
803 
804  editor_tab_map[fileName] = ID;
805 }
806 
807 void
809 {
810  emit fetab_change_request (_tab_widget->widget (index));
811 }
812 
813 void
814 file_editor::handle_editor_state_changed (bool copy_available,
815  const QString& file_name)
816 {
817  // In case there is some scenario where traffic could be coming from
818  // all the file editor tabs, just process info from the current active tab.
819  if (sender () == _tab_widget->currentWidget ())
820  {
821  _copy_action->setEnabled (copy_available);
822  _cut_action->setEnabled (copy_available);
823  _context_run_action->setEnabled (copy_available);
824 
825  if (!file_name.isEmpty ())
826  {
827  ced = QDir::cleanPath (file_name);
828  int lastslash = ced.lastIndexOf ('/');
829 
830  // Test against > 0 because if somehow the directory is "/" the
831  // slash should be retained. Otherwise, last slash is removed.
832  if (lastslash > 0 && lastslash != ced.count ())
833  ced = ced.left (lastslash);
834  }
835 
836  setFocusProxy (_tab_widget->currentWidget ());
837  }
838 }
839 
840 void
841 file_editor::notice_settings (const QSettings *settings)
842 {
843  int icon_size = settings->value ("toolbar_icon_size", 16).toInt ();
844  _tool_bar->setIconSize (QSize (icon_size, icon_size));
845  // Relay signal to file editor tabs.
846  emit fetab_settings_changed (settings);
847 }
848 
849 void
851 {
852  emit request_settings_dialog ("editor");
853 }
854 
855 void
857 {
858  emit request_settings_dialog ("editor_styles");
859 }
860 
861 void
863 {
864  QWidget *editor_widget = new QWidget (this);
865 
866  // FIXME: what was the intended purpose of this unused variable?
867  // QStyle *editor_style = QApplication::style ();
868 
869  _menu_bar = new QMenuBar (editor_widget);
870  _tool_bar = new QToolBar (editor_widget);
871  _tool_bar->setMovable (true);
872  _tab_widget = new QTabWidget (editor_widget);
873  _tab_widget->setTabsClosable (true);
874 
875  QAction *new_action = new QAction (QIcon (":/actions/icons/filenew.png"),
876  tr ("&New File"), _tool_bar);
877 
878  QAction *open_action = new QAction (QIcon (":/actions/icons/fileopen.png"),
879  tr ("&Open File"), _tool_bar);
880 
881  _save_action = new QAction (QIcon (":/actions/icons/filesave.png"),
882  tr ("&Save File"), _tool_bar);
883 
884  _save_as_action = new QAction (QIcon (":/actions/icons/filesaveas.png"),
885  tr ("Save File &As"), _tool_bar);
886 
887  _print_action = new QAction ( QIcon (":/actions/icons/fileprint.png"),
888  tr ("Print"), _tool_bar);
889 
890  _undo_action = new QAction (QIcon (":/actions/icons/undo.png"),
891  tr ("&Undo"), _tool_bar);
892 
893  _redo_action = new QAction (QIcon (":/actions/icons/redo.png"),
894  tr ("&Redo"), _tool_bar);
895 
896  _copy_action = new QAction (QIcon (":/actions/icons/editcopy.png"),
897  tr ("&Copy"), _tool_bar);
898  _copy_action->setEnabled (false);
899 
900  _cut_action = new QAction (QIcon (":/actions/icons/editcut.png"),
901  tr ("Cu&t"), _tool_bar);
902  _cut_action->setEnabled (false);
903 
905  = new QAction (QIcon (":/actions/icons/editpaste.png"),
906  tr ("Paste"), _tool_bar);
907 
908  _next_bookmark_action = new QAction (tr ("&Next Bookmark"), _tool_bar);
909 
910  _previous_bookmark_action = new QAction (tr ("Pre&vious Bookmark"),
911  _tool_bar);
912 
913  _toggle_bookmark_action = new QAction (tr ("Toggle &Bookmark"), _tool_bar);
914 
916  = new QAction (tr ("&Remove All Bookmarks"), _tool_bar);
917 
918  QAction *next_breakpoint_action
919  = new QAction (QIcon (":/actions/icons/bp_next.png"),
920  tr ("&Next Breakpoint"), _tool_bar);
921  QAction *previous_breakpoint_action
922  = new QAction (QIcon (":/actions/icons/bp_prev.png"),
923  tr ("Pre&vious Breakpoint"), _tool_bar);
924  QAction *toggle_breakpoint_action
925  = new QAction (QIcon (":/actions/icons/bp_toggle.png"),
926  tr ("Toggle &Breakpoint"), _tool_bar);
927  QAction *remove_all_breakpoints_action
928  = new QAction (QIcon (":/actions/icons/bp_rm_all.png"),
929  tr ("&Remove All Breakpoints"), _tool_bar);
930 
932  = new QAction (tr ("&Comment"), _tool_bar);
934  = new QAction (tr ("&Uncomment"), _tool_bar);
935 
936  _find_action = new QAction (QIcon (":/actions/icons/search.png"),
937  tr ("&Find and Replace"), _tool_bar);
938 
939  _run_action = new QAction (QIcon (":/actions/icons/artsbuilderexecute.png"),
940  tr ("Save File and Run"), _tool_bar);
941 
942  _goto_line_action = new QAction (tr ("Go&to Line"), _tool_bar);
943 
944  // the mru-list and an empty array of actions
945  QSettings *settings = resource_manager::get_settings ();
946  // FIXME: what should happen if settings is 0?
947  _mru_files = settings->value ("editor/mru_file_list").toStringList ();
948  for (int i = 0; i < MaxMRUFiles; ++i)
949  {
950  _mru_file_actions[i] = new QAction (this);
951  _mru_file_actions[i]->setVisible (false);
952  }
953 
954  // some actions are disabled from the beginning
955  _copy_action->setEnabled (false);
956  _cut_action->setEnabled (false);
957 
958  _run_action->setShortcutContext (Qt::WindowShortcut);
959  _save_action->setShortcutContext (Qt::WindowShortcut);
960  _save_as_action->setShortcutContext (Qt::WindowShortcut);
961 
962  _print_action->setShortcutContext (Qt::WindowShortcut);
963 
964  _next_bookmark_action->setShortcutContext (Qt::WindowShortcut);
965  _previous_bookmark_action->setShortcutContext (Qt::WindowShortcut);
966  _toggle_bookmark_action->setShortcutContext (Qt::WindowShortcut);
967  _comment_selection_action->setShortcutContext (Qt::WindowShortcut);
968  _uncomment_selection_action->setShortcutContext (Qt::WindowShortcut);
969  _find_action->setShortcutContext (Qt::WindowShortcut);
970  _goto_line_action->setShortcutContext (Qt::WindowShortcut);
971 
972  // toolbar
973  _tool_bar->addAction (new_action);
974  _tool_bar->addAction (open_action);
975  _tool_bar->addAction (_save_action);
976  _tool_bar->addAction (_save_as_action);
977  _tool_bar->addSeparator ();
978  _tool_bar->addAction (_print_action);
979  _tool_bar->addSeparator ();
980  _tool_bar->addAction (_undo_action);
981  _tool_bar->addAction (_redo_action);
982  _tool_bar->addAction (_copy_action);
983  _tool_bar->addAction (_cut_action);
984  _tool_bar->addAction (_paste_action);
985  _tool_bar->addSeparator ();
986  _tool_bar->addAction (_find_action);
987  _tool_bar->addAction (_run_action);
988  _tool_bar->addSeparator ();
989  _tool_bar->addAction (toggle_breakpoint_action);
990  _tool_bar->addAction (next_breakpoint_action);
991  _tool_bar->addAction (previous_breakpoint_action);
992  _tool_bar->addAction (remove_all_breakpoints_action);
993 
994  // menu bar
995  QMenu *fileMenu = new QMenu (tr ("&File"), _menu_bar);
996 
997  _mru_file_menu = new QMenu (tr ("&Recent Editor Files"), fileMenu);
998  for (int i = 0; i < MaxMRUFiles; ++i)
999  _mru_file_menu->addAction (_mru_file_actions[i]);
1000 
1001  fileMenu->addAction (new_action);
1002  fileMenu->addAction (QIcon (), tr ("New &Function"),
1003  this, SLOT (request_new_function (bool)));
1004  fileMenu->addAction (open_action);
1005  fileMenu->addMenu (_mru_file_menu);
1006  fileMenu->addSeparator ();
1008  fileMenu->addAction (QIcon (), tr ("&Edit Function"),
1009  this, SLOT (request_context_edit (bool)));
1010  fileMenu->addSeparator ();
1011  fileMenu->addAction (_save_action);
1012  fileMenu->addAction (_save_as_action);
1013 
1014  fileMenu->addSeparator ();
1015  _close_action =
1016  fileMenu->addAction (QIcon::fromTheme("window-close",
1017  QIcon (":/actions/icons/fileclose.png")),
1018  tr ("&Close"), this, SLOT (request_close_file (bool)));
1020  fileMenu->addAction (QIcon::fromTheme("window-close",
1021  QIcon (":/actions/icons/fileclose.png")),
1022  tr ("Close All"),
1023  this, SLOT (request_close_all_files (bool)));
1025  fileMenu->addAction (QIcon::fromTheme("window-close",
1026  QIcon (":/actions/icons/fileclose.png")),
1027  tr ("Close Other Files"),
1028  this, SLOT (request_close_other_files (bool)));
1029 
1030  fileMenu->addSeparator ();
1031  fileMenu->addAction (_print_action);
1032 
1033  _menu_bar->addMenu (fileMenu);
1034 
1035 
1036  QMenu *editMenu = new QMenu (tr ("&Edit"), _menu_bar);
1037  editMenu->addAction (_undo_action);
1038  editMenu->addAction (_redo_action);
1039  editMenu->addSeparator ();
1040  editMenu->addAction (_copy_action);
1041  editMenu->addAction (_cut_action);
1042  editMenu->addAction (_paste_action);
1043  editMenu->addSeparator ();
1044  editMenu->addAction (_find_action);
1045  editMenu->addSeparator ();
1046  editMenu->addAction (_comment_selection_action);
1047  editMenu->addAction (_uncomment_selection_action);
1048  editMenu->addSeparator ();
1049  editMenu->addAction (_toggle_bookmark_action);
1050  editMenu->addAction (_next_bookmark_action);
1051  editMenu->addAction (_previous_bookmark_action);
1052  editMenu->addAction (_remove_bookmark_action);
1053  editMenu->addSeparator ();
1054  editMenu->addAction (_goto_line_action);
1055  editMenu->addSeparator ();
1057  editMenu->addAction (QIcon (":/actions/icons/configure.png"),
1058  tr ("&Preferences"),
1059  this, SLOT (request_preferences (bool)));
1061  editMenu->addAction (QIcon (":/actions/icons/configure.png"),
1062  tr ("&Styles Preferences"),
1063  this, SLOT (request_styles_preferences (bool)));
1064  _menu_bar->addMenu (editMenu);
1065 
1066  _debug_menu = new QMenu (tr ("&Debug"), _menu_bar);
1067  _debug_menu->addAction (toggle_breakpoint_action);
1068  _debug_menu->addAction (next_breakpoint_action);
1069  _debug_menu->addAction (previous_breakpoint_action);
1070  _debug_menu->addAction (remove_all_breakpoints_action);
1071  _debug_menu->addSeparator ();
1072  // The other debug actions will be added by the main window.
1073  _menu_bar->addMenu (_debug_menu);
1074 
1075  QMenu *_run_menu = new QMenu (tr ("&Run"), _menu_bar);
1076  _run_menu->addAction (_run_action);
1078  _run_menu->addAction (QIcon (), tr ("Run &Selection"),
1079  this, SLOT (request_context_run (bool)));
1080  _context_run_action->setEnabled (false);
1081  _menu_bar->addMenu (_run_menu);
1082 
1083  QMenu *_help_menu = new QMenu (tr ("&Help"), _menu_bar);
1085  _help_menu->addAction (QIcon (), tr ("&Help on Keyword"),
1086  this, SLOT (request_context_help (bool)));
1088  _help_menu->addAction (QIcon (), tr ("&Documentation on Keyword"),
1089  this, SLOT (request_context_doc (bool)));
1090  _menu_bar->addMenu (_help_menu);
1091 
1092  // shortcuts
1093  set_shortcuts (true);
1094 
1095  // layout
1096  QVBoxLayout *vbox_layout = new QVBoxLayout ();
1097  vbox_layout->addWidget (_menu_bar);
1098  vbox_layout->addWidget (_tool_bar);
1099  vbox_layout->addWidget (_tab_widget);
1100  vbox_layout->setMargin (0);
1101  editor_widget->setLayout (vbox_layout);
1102  setWidget (editor_widget);
1103 
1104  // signals
1105  connect (this, SIGNAL (request_settings_dialog (const QString&)),
1106  main_win (),
1107  SLOT (process_settings_dialog_request (const QString&)));
1108 
1109  connect (main_win (), SIGNAL (new_file_signal (const QString&)),
1110  this, SLOT (request_new_file (const QString&)));
1111 
1112  connect (main_win (), SIGNAL (open_file_signal (const QString&)),
1113  this, SLOT (request_open_file (const QString&)));
1114 
1115  connect (new_action, SIGNAL (triggered ()),
1116  this, SLOT (request_new_file ()));
1117 
1118  connect (open_action, SIGNAL (triggered ()),
1119  this, SLOT (request_open_file ()));
1120 
1121  connect (_undo_action, SIGNAL (triggered ()),
1122  this, SLOT (request_undo ()));
1123 
1124  connect (_redo_action, SIGNAL (triggered ()),
1125  this, SLOT (request_redo ()));
1126 
1127  connect (_copy_action, SIGNAL (triggered ()),
1128  this, SLOT (request_copy ()));
1129 
1130  connect (_cut_action, SIGNAL (triggered ()),
1131  this, SLOT (request_cut ()));
1132 
1133  connect (_paste_action, SIGNAL (triggered ()),
1134  this, SLOT (request_paste ()));
1135 
1136  connect (_save_action, SIGNAL (triggered ()),
1137  this, SLOT (request_save_file ()));
1138 
1139  connect (_save_as_action, SIGNAL (triggered ()),
1140  this, SLOT (request_save_file_as ()));
1141 
1142  connect (_print_action, SIGNAL (triggered ()),
1143  this, SLOT (request_print_file ()));
1144 
1145  connect (_run_action, SIGNAL (triggered ()),
1146  this, SLOT (request_run_file ()));
1147 
1148  connect (_toggle_bookmark_action, SIGNAL (triggered ()),
1149  this, SLOT (request_toggle_bookmark ()));
1150 
1151  connect (_next_bookmark_action, SIGNAL (triggered ()),
1152  this, SLOT (request_next_bookmark ()));
1153 
1154  connect (_previous_bookmark_action, SIGNAL (triggered ()),
1155  this, SLOT (request_previous_bookmark ()));
1156 
1157  connect (_remove_bookmark_action, SIGNAL (triggered ()),
1158  this, SLOT (request_remove_bookmark ()));
1159 
1160  connect (toggle_breakpoint_action, SIGNAL (triggered ()),
1161  this, SLOT (request_toggle_breakpoint ()));
1162 
1163  connect (next_breakpoint_action, SIGNAL (triggered ()),
1164  this, SLOT (request_next_breakpoint ()));
1165 
1166  connect (previous_breakpoint_action, SIGNAL (triggered ()),
1167  this, SLOT (request_previous_breakpoint ()));
1168 
1169  connect (remove_all_breakpoints_action, SIGNAL (triggered ()),
1170  this, SLOT (request_remove_breakpoint ()));
1171 
1172  connect (_comment_selection_action, SIGNAL (triggered ()),
1173  this, SLOT (request_comment_selected_text ()));
1174 
1175  connect (_uncomment_selection_action, SIGNAL (triggered ()),
1176  this, SLOT (request_uncomment_selected_text ()));
1177 
1178  connect (_find_action, SIGNAL (triggered ()),
1179  this, SLOT (request_find ()));
1180 
1181  connect (_goto_line_action, SIGNAL (triggered ()),
1182  this, SLOT (request_goto_line ()));
1183 
1184  connect (_mru_file_menu, SIGNAL (triggered (QAction *)),
1185  this, SLOT (request_mru_open_file (QAction *)));
1186 
1187  mru_menu_update ();
1188 
1189  connect (_tab_widget, SIGNAL (tabCloseRequested (int)),
1190  this, SLOT (handle_tab_close_request (int)));
1191 
1192  connect (_tab_widget, SIGNAL (currentChanged (int)),
1193  this, SLOT (active_tab_changed (int)));
1194 
1195  connect (this, SIGNAL (execute_command_in_terminal_signal (const QString&)),
1196  main_win (), SLOT (execute_command_in_terminal (const QString&)));
1197 
1198  resize (500, 400);
1199  setWindowIcon (QIcon (":/actions/icons/logo.png"));
1200  set_title ("Editor");
1201 
1202  //restore previous session
1203  if (settings->value ("editor/restoreSession", true).toBool ())
1204  {
1205  QStringList sessionFileNames
1206  = settings->value ("editor/savedSessionTabs",
1207  QStringList ()).toStringList ();
1208 
1209  for (int n = 0; n < sessionFileNames.count (); ++n)
1210  request_open_file (sessionFileNames.at (n));
1211  }
1212 
1213  check_actions ();
1214 }
1215 
1216 void
1218 {
1219  _tab_widget->addTab (f, fn);
1220 
1221  // Signals from the file editor_tab
1222  connect (f, SIGNAL (file_name_changed (const QString&, const QString&)),
1223  this, SLOT (handle_file_name_changed (const QString&,
1224  const QString&)));
1225 
1226  connect (f, SIGNAL (editor_state_changed (bool, const QString&)),
1227  this, SLOT (handle_editor_state_changed (bool, const QString&)));
1228 
1229  connect (f, SIGNAL (tab_remove_request ()),
1230  this, SLOT (handle_tab_remove_request ()));
1231 
1232  connect (f, SIGNAL (add_filename_to_list (const QString&, QWidget*)),
1233  this, SLOT (handle_add_filename_to_list (const QString&, QWidget*)));
1234 
1235  connect (f, SIGNAL (editor_check_conflict_save (const QString&, bool)),
1236  this, SLOT (check_conflict_save (const QString&, bool)));
1237 
1238  connect (f, SIGNAL (mru_add_file (const QString&)),
1239  this, SLOT (handle_mru_add_file (const QString&)));
1240 
1241  connect (f, SIGNAL (run_file_signal (const QFileInfo&)),
1242  main_win (), SLOT (run_file_in_terminal (const QFileInfo&)));
1243 
1244  connect (f, SIGNAL (execute_command_in_terminal_signal (const QString&)),
1245  main_win (), SLOT (execute_command_in_terminal (const QString&)));
1246 
1247  // Signals from the file_editor non-trivial operations
1248  connect (this, SIGNAL (fetab_settings_changed (const QSettings *)),
1249  f, SLOT (notice_settings (const QSettings *)));
1250 
1251  connect (this, SIGNAL (fetab_close_request (const QWidget*,bool)),
1252  f, SLOT (conditional_close (const QWidget*,bool)));
1253 
1254  connect (this, SIGNAL (fetab_change_request (const QWidget*)),
1255  f, SLOT (change_editor_state (const QWidget*)));
1256 
1257  connect (this, SIGNAL (fetab_file_name_query (const QWidget*)),
1258  f, SLOT (file_name_query (const QWidget*)));
1259 
1260  connect (this, SIGNAL (fetab_save_file (const QWidget*, const QString&,
1261  bool)),
1262  f, SLOT (save_file (const QWidget*, const QString&, bool)));
1263 
1264  // Signals from the file_editor trivial operations
1265  connect (this, SIGNAL (fetab_undo (const QWidget*)),
1266  f, SLOT (undo (const QWidget*)));
1267 
1268  connect (this, SIGNAL (fetab_redo (const QWidget*)),
1269  f, SLOT (redo (const QWidget*)));
1270 
1271  connect (this, SIGNAL (fetab_copy (const QWidget*)),
1272  f, SLOT (copy (const QWidget*)));
1273 
1274  connect (this, SIGNAL (fetab_cut (const QWidget*)),
1275  f, SLOT (cut (const QWidget*)));
1276 
1277  connect (this, SIGNAL (fetab_paste (const QWidget*)),
1278  f, SLOT (paste (const QWidget*)));
1279 
1280  connect (this, SIGNAL (fetab_context_help (const QWidget*, bool)),
1281  f, SLOT (context_help (const QWidget*, bool)));
1282 
1283  connect (this, SIGNAL (fetab_context_edit (const QWidget*)),
1284  f, SLOT (context_edit (const QWidget*)));
1285 
1286  connect (this, SIGNAL (fetab_save_file (const QWidget*)),
1287  f, SLOT (save_file (const QWidget*)));
1288 
1289  connect (this, SIGNAL (fetab_save_file_as (const QWidget*)),
1290  f, SLOT (save_file_as (const QWidget*)));
1291 
1292  connect (this, SIGNAL (fetab_print_file (const QWidget*)),
1293  f, SLOT (print_file (const QWidget*)));
1294 
1295  connect (this, SIGNAL (fetab_run_file (const QWidget*)),
1296  f, SLOT (run_file (const QWidget*)));
1297 
1298  connect (this, SIGNAL (fetab_context_run (const QWidget*)),
1299  f, SLOT (context_run (const QWidget*)));
1300 
1301  connect (this, SIGNAL (fetab_toggle_bookmark (const QWidget*)),
1302  f, SLOT (toggle_bookmark (const QWidget*)));
1303 
1304  connect (this, SIGNAL (fetab_next_bookmark (const QWidget*)),
1305  f, SLOT (next_bookmark (const QWidget*)));
1306 
1307  connect (this, SIGNAL (fetab_previous_bookmark (const QWidget*)),
1308  f, SLOT (previous_bookmark (const QWidget*)));
1309 
1310  connect (this, SIGNAL (fetab_remove_bookmark (const QWidget*)),
1311  f, SLOT (remove_bookmark (const QWidget*)));
1312 
1313  connect (this, SIGNAL (fetab_toggle_breakpoint (const QWidget*)),
1314  f, SLOT (toggle_breakpoint (const QWidget*)));
1315 
1316  connect (this, SIGNAL (fetab_next_breakpoint (const QWidget*)),
1317  f, SLOT (next_breakpoint (const QWidget*)));
1318 
1319  connect (this, SIGNAL (fetab_previous_breakpoint (const QWidget*)),
1320  f, SLOT (previous_breakpoint (const QWidget*)));
1321 
1322  connect (this, SIGNAL (fetab_remove_all_breakpoints (const QWidget*)),
1323  f, SLOT (remove_all_breakpoints (const QWidget*)));
1324 
1325  connect (this, SIGNAL (fetab_comment_selected_text (const QWidget*)),
1326  f, SLOT (comment_selected_text (const QWidget*)));
1327 
1328  connect (this, SIGNAL (fetab_uncomment_selected_text (const QWidget*)),
1329  f, SLOT (uncomment_selected_text (const QWidget*)));
1330 
1331  connect (this, SIGNAL (fetab_find (const QWidget*)),
1332  f, SLOT (find (const QWidget*)));
1333 
1334  connect (this, SIGNAL (fetab_goto_line (const QWidget*, int)),
1335  f, SLOT (goto_line (const QWidget*, int)));
1336 
1337  connect (this, SIGNAL (fetab_set_focus (const QWidget*)),
1338  f, SLOT (set_focus (const QWidget*)));
1339 
1340  connect (this, SIGNAL (fetab_insert_debugger_pointer (const QWidget*, int)),
1341  f, SLOT (insert_debugger_pointer (const QWidget*, int)));
1342 
1343  connect (this, SIGNAL (fetab_delete_debugger_pointer (const QWidget*, int)),
1344  f, SLOT (delete_debugger_pointer (const QWidget*, int)));
1345 
1346  connect (this, SIGNAL (fetab_do_breakpoint_marker (bool, const QWidget*,
1347  int)),
1348  f, SLOT (do_breakpoint_marker (bool, const QWidget*, int)));
1349 
1350  _tab_widget->setCurrentWidget (f);
1351 
1352  check_actions ();
1353 }
1354 
1355 void
1357 {
1358  QWidget * foc_w = focusWidget ();
1359 
1360  if (foc_w && foc_w->inherits ("octave_qscintilla"))
1361  {
1362  request_copy ();
1363  }
1364 }
1365 void
1367 {
1368  QWidget * foc_w = focusWidget ();
1369 
1370  if (foc_w && foc_w->inherits ("octave_qscintilla"))
1371  {
1372  request_paste ();
1373  }
1374 }
1375 
1376 void
1377 file_editor::set_shortcuts (bool set)
1378 {
1379  if (set)
1380  {
1381  _comment_selection_action->setShortcut (Qt::ControlModifier + Qt::Key_R);
1382  _uncomment_selection_action->setShortcut (Qt::SHIFT
1383  + Qt::ControlModifier
1384  + Qt::Key_R);
1385 
1386  _copy_action->setShortcut (QKeySequence::Copy);
1387  _cut_action->setShortcut (QKeySequence::Cut);
1388  _paste_action->setShortcut (QKeySequence::Paste);
1389  _context_help_action->setShortcut (QKeySequence::HelpContents);
1390  _context_doc_action->setShortcut (Qt::SHIFT + Qt::Key_F1);
1391 
1392  _find_action->setShortcut (QKeySequence::Find);
1393  _goto_line_action->setShortcut (Qt::ControlModifier+ Qt::Key_G);
1394 
1395  _next_bookmark_action->setShortcut (Qt::Key_F2);
1396  _previous_bookmark_action->setShortcut (Qt::SHIFT + Qt::Key_F2);
1397  _toggle_bookmark_action->setShortcut (Qt::Key_F7);
1398 
1399  _print_action->setShortcut (QKeySequence::Print);
1400  _run_action->setShortcut (Qt::Key_F5);
1401  _context_run_action->setShortcut (Qt::Key_F9);
1402 
1403  _context_edit_action->setShortcut (Qt::ControlModifier + Qt::Key_E);
1404  _save_action->setShortcut (QKeySequence::Save);
1405  _save_as_action->setShortcut (QKeySequence::SaveAs);
1406  _close_action->setShortcut (QKeySequence::Close);
1407 
1408  _redo_action->setShortcut (QKeySequence::Redo);
1409  _undo_action->setShortcut (QKeySequence::Undo);
1410  }
1411  else
1412  {
1413  QKeySequence no_key = QKeySequence ();
1414 
1415  _comment_selection_action->setShortcut (no_key);
1416  _uncomment_selection_action->setShortcut (no_key);
1417 
1418  _copy_action->setShortcut (no_key);
1419  _cut_action->setShortcut (no_key);
1420  _paste_action->setShortcut (no_key);
1421  _context_help_action->setShortcut (no_key);
1422 
1423  _find_action->setShortcut (no_key);
1424  _goto_line_action->setShortcut (no_key);
1425 
1426  _next_bookmark_action->setShortcut (no_key);
1427  _previous_bookmark_action->setShortcut (no_key);
1428  _toggle_bookmark_action->setShortcut (no_key);
1429 
1430  _print_action->setShortcut (no_key);
1431  _run_action->setShortcut (no_key);
1432  _context_run_action->setShortcut (no_key);
1433 
1434  _context_edit_action->setShortcut (no_key);
1435  _save_action->setShortcut (no_key);
1436  _save_as_action->setShortcut (no_key);
1437  _close_action->setShortcut (no_key);
1438 
1439  _redo_action->setShortcut (no_key);
1440  _undo_action->setShortcut (no_key);
1441  }
1442 }
1443 
1444 void
1446 {
1447  bool have_tabs = _tab_widget->count () > 0;
1448 
1449  _comment_selection_action->setEnabled (have_tabs);
1450  _uncomment_selection_action->setEnabled (have_tabs);
1451 
1452  _paste_action->setEnabled (have_tabs);
1453  _context_help_action->setEnabled (have_tabs);
1454  _context_doc_action->setEnabled (have_tabs);
1455 
1456  _find_action->setEnabled (have_tabs);
1457  _goto_line_action->setEnabled (have_tabs);
1458 
1459  _next_bookmark_action->setEnabled (have_tabs);
1460  _previous_bookmark_action->setEnabled (have_tabs);
1461  _toggle_bookmark_action->setEnabled (have_tabs);
1462  _remove_bookmark_action->setEnabled (have_tabs);
1463 
1464  _print_action->setEnabled (have_tabs);
1465  _run_action->setEnabled (have_tabs);
1466 
1467  _context_edit_action->setEnabled (have_tabs);
1468  _save_action->setEnabled (have_tabs);
1469  _save_as_action->setEnabled (have_tabs);
1470  _close_action->setEnabled (have_tabs);
1471  _close_all_action->setEnabled (have_tabs);
1472  _close_others_action->setEnabled (have_tabs && _tab_widget->count () > 1);
1473 
1474  _undo_action->setEnabled (have_tabs);
1475  _redo_action->setEnabled (have_tabs);
1476 }
1477 
1478 
1479 #endif