]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiApplication.cpp
69e5f09a28b06979f2409e807f456a75494e25bd
[lyx.git] / src / frontends / qt4 / GuiApplication.cpp
1 /**
2  * \file GuiApplication.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author unknown
7  * \author John Levon
8  * \author Abdelrazak Younes
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiApplication.h"
16
17 #include "qt_helpers.h"
18 #include "GuiImage.h"
19 #include "GuiKeySymbol.h"
20 #include "GuiView.h"
21
22 #include "frontends/alert.h"
23 #include "frontends/Application.h"
24 #include "frontends/FontLoader.h"
25 #include "frontends/FontMetrics.h"
26
27 #include "Buffer.h"
28 #include "BufferList.h"
29 #include "BufferView.h"
30 #include "Font.h"
31 #include "FuncRequest.h"
32 #include "FuncStatus.h"
33 #include "LyX.h"
34 #include "LyXFunc.h"
35 #include "LyXRC.h"
36 #include "Session.h"
37 #include "version.h"
38
39 #include "support/debug.h"
40 #include "support/ExceptionMessage.h"
41 #include "support/FileName.h"
42 #include "support/ForkedCalls.h"
43 #include "support/gettext.h"
44 #include "support/lstrings.h"
45 #include "support/os.h"
46 #include "support/Package.h"
47
48 #include <QApplication>
49 #include <QClipboard>
50 #include <QEventLoop>
51 #include <QFileOpenEvent>
52 #include <QLocale>
53 #include <QLibraryInfo>
54 #include <QMenuBar>
55 #include <QPixmapCache>
56 #include <QRegExp>
57 #include <QSessionManager>
58 #include <QSocketNotifier>
59 #include <QTextCodec>
60 #include <QTimer>
61 #include <QTranslator>
62 #include <QWidget>
63
64 #ifdef Q_WS_X11
65 #include <X11/Xatom.h>
66 #include <X11/Xlib.h>
67 #undef CursorShape
68 #undef None
69 #endif
70
71 #include <boost/bind.hpp>
72
73 #include <exception>
74
75 using namespace std;
76 using namespace lyx::support;
77
78 namespace lyx {
79
80 frontend::Application * createApplication(int & argc, char * argv[])
81 {
82         return new frontend::GuiApplication(argc, argv);
83 }
84
85
86 namespace frontend {
87
88 class SocketNotifier : public QSocketNotifier
89 {
90 public:
91         /// connect a connection notification from the LyXServerSocket
92         SocketNotifier(QObject * parent, int fd, Application::SocketCallback func)
93                 : QSocketNotifier(fd, QSocketNotifier::Read, parent), func_(func)
94         {}
95
96 public:
97         /// The callback function
98         Application::SocketCallback func_;
99 };
100
101
102 ////////////////////////////////////////////////////////////////////////
103 // Mac specific stuff goes here...
104
105 class MenuTranslator : public QTranslator
106 {
107 public:
108         MenuTranslator(QObject * parent)
109                 : QTranslator(parent)
110         {}
111
112         QString translate(const char * /*context*/, 
113           const char * sourceText, 
114           const char * /*comment*/ = 0) 
115         {
116                 string const s = sourceText;
117                 if (s == N_("About %1") || s == N_("Preferences") 
118                                 || s == N_("Reconfigure") || s == N_("Quit %1"))
119                         return qt_(s);
120                 else 
121                         return QString();
122         }
123 };
124
125 class GlobalMenuBar : public QMenuBar
126 {
127 public:
128         ///
129         GlobalMenuBar() : QMenuBar(0) {}
130         
131         ///
132         bool event(QEvent * e)
133         {
134                 if (e->type() == QEvent::ShortcutOverride) {
135                         //          && activeWindow() == 0) {
136                         QKeyEvent * ke = static_cast<QKeyEvent*>(e);
137                         KeySymbol sym;
138                         setKeySymbol(&sym, ke);
139                         theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers()));
140                         e->accept();
141                         return true;
142                 }
143                 return false;
144         }
145 };
146
147 ///////////////////////////////////////////////////////////////
148 // You can find more platform specific stuff
149 // at the end of this file...
150 ///////////////////////////////////////////////////////////////
151
152
153 GuiApplication * guiApp;
154
155
156 GuiApplication::GuiApplication(int & argc, char ** argv)
157         : QApplication(argc, argv), Application(), current_view_(0), global_menubar_(0)
158 {
159         QString app_name = "LyX";
160         QCoreApplication::setOrganizationName(app_name);
161         QCoreApplication::setOrganizationDomain("lyx.org");
162         QCoreApplication::setApplicationName(app_name + "-" + lyx_version);
163
164         // FIXME: quitOnLastWindowClosed is true by default. We should have a
165         // lyxrc setting for this in order to let the application stay resident.
166         // But then we need some kind of dock icon, at least on Windows.
167         /*
168         if (lyxrc.quit_on_last_window_closed)
169                 setQuitOnLastWindowClosed(false);
170         */
171 #ifdef Q_WS_MAC
172         setQuitOnLastWindowClosed(false);
173 #endif
174         
175 #ifdef Q_WS_X11
176         // doubleClickInterval() is 400 ms on X11 which is just too long.
177         // On Windows and Mac OS X, the operating system's value is used.
178         // On Microsoft Windows, calling this function sets the double
179         // click interval for all applications. So we don't!
180         QApplication::setDoubleClickInterval(300);
181 #endif
182
183         // install translation file for Qt built-in dialogs
184         QString language_name = QString("qt_") + QLocale::system().name();
185         
186         // language_name can be short (e.g. qt_zh) or long (e.g. qt_zh_CN). 
187         // Short-named translator can be loaded from a long name, but not the
188         // opposite. Therefore, long name should be used without truncation.
189         // c.f. http://doc.trolltech.com/4.1/qtranslator.html#load
190         if (qt_trans_.load(language_name,
191                 QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
192         {
193                 installTranslator(&qt_trans_);
194                 // even if the language calls for RtL, don't do that
195                 setLayoutDirection(Qt::LeftToRight);
196                 LYXERR(Debug::GUI, "Successfully installed Qt translations for locale "
197                         << fromqstr(language_name));
198         } else
199                 LYXERR(Debug::GUI, "Could not find  Qt translations for locale "
200                         << fromqstr(language_name));
201
202 #ifdef Q_WS_MACX
203         // This allows to translate the strings that appear in the LyX menu.
204         addMenuTranslator();
205 #endif
206         connect(this, SIGNAL(lastWindowClosed()), this, SLOT(onLastWindowClosed()));
207
208         using namespace lyx::graphics;
209
210         Image::newImage = boost::bind(&GuiImage::newImage);
211         Image::loadableFormats = boost::bind(&GuiImage::loadableFormats);
212
213         // needs to be done before reading lyxrc
214         QWidget w;
215         lyxrc.dpi = (w.logicalDpiX() + w.logicalDpiY()) / 2;
216
217         guiApp = this;
218
219         // Set the cache to 5120 kilobytes which corresponds to screen size of
220         // 1280 by 1024 pixels with a color depth of 32 bits.
221         QPixmapCache::setCacheLimit(5120);
222
223         // Initialize RC Fonts
224         if (lyxrc.roman_font_name.empty())
225                 lyxrc.roman_font_name = fromqstr(romanFontName());
226
227         if (lyxrc.sans_font_name.empty())
228                 lyxrc.sans_font_name = fromqstr(sansFontName());
229
230         if (lyxrc.typewriter_font_name.empty())
231                 lyxrc.typewriter_font_name = fromqstr(typewriterFontName());
232
233         general_timer_.setInterval(500);
234         connect(&general_timer_, SIGNAL(timeout()),
235                 this, SLOT(handleRegularEvents()));
236         general_timer_.start();
237         
238 #ifdef Q_WS_MACX
239         if (global_menubar_ == 0) {
240                 // Create the global default menubar which is shown for the dialogs
241                 // and if no GuiView is visible.
242                 global_menubar_ = new GlobalMenuBar();
243         }
244 #endif  
245 }
246
247
248 GuiApplication::~GuiApplication()
249 {
250         socket_notifiers_.clear();
251 }
252
253
254 FuncStatus GuiApplication::getStatus(FuncRequest const & cmd)
255 {
256         FuncStatus flag;
257         bool enable = true;
258
259         switch(cmd.action) {
260
261         case LFUN_WINDOW_CLOSE:
262                 enable = view_ids_.size() > 0;
263                 break;
264
265         default:
266                 if (!current_view_) {
267                         enable = false;
268                         break;
269                 }
270         }
271
272         if (!enable)
273                 flag.enabled(false);
274
275         return flag;
276 }
277
278         
279 bool GuiApplication::dispatch(FuncRequest const & cmd)
280 {
281         switch(cmd.action) {
282
283         case LFUN_WINDOW_NEW:
284                 createView(toqstr(cmd.argument()));
285                 break;
286
287         case LFUN_WINDOW_CLOSE:
288                 // update bookmark pit of the current buffer before window close
289                 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
290                         theLyXFunc().gotoBookmark(i+1, false, false);
291                 current_view_->close();
292                 break;
293
294         case LFUN_LYX_QUIT:
295                 // quitting is triggered by the gui code
296                 // (leaving the event loop).
297                 current_view_->message(from_utf8(N_("Exiting.")));
298                 if (closeAllViews())
299                         quit();
300                 break;
301
302         case LFUN_SCREEN_FONT_UPDATE: {
303                 // handle the screen font changes.
304                 font_loader_.update();
305                 // Backup current_view_
306                 GuiView * view = current_view_;
307                 // Set current_view_ to zero to forbid GuiWorkArea::redraw()
308                 // to skip the refresh.
309                 current_view_ = 0;
310                 BufferList::iterator it = theBufferList().begin();
311                 BufferList::iterator const end = theBufferList().end();
312                 for (; it != end; ++it)
313                         (*it)->changed();
314                 // Restore current_view_
315                 current_view_ = view;
316                 break;
317         }
318
319         case LFUN_BUFFER_NEW:
320                 if (viewCount() == 0
321                     || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0))
322                         createView();
323                 current_view_->newDocument(to_utf8(cmd.argument()), false);
324                 break;
325
326         case LFUN_BUFFER_NEW_TEMPLATE:
327                 if (viewCount() == 0 
328                     || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) {
329                         createView();
330                         current_view_->newDocument(to_utf8(cmd.argument()), true);
331                         if (!current_view_->buffer())
332                                 current_view_->close();
333                 } else
334                         current_view_->newDocument(to_utf8(cmd.argument()), true);
335                 break;
336
337         case LFUN_FILE_OPEN:
338                 if (viewCount() == 0
339                     || (!lyxrc.open_buffers_in_tabs && current_view_->buffer() != 0)) {
340                         createView();
341                         current_view_->openDocument(to_utf8(cmd.argument()));
342                         if (!current_view_->buffer())
343                                 current_view_->close();
344                 } else
345                         current_view_->openDocument(to_utf8(cmd.argument()));
346                 break;
347
348         default:
349                 // Notify the caller that the action has not been dispatched.
350                 return false;
351         }
352
353         // The action has been dispatched.
354         return true;
355 }
356
357
358 void GuiApplication::resetGui()
359 {
360         map<int, GuiView *>::iterator it;
361         for (it = views_.begin(); it != views_.end(); ++it)
362                 it->second->resetDialogs();
363
364         dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE));
365 }
366
367
368 static void updateIds(map<int, GuiView *> const & stdmap, vector<int> & ids)
369 {
370         ids.clear();
371         map<int, GuiView *>::const_iterator it;
372         for (it = stdmap.begin(); it != stdmap.end(); ++it)
373                 ids.push_back(it->first);
374 }
375
376
377 void GuiApplication::createView(QString const & geometry_arg)
378 {
379         if (global_menubar_)
380                 global_menubar_->releaseKeyboard();
381
382         // create new view
383         updateIds(views_, view_ids_);
384         int id = 0;
385         while (views_.find(id) != views_.end())
386                 id++;
387         GuiView * view = new GuiView(id);
388         
389         // copy the icon size from old view
390         if (viewCount() > 0)
391                 view->setIconSize(current_view_->iconSize());
392
393         // register view
394         views_[id] = view;
395         updateIds(views_, view_ids_);
396
397         view->show();
398         if (!geometry_arg.isEmpty()) {
399 #ifdef Q_WS_WIN
400                 int x, y;
401                 int w, h;
402                 QRegExp re( "[=]*(?:([0-9]+)[xX]([0-9]+)){0,1}[ ]*(?:([+-][0-9]*)([+-][0-9]*)){0,1}" );
403                 re.indexIn(geometry_arg);
404                 w = re.cap(1).toInt();
405                 h = re.cap(2).toInt();
406                 x = re.cap(3).toInt();
407                 y = re.cap(4).toInt();
408                 view->setGeometry(x, y, w, h);
409 #endif
410         }
411         view->setFocus();
412         setActiveWindow(view);
413         setCurrentView(*view);
414 }
415
416
417
418
419 Clipboard & GuiApplication::clipboard()
420 {
421         return clipboard_;
422 }
423
424
425 Selection & GuiApplication::selection()
426 {
427         return selection_;
428 }
429
430
431 int GuiApplication::exec()
432 {
433         QTimer::singleShot(1, this, SLOT(execBatchCommands()));
434         return QApplication::exec();
435 }
436
437
438 void GuiApplication::exit(int status)
439 {
440         QApplication::exit(status);
441 }
442
443
444 void GuiApplication::execBatchCommands()
445 {
446         LyX::ref().execBatchCommands();
447 }
448
449
450 void GuiApplication::restoreGuiSession()
451 {
452         if (!lyxrc.load_session)
453                 return;
454
455         Session & session = LyX::ref().session();
456         vector<FileName> const & lastopened = session.lastOpened().getfiles();
457         // do not add to the lastfile list since these files are restored from
458         // last session, and should be already there (regular files), or should
459         // not be added at all (help files).
460         for_each(lastopened.begin(), lastopened.end(),
461                 bind(&GuiView::loadDocument, current_view_, _1, false));
462
463         // clear this list to save a few bytes of RAM
464         session.lastOpened().clear();
465 }
466
467
468 QString const GuiApplication::romanFontName()
469 {
470         QFont font;
471         font.setKerning(false);
472         font.setStyleHint(QFont::Serif);
473         font.setFamily("serif");
474
475         return QFontInfo(font).family();
476 }
477
478
479 QString const GuiApplication::sansFontName()
480 {
481         QFont font;
482         font.setKerning(false);
483         font.setStyleHint(QFont::SansSerif);
484         font.setFamily("sans");
485
486         return QFontInfo(font).family();
487 }
488
489
490 QString const GuiApplication::typewriterFontName()
491 {
492         QFont font;
493         font.setKerning(false);
494         font.setStyleHint(QFont::TypeWriter);
495         font.setFamily("monospace");
496
497         return QFontInfo(font).family();
498 }
499
500
501 void GuiApplication::handleRegularEvents()
502 {
503         ForkedCallsController::handleCompletedProcesses();
504 }
505
506
507 bool GuiApplication::event(QEvent * e)
508 {
509         switch(e->type()) {
510         case QEvent::FileOpen: {
511                 // Open a file; this happens only on Mac OS X for now
512                 QFileOpenEvent * foe = static_cast<QFileOpenEvent *>(e);
513
514                 if (!current_view_ || !current_view_->view())
515                         // The application is not properly initialized yet.
516                         // So we acknowledge the event and delay the file opening
517                         // until LyX is ready.
518                         // FIXME UNICODE: FileName accept an utf8 encoded string.
519                         LyX::ref().addFileToLoad(fromqstr(foe->file()));
520                 else
521                         lyx::dispatch(FuncRequest(LFUN_FILE_OPEN,
522                                 qstring_to_ucs4(foe->file())));
523
524                 e->accept();
525                 return true;
526         }
527         default:
528                 return QApplication::event(e);
529         }
530 }
531
532
533 bool GuiApplication::notify(QObject * receiver, QEvent * event)
534 {
535         try {
536                 return QApplication::notify(receiver, event);
537         }
538         catch (ExceptionMessage const & e) {
539                 switch(e.type_) { 
540                 case ErrorException:
541                         LyX::cref().emergencyCleanup();
542                         setQuitOnLastWindowClosed(false);
543                         closeAllViews();
544                         Alert::error(e.title_, e.details_);
545 #ifndef NDEBUG
546                         // Properly crash in debug mode in order to get a useful backtrace.
547                         abort();
548 #endif
549                         // In release mode, try to exit gracefully.
550                         this->exit(1);
551
552                 case BufferException: {
553                         Buffer * buf = current_view_->buffer();
554                         docstring details = e.details_ + '\n';
555                         details += theBufferList().emergencyWrite(buf);
556                         theBufferList().release(buf);
557                         details += _("\nThe current document was closed.");
558                         Alert::error(e.title_, details);
559                         return false;
560                 }
561                 case WarningException:
562                         Alert::warning(e.title_, e.details_);
563                         return false;
564                 };
565         }
566         catch (exception const & e) {
567                 docstring s = _("LyX has caught an exception, it will now "
568                         "attempt to save all unsaved documents and exit."
569                         "\n\nException: ");
570                 s += from_ascii(e.what());
571                 Alert::error(_("Software exception Detected"), s);
572                 LyX::cref().exit(1);
573         }
574         catch (...) {
575                 docstring s = _("LyX has caught some really weird exception, it will "
576                         "now attempt to save all unsaved documents and exit.");
577                 Alert::error(_("Software exception Detected"), s);
578                 LyX::cref().exit(1);
579         }
580
581         return false;
582 }
583
584
585 bool GuiApplication::getRgbColor(ColorCode col, RGBColor & rgbcol)
586 {
587         QColor const & qcol = color_cache_.get(col);
588         if (!qcol.isValid()) {
589                 rgbcol.r = 0;
590                 rgbcol.g = 0;
591                 rgbcol.b = 0;
592                 return false;
593         }
594         rgbcol.r = qcol.red();
595         rgbcol.g = qcol.green();
596         rgbcol.b = qcol.blue();
597         return true;
598 }
599
600
601 string const GuiApplication::hexName(ColorCode col)
602 {
603         return ltrim(fromqstr(color_cache_.get(col).name()), "#");
604 }
605
606
607 void GuiApplication::updateColor(ColorCode)
608 {
609         // FIXME: Bleh, can't we just clear them all at once ?
610         color_cache_.clear();
611 }
612
613
614 void GuiApplication::registerSocketCallback(int fd, SocketCallback func)
615 {
616         SocketNotifier * sn = new SocketNotifier(this, fd, func);
617         socket_notifiers_[fd] = sn;
618         connect(sn, SIGNAL(activated(int)), this, SLOT(socketDataReceived(int)));
619 }
620
621
622 void GuiApplication::socketDataReceived(int fd)
623 {
624         socket_notifiers_[fd]->func_();
625 }
626
627
628 void GuiApplication::unregisterSocketCallback(int fd)
629 {
630         socket_notifiers_.erase(fd);
631 }
632
633
634 void GuiApplication::commitData(QSessionManager & sm)
635 {
636         /// The implementation is required to avoid an application exit
637         /// when session state save is triggered by session manager.
638         /// The default implementation sends a close event to all
639         /// visible top level widgets when session managment allows
640         /// interaction.
641         /// We are changing that to close all wiew one by one.
642         /// FIXME: verify if the default implementation is enough now.
643         if (sm.allowsInteraction() && !closeAllViews())
644                 sm.cancel();
645 }
646
647
648 void GuiApplication::addMenuTranslator()
649 {
650         installTranslator(new MenuTranslator(this));
651 }
652
653
654 bool GuiApplication::unregisterView(int id)
655 {
656         updateIds(views_, view_ids_);
657         BOOST_ASSERT(views_.find(id) != views_.end());
658         BOOST_ASSERT(views_[id]);
659
660         map<int, GuiView *>::iterator it;
661         for (it = views_.begin(); it != views_.end(); ++it) {
662                 if (it->first == id) {
663                         views_.erase(id);
664                         break;
665                 }
666         }
667         updateIds(views_, view_ids_);
668         return true;
669 }
670
671
672 bool GuiApplication::closeAllViews()
673 {
674         updateIds(views_, view_ids_);
675         if (views_.empty())
676                 return true;
677
678         map<int, GuiView*> const cmap = views_;
679         map<int, GuiView*>::const_iterator it;
680         for (it = cmap.begin(); it != cmap.end(); ++it) {
681                 if (!it->second->close())
682                         return false;
683         }
684
685         views_.clear();
686         view_ids_.clear();
687         return true;
688 }
689
690
691 GuiView & GuiApplication::view(int id) const
692 {
693         BOOST_ASSERT(views_.find(id) != views_.end());
694         return *views_.find(id)->second;
695 }
696
697
698 void GuiApplication::hideDialogs(string const & name, Inset * inset) const
699 {
700         vector<int>::const_iterator it = view_ids_.begin();
701         vector<int>::const_iterator const end = view_ids_.end();
702         for (; it != end; ++it)
703                 view(*it).hideDialog(name, inset);
704 }
705
706
707 Buffer const * GuiApplication::updateInset(Inset const * inset) const
708 {
709         Buffer const * buffer_ = 0;
710         vector<int>::const_iterator it = view_ids_.begin();
711         vector<int>::const_iterator const end = view_ids_.end();
712         for (; it != end; ++it) {
713                 Buffer const * ptr = view(*it).updateInset(inset);
714                 if (ptr)
715                         buffer_ = ptr;
716         }
717         return buffer_;
718 }
719
720
721 void GuiApplication::readMenus(Lexer & lex)
722 {
723         menus().read(lex);
724 }
725
726
727 bool GuiApplication::searchMenu(FuncRequest const & func,
728         vector<docstring> & names) const
729 {
730         return menus().searchMenu(func, names);
731 }
732
733
734 void GuiApplication::initGlobalMenu()
735 {
736         if (global_menubar_)
737                 menus().fillMenuBar(global_menubar_, 0);
738 }
739
740
741 void GuiApplication::onLastWindowClosed()
742 {
743         if (global_menubar_)
744                 global_menubar_->grabKeyboard();
745 }
746
747 ////////////////////////////////////////////////////////////////////////
748 // X11 specific stuff goes here...
749 #ifdef Q_WS_X11
750 bool GuiApplication::x11EventFilter(XEvent * xev)
751 {
752         if (!current_view_)
753                 return false;
754
755         switch (xev->type) {
756         case SelectionRequest: {
757                 if (xev->xselectionrequest.selection != XA_PRIMARY)
758                         break;
759                 LYXERR(Debug::GUI, "X requested selection.");
760                 BufferView * bv = current_view_->view();
761                 if (bv) {
762                         docstring const sel = bv->requestSelection();
763                         if (!sel.empty())
764                                 selection_.put(sel);
765                 }
766                 break;
767         }
768         case SelectionClear: {
769                 if (xev->xselectionclear.selection != XA_PRIMARY)
770                         break;
771                 LYXERR(Debug::GUI, "Lost selection.");
772                 BufferView * bv = current_view_->view();
773                 if (bv)
774                         bv->clearSelection();
775                 break;
776         }
777         }
778         return false;
779 }
780 #endif
781
782 } // namespace frontend
783
784
785 ////////////////////////////////////////////////////////////////////
786 //
787 // Font stuff
788 //
789 ////////////////////////////////////////////////////////////////////
790
791 frontend::FontLoader & theFontLoader()
792 {
793         BOOST_ASSERT(frontend::guiApp);
794         return frontend::guiApp->fontLoader();
795 }
796
797
798 frontend::FontMetrics const & theFontMetrics(Font const & f)
799 {
800         return theFontMetrics(f.fontInfo());
801 }
802
803
804 frontend::FontMetrics const & theFontMetrics(FontInfo const & f)
805 {
806         BOOST_ASSERT(frontend::guiApp);
807         return frontend::guiApp->fontLoader().metrics(f);
808 }
809
810
811 frontend::Clipboard & theClipboard()
812 {
813         BOOST_ASSERT(frontend::guiApp);
814         return frontend::guiApp->clipboard();
815 }
816
817
818 frontend::Selection & theSelection()
819 {
820         BOOST_ASSERT(frontend::guiApp);
821         return frontend::guiApp->selection();
822 }
823
824 } // namespace lyx
825
826 #include "GuiApplication_moc.cpp"