forked from qt-creator/qt-creator
This change might help first-time users getting started. Task-number: QTCREATORBUG-20674 Change-Id: If55402160bf6b1515142bb64f281654fe4c68134 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
428 lines
13 KiB
C++
428 lines
13 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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 <extensionsystem/iplugin.h>
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
#include <app/app_version.h>
|
|
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
|
#include <coreplugin/actionmanager/command.h>
|
|
#include <coreplugin/coreconstants.h>
|
|
#include <coreplugin/icore.h>
|
|
#include <coreplugin/imode.h>
|
|
#include <coreplugin/iwelcomepage.h>
|
|
#include <coreplugin/iwizardfactory.h>
|
|
#include <coreplugin/modemanager.h>
|
|
|
|
#include <utils/algorithm.h>
|
|
#include <utils/icon.h>
|
|
#include <utils/fileutils.h>
|
|
#include <utils/hostosinfo.h>
|
|
#include <utils/qtcassert.h>
|
|
#include <utils/styledbar.h>
|
|
#include <utils/treemodel.h>
|
|
#include <utils/theme/theme.h>
|
|
|
|
#include <QDesktopServices>
|
|
#include <QHeaderView>
|
|
#include <QLabel>
|
|
#include <QMouseEvent>
|
|
#include <QOpenGLWidget>
|
|
#include <QPainter>
|
|
#include <QScrollArea>
|
|
#include <QStackedWidget>
|
|
#include <QTimer>
|
|
#include <QVBoxLayout>
|
|
|
|
using namespace Core;
|
|
using namespace ExtensionSystem;
|
|
using namespace Utils;
|
|
|
|
namespace Welcome {
|
|
namespace Internal {
|
|
|
|
class SideBar;
|
|
|
|
const int lrPadding = 34;
|
|
const char currentPageSettingsKeyC[] = "Welcome2Tab";
|
|
|
|
static QColor themeColor(Theme::Color role)
|
|
{
|
|
return Utils::creatorTheme()->color(role);
|
|
}
|
|
|
|
static QFont sizedFont(int size, const QWidget *widget, bool underline = false)
|
|
{
|
|
QFont f = widget->font();
|
|
f.setPixelSize(size);
|
|
f.setUnderline(underline);
|
|
return f;
|
|
}
|
|
|
|
static QPalette lightText()
|
|
{
|
|
QPalette pal;
|
|
pal.setColor(QPalette::Foreground, themeColor(Theme::Welcome_ForegroundPrimaryColor));
|
|
pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_ForegroundPrimaryColor));
|
|
return pal;
|
|
}
|
|
|
|
static void addWeakVerticalSpacerToLayout(QVBoxLayout *layout, int maximumSize)
|
|
{
|
|
auto weakSpacer = new QWidget;
|
|
weakSpacer->setMaximumHeight(maximumSize);
|
|
weakSpacer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum);
|
|
layout->addWidget(weakSpacer);
|
|
layout->setStretchFactor(weakSpacer, 1);
|
|
}
|
|
|
|
class WelcomeMode : public IMode
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
WelcomeMode();
|
|
~WelcomeMode();
|
|
|
|
void initPlugins();
|
|
|
|
Q_INVOKABLE bool openDroppedFiles(const QList<QUrl> &urls);
|
|
|
|
private:
|
|
void addPage(IWelcomePage *page);
|
|
|
|
QWidget *m_modeWidget;
|
|
QStackedWidget *m_pageStack;
|
|
SideBar *m_sideBar;
|
|
QList<IWelcomePage *> m_pluginList;
|
|
QList<WelcomePageButton *> m_pageButtons;
|
|
Id m_activePage;
|
|
};
|
|
|
|
class WelcomePlugin : public ExtensionSystem::IPlugin
|
|
{
|
|
Q_OBJECT
|
|
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Welcome.json")
|
|
|
|
public:
|
|
~WelcomePlugin() final { delete m_welcomeMode; }
|
|
|
|
bool initialize(const QStringList &, QString *) final
|
|
{
|
|
m_welcomeMode = new WelcomeMode;
|
|
return true;
|
|
}
|
|
|
|
void extensionsInitialized() final
|
|
{
|
|
m_welcomeMode->initPlugins();
|
|
ModeManager::activateMode(m_welcomeMode->id());
|
|
}
|
|
|
|
WelcomeMode *m_welcomeMode = nullptr;
|
|
};
|
|
|
|
class IconAndLink : public QWidget
|
|
{
|
|
public:
|
|
IconAndLink(const QString &iconSource,
|
|
const QString &title,
|
|
const QString &openUrl,
|
|
QWidget *parent)
|
|
: QWidget(parent), m_iconSource(iconSource), m_title(title), m_openUrl(openUrl)
|
|
{
|
|
setAutoFillBackground(true);
|
|
setMinimumHeight(30);
|
|
setToolTip(m_openUrl);
|
|
|
|
const QString fileName = QString(":/welcome/images/%1.png").arg(iconSource);
|
|
const Icon icon({{fileName, Theme::Welcome_ForegroundPrimaryColor}}, Icon::Tint);
|
|
|
|
m_icon = new QLabel;
|
|
m_icon->setPixmap(icon.pixmap());
|
|
|
|
m_label = new QLabel(title);
|
|
m_label->setFont(sizedFont(11, m_label, false));
|
|
|
|
auto layout = new QHBoxLayout;
|
|
layout->setContentsMargins(lrPadding, 0, lrPadding, 0);
|
|
layout->addWidget(m_icon);
|
|
layout->addSpacing(2);
|
|
layout->addWidget(m_label);
|
|
layout->addStretch(1);
|
|
setLayout(layout);
|
|
}
|
|
|
|
void enterEvent(QEvent *) override
|
|
{
|
|
QPalette pal;
|
|
pal.setColor(QPalette::Background, themeColor(Theme::Welcome_HoverColor));
|
|
setPalette(pal);
|
|
m_label->setFont(sizedFont(11, m_label, true));
|
|
update();
|
|
}
|
|
|
|
void leaveEvent(QEvent *) override
|
|
{
|
|
QPalette pal;
|
|
pal.setColor(QPalette::Background, themeColor(Theme::Welcome_BackgroundColor));
|
|
setPalette(pal);
|
|
m_label->setFont(sizedFont(11, m_label, false));
|
|
update();
|
|
}
|
|
|
|
void mousePressEvent(QMouseEvent *) override
|
|
{
|
|
QDesktopServices::openUrl(m_openUrl);
|
|
}
|
|
|
|
QString m_iconSource;
|
|
QString m_title;
|
|
const QString m_openUrl;
|
|
|
|
QLabel *m_icon;
|
|
QLabel *m_label;
|
|
};
|
|
|
|
class SideBar : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
SideBar(QWidget *parent)
|
|
: QWidget(parent)
|
|
{
|
|
setAutoFillBackground(true);
|
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
setPalette(themeColor(Theme::Welcome_BackgroundColor));
|
|
|
|
auto vbox = new QVBoxLayout(this);
|
|
vbox->setSpacing(0);
|
|
vbox->setContentsMargins(0, 27, 0, 0);
|
|
|
|
{
|
|
auto l = m_pluginButtons = new QVBoxLayout;
|
|
l->setContentsMargins(lrPadding, 0, lrPadding, 0);
|
|
l->setSpacing(19);
|
|
vbox->addItem(l);
|
|
}
|
|
|
|
addWeakVerticalSpacerToLayout(vbox, 62);
|
|
|
|
{
|
|
auto l = new QVBoxLayout;
|
|
l->setContentsMargins(lrPadding, 0, lrPadding, 0);
|
|
l->setSpacing(12);
|
|
|
|
auto newLabel = new QLabel(tr("New to Qt?"), this);
|
|
newLabel->setFont(sizedFont(18, this));
|
|
l->addWidget(newLabel);
|
|
|
|
auto learnLabel = new QLabel(tr("Learn how to develop your own applications "
|
|
"and explore %1.")
|
|
.arg(Core::Constants::IDE_DISPLAY_NAME), this);
|
|
learnLabel->setMaximumWidth(200);
|
|
learnLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
|
learnLabel->setWordWrap(true);
|
|
learnLabel->setFont(sizedFont(12, this));
|
|
learnLabel->setPalette(lightText());
|
|
l->addWidget(learnLabel);
|
|
|
|
l->addSpacing(8);
|
|
|
|
auto getStartedButton = new WelcomePageButton(this);
|
|
getStartedButton->setText(tr("Get Started Now"));
|
|
getStartedButton->setOnClicked([] {
|
|
QDesktopServices::openUrl(QString("qthelp://org.qt-project.qtcreator/doc/index.html"));
|
|
});
|
|
l->addWidget(getStartedButton);
|
|
|
|
vbox->addItem(l);
|
|
}
|
|
|
|
vbox->addStretch(1);
|
|
|
|
{
|
|
auto l = new QVBoxLayout;
|
|
l->setContentsMargins(0, 0, 0, 0);
|
|
l->setSpacing(5);
|
|
l->addWidget(new IconAndLink("qtaccount", tr("Qt Account"), "https://account.qt.io", this));
|
|
l->addWidget(new IconAndLink("community", tr("Online Community"), "https://forum.qt.io", this));
|
|
l->addWidget(new IconAndLink("blogs", tr("Blogs"), "https://planet.qt.io", this));
|
|
l->addWidget(new IconAndLink("userguide", tr("User Guide"),
|
|
"qthelp://org.qt-project.qtcreator/doc/index.html", this));
|
|
vbox->addItem(l);
|
|
}
|
|
|
|
addWeakVerticalSpacerToLayout(vbox, vbox->contentsMargins().top());
|
|
}
|
|
|
|
QVBoxLayout *m_pluginButtons = nullptr;
|
|
};
|
|
|
|
WelcomeMode::WelcomeMode()
|
|
{
|
|
setDisplayName(tr("Welcome"));
|
|
|
|
const Icon CLASSIC(":/welcome/images/mode_welcome.png");
|
|
const Icon FLAT({{":/welcome/images/mode_welcome_mask.png",
|
|
Theme::IconsBaseColor}});
|
|
const Icon FLAT_ACTIVE({{":/welcome/images/mode_welcome_mask.png",
|
|
Theme::IconsModeWelcomeActiveColor}});
|
|
setIcon(Icon::modeIcon(CLASSIC, FLAT, FLAT_ACTIVE));
|
|
|
|
setPriority(Constants::P_MODE_WELCOME);
|
|
setId(Constants::MODE_WELCOME);
|
|
setContextHelpId("Qt Creator Manual");
|
|
setContext(Context(Constants::C_WELCOME_MODE));
|
|
|
|
QPalette palette = creatorTheme()->palette();
|
|
palette.setColor(QPalette::Background, themeColor(Theme::Welcome_BackgroundColor));
|
|
|
|
m_modeWidget = new QWidget;
|
|
m_modeWidget->setPalette(palette);
|
|
|
|
m_sideBar = new SideBar(m_modeWidget);
|
|
auto scrollableSideBar = new QScrollArea(m_modeWidget);
|
|
scrollableSideBar->setWidget(m_sideBar);
|
|
scrollableSideBar->setWidgetResizable(true);
|
|
scrollableSideBar->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
scrollableSideBar->setFrameShape(QFrame::NoFrame);
|
|
|
|
auto divider = new QWidget(m_modeWidget);
|
|
divider->setMaximumWidth(1);
|
|
divider->setMinimumWidth(1);
|
|
divider->setAutoFillBackground(true);
|
|
divider->setPalette(themeColor(Theme::Welcome_DividerColor));
|
|
|
|
m_pageStack = new QStackedWidget(m_modeWidget);
|
|
m_pageStack->setObjectName("WelcomeScreenStackedWidget");
|
|
m_pageStack->setAutoFillBackground(true);
|
|
|
|
auto hbox = new QHBoxLayout;
|
|
hbox->addWidget(scrollableSideBar);
|
|
hbox->addWidget(divider);
|
|
hbox->addWidget(m_pageStack);
|
|
hbox->setStretchFactor(m_pageStack, 10);
|
|
|
|
auto layout = new QVBoxLayout(m_modeWidget);
|
|
layout->setMargin(0);
|
|
layout->setSpacing(0);
|
|
layout->addWidget(new StyledBar(m_modeWidget));
|
|
layout->addItem(hbox);
|
|
|
|
if (Utils::HostOsInfo::isMacHost()) { // workaround QTBUG-61384
|
|
auto openglWidget = new QOpenGLWidget;
|
|
openglWidget->hide();
|
|
layout->addWidget(openglWidget);
|
|
}
|
|
|
|
setWidget(m_modeWidget);
|
|
}
|
|
|
|
WelcomeMode::~WelcomeMode()
|
|
{
|
|
QSettings *settings = ICore::settings();
|
|
settings->setValue(currentPageSettingsKeyC, m_activePage.toSetting());
|
|
delete m_modeWidget;
|
|
}
|
|
|
|
void WelcomeMode::initPlugins()
|
|
{
|
|
QSettings *settings = ICore::settings();
|
|
m_activePage = Id::fromSetting(settings->value(currentPageSettingsKeyC));
|
|
|
|
for (IWelcomePage *page : IWelcomePage::allWelcomePages())
|
|
addPage(page);
|
|
|
|
if (!m_activePage.isValid() && !m_pageButtons.isEmpty()) {
|
|
const int welcomeIndex = Utils::indexOf(m_pluginList,
|
|
Utils::equal(&IWelcomePage::id,
|
|
Core::Id("Examples")));
|
|
const int defaultIndex = welcomeIndex >= 0 ? welcomeIndex : 0;
|
|
m_activePage = m_pluginList.at(defaultIndex)->id();
|
|
m_pageButtons.at(defaultIndex)->click();
|
|
}
|
|
}
|
|
|
|
bool WelcomeMode::openDroppedFiles(const QList<QUrl> &urls)
|
|
{
|
|
// DropArea {
|
|
// anchors.fill: parent
|
|
// keys: ["text/uri-list"]
|
|
// onDropped: {
|
|
// if ((drop.supportedActions & Qt.CopyAction != 0)
|
|
// && welcomeMode.openDroppedFiles(drop.urls))
|
|
// drop.accept(Qt.CopyAction);
|
|
// }
|
|
// }
|
|
const QList<QUrl> localUrls = Utils::filtered(urls, &QUrl::isLocalFile);
|
|
if (!localUrls.isEmpty()) {
|
|
QTimer::singleShot(0, [localUrls]() {
|
|
ICore::openFiles(Utils::transform(localUrls, &QUrl::toLocalFile), ICore::SwitchMode);
|
|
});
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void WelcomeMode::addPage(IWelcomePage *page)
|
|
{
|
|
int idx;
|
|
int pagePriority = page->priority();
|
|
for (idx = 0; idx != m_pluginList.size(); ++idx) {
|
|
if (m_pluginList.at(idx)->priority() >= pagePriority)
|
|
break;
|
|
}
|
|
auto pageButton = new WelcomePageButton(m_sideBar);
|
|
auto pageId = page->id();
|
|
pageButton->setText(page->title());
|
|
pageButton->setActiveChecker([this, pageId] { return m_activePage == pageId; });
|
|
|
|
m_pluginList.append(page);
|
|
m_pageButtons.append(pageButton);
|
|
|
|
m_sideBar->m_pluginButtons->insertWidget(idx, pageButton);
|
|
|
|
QWidget *stackPage = page->createWidget();
|
|
stackPage->setAutoFillBackground(true);
|
|
m_pageStack->insertWidget(idx, stackPage);
|
|
|
|
auto onClicked = [this, pageId, stackPage] {
|
|
m_activePage = pageId;
|
|
m_pageStack->setCurrentWidget(stackPage);
|
|
for (WelcomePageButton *pageButton : m_pageButtons)
|
|
pageButton->recheckActive();
|
|
};
|
|
|
|
pageButton->setOnClicked(onClicked);
|
|
if (pageId == m_activePage)
|
|
onClicked();
|
|
}
|
|
|
|
} // namespace Internal
|
|
} // namespace Welcome
|
|
|
|
#include "welcomeplugin.moc"
|