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
main-window.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2013 John W. Eaton
4 Copyright (C) 2011-2013 Jacob Dawid
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <QKeySequence>
29 #include <QApplication>
30 #include <QLabel>
31 #include <QMenuBar>
32 #include <QMenu>
33 #include <QAction>
34 #include <QSettings>
35 #include <QStyle>
36 #include <QToolBar>
37 #include <QDesktopServices>
38 #include <QDesktopWidget>
39 #include <QFileDialog>
40 #include <QMessageBox>
41 #include <QIcon>
42 #include <QTextStream>
43 #include <QThread>
44 #include <QDateTime>
45 #include <QDebug>
46 
47 #include <utility>
48 
49 #ifdef HAVE_QSCINTILLA
50 #include "file-editor.h"
51 #endif
52 #include "main-window.h"
53 #include "settings-dialog.h"
54 
55 #include "Array.h"
56 #include "cmd-edit.h"
57 #include "url-transfer.h"
58 
59 #include "builtin-defun-decls.h"
60 #include "defaults.h"
61 #include "symtab.h"
62 #include "version.h"
63 
64 static file_editor_interface *
66 {
67 #ifdef HAVE_QSCINTILLA
68  return new file_editor (p);
69 #else
70  return 0;
71 #endif
72 }
73 
75  : QMainWindow (p),
76  _workspace_model (new workspace_model ()),
77  status_bar (new QStatusBar ()),
78  command_window (new terminal_dock_widget (this)),
79  history_window (new history_dock_widget (this)),
80  file_browser_window (new files_dock_widget (this)),
81  doc_browser_window (new documentation_dock_widget (this)),
82  editor_window (create_default_editor (this)),
83  workspace_window (new workspace_view (this)),
84  find_files_dlg (0),
85  release_notes_window (0),
86  community_news_window (0),
87  _octave_qt_link (0),
88  _clipboard (QApplication::clipboard ()),
89  _cmd_queue (new QStringList ()), // no command pending
90  _cmd_processing (1),
91  _cmd_queue_mutex ()
92 {
93  QSettings *settings = resource_manager::get_settings ();
94 
95  bool connect_to_web = true;
96  QDateTime last_checked;
97  int serial = 0;
98 
99  if (settings)
100  {
101  connect_to_web
102  = settings->value ("news/allow_web_connection", true).toBool ();
103 
104  last_checked
105  = settings->value ("news/last_time_checked", QDateTime ()).toDateTime ();
106 
107  serial = settings->value ("news/last_news_item", 0).toInt ();
108  }
109 
110  QDateTime current = QDateTime::currentDateTime ();
111  QDateTime one_day_ago = current.addDays (-1);
112 
113  if (connect_to_web
114  && (! last_checked.isValid () || one_day_ago > last_checked))
116 
117  // We have to set up all our windows, before we finally launch octave.
118  construct ();
119 }
120 
122 {
123  // Destroy the terminal first so that STDERR stream is redirected back
124  // to its original pipe to capture error messages at exit.
125 
126  delete editor_window; // first one for dialogs of modified editor-tabs
127  delete command_window;
128  delete workspace_window;
129  delete doc_browser_window;
130  delete file_browser_window;
131  delete history_window;
132  delete status_bar;
133  delete _workspace_model;
134  if (find_files_dlg)
135  {
136  delete find_files_dlg;
137  find_files_dlg = 0;
138  }
140  {
141  delete release_notes_window;
143  }
145  {
146  delete community_news_window;
148  }
149  delete _octave_qt_link;
150  delete _cmd_queue;
151 }
152 
153 bool
155 {
156  return command_window->has_focus ();
157 }
158 
159 void
161 {
162  command_window->focus ();
163 }
164 
165 void
166 main_window::new_file (const QString& commands)
167 {
168  emit new_file_signal (commands);
169 }
170 
171 void
172 main_window::open_file (const QString& file_name)
173 {
174  emit open_file_signal (file_name);
175 }
176 
177 void
178 main_window::report_status_message (const QString& statusMessage)
179 {
180  status_bar->showMessage (statusMessage, 1000);
181 }
182 
183 void
185 {
186  QString file =
187  QFileDialog::getSaveFileName (this, tr ("Save Workspace As"), ".", 0, 0,
188  QFileDialog::DontUseNativeDialog);
189 
190  if (! file.isEmpty ())
192  file.toStdString ());
193 }
194 
195 void
197 {
198  QString file = file_arg;
199 
200  if (file.isEmpty ())
201  file = QFileDialog::getOpenFileName (this, tr ("Load Workspace"), ".", 0, 0,
202  QFileDialog::DontUseNativeDialog);
203 
204  if (! file.isEmpty ())
206  file.toStdString ());
207 }
208 
209 void
211 {
213 }
214 
215 void
217  const QString& new_name)
218 
219 {
220  name_pair names (old_name.toStdString (), new_name.toStdString ());
221 
223  names);
224 }
225 
226 void
228 {
230 }
231 
232 void
234 {
236 }
237 
238 void
240 {
242 }
243 
244 void
246 {
247  queue_command (command);
249 }
250 
251 void
252 main_window::run_file_in_terminal (const QFileInfo& info)
253 {
255 }
256 
257 void
258 main_window::run_file_callback (const QFileInfo& info)
259 {
260  QString dir = info.absolutePath ();
261  QString function_name = info.fileName ();
262  function_name.chop (info.suffix ().length () + 1);
263  if (octave_qt_link::file_in_path (info.absoluteFilePath ().toStdString (),
264  dir.toStdString ()))
265  queue_command (function_name);
266 }
267 
268 void
269 main_window::queue_command (QString command)
270 {
271  _cmd_queue_mutex.lock ();
272  _cmd_queue->append (command); // queue command
273  _cmd_queue_mutex.unlock ();
274 
275  if (_cmd_processing.tryAcquire ()) // if callback not processing, post event
277 }
278 
279 void
281 {
283 }
284 
285 void
287 {
288  QDesktopServices::openUrl (QUrl ("http://octave.org/doc/interpreter"));
289 }
290 
291 void
293 {
294  if (! release_notes_window)
295  {
296  std::string news_file = Voct_etc_dir + "/NEWS";
297 
298  QString news;
299 
300  QFile *file = new QFile (QString::fromStdString (news_file));
301  if (file->open (QFile::ReadOnly))
302  {
303  QTextStream *stream = new QTextStream (file);
304  news = stream->readAll ();
305  if (! news.isEmpty ())
306  {
307  news.prepend ("<pre>");
308  news.append ("</pre>");
309  }
310  else
311  news = (tr ("The release notes file '%1' is empty.")
312  . arg (QString::fromStdString (news_file)));
313  }
314  else
315  news = (tr ("The release notes file '%1' cannot be read.")
316  . arg (QString::fromStdString (news_file)));
317 
318 
320 
321  QTextBrowser *browser = new QTextBrowser (release_notes_window);
322  browser->setText (news);
323 
324  QVBoxLayout *vlayout = new QVBoxLayout;
325  vlayout->addWidget (browser);
326 
327  release_notes_window->setLayout (vlayout);
328  release_notes_window->setWindowTitle (tr ("Octave Release Notes"));
329 
330  browser->document()->adjustSize ();
331  QSize doc_size = browser->document()->size().toSize ();
332  doc_size.rwidth () += 45;
333  int h = QApplication::desktop ()->height ();
334  if (h > 800)
335  h = 800;
336  doc_size.rheight () = h;
337 
338  release_notes_window->resize (doc_size);
339  }
340 
341  if (! release_notes_window->isVisible ())
342  release_notes_window->show ();
343  else if (release_notes_window->isMinimized ())
344  release_notes_window->showNormal ();
345 
346  release_notes_window->setWindowIcon (QIcon (_release_notes_icon));
347 
348  release_notes_window->raise ();
349  release_notes_window->activateWindow ();
350 }
351 
352 void
354 {
355  QString html_text;
356 
357  if (connect_to_web)
358  {
359  // Run this part in a separate thread so Octave can continue to
360  // run while we wait for the page to load. Then emit the signal
361  // to display it when we have the page contents.
362 
363  QString url = base_url + "/" + page;
364  std::ostringstream buf;
365  url_transfer octave_dot_org (url.toStdString (), buf);
366 
367  Array<std::string> param;
368  octave_dot_org.http_get (param);
369 
370  if (octave_dot_org.good ())
371  html_text = QString::fromStdString (buf.str ());
372 
373  if (html_text.contains ("this-is-the-gnu-octave-community-news-page"))
374  {
375  if (serial >= 0)
376  {
377  QSettings *settings = resource_manager::get_settings ();
378 
379  if (settings)
380  {
381  settings->setValue ("news/last_time_checked",
382  QDateTime::currentDateTime ());
383 
384  settings->sync ();
385  }
386 
387  QString tag ("community-news-page-serial=");
388 
389  int b = html_text.indexOf (tag);
390 
391  if (b)
392  {
393  b += tag.length ();
394 
395  int e = html_text.indexOf ("\n", b);
396 
397  QString tmp = html_text.mid (b, e-b);
398 
399  int curr_page_serial = tmp.toInt ();
400 
401  if (curr_page_serial > serial)
402  {
403  if (settings)
404  {
405  settings->setValue ("news/last_news_item",
406  curr_page_serial);
407 
408  settings->sync ();
409  }
410  }
411  else
412  return;
413  }
414  else
415  return;
416  }
417  }
418  else
419  html_text = QString
420  (tr ("<html>\n"
421  "<body>\n"
422  "<p>\n"
423  "Octave's community news source seems to be unavailable.\n"
424  "</p>\n"
425  "<p>\n"
426  "For the latest news, please check\n"
427  "<a href=\"http://octave.org/community-news.html\">http://octave.org/community-news.html</a>\n"
428  "when you have a connection to the web (link opens in an external browser).\n"
429  "</p>\n"
430  "<p>\n"
431  "<small><em>&mdash; The Octave Developers, " OCTAVE_RELEASE_DATE "</em></small>\n"
432  "</p>\n"
433  "</body>\n"
434  "</html>\n"));
435  }
436  else
437  html_text = QString
438  (tr ("<html>\n"
439  "<body>\n"
440  "<p>\n"
441  "Connecting to the web to display the latest Octave Community news has been disabled.\n"
442  "</p>\n"
443  "<p>\n"
444  "For the latest news, please check\n"
445  "<a href=\"http://octave.org/community-news.html\">http://octave.org/community-news.html</a>\n"
446  "when you have a connection to the web (link opens in an external browser)\n"
447  "or enable web connections for news in Octave's network settings dialog.\n"
448  "</p>\n"
449  "<p>\n"
450  "<small><em>&mdash; The Octave Developers, " OCTAVE_RELEASE_DATE "</em></small>\n"
451  "</p>\n"
452  "</body>\n"
453  "</html>\n"));
454 
455  emit display_news_signal (html_text);
456 
457  emit finished ();
458 }
459 
460 void
462 {
463  QSettings *settings = resource_manager::get_settings ();
464 
465  bool connect_to_web
466  = (settings
467  ? settings->value ("news/allow_web_connection", true).toBool ()
468  : true);
469 
470  QString base_url = "http://octave.org";
471  QString page = "community-news.html";
472 
473  QThread *worker_thread = new QThread;
474 
475  news_reader *reader = new news_reader (base_url, page, serial,
476  connect_to_web);
477 
478  reader->moveToThread (worker_thread);
479 
480  connect (reader, SIGNAL (display_news_signal (const QString&)),
481  this, SLOT (display_community_news (const QString&)));
482 
483  connect (worker_thread, SIGNAL (started (void)),
484  reader, SLOT (process ()));
485 
486  connect (reader, SIGNAL (finished (void)), worker_thread, SLOT (quit ()));
487 
488  connect (reader, SIGNAL (finished (void)), reader, SLOT (deleteLater ()));
489 
490  connect (worker_thread, SIGNAL (finished (void)),
491  worker_thread, SLOT (deleteLater ()));
492 
493  worker_thread->start ();
494 }
495 
496 void
498 {
499  if (! community_news_window)
500  {
502 
503  QTextBrowser *browser = new QTextBrowser (community_news_window);
504 
505  browser->setHtml (news);
506  browser->setObjectName ("OctaveNews");
507  browser->setOpenExternalLinks (true);
508 
509  QVBoxLayout *vlayout = new QVBoxLayout;
510 
511  vlayout->addWidget (browser);
512 
513  community_news_window->setLayout (vlayout);
514  community_news_window->setWindowTitle (tr ("Octave Community News"));
515  community_news_window->resize (640, 480);
516  int win_x = QApplication::desktop ()->width ();
517  int win_y = QApplication::desktop ()->height ();
518  community_news_window->move ((win_x - community_news_window->width ())/2,
519  (win_y - community_news_window->height ())/2);
520  }
521 
522  if (! community_news_window->isVisible ())
523  community_news_window->show ();
524  else if (community_news_window->isMinimized ())
525  community_news_window->showNormal ();
526 
527  // same icon as release notes
528  community_news_window->setWindowIcon (QIcon (_release_notes_icon));
529 
530  community_news_window->raise ();
531  community_news_window->activateWindow ();
532 }
533 
534 void
536 {
537  QDesktopServices::openUrl (QUrl ("http://octave.org/bugs.html"));
538 }
539 
540 void
542 {
543  QDesktopServices::openUrl (QUrl ("http://octave.org/packages.html"));
544 }
545 
546 void
548 {
549  QDesktopServices::openUrl (QUrl ("http://agora.octave.org"));
550 }
551 
552 void
554 {
555  QDesktopServices::openUrl (QUrl ("http://octave.org/donate.html"));
556 }
557 
558 void
560 {
561  QDesktopServices::openUrl (QUrl ("http://octave.org/get-involved.html"));
562 }
563 
564 void
566 {
567  settings_dialog *settingsDialog = new settings_dialog (this, desired_tab);
568  int change_settings = settingsDialog->exec ();
569  if (change_settings == QDialog::Accepted)
570  {
571  settingsDialog->write_changed_settings ();
572  QSettings *settings = resource_manager::get_settings ();
573  if (settings)
574  emit settings_changed (settings);
575  }
576  delete settingsDialog;
577 }
578 
579 
580 void
581 main_window::notice_settings (const QSettings *settings)
582 {
583  // QSettings pointer is checked before emitting.
584 
585  // the widget's icons (when floating)
586  QString icon_set
587  = settings->value ("DockWidgets/widget_icon_set", "NONE").toString ();
588 
589  static struct
590  {
591  QString name;
592  QString path;
593  }
594 
595  widget_icon_data[] =
596  {
597  // array of possible icon sets (name, path (complete for NONE))
598  // the first entry here is the default!
599  {"NONE", ":/actions/icons/logo.png"},
600  {"GRAPHIC", ":/actions/icons/graphic_logo_"},
601  {"LETTER", ":/actions/icons/letter_logo_"},
602  {"", ""} // end marker has empty name
603  };
604 
605  int count = 0;
606  int icon_set_found = 0; // default
607 
608  while (!widget_icon_data[count].name.isEmpty ())
609  {
610  // while not end of data
611  if (widget_icon_data[count].name == icon_set)
612  {
613  // data of desired icon set found
614  icon_set_found = count;
615  break;
616  }
617  count++;
618  }
619 
620  QString icon;
621  foreach (octave_dock_widget *widget, dock_widget_list ())
622  {
623  QString name = widget->objectName ();
624  if (! name.isEmpty ())
625  { // if children has a name
626  icon = widget_icon_data[icon_set_found].path; // prefix or octave-logo
627  if (widget_icon_data[icon_set_found].name != "NONE")
628  icon = icon + name + ".png"; // add widget name and ext.
629  widget->setWindowIcon (QIcon (icon));
630  }
631  }
632  if (widget_icon_data[icon_set_found].name != "NONE")
633  _release_notes_icon = widget_icon_data[icon_set_found].path
634  + "ReleaseWidget.png";
635  else
636  _release_notes_icon = ":/actions/icons/logo.png";
637 
638  int icon_size = settings->value ("toolbar_icon_size",16).toInt ();
639  _main_tool_bar->setIconSize (QSize (icon_size,icon_size));
640 
642 }
643 
644 
645 void
647 {
648  write_settings ();
649 }
650 
651 void
652 main_window::exit (int status)
653 {
654  qApp->exit (status);
655 }
656 
657 void
659 {
660  QSettings *settings = resource_manager::get_default_settings ();
661 
662  set_window_layout (settings);
663  showNormal (); // make sure main window is not minimized
664 }
665 
666 void
667 main_window::change_directory (const QString& dir)
668 {
669  // Remove existing entry, if any, then add new directory at top and
670  // mark it as the current directory. Finally, update the file list
671  // widget.
672 
673  int index = _current_directory_combo_box->findText (dir);
674 
675  if (index >= 0)
676  _current_directory_combo_box->removeItem (index);
677 
678  _current_directory_combo_box->insertItem (0, dir);
679  _current_directory_combo_box->setCurrentIndex (0);
680 
682 }
683 
684 void
686 {
687  QString dir
688  = QFileDialog::getExistingDirectory (this, tr ("Browse directories"), 0,
689  QFileDialog::DontUseNativeDialog);
690 
692 
693  // FIXME: on Windows systems, the command window freezes after the
694  // previous actions. Forcing the focus appears to unstick it.
695 
697 }
698 
699 void
701 {
702  // Change to dir if it is an existing directory.
703 
704  QString xdir = dir.isEmpty () ? "." : dir;
705 
706  QFileInfo fileInfo (xdir);
707 
708  if (fileInfo.exists () && fileInfo.isDir ())
710  xdir.toStdString ());
711 }
712 
713 void
715 {
717 }
718 
719 // Slot that is called if return is pressed in the line edit of the
720 // combobox to change to a new directory or a directory that is already
721 // in the drop down list.
722 
723 void
725 {
726  // Get new directory name, and change to it if it is new. Otherwise,
727  // the combo box will triggers the "activated" signal to change to the
728  // directory.
729 
730  QString dir = _current_directory_combo_box->currentText ();
731 
732  int index = _current_directory_combo_box->findText (dir);
733 
734  if (index < 0)
736 }
737 
738 void
740 {
741  setWindowTitle ("Octave (Debugging)");
742 
743  _debug_continue->setEnabled (true);
744  _debug_step_into->setEnabled (true);
745  _debug_step_over->setEnabled (true);
746  _debug_step_out->setEnabled (true);
747  _debug_quit->setEnabled (true);
748 
749 #ifdef HAVE_QSCINTILLA
751 #endif
752 }
753 
754 void
756 {
757  setWindowTitle ("Octave");
758 
759  _debug_continue->setEnabled (false);
760  _debug_step_into->setEnabled (false);
761  _debug_step_over->setEnabled (false);
762  _debug_step_out->setEnabled (false);
763  _debug_quit->setEnabled (false);
764 
765 #ifdef HAVE_QSCINTILLA
767 #endif
768 }
769 
770 void
772 {
774 }
775 
776 void
778 {
780 }
781 
782 void
784 {
786 }
787 
788 void
790 {
792 }
793 
794 void
796 {
798 }
799 
800 void
802  int line)
803 {
804  bool cmd_focus = command_window_has_focus ();
805 
806  emit insert_debugger_pointer_signal (file, line);
807 
808  if (cmd_focus)
810 }
811 
812 void
814  int line)
815 {
816  bool cmd_focus = command_window_has_focus ();
817 
818  emit delete_debugger_pointer_signal (file, line);
819 
820  if (cmd_focus)
822 }
823 
824 void
826  const QString& file,
827  int line)
828 {
829  bool cmd_focus = command_window_has_focus ();
830 
831  emit update_breakpoint_marker_signal (insert, file, line);
832 
833  if (cmd_focus)
835 }
836 
837 void
839 {
840  std::string message
842 
843  QMessageBox::about (this, tr ("About Octave"),
844  QString::fromStdString (message));
845 }
846 
847 void
848 main_window::closeEvent (QCloseEvent *e)
849 {
850  e->ignore ();
852 }
853 
854 void
856 {
857  QSettings *settings = resource_manager::get_settings ();
858 
859  if (!settings)
860  {
861  qDebug ("Error: QSettings pointer from resource manager is NULL.");
862  return;
863  }
864 
865  set_window_layout (settings);
866 
867  // restore the list of the last directories
868  QStringList curr_dirs
869  = settings->value ("MainWindow/current_directory_list").toStringList ();
870  for (int i=0; i < curr_dirs.size (); i++)
871  {
872  _current_directory_combo_box->addItem (curr_dirs.at (i));
873  }
874  emit settings_changed (settings);
875 }
876 
877 void
878 main_window::set_window_layout (QSettings *settings)
879 {
880  QList<octave_dock_widget *> float_and_visible;
881 
882  // Restore the geometry of all dock-widgets
883  foreach (octave_dock_widget *widget, dock_widget_list ())
884  {
885  QString name = widget->objectName ();
886 
887  if (! name.isEmpty ())
888  {
889  bool floating = settings->value
890  ("DockWidgets/" + name + "Floating", false).toBool ();
891  bool visible = settings->value
892  ("DockWidgets/" + name + "Visible", true).toBool ();
893 
894 #if defined (Q_OS_WIN32)
895  // If floating, make window from widget.
896  if (floating)
897  widget->make_window ();
898  else if (! widget->parent ()) // should not be floating but is
899  widget->make_widget (false); // no docking, just reparent
900 #else
901  // restore geometry
902  QVariant val = settings->value ("DockWidgets/" + name);
903  widget->restoreGeometry (val.toByteArray ());
904 #endif
905  // make widget visible if desired
906  if (floating && visible) // floating and visible
907  float_and_visible.append (widget); // not show before main win
908  else
909  {
910  widget->make_widget ();
911  widget->setVisible (visible); // not floating -> show
912  }
913  }
914  }
915 
916 #if ! defined (Q_OS_WIN32)
917  // show main first but minimized to avoid flickering,
918  // otherwise the name of a floating widget is shown in a global menu bar
919  showMinimized ();
920  // hide again, otherwise the geometry is not exactly restored
921  hide ();
922 #endif
923  // restore geomoetry of main window
924  restoreState (settings->value ("MainWindow/windowState").toByteArray ());
925  restoreGeometry (settings->value ("MainWindow/geometry").toByteArray ());
926  // show main window
927  show ();
928 
929  // show floating widgets after main win to ensure "Octave" in central menu
930  foreach (octave_dock_widget *widget, float_and_visible)
931  {
932 #if ! defined (Q_OS_WIN32)
933  widget->make_window ();
934 #endif
935  if (settings->value ("DockWidgets/" + widget->objectName () + "_minimized").toBool ())
936  widget->showMinimized ();
937  else
938  widget->setVisible (true);
939  }
940 
941 }
942 
943 void
945 {
946  QSettings *settings = resource_manager::get_settings ();
947  if (!settings)
948  {
949  qDebug ("Error: QSettings pointer from resource manager is NULL.");
950  return;
951  }
952 
953  settings->setValue ("MainWindow/geometry", saveGeometry ());
954  settings->setValue ("MainWindow/windowState", saveState ());
955  // write the list of recent used directories
956  QStringList curr_dirs;
957  for (int i=0; i<_current_directory_combo_box->count (); i++)
958  {
959  curr_dirs.append (_current_directory_combo_box->itemText (i));
960  }
961  settings->setValue ("MainWindow/current_directory_list", curr_dirs);
962  settings->sync ();
963 }
964 
965 
966 // Connecting the signals emitted when the visibility of a widget changes.
967 // This has to be done after the window is shown (see octave-gui.cc)
968 void
970 {
971  foreach (octave_dock_widget *widget, dock_widget_list ())
972  widget->connect_visibility_changed ();
973 }
974 
975 void
977 {
978  if (_current_directory_combo_box->hasFocus ())
979  {
980  QLineEdit * edit = _current_directory_combo_box->lineEdit ();
981  if (edit && edit->hasSelectedText ())
982  {
983  QClipboard *clipboard = QApplication::clipboard ();
984  clipboard->setText (edit->selectedText ());
985  }
986  }
987  else
988  emit copyClipboard_signal ();
989 }
990 
991 void
993 {
994  if (_current_directory_combo_box->hasFocus ())
995  {
996  QLineEdit * edit = _current_directory_combo_box->lineEdit ();
997  QClipboard *clipboard = QApplication::clipboard ();
998  QString str = clipboard->text ();
999  if (edit && str.length () > 0)
1000  {
1001  edit->insert (str);
1002  }
1003  }
1004  else
1005  emit pasteClipboard_signal ();
1006 }
1007 
1008 // Connect the signals emitted when the Octave thread wants to create
1009 // a dialog box of some sort. Perhaps a better place for this would be
1010 // as part of the QUIWidgetCreator class. However, mainWindow currently
1011 // is not a global variable and not accessible for connecting.
1012 
1013 void
1015 {
1016  connect (&uiwidget_creator,
1017  SIGNAL (create_dialog (const QString&, const QString&,
1018  const QString&, const QStringList&,
1019  const QString&, const QStringList&)),
1020  this,
1021  SLOT (handle_create_dialog (const QString&, const QString&,
1022  const QString&, const QStringList&,
1023  const QString&, const QStringList&)));
1024 
1025  // Register QIntList so that list of ints may be part of a signal.
1026  qRegisterMetaType<QIntList> ("QIntList");
1027  connect (&uiwidget_creator,
1028  SIGNAL (create_listview (const QStringList&, const QString&,
1029  int, int, const QIntList&,
1030  const QString&, const QStringList&,
1031  const QString&, const QString&)),
1032  this,
1033  SLOT (handle_create_listview (const QStringList&, const QString&,
1034  int, int, const QIntList&,
1035  const QString&, const QStringList&,
1036  const QString&, const QString&)));
1037 
1038  // Register QFloatList so that list of floats may be part of a signal.
1039  qRegisterMetaType<QFloatList> ("QFloatList");
1040  connect (&uiwidget_creator,
1041  SIGNAL (create_inputlayout (const QStringList&, const QString&,
1042  const QFloatList&, const QFloatList&,
1043  const QStringList&)),
1044  this,
1045  SLOT (handle_create_inputlayout (const QStringList&, const QString&,
1046  const QFloatList&,
1047  const QFloatList&,
1048  const QStringList&)));
1049 
1050  connect (&uiwidget_creator,
1051  SIGNAL (create_filedialog (const QStringList &,const QString&,
1052  const QString&, const QString&,
1053  const QString&)),
1054  this,
1055  SLOT (handle_create_filedialog (const QStringList &, const QString&,
1056  const QString&, const QString&,
1057  const QString&)));
1058 }
1059 
1060 // Create a message dialog with specified string, buttons and decorative
1061 // text.
1062 
1063 void
1065  const QString& title,
1066  const QString& icon,
1067  const QStringList& button,
1068  const QString& defbutton,
1069  const QStringList& role)
1070 {
1071  MessageDialog *message_dialog = new MessageDialog (message, title, icon,
1072  button, defbutton, role);
1073  message_dialog->setAttribute (Qt::WA_DeleteOnClose);
1074  message_dialog->show ();
1075 }
1076 
1077 // Create a list dialog with specified list, initially selected, mode,
1078 // view size and decorative text.
1079 
1080 void
1081 main_window::handle_create_listview (const QStringList& list,
1082  const QString& mode,
1083  int wd, int ht,
1084  const QIntList& initial,
1085  const QString& name,
1086  const QStringList& prompt,
1087  const QString& ok_string,
1088  const QString& cancel_string)
1089 {
1090  ListDialog *list_dialog = new ListDialog (list, mode, wd, ht,
1091  initial, name, prompt,
1092  ok_string, cancel_string);
1093 
1094  list_dialog->setAttribute (Qt::WA_DeleteOnClose);
1095  list_dialog->show ();
1096 }
1097 
1098 // Create an input dialog with specified prompts and defaults, title and
1099 // row/column size specifications.
1100 void
1101 main_window::handle_create_inputlayout (const QStringList& prompt,
1102  const QString& title,
1103  const QFloatList& nr,
1104  const QFloatList& nc,
1105  const QStringList& defaults)
1106 {
1107  InputDialog *input_dialog = new InputDialog (prompt, title, nr, nc,
1108  defaults);
1109 
1110  input_dialog->setAttribute (Qt::WA_DeleteOnClose);
1111  input_dialog->show ();
1112 }
1113 
1114 void
1115 main_window::handle_create_filedialog (const QStringList& filters,
1116  const QString& title,
1117  const QString& filename,
1118  const QString& dirname,
1119  const QString& multimode)
1120 {
1121  FileDialog *file_dialog = new FileDialog (filters, title, filename,
1122  dirname, multimode);
1123 
1124  file_dialog->setAttribute (Qt::WA_DeleteOnClose);
1125  file_dialog->show ();
1126 }
1127 
1128 // Main subroutine of the constructor
1129 void
1131 {
1132  _closing = false; // flag for editor files when closed
1133  setWindowIcon (QIcon (":/actions/icons/logo.png"));
1134 
1136  connect (_workspace_model, SIGNAL (model_changed (void)),
1137  workspace_window, SLOT (handle_model_changed (void)));
1138 
1139  // Create and set the central widget. QMainWindow takes ownership of
1140  // the widget (pointer) so there is no need to delete the object upon
1141  // destroying this main_window.
1142 
1143  QWidget *dummyWidget = new QWidget ();
1144  dummyWidget->setObjectName ("CentralDummyWidget");
1145  dummyWidget->resize (10, 10);
1146  dummyWidget->setSizePolicy (QSizePolicy::Minimum, QSizePolicy::Minimum);
1147  dummyWidget->hide ();
1148  setCentralWidget (dummyWidget);
1149 
1150  construct_menu_bar ();
1151 
1152  construct_tool_bar ();
1153 
1155 
1156  connect (qApp, SIGNAL (aboutToQuit ()),
1157  this, SLOT (prepare_to_exit ()));
1158 
1159  connect (this, SIGNAL (settings_changed (const QSettings *)),
1160  this, SLOT (notice_settings (const QSettings *)));
1161 
1162  connect (file_browser_window, SIGNAL (load_file_signal (const QString&)),
1163  this, SLOT (handle_load_workspace_request (const QString&)));
1164 
1165  connect (file_browser_window, SIGNAL (find_files_signal (const QString&)),
1166  this, SLOT (find_files (const QString&)));
1167 
1168  connect (this, SIGNAL (set_widget_shortcuts_signal (bool)),
1169  editor_window, SLOT (set_shortcuts (bool)));
1170 
1172 
1173  setWindowTitle ("Octave");
1174 
1175  setDockOptions (QMainWindow::AnimatedDocks
1176  | QMainWindow::AllowNestedDocks
1177  | QMainWindow::AllowTabbedDocks);
1178 
1179  addDockWidget (Qt::RightDockWidgetArea, command_window);
1180  addDockWidget (Qt::RightDockWidgetArea, doc_browser_window);
1181  tabifyDockWidget (command_window, doc_browser_window);
1182 
1183 #ifdef HAVE_QSCINTILLA
1184  addDockWidget (Qt::RightDockWidgetArea, editor_window);
1185  tabifyDockWidget (command_window, editor_window);
1186 #endif
1187 
1188  addDockWidget (Qt::LeftDockWidgetArea, file_browser_window);
1189  addDockWidget (Qt::LeftDockWidgetArea, workspace_window);
1190  addDockWidget (Qt::LeftDockWidgetArea, history_window);
1191 
1192  int win_x = QApplication::desktop ()->width ();
1193  int win_y = QApplication::desktop ()->height ();
1194 
1195  if (win_x > 960)
1196  win_x = 960;
1197 
1198  if (win_y > 720)
1199  win_y = 720;
1200 
1201  setGeometry (0, 0, win_x, win_y);
1202 
1203  setStatusBar (status_bar);
1204 
1206 
1207 #ifdef HAVE_QSCINTILLA
1208  connect (this,
1209  SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
1210  editor_window,
1211  SLOT (handle_insert_debugger_pointer_request (const QString&, int)));
1212 
1213  connect (this,
1214  SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
1215  editor_window,
1216  SLOT (handle_delete_debugger_pointer_request (const QString&, int)));
1217 
1218  connect (this,
1219  SIGNAL (update_breakpoint_marker_signal (bool, const QString&, int)),
1220  editor_window,
1222  const QString&,
1223  int)));
1224 #endif
1225 
1226  QDir curr_dir;
1227  set_current_working_directory (curr_dir.absolutePath ());
1228 
1230 
1231  set_global_shortcuts (true);
1232 
1233 }
1234 
1235 void
1237 {
1239 
1240  connect (_octave_qt_link, SIGNAL (exit_signal (int)),
1241  this, SLOT (exit (int)));
1242 
1243  connect (_octave_qt_link,
1244  SIGNAL (set_workspace_signal
1245  (bool, const QString&, const QStringList&,
1246  const QStringList&, const QStringList&,
1247  const QStringList&, const QIntList&)),
1249  SLOT (set_workspace
1250  (bool, const QString&, const QStringList&,
1251  const QStringList&, const QStringList&,
1252  const QStringList&, const QIntList&)));
1253 
1254  connect (_octave_qt_link, SIGNAL (clear_workspace_signal ()),
1255  _workspace_model, SLOT (clear_workspace ()));
1256 
1257  connect (_octave_qt_link, SIGNAL (change_directory_signal (QString)),
1258  this, SLOT (change_directory (QString)));
1259 
1260  connect (_octave_qt_link,
1261  SIGNAL (execute_command_in_terminal_signal (QString)),
1262  this, SLOT (execute_command_in_terminal (QString)));
1263 
1264  connect (_octave_qt_link,
1265  SIGNAL (set_history_signal (const QStringList&)),
1266  history_window, SLOT (set_history (const QStringList&)));
1267 
1268  connect (_octave_qt_link,
1269  SIGNAL (append_history_signal (const QString&)),
1270  history_window, SLOT (append_history (const QString&)));
1271 
1272  connect (_octave_qt_link,
1273  SIGNAL (clear_history_signal (void)),
1274  history_window, SLOT (clear_history (void)));
1275 
1276  connect (_octave_qt_link, SIGNAL (enter_debugger_signal ()),
1277  this, SLOT (handle_enter_debugger ()));
1278 
1279  connect (_octave_qt_link, SIGNAL (exit_debugger_signal ()),
1280  this, SLOT (handle_exit_debugger ()));
1281 
1282  connect (_octave_qt_link,
1283  SIGNAL (show_preferences_signal (void)),
1284  this, SLOT (process_settings_dialog_request ()));
1285 
1286 #ifdef HAVE_QSCINTILLA
1287  connect (_octave_qt_link,
1288  SIGNAL (edit_file_signal (const QString&)),
1289  editor_window,
1290  SLOT (handle_edit_file_request (const QString&)));
1291 #endif
1292 
1293  connect (_octave_qt_link,
1294  SIGNAL (insert_debugger_pointer_signal (const QString&, int)),
1295  this,
1296  SLOT (handle_insert_debugger_pointer_request (const QString&, int)));
1297 
1298  connect (_octave_qt_link,
1299  SIGNAL (delete_debugger_pointer_signal (const QString&, int)),
1300  this,
1301  SLOT (handle_delete_debugger_pointer_request (const QString&, int)));
1302 
1303  connect (_octave_qt_link,
1304  SIGNAL (update_breakpoint_marker_signal (bool, const QString&, int)),
1305  this,
1306  SLOT (handle_update_breakpoint_marker_request (bool, const QString&,
1307  int)));
1308 
1309  connect (_octave_qt_link,
1310  SIGNAL (show_doc_signal (const QString &)),
1311  this, SLOT (handle_show_doc (const QString &)));
1312 
1313  connect (_workspace_model,
1314  SIGNAL (rename_variable (const QString&, const QString&)),
1315  this,
1316  SLOT (handle_rename_variable_request (const QString&,
1317  const QString&)));
1318 
1319  connect (command_window, SIGNAL (interrupt_signal (void)),
1320  _octave_qt_link, SLOT (terminal_interrupt (void)));
1321 
1323 
1325 }
1326 
1327 void
1329 {
1330  QMenuBar *menu_bar = menuBar ();
1331 
1332  construct_file_menu (menu_bar);
1333 
1334  construct_edit_menu (menu_bar);
1335 
1336  construct_debug_menu (menu_bar);
1337 
1338  construct_window_menu (menu_bar);
1339 
1340  construct_help_menu (menu_bar);
1341 
1342  construct_news_menu (menu_bar);
1343 }
1344 
1345 void
1347 {
1348  QMenu *file_menu = p->addMenu (tr ("&File"));
1349 
1350  construct_new_menu (file_menu);
1351 
1352  _open_action
1353  = file_menu->addAction (QIcon (":/actions/icons/fileopen.png"),
1354  tr ("Open..."));
1355  _open_action->setShortcutContext (Qt::ApplicationShortcut);
1356 
1357 
1358 #ifdef HAVE_QSCINTILLA
1359  file_menu->addMenu (editor_window->get_mru_menu ());
1360 #endif
1361 
1362  file_menu->addSeparator ();
1363 
1364  QAction *load_workspace_action
1365  = file_menu->addAction (tr ("Load Workspace"));
1366 
1367  QAction *save_workspace_action
1368  = file_menu->addAction (tr ("Save Workspace As"));
1369 
1370  file_menu->addSeparator ();
1371 
1372  QAction *preferences_action
1373  = file_menu->addAction (QIcon (":/actions/icons/configure.png"),
1374  tr ("Preferences..."));
1375 
1376  file_menu->addSeparator ();
1377 
1378  _exit_action = file_menu->addAction (tr ("Exit"));
1379  _exit_action->setShortcutContext (Qt::ApplicationShortcut);
1380 
1381  connect (preferences_action, SIGNAL (triggered ()),
1382  this, SLOT (process_settings_dialog_request ()));
1383 
1384 #ifdef HAVE_QSCINTILLA
1385  connect (_open_action, SIGNAL (triggered ()),
1386  editor_window, SLOT (request_open_file ()));
1387 #endif
1388 
1389  connect (load_workspace_action, SIGNAL (triggered ()),
1390  this, SLOT (handle_load_workspace_request ()));
1391 
1392  connect (save_workspace_action, SIGNAL (triggered ()),
1393  this, SLOT (handle_save_workspace_request ()));
1394 
1395  connect (_exit_action, SIGNAL (triggered ()),
1396  this, SLOT (close ()));
1397 }
1398 
1399 void
1401 {
1402  QMenu *new_menu = p->addMenu (tr ("New"));
1403 
1405  = new_menu->addAction (QIcon (":/actions/icons/filenew.png"),
1406  tr ("Script"));
1407  _new_script_action->setShortcutContext (Qt::ApplicationShortcut);
1408 
1409  _new_function_action = new_menu->addAction (tr ("Function"));
1410  _new_function_action->setEnabled (true);
1411  _new_function_action->setShortcutContext (Qt::ApplicationShortcut);
1412 
1413  QAction *new_figure_action = new_menu->addAction (tr ("Figure"));
1414  new_figure_action->setEnabled (true);
1415 
1416 #ifdef HAVE_QSCINTILLA
1417  connect (_new_script_action, SIGNAL (triggered ()),
1418  editor_window, SLOT (request_new_script ()));
1419 
1420  connect (_new_function_action, SIGNAL (triggered ()),
1421  editor_window, SLOT (request_new_function ()));
1422 #endif
1423 
1424  connect (new_figure_action, SIGNAL (triggered ()),
1425  this, SLOT (handle_new_figure_request ()));
1426 }
1427 
1428 void
1430 {
1431  QMenu *edit_menu = p->addMenu (tr ("&Edit"));
1432 
1433  QKeySequence ctrl_shift = Qt::ControlModifier + Qt::ShiftModifier;
1434 
1435  _undo_action
1436  = edit_menu->addAction (QIcon (":/actions/icons/undo.png"), tr ("Undo"));
1437  _undo_action->setShortcut (QKeySequence::Undo);
1438 
1439  edit_menu->addSeparator ();
1440 
1441  _copy_action
1442  = edit_menu->addAction (QIcon (":/actions/icons/editcopy.png"),
1443  tr ("Copy"), this, SLOT (copyClipboard ()));
1444  _copy_action->setShortcut (QKeySequence::Copy);
1445 
1446 
1448  = edit_menu->addAction (QIcon (":/actions/icons/editpaste.png"),
1449  tr ("Paste"), this, SLOT (pasteClipboard ()));
1450  _paste_action->setShortcut (QKeySequence::Paste);
1451 
1453  = edit_menu->addAction (tr ("Clear Clipboard"), this,
1454  SLOT (clear_clipboard ()));
1455 
1456  edit_menu->addSeparator ();
1457 
1458  _find_files_action = edit_menu->addAction (tr ("Find Files..."));
1459 
1460  edit_menu->addSeparator ();
1461 
1462  QAction *clear_command_window_action
1463  = edit_menu->addAction (tr ("Clear Command Window"));
1464 
1465  QAction *clear_command_history
1466  = edit_menu->addAction (tr ("Clear Command History"));
1467 
1468  QAction *clear_workspace_action
1469  = edit_menu->addAction (tr ("Clear Workspace"));
1470 
1471  connect (_find_files_action, SIGNAL (triggered ()),
1472  this, SLOT (find_files ()));
1473 
1474  connect (clear_command_window_action, SIGNAL (triggered ()),
1475  this, SLOT (handle_clear_command_window_request ()));
1476 
1477  connect (clear_command_history, SIGNAL (triggered ()),
1478  this, SLOT (handle_clear_history_request ()));
1479 
1480  connect (clear_workspace_action, SIGNAL (triggered ()),
1481  this, SLOT (handle_clear_workspace_request ()));
1482 
1483  connect (_clipboard, SIGNAL (changed (QClipboard::Mode)),
1484  this, SLOT (clipboard_has_changed (QClipboard::Mode)));
1485  clipboard_has_changed (QClipboard::Clipboard);
1486 }
1487 
1488 QAction *
1490  const QString& item,
1491  const QKeySequence& key)
1492 {
1493  QAction *action = _debug_menu->addAction (QIcon (icon_file), item);
1494 
1495  action->setEnabled (false);
1496  action->setShortcut (key);
1497 
1498 #ifdef HAVE_QSCINTILLA
1499  editor_window->debug_menu ()->addAction (action);
1500  editor_window->toolbar ()->addAction (action);
1501 #endif
1502 
1503  return action;
1504 }
1505 
1506 void
1508 {
1509  _debug_menu = p->addMenu (tr ("De&bug"));
1510 
1512  (":/actions/icons/db_step.png", tr ("Step"),
1513  Qt::Key_F10);
1514 
1516  (":/actions/icons/db_step_in.png", tr ("Step In"),
1517  Qt::Key_F11);
1518 
1520  (":/actions/icons/db_step_out.png", tr ("Step Out"),
1521  Qt::ShiftModifier + Qt::Key_F11);
1522 
1524  (":/actions/icons/db_cont.png", tr ("Continue"),
1525  Qt::Key_F5);
1526 
1527  _debug_menu->addSeparator ();
1528 #ifdef HAVE_QSCINTILLA
1529  editor_window->debug_menu ()->addSeparator ();
1530 #endif
1531 
1533  (":/actions/icons/db_stop.png", tr ("Exit Debug Mode"),
1534  Qt::ShiftModifier + Qt::Key_F5);
1535 
1536  connect (_debug_step_over, SIGNAL (triggered ()),
1537  this, SLOT (debug_step_over ()));
1538 
1539  connect (_debug_step_into, SIGNAL (triggered ()),
1540  this, SLOT (debug_step_into ()));
1541 
1542  connect (_debug_step_out, SIGNAL (triggered ()),
1543  this, SLOT (debug_step_out ()));
1544 
1545  connect (_debug_continue, SIGNAL (triggered ()),
1546  this, SLOT (debug_continue ()));
1547 
1548  connect (_debug_quit, SIGNAL (triggered ()),
1549  this, SLOT (debug_quit ()));
1550 }
1551 
1552 QAction *
1553 main_window::construct_window_menu_item (QMenu *p, const QString& item,
1554  bool checkable,
1555  const QKeySequence& key)
1556 {
1557  QAction *action = p->addAction (item);
1558 
1559  action->setCheckable (checkable);
1560  action->setShortcut (key);
1561  action->setShortcutContext (Qt::ApplicationShortcut);
1562 
1563  return action;
1564 }
1565 
1566 void
1568 {
1569  QMenu *window_menu = p->addMenu (tr ("&Window"));
1570 
1571  QKeySequence ctrl = Qt::ControlModifier;
1572  QKeySequence ctrl_shift = Qt::ControlModifier + Qt::ShiftModifier;
1573 
1574  QAction *show_command_window_action = construct_window_menu_item
1575  (window_menu,
1576  tr ("Show Command Window"), true,
1577  ctrl_shift + Qt::Key_0);
1578 
1579  QAction *show_history_action = construct_window_menu_item
1580  (window_menu, tr ("Show Command History"),
1581  true, ctrl_shift + Qt::Key_1);
1582 
1583  QAction *show_file_browser_action = construct_window_menu_item
1584  (window_menu, tr ("Show File Browser"),
1585  true, ctrl_shift + Qt::Key_2);
1586 
1587  QAction *show_workspace_action = construct_window_menu_item
1588  (window_menu, tr ("Show Workspace"), true,
1589  ctrl_shift + Qt::Key_3);
1590 
1591  QAction *show_editor_action = construct_window_menu_item
1592  (window_menu, tr ("Show Editor"), true,
1593  ctrl_shift + Qt::Key_4);
1594 
1595  QAction *show_documentation_action = construct_window_menu_item
1596  (window_menu, tr ("Show Documentation"),
1597  true, ctrl_shift + Qt::Key_5);
1598 
1599  window_menu->addSeparator ();
1600 
1601  QAction *command_window_action = construct_window_menu_item
1602  (window_menu, tr ("Command Window"), false,
1603  ctrl + Qt::Key_0);
1604 
1605  QAction *history_action = construct_window_menu_item
1606  (window_menu, tr ("Command History"), false,
1607  ctrl + Qt::Key_1);
1608 
1609  QAction *file_browser_action = construct_window_menu_item
1610  (window_menu, tr ("File Browser"), false,
1611  ctrl + Qt::Key_2);
1612 
1613  QAction *workspace_action = construct_window_menu_item
1614  (window_menu, tr ("Workspace"), false,
1615  ctrl + Qt::Key_3);
1616 
1617  QAction *editor_action = construct_window_menu_item
1618  (window_menu, tr ("Editor"), false,
1619  ctrl + Qt::Key_4);
1620 
1621  QAction *documentation_action = construct_window_menu_item
1622  (window_menu, tr ("Documentation"), false,
1623  ctrl + Qt::Key_5);
1624 
1625  window_menu->addSeparator ();
1626 
1627  QAction *reset_windows_action
1628  = window_menu->addAction (tr ("Reset Default Window Layout"));
1629 
1630  connect (show_command_window_action, SIGNAL (toggled (bool)),
1631  command_window, SLOT (setVisible (bool)));
1632 
1633  connect (command_window, SIGNAL (active_changed (bool)),
1634  show_command_window_action, SLOT (setChecked (bool)));
1635 
1636  connect (show_workspace_action, SIGNAL (toggled (bool)),
1637  workspace_window, SLOT (setVisible (bool)));
1638 
1639  connect (workspace_window, SIGNAL (active_changed (bool)),
1640  show_workspace_action, SLOT (setChecked (bool)));
1641 
1642  connect (show_history_action, SIGNAL (toggled (bool)),
1643  history_window, SLOT (setVisible (bool)));
1644 
1645  connect (history_window, SIGNAL (active_changed (bool)),
1646  show_history_action, SLOT (setChecked (bool)));
1647 
1648  connect (show_file_browser_action, SIGNAL (toggled (bool)),
1649  file_browser_window, SLOT (setVisible (bool)));
1650 
1651  connect (file_browser_window, SIGNAL (active_changed (bool)),
1652  show_file_browser_action, SLOT (setChecked (bool)));
1653 
1654 #ifdef HAVE_QSCINTILLA
1655  connect (show_editor_action, SIGNAL (toggled (bool)),
1656  editor_window, SLOT (setVisible (bool)));
1657 
1658  connect (editor_window, SIGNAL (active_changed (bool)),
1659  show_editor_action, SLOT (setChecked (bool)));
1660 #endif
1661 
1662  connect (show_documentation_action, SIGNAL (toggled (bool)),
1663  doc_browser_window, SLOT (setVisible (bool)));
1664 
1665  connect (doc_browser_window, SIGNAL (active_changed (bool)),
1666  show_documentation_action, SLOT (setChecked (bool)));
1667 
1668  connect (command_window_action, SIGNAL (triggered ()),
1669  command_window, SLOT (focus ()));
1670 
1671  connect (workspace_action, SIGNAL (triggered ()),
1672  workspace_window, SLOT (focus ()));
1673 
1674  connect (history_action, SIGNAL (triggered ()),
1675  history_window, SLOT (focus ()));
1676 
1677  connect (file_browser_action, SIGNAL (triggered ()),
1678  file_browser_window, SLOT (focus ()));
1679 
1680 #ifdef HAVE_QSCINTILLA
1681  connect (editor_action, SIGNAL (triggered ()),
1682  editor_window, SLOT (focus ()));
1683 #endif
1684 
1685  connect (documentation_action, SIGNAL (triggered ()),
1686  doc_browser_window, SLOT (focus ()));
1687 
1688  connect (reset_windows_action, SIGNAL (triggered ()),
1689  this, SLOT (reset_windows ()));
1690 }
1691 
1692 void
1694 {
1695  QMenu *help_menu = p->addMenu (tr ("&Help"));
1696 
1697  construct_documentation_menu (help_menu);
1698 
1699  help_menu->addSeparator ();
1700 
1701  QAction *report_bug_action
1702  = help_menu->addAction (tr ("Report Bug"));
1703 
1704  QAction *octave_packages_action
1705  = help_menu->addAction (tr ("Octave Packages"));
1706 
1707  QAction *agora_action
1708  = help_menu->addAction (tr ("Share Code"));
1709 
1710  QAction *contribute_action
1711  = help_menu->addAction (tr ("Contribute to Octave"));
1712 
1713  QAction *developer_action
1714  = help_menu->addAction (tr ("Octave Developer Resources"));
1715 
1716  help_menu->addSeparator ();
1717 
1718  QAction *about_octave_action
1719  = help_menu->addAction (tr ("About Octave"));
1720 
1721  connect (report_bug_action, SIGNAL (triggered ()),
1722  this, SLOT (open_bug_tracker_page ()));
1723 
1724  connect (octave_packages_action, SIGNAL (triggered ()),
1725  this, SLOT (open_octave_packages_page ()));
1726 
1727  connect (agora_action, SIGNAL (triggered ()),
1728  this, SLOT (open_agora_page ()));
1729 
1730  connect (contribute_action, SIGNAL (triggered ()),
1731  this, SLOT (open_contribute_page ()));
1732 
1733  connect (developer_action, SIGNAL (triggered ()),
1734  this, SLOT (open_developer_page ()));
1735 
1736  connect (about_octave_action, SIGNAL (triggered ()),
1737  this, SLOT (show_about_octave ()));
1738 }
1739 
1740 void
1742 {
1743  QMenu *documentation_menu = p->addMenu (tr ("Documentation"));
1744 
1745  QAction *ondisk_documentation_action
1746  = documentation_menu->addAction (tr ("On Disk"));
1747 
1748  QAction *online_documentation_action
1749  = documentation_menu->addAction (tr ("Online"));
1750 
1751  connect (ondisk_documentation_action, SIGNAL (triggered ()),
1752  doc_browser_window, SLOT (focus ()));
1753 
1754  connect (online_documentation_action, SIGNAL (triggered ()),
1755  this, SLOT (open_online_documentation_page ()));
1756 }
1757 
1758 void
1760 {
1761  QMenu *news_menu = p->addMenu (tr ("&News"));
1762 
1763  QAction *release_notes_action
1764  = news_menu->addAction (tr ("Release Notes"));
1765 
1766  QAction *current_news_action
1767  = news_menu->addAction (tr ("Community News"));
1768 
1769  connect (release_notes_action, SIGNAL (triggered ()),
1770  this, SLOT (display_release_notes ()));
1771 
1772  connect (current_news_action, SIGNAL (triggered ()),
1773  this, SLOT (load_and_display_community_news ()));
1774 }
1775 
1776 void
1778 {
1779  QSettings *settings = resource_manager::get_settings ();
1780 
1781  if (settings
1782  && settings->value ("General/hide_new_gui_warning", false).toBool ())
1783  {
1785 
1786  return;
1787  }
1788 
1789  _warning_bar = new QDockWidget (this);
1790  _warning_bar->setAttribute (Qt::WA_DeleteOnClose);
1791 
1792  QFrame *box = new QFrame (_warning_bar);
1793 
1794  QLabel *icon = new QLabel (box);
1795  QIcon warning_icon
1796  = QIcon::fromTheme ("dialog-warning",
1797  QIcon (":/actions/icons/warning.png"));
1798  QPixmap icon_pixmap = warning_icon.pixmap (QSize (32, 32));
1799  icon->setPixmap (icon_pixmap);
1800 
1801  QTextBrowser *msg = new QTextBrowser (box);
1802  msg->setOpenExternalLinks (true);
1803  msg->setText
1804  (tr ("<strong>You are using a release candidate of Octave's experimental GUI.</strong> "
1805  "Octave is under continuous improvement and the GUI will be the "
1806  "default interface for the 4.0 release. For more information, "
1807  "select the \"Release Notes\" item in the \"Help\" menu of the GUI, "
1808  "or visit <a href=\"http://octave.org\">http://octave.org</a>."));
1809 
1810  msg->setStyleSheet ("background-color: #ffd97f; color: black; margin 4px;");
1811  msg->setMinimumWidth (100);
1812  msg->setMinimumHeight (60);
1813  msg->setMaximumHeight (80);
1814  msg->setSizePolicy (QSizePolicy (QSizePolicy::Expanding,
1815  QSizePolicy::Minimum));
1816 
1817  QPushButton *info_button = new QPushButton (tr ("More Info"), box);
1818  QPushButton *hide_button = new QPushButton (tr ("Hide"), box);
1819 
1820  connect (info_button, SIGNAL (clicked ()),
1821  this, SLOT (show_gui_info ()));
1822 
1823  connect (hide_button, SIGNAL (clicked ()),
1824  this, SLOT (hide_warning_bar ()));
1825 
1826  QVBoxLayout *button_layout = new QVBoxLayout;
1827 
1828  button_layout->addWidget (info_button);
1829  button_layout->addWidget (hide_button);
1830 
1831  QHBoxLayout *icon_and_message = new QHBoxLayout;
1832 
1833  icon_and_message->addWidget (icon);
1834  icon_and_message->addSpacing (10);
1835  icon_and_message->addWidget (msg);
1836  icon_and_message->addSpacing (10);
1837  icon_and_message->addLayout (button_layout);
1838 
1839  icon_and_message->setAlignment (hide_button, Qt::AlignTop);
1840 
1841  box->setFrameStyle (QFrame::Box);
1842  box->setLineWidth (2);
1843  box->setMaximumWidth (1000);
1844  box->adjustSize ();
1845  box->setLayout (icon_and_message);
1846 
1847  _warning_bar->setFeatures (QDockWidget::NoDockWidgetFeatures);
1848  _warning_bar->setObjectName ("WarningToolBar");
1849  _warning_bar->setWidget (box);
1850 
1851  setCorner (Qt::TopLeftCorner, Qt::TopDockWidgetArea);
1852  setCorner (Qt::TopRightCorner, Qt::TopDockWidgetArea);
1853 
1854  addDockWidget (Qt::TopDockWidgetArea, _warning_bar);
1855 };
1856 
1857 void
1859 {
1860  QIcon warning_icon
1861  = QIcon::fromTheme ("dialog-warning",
1862  QIcon (":/actions/icons/warning.png"));
1863 
1865  = new QPushButton (warning_icon, tr ("Experimental GUI Info"));
1866 
1867  _main_tool_bar->addWidget (_gui_info_button);
1868 
1869  connect (_gui_info_button, SIGNAL (clicked ()),
1870  this, SLOT (show_gui_info ()));
1871 }
1872 
1873 void
1875 {
1876  QSettings *settings = resource_manager::get_settings ();
1877 
1878  if (settings)
1879  {
1880  settings->setValue ("General/hide_new_gui_warning", true);
1881 
1882  settings->sync ();
1883  }
1884 
1885  removeDockWidget (_warning_bar);
1886 
1888 }
1889 
1890 void
1892 {
1893  QString gui_info
1894  (tr ("<p><strong>A Note about Octave's New GUI</strong></p>"
1895  "<p>One of the biggest new features for Octave 3.8 is a graphical "
1896  "user interface. It is the one thing that users have requested "
1897  "most often over the last few years and now it is almost ready. "
1898  "But because it is not quite as polished as we would like, we "
1899  "have decided to wait until the 4.0.x release series before "
1900  "making the GUI the default interface.</p>"
1901  "<p>Given the length of time and the number of bug fixes and "
1902  "improvements since the last major release, we also "
1903  "decided against delaying the release of all these new "
1904  "improvements any longer just to perfect the GUI. So please "
1905  "enjoy the 3.8 release of Octave and the preview of the new GUI. "
1906  "We believe it is working reasonably well, but we also know that "
1907  "there are some obvious rough spots and many things that could be "
1908  "improved.</p>"
1909  "<p><strong>We Need Your Help</strong></p>"
1910  "<p>There are many ways that you can help us fix the remaining "
1911  "problems, complete the GUI, and improve the overall user "
1912  "experience for both novices and experts alike (links will open "
1913  "an external browser):</p>"
1914  "<p><ul><li>If you are a skilled software developer, you can "
1915  "help by contributing your time to help "
1916  "<a href=\"http://octave.org/get-involved.html\">develop "
1917  "Octave</a>.</li>"
1918  "<li>If Octave does not work properly, you are encouraged to "
1919  "<a href=\"http://octave.org/bugs.html\">report problems </a> "
1920  "that you find.</li>"
1921  "<li>Whether you are a user or developer, you can "
1922  "<a href=\"http://octave.org/donate.html\">help to fund the "
1923  "project</a>. "
1924  "Octave development takes a lot of time and expertise. "
1925  "Your contributions help to ensure that Octave will continue "
1926  "to improve.</li></ul></p>"
1927  "<p>We hope you find Octave to be useful. Please help us make "
1928  "it even better for the future!</p>"));
1929 
1930  QMessageBox gui_info_dialog (QMessageBox::Warning,
1931  tr ("Experimental GUI Info"),
1932  gui_info, QMessageBox::Close);
1933 
1934  gui_info_dialog.exec ();
1935 }
1936 
1937 void
1939 {
1940  _main_tool_bar = addToolBar ("Main");
1941 
1942  _main_tool_bar->setObjectName ("MainToolBar");
1943  _main_tool_bar->addAction (_new_script_action);
1944  _main_tool_bar->addAction (_open_action);
1945 
1946  _main_tool_bar->addSeparator ();
1947 
1948  _main_tool_bar->addAction (_copy_action);
1949  _main_tool_bar->addAction (_paste_action);
1950  _main_tool_bar->addAction (_undo_action);
1951 
1952  _main_tool_bar->addSeparator ();
1953 
1954  _current_directory_combo_box = new QComboBox (this);
1956  _current_directory_combo_box->setEditable (true);
1957  _current_directory_combo_box->setInsertPolicy (QComboBox::NoInsert);
1958  _current_directory_combo_box->setToolTip (tr ("Enter directory name"));
1959  _current_directory_combo_box->setMaxVisibleItems (
1962  QSizePolicy sizePol (QSizePolicy::Expanding, QSizePolicy::Preferred);
1963  _current_directory_combo_box->setSizePolicy (sizePol);
1964 
1965  // addWidget takes ownership of the objects so there is no
1966  // need to delete these upon destroying this main_window.
1967  _main_tool_bar->addWidget (new QLabel (tr ("Current Directory: ")));
1969  QAction *current_dir_up = _main_tool_bar->addAction (
1970  QIcon (":/actions/icons/up.png"),
1971  tr ("One directory up"));
1972  QAction *current_dir_search = _main_tool_bar->addAction (
1973  QIcon (":/actions/icons/search.png"),
1974  tr ("Browse directories"));
1975 
1976  connect (_current_directory_combo_box, SIGNAL (activated (QString)),
1977  this, SLOT (set_current_working_directory (QString)));
1978 
1979  connect (_current_directory_combo_box->lineEdit (), SIGNAL (returnPressed ()),
1980  this, SLOT (accept_directory_line_edit ()));
1981 
1982  connect (current_dir_search, SIGNAL (triggered ()),
1983  this, SLOT (browse_for_directory ()));
1984 
1985  connect (current_dir_up, SIGNAL (triggered ()),
1986  this, SLOT (change_directory_up ()));
1987 
1988  connect (_undo_action, SIGNAL (triggered ()),
1989  this, SLOT (handle_undo_request ()));
1990 }
1991 
1992 void
1993 main_window::save_workspace_callback (const std::string& file)
1994 {
1995  Fsave (ovl (file));
1996 }
1997 
1998 void
1999 main_window::load_workspace_callback (const std::string& file)
2000 {
2001  Fload (ovl (file));
2002 
2004 }
2005 
2006 void
2008 {
2009  Fclear ();
2010 }
2011 
2012 void
2014 {
2015  /* bool status = */ symbol_table::rename (names.first, names.second);
2016 
2017  // if (status)
2019 
2020  // else
2021  // ; // we need an octave_link action that runs a GUI error option.
2022 }
2023 
2024 void
2026 {
2029 }
2030 
2031 void
2033 {
2034  Fclc ();
2036 }
2037 
2038 void
2040 {
2042 }
2043 
2044 void
2046 {
2047  Fhistory (ovl ("-c"));
2048 }
2049 
2050 void
2052 {
2053  bool repost = false; // flag for reposting event for this callback
2054 
2055  if (!_cmd_queue->isEmpty ()) // list can not be empty here, just to make sure
2056  {
2057  std::string pending_input = command_editor::get_current_line ();
2058  command_editor::set_initial_input (pending_input);
2059 
2060  _cmd_queue_mutex.lock (); // critical path
2061  std::string command = _cmd_queue->takeFirst ().toStdString ();
2062  if (_cmd_queue->isEmpty ())
2063  _cmd_processing.release (); // cmd queue empty, processing will stop
2064  else
2065  repost = true; // not empty, repost at end
2066  _cmd_queue_mutex.unlock ();
2067 
2068  command_editor::replace_line (command);
2069 
2071  // We are executing inside the command editor event loop. Force
2072  // the current line to be returned for processing.
2074  }
2075 
2076  if (repost) // queue not empty, so repost event for further processing
2078 
2079 }
2080 
2081 void
2083 {
2084  Fbuiltin (ovl ("figure"));
2085  Fdrawnow ();
2086 }
2087 
2088 void
2089 main_window::change_directory_callback (const std::string& directory)
2090 {
2091  Fcd (ovl (directory));
2092 }
2093 
2094 void
2096 {
2097  Fdbcont ();
2098 
2100 }
2101 
2102 // The next three callbacks are invoked by GUI buttons. Those buttons
2103 // should only be active when we are doing debugging, which means that
2104 // Octave is waiting for input in get_debug_input. Calling
2105 // command_editor::interrupt will force readline to return even if it
2106 // has not read any input, and then get_debug_input will return,
2107 // allowing the evaluator to continue and execute the next statement.
2108 
2109 void
2111 {
2112  Fdbstep (ovl ("in"));
2113 
2115 }
2116 
2117 void
2119 {
2120  Fdbstep ();
2121 
2123 }
2124 
2125 void
2127 {
2128  Fdbstep (ovl ("out"));
2129 
2131 }
2132 
2133 void
2135 {
2136  Fdbquit ();
2137 
2139 }
2140 
2141 void
2143 {
2144  Fquit ();
2145 }
2146 
2147 void
2148 main_window::find_files (const QString &start_dir)
2149 {
2150 
2151  if (! find_files_dlg)
2152  {
2153  find_files_dlg = new find_files_dialog (this);
2154 
2155  connect (find_files_dlg, SIGNAL (finished (int)),
2156  this, SLOT (find_files_finished (int)));
2157 
2158  connect (find_files_dlg, SIGNAL (dir_selected (const QString &)),
2160  SLOT (set_current_directory (const QString&)));
2161 
2162  connect (find_files_dlg, SIGNAL (file_selected (const QString &)),
2163  this, SLOT (open_file (const QString &)));
2164 
2165  find_files_dlg->setWindowModality (Qt::NonModal);
2166  }
2167 
2168  if (! find_files_dlg->isVisible ())
2169  {
2170  find_files_dlg->show ();
2171  }
2172 
2173  find_files_dlg->set_search_dir (start_dir);
2174 
2175  find_files_dlg->activateWindow ();
2176 
2177 }
2178 
2179 void
2181 {
2182 
2183 }
2184 
2185 void
2187 {
2188  if (set_shortcuts)
2189  {
2190 
2191  _open_action->setShortcut (QKeySequence::Open);
2192  _new_script_action->setShortcut (QKeySequence::New);
2193  _new_function_action->setShortcut (Qt::ControlModifier
2194  + Qt::ShiftModifier
2195  + Qt::Key_N);
2196 
2197  _exit_action->setShortcut (QKeySequence::Quit);
2198 
2199  _find_files_action->setShortcut (Qt::ControlModifier
2200  + Qt::ShiftModifier
2201  + Qt::Key_F);
2202 
2203  }
2204  else
2205  {
2206 
2207  QKeySequence no_key = QKeySequence ();
2208 
2209  _open_action->setShortcut (no_key);
2210  _new_script_action->setShortcut (no_key);
2211  _new_function_action->setShortcut (no_key);
2212 
2213  _exit_action->setShortcut (no_key);
2214 
2215  _find_files_action->setShortcut (no_key);
2216 
2217  }
2218 
2219  emit set_widget_shortcuts_signal (set_shortcuts);
2220 }
2221 
2222 void
2223 main_window::handle_show_doc (const QString& file)
2224 {
2225  doc_browser_window->setVisible (true);
2226  emit show_doc_signal (file);
2227 }
2228 
2229 void
2230 main_window::clipboard_has_changed (QClipboard::Mode cp_mode)
2231 {
2232  if (cp_mode == QClipboard::Clipboard)
2233  {
2234  if (_clipboard->text ().isEmpty ())
2235  {
2236  _paste_action->setEnabled (false);
2237  _clear_clipboard_action->setEnabled (false);
2238  }
2239  else
2240  {
2241  _paste_action->setEnabled (true);
2242  _clear_clipboard_action->setEnabled (true);
2243  }
2244  }
2245 }
2246 
2247 void
2249 {
2250  _clipboard->clear (QClipboard::Clipboard);
2251 }