2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2009-01-13 17:03:14 +01:00
|
|
|
|
2009-01-12 14:41:24 +01:00
|
|
|
#include "icore.h"
|
2018-02-01 17:44:27 +01:00
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
#include "actionmanager/actioncontainer.h"
|
|
|
|
|
#include "actionmanager/actionmanager.h"
|
|
|
|
|
#include "actionmanager/command.h"
|
|
|
|
|
#include "coreicons.h"
|
2022-07-05 13:56:04 +02:00
|
|
|
#include "coreplugintr.h"
|
2023-09-15 12:58:44 +02:00
|
|
|
#include "coreplugintr.h"
|
|
|
|
|
#include "dialogs/externaltoolconfig.h"
|
2018-02-01 17:44:27 +01:00
|
|
|
#include "dialogs/settingsdialog.h"
|
2023-09-15 12:58:44 +02:00
|
|
|
#include "dialogs/shortcutsettings.h"
|
|
|
|
|
#include "documentmanager.h"
|
|
|
|
|
#include "editormanager/documentmodel_p.h"
|
|
|
|
|
#include "editormanager/editormanager.h"
|
|
|
|
|
#include "editormanager/editormanager_p.h"
|
|
|
|
|
#include "editormanager/ieditor.h"
|
|
|
|
|
#include "editormanager/ieditorfactory.h"
|
|
|
|
|
#include "editormanager/systemeditor.h"
|
|
|
|
|
#include "externaltoolmanager.h"
|
|
|
|
|
#include "fancytabwidget.h"
|
|
|
|
|
#include "fileutils.h"
|
|
|
|
|
#include "find/basetextfind.h"
|
|
|
|
|
#include "findplaceholder.h"
|
|
|
|
|
#include "helpmanager.h"
|
|
|
|
|
#include "icore.h"
|
|
|
|
|
#include "idocumentfactory.h"
|
|
|
|
|
#include "inavigationwidgetfactory.h"
|
|
|
|
|
#include "iwizardfactory.h"
|
|
|
|
|
#include "jsexpander.h"
|
|
|
|
|
#include "loggingviewer.h"
|
|
|
|
|
#include "manhattanstyle.h"
|
|
|
|
|
#include "messagemanager.h"
|
|
|
|
|
#include "mimetypesettings.h"
|
|
|
|
|
#include "modemanager.h"
|
|
|
|
|
#include "navigationwidget.h"
|
|
|
|
|
#include "outputpanemanager.h"
|
|
|
|
|
#include "plugindialog.h"
|
|
|
|
|
#include "progressmanager/progressmanager_p.h"
|
|
|
|
|
#include "progressmanager/progressview.h"
|
|
|
|
|
#include "rightpane.h"
|
|
|
|
|
#include "statusbarmanager.h"
|
|
|
|
|
#include "systemsettings.h"
|
|
|
|
|
#include "vcsmanager.h"
|
|
|
|
|
#include "versiondialog.h"
|
2022-07-05 13:56:04 +02:00
|
|
|
#include "windowsupport.h"
|
2009-01-12 14:41:24 +01:00
|
|
|
|
2012-08-17 09:09:15 +02:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
|
2021-11-09 18:58:15 +02:00
|
|
|
#include <utils/algorithm.h>
|
2023-06-21 15:12:46 +02:00
|
|
|
#include <utils/appinfo.h>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <utils/checkablemessagebox.h>
|
2023-11-28 13:43:09 +01:00
|
|
|
#include <utils/dropsupport.h>
|
2022-08-24 14:55:41 +02:00
|
|
|
#include <utils/environment.h>
|
2022-07-22 13:07:53 +02:00
|
|
|
#include <utils/fileutils.h>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <utils/fsengine/fileiconprovider.h>
|
|
|
|
|
#include <utils/fsengine/fsengine.h>
|
|
|
|
|
#include <utils/historycompleter.h>
|
|
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
|
#include <utils/mimeutils.h>
|
|
|
|
|
#include <utils/proxyaction.h>
|
2022-08-24 14:55:41 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <utils/stringutils.h>
|
|
|
|
|
#include <utils/stylehelper.h>
|
|
|
|
|
#include <utils/terminalcommand.h>
|
|
|
|
|
#include <utils/theme/theme.h>
|
|
|
|
|
#include <utils/touchbar/touchbar.h>
|
|
|
|
|
#include <utils/utilsicons.h>
|
|
|
|
|
|
|
|
|
|
#include <nanotrace/nanotrace.h>
|
2015-05-29 13:24:02 +02:00
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <QActionGroup>
|
2014-11-20 16:00:06 +01:00
|
|
|
#include <QApplication>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <QCloseEvent>
|
|
|
|
|
#include <QColorDialog>
|
|
|
|
|
#include <QComboBox>
|
2019-03-13 14:38:07 +01:00
|
|
|
#include <QDebug>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <QDialogButtonBox>
|
2022-08-30 13:29:36 +02:00
|
|
|
#include <QLibraryInfo>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <QMenu>
|
|
|
|
|
#include <QMenuBar>
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QPrinter>
|
2019-02-20 17:26:36 +01:00
|
|
|
#include <QStandardPaths>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <QStatusBar>
|
|
|
|
|
#include <QStyleFactory>
|
2019-03-13 14:38:07 +01:00
|
|
|
#include <QSysInfo>
|
2023-09-15 12:58:44 +02:00
|
|
|
#include <QTextBrowser>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QToolButton>
|
|
|
|
|
#include <QVersionNumber>
|
|
|
|
|
|
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
|
#include <malloc.h>
|
|
|
|
|
#endif
|
2013-05-24 16:45:49 +02:00
|
|
|
|
2009-01-12 14:41:24 +01:00
|
|
|
/*!
|
|
|
|
|
\namespace Core
|
2020-03-18 13:32:02 +01:00
|
|
|
\inmodule QtCreator
|
2009-01-12 14:41:24 +01:00
|
|
|
\brief The Core namespace contains all classes that make up the Core plugin
|
2013-09-06 16:38:53 +02:00
|
|
|
which constitute the basic functionality of \QC.
|
2009-01-12 14:41:24 +01:00
|
|
|
*/
|
|
|
|
|
|
2020-02-13 16:14:56 +01:00
|
|
|
/*!
|
2023-05-22 13:56:37 +02:00
|
|
|
\enum Utils::FindFlag
|
2020-02-13 16:14:56 +01:00
|
|
|
This enum holds the find flags.
|
|
|
|
|
|
|
|
|
|
\value FindBackward
|
|
|
|
|
Searches backwards.
|
|
|
|
|
\value FindCaseSensitively
|
|
|
|
|
Considers case when searching.
|
|
|
|
|
\value FindWholeWords
|
|
|
|
|
Finds only whole words.
|
|
|
|
|
\value FindRegularExpression
|
|
|
|
|
Uses a regular epression as a search term.
|
|
|
|
|
\value FindPreserveCase
|
|
|
|
|
Preserves the case when replacing search terms.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\enum Core::ICore::ContextPriority
|
|
|
|
|
|
|
|
|
|
This enum defines the priority of additional contexts.
|
|
|
|
|
|
|
|
|
|
\value High
|
|
|
|
|
Additional contexts that have higher priority than contexts from
|
|
|
|
|
Core::IContext instances.
|
|
|
|
|
\value Low
|
|
|
|
|
Additional contexts that have lower priority than contexts from
|
|
|
|
|
Core::IContext instances.
|
|
|
|
|
|
|
|
|
|
\sa Core::ICore::updateAdditionalContexts()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\enum Core::SaveSettingsReason
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
|
2009-01-12 14:41:24 +01:00
|
|
|
/*!
|
|
|
|
|
\namespace Core::Internal
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class Core::ICore
|
2020-06-12 16:04:30 +02:00
|
|
|
\inheaderfile coreplugin/icore.h
|
2020-02-13 16:14:56 +01:00
|
|
|
\inmodule QtCreator
|
2020-03-18 13:32:02 +01:00
|
|
|
\ingroup mainclasses
|
2020-06-12 16:04:30 +02:00
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The ICore class allows access to the different parts that make up
|
|
|
|
|
the basic functionality of \QC.
|
2009-01-12 14:41:24 +01:00
|
|
|
|
|
|
|
|
You should never create a subclass of this interface. The one and only
|
|
|
|
|
instance is created by the Core plugin. You can access this instance
|
2020-03-18 13:32:02 +01:00
|
|
|
from your plugin through instance().
|
2009-01-12 14:41:24 +01:00
|
|
|
*/
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\fn void Core::ICore::coreAboutToOpen()
|
|
|
|
|
|
|
|
|
|
Indicates that all plugins have been loaded and the main window is about to
|
|
|
|
|
be shown.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-01-12 14:41:24 +01:00
|
|
|
/*!
|
2020-03-18 13:32:02 +01:00
|
|
|
\fn void Core::ICore::coreOpened()
|
2013-09-06 16:38:53 +02:00
|
|
|
Indicates that all plugins have been loaded and the main window is shown.
|
2009-01-12 14:41:24 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
2020-03-18 13:32:02 +01:00
|
|
|
\fn void Core::ICore::saveSettingsRequested(Core::ICore::SaveSettingsReason reason)
|
2013-09-06 16:38:53 +02:00
|
|
|
Signals that the user has requested that the global settings
|
2020-03-18 13:32:02 +01:00
|
|
|
should be saved to disk for a \a reason.
|
2009-01-12 14:41:24 +01:00
|
|
|
|
2020-02-13 16:14:56 +01:00
|
|
|
At the moment that happens when the application is closed, and on \uicontrol{Save All}.
|
2009-01-12 14:41:24 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
2020-03-18 13:32:02 +01:00
|
|
|
\fn void Core::ICore::coreAboutToClose()
|
2013-09-06 16:38:53 +02:00
|
|
|
Enables plugins to perform some pre-end-of-life actions.
|
2009-01-12 14:41:24 +01:00
|
|
|
|
|
|
|
|
The application is guaranteed to shut down after this signal is emitted.
|
2013-10-07 13:34:40 +02:00
|
|
|
It is there as an addition to the usual plugin lifecycle functions, namely
|
2013-09-06 16:38:53 +02:00
|
|
|
\c IPlugin::aboutToShutdown(), just for convenience.
|
2009-01-12 14:41:24 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
2020-03-18 13:32:02 +01:00
|
|
|
\fn void Core::ICore::contextAboutToChange(const QList<Core::IContext *> &context)
|
2013-09-06 16:38:53 +02:00
|
|
|
Indicates that a new \a context will shortly become the current context
|
|
|
|
|
(meaning that its widget got focus).
|
2009-01-12 14:41:24 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
2020-03-18 13:32:02 +01:00
|
|
|
\fn void Core::ICore::contextChanged(const Core::Context &context)
|
2015-09-22 09:17:59 +02:00
|
|
|
Indicates that a new \a context just became the current context. This includes the context
|
|
|
|
|
from the focus object as well as the additional context.
|
2009-01-12 14:41:24 +01:00
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
|
2021-08-26 20:02:55 +03:00
|
|
|
#include "dialogs/newdialogwidget.h"
|
2015-05-29 13:24:02 +02:00
|
|
|
#include "dialogs/newdialog.h"
|
2015-05-29 15:55:49 +02:00
|
|
|
#include "iwizardfactory.h"
|
2012-02-14 16:43:51 +01:00
|
|
|
#include "documentmanager.h"
|
2012-01-18 23:25:34 +01:00
|
|
|
|
2013-03-14 10:44:46 +01:00
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QCoreApplication>
|
|
|
|
|
#include <QDebug>
|
2013-09-20 23:17:22 +02:00
|
|
|
#include <QDir>
|
2018-01-29 11:46:23 +01:00
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QPushButton>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QStatusBar>
|
2012-01-18 23:25:34 +01:00
|
|
|
|
2013-09-20 23:17:22 +02:00
|
|
|
using namespace Core::Internal;
|
2014-03-04 16:07:44 +01:00
|
|
|
using namespace ExtensionSystem;
|
2020-06-26 13:59:38 +02:00
|
|
|
using namespace Utils;
|
2013-09-20 23:17:22 +02:00
|
|
|
|
2012-01-18 23:25:34 +01:00
|
|
|
namespace Core {
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
const char settingsGroup[] = "MainWindow";
|
|
|
|
|
const char colorKey[] = "Color";
|
|
|
|
|
const char windowGeometryKey[] = "WindowGeometry";
|
|
|
|
|
const char windowStateKey[] = "WindowState";
|
|
|
|
|
const char modeSelectorLayoutKey[] = "ModeSelectorLayout";
|
|
|
|
|
const char menubarVisibleKey[] = "MenubarVisible";
|
|
|
|
|
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
|
|
|
|
class MainWindow : public AppMainWindow
|
|
|
|
|
{
|
|
|
|
|
public:
|
2023-10-02 17:27:26 +02:00
|
|
|
MainWindow()
|
|
|
|
|
{
|
|
|
|
|
setWindowTitle(QGuiApplication::applicationDisplayName());
|
|
|
|
|
setDockNestingEnabled(true);
|
|
|
|
|
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
|
|
|
|
|
setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
|
|
|
|
|
}
|
2023-09-15 16:47:37 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void closeEvent(QCloseEvent *event) override;
|
|
|
|
|
void keyPressEvent(QKeyEvent *event) override;
|
|
|
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-02 17:54:48 +02:00
|
|
|
static QColor s_overrideColor;
|
2023-09-15 16:47:37 +02:00
|
|
|
|
2012-01-18 23:25:34 +01:00
|
|
|
// The Core Singleton
|
2023-09-15 12:58:44 +02:00
|
|
|
static ICore *m_core = nullptr;
|
2021-11-09 18:58:15 +02:00
|
|
|
|
|
|
|
|
static NewDialog *defaultDialogFactory(QWidget *parent)
|
|
|
|
|
{
|
2021-08-26 20:02:55 +03:00
|
|
|
return new NewDialogWidget(parent);
|
2021-11-09 18:58:15 +02:00
|
|
|
}
|
2023-10-02 16:24:02 +02:00
|
|
|
class ICorePrivate : public QObject
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
public:
|
2023-10-02 17:27:26 +02:00
|
|
|
ICorePrivate() {}
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
~ICorePrivate();
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
void init();
|
|
|
|
|
|
|
|
|
|
static void openFile();
|
|
|
|
|
void aboutToShowRecentFiles();
|
|
|
|
|
|
|
|
|
|
static void setFocusToEditor();
|
|
|
|
|
void aboutQtCreator();
|
|
|
|
|
void aboutPlugins();
|
|
|
|
|
void changeLog();
|
|
|
|
|
void contact();
|
|
|
|
|
void updateFocusWidget(QWidget *old, QWidget *now);
|
|
|
|
|
NavigationWidget *navigationWidget(Side side) const;
|
|
|
|
|
void setSidebarVisible(bool visible, Side side);
|
|
|
|
|
void destroyVersionDialog();
|
|
|
|
|
void openDroppedFiles(const QList<Utils::DropSupport::FileSpec> &files);
|
|
|
|
|
void restoreWindowState();
|
|
|
|
|
|
|
|
|
|
void openFileFromDevice();
|
|
|
|
|
|
|
|
|
|
void updateContextObject(const QList<IContext *> &context);
|
|
|
|
|
void updateContext();
|
|
|
|
|
|
|
|
|
|
void registerDefaultContainers();
|
|
|
|
|
void registerDefaultActions();
|
|
|
|
|
void registerModeSelectorStyleActions();
|
|
|
|
|
|
|
|
|
|
void readSettings();
|
|
|
|
|
void saveWindowSettings();
|
|
|
|
|
|
|
|
|
|
void updateModeSelectorStyleMenu();
|
|
|
|
|
|
2023-10-02 17:27:26 +02:00
|
|
|
MainWindow *m_mainwindow = nullptr;
|
2023-09-15 12:58:44 +02:00
|
|
|
QTimer m_trimTimer;
|
|
|
|
|
QStringList m_aboutInformation;
|
|
|
|
|
Context m_highPrioAdditionalContexts;
|
|
|
|
|
Context m_lowPrioAdditionalContexts{Constants::C_GLOBAL};
|
|
|
|
|
mutable QPrinter *m_printer = nullptr;
|
|
|
|
|
WindowSupport *m_windowSupport = nullptr;
|
|
|
|
|
EditorManager *m_editorManager = nullptr;
|
|
|
|
|
ExternalToolManager *m_externalToolManager = nullptr;
|
|
|
|
|
MessageManager *m_messageManager = nullptr;
|
|
|
|
|
ProgressManagerPrivate *m_progressManager = nullptr;
|
|
|
|
|
JsExpander *m_jsExpander = nullptr;
|
|
|
|
|
VcsManager *m_vcsManager = nullptr;
|
|
|
|
|
ModeManager *m_modeManager = nullptr;
|
|
|
|
|
FancyTabWidget *m_modeStack = nullptr;
|
|
|
|
|
NavigationWidget *m_leftNavigationWidget = nullptr;
|
|
|
|
|
NavigationWidget *m_rightNavigationWidget = nullptr;
|
|
|
|
|
RightPaneWidget *m_rightPaneWidget = nullptr;
|
|
|
|
|
VersionDialog *m_versionDialog = nullptr;
|
|
|
|
|
|
|
|
|
|
QList<IContext *> m_activeContext;
|
|
|
|
|
|
|
|
|
|
std::unordered_map<QWidget *, IContext *> m_contextWidgets;
|
|
|
|
|
|
|
|
|
|
ShortcutSettings *m_shortcutSettings = nullptr;
|
|
|
|
|
ToolSettings *m_toolSettings = nullptr;
|
|
|
|
|
MimeTypeSettings *m_mimeTypeSettings = nullptr;
|
|
|
|
|
SystemEditor *m_systemEditor = nullptr;
|
|
|
|
|
|
|
|
|
|
// actions
|
|
|
|
|
QAction *m_saveAllAction = nullptr;
|
|
|
|
|
QAction *m_toggleLeftSideBarAction = nullptr;
|
|
|
|
|
QAction *m_toggleRightSideBarAction = nullptr;
|
|
|
|
|
QAction *m_toggleMenubarAction = nullptr;
|
|
|
|
|
QAction *m_cycleModeSelectorStyleAction = nullptr;
|
|
|
|
|
QAction *m_setModeSelectorStyleIconsAndTextAction = nullptr;
|
|
|
|
|
QAction *m_setModeSelectorStyleHiddenAction = nullptr;
|
|
|
|
|
QAction *m_setModeSelectorStyleIconsOnlyAction = nullptr;
|
|
|
|
|
|
|
|
|
|
QToolButton *m_toggleLeftSideBarButton = nullptr;
|
|
|
|
|
QToolButton *m_toggleRightSideBarButton = nullptr;
|
|
|
|
|
QList<std::function<bool()>> m_preCloseListeners;
|
|
|
|
|
};
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
static QMenuBar *globalMenuBar()
|
|
|
|
|
{
|
|
|
|
|
return ActionManager::actionContainer(Constants::MENU_BAR)->menuBar();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
} // Internal
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
static ICorePrivate *d = nullptr;
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2021-11-09 18:58:15 +02:00
|
|
|
static std::function<NewDialog *(QWidget *)> m_newDialogFactory = defaultDialogFactory;
|
2012-01-18 23:25:34 +01:00
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the pointer to the instance. Only use for connecting to signals.
|
|
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
ICore *ICore::instance()
|
|
|
|
|
{
|
2023-09-15 12:58:44 +02:00
|
|
|
return m_core;
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns whether the new item dialog is currently open.
|
|
|
|
|
*/
|
2014-06-27 15:15:09 +02:00
|
|
|
bool ICore::isNewItemDialogRunning()
|
|
|
|
|
{
|
2016-09-26 16:39:49 +02:00
|
|
|
return NewDialog::currentDialog() || IWizardFactory::isWizardRunning();
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the currently open new item dialog widget, or \c nullptr if there is none.
|
|
|
|
|
|
|
|
|
|
\sa isNewItemDialogRunning()
|
|
|
|
|
\sa showNewItemDialog()
|
|
|
|
|
*/
|
2016-09-26 16:39:49 +02:00
|
|
|
QWidget *ICore::newItemDialog()
|
|
|
|
|
{
|
|
|
|
|
if (NewDialog::currentDialog())
|
|
|
|
|
return NewDialog::currentDialog();
|
|
|
|
|
return IWizardFactory::currentWizard();
|
2014-06-27 15:15:09 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2023-09-15 12:58:44 +02:00
|
|
|
ICore::ICore()
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2023-09-15 12:58:44 +02:00
|
|
|
m_core = this;
|
2023-10-02 17:27:26 +02:00
|
|
|
|
|
|
|
|
d = new ICorePrivate;
|
|
|
|
|
d->init(); // Separation needed for now as the call triggers other MainWindow calls.
|
2023-06-28 15:35:47 +02:00
|
|
|
|
2022-12-07 16:25:11 +01:00
|
|
|
connect(PluginManager::instance(), &PluginManager::testsFinished,
|
|
|
|
|
this, [this](int failedTests) {
|
2015-07-14 10:35:49 +02:00
|
|
|
emit coreAboutToClose();
|
2019-03-13 14:38:07 +01:00
|
|
|
if (failedTests != 0)
|
|
|
|
|
qWarning("Test run was not successful: %d test(s) failed.", failedTests);
|
2015-07-14 10:35:49 +02:00
|
|
|
QCoreApplication::exit(failedTests);
|
|
|
|
|
});
|
2022-12-07 16:25:11 +01:00
|
|
|
connect(PluginManager::instance(), &PluginManager::scenarioFinished,
|
|
|
|
|
this, [this](int exitCode) {
|
2021-04-28 15:59:18 +02:00
|
|
|
emit coreAboutToClose();
|
|
|
|
|
QCoreApplication::exit(exitCode);
|
|
|
|
|
});
|
2021-07-16 15:24:26 +02:00
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
Utils::FileUtils::setDialogParentGetter(&ICore::dialogParent);
|
2023-10-02 17:54:48 +02:00
|
|
|
|
|
|
|
|
d->m_progressManager->init(); // needs the status bar manager
|
|
|
|
|
MessageManager::init();
|
|
|
|
|
OutputPaneManager::create();
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
ICore::~ICore()
|
|
|
|
|
{
|
2023-10-02 17:27:26 +02:00
|
|
|
delete d;
|
2023-09-15 12:58:44 +02:00
|
|
|
m_core = nullptr;
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
|
|
|
|
Opens a dialog where the user can choose from a set of \a factories that
|
|
|
|
|
create new files or projects.
|
|
|
|
|
|
|
|
|
|
The \a title argument is shown as the dialog title. The path where the
|
|
|
|
|
files will be created (if the user does not change it) is set
|
|
|
|
|
in \a defaultLocation. Defaults to DocumentManager::projectsDirectory()
|
|
|
|
|
or DocumentManager::fileDialogLastVisitedDirectory(), depending on wizard
|
|
|
|
|
kind.
|
|
|
|
|
|
|
|
|
|
Additional variables for the wizards are set in \a extraVariables.
|
|
|
|
|
|
|
|
|
|
\sa Core::DocumentManager
|
2020-05-28 16:26:01 +02:00
|
|
|
\sa isNewItemDialogRunning()
|
|
|
|
|
\sa newItemDialog()
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
void ICore::showNewItemDialog(const QString &title,
|
2014-05-02 17:38:42 +02:00
|
|
|
const QList<IWizardFactory *> &factories,
|
2021-07-26 17:20:03 +02:00
|
|
|
const FilePath &defaultLocation,
|
2012-04-02 14:55:56 +02:00
|
|
|
const QVariantMap &extraVariables)
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2015-05-29 14:23:59 +02:00
|
|
|
QTC_ASSERT(!isNewItemDialogRunning(), return);
|
2021-11-09 18:58:15 +02:00
|
|
|
|
|
|
|
|
/* This is a workaround for QDS: In QDS, we currently have a "New Project" dialog box but we do
|
|
|
|
|
* not also have a "New file" dialog box (yet). Therefore, when requested to add a new file, we
|
|
|
|
|
* need to use QtCreator's dialog box. In QDS, if `factories` contains project wizard factories
|
|
|
|
|
* (even though it may contain file wizard factories as well), then we consider it to be a
|
|
|
|
|
* request for "New Project". Otherwise, if we only have file wizard factories, we defer to
|
|
|
|
|
* QtCreator's dialog and request "New File"
|
|
|
|
|
*/
|
|
|
|
|
auto dialogFactory = m_newDialogFactory;
|
|
|
|
|
bool haveProjectWizards = Utils::anyOf(factories, [](IWizardFactory *f) {
|
|
|
|
|
return f->kind() == IWizardFactory::ProjectWizard;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!haveProjectWizards)
|
|
|
|
|
dialogFactory = defaultDialogFactory;
|
|
|
|
|
|
|
|
|
|
NewDialog *newDialog = dialogFactory(dialogParent());
|
2023-09-15 12:58:44 +02:00
|
|
|
connect(newDialog->widget(), &QObject::destroyed, m_core, &ICore::updateNewItemDialogState);
|
2015-05-29 13:24:02 +02:00
|
|
|
newDialog->setWizardFactories(factories, defaultLocation, extraVariables);
|
|
|
|
|
newDialog->setWindowTitle(title);
|
|
|
|
|
newDialog->showDialog();
|
|
|
|
|
|
2016-09-26 16:39:49 +02:00
|
|
|
updateNewItemDialogState();
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Opens the options dialog on the specified \a page. The dialog's \a parent
|
|
|
|
|
defaults to dialogParent(). If the dialog is already shown when this method
|
|
|
|
|
is called, it is just switched to the specified \a page.
|
|
|
|
|
|
|
|
|
|
Returns whether the user accepted the dialog.
|
|
|
|
|
|
|
|
|
|
\sa msgShowOptionsDialog()
|
|
|
|
|
\sa msgShowOptionsDialogToolTip()
|
|
|
|
|
*/
|
2015-02-23 11:07:38 +01:00
|
|
|
bool ICore::showOptionsDialog(const Id page, QWidget *parent)
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2018-02-01 15:20:16 +01:00
|
|
|
return executeSettingsDialog(parent ? parent : dialogParent(), page);
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the text to use on buttons that open the options dialog.
|
|
|
|
|
|
|
|
|
|
\sa showOptionsDialog()
|
|
|
|
|
\sa msgShowOptionsDialogToolTip()
|
|
|
|
|
*/
|
2014-02-20 14:52:10 +01:00
|
|
|
QString ICore::msgShowOptionsDialog()
|
|
|
|
|
{
|
2022-07-05 13:56:04 +02:00
|
|
|
return Tr::tr("Configure...", "msgShowOptionsDialog");
|
2014-02-20 14:52:10 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the tool tip to use on buttons that open the options dialog.
|
|
|
|
|
|
|
|
|
|
\sa showOptionsDialog()
|
|
|
|
|
\sa msgShowOptionsDialog()
|
|
|
|
|
*/
|
2014-06-23 10:39:01 +02:00
|
|
|
QString ICore::msgShowOptionsDialogToolTip()
|
|
|
|
|
{
|
|
|
|
|
if (Utils::HostOsInfo::isMacHost())
|
2022-07-05 13:56:04 +02:00
|
|
|
return Tr::tr("Open Preferences dialog.", "msgShowOptionsDialogToolTip (mac version)");
|
2014-06-23 10:39:01 +02:00
|
|
|
else
|
2022-07-05 13:56:04 +02:00
|
|
|
return Tr::tr("Open Options dialog.", "msgShowOptionsDialogToolTip (non-mac version)");
|
2014-06-23 10:39:01 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
2020-05-28 16:26:01 +02:00
|
|
|
Creates a message box with \a parent that contains a \uicontrol Configure
|
2020-03-18 13:32:02 +01:00
|
|
|
button for opening the settings page specified by \a settingsId.
|
|
|
|
|
|
|
|
|
|
The dialog has \a title and displays the message \a text and detailed
|
|
|
|
|
information specified by \a details.
|
|
|
|
|
|
|
|
|
|
Use this function to display configuration errors and to point users to the
|
|
|
|
|
setting they should fix.
|
|
|
|
|
|
|
|
|
|
Returns \c true if the user accepted the settings dialog.
|
2020-05-28 16:26:01 +02:00
|
|
|
|
|
|
|
|
\sa showOptionsDialog()
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
bool ICore::showWarningWithOptions(const QString &title, const QString &text,
|
2015-02-23 11:07:38 +01:00
|
|
|
const QString &details, Id settingsId, QWidget *parent)
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2018-01-29 11:46:23 +01:00
|
|
|
if (!parent)
|
2023-10-02 17:27:26 +02:00
|
|
|
parent = d->m_mainwindow;
|
2018-01-29 11:46:23 +01:00
|
|
|
QMessageBox msgBox(QMessageBox::Warning, title, text,
|
|
|
|
|
QMessageBox::Ok, parent);
|
2022-07-11 12:42:45 +03:00
|
|
|
msgBox.setEscapeButton(QMessageBox::Ok);
|
2018-01-29 11:46:23 +01:00
|
|
|
if (!details.isEmpty())
|
|
|
|
|
msgBox.setDetailedText(details);
|
|
|
|
|
QAbstractButton *settingsButton = nullptr;
|
|
|
|
|
if (settingsId.isValid())
|
2020-05-28 16:26:01 +02:00
|
|
|
settingsButton = msgBox.addButton(msgShowOptionsDialog(), QMessageBox::AcceptRole);
|
2018-01-29 11:46:23 +01:00
|
|
|
msgBox.exec();
|
|
|
|
|
if (settingsButton && msgBox.clickedButton() == settingsButton)
|
|
|
|
|
return showOptionsDialog(settingsId);
|
|
|
|
|
return false;
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-04 16:26:15 +02:00
|
|
|
bool ICore::isQtDesignStudio()
|
|
|
|
|
{
|
|
|
|
|
QtcSettings *settings = Core::ICore::settings();
|
|
|
|
|
return settings->value("QML/Designer/StandAloneMode", false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
|
|
|
|
Returns the application's main settings object.
|
|
|
|
|
|
|
|
|
|
You can use it to retrieve or set application-wide settings
|
|
|
|
|
(in contrast to session or project specific settings).
|
|
|
|
|
|
|
|
|
|
If \a scope is \c QSettings::UserScope (the default), the
|
|
|
|
|
settings will be read from the user's settings, with
|
|
|
|
|
a fallback to global settings provided with \QC.
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
If \a scope is \c QSettings::SystemScope, only the installation settings
|
2020-03-18 13:32:02 +01:00
|
|
|
shipped with the current version of \QC will be read. This
|
|
|
|
|
functionality exists for internal purposes only.
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
\sa settingsDatabase()
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2020-11-19 15:34:59 +01:00
|
|
|
QtcSettings *ICore::settings(QSettings::Scope scope)
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2014-03-04 16:07:44 +01:00
|
|
|
if (scope == QSettings::UserScope)
|
|
|
|
|
return PluginManager::settings();
|
|
|
|
|
else
|
|
|
|
|
return PluginManager::globalSettings();
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
|
|
|
|
Returns the application's printer object.
|
|
|
|
|
|
|
|
|
|
Always use this printer object for printing, so the different parts of the
|
|
|
|
|
application re-use its settings.
|
|
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
QPrinter *ICore::printer()
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
if (!d->m_printer)
|
|
|
|
|
d->m_printer = new QPrinter(QPrinter::HighResolution);
|
|
|
|
|
return d->m_printer;
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the locale string for the user interface language that is currently
|
|
|
|
|
configured in \QC. Use this to install your plugin's translation file with
|
|
|
|
|
QTranslator.
|
|
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
QString ICore::userInterfaceLanguage()
|
|
|
|
|
{
|
|
|
|
|
return qApp->property("qtc_locale").toString();
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 15:46:09 +02:00
|
|
|
static QString pathHelper(const QString &rel)
|
|
|
|
|
{
|
|
|
|
|
if (rel.isEmpty())
|
|
|
|
|
return rel;
|
|
|
|
|
if (rel.startsWith('/'))
|
|
|
|
|
return rel;
|
|
|
|
|
return '/' + rel;
|
|
|
|
|
}
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
2021-11-25 16:11:53 +01:00
|
|
|
Returns the absolute path for the relative path \a rel that is used for resources like
|
2020-03-18 13:32:02 +01:00
|
|
|
project templates and the debugger macros.
|
|
|
|
|
|
|
|
|
|
This abstraction is needed to avoid platform-specific code all over
|
|
|
|
|
the place, since on \macos, for example, the resources are part of the
|
|
|
|
|
application bundle.
|
2020-05-28 16:26:01 +02:00
|
|
|
|
|
|
|
|
\sa userResourcePath()
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2021-04-26 15:46:09 +02:00
|
|
|
FilePath ICore::resourcePath(const QString &rel)
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2021-04-22 16:15:26 +02:00
|
|
|
return FilePath::fromString(
|
2021-05-26 10:12:58 +02:00
|
|
|
QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + RELATIVE_DATA_PATH))
|
|
|
|
|
/ rel;
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
2021-11-25 16:11:53 +01:00
|
|
|
Returns the absolute path for the relative path \a rel in the users directory that is used for
|
2020-03-18 13:32:02 +01:00
|
|
|
resources like project templates.
|
|
|
|
|
|
|
|
|
|
Use this function for finding the place for resources that the user may
|
|
|
|
|
write to, for example, to allow for custom palettes or templates.
|
2020-05-28 16:26:01 +02:00
|
|
|
|
|
|
|
|
\sa resourcePath()
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
|
|
|
|
|
2021-04-26 15:46:09 +02:00
|
|
|
FilePath ICore::userResourcePath(const QString &rel)
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
|
|
|
|
// Create qtcreator dir if it doesn't yet exist
|
|
|
|
|
const QString configDir = QFileInfo(settings(QSettings::UserScope)->fileName()).path();
|
2023-06-21 15:12:46 +02:00
|
|
|
const QString urp = configDir + '/' + appInfo().id;
|
2012-01-18 23:25:34 +01:00
|
|
|
|
2014-10-24 10:28:28 +02:00
|
|
|
if (!QFileInfo::exists(urp + QLatin1Char('/'))) {
|
2012-01-18 23:25:34 +01:00
|
|
|
QDir dir;
|
|
|
|
|
if (!dir.mkpath(urp))
|
|
|
|
|
qWarning() << "could not create" << urp;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 15:46:09 +02:00
|
|
|
return FilePath::fromString(urp + pathHelper(rel));
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
2021-11-25 16:11:53 +01:00
|
|
|
Returns a writable path for the relative path \a rel that can be used for persistent cache files.
|
2020-05-28 16:26:01 +02:00
|
|
|
*/
|
2021-04-26 15:46:09 +02:00
|
|
|
FilePath ICore::cacheResourcePath(const QString &rel)
|
2019-02-20 17:26:36 +01:00
|
|
|
{
|
2021-04-26 15:46:09 +02:00
|
|
|
return FilePath::fromString(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
|
|
|
|
|
+ pathHelper(rel));
|
2019-02-20 17:26:36 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
2021-11-25 16:11:53 +01:00
|
|
|
Returns the path, based on the relative path \a rel, to resources written by the installer,
|
|
|
|
|
for example pre-defined kits and toolchains.
|
2020-05-28 16:26:01 +02:00
|
|
|
*/
|
2021-04-26 15:46:09 +02:00
|
|
|
FilePath ICore::installerResourcePath(const QString &rel)
|
2018-01-10 17:29:27 +01:00
|
|
|
{
|
2021-04-22 16:15:26 +02:00
|
|
|
return FilePath::fromString(settings(QSettings::SystemScope)->fileName()).parentDir()
|
2023-06-21 15:12:46 +02:00
|
|
|
/ appInfo().id / rel;
|
2020-01-21 14:17:05 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the path to the plugins that are included in the \QC installation.
|
|
|
|
|
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2020-01-21 14:17:05 +01:00
|
|
|
QString ICore::pluginPath()
|
|
|
|
|
{
|
|
|
|
|
return QDir::cleanPath(QCoreApplication::applicationDirPath() + '/' + RELATIVE_PLUGIN_PATH);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the path where user-specific plugins should be written.
|
|
|
|
|
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2020-01-21 14:17:05 +01:00
|
|
|
QString ICore::userPluginPath()
|
|
|
|
|
{
|
2023-06-21 15:12:46 +02:00
|
|
|
const QVersionNumber appVersion = QVersionNumber::fromString(
|
|
|
|
|
QCoreApplication::applicationVersion());
|
2020-01-21 14:17:05 +01:00
|
|
|
QString pluginPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
|
|
|
|
|
if (Utils::HostOsInfo::isAnyUnixHost() && !Utils::HostOsInfo::isMacHost())
|
|
|
|
|
pluginPath += "/data";
|
2023-06-21 15:12:46 +02:00
|
|
|
pluginPath += '/' + QCoreApplication::organizationName() + '/';
|
|
|
|
|
pluginPath += Utils::HostOsInfo::isMacHost() ? QGuiApplication::applicationDisplayName()
|
|
|
|
|
: appInfo().id;
|
2020-01-21 14:17:05 +01:00
|
|
|
pluginPath += "/plugins/";
|
2023-06-21 15:12:46 +02:00
|
|
|
pluginPath += QString::number(appVersion.majorVersion()) + '.'
|
|
|
|
|
+ QString::number(appVersion.minorVersion()) + '.'
|
|
|
|
|
+ QString::number(appVersion.microVersion());
|
2020-01-21 14:17:05 +01:00
|
|
|
return pluginPath;
|
2018-01-10 17:29:27 +01:00
|
|
|
}
|
|
|
|
|
|
2013-10-02 16:09:23 +02:00
|
|
|
/*!
|
2021-11-25 16:11:53 +01:00
|
|
|
Returns the path, based on the relative path \a rel, to the command line tools that are
|
|
|
|
|
included in the \QC installation.
|
2013-10-02 16:09:23 +02:00
|
|
|
*/
|
2021-04-26 15:46:09 +02:00
|
|
|
FilePath ICore::libexecPath(const QString &rel)
|
2013-10-02 16:09:23 +02:00
|
|
|
{
|
2021-05-26 10:12:58 +02:00
|
|
|
return FilePath::fromString(QDir::cleanPath(QApplication::applicationDirPath()
|
|
|
|
|
+ pathHelper(RELATIVE_LIBEXEC_PATH)))
|
|
|
|
|
/ rel;
|
2013-10-02 16:09:23 +02:00
|
|
|
}
|
|
|
|
|
|
2021-04-22 16:15:26 +02:00
|
|
|
FilePath ICore::crashReportsPath()
|
2020-09-21 12:58:35 +03:00
|
|
|
{
|
|
|
|
|
if (Utils::HostOsInfo::isMacHost())
|
2023-03-03 18:13:30 +01:00
|
|
|
return Core::ICore::userResourcePath("crashpad_reports/completed");
|
2020-09-21 12:58:35 +03:00
|
|
|
else
|
2021-04-26 15:46:09 +02:00
|
|
|
return libexecPath("crashpad_reports/reports");
|
2020-09-21 12:58:35 +03:00
|
|
|
}
|
|
|
|
|
|
2018-08-06 11:32:32 +02:00
|
|
|
static QString clangIncludePath(const QString &clangVersion)
|
|
|
|
|
{
|
|
|
|
|
return "/lib/clang/" + clangVersion + "/include";
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-08-12 09:19:55 +02:00
|
|
|
FilePath ICore::clangIncludeDirectory(const QString &clangVersion,
|
|
|
|
|
const FilePath &clangFallbackIncludeDir)
|
2018-08-06 11:32:32 +02:00
|
|
|
{
|
2021-04-26 15:46:09 +02:00
|
|
|
FilePath dir = libexecPath("clang" + clangIncludePath(clangVersion));
|
2021-04-22 16:15:26 +02:00
|
|
|
if (!dir.exists() || !dir.pathAppended("stdint.h").exists())
|
2021-08-12 09:19:55 +02:00
|
|
|
dir = clangFallbackIncludeDir;
|
|
|
|
|
return dir.canonicalPath();
|
2018-08-06 11:32:32 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-08-12 09:19:55 +02:00
|
|
|
static FilePath clangBinary(const QString &binaryBaseName, const FilePath &clangBinDirectory)
|
2018-08-06 11:32:32 +02:00
|
|
|
{
|
2021-08-12 09:19:55 +02:00
|
|
|
FilePath executable =
|
|
|
|
|
ICore::libexecPath("clang/bin").pathAppended(binaryBaseName).withExecutableSuffix();
|
2018-08-06 11:32:32 +02:00
|
|
|
if (!executable.exists())
|
2021-08-12 09:19:55 +02:00
|
|
|
executable = clangBinDirectory.pathAppended(binaryBaseName).withExecutableSuffix();
|
|
|
|
|
return executable.canonicalPath();
|
2018-08-06 11:32:32 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-08-12 09:19:55 +02:00
|
|
|
FilePath ICore::clangExecutable(const FilePath &clangBinDirectory)
|
2019-08-01 16:08:40 +02:00
|
|
|
{
|
|
|
|
|
return clangBinary("clang", clangBinDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-23 13:51:41 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-08-12 09:19:55 +02:00
|
|
|
FilePath ICore::clangdExecutable(const FilePath &clangBinDirectory)
|
2021-02-23 13:51:41 +01:00
|
|
|
{
|
|
|
|
|
return clangBinary("clangd", clangBinDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-08-12 09:19:55 +02:00
|
|
|
FilePath ICore::clangTidyExecutable(const FilePath &clangBinDirectory)
|
2019-08-01 16:08:40 +02:00
|
|
|
{
|
|
|
|
|
return clangBinary("clang-tidy", clangBinDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2021-08-12 09:19:55 +02:00
|
|
|
FilePath ICore::clazyStandaloneExecutable(const FilePath &clangBinDirectory)
|
2019-08-28 08:56:22 +02:00
|
|
|
{
|
|
|
|
|
return clangBinary("clazy-standalone", clangBinDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-16 12:47:57 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
FilePath ICore::lldbExecutable(const Utils::FilePath &lldbBinDirectory)
|
|
|
|
|
{
|
|
|
|
|
return clangBinary("lldb", lldbBinDirectory);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-24 16:45:49 +02:00
|
|
|
static QString compilerString()
|
|
|
|
|
{
|
|
|
|
|
#if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
|
2021-06-03 18:12:54 +02:00
|
|
|
QString platformSpecific;
|
2013-05-24 16:45:49 +02:00
|
|
|
#if defined(__apple_build_version__) // Apple clang has other version numbers
|
2021-06-03 18:12:54 +02:00
|
|
|
platformSpecific = QLatin1String(" (Apple)");
|
|
|
|
|
#elif defined(Q_CC_MSVC)
|
|
|
|
|
platformSpecific = QLatin1String(" (clang-cl)");
|
2013-05-24 16:45:49 +02:00
|
|
|
#endif
|
|
|
|
|
return QLatin1String("Clang " ) + QString::number(__clang_major__) + QLatin1Char('.')
|
2021-06-03 18:12:54 +02:00
|
|
|
+ QString::number(__clang_minor__) + platformSpecific;
|
2013-05-24 16:45:49 +02:00
|
|
|
#elif defined(Q_CC_GNU)
|
|
|
|
|
return QLatin1String("GCC " ) + QLatin1String(__VERSION__);
|
|
|
|
|
#elif defined(Q_CC_MSVC)
|
2016-01-19 15:21:11 +01:00
|
|
|
if (_MSC_VER > 1999)
|
|
|
|
|
return QLatin1String("MSVC <unknown>");
|
2022-04-14 12:23:32 +02:00
|
|
|
if (_MSC_VER >= 1930)
|
|
|
|
|
return QLatin1String("MSVC 2022");
|
2020-05-28 16:40:39 +02:00
|
|
|
if (_MSC_VER >= 1920)
|
|
|
|
|
return QLatin1String("MSVC 2019");
|
2017-04-14 16:25:21 +03:00
|
|
|
if (_MSC_VER >= 1910)
|
|
|
|
|
return QLatin1String("MSVC 2017");
|
|
|
|
|
if (_MSC_VER >= 1900)
|
2016-01-19 15:21:11 +01:00
|
|
|
return QLatin1String("MSVC 2015");
|
2013-05-24 16:45:49 +02:00
|
|
|
#endif
|
|
|
|
|
return QLatin1String("<unknown compiler>");
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns a string with the IDE's name and version, in the form "\QC X.Y.Z".
|
|
|
|
|
Use this for "Generated by" strings and similar tasks.
|
|
|
|
|
*/
|
2013-05-24 16:45:49 +02:00
|
|
|
QString ICore::versionString()
|
|
|
|
|
{
|
|
|
|
|
QString ideVersionDescription;
|
2023-06-21 15:12:46 +02:00
|
|
|
if (QCoreApplication::applicationVersion() != appInfo().displayVersion)
|
2023-11-15 12:44:30 +01:00
|
|
|
ideVersionDescription = QString(" (%1)").arg(QCoreApplication::applicationVersion());
|
|
|
|
|
return QString("%1 %2%3").arg(QGuiApplication::applicationDisplayName(),
|
|
|
|
|
appInfo().displayVersion,
|
|
|
|
|
ideVersionDescription);
|
2013-05-24 16:45:49 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
2020-05-28 16:26:01 +02:00
|
|
|
Returns the top level IContext of the current context, or \c nullptr if
|
|
|
|
|
there is none.
|
2020-03-18 13:32:02 +01:00
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
\sa updateAdditionalContexts()
|
|
|
|
|
\sa addContextObject()
|
|
|
|
|
\sa {The Action Manager and Commands}
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
IContext *ICore::currentContextObject()
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
return d->m_activeContext.isEmpty() ? nullptr : d->m_activeContext.first();
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the widget of the top level IContext of the current context, or \c
|
|
|
|
|
nullptr if there is none.
|
|
|
|
|
|
|
|
|
|
\sa currentContextObject()
|
|
|
|
|
*/
|
2017-11-30 16:32:55 +01:00
|
|
|
QWidget *ICore::currentContextWidget()
|
|
|
|
|
{
|
|
|
|
|
IContext *context = currentContextObject();
|
|
|
|
|
return context ? context->widget() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
|
|
|
|
Returns the main window of the application.
|
2012-01-18 23:25:34 +01:00
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
For dialog parents use dialogParent().
|
2020-05-28 16:26:01 +02:00
|
|
|
|
|
|
|
|
\sa dialogParent()
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2018-01-10 10:23:18 +01:00
|
|
|
QMainWindow *ICore::mainWindow()
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2023-10-02 17:27:26 +02:00
|
|
|
return d->m_mainwindow;
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
|
|
|
|
Returns a widget pointer suitable to use as parent for QDialogs.
|
2020-05-28 16:26:01 +02:00
|
|
|
*/
|
2014-01-06 10:36:40 +01:00
|
|
|
QWidget *ICore::dialogParent()
|
|
|
|
|
{
|
|
|
|
|
QWidget *active = QApplication::activeModalWidget();
|
2015-06-03 12:20:13 +02:00
|
|
|
if (!active)
|
|
|
|
|
active = QApplication::activeWindow();
|
2023-10-25 14:23:57 +02:00
|
|
|
if (!active || active->windowFlags().testFlag(Qt::SplashScreen)
|
|
|
|
|
|| active->windowFlags().testFlag(Qt::Popup)) {
|
2023-10-02 17:27:26 +02:00
|
|
|
active = d->m_mainwindow;
|
2023-10-25 14:23:57 +02:00
|
|
|
}
|
2015-06-03 12:20:13 +02:00
|
|
|
return active;
|
2014-01-06 10:36:40 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2012-01-18 23:25:34 +01:00
|
|
|
QStatusBar *ICore::statusBar()
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
return d->m_modeStack->statusBar();
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Returns a central InfoBar that is shown in \QC's main window.
|
|
|
|
|
Use for notifying the user of something without interrupting with
|
|
|
|
|
dialog. Use sparingly.
|
|
|
|
|
*/
|
2020-06-17 12:23:44 +02:00
|
|
|
Utils::InfoBar *ICore::infoBar()
|
2019-08-07 12:44:40 +02:00
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
return d->m_modeStack->infoBar();
|
2019-08-07 12:44:40 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Raises and activates the window for \a widget. This contains workarounds
|
|
|
|
|
for X11.
|
|
|
|
|
*/
|
2013-04-15 12:53:34 +02:00
|
|
|
void ICore::raiseWindow(QWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
if (!widget)
|
|
|
|
|
return;
|
|
|
|
|
QWidget *window = widget->window();
|
2022-11-30 14:47:49 +01:00
|
|
|
if (!window)
|
|
|
|
|
return;
|
2023-10-02 17:27:26 +02:00
|
|
|
if (window == d->m_mainwindow) {
|
|
|
|
|
d->m_mainwindow->raiseWindow();
|
2013-04-15 12:53:34 +02:00
|
|
|
} else {
|
|
|
|
|
window->raise();
|
|
|
|
|
window->activateWindow();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 14:53:59 +02:00
|
|
|
void ICore::raiseMainWindow()
|
|
|
|
|
{
|
2023-10-02 17:27:26 +02:00
|
|
|
d->m_mainwindow->raiseWindow();
|
2023-09-15 14:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
2020-05-28 16:26:01 +02:00
|
|
|
Removes the contexts specified by \a remove from the list of active
|
|
|
|
|
additional contexts, and adds the contexts specified by \a add with \a
|
|
|
|
|
priority.
|
2020-03-18 13:32:02 +01:00
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
The additional contexts are not associated with an IContext instance.
|
|
|
|
|
|
|
|
|
|
High priority additional contexts have higher priority than the contexts
|
|
|
|
|
added by IContext instances, low priority additional contexts have lower
|
|
|
|
|
priority than the contexts added by IContext instances.
|
|
|
|
|
|
|
|
|
|
\sa addContextObject()
|
|
|
|
|
\sa {The Action Manager and Commands}
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2015-08-07 17:21:38 +02:00
|
|
|
void ICore::updateAdditionalContexts(const Context &remove, const Context &add,
|
|
|
|
|
ContextPriority priority)
|
2012-01-18 23:25:34 +01:00
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
for (const Id id : remove) {
|
|
|
|
|
if (!id.isValid())
|
|
|
|
|
continue;
|
|
|
|
|
int index = d->m_lowPrioAdditionalContexts.indexOf(id);
|
|
|
|
|
if (index != -1)
|
|
|
|
|
d->m_lowPrioAdditionalContexts.removeAt(index);
|
|
|
|
|
index = d->m_highPrioAdditionalContexts.indexOf(id);
|
|
|
|
|
if (index != -1)
|
|
|
|
|
d->m_highPrioAdditionalContexts.removeAt(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const Id id : add) {
|
|
|
|
|
if (!id.isValid())
|
|
|
|
|
continue;
|
|
|
|
|
Context &cref = (priority == ICore::ContextPriority::High ? d->m_highPrioAdditionalContexts
|
|
|
|
|
: d->m_lowPrioAdditionalContexts);
|
|
|
|
|
if (!cref.contains(id))
|
|
|
|
|
cref.prepend(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d->updateContext();
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
/*!
|
2020-05-28 16:26:01 +02:00
|
|
|
Adds \a context with \a priority to the list of active additional contexts.
|
|
|
|
|
|
|
|
|
|
\sa updateAdditionalContexts()
|
2020-03-18 13:32:02 +01:00
|
|
|
*/
|
2015-08-07 17:21:38 +02:00
|
|
|
void ICore::addAdditionalContext(const Context &context, ContextPriority priority)
|
2014-11-16 11:47:18 +02:00
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
updateAdditionalContexts(Context(), context, priority);
|
2014-11-16 11:47:18 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Removes \a context from the list of active additional contexts.
|
|
|
|
|
|
|
|
|
|
\sa updateAdditionalContexts()
|
|
|
|
|
*/
|
2014-11-16 11:47:18 +02:00
|
|
|
void ICore::removeAdditionalContext(const Context &context)
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
updateAdditionalContexts(context, Context(), ContextPriority::Low);
|
2012-01-18 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Registers a \a window with the specified \a context. Registered windows are
|
|
|
|
|
shown in the \uicontrol Window menu and get registered for the various
|
|
|
|
|
window related actions, like the minimize, zoom, fullscreen and close
|
|
|
|
|
actions.
|
|
|
|
|
|
|
|
|
|
Whenever the application focus is in \a window, its \a context is made
|
|
|
|
|
active.
|
|
|
|
|
*/
|
2014-07-17 17:04:02 +02:00
|
|
|
void ICore::registerWindow(QWidget *window, const Context &context)
|
|
|
|
|
{
|
|
|
|
|
new WindowSupport(window, context); // deletes itself when widget is destroyed
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-26 14:39:15 +02:00
|
|
|
/*!
|
2020-03-18 13:32:02 +01:00
|
|
|
Provides a hook for plugins to veto on closing the application.
|
2015-08-26 14:39:15 +02:00
|
|
|
|
2020-03-18 13:32:02 +01:00
|
|
|
When the application window requests a close, all listeners are called. If
|
|
|
|
|
one of the \a listener calls returns \c false, the process is aborted and
|
|
|
|
|
the event is ignored. If all calls return \c true, coreAboutToClose()
|
|
|
|
|
is emitted and the event is accepted or performed.
|
2015-08-26 14:39:15 +02:00
|
|
|
*/
|
|
|
|
|
void ICore::addPreCloseListener(const std::function<bool ()> &listener)
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
d->m_preCloseListeners.append(listener);
|
2015-08-26 14:39:15 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2016-08-31 15:39:52 +02:00
|
|
|
QString ICore::systemInformation()
|
|
|
|
|
{
|
2023-11-14 18:00:47 +01:00
|
|
|
return PluginManager::systemInformation() + '\n' + aboutInformationCompact() + '\n';
|
2016-08-31 15:39:52 +02:00
|
|
|
}
|
|
|
|
|
|
2022-08-24 14:55:41 +02:00
|
|
|
static const QString &screenShotsPath()
|
2016-12-20 11:19:22 +01:00
|
|
|
{
|
2022-08-24 14:55:41 +02:00
|
|
|
static const QString path = qtcEnvironmentVariable("QTC_SCREENSHOTS_PATH");
|
2016-12-20 11:19:22 +01:00
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ScreenShooter : public QObject
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ScreenShooter(QWidget *widget, const QString &name, const QRect &rc)
|
|
|
|
|
: m_widget(widget), m_name(name), m_rc(rc)
|
|
|
|
|
{
|
|
|
|
|
m_widget->installEventFilter(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool eventFilter(QObject *watched, QEvent *event) override
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(watched == m_widget, return false);
|
|
|
|
|
if (event->type() == QEvent::Show)
|
2021-01-28 11:29:14 +01:00
|
|
|
QMetaObject::invokeMethod(this, &ScreenShooter::helper, Qt::QueuedConnection);
|
2016-12-20 11:19:22 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void helper()
|
|
|
|
|
{
|
|
|
|
|
if (m_widget) {
|
|
|
|
|
QRect rc = m_rc.isValid() ? m_rc : m_widget->rect();
|
|
|
|
|
QPixmap pm = m_widget->grab(rc);
|
|
|
|
|
for (int i = 0; ; ++i) {
|
|
|
|
|
QString fileName = screenShotsPath() + '/' + m_name + QString("-%1.png").arg(i);
|
|
|
|
|
if (!QFileInfo::exists(fileName)) {
|
|
|
|
|
pm.save(fileName);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
deleteLater();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QPointer<QWidget> m_widget;
|
|
|
|
|
QString m_name;
|
|
|
|
|
QRect m_rc;
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2016-12-20 11:19:22 +01:00
|
|
|
void ICore::setupScreenShooter(const QString &name, QWidget *w, const QRect &rc)
|
|
|
|
|
{
|
|
|
|
|
if (!screenShotsPath().isEmpty())
|
|
|
|
|
new ScreenShooter(w, name, rc);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
static void setRestart(bool restart)
|
|
|
|
|
{
|
|
|
|
|
qApp->setProperty("restart", restart);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
Restarts \QC and restores the last session.
|
|
|
|
|
*/
|
2020-01-03 16:47:15 +01:00
|
|
|
void ICore::restart()
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
setRestart(true);
|
|
|
|
|
exit();
|
2020-01-03 16:47:15 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2019-06-03 09:32:15 +02:00
|
|
|
void ICore::saveSettings(SaveSettingsReason reason)
|
2012-08-17 09:09:15 +02:00
|
|
|
{
|
2023-09-15 12:58:44 +02:00
|
|
|
emit m_core->saveSettingsRequested(reason);
|
2023-09-15 16:47:37 +02:00
|
|
|
|
|
|
|
|
QtcSettings *settings = PluginManager::settings();
|
|
|
|
|
settings->beginGroup(settingsGroup);
|
|
|
|
|
|
2023-10-02 17:54:48 +02:00
|
|
|
if (!(s_overrideColor.isValid() && StyleHelper::baseColor() == s_overrideColor))
|
2023-09-15 16:47:37 +02:00
|
|
|
settings->setValueWithDefault(colorKey,
|
|
|
|
|
StyleHelper::requestedBaseColor(),
|
|
|
|
|
QColor(StyleHelper::DEFAULT_BASE_COLOR));
|
|
|
|
|
|
|
|
|
|
if (Internal::globalMenuBar() && !Internal::globalMenuBar()->isNativeMenuBar())
|
|
|
|
|
settings->setValue(menubarVisibleKey, Internal::globalMenuBar()->isVisible());
|
|
|
|
|
|
|
|
|
|
settings->endGroup();
|
|
|
|
|
|
|
|
|
|
DocumentManager::saveSettings();
|
|
|
|
|
ActionManager::saveSettings();
|
|
|
|
|
EditorManagerPrivate::saveSettings();
|
|
|
|
|
d->m_leftNavigationWidget->saveSettings(settings);
|
|
|
|
|
d->m_rightNavigationWidget->saveSettings(settings);
|
|
|
|
|
|
|
|
|
|
// TODO Remove some time after Qt Creator 11
|
|
|
|
|
// Work around Qt Creator <= 10 writing the default terminal to the settings.
|
|
|
|
|
// TerminalCommand writes the terminal to the settings when changing it, which usually is
|
|
|
|
|
// enough. But because of the bug in Qt Creator <= 10 we want to clean up the settings
|
|
|
|
|
// even if the user never touched the terminal setting.
|
|
|
|
|
if (HostOsInfo::isMacHost())
|
|
|
|
|
TerminalCommand::setTerminalEmulator(TerminalCommand::terminalEmulator());
|
2012-08-17 09:09:15 +02:00
|
|
|
|
|
|
|
|
ICore::settings(QSettings::SystemScope)->sync();
|
|
|
|
|
ICore::settings(QSettings::UserScope)->sync();
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2015-10-02 15:15:38 +02:00
|
|
|
QStringList ICore::additionalAboutInformation()
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
return d->m_aboutInformation;
|
2015-10-02 15:15:38 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-07 14:06:37 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void ICore::clearAboutInformation()
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
d->m_aboutInformation.clear();
|
2023-09-07 14:06:37 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-28 16:26:01 +02:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2015-10-02 15:15:38 +02:00
|
|
|
void ICore::appendAboutInformation(const QString &line)
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
d->m_aboutInformation.append(line);
|
2015-10-02 15:15:38 +02:00
|
|
|
}
|
|
|
|
|
|
2023-11-14 18:00:47 +01:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
QString ICore::aboutInformationCompact()
|
|
|
|
|
{
|
|
|
|
|
QString information = QString("Product: %1\n").arg(versionString());
|
|
|
|
|
information += QString("Based on: Qt %1 (%2, %3)\n")
|
|
|
|
|
.arg(QLatin1String(qVersion()), compilerString(),
|
|
|
|
|
QSysInfo::buildCpuArchitecture());
|
|
|
|
|
#ifdef QTC_SHOW_BUILD_DATE
|
|
|
|
|
information += QString("Built on: %1 %2\n").arg(QLatin1String(__DATE__),
|
|
|
|
|
QLatin1String(__TIME__));
|
|
|
|
|
#endif
|
|
|
|
|
const AppInfo &appInfo = Utils::appInfo();
|
|
|
|
|
if (!appInfo.revision.isEmpty())
|
|
|
|
|
information += QString("From revision: %1\n").arg(appInfo.revision.left(10));
|
|
|
|
|
|
|
|
|
|
return information;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
QString ICore::aboutInformationHtml()
|
|
|
|
|
{
|
|
|
|
|
const QString buildCompatibilityString = Tr::tr("Based on Qt %1 (%2, %3)")
|
|
|
|
|
.arg(QLatin1String(qVersion()), compilerString(),
|
|
|
|
|
QSysInfo::buildCpuArchitecture());
|
|
|
|
|
const AppInfo &appInfo = Utils::appInfo();
|
|
|
|
|
QString ideRev;
|
|
|
|
|
if (!appInfo.revision.isEmpty())
|
|
|
|
|
ideRev = Tr::tr("<br/>From revision %1<br/>")
|
|
|
|
|
.arg(appInfo.revisionUrl.isEmpty()
|
|
|
|
|
? appInfo.revision
|
|
|
|
|
: QString::fromLatin1("<a href=\"%1\">%2</a>")
|
|
|
|
|
.arg(appInfo.revisionUrl, appInfo.revision));
|
|
|
|
|
QString buildDateInfo;
|
|
|
|
|
#ifdef QTC_SHOW_BUILD_DATE
|
|
|
|
|
buildDateInfo = Tr::tr("<br/>Built on %1 %2<br/>").arg(QLatin1String(__DATE__),
|
|
|
|
|
QLatin1String(__TIME__));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
const QString br = QLatin1String("<br/>");
|
|
|
|
|
const QStringList additionalInfoLines = ICore::additionalAboutInformation();
|
|
|
|
|
const QString additionalInfo =
|
|
|
|
|
QStringList(Utils::transform(additionalInfoLines, &QString::toHtmlEscaped)).join(br);
|
|
|
|
|
const QString information
|
|
|
|
|
= Tr::tr("<h3>%1</h3>"
|
|
|
|
|
"%2<br/>"
|
|
|
|
|
"%3"
|
|
|
|
|
"%4"
|
|
|
|
|
"%5"
|
|
|
|
|
"<br/>"
|
|
|
|
|
"Copyright 2008-%6 %7. All rights reserved.<br/>"
|
|
|
|
|
"<br/>"
|
|
|
|
|
"The program is provided AS IS with NO WARRANTY OF ANY KIND, "
|
|
|
|
|
"INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A "
|
|
|
|
|
"PARTICULAR PURPOSE.<br/>")
|
|
|
|
|
.arg(ICore::versionString(),
|
|
|
|
|
buildCompatibilityString,
|
|
|
|
|
buildDateInfo,
|
|
|
|
|
ideRev,
|
|
|
|
|
additionalInfo.isEmpty() ? QString() : br + additionalInfo + br,
|
|
|
|
|
appInfo.year,
|
|
|
|
|
appInfo.author)
|
|
|
|
|
+ "<br/>"
|
|
|
|
|
+ Tr::tr("The Qt logo as well as Qt®, Qt Quick®, Built with Qt®, Boot to Qt®, "
|
|
|
|
|
"Qt Quick Compiler®, Qt Enterprise®, Qt Mobile® and Qt Embedded® are "
|
|
|
|
|
"registered trademarks of The Qt Company Ltd.");
|
|
|
|
|
|
|
|
|
|
return information;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 16:39:49 +02:00
|
|
|
void ICore::updateNewItemDialogState()
|
2015-05-29 13:24:02 +02:00
|
|
|
{
|
2015-05-29 14:23:59 +02:00
|
|
|
static bool wasRunning = false;
|
2016-09-26 16:39:49 +02:00
|
|
|
static QWidget *previousDialog = nullptr;
|
|
|
|
|
if (wasRunning == isNewItemDialogRunning() && previousDialog == newItemDialog())
|
2015-05-29 14:23:59 +02:00
|
|
|
return;
|
|
|
|
|
wasRunning = isNewItemDialogRunning();
|
2016-09-26 16:39:49 +02:00
|
|
|
previousDialog = newItemDialog();
|
|
|
|
|
emit instance()->newItemDialogStateChanged();
|
2015-05-29 13:24:02 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-26 20:02:55 +03:00
|
|
|
/*!
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void ICore::setNewDialogFactory(const std::function<NewDialog *(QWidget *)> &newFactory)
|
|
|
|
|
{
|
|
|
|
|
m_newDialogFactory = newFactory;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
static bool hideToolsMenu()
|
|
|
|
|
{
|
|
|
|
|
return Core::ICore::settings()->value(Constants::SETTINGS_MENU_HIDE_TOOLS, false).toBool();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum { debugMainWindow = 0 };
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
namespace Internal {
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::init()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
2023-10-02 17:27:26 +02:00
|
|
|
m_mainwindow = new MainWindow;
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
m_progressManager = new ProgressManagerPrivate;
|
|
|
|
|
m_jsExpander = JsExpander::createGlobalJsExpander();
|
|
|
|
|
m_vcsManager = new VcsManager;
|
2023-09-15 16:47:37 +02:00
|
|
|
m_modeStack = new FancyTabWidget(m_mainwindow);
|
2023-09-15 12:58:44 +02:00
|
|
|
m_shortcutSettings = new ShortcutSettings;
|
|
|
|
|
m_toolSettings = new ToolSettings;
|
|
|
|
|
m_mimeTypeSettings = new MimeTypeSettings;
|
|
|
|
|
m_systemEditor = new SystemEditor;
|
|
|
|
|
m_toggleLeftSideBarButton = new QToolButton;
|
|
|
|
|
m_toggleRightSideBarButton = new QToolButton;
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
(void) new DocumentManager(this);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
HistoryCompleter::setSettings(PluginManager::settings());
|
|
|
|
|
|
|
|
|
|
if (HostOsInfo::isLinuxHost())
|
|
|
|
|
QApplication::setWindowIcon(Icons::QTCREATORLOGO_BIG.icon());
|
|
|
|
|
QString baseName = QApplication::style()->objectName();
|
|
|
|
|
// Sometimes we get the standard windows 95 style as a fallback
|
|
|
|
|
if (HostOsInfo::isAnyUnixHost() && !HostOsInfo::isMacHost()
|
|
|
|
|
&& baseName == QLatin1String("windows")) {
|
|
|
|
|
baseName = QLatin1String("fusion");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if the user has specified as base style in the theme settings,
|
|
|
|
|
// prefer that
|
|
|
|
|
const QStringList available = QStyleFactory::keys();
|
|
|
|
|
const QStringList styles = Utils::creatorTheme()->preferredStyles();
|
|
|
|
|
for (const QString &s : styles) {
|
|
|
|
|
if (available.contains(s, Qt::CaseInsensitive)) {
|
|
|
|
|
baseName = s;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QApplication::setStyle(new ManhattanStyle(baseName));
|
|
|
|
|
|
2023-10-04 17:01:15 +02:00
|
|
|
m_modeManager = new ModeManager(m_modeStack);
|
2023-09-15 12:58:44 +02:00
|
|
|
connect(m_modeStack, &FancyTabWidget::topAreaClicked, this, [](Qt::MouseButton, Qt::KeyboardModifiers modifiers) {
|
|
|
|
|
if (modifiers & Qt::ShiftModifier) {
|
|
|
|
|
QColor color = QColorDialog::getColor(StyleHelper::requestedBaseColor(), ICore::dialogParent());
|
|
|
|
|
if (color.isValid())
|
|
|
|
|
StyleHelper::setBaseColor(color);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2023-10-02 17:27:26 +02:00
|
|
|
m_mainwindow->setCentralWidget(d->m_modeStack);
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
registerDefaultContainers();
|
|
|
|
|
registerDefaultActions();
|
|
|
|
|
|
|
|
|
|
m_leftNavigationWidget = new NavigationWidget(m_toggleLeftSideBarAction, Side::Left);
|
|
|
|
|
m_rightNavigationWidget = new NavigationWidget(m_toggleRightSideBarAction, Side::Right);
|
|
|
|
|
m_rightPaneWidget = new RightPaneWidget();
|
|
|
|
|
|
|
|
|
|
m_messageManager = new MessageManager;
|
|
|
|
|
m_editorManager = new EditorManager(this);
|
|
|
|
|
m_externalToolManager = new ExternalToolManager();
|
|
|
|
|
|
2023-10-02 17:27:26 +02:00
|
|
|
m_progressManager->progressView()->setParent(m_mainwindow);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
connect(qApp, &QApplication::focusChanged, this, &ICorePrivate::updateFocusWidget);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Add small Toolbuttons for toggling the navigation widgets
|
|
|
|
|
StatusBarManager::addStatusBarWidget(m_toggleLeftSideBarButton, StatusBarManager::First);
|
2023-10-04 10:13:36 +02:00
|
|
|
int childsCount = m_modeStack->statusBar()
|
|
|
|
|
->findChildren<QWidget *>(QString(), Qt::FindDirectChildrenOnly)
|
|
|
|
|
.count();
|
|
|
|
|
m_modeStack->statusBar()->insertPermanentWidget(childsCount - 1,
|
|
|
|
|
m_toggleRightSideBarButton); // before QSizeGrip
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2023-10-04 10:13:36 +02:00
|
|
|
// setUnifiedTitleAndToolBarOnMac(true);
|
2023-09-15 12:58:44 +02:00
|
|
|
//if (HostOsInfo::isAnyUnixHost())
|
2023-10-04 10:13:36 +02:00
|
|
|
//signal(SIGINT, handleSigInt);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2023-10-04 10:13:36 +02:00
|
|
|
m_modeStack->statusBar()->setProperty("p_styled", true);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2023-11-28 13:43:09 +01:00
|
|
|
auto dropSupport = new DropSupport(m_mainwindow, [](QDropEvent *event, DropSupport *) {
|
2023-09-15 12:58:44 +02:00
|
|
|
return event->source() == nullptr; // only accept drops from the "outside" (e.g. file manager)
|
|
|
|
|
});
|
2023-11-28 13:43:09 +01:00
|
|
|
connect(dropSupport, &DropSupport::filesDropped, this, &ICorePrivate::openDroppedFiles);
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
if (HostOsInfo::isLinuxHost()) {
|
|
|
|
|
m_trimTimer.setSingleShot(true);
|
|
|
|
|
m_trimTimer.setInterval(60000);
|
|
|
|
|
// glibc may not actually free memory in free().
|
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
|
connect(&m_trimTimer, &QTimer::timeout, this, [] { malloc_trim(0); });
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
NavigationWidget *ICorePrivate::navigationWidget(Side side) const
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
return side == Side::Left ? m_leftNavigationWidget : m_rightNavigationWidget;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::setSidebarVisible(bool visible, Side side)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
Use sidebar buttons for hiding/showing dock areas
So far, if a mode includes navigation widget placeholders, these are
used for the sidebar toggle buttons, otherwise the buttons are disabled.
Now, if a mode does not include navigation widget placeholders, but the
mode has a FancyMainWindow attached, use the buttons to hide or show the
corresponding dock widget area (left or right).
Since QMainWindow does not really support "hiding a dock widget area",
the FancyMainWindow needs to track that state manually, by tracking the
dock widgets that were visible before "hiding the dock widget area".
Also, if a dock widget is dragged into a "hidden" area, or a widget is
made visible or "unfloated" into that area, show the other widgets in the
area again as well, "unhiding" the area.
Since the mode widgets that have a mainwindow somewhere usually wrap
that into a splitter for the output panes, and the Design mode is
actually a stack widget, IMode needs another method that returns the
appropriate FancyMainWindow if available.
The patch implements this for Widget Designer.
Change-Id: I03531f4d5130c846ff5d65831b1c9be210e1c561
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
2023-11-24 09:26:31 +01:00
|
|
|
navigationWidget(side)->setShown(visible);
|
2023-09-15 12:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
ICorePrivate::~ICorePrivate()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
// explicitly delete window support, because that calls methods from ICore that call methods
|
|
|
|
|
// from mainwindow, so mainwindow still needs to be alive
|
|
|
|
|
delete m_windowSupport;
|
|
|
|
|
m_windowSupport = nullptr;
|
|
|
|
|
|
|
|
|
|
delete m_externalToolManager;
|
|
|
|
|
m_externalToolManager = nullptr;
|
|
|
|
|
delete m_messageManager;
|
|
|
|
|
m_messageManager = nullptr;
|
|
|
|
|
delete m_shortcutSettings;
|
|
|
|
|
m_shortcutSettings = nullptr;
|
|
|
|
|
delete m_toolSettings;
|
|
|
|
|
m_toolSettings = nullptr;
|
|
|
|
|
delete m_mimeTypeSettings;
|
|
|
|
|
m_mimeTypeSettings = nullptr;
|
|
|
|
|
delete m_systemEditor;
|
|
|
|
|
m_systemEditor = nullptr;
|
|
|
|
|
delete m_printer;
|
|
|
|
|
m_printer = nullptr;
|
|
|
|
|
delete m_vcsManager;
|
|
|
|
|
m_vcsManager = nullptr;
|
|
|
|
|
//we need to delete editormanager and statusbarmanager explicitly before the end of the destructor,
|
|
|
|
|
//because they might trigger stuff that tries to access data from editorwindow, like removeContextWidget
|
|
|
|
|
|
|
|
|
|
// All modes are now gone
|
|
|
|
|
OutputPaneManager::destroy();
|
|
|
|
|
|
|
|
|
|
delete m_leftNavigationWidget;
|
|
|
|
|
delete m_rightNavigationWidget;
|
|
|
|
|
m_leftNavigationWidget = nullptr;
|
|
|
|
|
m_rightNavigationWidget = nullptr;
|
|
|
|
|
|
|
|
|
|
delete m_editorManager;
|
|
|
|
|
m_editorManager = nullptr;
|
|
|
|
|
delete m_progressManager;
|
|
|
|
|
m_progressManager = nullptr;
|
|
|
|
|
|
|
|
|
|
delete m_rightPaneWidget;
|
|
|
|
|
m_rightPaneWidget = nullptr;
|
|
|
|
|
|
|
|
|
|
delete m_modeManager;
|
|
|
|
|
m_modeManager = nullptr;
|
|
|
|
|
|
|
|
|
|
delete m_jsExpander;
|
|
|
|
|
m_jsExpander = nullptr;
|
2023-10-02 17:27:26 +02:00
|
|
|
|
|
|
|
|
delete m_mainwindow;
|
|
|
|
|
m_mainwindow = nullptr;
|
2023-09-15 12:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-15 14:53:59 +02:00
|
|
|
} // Internal
|
|
|
|
|
|
|
|
|
|
void ICore::extensionsInitialized()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
EditorManagerPrivate::extensionsInitialized();
|
|
|
|
|
MimeTypeSettings::restoreSettings();
|
2023-10-02 17:27:26 +02:00
|
|
|
d->m_windowSupport = new WindowSupport(d->m_mainwindow, Context("Core.MainWindow"));
|
2023-09-15 12:58:44 +02:00
|
|
|
d->m_windowSupport->setCloseActionEnabled(false);
|
|
|
|
|
OutputPaneManager::initialize();
|
|
|
|
|
VcsManager::extensionsInitialized();
|
|
|
|
|
d->m_leftNavigationWidget->setFactories(INavigationWidgetFactory::allNavigationFactories());
|
|
|
|
|
d->m_rightNavigationWidget->setFactories(INavigationWidgetFactory::allNavigationFactories());
|
|
|
|
|
|
|
|
|
|
ModeManager::extensionsInitialized();
|
|
|
|
|
|
|
|
|
|
d->readSettings();
|
|
|
|
|
d->updateContext();
|
|
|
|
|
|
|
|
|
|
emit m_core->coreAboutToOpen();
|
|
|
|
|
// Delay restoreWindowState, since it is overridden by LayoutRequest event
|
2023-10-02 16:24:02 +02:00
|
|
|
QMetaObject::invokeMethod(d, &ICorePrivate::restoreWindowState, Qt::QueuedConnection);
|
2023-09-15 12:58:44 +02:00
|
|
|
QMetaObject::invokeMethod(m_core, &ICore::coreOpened, Qt::QueuedConnection);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 14:53:59 +02:00
|
|
|
void ICore::aboutToShutdown()
|
|
|
|
|
{
|
2023-10-02 16:24:02 +02:00
|
|
|
disconnect(qApp, &QApplication::focusChanged, d, &ICorePrivate::updateFocusWidget);
|
2023-09-15 14:53:59 +02:00
|
|
|
for (auto contextPair : d->m_contextWidgets)
|
2023-10-02 17:27:26 +02:00
|
|
|
disconnect(contextPair.second, &QObject::destroyed, d->m_mainwindow, nullptr);
|
2023-09-15 14:53:59 +02:00
|
|
|
d->m_activeContext.clear();
|
2023-10-02 17:27:26 +02:00
|
|
|
d->m_mainwindow->hide();
|
2023-09-15 14:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
void ICore::restartTrimmer()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
if (HostOsInfo::isLinuxHost() && !d->m_trimTimer.isActive())
|
|
|
|
|
d->m_trimTimer.start();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
|
|
|
{
|
|
|
|
|
const auto cancelClose = [event] {
|
|
|
|
|
event->ignore();
|
|
|
|
|
setRestart(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// work around QTBUG-43344
|
|
|
|
|
static bool alreadyClosed = false;
|
|
|
|
|
if (alreadyClosed) {
|
|
|
|
|
event->accept();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (systemSettings().askBeforeExit()
|
|
|
|
|
&& (QMessageBox::question(this,
|
|
|
|
|
Tr::tr("Exit %1?").arg(QGuiApplication::applicationDisplayName()),
|
|
|
|
|
Tr::tr("Exit %1?").arg(QGuiApplication::applicationDisplayName()),
|
|
|
|
|
QMessageBox::Yes | QMessageBox::No,
|
|
|
|
|
QMessageBox::No)
|
|
|
|
|
== QMessageBox::No)) {
|
|
|
|
|
event->ignore();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICore::saveSettings(ICore::MainWindowClosing);
|
|
|
|
|
|
|
|
|
|
// Save opened files
|
|
|
|
|
if (!DocumentManager::saveAllModifiedDocuments()) {
|
|
|
|
|
cancelClose();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QList<std::function<bool()>> listeners = d->m_preCloseListeners;
|
|
|
|
|
for (const std::function<bool()> &listener : listeners) {
|
|
|
|
|
if (!listener()) {
|
|
|
|
|
cancelClose();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit m_core->coreAboutToClose();
|
|
|
|
|
|
|
|
|
|
d->saveWindowSettings();
|
|
|
|
|
|
|
|
|
|
d->m_leftNavigationWidget->closeSubWidgets();
|
|
|
|
|
d->m_rightNavigationWidget->closeSubWidgets();
|
|
|
|
|
|
|
|
|
|
event->accept();
|
|
|
|
|
alreadyClosed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::keyPressEvent(QKeyEvent *event)
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
ICore::restartTrimmer();
|
2023-09-15 12:58:44 +02:00
|
|
|
AppMainWindow::keyPressEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MainWindow::mousePressEvent(QMouseEvent *event)
|
|
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
ICore::restartTrimmer();
|
2023-09-15 12:58:44 +02:00
|
|
|
AppMainWindow::mousePressEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::openDroppedFiles(const QList<DropSupport::FileSpec> &files)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
2023-10-02 17:27:26 +02:00
|
|
|
m_mainwindow->raiseWindow();
|
2023-09-15 12:58:44 +02:00
|
|
|
const FilePaths filePaths = Utils::transform(files, &DropSupport::FileSpec::filePath);
|
2023-09-15 16:47:37 +02:00
|
|
|
ICore::openFiles(filePaths, ICore::SwitchMode);
|
2023-09-15 12:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::registerDefaultContainers()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
ActionContainer *menubar = ActionManager::createMenuBar(Constants::MENU_BAR);
|
|
|
|
|
|
|
|
|
|
if (!HostOsInfo::isMacHost()) // System menu bar on Mac
|
2023-10-02 17:27:26 +02:00
|
|
|
m_mainwindow->setMenuBar(menubar->menuBar());
|
2023-09-15 12:58:44 +02:00
|
|
|
menubar->appendGroup(Constants::G_FILE);
|
|
|
|
|
menubar->appendGroup(Constants::G_EDIT);
|
|
|
|
|
menubar->appendGroup(Constants::G_VIEW);
|
|
|
|
|
menubar->appendGroup(Constants::G_TOOLS);
|
|
|
|
|
menubar->appendGroup(Constants::G_WINDOW);
|
|
|
|
|
menubar->appendGroup(Constants::G_HELP);
|
|
|
|
|
|
|
|
|
|
// File Menu
|
|
|
|
|
ActionContainer *filemenu = ActionManager::createMenu(Constants::M_FILE);
|
|
|
|
|
menubar->addMenu(filemenu, Constants::G_FILE);
|
|
|
|
|
filemenu->menu()->setTitle(Tr::tr("&File"));
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_NEW);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_OPEN);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_SESSION);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_PROJECT);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_SAVE);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_EXPORT);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_CLOSE);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_PRINT);
|
|
|
|
|
filemenu->appendGroup(Constants::G_FILE_OTHER);
|
2023-10-02 16:24:02 +02:00
|
|
|
connect(filemenu->menu(), &QMenu::aboutToShow, this, &ICorePrivate::aboutToShowRecentFiles);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Edit Menu
|
|
|
|
|
ActionContainer *medit = ActionManager::createMenu(Constants::M_EDIT);
|
|
|
|
|
menubar->addMenu(medit, Constants::G_EDIT);
|
|
|
|
|
medit->menu()->setTitle(Tr::tr("&Edit"));
|
|
|
|
|
medit->appendGroup(Constants::G_EDIT_UNDOREDO);
|
|
|
|
|
medit->appendGroup(Constants::G_EDIT_COPYPASTE);
|
|
|
|
|
medit->appendGroup(Constants::G_EDIT_SELECTALL);
|
|
|
|
|
medit->appendGroup(Constants::G_EDIT_ADVANCED);
|
|
|
|
|
medit->appendGroup(Constants::G_EDIT_FIND);
|
|
|
|
|
medit->appendGroup(Constants::G_EDIT_OTHER);
|
|
|
|
|
|
|
|
|
|
ActionContainer *mview = ActionManager::createMenu(Constants::M_VIEW);
|
|
|
|
|
menubar->addMenu(mview, Constants::G_VIEW);
|
|
|
|
|
mview->menu()->setTitle(Tr::tr("&View"));
|
|
|
|
|
mview->appendGroup(Constants::G_VIEW_VIEWS);
|
|
|
|
|
mview->appendGroup(Constants::G_VIEW_PANES);
|
|
|
|
|
|
|
|
|
|
// Tools Menu
|
|
|
|
|
ActionContainer *ac = ActionManager::createMenu(Constants::M_TOOLS);
|
|
|
|
|
ac->setParent(this);
|
|
|
|
|
if (!hideToolsMenu())
|
|
|
|
|
menubar->addMenu(ac, Constants::G_TOOLS);
|
|
|
|
|
|
|
|
|
|
ac->menu()->setTitle(Tr::tr("&Tools"));
|
|
|
|
|
|
|
|
|
|
// Window Menu
|
|
|
|
|
ActionContainer *mwindow = ActionManager::createMenu(Constants::M_WINDOW);
|
|
|
|
|
menubar->addMenu(mwindow, Constants::G_WINDOW);
|
|
|
|
|
mwindow->menu()->setTitle(Tr::tr("&Window"));
|
|
|
|
|
mwindow->appendGroup(Constants::G_WINDOW_SIZE);
|
|
|
|
|
mwindow->appendGroup(Constants::G_WINDOW_SPLIT);
|
|
|
|
|
mwindow->appendGroup(Constants::G_WINDOW_NAVIGATE);
|
|
|
|
|
mwindow->appendGroup(Constants::G_WINDOW_LIST);
|
|
|
|
|
mwindow->appendGroup(Constants::G_WINDOW_OTHER);
|
|
|
|
|
|
|
|
|
|
// Help Menu
|
|
|
|
|
ac = ActionManager::createMenu(Constants::M_HELP);
|
|
|
|
|
menubar->addMenu(ac, Constants::G_HELP);
|
|
|
|
|
ac->menu()->setTitle(Tr::tr("&Help"));
|
|
|
|
|
Theme::setHelpMenu(ac->menu());
|
|
|
|
|
ac->appendGroup(Constants::G_HELP_HELP);
|
|
|
|
|
ac->appendGroup(Constants::G_HELP_SUPPORT);
|
|
|
|
|
ac->appendGroup(Constants::G_HELP_ABOUT);
|
|
|
|
|
ac->appendGroup(Constants::G_HELP_UPDATES);
|
|
|
|
|
|
|
|
|
|
// macOS touch bar
|
|
|
|
|
ac = ActionManager::createTouchBar(Constants::TOUCH_BAR,
|
|
|
|
|
QIcon(),
|
|
|
|
|
"Main TouchBar" /*never visible*/);
|
|
|
|
|
ac->appendGroup(Constants::G_TOUCHBAR_HELP);
|
|
|
|
|
ac->appendGroup(Constants::G_TOUCHBAR_NAVIGATION);
|
|
|
|
|
ac->appendGroup(Constants::G_TOUCHBAR_EDITOR);
|
|
|
|
|
ac->appendGroup(Constants::G_TOUCHBAR_OTHER);
|
|
|
|
|
ac->touchBar()->setApplicationTouchBar();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::registerDefaultActions()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
ActionContainer *mfile = ActionManager::actionContainer(Constants::M_FILE);
|
|
|
|
|
ActionContainer *medit = ActionManager::actionContainer(Constants::M_EDIT);
|
|
|
|
|
ActionContainer *mview = ActionManager::actionContainer(Constants::M_VIEW);
|
|
|
|
|
ActionContainer *mtools = ActionManager::actionContainer(Constants::M_TOOLS);
|
|
|
|
|
ActionContainer *mwindow = ActionManager::actionContainer(Constants::M_WINDOW);
|
|
|
|
|
ActionContainer *mhelp = ActionManager::actionContainer(Constants::M_HELP);
|
|
|
|
|
|
|
|
|
|
// File menu separators
|
|
|
|
|
mfile->addSeparator(Constants::G_FILE_SAVE);
|
|
|
|
|
mfile->addSeparator(Constants::G_FILE_EXPORT);
|
|
|
|
|
mfile->addSeparator(Constants::G_FILE_PRINT);
|
|
|
|
|
mfile->addSeparator(Constants::G_FILE_CLOSE);
|
|
|
|
|
mfile->addSeparator(Constants::G_FILE_OTHER);
|
|
|
|
|
// Edit menu separators
|
|
|
|
|
medit->addSeparator(Constants::G_EDIT_COPYPASTE);
|
|
|
|
|
medit->addSeparator(Constants::G_EDIT_SELECTALL);
|
|
|
|
|
medit->addSeparator(Constants::G_EDIT_FIND);
|
|
|
|
|
medit->addSeparator(Constants::G_EDIT_ADVANCED);
|
|
|
|
|
|
|
|
|
|
// Return to editor shortcut: Note this requires Qt to fix up
|
|
|
|
|
// handling of shortcut overrides in menus, item views, combos....
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder focusToEditor(this, Constants::S_RETURNTOEDITOR);
|
|
|
|
|
focusToEditor.setText(Tr::tr("Return to Editor"));
|
|
|
|
|
focusToEditor.setDefaultKeySequence(QKeySequence(Qt::Key_Escape));
|
2023-12-13 12:29:46 +01:00
|
|
|
focusToEditor.addOnTriggered(this, [] { setFocusToEditor(); });
|
2023-11-09 10:51:53 +01:00
|
|
|
|
|
|
|
|
// New Project Action
|
|
|
|
|
ActionBuilder newProjectAction(this, Constants::NEW);
|
|
|
|
|
newProjectAction.setText(Tr::tr("&New Project..."));
|
|
|
|
|
newProjectAction.setIcon(Icon::fromTheme("document-new"));
|
|
|
|
|
newProjectAction.setDefaultKeySequence(QKeySequence("Ctrl+Shift+N"));
|
2023-12-13 09:02:02 +01:00
|
|
|
newProjectAction.addToContainer(Constants::M_FILE, Constants::G_FILE_NEW);
|
2023-12-13 12:29:46 +01:00
|
|
|
newProjectAction.addOnTriggered(this, [] {
|
2023-09-15 12:58:44 +02:00
|
|
|
if (!ICore::isNewItemDialogRunning()) {
|
|
|
|
|
ICore::showNewItemDialog(
|
|
|
|
|
Tr::tr("New Project", "Title of dialog"),
|
|
|
|
|
Utils::filtered(Core::IWizardFactory::allWizardFactories(),
|
|
|
|
|
Utils::equal(&Core::IWizardFactory::kind,
|
|
|
|
|
Core::IWizardFactory::ProjectWizard)),
|
|
|
|
|
FilePath());
|
|
|
|
|
} else {
|
|
|
|
|
ICore::raiseWindow(ICore::newItemDialog());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2023-11-09 10:51:53 +01:00
|
|
|
// New File Action
|
|
|
|
|
ActionBuilder newFileAction(this, Constants::NEW_FILE);
|
|
|
|
|
newFileAction.setText(Tr::tr("New File..."));
|
|
|
|
|
newFileAction.setIcon(Icon::fromTheme("document-new"));
|
|
|
|
|
newFileAction.setDefaultKeySequence(QKeySequence::New);
|
2023-12-13 09:02:02 +01:00
|
|
|
newFileAction.addToContainer(Constants::M_FILE, Constants::G_FILE_NEW);
|
2023-12-13 12:29:46 +01:00
|
|
|
newFileAction.addOnTriggered(this, [] {
|
2023-09-15 12:58:44 +02:00
|
|
|
if (!ICore::isNewItemDialogRunning()) {
|
2023-11-09 10:51:53 +01:00
|
|
|
ICore::showNewItemDialog(
|
|
|
|
|
Tr::tr("New File", "Title of dialog"),
|
|
|
|
|
Utils::filtered(Core::IWizardFactory::allWizardFactories(),
|
|
|
|
|
Utils::equal(&Core::IWizardFactory::kind,
|
|
|
|
|
Core::IWizardFactory::FileWizard)),
|
|
|
|
|
FilePath());
|
2023-09-15 12:58:44 +02:00
|
|
|
} else {
|
|
|
|
|
ICore::raiseWindow(ICore::newItemDialog());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Open Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder openAction(this, Constants::OPEN);
|
|
|
|
|
openAction.setText(Tr::tr("&Open File or Project..."));
|
|
|
|
|
openAction.setIcon(Icon::fromTheme("document-open"));
|
|
|
|
|
openAction.setDefaultKeySequence(QKeySequence::Open);
|
2023-12-13 09:02:02 +01:00
|
|
|
openAction.addToContainer(Constants::M_FILE, Constants::G_FILE_OPEN);
|
2023-12-13 12:29:46 +01:00
|
|
|
openAction.addOnTriggered(this, [] { openFile(); });
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Open With Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder openWithAction(this, Constants::OPEN_WITH);
|
|
|
|
|
openWithAction.setText(Tr::tr("Open File &With..."));
|
2023-12-13 09:02:02 +01:00
|
|
|
openWithAction.addToContainer(Constants::M_FILE, Constants::G_FILE_OPEN);
|
2023-12-13 12:29:46 +01:00
|
|
|
openWithAction.addOnTriggered(this, &ICore::openFileWith);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
if (FSEngine::isAvailable()) {
|
|
|
|
|
// Open From Device Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder openFromDeviceAction(this, Constants::OPEN_FROM_DEVICE);
|
|
|
|
|
openFromDeviceAction.setText(Tr::tr("Open From Device..."));
|
2023-12-13 09:02:02 +01:00
|
|
|
openFromDeviceAction.addToContainer(Constants::M_FILE, Constants::G_FILE_OPEN);
|
2023-12-13 12:29:46 +01:00
|
|
|
openFromDeviceAction.addOnTriggered(this, [this] { openFileFromDevice(); });
|
2023-09-15 12:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// File->Recent Files Menu
|
|
|
|
|
ActionContainer *ac = ActionManager::createMenu(Constants::M_FILE_RECENTFILES);
|
|
|
|
|
mfile->addMenu(ac, Constants::G_FILE_OPEN);
|
|
|
|
|
ac->menu()->setTitle(Tr::tr("Recent &Files"));
|
|
|
|
|
ac->setOnAllDisabledBehavior(ActionContainer::Show);
|
|
|
|
|
|
|
|
|
|
// Save Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder saveAction(this, Constants::SAVE);
|
|
|
|
|
saveAction.setText(Tr::tr("&Save"));
|
|
|
|
|
saveAction.setIcon(Icon::fromTheme("document-save"));
|
|
|
|
|
saveAction.setEnabled(false);
|
|
|
|
|
saveAction.setDefaultKeySequence(QKeySequence::Save);
|
|
|
|
|
saveAction.setCommandAttribute(Command::CA_UpdateText);
|
|
|
|
|
saveAction.setCommandDescription(Tr::tr("Save"));
|
2023-12-13 09:02:02 +01:00
|
|
|
saveAction.addToContainer(Constants::M_FILE, Constants::G_FILE_SAVE);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Save As Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder saveAsAction(this, Constants::SAVEAS);
|
|
|
|
|
saveAsAction.setText(Tr::tr("Save &As..."));
|
|
|
|
|
saveAsAction.setIcon(Icon::fromTheme("document-save-as"));
|
|
|
|
|
saveAsAction.setEnabled(false);
|
|
|
|
|
saveAsAction.setDefaultKeySequence(Tr::tr("Ctrl+Shift+S"), QString());
|
|
|
|
|
saveAsAction.setCommandAttribute(Command::CA_UpdateText);
|
|
|
|
|
saveAsAction.setCommandDescription(Tr::tr("Save As..."));
|
2023-12-13 09:02:02 +01:00
|
|
|
saveAsAction.addToContainer(Constants::M_FILE, Constants::G_FILE_SAVE);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// SaveAll Action
|
|
|
|
|
DocumentManager::registerSaveAllAction();
|
|
|
|
|
|
|
|
|
|
// Print Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder printAction(this, Constants::PRINT);
|
|
|
|
|
printAction.setText(Tr::tr("&Print..."));
|
|
|
|
|
printAction.setIcon(Icon::fromTheme("document-print"));
|
|
|
|
|
printAction.setEnabled(false);
|
|
|
|
|
printAction.setDefaultKeySequence(QKeySequence::Print);
|
2023-12-13 09:02:02 +01:00
|
|
|
printAction.addToContainer(Constants::M_FILE, Constants::G_FILE_PRINT);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Exit Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder exitAction(this, Constants::EXIT);
|
|
|
|
|
exitAction.setText(Tr::tr("E&xit"));
|
|
|
|
|
exitAction.setIcon(Icon::fromTheme("application-exit"));
|
|
|
|
|
exitAction.setMenuRole(QAction::QuitRole);
|
|
|
|
|
exitAction.setDefaultKeySequence(Tr::tr("Ctrl+Q"));
|
2023-12-13 09:02:02 +01:00
|
|
|
exitAction.addToContainer(Constants::M_FILE, Constants::G_FILE_OTHER);
|
2023-12-13 12:29:46 +01:00
|
|
|
exitAction.addOnTriggered(this, &ICore::exit);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Undo Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder undoAction(this, Constants::UNDO);
|
|
|
|
|
undoAction.setText(Tr::tr("&Undo"));
|
|
|
|
|
undoAction.setIcon(Icon::fromTheme("edit-undo"));
|
|
|
|
|
undoAction.setDefaultKeySequence(QKeySequence::Undo);
|
|
|
|
|
undoAction.setCommandAttribute(Command::CA_UpdateText);
|
|
|
|
|
undoAction.setCommandDescription(Tr::tr("Undo"));
|
2023-12-13 09:02:02 +01:00
|
|
|
undoAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_UNDOREDO);
|
2023-11-09 10:51:53 +01:00
|
|
|
undoAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Redo Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder redoAction(this, Constants::REDO);
|
|
|
|
|
redoAction.setIcon(Icon::fromTheme("edit-redo"));
|
|
|
|
|
redoAction.setText(Tr::tr("&Redo"));
|
|
|
|
|
redoAction.setDefaultKeySequence(QKeySequence::Redo);
|
|
|
|
|
redoAction.setCommandAttribute(Command::CA_UpdateText);
|
|
|
|
|
redoAction.setCommandDescription(Tr::tr("Redo"));
|
2023-12-13 09:02:02 +01:00
|
|
|
redoAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_UNDOREDO);
|
2023-11-09 10:51:53 +01:00
|
|
|
redoAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Cut Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder cutAction(this, Constants::CUT);
|
|
|
|
|
cutAction.setText(Tr::tr("Cu&t"));
|
|
|
|
|
cutAction.setIcon(Icon::fromTheme("edit-cut"));
|
|
|
|
|
cutAction.setDefaultKeySequence(QKeySequence::Cut);
|
2023-12-13 09:02:02 +01:00
|
|
|
cutAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_COPYPASTE);
|
2023-11-09 10:51:53 +01:00
|
|
|
cutAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Copy Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder copyAction(this, Constants::COPY);
|
|
|
|
|
copyAction.setText(Tr::tr("&Copy"));
|
|
|
|
|
copyAction.setIcon(Icon::fromTheme("edit-copy"));
|
|
|
|
|
copyAction.setDefaultKeySequence(QKeySequence::Copy);
|
2023-12-13 09:02:02 +01:00
|
|
|
copyAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_COPYPASTE);
|
2023-11-09 10:51:53 +01:00
|
|
|
copyAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Paste Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder pasteAction(this, Constants::PASTE);
|
|
|
|
|
pasteAction.setText(Tr::tr("&Paste"));
|
|
|
|
|
pasteAction.setIcon(Icon::fromTheme("edit-paste"));
|
|
|
|
|
pasteAction.setDefaultKeySequence(QKeySequence::Paste);
|
2023-12-13 09:02:02 +01:00
|
|
|
pasteAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_COPYPASTE);
|
2023-11-09 10:51:53 +01:00
|
|
|
pasteAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Select All
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder selectAllAction(this, Constants::SELECTALL);
|
|
|
|
|
selectAllAction.setText(Tr::tr("Select &All"));
|
|
|
|
|
selectAllAction.setIcon(Icon::fromTheme("edit-select-all"));
|
|
|
|
|
selectAllAction.setDefaultKeySequence(QKeySequence::SelectAll);
|
2023-12-13 09:02:02 +01:00
|
|
|
selectAllAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_SELECTALL);
|
2023-11-09 10:51:53 +01:00
|
|
|
selectAllAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Goto Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder gotoLineAction(this, Constants::GOTO);
|
|
|
|
|
gotoLineAction.setText(Tr::tr("&Go to Line..."));
|
|
|
|
|
gotoLineAction.setIcon(Icon::fromTheme("go-jump"));
|
|
|
|
|
gotoLineAction.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+L")));
|
2023-12-13 09:02:02 +01:00
|
|
|
gotoLineAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_OTHER);
|
2023-11-09 10:51:53 +01:00
|
|
|
gotoLineAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Zoom In Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder zoomInAction(this, Constants::ZOOM_IN);
|
|
|
|
|
zoomInAction.setText(Tr::tr("Zoom In"));
|
|
|
|
|
zoomInAction.setIcon(Icon::fromTheme("zoom-in"));
|
|
|
|
|
zoomInAction.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl++")));
|
|
|
|
|
zoomInAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Zoom Out Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder zoomOutAction(this, Constants::ZOOM_OUT);
|
|
|
|
|
zoomOutAction.setText(Tr::tr("Zoom Out"));
|
|
|
|
|
zoomOutAction.setIcon(Icon::fromTheme("zoom-out"));
|
2023-09-15 12:58:44 +02:00
|
|
|
if (useMacShortcuts)
|
2023-11-09 10:51:53 +01:00
|
|
|
zoomOutAction.setDefaultKeySequences({QKeySequence(Tr::tr("Ctrl+-")), QKeySequence(Tr::tr("Ctrl+Shift+-"))});
|
2023-09-15 12:58:44 +02:00
|
|
|
else
|
2023-11-09 10:51:53 +01:00
|
|
|
zoomOutAction.setDefaultKeySequence(Tr::tr("Ctrl+-"));
|
|
|
|
|
zoomOutAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Zoom Reset Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder zoomOriginalAction(this, Constants::ZOOM_RESET);
|
|
|
|
|
zoomOriginalAction.setText(Tr::tr("Original Size"));
|
|
|
|
|
zoomOriginalAction.setIcon(Icon::fromTheme("zoom-original"));
|
|
|
|
|
zoomOriginalAction.setDefaultKeySequence(Tr::tr("Meta+0"), Tr::tr("Ctrl+0"));
|
|
|
|
|
zoomOriginalAction.setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Debug Qt Creator menu
|
|
|
|
|
mtools->appendGroup(Constants::G_TOOLS_DEBUG);
|
|
|
|
|
ActionContainer *mtoolsdebug = ActionManager::createMenu(Constants::M_TOOLS_DEBUG);
|
|
|
|
|
mtoolsdebug->menu()->setTitle(Tr::tr("Debug %1").arg(QGuiApplication::applicationDisplayName()));
|
|
|
|
|
mtools->addMenu(mtoolsdebug, Constants::G_TOOLS_DEBUG);
|
|
|
|
|
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder loggerAction(this, Constants::LOGGER);
|
|
|
|
|
loggerAction.setText(Tr::tr("Show Logs..."));
|
2023-12-13 09:02:02 +01:00
|
|
|
loggerAction.addToContainer(Constants::M_TOOLS_DEBUG);
|
2023-12-13 12:29:46 +01:00
|
|
|
loggerAction.addOnTriggered(this, &LoggingViewer::showLoggingView);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Options Action
|
|
|
|
|
medit->appendGroup(Constants::G_EDIT_PREFERENCES);
|
|
|
|
|
medit->addSeparator(Constants::G_EDIT_PREFERENCES);
|
|
|
|
|
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder optionsAction(this, Constants::OPTIONS);
|
|
|
|
|
optionsAction.setText(Tr::tr("Pr&eferences..."));
|
|
|
|
|
optionsAction.setMenuRole(QAction::PreferencesRole);
|
|
|
|
|
optionsAction.setDefaultKeySequence(QKeySequence::Preferences);
|
2023-12-13 09:02:02 +01:00
|
|
|
optionsAction.addToContainer(Constants::M_EDIT, Constants::G_EDIT_PREFERENCES);
|
2023-12-13 12:29:46 +01:00
|
|
|
optionsAction.addOnTriggered(this, [] { ICore::showOptionsDialog(Id()); });
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
mwindow->addSeparator(Constants::G_WINDOW_LIST);
|
|
|
|
|
|
|
|
|
|
if (useMacShortcuts) {
|
|
|
|
|
// Minimize Action
|
|
|
|
|
QAction *minimizeAction = new QAction(Tr::tr("Minimize"), this);
|
|
|
|
|
minimizeAction->setEnabled(false); // actual implementation in WindowSupport
|
2023-11-09 10:51:53 +01:00
|
|
|
Command *cmd = ActionManager::registerAction(minimizeAction, Constants::MINIMIZE_WINDOW);
|
2023-09-15 12:58:44 +02:00
|
|
|
cmd->setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+M")));
|
|
|
|
|
mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
|
|
|
|
|
|
|
|
|
|
// Zoom Action
|
|
|
|
|
QAction *zoomAction = new QAction(Tr::tr("Zoom"), this);
|
|
|
|
|
zoomAction->setEnabled(false); // actual implementation in WindowSupport
|
|
|
|
|
cmd = ActionManager::registerAction(zoomAction, Constants::ZOOM_WINDOW);
|
|
|
|
|
mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Full Screen Action
|
|
|
|
|
QAction *toggleFullScreenAction = new QAction(Tr::tr("Full Screen"), this);
|
|
|
|
|
toggleFullScreenAction->setCheckable(!HostOsInfo::isMacHost());
|
|
|
|
|
toggleFullScreenAction->setEnabled(false); // actual implementation in WindowSupport
|
2023-11-09 10:51:53 +01:00
|
|
|
Command *cmd = ActionManager::registerAction(toggleFullScreenAction, Constants::TOGGLE_FULLSCREEN);
|
2023-09-15 12:58:44 +02:00
|
|
|
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Ctrl+Meta+F") : Tr::tr("Ctrl+Shift+F11")));
|
|
|
|
|
if (HostOsInfo::isMacHost())
|
|
|
|
|
cmd->setAttribute(Command::CA_UpdateText);
|
|
|
|
|
mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
|
|
|
|
|
|
|
|
|
|
if (useMacShortcuts) {
|
|
|
|
|
mwindow->addSeparator(Constants::G_WINDOW_SIZE);
|
|
|
|
|
|
|
|
|
|
QAction *closeAction = new QAction(Tr::tr("Close Window"), this);
|
|
|
|
|
closeAction->setEnabled(false);
|
|
|
|
|
cmd = ActionManager::registerAction(closeAction, Constants::CLOSE_WINDOW);
|
|
|
|
|
cmd->setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Meta+W")));
|
|
|
|
|
mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
|
|
|
|
|
|
|
|
|
|
mwindow->addSeparator(Constants::G_WINDOW_SIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Show Left Sidebar Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder toggleLeftSideBarAction(this, Constants::TOGGLE_LEFT_SIDEBAR);
|
|
|
|
|
toggleLeftSideBarAction.setIcon(Utils::Icons::TOGGLE_LEFT_SIDEBAR.icon());
|
|
|
|
|
toggleLeftSideBarAction.setText(Tr::tr(Constants::TR_SHOW_LEFT_SIDEBAR));
|
|
|
|
|
toggleLeftSideBarAction.setCheckable(true);
|
|
|
|
|
toggleLeftSideBarAction.setCommandAttribute(Command::CA_UpdateText);
|
|
|
|
|
toggleLeftSideBarAction.setDefaultKeySequence(Tr::tr("Ctrl+0"), Tr::tr("Alt+0"));
|
2023-12-13 09:02:02 +01:00
|
|
|
toggleLeftSideBarAction.addToContainer(Constants::M_VIEW, Constants::G_VIEW_VIEWS);
|
2023-12-13 12:29:46 +01:00
|
|
|
toggleLeftSideBarAction.addOnTriggered(this,
|
2023-11-09 10:51:53 +01:00
|
|
|
[this](bool visible) { setSidebarVisible(visible, Side::Left); });
|
|
|
|
|
|
|
|
|
|
m_toggleLeftSideBarAction = toggleLeftSideBarAction.contextAction();
|
|
|
|
|
m_toggleLeftSideBarButton->setDefaultAction(ProxyAction::proxyActionWithIcon(
|
|
|
|
|
toggleLeftSideBarAction.commandAction(), Utils::Icons::TOGGLE_LEFT_SIDEBAR_TOOLBAR.icon()));
|
|
|
|
|
m_toggleLeftSideBarButton->setEnabled(false);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Show Right Sidebar Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder toggleRightSideBarAction(this, Constants::TOGGLE_RIGHT_SIDEBAR);
|
|
|
|
|
toggleRightSideBarAction.setIcon(Utils::Icons::TOGGLE_RIGHT_SIDEBAR.icon());
|
|
|
|
|
toggleRightSideBarAction.setText(Tr::tr(Constants::TR_SHOW_RIGHT_SIDEBAR));
|
|
|
|
|
toggleRightSideBarAction.setCheckable(true);
|
|
|
|
|
toggleRightSideBarAction.setCommandAttribute(Command::CA_UpdateText);
|
|
|
|
|
toggleRightSideBarAction.setDefaultKeySequence(Tr::tr("Ctrl+Shift+0"), Tr::tr("Alt+Shift+0"));
|
2023-12-13 09:02:02 +01:00
|
|
|
toggleRightSideBarAction.addToContainer(Constants::M_VIEW, Constants::G_VIEW_VIEWS);
|
2023-11-09 10:51:53 +01:00
|
|
|
toggleRightSideBarAction.setEnabled(false);
|
2023-12-13 12:29:46 +01:00
|
|
|
toggleRightSideBarAction.addOnTriggered(this,
|
2023-11-09 10:51:53 +01:00
|
|
|
[this](bool visible) { setSidebarVisible(visible, Side::Right); });
|
|
|
|
|
|
|
|
|
|
m_toggleRightSideBarAction = toggleRightSideBarAction.contextAction();
|
|
|
|
|
m_toggleRightSideBarButton->setDefaultAction(ProxyAction::proxyActionWithIcon(
|
|
|
|
|
toggleRightSideBarAction.commandAction(), Utils::Icons::TOGGLE_RIGHT_SIDEBAR_TOOLBAR.icon()));
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Show Menubar Action
|
|
|
|
|
if (globalMenuBar() && !globalMenuBar()->isNativeMenuBar()) {
|
2023-10-18 15:18:10 +02:00
|
|
|
m_toggleMenubarAction = new QAction(Tr::tr("Show Menu Bar"), this);
|
2023-09-15 12:58:44 +02:00
|
|
|
m_toggleMenubarAction->setCheckable(true);
|
|
|
|
|
cmd = ActionManager::registerAction(m_toggleMenubarAction, Constants::TOGGLE_MENUBAR);
|
|
|
|
|
cmd->setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Alt+M")));
|
|
|
|
|
connect(m_toggleMenubarAction, &QAction::toggled, this, [cmd](bool visible) {
|
|
|
|
|
if (!visible) {
|
2023-10-18 15:18:10 +02:00
|
|
|
CheckableMessageBox::information(Core::ICore::dialogParent(),
|
|
|
|
|
Tr::tr("Hide Menu Bar"),
|
|
|
|
|
Tr::tr("This will hide the menu bar completely. "
|
|
|
|
|
"You can show it again by typing %1.")
|
|
|
|
|
.arg(cmd->keySequence().toString(
|
|
|
|
|
QKeySequence::NativeText)),
|
|
|
|
|
Key("ToogleMenuBarHint"));
|
2023-09-15 12:58:44 +02:00
|
|
|
}
|
|
|
|
|
globalMenuBar()->setVisible(visible);
|
|
|
|
|
});
|
|
|
|
|
mview->addAction(cmd, Constants::G_VIEW_VIEWS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
registerModeSelectorStyleActions();
|
|
|
|
|
|
|
|
|
|
// Window->Views
|
|
|
|
|
ActionContainer *mviews = ActionManager::createMenu(Constants::M_VIEW_VIEWS);
|
|
|
|
|
mview->addMenu(mviews, Constants::G_VIEW_VIEWS);
|
|
|
|
|
mviews->menu()->setTitle(Tr::tr("&Views"));
|
|
|
|
|
|
|
|
|
|
// "Help" separators
|
|
|
|
|
mhelp->addSeparator(Constants::G_HELP_SUPPORT);
|
|
|
|
|
if (!HostOsInfo::isMacHost())
|
|
|
|
|
mhelp->addSeparator(Constants::G_HELP_ABOUT);
|
|
|
|
|
|
|
|
|
|
// About IDE Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder aboutIdeAction(this, Constants::ABOUT_QTCREATOR);
|
|
|
|
|
aboutIdeAction.setIcon(Icon::fromTheme("help-about"));
|
|
|
|
|
aboutIdeAction.setText(
|
|
|
|
|
(HostOsInfo::isMacHost() ? Tr::tr("About &%1") : Tr::tr("About &%1..."))
|
|
|
|
|
.arg(QGuiApplication::applicationDisplayName()));
|
|
|
|
|
aboutIdeAction.setMenuRole(QAction::AboutRole);
|
2023-12-13 09:02:02 +01:00
|
|
|
aboutIdeAction.addToContainer(Constants::M_HELP, Constants::G_HELP_ABOUT);
|
2023-11-09 10:51:53 +01:00
|
|
|
aboutIdeAction.setEnabled(true);
|
2023-12-13 12:29:46 +01:00
|
|
|
aboutIdeAction.addOnTriggered(this, [this] { aboutQtCreator(); });
|
2023-11-09 12:04:30 +01:00
|
|
|
|
|
|
|
|
// About Plugins Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder aboutPluginsAction(this, Constants::ABOUT_PLUGINS);
|
|
|
|
|
aboutPluginsAction.setText(Tr::tr("About &Plugins..."));
|
|
|
|
|
aboutPluginsAction.setMenuRole(QAction::ApplicationSpecificRole);
|
2023-12-13 09:02:02 +01:00
|
|
|
aboutPluginsAction.addToContainer(Constants::M_HELP, Constants::G_HELP_ABOUT);
|
2023-11-09 10:51:53 +01:00
|
|
|
aboutPluginsAction.setEnabled(true);
|
2023-12-13 12:29:46 +01:00
|
|
|
aboutPluginsAction.addOnTriggered(this, [this] { aboutPlugins(); });
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Change Log Action
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder changeLogAction(this, Constants::CHANGE_LOG);
|
|
|
|
|
changeLogAction.setText(Tr::tr("Change Log..."));
|
|
|
|
|
changeLogAction.setMenuRole(QAction::ApplicationSpecificRole);
|
2023-12-13 09:02:02 +01:00
|
|
|
changeLogAction.addToContainer(Constants::M_HELP, Constants::G_HELP_ABOUT);
|
2023-11-09 10:51:53 +01:00
|
|
|
changeLogAction.setEnabled(true);
|
2023-12-13 12:29:46 +01:00
|
|
|
changeLogAction.addOnTriggered(this, [this] { changeLog(); });
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// Contact
|
2023-11-09 10:51:53 +01:00
|
|
|
ActionBuilder contactAction(this, "QtCreator.Contact");
|
|
|
|
|
contactAction.setText(Tr::tr("Contact..."));
|
2023-12-13 09:02:02 +01:00
|
|
|
contactAction.addToContainer(Constants::M_HELP, Constants::G_HELP_ABOUT);
|
2023-11-09 10:51:53 +01:00
|
|
|
contactAction.setEnabled(true);
|
2023-12-13 12:29:46 +01:00
|
|
|
contactAction.addOnTriggered(this, [this] { contact(); });
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
// About sep
|
|
|
|
|
if (!HostOsInfo::isMacHost()) { // doesn't have the "About" actions in the Help menu
|
2023-11-09 10:51:53 +01:00
|
|
|
auto tmpaction = new QAction(this);
|
2023-09-15 12:58:44 +02:00
|
|
|
tmpaction->setSeparator(true);
|
|
|
|
|
cmd = ActionManager::registerAction(tmpaction, "QtCreator.Help.Sep.About");
|
|
|
|
|
mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::registerModeSelectorStyleActions()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
ActionContainer *mview = ActionManager::actionContainer(Constants::M_VIEW);
|
|
|
|
|
|
|
|
|
|
// Cycle Mode Selector Styles
|
|
|
|
|
m_cycleModeSelectorStyleAction = new QAction(Tr::tr("Cycle Mode Selector Styles"), this);
|
|
|
|
|
ActionManager::registerAction(m_cycleModeSelectorStyleAction, Constants::CYCLE_MODE_SELECTOR_STYLE);
|
|
|
|
|
connect(m_cycleModeSelectorStyleAction, &QAction::triggered, this, [this] {
|
|
|
|
|
ModeManager::cycleModeStyle();
|
|
|
|
|
updateModeSelectorStyleMenu();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Mode Selector Styles
|
|
|
|
|
ActionContainer *mmodeLayouts = ActionManager::createMenu(Constants::M_VIEW_MODESTYLES);
|
|
|
|
|
mview->addMenu(mmodeLayouts, Constants::G_VIEW_VIEWS);
|
|
|
|
|
QMenu *styleMenu = mmodeLayouts->menu();
|
|
|
|
|
styleMenu->setTitle(Tr::tr("Mode Selector Style"));
|
|
|
|
|
auto *stylesGroup = new QActionGroup(styleMenu);
|
|
|
|
|
stylesGroup->setExclusive(true);
|
|
|
|
|
|
|
|
|
|
m_setModeSelectorStyleIconsAndTextAction = stylesGroup->addAction(Tr::tr("Icons and Text"));
|
|
|
|
|
connect(m_setModeSelectorStyleIconsAndTextAction, &QAction::triggered,
|
|
|
|
|
[] { ModeManager::setModeStyle(ModeManager::Style::IconsAndText); });
|
|
|
|
|
m_setModeSelectorStyleIconsAndTextAction->setCheckable(true);
|
|
|
|
|
m_setModeSelectorStyleIconsOnlyAction = stylesGroup->addAction(Tr::tr("Icons Only"));
|
|
|
|
|
connect(m_setModeSelectorStyleIconsOnlyAction, &QAction::triggered,
|
|
|
|
|
[] { ModeManager::setModeStyle(ModeManager::Style::IconsOnly); });
|
|
|
|
|
m_setModeSelectorStyleIconsOnlyAction->setCheckable(true);
|
|
|
|
|
m_setModeSelectorStyleHiddenAction = stylesGroup->addAction(Tr::tr("Hidden"));
|
|
|
|
|
connect(m_setModeSelectorStyleHiddenAction, &QAction::triggered,
|
|
|
|
|
[] { ModeManager::setModeStyle(ModeManager::Style::Hidden); });
|
|
|
|
|
m_setModeSelectorStyleHiddenAction->setCheckable(true);
|
|
|
|
|
|
|
|
|
|
styleMenu->addActions(stylesGroup->actions());
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::openFile()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
2023-09-15 16:47:37 +02:00
|
|
|
ICore::openFiles(EditorManager::getOpenFilePaths(), ICore::SwitchMode);
|
2023-09-15 12:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static IDocumentFactory *findDocumentFactory(const QList<IDocumentFactory*> &fileFactories,
|
|
|
|
|
const FilePath &filePath)
|
|
|
|
|
{
|
|
|
|
|
const QString typeName = Utils::mimeTypeForFile(filePath, MimeMatchMode::MatchDefaultAndRemote)
|
|
|
|
|
.name();
|
|
|
|
|
return Utils::findOrDefault(fileFactories, [typeName](IDocumentFactory *f) {
|
|
|
|
|
return f->mimeTypes().contains(typeName);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
} // Internal
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
/*!
|
|
|
|
|
* \internal
|
|
|
|
|
* Either opens \a filePaths with editors or loads a project.
|
|
|
|
|
*
|
|
|
|
|
* \a flags can be used to stop on first failure, indicate that a file name
|
|
|
|
|
* might include line numbers and/or switch mode to edit mode.
|
|
|
|
|
*
|
|
|
|
|
* \a workingDirectory is used when files are opened by a remote client, since
|
|
|
|
|
* the file names are relative to the client working directory.
|
|
|
|
|
*
|
|
|
|
|
* Returns the first opened document. Required to support the \c -block flag
|
|
|
|
|
* for client mode.
|
|
|
|
|
*
|
|
|
|
|
* \sa IPlugin::remoteArguments()
|
|
|
|
|
*/
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
IDocument *ICore::openFiles(const FilePaths &filePaths,
|
|
|
|
|
ICore::OpenFilesFlags flags,
|
|
|
|
|
const FilePath &workingDirectory)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
const QList<IDocumentFactory*> documentFactories = IDocumentFactory::allDocumentFactories();
|
|
|
|
|
IDocument *res = nullptr;
|
|
|
|
|
|
|
|
|
|
const FilePath workingDirBase =
|
|
|
|
|
workingDirectory.isEmpty() ? FilePath::currentWorkingPath() : workingDirectory;
|
|
|
|
|
for (const FilePath &filePath : filePaths) {
|
|
|
|
|
const FilePath absoluteFilePath = workingDirBase.resolvePath(filePath);
|
|
|
|
|
if (IDocumentFactory *documentFactory = findDocumentFactory(documentFactories, filePath)) {
|
|
|
|
|
IDocument *document = documentFactory->open(absoluteFilePath);
|
|
|
|
|
if (!document) {
|
|
|
|
|
if (flags & ICore::StopOnLoadFail)
|
|
|
|
|
return res;
|
|
|
|
|
} else {
|
|
|
|
|
if (!res)
|
|
|
|
|
res = document;
|
|
|
|
|
if (flags & ICore::SwitchMode)
|
|
|
|
|
ModeManager::activateMode(Id(Constants::MODE_EDIT));
|
|
|
|
|
}
|
|
|
|
|
} else if (flags & (ICore::SwitchSplitIfAlreadyVisible | ICore::CanContainLineAndColumnNumbers)
|
|
|
|
|
|| !res) {
|
|
|
|
|
QFlags<EditorManager::OpenEditorFlag> emFlags;
|
|
|
|
|
if (flags & ICore::SwitchSplitIfAlreadyVisible)
|
|
|
|
|
emFlags |= EditorManager::SwitchSplitIfAlreadyVisible;
|
|
|
|
|
IEditor *editor = nullptr;
|
|
|
|
|
if (flags & ICore::CanContainLineAndColumnNumbers) {
|
|
|
|
|
const Link &link = Link::fromString(absoluteFilePath.toString(), true);
|
|
|
|
|
editor = EditorManager::openEditorAt(link, {}, emFlags);
|
|
|
|
|
} else {
|
|
|
|
|
editor = EditorManager::openEditor(absoluteFilePath, {}, emFlags);
|
|
|
|
|
}
|
|
|
|
|
if (!editor) {
|
|
|
|
|
if (flags & ICore::StopOnLoadFail)
|
|
|
|
|
return res;
|
|
|
|
|
} else if (!res) {
|
|
|
|
|
res = editor->document();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
auto factory = IEditorFactory::preferredEditorFactories(absoluteFilePath).value(0);
|
|
|
|
|
DocumentModelPrivate::addSuspendedDocument(absoluteFilePath, {},
|
|
|
|
|
factory ? factory->id() : Id());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::setFocusToEditor()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
EditorManagerPrivate::doEscapeKeyFocusMoveMagic();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::openFileFromDevice()
|
2023-09-15 16:47:37 +02:00
|
|
|
{
|
|
|
|
|
ICore::openFiles(EditorManager::getOpenFilePaths(QFileDialog::DontUseNativeDialog), ICore::SwitchMode);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 12:58:44 +02:00
|
|
|
static void acceptModalDialogs()
|
|
|
|
|
{
|
|
|
|
|
const QWidgetList topLevels = QApplication::topLevelWidgets();
|
|
|
|
|
QList<QDialog *> dialogsToClose;
|
|
|
|
|
for (QWidget *topLevel : topLevels) {
|
|
|
|
|
if (auto dialog = qobject_cast<QDialog *>(topLevel)) {
|
|
|
|
|
if (dialog->isModal())
|
|
|
|
|
dialogsToClose.append(dialog);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (QDialog *dialog : dialogsToClose)
|
|
|
|
|
dialog->accept();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
} // Internal
|
|
|
|
|
|
|
|
|
|
void ICore::exit()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
// this function is most likely called from a user action
|
|
|
|
|
// that is from an event handler of an object
|
|
|
|
|
// since on close we are going to delete everything
|
|
|
|
|
// so to prevent the deleting of that object we
|
|
|
|
|
// just append it
|
|
|
|
|
QMetaObject::invokeMethod(
|
2023-10-02 17:27:26 +02:00
|
|
|
d->m_mainwindow,
|
2023-09-15 16:47:37 +02:00
|
|
|
[] {
|
2023-09-15 12:58:44 +02:00
|
|
|
// Modal dialogs block the close event. So close them, in case this was triggered from
|
|
|
|
|
// a RestartDialog in the settings dialog.
|
|
|
|
|
acceptModalDialogs();
|
2023-10-02 17:27:26 +02:00
|
|
|
d->m_mainwindow->close();
|
2023-09-15 12:58:44 +02:00
|
|
|
},
|
|
|
|
|
Qt::QueuedConnection);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
void ICore::openFileWith()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
const FilePaths filePaths = EditorManager::getOpenFilePaths();
|
|
|
|
|
for (const FilePath &filePath : filePaths) {
|
|
|
|
|
bool isExternal;
|
|
|
|
|
const Id editorId = EditorManagerPrivate::getOpenWithEditorId(filePath, &isExternal);
|
|
|
|
|
if (!editorId.isValid())
|
|
|
|
|
continue;
|
|
|
|
|
if (isExternal)
|
|
|
|
|
EditorManager::openExternalEditor(filePath, editorId);
|
|
|
|
|
else
|
|
|
|
|
EditorManagerPrivate::openEditorWith(filePath, editorId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
/*!
|
|
|
|
|
Returns the registered IContext instance for the specified \a widget,
|
|
|
|
|
if any.
|
|
|
|
|
*/
|
|
|
|
|
IContext *ICore::contextObject(QWidget *widget)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
const auto it = d->m_contextWidgets.find(widget);
|
|
|
|
|
return it == d->m_contextWidgets.end() ? nullptr : it->second;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
/*!
|
|
|
|
|
Adds \a context to the list of registered IContext instances.
|
|
|
|
|
Whenever the IContext's \l{IContext::widget()}{widget} is in the application
|
|
|
|
|
focus widget's parent hierarchy, its \l{IContext::context()}{context} is
|
|
|
|
|
added to the list of active contexts.
|
|
|
|
|
|
|
|
|
|
\sa removeContextObject()
|
|
|
|
|
\sa updateAdditionalContexts()
|
|
|
|
|
\sa currentContextObject()
|
|
|
|
|
\sa {The Action Manager and Commands}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void ICore::addContextObject(IContext *context)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
if (!context)
|
|
|
|
|
return;
|
|
|
|
|
QWidget *widget = context->widget();
|
|
|
|
|
if (d->m_contextWidgets.find(widget) != d->m_contextWidgets.end())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
d->m_contextWidgets.insert({widget, context});
|
2023-09-15 16:47:37 +02:00
|
|
|
connect(context, &QObject::destroyed, m_core, [context] { removeContextObject(context); });
|
2023-09-15 12:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
/*!
|
|
|
|
|
Unregisters a \a context object from the list of registered IContext
|
|
|
|
|
instances. IContext instances are automatically removed when they are
|
|
|
|
|
deleted.
|
|
|
|
|
|
|
|
|
|
\sa addContextObject()
|
|
|
|
|
\sa updateAdditionalContexts()
|
|
|
|
|
\sa currentContextObject()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void ICore::removeContextObject(IContext *context)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
if (!context)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
disconnect(context, &QObject::destroyed, m_core, nullptr);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
|
|
|
|
const auto it = std::find_if(d->m_contextWidgets.cbegin(),
|
|
|
|
|
d->m_contextWidgets.cend(),
|
|
|
|
|
[context](const std::pair<QWidget *, IContext *> &v) {
|
|
|
|
|
return v.second == context;
|
|
|
|
|
});
|
|
|
|
|
if (it == d->m_contextWidgets.cend())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
d->m_contextWidgets.erase(it);
|
|
|
|
|
if (d->m_activeContext.removeAll(context) > 0)
|
|
|
|
|
d->updateContextObject(d->m_activeContext);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::updateFocusWidget(QWidget *old, QWidget *now)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
Q_UNUSED(old)
|
|
|
|
|
|
|
|
|
|
// Prevent changing the context object just because the menu or a menu item is activated
|
|
|
|
|
if (qobject_cast<QMenuBar*>(now) || qobject_cast<QMenu*>(now))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QList<IContext *> newContext;
|
|
|
|
|
if (QWidget *p = QApplication::focusWidget()) {
|
|
|
|
|
IContext *context = nullptr;
|
|
|
|
|
while (p) {
|
2023-09-15 16:47:37 +02:00
|
|
|
context = ICore::contextObject(p);
|
2023-09-15 12:58:44 +02:00
|
|
|
if (context)
|
|
|
|
|
newContext.append(context);
|
|
|
|
|
p = p->parentWidget();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ignore toplevels that define no context, like popups without parent
|
2023-10-02 17:27:26 +02:00
|
|
|
if (!newContext.isEmpty() || QApplication::focusWidget() == m_mainwindow->focusWidget())
|
2023-09-15 12:58:44 +02:00
|
|
|
updateContextObject(newContext);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::updateContextObject(const QList<IContext *> &context)
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
emit m_core->contextAboutToChange(context);
|
|
|
|
|
m_activeContext = context;
|
|
|
|
|
updateContext();
|
|
|
|
|
if (debugMainWindow) {
|
|
|
|
|
qDebug() << "new context objects =" << context;
|
|
|
|
|
for (const IContext *c : context)
|
|
|
|
|
qDebug() << (c ? c->widget() : nullptr) << (c ? c->widget()->metaObject()->className() : nullptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::readSettings()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
QtcSettings *settings = PluginManager::settings();
|
2023-09-05 15:25:26 +02:00
|
|
|
settings->beginGroup(settingsGroup);
|
2023-09-15 12:58:44 +02:00
|
|
|
|
2023-10-02 17:54:48 +02:00
|
|
|
if (s_overrideColor.isValid()) {
|
|
|
|
|
StyleHelper::setBaseColor(s_overrideColor);
|
2023-09-15 12:58:44 +02:00
|
|
|
// Get adapted base color.
|
2023-10-02 17:54:48 +02:00
|
|
|
s_overrideColor = StyleHelper::baseColor();
|
2023-09-15 12:58:44 +02:00
|
|
|
} else {
|
|
|
|
|
StyleHelper::setBaseColor(settings->value(colorKey,
|
|
|
|
|
QColor(StyleHelper::DEFAULT_BASE_COLOR)).value<QColor>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
ModeManager::Style modeStyle =
|
|
|
|
|
ModeManager::Style(settings->value(modeSelectorLayoutKey, int(ModeManager::Style::IconsAndText)).toInt());
|
|
|
|
|
|
|
|
|
|
// Migrate legacy setting from Qt Creator 4.6 and earlier
|
|
|
|
|
static const char modeSelectorVisibleKey[] = "ModeSelectorVisible";
|
|
|
|
|
if (!settings->contains(modeSelectorLayoutKey) && settings->contains(modeSelectorVisibleKey)) {
|
|
|
|
|
bool visible = settings->value(modeSelectorVisibleKey, true).toBool();
|
|
|
|
|
modeStyle = visible ? ModeManager::Style::IconsAndText : ModeManager::Style::Hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ModeManager::setModeStyle(modeStyle);
|
|
|
|
|
updateModeSelectorStyleMenu();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (globalMenuBar() && !globalMenuBar()->isNativeMenuBar()) {
|
|
|
|
|
const bool isVisible = settings->value(menubarVisibleKey, true).toBool();
|
|
|
|
|
|
|
|
|
|
globalMenuBar()->setVisible(isVisible);
|
|
|
|
|
if (m_toggleMenubarAction)
|
|
|
|
|
m_toggleMenubarAction->setChecked(isVisible);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
settings->endGroup();
|
|
|
|
|
|
|
|
|
|
EditorManagerPrivate::readSettings();
|
|
|
|
|
m_leftNavigationWidget->restoreSettings(settings);
|
|
|
|
|
m_rightNavigationWidget->restoreSettings(settings);
|
|
|
|
|
m_rightPaneWidget->readSettings(settings);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::saveWindowSettings()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
QtcSettings *settings = PluginManager::settings();
|
|
|
|
|
settings->beginGroup(settingsGroup);
|
|
|
|
|
|
|
|
|
|
// On OS X applications usually do not restore their full screen state.
|
|
|
|
|
// To be able to restore the correct non-full screen geometry, we have to put
|
|
|
|
|
// the window out of full screen before saving the geometry.
|
|
|
|
|
// Works around QTBUG-45241
|
2023-10-02 17:27:26 +02:00
|
|
|
if (Utils::HostOsInfo::isMacHost() && m_mainwindow->isFullScreen())
|
|
|
|
|
m_mainwindow->setWindowState(m_mainwindow->windowState() & ~Qt::WindowFullScreen);
|
|
|
|
|
settings->setValue(windowGeometryKey, m_mainwindow->saveGeometry());
|
|
|
|
|
settings->setValue(windowStateKey, m_mainwindow->saveState());
|
2023-09-15 12:58:44 +02:00
|
|
|
settings->setValue(modeSelectorLayoutKey, int(ModeManager::modeStyle()));
|
|
|
|
|
|
|
|
|
|
settings->endGroup();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::updateModeSelectorStyleMenu()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
switch (ModeManager::modeStyle()) {
|
|
|
|
|
case ModeManager::Style::IconsAndText:
|
|
|
|
|
m_setModeSelectorStyleIconsAndTextAction->setChecked(true);
|
|
|
|
|
break;
|
|
|
|
|
case ModeManager::Style::IconsOnly:
|
|
|
|
|
m_setModeSelectorStyleIconsOnlyAction->setChecked(true);
|
|
|
|
|
break;
|
|
|
|
|
case ModeManager::Style::Hidden:
|
|
|
|
|
m_setModeSelectorStyleHiddenAction->setChecked(true);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::updateContext()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
Context contexts = m_highPrioAdditionalContexts;
|
|
|
|
|
|
|
|
|
|
for (IContext *context : std::as_const(m_activeContext))
|
|
|
|
|
contexts.add(context->context());
|
|
|
|
|
|
|
|
|
|
contexts.add(m_lowPrioAdditionalContexts);
|
|
|
|
|
|
|
|
|
|
Context uniquecontexts;
|
|
|
|
|
for (const Id &id : std::as_const(contexts)) {
|
|
|
|
|
if (!uniquecontexts.contains(id))
|
|
|
|
|
uniquecontexts.add(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ActionManager::setContext(uniquecontexts);
|
|
|
|
|
emit m_core->contextChanged(uniquecontexts);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::aboutToShowRecentFiles()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
ActionContainer *aci = ActionManager::actionContainer(Constants::M_FILE_RECENTFILES);
|
|
|
|
|
QMenu *menu = aci->menu();
|
|
|
|
|
menu->clear();
|
|
|
|
|
|
|
|
|
|
const QList<DocumentManager::RecentFile> recentFiles = DocumentManager::recentFiles();
|
|
|
|
|
for (int i = 0; i < recentFiles.count(); ++i) {
|
|
|
|
|
const DocumentManager::RecentFile file = recentFiles[i];
|
|
|
|
|
|
|
|
|
|
const QString filePath = Utils::quoteAmpersands(file.first.shortNativePath());
|
|
|
|
|
const QString actionText = ActionManager::withNumberAccelerator(filePath, i + 1);
|
|
|
|
|
QAction *action = menu->addAction(actionText);
|
|
|
|
|
connect(action, &QAction::triggered, this, [file] {
|
|
|
|
|
EditorManager::openEditor(file.first, file.second);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool hasRecentFiles = !recentFiles.isEmpty();
|
|
|
|
|
menu->setEnabled(hasRecentFiles);
|
|
|
|
|
|
|
|
|
|
// add the Clear Menu item
|
|
|
|
|
if (hasRecentFiles) {
|
|
|
|
|
menu->addSeparator();
|
|
|
|
|
QAction *action = menu->addAction(Tr::tr(Constants::TR_CLEAR_MENU));
|
|
|
|
|
connect(action, &QAction::triggered,
|
|
|
|
|
DocumentManager::instance(), &DocumentManager::clearRecentFiles);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::aboutQtCreator()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
if (!m_versionDialog) {
|
2023-10-02 17:27:26 +02:00
|
|
|
m_versionDialog = new VersionDialog(m_mainwindow);
|
2023-09-15 12:58:44 +02:00
|
|
|
connect(m_versionDialog, &QDialog::finished,
|
2023-10-02 16:24:02 +02:00
|
|
|
this, &ICorePrivate::destroyVersionDialog);
|
2023-09-15 12:58:44 +02:00
|
|
|
ICore::registerWindow(m_versionDialog, Context("Core.VersionDialog"));
|
|
|
|
|
m_versionDialog->show();
|
|
|
|
|
} else {
|
|
|
|
|
ICore::raiseWindow(m_versionDialog);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::destroyVersionDialog()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
if (m_versionDialog) {
|
|
|
|
|
m_versionDialog->deleteLater();
|
|
|
|
|
m_versionDialog = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::aboutPlugins()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
2023-10-02 17:27:26 +02:00
|
|
|
PluginDialog dialog(m_mainwindow);
|
2023-09-15 12:58:44 +02:00
|
|
|
dialog.exec();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class LogDialog : public QDialog
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
LogDialog(QWidget *parent)
|
|
|
|
|
: QDialog(parent)
|
|
|
|
|
{}
|
|
|
|
|
bool event(QEvent *event) override
|
|
|
|
|
{
|
|
|
|
|
if (event->type() == QEvent::ShortcutOverride) {
|
|
|
|
|
auto ke = static_cast<QKeyEvent *>(event);
|
|
|
|
|
if (ke->key() == Qt::Key_Escape && !ke->modifiers()) {
|
|
|
|
|
ke->accept();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return QDialog::event(event);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::changeLog()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
static QPointer<LogDialog> dialog;
|
|
|
|
|
if (dialog) {
|
|
|
|
|
ICore::raiseWindow(dialog);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const FilePaths files =
|
|
|
|
|
ICore::resourcePath("changelog").dirEntries({{"changes-*"}, QDir::Files});
|
|
|
|
|
static const QRegularExpression versionRegex("\\d+[.]\\d+[.]\\d+");
|
|
|
|
|
using VersionFilePair = std::pair<QVersionNumber, FilePath>;
|
|
|
|
|
QList<VersionFilePair> versionedFiles = Utils::transform(files, [](const FilePath &fp) {
|
|
|
|
|
const QRegularExpressionMatch match = versionRegex.match(fp.fileName());
|
|
|
|
|
const QVersionNumber version = match.hasMatch()
|
|
|
|
|
? QVersionNumber::fromString(match.captured())
|
|
|
|
|
: QVersionNumber();
|
|
|
|
|
return std::make_pair(version, fp);
|
|
|
|
|
});
|
|
|
|
|
Utils::sort(versionedFiles, [](const VersionFilePair &a, const VersionFilePair &b) {
|
|
|
|
|
return a.first > b.first;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto versionCombo = new QComboBox;
|
|
|
|
|
for (const VersionFilePair &f : versionedFiles)
|
|
|
|
|
versionCombo->addItem(f.first.toString());
|
|
|
|
|
dialog = new LogDialog(ICore::dialogParent());
|
|
|
|
|
auto versionLayout = new QHBoxLayout;
|
|
|
|
|
versionLayout->addWidget(new QLabel(Tr::tr("Version:")));
|
|
|
|
|
versionLayout->addWidget(versionCombo);
|
|
|
|
|
versionLayout->addStretch(1);
|
|
|
|
|
auto showInExplorer = new QPushButton(FileUtils::msgGraphicalShellAction());
|
|
|
|
|
versionLayout->addWidget(showInExplorer);
|
|
|
|
|
auto textEdit = new QTextBrowser;
|
|
|
|
|
textEdit->setOpenExternalLinks(true);
|
|
|
|
|
|
|
|
|
|
auto aggregate = new Aggregation::Aggregate;
|
|
|
|
|
aggregate->add(textEdit);
|
|
|
|
|
aggregate->add(new Core::BaseTextFind(textEdit));
|
|
|
|
|
|
|
|
|
|
new MarkdownHighlighter(textEdit->document());
|
|
|
|
|
|
|
|
|
|
auto textEditWidget = new QFrame;
|
|
|
|
|
textEditWidget->setFrameStyle(QFrame::NoFrame);
|
|
|
|
|
auto findToolBar = new FindToolBarPlaceHolder(dialog);
|
|
|
|
|
findToolBar->setLightColored(true);
|
|
|
|
|
auto textEditLayout = new QVBoxLayout;
|
|
|
|
|
textEditLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
textEditLayout->setSpacing(0);
|
|
|
|
|
textEditLayout->addWidget(textEdit);
|
|
|
|
|
textEditLayout->addWidget(findToolBar);
|
|
|
|
|
textEditWidget->setLayout(textEditLayout);
|
|
|
|
|
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
|
|
|
|
|
auto dialogLayout = new QVBoxLayout;
|
|
|
|
|
dialogLayout->addLayout(versionLayout);
|
|
|
|
|
dialogLayout->addWidget(textEditWidget);
|
|
|
|
|
dialogLayout->addWidget(buttonBox);
|
|
|
|
|
dialog->setLayout(dialogLayout);
|
|
|
|
|
dialog->resize(700, 600);
|
|
|
|
|
dialog->setWindowTitle(Tr::tr("Change Log"));
|
|
|
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
ICore::registerWindow(dialog, Context("CorePlugin.VersionDialog"));
|
|
|
|
|
|
|
|
|
|
connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::close);
|
|
|
|
|
QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close);
|
|
|
|
|
if (QTC_GUARD(closeButton))
|
|
|
|
|
closeButton->setDefault(true); // grab from "Open in Explorer" button
|
|
|
|
|
|
|
|
|
|
const auto showLog = [textEdit, versionedFiles](int index) {
|
|
|
|
|
if (index < 0 || index >= versionedFiles.size())
|
|
|
|
|
return;
|
|
|
|
|
const FilePath file = versionedFiles.at(index).second;
|
|
|
|
|
QString contents = QString::fromUtf8(file.fileContents().value_or(QByteArray()));
|
|
|
|
|
// (?<![[\/]) == don't replace if it is preceded by "[" or "/"
|
|
|
|
|
// i.e. if it already is part of a link
|
|
|
|
|
static const QRegularExpression bugexpr(R"((?<![[\/])((QT(CREATOR)?BUG|PYSIDE)-\d+))");
|
|
|
|
|
contents.replace(bugexpr, R"([\1](https://bugreports.qt.io/browse/\1))");
|
|
|
|
|
static const QRegularExpression docexpr("https://doc[.]qt[.]io/qtcreator/([.a-zA-Z/_-]*)");
|
|
|
|
|
QList<QRegularExpressionMatch> matches;
|
|
|
|
|
for (const QRegularExpressionMatch &m : docexpr.globalMatch(contents))
|
|
|
|
|
matches.append(m);
|
|
|
|
|
Utils::reverseForeach(matches, [&contents](const QRegularExpressionMatch &match) {
|
|
|
|
|
const QString qthelpUrl = "qthelp://org.qt-project.qtcreator/doc/" + match.captured(1);
|
|
|
|
|
if (!HelpManager::fileData(qthelpUrl).isEmpty())
|
|
|
|
|
contents.replace(match.capturedStart(), match.capturedLength(), qthelpUrl);
|
|
|
|
|
});
|
|
|
|
|
textEdit->setMarkdown(contents);
|
|
|
|
|
};
|
|
|
|
|
connect(versionCombo, &QComboBox::currentIndexChanged, textEdit, showLog);
|
|
|
|
|
showLog(versionCombo->currentIndex());
|
|
|
|
|
|
|
|
|
|
connect(showInExplorer, &QPushButton::clicked, this, [versionCombo, versionedFiles] {
|
|
|
|
|
const int index = versionCombo->currentIndex();
|
|
|
|
|
if (index >= 0 && index < versionedFiles.size())
|
|
|
|
|
FileUtils::showInGraphicalShell(ICore::dialogParent(), versionedFiles.at(index).second);
|
|
|
|
|
else
|
|
|
|
|
FileUtils::showInGraphicalShell(ICore::dialogParent(), ICore::resourcePath("changelog"));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
dialog->show();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::contact()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
QMessageBox dlg(QMessageBox::Information, Tr::tr("Contact"),
|
|
|
|
|
Tr::tr("<p>Qt Creator developers can be reached at the Qt Creator mailing list:</p>"
|
|
|
|
|
"%1"
|
|
|
|
|
"<p>or the #qt-creator channel on Libera.Chat IRC:</p>"
|
|
|
|
|
"%2"
|
|
|
|
|
"<p>Our bug tracker is located at %3.</p>"
|
|
|
|
|
"<p>Please use %4 for bigger chunks of text.</p>")
|
|
|
|
|
.arg("<p> "
|
|
|
|
|
"<a href=\"https://lists.qt-project.org/listinfo/qt-creator\">"
|
|
|
|
|
"mailto:qt-creator@qt-project.org"
|
|
|
|
|
"</a></p>")
|
|
|
|
|
.arg("<p> "
|
|
|
|
|
"<a href=\"https://web.libera.chat/#qt-creator\">"
|
|
|
|
|
"https://web.libera.chat/#qt-creator"
|
|
|
|
|
"</a></p>")
|
|
|
|
|
.arg("<a href=\"https://bugreports.qt.io/projects/QTCREATORBUG\">"
|
|
|
|
|
"https://bugreports.qt.io"
|
|
|
|
|
"</a>")
|
|
|
|
|
.arg("<a href=\"https://pastebin.com\">"
|
|
|
|
|
"https://pastebin.com"
|
|
|
|
|
"</a>"),
|
2023-09-15 16:47:37 +02:00
|
|
|
QMessageBox::Ok, m_mainwindow);
|
2023-09-15 12:58:44 +02:00
|
|
|
dlg.exec();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 16:24:02 +02:00
|
|
|
void ICorePrivate::restoreWindowState()
|
2023-09-15 12:58:44 +02:00
|
|
|
{
|
|
|
|
|
NANOTRACE_SCOPE("Core", "MainWindow::restoreWindowState");
|
|
|
|
|
QtcSettings *settings = PluginManager::settings();
|
|
|
|
|
settings->beginGroup(settingsGroup);
|
2023-10-02 17:27:26 +02:00
|
|
|
if (!m_mainwindow->restoreGeometry(settings->value(windowGeometryKey).toByteArray()))
|
|
|
|
|
m_mainwindow->resize(1260, 700); // size without window decoration
|
|
|
|
|
m_mainwindow->restoreState(settings->value(windowStateKey).toByteArray());
|
2023-09-15 12:58:44 +02:00
|
|
|
settings->endGroup();
|
2023-10-02 17:27:26 +02:00
|
|
|
m_mainwindow->show();
|
2023-09-15 12:58:44 +02:00
|
|
|
StatusBarManager::restoreSettings();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 16:47:37 +02:00
|
|
|
} // Internal
|
2023-09-15 14:53:59 +02:00
|
|
|
|
|
|
|
|
void ICore::setOverrideColor(const QColor &color)
|
|
|
|
|
{
|
2023-10-02 17:54:48 +02:00
|
|
|
s_overrideColor = color;
|
2023-09-15 14:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-18 23:25:34 +01:00
|
|
|
} // namespace Core
|