comparison libgui/src/octave-qobject.cc @ 27197:b8c0d5ad024f

refactor and rename some qt application objects * octave-qobject.h, octave-qobject.cc: New files. Move octave_qapplication, octave_qt_app, octave_qt_cli_app, and octave_qt_gui_app classes here from main-window.h and main-window.cc. Rename octave_qt_app to base_qobject. Rename octave_qt_cli_app to cli_qobject. Rename octave_qt_gui_app to gui_qobject. * qt-application.h, qt-application.cc: Rename from octave-gui.h and octave-gui.cc. Rename gui_application class to qt_application. Change all uses. * libgui/src/module.mk: Update.
author John W. Eaton <jwe@octave.org>
date Sat, 22 Jun 2019 17:30:16 -0500
parents
children a044202208af
comparison
equal deleted inserted replaced
27196:d993642352d0 27197:b8c0d5ad024f
1 /*
2
3 Copyright (C) 2013-2019 John W. Eaton
4 Copyright (C) 2011-2019 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
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21
22 */
23
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27
28 #include <QApplication>
29 #include <QFile>
30 #include <QTextCodec>
31 #include <QThread>
32 #include <QTranslator>
33 #include <QTimer>
34
35 #include <utility>
36
37 #include "dialog.h"
38 #include "interpreter-qobject.h"
39 #include "main-window.h"
40 #include "octave-qobject.h"
41 #include "octave-qt-link.h"
42 #include "qt-application.h"
43 #include "resource-manager.h"
44
45 #include "oct-env.h"
46 #include "version.h"
47
48 namespace octave
49 {
50 // Disable all Qt messages by default.
51
52 static void
53 #if defined (QTMESSAGEHANDLER_ACCEPTS_QMESSAGELOGCONTEXT)
54 message_handler (QtMsgType, const QMessageLogContext &, const QString &)
55 #else
56 message_handler (QtMsgType, const char *)
57 #endif
58 { }
59
60 //! Reimplement QApplication::notify. Octave's own exceptions are
61 //! caught and rethrown in the interpreter thread.
62
63 bool octave_qapplication::notify (QObject *receiver, QEvent *ev)
64 {
65 try
66 {
67 return QApplication::notify (receiver, ev);
68 }
69 catch (execution_exception&)
70 {
71 octave_link::post_exception (std::current_exception ());
72 }
73
74 return false;
75 }
76
77 // We will create a QApplication object, even if START_GUI is false,
78 // so that we can use Qt widgets for plot windows when running in
79 // command-line mode. Note that we are creating an
80 // octave_qapplication object but handling it as a QApplication object
81 // because the octave_qapplication should behave identically to a
82 // QApplication object except that it overrides the notify method so
83 // we can handle forward Octave interpreter exceptions from the GUI
84 // thread to the interpreter thread.
85
86 base_qobject::base_qobject (qt_application& app_context)
87 : QObject (), m_app_context (app_context),
88 m_argc (m_app_context.sys_argc ()),
89 m_argv (m_app_context.sys_argv ()),
90 m_octave_qapp (new octave_qapplication (m_argc, m_argv)),
91 m_qt_tr (new QTranslator ()), m_gui_tr (new QTranslator ()),
92 m_qsci_tr (new QTranslator ()), m_translators_installed (false),
93 m_octave_qt_link (new octave_qt_link ()),
94 m_interpreter_qobject (new interpreter_qobject (m_app_context)),
95 m_main_thread (new QThread ())
96 {
97 std::string show_gui_msgs =
98 sys::env::getenv ("OCTAVE_SHOW_GUI_MESSAGES");
99
100 // Installing our handler suppresses the messages.
101
102 if (show_gui_msgs.empty ())
103 {
104 #if defined (HAVE_QINSTALLMESSAGEHANDLER)
105 qInstallMessageHandler (message_handler);
106 #else
107 qInstallMsgHandler (message_handler);
108 #endif
109 }
110
111 // Set the codec for all strings (before wizard or any GUI object)
112 #if ! defined (Q_OS_WIN32)
113 QTextCodec::setCodecForLocale (QTextCodec::codecForName ("UTF-8"));
114 #endif
115
116 #if defined (HAVE_QT4)
117 QTextCodec::setCodecForCStrings (QTextCodec::codecForName ("UTF-8"));
118 #endif
119
120 // Initialize global Qt application metadata.
121
122 QCoreApplication::setApplicationName ("GNU Octave");
123 QCoreApplication::setApplicationVersion (OCTAVE_VERSION);
124
125 // Register octave_value_list for connecting thread crossing signals.
126
127 qRegisterMetaType<octave_value_list> ("octave_value_list");
128
129 // Force left-to-right alignment (see bug #46204)
130 m_octave_qapp->setLayoutDirection (Qt::LeftToRight);
131
132 octave_link::connect_link (m_octave_qt_link);
133
134 connect (m_octave_qt_link, SIGNAL (confirm_shutdown_signal (void)),
135 this, SLOT (confirm_shutdown_octave (void)));
136
137 connect (m_octave_qt_link,
138 SIGNAL (copy_image_to_clipboard_signal (const QString&, bool)),
139 this, SLOT (copy_image_to_clipboard (const QString&, bool)));
140
141 connect_uiwidget_links ();
142
143 connect (m_interpreter_qobject, SIGNAL (octave_finished_signal (int)),
144 this, SLOT (handle_octave_finished (int)));
145
146 connect (m_interpreter_qobject, SIGNAL (octave_finished_signal (int)),
147 m_main_thread, SLOT (quit (void)));
148
149 connect (m_main_thread, SIGNAL (finished (void)),
150 m_main_thread, SLOT (deleteLater (void)));
151 }
152
153 base_qobject::~base_qobject (void)
154 {
155 delete m_interpreter_qobject;
156 delete m_octave_qapp;
157
158 string_vector::delete_c_str_vec (m_argv);
159 }
160
161 void base_qobject::config_translators (void)
162 {
163 if (m_translators_installed)
164 return;
165
166 resource_manager::config_translators (m_qt_tr, m_qsci_tr, m_gui_tr);
167
168 m_octave_qapp->installTranslator (m_qt_tr);
169 m_octave_qapp->installTranslator (m_gui_tr);
170 m_octave_qapp->installTranslator (m_qsci_tr);
171
172 m_translators_installed = true;
173 }
174
175 void base_qobject::start_main_thread (void)
176 {
177 // Defer initializing and executing the interpreter until after the main
178 // window and QApplication are running to prevent race conditions
179 QTimer::singleShot (0, m_interpreter_qobject, SLOT (execute (void)));
180
181 m_interpreter_qobject->moveToThread (m_main_thread);
182
183 m_main_thread->start ();
184 }
185
186 int base_qobject::exec (void)
187 {
188 return m_octave_qapp->exec ();
189 }
190
191 void base_qobject::handle_octave_finished (int exit_status)
192 {
193 qApp->exit (exit_status);
194 }
195
196 void base_qobject::confirm_shutdown_octave (void)
197 {
198 confirm_shutdown_octave_internal (true);
199 }
200
201 void base_qobject::copy_image_to_clipboard (const QString& file,
202 bool remove_file)
203 {
204 QClipboard *clipboard = QApplication::clipboard ();
205
206 QImage img (file);
207
208 if (img.isNull ())
209 {
210 // Report error?
211 return;
212 }
213
214 clipboard->setImage (img);
215
216 if (remove_file)
217 QFile::remove (file);
218 }
219
220 // Create a message dialog with specified string, buttons and decorative
221 // text.
222
223 void base_qobject::handle_create_dialog (const QString& message,
224 const QString& title,
225 const QString& icon,
226 const QStringList& button,
227 const QString& defbutton,
228 const QStringList& role)
229 {
230 MessageDialog *message_dialog = new MessageDialog (message, title, icon,
231 button, defbutton, role);
232 message_dialog->setAttribute (Qt::WA_DeleteOnClose);
233 message_dialog->show ();
234 }
235
236 // Create a list dialog with specified list, initially selected, mode,
237 // view size and decorative text.
238
239 void base_qobject::handle_create_listview (const QStringList& list,
240 const QString& mode,
241 int wd, int ht,
242 const QIntList& initial,
243 const QString& name,
244 const QStringList& prompt,
245 const QString& ok_string,
246 const QString& cancel_string)
247 {
248 ListDialog *list_dialog = new ListDialog (list, mode, wd, ht,
249 initial, name, prompt,
250 ok_string, cancel_string);
251
252 list_dialog->setAttribute (Qt::WA_DeleteOnClose);
253 list_dialog->show ();
254 }
255
256 // Create an input dialog with specified prompts and defaults, title and
257 // row/column size specifications.
258 void base_qobject::handle_create_inputlayout (const QStringList& prompt,
259 const QString& title,
260 const QFloatList& nr,
261 const QFloatList& nc,
262 const QStringList& defaults)
263 {
264 InputDialog *input_dialog = new InputDialog (prompt, title, nr, nc,
265 defaults);
266
267 input_dialog->setAttribute (Qt::WA_DeleteOnClose);
268 input_dialog->show ();
269 }
270
271 void base_qobject::handle_create_filedialog (const QStringList& filters,
272 const QString& title,
273 const QString& filename,
274 const QString& dirname,
275 const QString& multimode)
276 {
277 FileDialog *file_dialog = new FileDialog (filters, title, filename,
278 dirname, multimode);
279
280 file_dialog->setAttribute (Qt::WA_DeleteOnClose);
281 file_dialog->show ();
282 }
283
284 // Connect the signals emitted when the Octave thread wants to create
285 // a dialog box of some sort. Perhaps a better place for this would be
286 // as part of the QUIWidgetCreator class. However, mainWindow currently
287 // is not a global variable and not accessible for connecting.
288
289 void base_qobject::connect_uiwidget_links (void)
290 {
291 connect (&uiwidget_creator,
292 SIGNAL (create_dialog (const QString&, const QString&,
293 const QString&, const QStringList&,
294 const QString&, const QStringList&)),
295 this,
296 SLOT (handle_create_dialog (const QString&, const QString&,
297 const QString&, const QStringList&,
298 const QString&, const QStringList&)));
299
300 // Register QIntList so that list of ints may be part of a signal.
301 qRegisterMetaType<QIntList> ("QIntList");
302 connect (&uiwidget_creator,
303 SIGNAL (create_listview (const QStringList&, const QString&,
304 int, int, const QIntList&,
305 const QString&, const QStringList&,
306 const QString&, const QString&)),
307 this,
308 SLOT (handle_create_listview (const QStringList&, const QString&,
309 int, int, const QIntList&,
310 const QString&, const QStringList&,
311 const QString&, const QString&)));
312
313 // Register QFloatList so that list of floats may be part of a signal.
314 qRegisterMetaType<QFloatList> ("QFloatList");
315 connect (&uiwidget_creator,
316 SIGNAL (create_inputlayout (const QStringList&, const QString&,
317 const QFloatList&, const QFloatList&,
318 const QStringList&)),
319 this,
320 SLOT (handle_create_inputlayout (const QStringList&, const QString&,
321 const QFloatList&,
322 const QFloatList&,
323 const QStringList&)));
324
325 connect (&uiwidget_creator,
326 SIGNAL (create_filedialog (const QStringList &,const QString&,
327 const QString&, const QString&,
328 const QString&)),
329 this,
330 SLOT (handle_create_filedialog (const QStringList &, const QString&,
331 const QString&, const QString&,
332 const QString&)));
333 }
334
335 void base_qobject::confirm_shutdown_octave_internal (bool closenow)
336 {
337 // Wait for link thread to go to sleep state.
338 m_octave_qt_link->lock ();
339
340 m_octave_qt_link->shutdown_confirmation (closenow);
341
342 m_octave_qt_link->unlock ();
343
344 // Awake the worker thread so that it continues shutting down (or not).
345 m_octave_qt_link->wake_all ();
346 }
347
348 cli_qobject::cli_qobject (qt_application& app_context)
349 : base_qobject (app_context)
350 {
351 // Get settings file.
352 resource_manager::reload_settings ();
353
354 // After settings.
355 config_translators ();
356
357 m_octave_qapp->setQuitOnLastWindowClosed (false);
358
359 start_main_thread ();
360 }
361
362 gui_qobject::gui_qobject (qt_application& app_context)
363 : base_qobject (app_context),
364 m_main_window (new main_window (*this, m_octave_qt_link))
365 {
366 connect (m_interpreter_qobject, SIGNAL (octave_ready_signal (void)),
367 m_main_window, SLOT (handle_octave_ready (void)));
368
369 m_app_context.gui_running (true);
370
371 start_main_thread ();
372 }
373
374 gui_qobject::~gui_qobject (void)
375 {
376 delete m_main_window;
377 }
378
379 void gui_qobject::confirm_shutdown_octave (void)
380 {
381 bool closenow = true;
382
383 if (m_main_window)
384 closenow = m_main_window->confirm_shutdown_octave ();
385
386 confirm_shutdown_octave_internal (closenow);
387 }
388 }