Files
qt-creator/src/plugins/coreplugin/mainwindow.cpp

1296 lines
49 KiB
C++
Raw Normal View History

/****************************************************************************
2008-12-02 12:01:29 +01:00
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
2008-12-02 12:01:29 +01:00
**
** This file is part of Qt Creator.
2008-12-02 12:01:29 +01:00
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
2010-12-17 16:01:08 +01:00
**
****************************************************************************/
2008-12-02 12:01:29 +01:00
#include "mainwindow.h"
Add macOS touch bar support Introduce a generic Utils::TouchBar that implements a touch bar for macOS based on QAction. Touch bars can be nested, and one is set to be the application's top level touch bar. Also add an ActionContainer for the touch bar. That allows us to manage the layout of the touch bar the same way we do with menus. Since the touch bar is an input device with very limited space, a command in the touch bar needs to be specifically styled for the touch bar by setting either touchBarText or touchBarIcon (or both). Touch bars can be nested by nesting the ActionContainers. A nested touch bar ActionContainer needs to specify an icon and/or text to show in the touch bar button that opens that sub-bar. Commands are only shown in the touch bar if they are valid within the current context. Implementation-wise we cannot use the standard NSPopoverTouchBarItem for nesting touch bar levels. We cannot hide items in the touch bar, because hidden items still take up space in the touch bar. So we need to rebuild the touch bar regularly. Since the items we show are very dynamic, every time the items in the toplevel bar change because of a context change, any opened sub-level touch bar closes. That is why we maintain a stack of touch bar levels ourselves, replacing the main touch bar with the current level, and managing opening and closing the levels manually. This patch adds buttons for Help, Bookmarks, Header/Source, Follow (Symbol), Decl/Def, and a sub-bar for the debugger actions. Fixes: QTCREATORBUG-21263 Change-Id: Ib63e610f21a993f1d324fe23c83a7f2224f434ac Reviewed-by: Eike Ziller <eike.ziller@qt.io> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: Vikas Pachdha <vikas.pachdha@qt.io>
2018-10-05 13:52:57 +02:00
#include "icore.h"
#include "jsexpander.h"
#include "mimetypesettings.h"
2008-12-02 12:01:29 +01:00
#include "fancytabwidget.h"
#include "documentmanager.h"
2008-12-02 12:01:29 +01:00
#include "generalsettings.h"
#include "idocumentfactory.h"
2008-12-02 12:01:29 +01:00
#include "messagemanager.h"
#include "modemanager.h"
2010-09-16 12:26:28 +02:00
#include "outputpanemanager.h"
2008-12-02 12:01:29 +01:00
#include "plugindialog.h"
#include "vcsmanager.h"
#include "versiondialog.h"
2009-12-09 11:05:18 +01:00
#include "statusbarmanager.h"
2008-12-02 12:01:29 +01:00
#include "manhattanstyle.h"
#include "navigationwidget.h"
#include "rightpane.h"
#include "editormanager/ieditorfactory.h"
#include "systemsettings.h"
#include "externaltoolmanager.h"
#include "editormanager/systemeditor.h"
#include "windowsupport.h"
#include "coreicons.h"
2008-12-02 12:01:29 +01:00
#include <app/app_version.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actionmanager_p.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/dialogs/externaltoolconfig.h>
#include <coreplugin/dialogs/newdialog.h>
#include <coreplugin/dialogs/shortcutsettings.h>
#include <coreplugin/editormanager/documentmodel_p.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/editormanager_p.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/inavigationwidgetfactory.h>
#include <coreplugin/progressmanager/progressmanager_p.h>
#include <coreplugin/progressmanager/progressview.h>
#include <coreplugin/settingsdatabase.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/historycompleter.h>
#include <utils/hostosinfo.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
Implement theming for QtCreator Adds a 'Theme' tab to the environment settings and a '-theme' command line option. A theme is a combination of colors, gradients, flags and style information. There are two themes: - 'default': preserves the current default look - 'dark': uses a more flat for many widgets, dark color theme for everything This does not use a stylesheet (too limited), but rather sets the palette via C++ and modifies drawing behavior. Overall, the look is more flat (removed some gradients and bevels). Tested on Ubuntu 14.04 using Qt 5.4 and running on a KDE Desktop (Oxygen base style). For a screenshot, see https://gist.github.com/thorbenk/5ab06bea726de0aa7473 Changes: - Introduce class Theme, defining the interface how to access theme specific settings. The class reads a .creatortheme file (INI file, via QSettings) - Define named colors in the [Palette] section (see dark.creatortheme for example usage) - Use either named colors of AARRGGBB (hex) in the [Colors] section - A file ending with .creatortheme may be supplied to the '-theme' command line option - A global Theme instance can be accessed via creatorTheme() - Query colors, gradients, icons and flags from the theme were possible (TODO: use this in more places...) - There are very many color roles. It seems better to me to describe the role clearly, and then to consolidate later in the actual theme by assigning the same color. For example, one can set the text color of the output pane button individualy. - Many elements are also drawn differently. For the dark theme, I wanted to have a flatter look. - Introduce Theme::WidgetStyle enum, for now {Original, Flat}. - The theme specifies which kind of widget style it wants. - The drawing code queries the theme's style flag and switches between the original, gradient based look and the new, flat look. - Create some custom icons which look better on dark background (wip, currently folder/file icons) - Let ManhattanStyle draw some elements for non-panelwidgets, too (open/close arrows in QTreeView, custom folder/file icons) - For the welcomescreen, pass the WelcomeTheme class. WelcomeTheme exposes theme colors as Q_PROPERTY accessible from .qml - Themes can be modified via the 'Themes' tab in the environment settings. TODO: * Unify image handling * Avoid style name references * Fix gradients Change-Id: I92c2050ab0fb327649ea1eff4adec973d2073944 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com> Reviewed-by: hjk <hjk121@nokiamail.com>
2014-10-14 19:09:48 +02:00
#include <utils/theme/theme.h>
#include <utils/stringutils.h>
#include <utils/utilsicons.h>
2008-12-02 12:01:29 +01:00
#include <QActionGroup>
#include <QApplication>
#include <QCloseEvent>
#include <QColorDialog>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QPrinter>
#include <QSettings>
#include <QStatusBar>
#include <QStyleFactory>
#include <QToolButton>
#include <QUrl>
2008-12-02 12:01:29 +01:00
using namespace ExtensionSystem;
using namespace Utils;
namespace Core {
namespace Internal {
2008-12-02 12:01:29 +01:00
enum { debugMainWindow = 0 };
2008-12-02 12:01:29 +01:00
MainWindow::MainWindow()
: AppMainWindow()
, m_coreImpl(new ICore(this))
, m_lowPrioAdditionalContexts(Constants::C_GLOBAL)
, m_settingsDatabase(
new SettingsDatabase(QFileInfo(PluginManager::settings()->fileName()).path(),
QLatin1String(Constants::IDE_CASED_ID),
this))
, m_progressManager(new ProgressManagerPrivate)
, m_jsExpander(JsExpander::createGlobalJsExpander())
, m_vcsManager(new VcsManager)
, m_modeStack(new FancyTabWidget(this))
, m_generalSettings(new GeneralSettings)
, m_systemSettings(new SystemSettings)
, m_shortcutSettings(new ShortcutSettings)
, m_toolSettings(new ToolSettings)
, m_mimeTypeSettings(new MimeTypeSettings)
, m_systemEditor(new SystemEditor)
, m_toggleLeftSideBarButton(new QToolButton)
, m_toggleRightSideBarButton(new QToolButton)
2008-12-02 12:01:29 +01:00
{
(void) new DocumentManager(this);
HistoryCompleter::setSettings(PluginManager::settings());
setWindowTitle(Constants::IDE_DISPLAY_NAME);
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();
foreach (const QString &s, Utils::creatorTheme()->preferredStyles()) {
if (available.contains(s, Qt::CaseInsensitive)) {
baseName = s;
break;
}
}
QApplication::setStyle(new ManhattanStyle(baseName));
m_generalSettings->setShowShortcutsInContextMenu(
GeneralSettings::showShortcutsInContextMenu());
2008-12-02 12:01:29 +01:00
setDockNestingEnabled(true);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea);
m_modeManager = new ModeManager(this, m_modeStack);
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);
}
});
2008-12-02 12:01:29 +01:00
registerDefaultContainers();
registerDefaultActions();
m_leftNavigationWidget = new NavigationWidget(m_toggleLeftSideBarAction, Side::Left);
m_rightNavigationWidget = new NavigationWidget(m_toggleRightSideBarAction, Side::Right);
2008-12-02 12:01:29 +01:00
m_rightPaneWidget = new RightPaneWidget();
m_messageManager = new MessageManager;
m_editorManager = new EditorManager(this);
m_externalToolManager = new ExternalToolManager();
2008-12-02 12:01:29 +01:00
setCentralWidget(m_modeStack);
m_progressManager->progressView()->setParent(this);
connect(qApp, &QApplication::focusChanged, this, &MainWindow::updateFocusWidget);
// Add small Toolbuttons for toggling the navigation widgets
StatusBarManager::addStatusBarWidget(m_toggleLeftSideBarButton, StatusBarManager::First);
int childsCount = statusBar()->findChildren<QWidget *>(QString(), Qt::FindDirectChildrenOnly).count();
statusBar()->insertPermanentWidget(childsCount - 1, m_toggleRightSideBarButton); // before QSizeGrip
2008-12-02 12:01:29 +01:00
// setUnifiedTitleAndToolBarOnMac(true);
//if (HostOsInfo::isAnyUnixHost())
//signal(SIGINT, handleSigInt);
2008-12-02 12:01:29 +01:00
statusBar()->setProperty("p_styled", true);
auto dropSupport = new DropSupport(this, [](QDropEvent *event, DropSupport *) {
return event->source() == nullptr; // only accept drops from the "outside" (e.g. file manager)
});
connect(dropSupport, &DropSupport::filesDropped,
this, &MainWindow::openDroppedFiles);
2008-12-02 12:01:29 +01:00
}
NavigationWidget *MainWindow::navigationWidget(Side side) const
2008-12-02 12:01:29 +01:00
{
return side == Side::Left ? m_leftNavigationWidget : m_rightNavigationWidget;
2008-12-02 12:01:29 +01:00
}
void MainWindow::setSidebarVisible(bool visible, Side side)
2008-12-02 12:01:29 +01:00
{
if (NavigationWidgetPlaceHolder::current(side))
navigationWidget(side)->setShown(visible);
2008-12-02 12:01:29 +01:00
}
bool MainWindow::askConfirmationBeforeExit() const
{
return m_askConfirmationBeforeExit;
}
void MainWindow::setAskConfirmationBeforeExit(bool ask)
{
m_askConfirmationBeforeExit = ask;
}
void MainWindow::setOverrideColor(const QColor &color)
{
m_overrideColor = color;
}
QStringList MainWindow::additionalAboutInformation() const
{
return m_aboutInformation;
}
void MainWindow::appendAboutInformation(const QString &line)
{
m_aboutInformation.append(line);
}
void MainWindow::addPreCloseListener(const std::function<bool ()> &listener)
{
m_preCloseListeners.append(listener);
}
2008-12-02 12:01:29 +01:00
MainWindow::~MainWindow()
{
// 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;
2008-12-02 12:01:29 +01:00
delete m_messageManager;
m_messageManager = nullptr;
2008-12-02 12:01:29 +01:00
delete m_shortcutSettings;
m_shortcutSettings = nullptr;
2008-12-02 12:01:29 +01:00
delete m_generalSettings;
m_generalSettings = nullptr;
delete m_systemSettings;
m_systemSettings = nullptr;
delete m_toolSettings;
m_toolSettings = nullptr;
delete m_mimeTypeSettings;
m_mimeTypeSettings = nullptr;
delete m_systemEditor;
m_systemEditor = nullptr;
2008-12-02 12:01:29 +01:00
delete m_printer;
m_printer = nullptr;
2008-12-02 12:01:29 +01:00
delete m_vcsManager;
m_vcsManager = nullptr;
2009-12-09 11:05:18 +01:00
//we need to delete editormanager and statusbarmanager explicitly before the end of the destructor,
2008-12-02 12:01:29 +01:00
//because they might trigger stuff that tries to access data from editorwindow, like removeContextWidget
// All modes are now gone
OutputPaneManager::destroy();
2008-12-02 12:01:29 +01:00
delete m_leftNavigationWidget;
delete m_rightNavigationWidget;
m_leftNavigationWidget = nullptr;
m_rightNavigationWidget = nullptr;
2008-12-02 12:01:29 +01:00
delete m_editorManager;
m_editorManager = nullptr;
2008-12-02 12:01:29 +01:00
delete m_progressManager;
m_progressManager = nullptr;
2008-12-02 12:01:29 +01:00
delete m_coreImpl;
m_coreImpl = nullptr;
2008-12-02 12:01:29 +01:00
delete m_rightPaneWidget;
m_rightPaneWidget = nullptr;
2008-12-02 12:01:29 +01:00
delete m_modeManager;
m_modeManager = nullptr;
delete m_jsExpander;
m_jsExpander = nullptr;
2008-12-02 12:01:29 +01:00
}
void MainWindow::init()
2008-12-02 12:01:29 +01:00
{
m_progressManager->init(); // needs the status bar manager
MessageManager::init();
2008-12-02 12:01:29 +01:00
}
void MainWindow::extensionsInitialized()
{
EditorManagerPrivate::extensionsInitialized();
MimeTypeSettings::restoreSettings();
m_windowSupport = new WindowSupport(this, Context("Core.MainWindow"));
m_windowSupport->setCloseActionEnabled(false);
OutputPaneManager::create();
VcsManager::extensionsInitialized();
m_leftNavigationWidget->setFactories(INavigationWidgetFactory::allNavigationFactories());
m_rightNavigationWidget->setFactories(INavigationWidgetFactory::allNavigationFactories());
ModeManager::extensionsInitialized();
2008-12-02 12:01:29 +01:00
readSettings();
updateContext();
emit m_coreImpl->coreAboutToOpen();
// Delay restoreWindowState, since it is overridden by LayoutRequest event
QMetaObject::invokeMethod(this, &MainWindow::restoreWindowState, Qt::QueuedConnection);
QMetaObject::invokeMethod(m_coreImpl, &ICore::coreOpened, Qt::QueuedConnection);
2008-12-02 12:01:29 +01:00
}
static void setRestart(bool restart)
{
qApp->setProperty("restart", restart);
}
void MainWindow::restart()
{
setRestart(true);
exit();
}
2008-12-02 12:01:29 +01: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 (m_askConfirmationBeforeExit &&
(QMessageBox::question(this,
tr("Exit %1?").arg(Constants::IDE_DISPLAY_NAME),
tr("Exit %1?").arg(Constants::IDE_DISPLAY_NAME),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No)
== QMessageBox::No)) {
event->ignore();
return;
}
ICore::saveSettings(ICore::MainWindowClosing);
2008-12-02 12:01:29 +01:00
// Save opened files
if (!DocumentManager::saveAllModifiedDocuments()) {
cancelClose();
2008-12-02 12:01:29 +01:00
return;
}
foreach (const std::function<bool()> &listener, m_preCloseListeners) {
if (!listener()) {
cancelClose();
2008-12-02 12:01:29 +01:00
return;
}
}
emit m_coreImpl->coreAboutToClose();
saveWindowSettings();
m_leftNavigationWidget->closeSubWidgets();
m_rightNavigationWidget->closeSubWidgets();
2008-12-02 12:01:29 +01:00
event->accept();
alreadyClosed = true;
2008-12-02 12:01:29 +01:00
}
void MainWindow::openDroppedFiles(const QList<DropSupport::FileSpec> &files)
{
raiseWindow();
QStringList filePaths = Utils::transform(files, &DropSupport::FileSpec::filePath);
openFiles(filePaths, ICore::SwitchMode);
}
2008-12-02 12:01:29 +01:00
IContext *MainWindow::currentContextObject() const
{
return m_activeContext.isEmpty() ? nullptr : m_activeContext.first();
2008-12-02 12:01:29 +01:00
}
QStatusBar *MainWindow::statusBar() const
{
return m_modeStack->statusBar();
}
InfoBar *MainWindow::infoBar() const
{
return m_modeStack->infoBar();
}
2008-12-02 12:01:29 +01:00
void MainWindow::registerDefaultContainers()
{
ActionContainer *menubar = ActionManager::createMenuBar(Constants::MENU_BAR);
2008-12-02 12:01:29 +01:00
if (!HostOsInfo::isMacHost()) // System menu bar on Mac
setMenuBar(menubar->menuBar());
2008-12-02 12:01:29 +01: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);
2008-12-02 12:01:29 +01:00
menubar->addMenu(filemenu, Constants::G_FILE);
filemenu->menu()->setTitle(tr("&File"));
filemenu->appendGroup(Constants::G_FILE_NEW);
filemenu->appendGroup(Constants::G_FILE_OPEN);
filemenu->appendGroup(Constants::G_FILE_PROJECT);
filemenu->appendGroup(Constants::G_FILE_SAVE);
filemenu->appendGroup(Constants::G_FILE_EXPORT);
2008-12-02 12:01:29 +01:00
filemenu->appendGroup(Constants::G_FILE_CLOSE);
filemenu->appendGroup(Constants::G_FILE_PRINT);
filemenu->appendGroup(Constants::G_FILE_OTHER);
connect(filemenu->menu(), &QMenu::aboutToShow, this, &MainWindow::aboutToShowRecentFiles);
2008-12-02 12:01:29 +01:00
// Edit Menu
ActionContainer *medit = ActionManager::createMenu(Constants::M_EDIT);
2008-12-02 12:01:29 +01:00
menubar->addMenu(medit, Constants::G_EDIT);
medit->menu()->setTitle(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);
2008-12-02 12:01:29 +01:00
medit->appendGroup(Constants::G_EDIT_OTHER);
ActionContainer *mview = ActionManager::createMenu(Constants::M_VIEW);
menubar->addMenu(mview, Constants::G_VIEW);
mview->menu()->setTitle(tr("&View"));
mview->appendGroup(Constants::G_VIEW_VIEWS);
mview->appendGroup(Constants::G_VIEW_PANES);
// Tools Menu
ActionContainer *ac = ActionManager::createMenu(Constants::M_TOOLS);
2008-12-02 12:01:29 +01:00
menubar->addMenu(ac, Constants::G_TOOLS);
ac->menu()->setTitle(tr("&Tools"));
// Window Menu
ActionContainer *mwindow = ActionManager::createMenu(Constants::M_WINDOW);
2008-12-02 12:01:29 +01:00
menubar->addMenu(mwindow, Constants::G_WINDOW);
mwindow->menu()->setTitle(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);
2008-12-02 12:01:29 +01:00
mwindow->appendGroup(Constants::G_WINDOW_OTHER);
// Help Menu
ac = ActionManager::createMenu(Constants::M_HELP);
2008-12-02 12:01:29 +01:00
menubar->addMenu(ac, Constants::G_HELP);
ac->menu()->setTitle(tr("&Help"));
ac->appendGroup(Constants::G_HELP_HELP);
ac->appendGroup(Constants::G_HELP_SUPPORT);
ac->appendGroup(Constants::G_HELP_ABOUT);
ac->appendGroup(Constants::G_HELP_UPDATES);
Add macOS touch bar support Introduce a generic Utils::TouchBar that implements a touch bar for macOS based on QAction. Touch bars can be nested, and one is set to be the application's top level touch bar. Also add an ActionContainer for the touch bar. That allows us to manage the layout of the touch bar the same way we do with menus. Since the touch bar is an input device with very limited space, a command in the touch bar needs to be specifically styled for the touch bar by setting either touchBarText or touchBarIcon (or both). Touch bars can be nested by nesting the ActionContainers. A nested touch bar ActionContainer needs to specify an icon and/or text to show in the touch bar button that opens that sub-bar. Commands are only shown in the touch bar if they are valid within the current context. Implementation-wise we cannot use the standard NSPopoverTouchBarItem for nesting touch bar levels. We cannot hide items in the touch bar, because hidden items still take up space in the touch bar. So we need to rebuild the touch bar regularly. Since the items we show are very dynamic, every time the items in the toplevel bar change because of a context change, any opened sub-level touch bar closes. That is why we maintain a stack of touch bar levels ourselves, replacing the main touch bar with the current level, and managing opening and closing the levels manually. This patch adds buttons for Help, Bookmarks, Header/Source, Follow (Symbol), Decl/Def, and a sub-bar for the debugger actions. Fixes: QTCREATORBUG-21263 Change-Id: Ib63e610f21a993f1d324fe23c83a7f2224f434ac Reviewed-by: Eike Ziller <eike.ziller@qt.io> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: Vikas Pachdha <vikas.pachdha@qt.io>
2018-10-05 13:52:57 +02:00
// 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_EDITOR);
ac->appendGroup(Constants::G_TOUCHBAR_NAVIGATION);
ac->appendGroup(Constants::G_TOUCHBAR_OTHER);
ac->touchBar()->setApplicationTouchBar();
2008-12-02 12:01:29 +01:00
}
void MainWindow::registerDefaultActions()
{
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);
2008-12-02 12:01:29 +01:00
// 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);
2008-12-02 12:01:29 +01:00
// 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);
2008-12-02 12:01:29 +01:00
// Return to editor shortcut: Note this requires Qt to fix up
2008-12-02 12:01:29 +01:00
// handling of shortcut overrides in menus, item views, combos....
m_focusToEditor = new QAction(tr("Return to Editor"), this);
Command *cmd = ActionManager::registerAction(m_focusToEditor, Constants::S_RETURNTOEDITOR);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence(Qt::Key_Escape));
connect(m_focusToEditor, &QAction::triggered, this, &MainWindow::setFocusToEditor);
2008-12-02 12:01:29 +01:00
// New File Action
QIcon icon = QIcon::fromTheme(QLatin1String("document-new"), Utils::Icons::NEWFILE.icon());
m_newAction = new QAction(icon, tr("&New File or Project..."), this);
cmd = ActionManager::registerAction(m_newAction, Constants::NEW);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::New);
mfile->addAction(cmd, Constants::G_FILE_NEW);
connect(m_newAction, &QAction::triggered, this, []() {
if (!ICore::isNewItemDialogRunning()) {
ICore::showNewItemDialog(tr("New File or Project", "Title of dialog"),
IWizardFactory::allWizardFactories(), QString());
} else {
ICore::raiseWindow(ICore::newItemDialog());
}
});
2008-12-02 12:01:29 +01:00
// Open Action
icon = QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon());
m_openAction = new QAction(icon, tr("&Open File or Project..."), this);
cmd = ActionManager::registerAction(m_openAction, Constants::OPEN);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::Open);
mfile->addAction(cmd, Constants::G_FILE_OPEN);
connect(m_openAction, &QAction::triggered, this, &MainWindow::openFile);
2008-12-02 12:01:29 +01:00
// Open With Action
m_openWithAction = new QAction(tr("Open File &With..."), this);
cmd = ActionManager::registerAction(m_openWithAction, Constants::OPEN_WITH);
2008-12-02 12:01:29 +01:00
mfile->addAction(cmd, Constants::G_FILE_OPEN);
connect(m_openWithAction, &QAction::triggered, this, &MainWindow::openFileWith);
2008-12-02 12:01:29 +01:00
// File->Recent Files Menu
ActionContainer *ac = ActionManager::createMenu(Constants::M_FILE_RECENTFILES);
2008-12-02 12:01:29 +01:00
mfile->addMenu(ac, Constants::G_FILE_OPEN);
ac->menu()->setTitle(tr("Recent &Files"));
ac->setOnAllDisabledBehavior(ActionContainer::Show);
2008-12-02 12:01:29 +01:00
// Save Action
icon = QIcon::fromTheme(QLatin1String("document-save"), Utils::Icons::SAVEFILE.icon());
QAction *tmpaction = new QAction(icon, EditorManager::tr("&Save"), this);
tmpaction->setEnabled(false);
cmd = ActionManager::registerAction(tmpaction, Constants::SAVE);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::Save);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(tr("Save"));
2008-12-02 12:01:29 +01:00
mfile->addAction(cmd, Constants::G_FILE_SAVE);
// Save As Action
icon = QIcon::fromTheme(QLatin1String("document-save-as"));
tmpaction = new QAction(icon, EditorManager::tr("Save &As..."), this);
tmpaction->setEnabled(false);
cmd = ActionManager::registerAction(tmpaction, Constants::SAVEAS);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+S") : QString()));
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(tr("Save As..."));
2008-12-02 12:01:29 +01:00
mfile->addAction(cmd, Constants::G_FILE_SAVE);
// SaveAll Action
DocumentManager::registerSaveAllAction();
2008-12-02 12:01:29 +01:00
// Print Action
icon = QIcon::fromTheme(QLatin1String("document-print"));
tmpaction = new QAction(icon, tr("&Print..."), this);
tmpaction->setEnabled(false);
cmd = ActionManager::registerAction(tmpaction, Constants::PRINT);
cmd->setDefaultKeySequence(QKeySequence::Print);
2008-12-02 12:01:29 +01:00
mfile->addAction(cmd, Constants::G_FILE_PRINT);
// Exit Action
icon = QIcon::fromTheme(QLatin1String("application-exit"));
m_exitAction = new QAction(icon, tr("E&xit"), this);
m_exitAction->setMenuRole(QAction::QuitRole);
cmd = ActionManager::registerAction(m_exitAction, Constants::EXIT);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Q")));
mfile->addAction(cmd, Constants::G_FILE_OTHER);
connect(m_exitAction, &QAction::triggered, this, &MainWindow::exit);
2008-12-02 12:01:29 +01:00
// Undo Action
icon = QIcon::fromTheme(QLatin1String("edit-undo"), Utils::Icons::UNDO.icon());
tmpaction = new QAction(icon, tr("&Undo"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::UNDO);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::Undo);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(tr("Undo"));
2008-12-02 12:01:29 +01:00
medit->addAction(cmd, Constants::G_EDIT_UNDOREDO);
tmpaction->setEnabled(false);
2008-12-02 12:01:29 +01:00
// Redo Action
icon = QIcon::fromTheme(QLatin1String("edit-redo"), Utils::Icons::REDO.icon());
tmpaction = new QAction(icon, tr("&Redo"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::REDO);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::Redo);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDescription(tr("Redo"));
2008-12-02 12:01:29 +01:00
medit->addAction(cmd, Constants::G_EDIT_UNDOREDO);
tmpaction->setEnabled(false);
2008-12-02 12:01:29 +01:00
// Cut Action
icon = QIcon::fromTheme(QLatin1String("edit-cut"), Utils::Icons::CUT.icon());
tmpaction = new QAction(icon, tr("Cu&t"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::CUT);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::Cut);
medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
tmpaction->setEnabled(false);
2008-12-02 12:01:29 +01:00
// Copy Action
icon = QIcon::fromTheme(QLatin1String("edit-copy"), Utils::Icons::COPY.icon());
tmpaction = new QAction(icon, tr("&Copy"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::COPY);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::Copy);
medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
tmpaction->setEnabled(false);
2008-12-02 12:01:29 +01:00
// Paste Action
icon = QIcon::fromTheme(QLatin1String("edit-paste"), Utils::Icons::PASTE.icon());
tmpaction = new QAction(icon, tr("&Paste"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::PASTE);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::Paste);
medit->addAction(cmd, Constants::G_EDIT_COPYPASTE);
tmpaction->setEnabled(false);
2008-12-02 12:01:29 +01:00
// Select All
icon = QIcon::fromTheme(QLatin1String("edit-select-all"));
tmpaction = new QAction(icon, tr("Select &All"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::SELECTALL);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence::SelectAll);
medit->addAction(cmd, Constants::G_EDIT_SELECTALL);
tmpaction->setEnabled(false);
2008-12-02 12:01:29 +01:00
// Goto Action
icon = QIcon::fromTheme(QLatin1String("go-jump"));
tmpaction = new QAction(icon, tr("&Go to Line..."), this);
cmd = ActionManager::registerAction(tmpaction, Constants::GOTO);
2008-12-02 12:01:29 +01:00
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+L")));
medit->addAction(cmd, Constants::G_EDIT_OTHER);
tmpaction->setEnabled(false);
2008-12-02 12:01:29 +01:00
// Zoom In Action
icon = QIcon::hasThemeIcon("zoom-in") ? QIcon::fromTheme("zoom-in")
: Utils::Icons::ZOOMIN_TOOLBAR.icon();
tmpaction = new QAction(icon, tr("Zoom In"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::ZOOM_IN);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl++")));
tmpaction->setEnabled(false);
// Zoom Out Action
icon = QIcon::hasThemeIcon("zoom-out") ? QIcon::fromTheme("zoom-out")
: Utils::Icons::ZOOMOUT_TOOLBAR.icon();
tmpaction = new QAction(icon, tr("Zoom Out"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::ZOOM_OUT);
if (useMacShortcuts)
cmd->setDefaultKeySequences({QKeySequence(tr("Ctrl+-")), QKeySequence(tr("Ctrl+Shift+-"))});
else
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+-")));
tmpaction->setEnabled(false);
// Zoom Reset Action
icon = QIcon::hasThemeIcon("zoom-original") ? QIcon::fromTheme("zoom-original")
: Utils::Icons::EYE_OPEN_TOOLBAR.icon();
tmpaction = new QAction(icon, tr("Original Size"), this);
cmd = ActionManager::registerAction(tmpaction, Constants::ZOOM_RESET);
cmd->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? tr("Meta+0") : tr("Ctrl+0")));
tmpaction->setEnabled(false);
// Options Action
mtools->appendGroup(Constants::G_TOOLS_OPTIONS);
mtools->addSeparator(Constants::G_TOOLS_OPTIONS);
Implement theming for QtCreator Adds a 'Theme' tab to the environment settings and a '-theme' command line option. A theme is a combination of colors, gradients, flags and style information. There are two themes: - 'default': preserves the current default look - 'dark': uses a more flat for many widgets, dark color theme for everything This does not use a stylesheet (too limited), but rather sets the palette via C++ and modifies drawing behavior. Overall, the look is more flat (removed some gradients and bevels). Tested on Ubuntu 14.04 using Qt 5.4 and running on a KDE Desktop (Oxygen base style). For a screenshot, see https://gist.github.com/thorbenk/5ab06bea726de0aa7473 Changes: - Introduce class Theme, defining the interface how to access theme specific settings. The class reads a .creatortheme file (INI file, via QSettings) - Define named colors in the [Palette] section (see dark.creatortheme for example usage) - Use either named colors of AARRGGBB (hex) in the [Colors] section - A file ending with .creatortheme may be supplied to the '-theme' command line option - A global Theme instance can be accessed via creatorTheme() - Query colors, gradients, icons and flags from the theme were possible (TODO: use this in more places...) - There are very many color roles. It seems better to me to describe the role clearly, and then to consolidate later in the actual theme by assigning the same color. For example, one can set the text color of the output pane button individualy. - Many elements are also drawn differently. For the dark theme, I wanted to have a flatter look. - Introduce Theme::WidgetStyle enum, for now {Original, Flat}. - The theme specifies which kind of widget style it wants. - The drawing code queries the theme's style flag and switches between the original, gradient based look and the new, flat look. - Create some custom icons which look better on dark background (wip, currently folder/file icons) - Let ManhattanStyle draw some elements for non-panelwidgets, too (open/close arrows in QTreeView, custom folder/file icons) - For the welcomescreen, pass the WelcomeTheme class. WelcomeTheme exposes theme colors as Q_PROPERTY accessible from .qml - Themes can be modified via the 'Themes' tab in the environment settings. TODO: * Unify image handling * Avoid style name references * Fix gradients Change-Id: I92c2050ab0fb327649ea1eff4adec973d2073944 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com> Reviewed-by: hjk <hjk121@nokiamail.com>
2014-10-14 19:09:48 +02:00
2008-12-02 12:01:29 +01:00
m_optionsAction = new QAction(tr("&Options..."), this);
m_optionsAction->setMenuRole(QAction::PreferencesRole);
cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS);
cmd->setDefaultKeySequence(QKeySequence::Preferences);
mtools->addAction(cmd, Constants::G_TOOLS_OPTIONS);
connect(m_optionsAction, &QAction::triggered, this, [] { ICore::showOptionsDialog(Id()); });
2008-12-02 12:01:29 +01:00
mwindow->addSeparator(Constants::G_WINDOW_LIST);
if (useMacShortcuts) {
// Minimize Action
QAction *minimizeAction = new QAction(tr("Minimize"), this);
minimizeAction->setEnabled(false); // actual implementation in WindowSupport
cmd = ActionManager::registerAction(minimizeAction, Constants::MINIMIZE_WINDOW);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+M")));
mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
// Zoom Action
QAction *zoomAction = new QAction(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("Full Screen"), this);
toggleFullScreenAction->setCheckable(!HostOsInfo::isMacHost());
toggleFullScreenAction->setEnabled(false); // actual implementation in WindowSupport
cmd = ActionManager::registerAction(toggleFullScreenAction, Constants::TOGGLE_FULLSCREEN);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Meta+F") : 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);
2008-12-02 12:01:29 +01:00
QAction *closeAction = new QAction(tr("Close Window"), this);
closeAction->setEnabled(false);
cmd = ActionManager::registerAction(closeAction, Constants::CLOSE_WINDOW);
cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Meta+W")));
mwindow->addAction(cmd, Constants::G_WINDOW_SIZE);
mwindow->addSeparator(Constants::G_WINDOW_SIZE);
}
2008-12-02 12:01:29 +01:00
// Show Left Sidebar Action
m_toggleLeftSideBarAction = new QAction(Utils::Icons::TOGGLE_LEFT_SIDEBAR.icon(),
QCoreApplication::translate("Core", Constants::TR_SHOW_LEFT_SIDEBAR),
this);
m_toggleLeftSideBarAction->setCheckable(true);
cmd = ActionManager::registerAction(m_toggleLeftSideBarAction, Constants::TOGGLE_LEFT_SIDEBAR);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+0") : tr("Alt+0")));
connect(m_toggleLeftSideBarAction, &QAction::triggered,
this, [this](bool visible) { setSidebarVisible(visible, Side::Left); });
ProxyAction *toggleLeftSideBarProxyAction =
ProxyAction::proxyActionWithIcon(cmd->action(), Utils::Icons::TOGGLE_LEFT_SIDEBAR_TOOLBAR.icon());
m_toggleLeftSideBarButton->setDefaultAction(toggleLeftSideBarProxyAction);
mview->addAction(cmd, Constants::G_VIEW_VIEWS);
m_toggleLeftSideBarAction->setEnabled(false);
// Show Right Sidebar Action
m_toggleRightSideBarAction = new QAction(Utils::Icons::TOGGLE_RIGHT_SIDEBAR.icon(),
QCoreApplication::translate("Core", Constants::TR_SHOW_RIGHT_SIDEBAR),
this);
m_toggleRightSideBarAction->setCheckable(true);
cmd = ActionManager::registerAction(m_toggleRightSideBarAction, Constants::TOGGLE_RIGHT_SIDEBAR);
cmd->setAttribute(Command::CA_UpdateText);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? tr("Ctrl+Shift+0") : tr("Alt+Shift+0")));
connect(m_toggleRightSideBarAction, &QAction::triggered,
this, [this](bool visible) { setSidebarVisible(visible, Side::Right); });
ProxyAction *toggleRightSideBarProxyAction =
ProxyAction::proxyActionWithIcon(cmd->action(), Utils::Icons::TOGGLE_RIGHT_SIDEBAR_TOOLBAR.icon());
m_toggleRightSideBarButton->setDefaultAction(toggleRightSideBarProxyAction);
mview->addAction(cmd, Constants::G_VIEW_VIEWS);
m_toggleRightSideBarButton->setEnabled(false);
2008-12-02 12:01:29 +01:00
registerModeSelectorStyleActions();
// Window->Views
ActionContainer *mviews = ActionManager::createMenu(Constants::M_VIEW_VIEWS);
mview->addMenu(mviews, Constants::G_VIEW_VIEWS);
mviews->menu()->setTitle(tr("&Views"));
// "Help" separators
mhelp->addSeparator(Constants::G_HELP_SUPPORT);
if (!HostOsInfo::isMacHost())
mhelp->addSeparator(Constants::G_HELP_ABOUT);
// About IDE Action
icon = QIcon::fromTheme(QLatin1String("help-about"));
if (HostOsInfo::isMacHost())
tmpaction = new QAction(icon, tr("About &%1").arg(Constants::IDE_DISPLAY_NAME), this); // it's convention not to add dots to the about menu
else
tmpaction = new QAction(icon, tr("About &%1...").arg(Constants::IDE_DISPLAY_NAME), this);
tmpaction->setMenuRole(QAction::AboutRole);
cmd = ActionManager::registerAction(tmpaction, Constants::ABOUT_QTCREATOR);
mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
tmpaction->setEnabled(true);
connect(tmpaction, &QAction::triggered, this, &MainWindow::aboutQtCreator);
2008-12-02 12:01:29 +01:00
//About Plugins Action
tmpaction = new QAction(tr("About &Plugins..."), this);
tmpaction->setMenuRole(QAction::ApplicationSpecificRole);
cmd = ActionManager::registerAction(tmpaction, Constants::ABOUT_PLUGINS);
mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
tmpaction->setEnabled(true);
connect(tmpaction, &QAction::triggered, this, &MainWindow::aboutPlugins);
// About Qt Action
2008-12-02 12:01:29 +01:00
// tmpaction = new QAction(tr("About &Qt..."), this);
// cmd = ActionManager::registerAction(tmpaction, Constants:: ABOUT_QT);
2008-12-02 12:01:29 +01:00
// mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
// tmpaction->setEnabled(true);
// connect(tmpaction, &QAction::triggered, qApp, &QApplication::aboutQt);
// Contact
tmpaction = new QAction(tr("Contact..."), this);
cmd = ActionManager::registerAction(tmpaction, "QtCreator.Contact");
mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
tmpaction->setEnabled(true);
connect(tmpaction, &QAction::triggered, this, &MainWindow::contact);
2008-12-02 12:01:29 +01:00
// About sep
if (!HostOsInfo::isMacHost()) { // doesn't have the "About" actions in the Help menu
tmpaction = new QAction(this);
tmpaction->setSeparator(true);
cmd = ActionManager::registerAction(tmpaction, "QtCreator.Help.Sep.About");
mhelp->addAction(cmd, Constants::G_HELP_ABOUT);
}
2008-12-02 12:01:29 +01:00
}
void MainWindow::registerModeSelectorStyleActions()
{
ActionContainer *mview = ActionManager::actionContainer(Constants::M_VIEW);
// Cycle Mode Selector Styles
m_cycleModeSelectorStyleAction = new QAction(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("Mode Selector Style"));
auto *stylesGroup = new QActionGroup(styleMenu);
stylesGroup->setExclusive(true);
m_setModeSelectorStyleIconsAndTextAction = stylesGroup->addAction(tr("Icons and Text"));
connect(m_setModeSelectorStyleIconsAndTextAction, &QAction::triggered,
[] { ModeManager::setModeStyle(ModeManager::Style::IconsAndText); });
m_setModeSelectorStyleIconsAndTextAction->setCheckable(true);
m_setModeSelectorStyleIconsOnlyAction = stylesGroup->addAction(tr("Icons Only"));
connect(m_setModeSelectorStyleIconsOnlyAction, &QAction::triggered,
[] { ModeManager::setModeStyle(ModeManager::Style::IconsOnly); });
m_setModeSelectorStyleIconsOnlyAction->setCheckable(true);
m_setModeSelectorStyleHiddenAction = stylesGroup->addAction(tr("Hidden"));
connect(m_setModeSelectorStyleHiddenAction, &QAction::triggered,
[] { ModeManager::setModeStyle(ModeManager::Style::Hidden); });
m_setModeSelectorStyleHiddenAction->setCheckable(true);
styleMenu->addActions(stylesGroup->actions());
}
2008-12-02 12:01:29 +01:00
void MainWindow::openFile()
{
openFiles(EditorManager::getOpenFileNames(), ICore::SwitchMode);
2008-12-02 12:01:29 +01:00
}
static IDocumentFactory *findDocumentFactory(const QList<IDocumentFactory*> &fileFactories,
2008-12-02 12:01:29 +01:00
const QFileInfo &fi)
{
const QString typeName = Utils::mimeTypeForFile(fi).name();
return Utils::findOrDefault(fileFactories, [typeName](IDocumentFactory *f) {
return f->mimeTypes().contains(typeName);
});
2008-12-02 12:01:29 +01:00
}
/*!
* \internal
* Either opens \a fileNames 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()
*/
IDocument *MainWindow::openFiles(const QStringList &fileNames,
ICore::OpenFilesFlags flags,
const QString &workingDirectory)
2008-12-02 12:01:29 +01:00
{
const QList<IDocumentFactory*> documentFactories = IDocumentFactory::allDocumentFactories();
IDocument *res = nullptr;
2008-12-02 12:01:29 +01:00
for (const QString &fileName : fileNames) {
const QDir workingDir(workingDirectory.isEmpty() ? QDir::currentPath() : workingDirectory);
const QFileInfo fi(workingDir, fileName);
2008-12-02 12:01:29 +01:00
const QString absoluteFilePath = fi.absoluteFilePath();
if (IDocumentFactory *documentFactory = findDocumentFactory(documentFactories, fi)) {
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));
}
2008-12-02 12:01:29 +01:00
} else {
QFlags<EditorManager::OpenEditorFlag> emFlags;
if (flags & ICore::CanContainLineAndColumnNumbers)
emFlags |= EditorManager::CanContainLineAndColumnNumber;
if (flags & ICore::SwitchSplitIfAlreadyVisible)
emFlags |= EditorManager::SwitchSplitIfAlreadyVisible;
if (emFlags != EditorManager::NoFlags || !res) {
IEditor *editor = EditorManager::openEditor(absoluteFilePath, Id(), 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());
}
2008-12-02 12:01:29 +01:00
}
}
return res;
2008-12-02 12:01:29 +01:00
}
void MainWindow::setFocusToEditor()
{
EditorManagerPrivate::doEscapeKeyFocusMoveMagic();
2008-12-02 12:01:29 +01:00
}
void MainWindow::exit()
{
// 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(this, &QWidget::close, Qt::QueuedConnection);
2008-12-02 12:01:29 +01:00
}
void MainWindow::openFileWith()
{
foreach (const QString &fileName, EditorManager::getOpenFileNames()) {
bool isExternal;
const Id editorId = EditorManagerPrivate::getOpenWithEditorId(fileName, &isExternal);
if (!editorId.isValid())
2008-12-02 12:01:29 +01:00
continue;
if (isExternal)
EditorManager::openExternalEditor(FilePath::fromString(fileName), editorId);
else
EditorManagerPrivate::openEditorWith(FilePath::fromString(fileName), editorId);
2008-12-02 12:01:29 +01:00
}
}
IContext *MainWindow::contextObject(QWidget *widget) const
2008-12-02 12:01:29 +01:00
{
const auto it = m_contextWidgets.find(widget);
return it == m_contextWidgets.end() ? nullptr : it->second;
2008-12-02 12:01:29 +01:00
}
void MainWindow::addContextObject(IContext *context)
{
if (!context)
return;
QWidget *widget = context->widget();
if (m_contextWidgets.find(widget) != m_contextWidgets.end())
2008-12-02 12:01:29 +01:00
return;
m_contextWidgets.insert(std::make_pair(widget, context));
connect(context, &QObject::destroyed, this, [this, context] { removeContextObject(context); });
2008-12-02 12:01:29 +01:00
}
void MainWindow::removeContextObject(IContext *context)
{
if (!context)
return;
disconnect(context, &QObject::destroyed, this, nullptr);
const auto it = std::find_if(m_contextWidgets.cbegin(),
m_contextWidgets.cend(),
[context](const std::pair<QWidget *, IContext *> &v) {
return v.second == context;
});
if (it == m_contextWidgets.cend())
2008-12-02 12:01:29 +01:00
return;
m_contextWidgets.erase(it);
if (m_activeContext.removeAll(context) > 0)
updateContextObject(m_activeContext);
2008-12-02 12:01:29 +01:00
}
void MainWindow::updateFocusWidget(QWidget *old, QWidget *now)
{
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;
2008-12-02 12:01:29 +01:00
while (p) {
context = contextObject(p);
if (context)
newContext.append(context);
2008-12-02 12:01:29 +01:00
p = p->parentWidget();
}
}
// ignore toplevels that define no context, like popups without parent
if (!newContext.isEmpty() || QApplication::focusWidget() == focusWidget())
updateContextObject(newContext);
2008-12-02 12:01:29 +01:00
}
void MainWindow::updateContextObject(const QList<IContext *> &context)
2008-12-02 12:01:29 +01:00
{
emit m_coreImpl->contextAboutToChange(context);
2008-12-02 12:01:29 +01:00
m_activeContext = context;
updateContext();
if (debugMainWindow) {
qDebug() << "new context objects =" << context;
foreach (IContext *c, context)
qDebug() << (c ? c->widget() : nullptr) << (c ? c->widget()->metaObject()->className() : nullptr);
}
2008-12-02 12:01:29 +01:00
}
void MainWindow::aboutToShutdown()
{
disconnect(qApp, &QApplication::focusChanged, this, &MainWindow::updateFocusWidget);
for (auto contextPair : m_contextWidgets)
disconnect(contextPair.second, &QObject::destroyed, this, nullptr);
m_activeContext.clear();
hide();
}
static const char settingsGroup[] = "MainWindow";
static const char colorKey[] = "Color";
static const char askBeforeExitKey[] = "AskBeforeExit";
static const char windowGeometryKey[] = "WindowGeometry";
static const char windowStateKey[] = "WindowState";
static const char modeSelectorLayoutKey[] = "ModeSelectorLayout";
static const bool askBeforeExitDefault = false;
2008-12-02 12:01:29 +01:00
void MainWindow::readSettings()
{
QSettings *settings = PluginManager::settings();
settings->beginGroup(QLatin1String(settingsGroup));
if (m_overrideColor.isValid()) {
StyleHelper::setBaseColor(m_overrideColor);
// Get adapted base color.
m_overrideColor = StyleHelper::baseColor();
} else {
StyleHelper::setBaseColor(settings->value(QLatin1String(colorKey),
QColor(StyleHelper::DEFAULT_BASE_COLOR)).value<QColor>());
}
m_askConfirmationBeforeExit = settings->value(askBeforeExitKey, askBeforeExitDefault).toBool();
{
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();
}
settings->endGroup();
EditorManagerPrivate::readSettings();
m_leftNavigationWidget->restoreSettings(settings);
m_rightNavigationWidget->restoreSettings(settings);
m_rightPaneWidget->readSettings(settings);
2008-12-02 12:01:29 +01:00
}
void MainWindow::saveSettings()
2008-12-02 12:01:29 +01:00
{
QtcSettings *settings = PluginManager::settings();
settings->beginGroup(QLatin1String(settingsGroup));
if (!(m_overrideColor.isValid() && StyleHelper::baseColor() == m_overrideColor))
settings->setValueWithDefault(colorKey,
StyleHelper::requestedBaseColor(),
QColor(StyleHelper::DEFAULT_BASE_COLOR));
settings->setValueWithDefault(askBeforeExitKey,
m_askConfirmationBeforeExit,
askBeforeExitDefault);
settings->endGroup();
DocumentManager::saveSettings();
ActionManager::saveSettings();
EditorManagerPrivate::saveSettings();
m_leftNavigationWidget->saveSettings(settings);
m_rightNavigationWidget->saveSettings(settings);
}
void MainWindow::saveWindowSettings()
{
QSettings *settings = PluginManager::settings();
settings->beginGroup(QLatin1String(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
if (Utils::HostOsInfo::isMacHost() && isFullScreen())
setWindowState(windowState() & ~Qt::WindowFullScreen);
settings->setValue(QLatin1String(windowGeometryKey), saveGeometry());
settings->setValue(QLatin1String(windowStateKey), saveState());
settings->setValue(modeSelectorLayoutKey, int(ModeManager::modeStyle()));
settings->endGroup();
2008-12-02 12:01:29 +01:00
}
void MainWindow::updateModeSelectorStyleMenu()
{
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;
}
}
void MainWindow::updateAdditionalContexts(const Context &remove, const Context &add,
ICore::ContextPriority priority)
2008-12-02 12:01:29 +01:00
{
foreach (const Id id, remove) {
if (!id.isValid())
continue;
int index = m_lowPrioAdditionalContexts.indexOf(id);
if (index != -1)
m_lowPrioAdditionalContexts.removeAt(index);
index = m_highPrioAdditionalContexts.indexOf(id);
if (index != -1)
m_highPrioAdditionalContexts.removeAt(index);
}
2008-12-02 12:01:29 +01:00
foreach (const Id id, add) {
if (!id.isValid())
continue;
Context &cref = (priority == ICore::ContextPriority::High ? m_highPrioAdditionalContexts
: m_lowPrioAdditionalContexts);
if (!cref.contains(id))
cref.prepend(id);
}
updateContext();
2008-12-02 12:01:29 +01:00
}
void MainWindow::updateContext()
{
Context contexts = m_highPrioAdditionalContexts;
2008-12-02 12:01:29 +01:00
foreach (IContext *context, m_activeContext)
contexts.add(context->context());
2008-12-02 12:01:29 +01:00
contexts.add(m_lowPrioAdditionalContexts);
2008-12-02 12:01:29 +01:00
Context uniquecontexts;
for (const Id &id : qAsConst(contexts)) {
if (!uniquecontexts.contains(id))
uniquecontexts.add(id);
2008-12-02 12:01:29 +01:00
}
ActionManager::setContext(uniquecontexts);
emit m_coreImpl->contextChanged(uniquecontexts);
2008-12-02 12:01:29 +01:00
}
void MainWindow::aboutToShowRecentFiles()
{
ActionContainer *aci = ActionManager::actionContainer(Constants::M_FILE_RECENTFILES);
QMenu *menu = aci->menu();
menu->clear();
2008-12-02 12:01:29 +01:00
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(QDir::toNativeSeparators(withTildeHomePath(file.first)));
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);
});
2008-12-02 12:01:29 +01:00
}
bool hasRecentFiles = !recentFiles.isEmpty();
menu->setEnabled(hasRecentFiles);
// add the Clear Menu item
if (hasRecentFiles) {
menu->addSeparator();
QAction *action = menu->addAction(QCoreApplication::translate(
"Core", Constants::TR_CLEAR_MENU));
connect(action, &QAction::triggered,
DocumentManager::instance(), &DocumentManager::clearRecentFiles);
2008-12-02 12:01:29 +01:00
}
}
void MainWindow::aboutQtCreator()
{
if (!m_versionDialog) {
m_versionDialog = new VersionDialog(this);
connect(m_versionDialog, &QDialog::finished,
this, &MainWindow::destroyVersionDialog);
ICore::registerWindow(m_versionDialog, Context("Core.VersionDialog"));
m_versionDialog->show();
} else {
ICore::raiseWindow(m_versionDialog);
}
}
void MainWindow::destroyVersionDialog()
{
if (m_versionDialog) {
m_versionDialog->deleteLater();
m_versionDialog = nullptr;
}
2008-12-02 12:01:29 +01:00
}
void MainWindow::aboutPlugins()
{
PluginDialog dialog(this);
2008-12-02 12:01:29 +01:00
dialog.exec();
}
void MainWindow::contact()
{
QMessageBox dlg(QMessageBox::Information, tr("Contact"),
tr("<p>Qt Creator developers can be reached at the Qt Creator mailing list:</p>"
"%1"
"<p>or the #qt-creator channel on FreeNode IRC:</p>"
"%2"
"<p>Our bug tracker is located at %3.</p>"
"<p>Please use %4 for bigger chunks of text.</p>")
.arg("<p>&nbsp;&nbsp;&nbsp;&nbsp;"
"<a href=\"https://lists.qt-project.org/listinfo/qt-creator\">"
"mailto:qt-creator@qt-project.org"
"</a></p>")
.arg("<p>&nbsp;&nbsp;&nbsp;&nbsp;"
"<a href=\"https://irc.freenode.org\">"
"irc://freenode.org/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>"),
QMessageBox::Ok, this);
dlg.exec();
}
2008-12-02 12:01:29 +01:00
QPrinter *MainWindow::printer() const
{
if (!m_printer)
m_printer = new QPrinter(QPrinter::HighResolution);
return m_printer;
2008-12-02 12:01:29 +01:00
}
2009-01-19 14:12:39 +01:00
void MainWindow::restoreWindowState()
{
QSettings *settings = PluginManager::settings();
settings->beginGroup(QLatin1String(settingsGroup));
if (!restoreGeometry(settings->value(QLatin1String(windowGeometryKey)).toByteArray()))
resize(1260, 700); // size without window decoration
restoreState(settings->value(QLatin1String(windowStateKey)).toByteArray());
settings->endGroup();
show();
StatusBarManager::restoreSettings();
}
} // namespace Internal
} // namespace Core