1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "icore.h"
27
28 #include "windowsupport.h"
29 #include "dialogs/settingsdialog.h"
30
31 #include <app/app_version.h>
32 #include <extensionsystem/pluginmanager.h>
33
34 #include <utils/qtcassert.h>
35
36 #include <QApplication>
37 #include <QDebug>
38 #include <QStandardPaths>
39 #include <QSysInfo>
40
41 /*!
42 \namespace Core
43 \inmodule QtCreator
44 \brief The Core namespace contains all classes that make up the Core plugin
45 which constitute the basic functionality of \QC.
46 */
47
48 /*!
49 \enum Core::FindFlag
50 This enum holds the find flags.
51
52 \value FindBackward
53 Searches backwards.
54 \value FindCaseSensitively
55 Considers case when searching.
56 \value FindWholeWords
57 Finds only whole words.
58 \value FindRegularExpression
59 Uses a regular epression as a search term.
60 \value FindPreserveCase
61 Preserves the case when replacing search terms.
62 */
63
64 /*!
65 \enum Core::ICore::ContextPriority
66
67 This enum defines the priority of additional contexts.
68
69 \value High
70 Additional contexts that have higher priority than contexts from
71 Core::IContext instances.
72 \value Low
73 Additional contexts that have lower priority than contexts from
74 Core::IContext instances.
75
76 \sa Core::ICore::updateAdditionalContexts()
77 */
78
79 /*!
80 \enum Core::SaveSettingsReason
81 \internal
82 */
83
84 /*!
85 \namespace Core::Internal
86 \internal
87 */
88
89 /*!
90 \class Core::ICore
91 \inheaderfile coreplugin/icore.h
92 \inmodule QtCreator
93 \ingroup mainclasses
94
95 \brief The ICore class allows access to the different parts that make up
96 the basic functionality of \QC.
97
98 You should never create a subclass of this interface. The one and only
99 instance is created by the Core plugin. You can access this instance
100 from your plugin through instance().
101 */
102
103 /*!
104 \fn void Core::ICore::coreAboutToOpen()
105
106 Indicates that all plugins have been loaded and the main window is about to
107 be shown.
108 */
109
110 /*!
111 \fn void Core::ICore::coreOpened()
112 Indicates that all plugins have been loaded and the main window is shown.
113 */
114
115 /*!
116 \fn void Core::ICore::saveSettingsRequested(Core::ICore::SaveSettingsReason reason)
117 Signals that the user has requested that the global settings
118 should be saved to disk for a \a reason.
119
120 At the moment that happens when the application is closed, and on \uicontrol{Save All}.
121 */
122
123 /*!
124 \fn void Core::ICore::coreAboutToClose()
125 Enables plugins to perform some pre-end-of-life actions.
126
127 The application is guaranteed to shut down after this signal is emitted.
128 It is there as an addition to the usual plugin lifecycle functions, namely
129 \c IPlugin::aboutToShutdown(), just for convenience.
130 */
131
132 /*!
133 \fn void Core::ICore::contextAboutToChange(const QList<Core::IContext *> &context)
134 Indicates that a new \a context will shortly become the current context
135 (meaning that its widget got focus).
136 */
137
138 /*!
139 \fn void Core::ICore::contextChanged(const Core::Context &context)
140 Indicates that a new \a context just became the current context. This includes the context
141 from the focus object as well as the additional context.
142 */
143
144 #include "dialogs/newdialog.h"
145 #include "iwizardfactory.h"
146 #include "mainwindow.h"
147 #include "documentmanager.h"
148
149 #include <utils/hostosinfo.h>
150
151 #include <QCoreApplication>
152 #include <QDebug>
153 #include <QDir>
154 #include <QMessageBox>
155 #include <QPushButton>
156 #include <QStatusBar>
157
158 using namespace Core::Internal;
159 using namespace ExtensionSystem;
160 using namespace Utils;
161
162 namespace Core {
163
164 // The Core Singleton
165 static ICore *m_instance = nullptr;
166 static MainWindow *m_mainwindow = nullptr;
167
168 /*!
169 Returns the pointer to the instance. Only use for connecting to signals.
170 */
instance()171 ICore *ICore::instance()
172 {
173 return m_instance;
174 }
175
176 /*!
177 Returns whether the new item dialog is currently open.
178 */
isNewItemDialogRunning()179 bool ICore::isNewItemDialogRunning()
180 {
181 return NewDialog::currentDialog() || IWizardFactory::isWizardRunning();
182 }
183
184 /*!
185 Returns the currently open new item dialog widget, or \c nullptr if there is none.
186
187 \sa isNewItemDialogRunning()
188 \sa showNewItemDialog()
189 */
newItemDialog()190 QWidget *ICore::newItemDialog()
191 {
192 if (NewDialog::currentDialog())
193 return NewDialog::currentDialog();
194 return IWizardFactory::currentWizard();
195 }
196
197 /*!
198 \internal
199 */
ICore(MainWindow * mainwindow)200 ICore::ICore(MainWindow *mainwindow)
201 {
202 m_instance = this;
203 m_mainwindow = mainwindow;
204 // Save settings once after all plugins are initialized:
205 connect(PluginManager::instance(), &PluginManager::initializationDone,
206 this, [] { ICore::saveSettings(ICore::InitializationDone); });
207 connect(PluginManager::instance(), &PluginManager::testsFinished, [this] (int failedTests) {
208 emit coreAboutToClose();
209 if (failedTests != 0)
210 qWarning("Test run was not successful: %d test(s) failed.", failedTests);
211 QCoreApplication::exit(failedTests);
212 });
213 connect(PluginManager::instance(), &PluginManager::scenarioFinished, [this] (int exitCode) {
214 emit coreAboutToClose();
215 QCoreApplication::exit(exitCode);
216 });
217 }
218
219 /*!
220 \internal
221 */
~ICore()222 ICore::~ICore()
223 {
224 m_instance = nullptr;
225 m_mainwindow = nullptr;
226 }
227
228 /*!
229 Opens a dialog where the user can choose from a set of \a factories that
230 create new files or projects.
231
232 The \a title argument is shown as the dialog title. The path where the
233 files will be created (if the user does not change it) is set
234 in \a defaultLocation. Defaults to DocumentManager::projectsDirectory()
235 or DocumentManager::fileDialogLastVisitedDirectory(), depending on wizard
236 kind.
237
238 Additional variables for the wizards are set in \a extraVariables.
239
240 \sa Core::DocumentManager
241 \sa isNewItemDialogRunning()
242 \sa newItemDialog()
243 */
showNewItemDialog(const QString & title,const QList<IWizardFactory * > & factories,const QString & defaultLocation,const QVariantMap & extraVariables)244 void ICore::showNewItemDialog(const QString &title,
245 const QList<IWizardFactory *> &factories,
246 const QString &defaultLocation,
247 const QVariantMap &extraVariables)
248 {
249 QTC_ASSERT(!isNewItemDialogRunning(), return);
250 auto newDialog = new NewDialog(dialogParent());
251 connect(newDialog, &QObject::destroyed, m_instance, &ICore::updateNewItemDialogState);
252 newDialog->setWizardFactories(factories, defaultLocation, extraVariables);
253 newDialog->setWindowTitle(title);
254 newDialog->showDialog();
255
256 updateNewItemDialogState();
257 }
258
259 /*!
260 Opens the options dialog on the specified \a page. The dialog's \a parent
261 defaults to dialogParent(). If the dialog is already shown when this method
262 is called, it is just switched to the specified \a page.
263
264 Returns whether the user accepted the dialog.
265
266 \sa msgShowOptionsDialog()
267 \sa msgShowOptionsDialogToolTip()
268 */
showOptionsDialog(const Id page,QWidget * parent)269 bool ICore::showOptionsDialog(const Id page, QWidget *parent)
270 {
271 return executeSettingsDialog(parent ? parent : dialogParent(), page);
272 }
273
274 /*!
275 Returns the text to use on buttons that open the options dialog.
276
277 \sa showOptionsDialog()
278 \sa msgShowOptionsDialogToolTip()
279 */
msgShowOptionsDialog()280 QString ICore::msgShowOptionsDialog()
281 {
282 return QCoreApplication::translate("Core", "Configure...", "msgShowOptionsDialog");
283 }
284
285 /*!
286 Returns the tool tip to use on buttons that open the options dialog.
287
288 \sa showOptionsDialog()
289 \sa msgShowOptionsDialog()
290 */
msgShowOptionsDialogToolTip()291 QString ICore::msgShowOptionsDialogToolTip()
292 {
293 if (Utils::HostOsInfo::isMacHost())
294 return QCoreApplication::translate("Core", "Open Preferences dialog.",
295 "msgShowOptionsDialogToolTip (mac version)");
296 else
297 return QCoreApplication::translate("Core", "Open Options dialog.",
298 "msgShowOptionsDialogToolTip (non-mac version)");
299 }
300
301 /*!
302 Creates a message box with \a parent that contains a \uicontrol Configure
303 button for opening the settings page specified by \a settingsId.
304
305 The dialog has \a title and displays the message \a text and detailed
306 information specified by \a details.
307
308 Use this function to display configuration errors and to point users to the
309 setting they should fix.
310
311 Returns \c true if the user accepted the settings dialog.
312
313 \sa showOptionsDialog()
314 */
showWarningWithOptions(const QString & title,const QString & text,const QString & details,Id settingsId,QWidget * parent)315 bool ICore::showWarningWithOptions(const QString &title, const QString &text,
316 const QString &details, Id settingsId, QWidget *parent)
317 {
318 if (!parent)
319 parent = m_mainwindow;
320 QMessageBox msgBox(QMessageBox::Warning, title, text,
321 QMessageBox::Ok, parent);
322 if (!details.isEmpty())
323 msgBox.setDetailedText(details);
324 QAbstractButton *settingsButton = nullptr;
325 if (settingsId.isValid())
326 settingsButton = msgBox.addButton(msgShowOptionsDialog(), QMessageBox::AcceptRole);
327 msgBox.exec();
328 if (settingsButton && msgBox.clickedButton() == settingsButton)
329 return showOptionsDialog(settingsId);
330 return false;
331 }
332
333 /*!
334 Returns the application's main settings object.
335
336 You can use it to retrieve or set application-wide settings
337 (in contrast to session or project specific settings).
338
339 If \a scope is \c QSettings::UserScope (the default), the
340 settings will be read from the user's settings, with
341 a fallback to global settings provided with \QC.
342
343 If \a scope is \c QSettings::SystemScope, only the installation settings
344 shipped with the current version of \QC will be read. This
345 functionality exists for internal purposes only.
346
347 \sa settingsDatabase()
348 */
settings(QSettings::Scope scope)349 QtcSettings *ICore::settings(QSettings::Scope scope)
350 {
351 if (scope == QSettings::UserScope)
352 return PluginManager::settings();
353 else
354 return PluginManager::globalSettings();
355 }
356
357 /*!
358 Returns the application's settings database.
359
360 The settings database is meant as an alternative to the regular settings
361 object. It is more suitable for storing large amounts of data. The settings
362 are application wide.
363
364 \sa SettingsDatabase
365 \sa settings()
366 */
settingsDatabase()367 SettingsDatabase *ICore::settingsDatabase()
368 {
369 return m_mainwindow->settingsDatabase();
370 }
371
372 /*!
373 Returns the application's printer object.
374
375 Always use this printer object for printing, so the different parts of the
376 application re-use its settings.
377 */
printer()378 QPrinter *ICore::printer()
379 {
380 return m_mainwindow->printer();
381 }
382
383 /*!
384 Returns the locale string for the user interface language that is currently
385 configured in \QC. Use this to install your plugin's translation file with
386 QTranslator.
387 */
userInterfaceLanguage()388 QString ICore::userInterfaceLanguage()
389 {
390 return qApp->property("qtc_locale").toString();
391 }
392
pathHelper(const QString & rel)393 static QString pathHelper(const QString &rel)
394 {
395 if (rel.isEmpty())
396 return rel;
397 if (rel.startsWith('/'))
398 return rel;
399 return '/' + rel;
400 }
401 /*!
402 Returns the absolute path that is used for resources like
403 project templates and the debugger macros.
404
405 This abstraction is needed to avoid platform-specific code all over
406 the place, since on \macos, for example, the resources are part of the
407 application bundle.
408
409 \sa userResourcePath()
410 */
resourcePath(const QString & rel)411 FilePath ICore::resourcePath(const QString &rel)
412 {
413 return FilePath::fromString(
414 QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + RELATIVE_DATA_PATH))
415 / rel;
416 }
417
418 /*!
419 Returns the absolute path in the users directory that is used for
420 resources like project templates.
421
422 Use this function for finding the place for resources that the user may
423 write to, for example, to allow for custom palettes or templates.
424
425 \sa resourcePath()
426 */
427
userResourcePath(const QString & rel)428 FilePath ICore::userResourcePath(const QString &rel)
429 {
430 // Create qtcreator dir if it doesn't yet exist
431 const QString configDir = QFileInfo(settings(QSettings::UserScope)->fileName()).path();
432 const QString urp = configDir + '/' + QLatin1String(Constants::IDE_ID);
433
434 if (!QFileInfo::exists(urp + QLatin1Char('/'))) {
435 QDir dir;
436 if (!dir.mkpath(urp))
437 qWarning() << "could not create" << urp;
438 }
439
440 return FilePath::fromString(urp + pathHelper(rel));
441 }
442
443 /*!
444 Returns a writable path that can be used for persistent cache files.
445 */
cacheResourcePath(const QString & rel)446 FilePath ICore::cacheResourcePath(const QString &rel)
447 {
448 return FilePath::fromString(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
449 + pathHelper(rel));
450 }
451
452 /*!
453 Returns the path to resources written by the installer, for example
454 pre-defined kits and toolchains.
455 */
installerResourcePath(const QString & rel)456 FilePath ICore::installerResourcePath(const QString &rel)
457 {
458 return FilePath::fromString(settings(QSettings::SystemScope)->fileName()).parentDir()
459 / Constants::IDE_ID / rel;
460 }
461
462 /*!
463 Returns the path to the plugins that are included in the \QC installation.
464
465 \internal
466 */
pluginPath()467 QString ICore::pluginPath()
468 {
469 return QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + RELATIVE_PLUGIN_PATH);
470 }
471
472 /*!
473 Returns the path where user-specific plugins should be written.
474
475 \internal
476 */
userPluginPath()477 QString ICore::userPluginPath()
478 {
479 QString pluginPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
480 if (Utils::HostOsInfo::isAnyUnixHost() && !Utils::HostOsInfo::isMacHost())
481 pluginPath += "/data";
482 pluginPath += '/' + QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR) + '/';
483 pluginPath += QLatin1String(Utils::HostOsInfo::isMacHost() ? Core::Constants::IDE_DISPLAY_NAME
484 : Core::Constants::IDE_ID);
485 pluginPath += "/plugins/";
486 pluginPath += QString::number(IDE_VERSION_MAJOR) + '.' + QString::number(IDE_VERSION_MINOR)
487 + '.' + QString::number(IDE_VERSION_RELEASE);
488 return pluginPath;
489 }
490
491 /*!
492 Returns the path to the command line tools that are included in the \QC
493 installation.
494 */
libexecPath(const QString & rel)495 FilePath ICore::libexecPath(const QString &rel)
496 {
497 return FilePath::fromString(QDir::cleanPath(QApplication::applicationDirPath()
498 + pathHelper(RELATIVE_LIBEXEC_PATH)))
499 / rel;
500 }
501
crashReportsPath()502 FilePath ICore::crashReportsPath()
503 {
504 if (Utils::HostOsInfo::isMacHost())
505 return libexecPath("crashpad_reports/completed");
506 else
507 return libexecPath("crashpad_reports/reports");
508 }
509
ideDisplayName()510 QString ICore::ideDisplayName()
511 {
512 return Constants::IDE_DISPLAY_NAME;
513 }
514
clangIncludePath(const QString & clangVersion)515 static QString clangIncludePath(const QString &clangVersion)
516 {
517 return "/lib/clang/" + clangVersion + "/include";
518 }
519
520 /*!
521 \internal
522 */
clangIncludeDirectory(const QString & clangVersion,const QString & clangFallbackIncludeDir)523 QString ICore::clangIncludeDirectory(const QString &clangVersion,
524 const QString &clangFallbackIncludeDir)
525 {
526 FilePath dir = libexecPath("clang" + clangIncludePath(clangVersion));
527 if (!dir.exists() || !dir.pathAppended("stdint.h").exists())
528 dir = FilePath::fromString(clangFallbackIncludeDir);
529 return dir.canonicalPath().toUserOutput();
530 }
531
532 /*!
533 \internal
534 */
clangBinary(const QString & binaryBaseName,const QString & clangBinDirectory)535 static QString clangBinary(const QString &binaryBaseName, const QString &clangBinDirectory)
536 {
537 const QString hostExeSuffix(QTC_HOST_EXE_SUFFIX);
538 FilePath executable = ICore::libexecPath("clang/bin") / binaryBaseName + hostExeSuffix;
539 if (!executable.exists())
540 executable = FilePath::fromString(clangBinDirectory) / binaryBaseName + hostExeSuffix;
541 return executable.canonicalPath().toUserOutput();
542 }
543
544 /*!
545 \internal
546 */
clangExecutable(const QString & clangBinDirectory)547 QString ICore::clangExecutable(const QString &clangBinDirectory)
548 {
549 return clangBinary("clang", clangBinDirectory);
550 }
551
552 /*!
553 \internal
554 */
clangdExecutable(const QString & clangBinDirectory)555 QString ICore::clangdExecutable(const QString &clangBinDirectory)
556 {
557 return clangBinary("clangd", clangBinDirectory);
558 }
559
560 /*!
561 \internal
562 */
clangTidyExecutable(const QString & clangBinDirectory)563 QString ICore::clangTidyExecutable(const QString &clangBinDirectory)
564 {
565 return clangBinary("clang-tidy", clangBinDirectory);
566 }
567
568 /*!
569 \internal
570 */
clazyStandaloneExecutable(const QString & clangBinDirectory)571 QString ICore::clazyStandaloneExecutable(const QString &clangBinDirectory)
572 {
573 return clangBinary("clazy-standalone", clangBinDirectory);
574 }
575
compilerString()576 static QString compilerString()
577 {
578 #if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
579 QString platformSpecific;
580 #if defined(__apple_build_version__) // Apple clang has other version numbers
581 platformSpecific = QLatin1String(" (Apple)");
582 #elif defined(Q_CC_MSVC)
583 platformSpecific = QLatin1String(" (clang-cl)");
584 #endif
585 return QLatin1String("Clang " ) + QString::number(__clang_major__) + QLatin1Char('.')
586 + QString::number(__clang_minor__) + platformSpecific;
587 #elif defined(Q_CC_GNU)
588 return QLatin1String("GCC " ) + QLatin1String(__VERSION__);
589 #elif defined(Q_CC_MSVC)
590 if (_MSC_VER > 1999)
591 return QLatin1String("MSVC <unknown>");
592 if (_MSC_VER >= 1920)
593 return QLatin1String("MSVC 2019");
594 if (_MSC_VER >= 1910)
595 return QLatin1String("MSVC 2017");
596 if (_MSC_VER >= 1900)
597 return QLatin1String("MSVC 2015");
598 #endif
599 return QLatin1String("<unknown compiler>");
600 }
601
602 /*!
603 Returns a string with the IDE's name and version, in the form "\QC X.Y.Z".
604 Use this for "Generated by" strings and similar tasks.
605 */
versionString()606 QString ICore::versionString()
607 {
608 QString ideVersionDescription;
609 if (QLatin1String(Constants::IDE_VERSION_LONG) != QLatin1String(Constants::IDE_VERSION_DISPLAY))
610 ideVersionDescription = tr(" (%1)").arg(QLatin1String(Constants::IDE_VERSION_LONG));
611 return tr("%1 %2%3").arg(QLatin1String(Constants::IDE_DISPLAY_NAME),
612 QLatin1String(Constants::IDE_VERSION_DISPLAY),
613 ideVersionDescription);
614 }
615
616 /*!
617 \internal
618 */
buildCompatibilityString()619 QString ICore::buildCompatibilityString()
620 {
621 return tr("Based on Qt %1 (%2, %3 bit)").arg(QLatin1String(qVersion()),
622 compilerString(),
623 QString::number(QSysInfo::WordSize));
624 }
625
626 /*!
627 Returns the top level IContext of the current context, or \c nullptr if
628 there is none.
629
630 \sa updateAdditionalContexts()
631 \sa addContextObject()
632 \sa {The Action Manager and Commands}
633 */
currentContextObject()634 IContext *ICore::currentContextObject()
635 {
636 return m_mainwindow->currentContextObject();
637 }
638
639 /*!
640 Returns the widget of the top level IContext of the current context, or \c
641 nullptr if there is none.
642
643 \sa currentContextObject()
644 */
currentContextWidget()645 QWidget *ICore::currentContextWidget()
646 {
647 IContext *context = currentContextObject();
648 return context ? context->widget() : nullptr;
649 }
650
651 /*!
652 Returns the registered IContext instance for the specified \a widget,
653 if any.
654 */
contextObject(QWidget * widget)655 IContext *ICore::contextObject(QWidget *widget)
656 {
657 return m_mainwindow->contextObject(widget);
658 }
659
660 /*!
661 Returns the main window of the application.
662
663 For dialog parents use dialogParent().
664
665 \sa dialogParent()
666 */
mainWindow()667 QMainWindow *ICore::mainWindow()
668 {
669 return m_mainwindow;
670 }
671
672 /*!
673 Returns a widget pointer suitable to use as parent for QDialogs.
674 */
dialogParent()675 QWidget *ICore::dialogParent()
676 {
677 QWidget *active = QApplication::activeModalWidget();
678 if (!active)
679 active = QApplication::activeWindow();
680 if (!active || (active && active->windowFlags().testFlag(Qt::SplashScreen)))
681 active = m_mainwindow;
682 return active;
683 }
684
685 /*!
686 \internal
687 */
statusBar()688 QStatusBar *ICore::statusBar()
689 {
690 return m_mainwindow->statusBar();
691 }
692
693 /*!
694 Returns a central InfoBar that is shown in \QC's main window.
695 Use for notifying the user of something without interrupting with
696 dialog. Use sparingly.
697 */
infoBar()698 Utils::InfoBar *ICore::infoBar()
699 {
700 return m_mainwindow->infoBar();
701 }
702
703 /*!
704 Raises and activates the window for \a widget. This contains workarounds
705 for X11.
706 */
raiseWindow(QWidget * widget)707 void ICore::raiseWindow(QWidget *widget)
708 {
709 if (!widget)
710 return;
711 QWidget *window = widget->window();
712 if (window && window == m_mainwindow) {
713 m_mainwindow->raiseWindow();
714 } else {
715 window->raise();
716 window->activateWindow();
717 }
718 }
719
720 /*!
721 Removes the contexts specified by \a remove from the list of active
722 additional contexts, and adds the contexts specified by \a add with \a
723 priority.
724
725 The additional contexts are not associated with an IContext instance.
726
727 High priority additional contexts have higher priority than the contexts
728 added by IContext instances, low priority additional contexts have lower
729 priority than the contexts added by IContext instances.
730
731 \sa addContextObject()
732 \sa {The Action Manager and Commands}
733 */
updateAdditionalContexts(const Context & remove,const Context & add,ContextPriority priority)734 void ICore::updateAdditionalContexts(const Context &remove, const Context &add,
735 ContextPriority priority)
736 {
737 m_mainwindow->updateAdditionalContexts(remove, add, priority);
738 }
739
740 /*!
741 Adds \a context with \a priority to the list of active additional contexts.
742
743 \sa updateAdditionalContexts()
744 */
addAdditionalContext(const Context & context,ContextPriority priority)745 void ICore::addAdditionalContext(const Context &context, ContextPriority priority)
746 {
747 m_mainwindow->updateAdditionalContexts(Context(), context, priority);
748 }
749
750 /*!
751 Removes \a context from the list of active additional contexts.
752
753 \sa updateAdditionalContexts()
754 */
removeAdditionalContext(const Context & context)755 void ICore::removeAdditionalContext(const Context &context)
756 {
757 m_mainwindow->updateAdditionalContexts(context, Context(), ContextPriority::Low);
758 }
759
760 /*!
761 Adds \a context to the list of registered IContext instances.
762 Whenever the IContext's \l{IContext::widget()}{widget} is in the application
763 focus widget's parent hierarchy, its \l{IContext::context()}{context} is
764 added to the list of active contexts.
765
766 \sa removeContextObject()
767 \sa updateAdditionalContexts()
768 \sa currentContextObject()
769 \sa {The Action Manager and Commands}
770 */
addContextObject(IContext * context)771 void ICore::addContextObject(IContext *context)
772 {
773 m_mainwindow->addContextObject(context);
774 }
775
776 /*!
777 Unregisters a \a context object from the list of registered IContext
778 instances. IContext instances are automatically removed when they are
779 deleted.
780
781 \sa addContextObject()
782 \sa updateAdditionalContexts()
783 \sa currentContextObject()
784 */
removeContextObject(IContext * context)785 void ICore::removeContextObject(IContext *context)
786 {
787 m_mainwindow->removeContextObject(context);
788 }
789
790 /*!
791 Registers a \a window with the specified \a context. Registered windows are
792 shown in the \uicontrol Window menu and get registered for the various
793 window related actions, like the minimize, zoom, fullscreen and close
794 actions.
795
796 Whenever the application focus is in \a window, its \a context is made
797 active.
798 */
registerWindow(QWidget * window,const Context & context)799 void ICore::registerWindow(QWidget *window, const Context &context)
800 {
801 new WindowSupport(window, context); // deletes itself when widget is destroyed
802 }
803
804 /*!
805 Opens files using \a arguments and \a flags like it would be
806 done if they were given to \QC on the command line, or
807 they were opened via \uicontrol File > \uicontrol Open.
808 */
809
openFiles(const QStringList & arguments,ICore::OpenFilesFlags flags)810 void ICore::openFiles(const QStringList &arguments, ICore::OpenFilesFlags flags)
811 {
812 MainWindow::openFiles(arguments, flags);
813 }
814
815 /*!
816 Provides a hook for plugins to veto on closing the application.
817
818 When the application window requests a close, all listeners are called. If
819 one of the \a listener calls returns \c false, the process is aborted and
820 the event is ignored. If all calls return \c true, coreAboutToClose()
821 is emitted and the event is accepted or performed.
822 */
addPreCloseListener(const std::function<bool ()> & listener)823 void ICore::addPreCloseListener(const std::function<bool ()> &listener)
824 {
825 m_mainwindow->addPreCloseListener(listener);
826 }
827
828 /*!
829 \internal
830 */
systemInformation()831 QString ICore::systemInformation()
832 {
833 QString result = PluginManager::systemInformation() + '\n';
834 result += versionString() + '\n';
835 result += buildCompatibilityString() + '\n';
836 #ifdef IDE_REVISION
837 result += QString("From revision %1\n").arg(QString::fromLatin1(Constants::IDE_REVISION_STR).left(10));
838 #endif
839 #ifdef QTC_SHOW_BUILD_DATE
840 result += QString("Built on %1 %2\n").arg(QLatin1String(__DATE__), QLatin1String(__TIME__));
841 #endif
842 return result;
843 }
844
screenShotsPath()845 static const QByteArray &screenShotsPath()
846 {
847 static const QByteArray path = qgetenv("QTC_SCREENSHOTS_PATH");
848 return path;
849 }
850
851 class ScreenShooter : public QObject
852 {
853 public:
ScreenShooter(QWidget * widget,const QString & name,const QRect & rc)854 ScreenShooter(QWidget *widget, const QString &name, const QRect &rc)
855 : m_widget(widget), m_name(name), m_rc(rc)
856 {
857 m_widget->installEventFilter(this);
858 }
859
eventFilter(QObject * watched,QEvent * event)860 bool eventFilter(QObject *watched, QEvent *event) override
861 {
862 QTC_ASSERT(watched == m_widget, return false);
863 if (event->type() == QEvent::Show)
864 QMetaObject::invokeMethod(this, &ScreenShooter::helper, Qt::QueuedConnection);
865 return false;
866 }
867
helper()868 void helper()
869 {
870 if (m_widget) {
871 QRect rc = m_rc.isValid() ? m_rc : m_widget->rect();
872 QPixmap pm = m_widget->grab(rc);
873 for (int i = 0; ; ++i) {
874 QString fileName = screenShotsPath() + '/' + m_name + QString("-%1.png").arg(i);
875 if (!QFileInfo::exists(fileName)) {
876 pm.save(fileName);
877 break;
878 }
879 }
880 }
881 deleteLater();
882 }
883
884 QPointer<QWidget> m_widget;
885 QString m_name;
886 QRect m_rc;
887 };
888
889 /*!
890 \internal
891 */
setupScreenShooter(const QString & name,QWidget * w,const QRect & rc)892 void ICore::setupScreenShooter(const QString &name, QWidget *w, const QRect &rc)
893 {
894 if (!screenShotsPath().isEmpty())
895 new ScreenShooter(w, name, rc);
896 }
897
898 /*!
899 Restarts \QC and restores the last session.
900 */
restart()901 void ICore::restart()
902 {
903 m_mainwindow->restart();
904 }
905
906 /*!
907 \internal
908 */
saveSettings(SaveSettingsReason reason)909 void ICore::saveSettings(SaveSettingsReason reason)
910 {
911 emit m_instance->saveSettingsRequested(reason);
912 m_mainwindow->saveSettings();
913
914 ICore::settings(QSettings::SystemScope)->sync();
915 ICore::settings(QSettings::UserScope)->sync();
916 }
917
918 /*!
919 \internal
920 */
additionalAboutInformation()921 QStringList ICore::additionalAboutInformation()
922 {
923 return m_mainwindow->additionalAboutInformation();
924 }
925
926 /*!
927 \internal
928 */
appendAboutInformation(const QString & line)929 void ICore::appendAboutInformation(const QString &line)
930 {
931 m_mainwindow->appendAboutInformation(line);
932 }
933
updateNewItemDialogState()934 void ICore::updateNewItemDialogState()
935 {
936 static bool wasRunning = false;
937 static QWidget *previousDialog = nullptr;
938 if (wasRunning == isNewItemDialogRunning() && previousDialog == newItemDialog())
939 return;
940 wasRunning = isNewItemDialogRunning();
941 previousDialog = newItemDialog();
942 emit instance()->newItemDialogStateChanged();
943 }
944
945 } // namespace Core
946