/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** 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. ** ****************************************************************************/ #include "debuggermainwindow.h" #include "debuggerconstants.h" #include "debuggerinternalconstants.h" #include "analyzer/analyzericons.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Debugger; using namespace Core; namespace Utils { const char LAST_PERSPECTIVE_KEY[] = "LastPerspective"; DebuggerMainWindow::DebuggerMainWindow() { m_controlsStackWidget = new QStackedWidget; m_statusLabel = new Utils::StatusLabel; m_perspectiveChooser = new QComboBox; m_perspectiveChooser->setObjectName(QLatin1String("PerspectiveChooser")); connect(m_perspectiveChooser, static_cast(&QComboBox::activated), this, [this](int item) { restorePerspective(m_perspectiveChooser->itemData(item).toByteArray()); }); setDockNestingEnabled(true); setDockActionsVisible(false); setDocumentMode(true); connect(this, &FancyMainWindow::resetLayout, this, &DebuggerMainWindow::resetCurrentPerspective); } DebuggerMainWindow::~DebuggerMainWindow() { // We keep track of widgets for operations that haven't been activated, yet, and make sure we // don't leak any. foreach (const Perspective &perspective, m_perspectiveForPerspectiveId) { foreach (const Perspective::Operation &operation, perspective.operations()) { if (operation.widget) { // There are two possible states: Either addDockForWidget(widget) has // been called on an operation.widget (e.g. when the perspective gets // activated for the first time), or not. In the first case we don't // have to explicitly delete it as we have called setParent(this) on // it. In the second case, if the widget didn't have a parent before, // we have to delete it. if (!operation.widget->parentWidget()) { // These are from perspectives that were never activated and didn't // have a parent to begin with. delete operation.widget; } } } } } void DebuggerMainWindow::registerPerspective(const QByteArray &perspectiveId, const Perspective &perspective) { m_perspectiveForPerspectiveId.insert(perspectiveId, perspective); m_perspectiveChooser->addItem(perspective.name(), perspectiveId); // adjust width if necessary const int oldWidth = m_perspectiveChooser->width(); const int contentWidth = m_perspectiveChooser->fontMetrics().width(perspective.name()); QStyleOptionComboBox option; option.initFrom(m_perspectiveChooser); const QSize sz(contentWidth, 1); const int width = m_perspectiveChooser->style()->sizeFromContents( QStyle::CT_ComboBox, &option, sz).width(); if (width > oldWidth) m_perspectiveChooser->setFixedWidth(width); } void DebuggerMainWindow::registerToolbar(const QByteArray &perspectiveId, QWidget *widget) { m_toolbarForPerspectiveId.insert(perspectiveId, widget); m_controlsStackWidget->addWidget(widget); } void DebuggerMainWindow::showStatusMessage(const QString &message, int timeoutMS) { m_statusLabel->showStatusMessage(message, timeoutMS); } QDockWidget *DebuggerMainWindow::dockWidget(const QByteArray &dockId) const { return m_dockForDockId.value(dockId); } void DebuggerMainWindow::resetCurrentPerspective() { loadPerspectiveHelper(m_currentPerspectiveId, false); } void DebuggerMainWindow::restorePerspective(const QByteArray &perspectiveId) { loadPerspectiveHelper(perspectiveId, true); int index = m_perspectiveChooser->findData(perspectiveId); if (index == -1) index = m_perspectiveChooser->findData(m_currentPerspectiveId); if (index != -1) m_perspectiveChooser->setCurrentIndex(index); } void DebuggerMainWindow::finalizeSetup() { auto viewButton = new QToolButton; viewButton->setText(tr("Views")); auto toolbar = new Utils::StyledBar; toolbar->setProperty("topBorder", true); auto hbox = new QHBoxLayout(toolbar); hbox->setMargin(0); hbox->setSpacing(0); hbox->addWidget(m_perspectiveChooser); hbox->addWidget(m_controlsStackWidget); hbox->addWidget(m_statusLabel); hbox->addStretch(); hbox->addWidget(new Utils::StyledSeparator); hbox->addWidget(viewButton); connect(viewButton, &QAbstractButton::clicked, [this, viewButton] { QMenu menu; addDockActionsToMenu(&menu); menu.exec(viewButton->mapToGlobal(QPoint())); }); Context debugcontext(Debugger::Constants::C_DEBUGMODE); ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS); Command *cmd = ActionManager::registerAction(menuSeparator1(), "Debugger.Views.Separator1", debugcontext); cmd->setAttribute(Command::CA_Hide); viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); cmd = ActionManager::registerAction(autoHideTitleBarsAction(), "Debugger.Views.AutoHideTitleBars", debugcontext); cmd->setAttribute(Command::CA_Hide); viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); cmd = ActionManager::registerAction(menuSeparator2(), "Debugger.Views.Separator2", debugcontext); cmd->setAttribute(Command::CA_Hide); viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); cmd = ActionManager::registerAction(resetLayoutAction(), "Debugger.Views.ResetSimple", debugcontext); cmd->setAttribute(Command::CA_Hide); viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); addDockActionsToMenu(viewsMenu->menu()); auto dock = new QDockWidget(tr("Toolbar")); dock->setObjectName(QLatin1String("Toolbar")); dock->setFeatures(QDockWidget::NoDockWidgetFeatures); dock->setAllowedAreas(Qt::BottomDockWidgetArea); dock->setTitleBarWidget(new QWidget(dock)); // hide title bar dock->setProperty("managed_dockwidget", QLatin1String("true")); dock->setWidget(toolbar); m_toolbarDock = dock; addDockWidget(Qt::BottomDockWidgetArea, dock); } QWidget *createModeWindow(Core::IMode *mode, DebuggerMainWindow *mainWindow, QWidget *central) { if (!central) central = new EditorManagerPlaceHolder(mode); auto editorHolderLayout = new QVBoxLayout; editorHolderLayout->setMargin(0); editorHolderLayout->setSpacing(0); auto editorAndFindWidget = new QWidget; editorAndFindWidget->setLayout(editorHolderLayout); editorHolderLayout->addWidget(central); editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); auto documentAndRightPane = new MiniSplitter; documentAndRightPane->addWidget(editorAndFindWidget); documentAndRightPane->addWidget(new RightPanePlaceHolder(mode)); documentAndRightPane->setStretchFactor(0, 1); documentAndRightPane->setStretchFactor(1, 0); auto centralEditorWidget = new QWidget; auto centralLayout = new QVBoxLayout(centralEditorWidget); centralEditorWidget->setLayout(centralLayout); centralLayout->setMargin(0); centralLayout->setSpacing(0); centralLayout->addWidget(documentAndRightPane); centralLayout->setStretch(0, 1); centralLayout->setStretch(1, 0); // Right-side window with editor, output etc. auto mainWindowSplitter = new MiniSplitter; mainWindowSplitter->addWidget(mainWindow); mainWindowSplitter->addWidget(new OutputPanePlaceHolder(mode, mainWindowSplitter)); auto outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter); outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder")); mainWindowSplitter->addWidget(outputPane); mainWindowSplitter->setStretchFactor(0, 10); mainWindowSplitter->setStretchFactor(1, 0); mainWindowSplitter->setOrientation(Qt::Vertical); // Navigation and right-side window. auto splitter = new MiniSplitter; splitter->setFocusProxy(central); splitter->addWidget(new NavigationWidgetPlaceHolder(mode)); splitter->addWidget(mainWindowSplitter); splitter->setStretchFactor(0, 0); splitter->setStretchFactor(1, 1); splitter->setObjectName(QLatin1String("DebugModeWidget")); mainWindow->setCentralWidget(centralEditorWidget); return splitter; } void DebuggerMainWindow::loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings) { // Clean up old perspective. if (!m_currentPerspectiveId.isEmpty()) { saveCurrentPerspective(); foreach (QDockWidget *dockWidget, m_dockForDockId) { QTC_ASSERT(dockWidget, continue); dockWidget->setFloating(false); dockWidget->setParent(this); removeDockWidget(dockWidget); dockWidget->hide(); } ICore::removeAdditionalContext(Context(Id::fromName(m_currentPerspectiveId))); } m_currentPerspectiveId = perspectiveId; if (m_currentPerspectiveId.isEmpty()) { const QSettings *settings = ICore::settings(); m_currentPerspectiveId = settings->value(QLatin1String(LAST_PERSPECTIVE_KEY)).toByteArray(); if (m_currentPerspectiveId.isEmpty()) m_currentPerspectiveId = Debugger::Constants::CppPerspectiveId; } ICore::addAdditionalContext(Context(Id::fromName(m_currentPerspectiveId))); QTC_ASSERT(m_perspectiveForPerspectiveId.contains(m_currentPerspectiveId), return); const Perspective perspective = m_perspectiveForPerspectiveId.value(m_currentPerspectiveId); for (const Perspective::Operation &operation : perspective.operations()) { QDockWidget *dock = m_dockForDockId.value(operation.dockId); if (!dock) { QTC_CHECK(!operation.widget->objectName().isEmpty()); dock = registerDockWidget(operation.dockId, operation.widget); QAction *toggleViewAction = dock->toggleViewAction(); toggleViewAction->setText(dock->windowTitle()); Command *cmd = ActionManager::registerAction(toggleViewAction, Id("Dock.").withSuffix(dock->objectName()), Context(Id::fromName(m_currentPerspectiveId))); cmd->setAttribute(Command::CA_Hide); ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd); } if (operation.operationType == Perspective::Raise) { dock->raise(); continue; } addDockWidget(operation.area, dock); QDockWidget *anchor = m_dockForDockId.value(operation.anchorDockId); if (!anchor && operation.area == Qt::BottomDockWidgetArea) anchor = m_toolbarDock; if (anchor) { switch (operation.operationType) { case Perspective::AddToTab: tabifyDockWidget(anchor, dock); break; case Perspective::SplitHorizontal: splitDockWidget(anchor, dock, Qt::Horizontal); break; case Perspective::SplitVertical: splitDockWidget(anchor, dock, Qt::Vertical); break; default: break; } } if (!operation.visibleByDefault) dock->hide(); else dock->show(); } if (fromStoredSettings) { QSettings *settings = ICore::settings(); settings->beginGroup(QString::fromLatin1(m_currentPerspectiveId)); if (settings->value(QLatin1String("ToolSettingsSaved"), false).toBool()) restoreSettings(settings); settings->endGroup(); } QTC_CHECK(m_toolbarForPerspectiveId.contains(m_currentPerspectiveId)); m_controlsStackWidget->setCurrentWidget(m_toolbarForPerspectiveId.value(m_currentPerspectiveId)); m_statusLabel->clear(); } void DebuggerMainWindow::saveCurrentPerspective() { if (m_currentPerspectiveId.isEmpty()) return; QSettings *settings = ICore::settings(); settings->beginGroup(QString::fromLatin1(m_currentPerspectiveId)); saveSettings(settings); settings->setValue(QLatin1String("ToolSettingsSaved"), true); settings->endGroup(); settings->setValue(QLatin1String(LAST_PERSPECTIVE_KEY), m_currentPerspectiveId); } QDockWidget *DebuggerMainWindow::registerDockWidget(const QByteArray &dockId, QWidget *widget) { QTC_ASSERT(!widget->objectName().isEmpty(), return 0); QDockWidget *dockWidget = addDockForWidget(widget); dockWidget->setParent(this); m_dockForDockId[dockId] = dockWidget; return dockWidget; } QString Perspective::name() const { return m_name; } void Perspective::setName(const QString &name) { m_name = name; } QList ToolbarDescription::widgets() const { return m_widgets; } void ToolbarDescription::addAction(QAction *action) { auto button = new QToolButton; button->setDefaultAction(action); m_widgets.append(button); } void ToolbarDescription::addWidget(QWidget *widget) { m_widgets.append(widget); } Perspective::Operation::Operation(const QByteArray &dockId, QWidget *widget, const QByteArray &anchorDockId, Perspective::OperationType splitType, bool visibleByDefault, Qt::DockWidgetArea area) : dockId(dockId), widget(widget), anchorDockId(anchorDockId), operationType(splitType), visibleByDefault(visibleByDefault), area(area) {} Perspective::Perspective(const QString &name, const QVector &splits) : m_name(name), m_operations(splits) { for (const Operation &split : splits) m_docks.append(split.dockId); } void Perspective::addOperation(const Operation &operation) { m_docks.append(operation.dockId); m_operations.append(operation); } } // Utils