/**************************************************************************** ** ** 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 "introductionwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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::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 &urls); private: void addPage(IWelcomePage *page); QWidget *m_modeWidget; QStackedWidget *m_pageStack; SideBar *m_sideBar; QList m_pluginList; QList m_pageButtons; Id m_activePage; }; class WelcomePlugin final : 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 &arguments, QString *) final { m_welcomeMode = new WelcomeMode; auto introAction = new QAction(tr("UI Tour"), this); connect(introAction, &QAction::triggered, this, []() { auto intro = new IntroductionWidget(ICore::mainWindow()); intro->show(); }); Command *cmd = ActionManager::registerAction(introAction, "Welcome.UITour"); ActionContainer *mhelp = ActionManager::actionContainer(Core::Constants::M_HELP); if (QTC_GUARD(mhelp)) mhelp->addAction(cmd, Core::Constants::G_HELP_HELP); if (!arguments.contains("-notour")) { connect(ICore::instance(), &ICore::coreOpened, this, []() { IntroductionWidget::askUserAboutIntroduction(ICore::mainWindow(), ICore::settings()); }, Qt::QueuedConnection); } 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::Window, themeColor(Theme::Welcome_HoverColor)); setPalette(pal); m_label->setFont(sizedFont(11, m_label, true)); update(); } void leaveEvent(QEvent *) override { QPalette pal; pal.setColor(QPalette::Window, 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); setContextHelp("Qt Creator Manual"); setContext(Context(Constants::C_WELCOME_MODE)); QPalette palette = creatorTheme()->palette(); palette.setColor(QPalette::Window, 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->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addWidget(new StyledBar(m_modeWidget)); layout->addItem(hbox); 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 &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 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.insert(idx, page); m_pageButtons.insert(idx, pageButton); m_sideBar->m_pluginButtons->insertWidget(idx, pageButton); QWidget *stackPage = page->createWidget(); stackPage->setAutoFillBackground(true); m_pageStack->insertWidget(idx, stackPage); connect(page, &QObject::destroyed, this, [this, page, stackPage, pageButton] { m_pluginList.removeOne(page); m_pageButtons.removeOne(pageButton); delete pageButton; delete 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"