Mercurial > octave
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 } |