Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:epopov:branches:openSUSE:Factory
okular
2001-new-welcomeview.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2001-new-welcomeview.patch of Package okular
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0616d21558586abee47e86cc77096a82714e543d..52fe9cdeecb2c137e012f1011ec2c7f5cbd2aa8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,6 +413,7 @@ install( FILES interfaces/printinterface.h interfaces/saveinterface.h interfaces/viewerinterface.h + interfaces/bookmarksinterface.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/okular/interfaces COMPONENT Devel) ki18n_wrap_ui(okularcore_SRCS diff --git a/aboutdata.h b/aboutdata.h index 90cfa95328370528130b8d1d163d8a5f9b5c185c..1a459d7642e7cfad4eeb53013fa6358703004d3f 100644 --- a/aboutdata.h +++ b/aboutdata.h @@ -13,6 +13,8 @@ #include <KLocalizedString> +#include <QIcon> + inline KAboutData okularAboutData() { KAboutData about(QStringLiteral("okular"), @@ -28,6 +30,7 @@ inline KAboutData okularAboutData() QString(), QStringLiteral("https://okular.kde.org")); + about.setProgramLogo(QIcon::fromTheme(QStringLiteral(":/okular/okular.svgz"))); about.addAuthor(i18n("Pino Toscano"), i18n("Former maintainer"), QStringLiteral("pino@kde.org")); about.addAuthor(i18n("Tobias Koenig"), i18n("Lots of framework work, FictionBook backend and former ODT backend"), QStringLiteral("tokoe@kde.org")); about.addAuthor(i18n("Albert Astals Cid"), i18n("Developer"), QStringLiteral("aacid@kde.org")); diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index d0d63678ce22e44106bc0d0024eb36916090c7c4..51752be7ed1e4eaa6d0b05e3dc736ae1038e055e 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -119,7 +119,7 @@ ecm_add_test(check_distinguished_name_parser.cpp LINK_LIBRARIES Qt6::Test) if(PlasmaActivities_FOUND AND BUILD_DESKTOP) - ecm_add_test(mainshelltest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp ../shell/welcomescreen.cpp ../shell/recentitemsmodel.cpp closedialoghelper.cpp + ecm_add_test(mainshelltest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp ../shell/welcomeview/welcomeview.cpp ../shell/welcomeview/recentfilesmodel.cpp ../shell/welcomeview/bookmarksmodel.cpp closedialoghelper.cpp TEST_NAME "mainshelltest" LINK_LIBRARIES Qt6::Test Plasma::Activities okularpart okularcore ) @@ -131,7 +131,7 @@ if(PlasmaActivities_FOUND AND BUILD_DESKTOP) endif() if(BUILD_DESKTOP) - ecm_add_test(annotationtoolbartest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp ../shell/welcomescreen.cpp ../shell/recentitemsmodel.cpp closedialoghelper.cpp ../shell/welcomescreen.ui + ecm_add_test(annotationtoolbartest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp ../shell/welcomeview/welcomeview.cpp ../shell/welcomeview/recentfilesmodel.cpp ../shell/welcomeview/bookmarksmodel.cpp closedialoghelper.cpp ../shell/welcomeview/welcomeview.ui TEST_NAME "annotationtoolbartest" LINK_LIBRARIES Qt6::Test okularpart ) diff --git a/interfaces/bookmarksinterface.h b/interfaces/bookmarksinterface.h new file mode 100644 index 0000000000000000000000000000000000000000..3ec5b380e63380d33e996e2b9118b8abf52e56b0 --- /dev/null +++ b/interfaces/bookmarksinterface.h @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2022 Eugene Popov <popov895@ukr.net> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef _OKULAR_BOOKMARKSINTERFACE_H_ +#define _OKULAR_BOOKMARKSINTERFACE_H_ + +#include "../core/okularcore_export.h" + +#include <QUrl> + +#ifdef Q_OS_WIN +#define BOOKMARKSINTERFACE_EXPORT __declspec(dllexport) +#else +#define BOOKMARKSINTERFACE_EXPORT OKULARCORE_EXPORT +#endif + +namespace Okular +{ +/** + * @short Abstract interface for managing bookmarks + * + * This interface can be used to list and open bookmarks. + */ +class BOOKMARKSINTERFACE_EXPORT BookmarksInterface +{ +public: + struct Bookmark { + QString title; + QUrl url; + }; + + BookmarksInterface() = default; + virtual ~BookmarksInterface() = default; + + BookmarksInterface(const BookmarksInterface &) = delete; + BookmarksInterface &operator=(const BookmarksInterface &) = delete; + + /** + * Returns bookmarks. + */ + virtual QMultiMap<QUrl, Bookmark> getBookmarks() const = 0; + + /** + * Open bookmark. + */ + virtual void openBookmark(const QUrl &bookmark) = 0; + + // SIGNALS + + /** + * This signal is emitted whenever the bookmark list has changed. + */ + void bookmarksChanged(); +}; +} + +Q_DECLARE_INTERFACE(Okular::BookmarksInterface, "org.kde.okular.BookmarksInterface/0.1") + +#endif // _OKULAR_BOOKMARKSINTERFACE_H_ diff --git a/part/part.cpp b/part/part.cpp index f5b91e6c683e840a67333f9319000d952ff3c134..feef6d58ee79813ac267131b62c53b97a2beca37 100644 --- a/part/part.cpp +++ b/part/part.cpp @@ -359,6 +359,8 @@ Part::Part(QObject *parent, const QVariantList &args) setWindowTitleFromDocument(); }); + connect(m_document->bookmarkManager(), &Okular::BookmarkManager::bookmarksChanged, this, &Part::bookmarksChanged); + if (parent && parent->metaObject()->indexOfSlot(QMetaObject::normalizedSignature("slotQuit()").constData()) != -1) { connect(m_document, SIGNAL(quit()), parent, SLOT(slotQuit())); // clazy:exclude=old-style-connect } else { @@ -468,8 +470,6 @@ Part::Part(QObject *parent, const QVariantList &args) rightLayout->addWidget(m_signatureMessage); m_pageView = new PageView(rightContainer, m_document); rightContainer->setFocusProxy(m_pageView); - QMetaObject::invokeMethod(m_pageView, "setFocus", Qt::QueuedConnection); // usability setting - // m_splitter->setFocusProxy(m_pageView); connect(m_pageView.data(), &PageView::rightClick, this, &Part::slotShowMenu); connect(m_pageView, &PageView::triggerSearch, this, [this](const QString &searchText) { m_findBar->startSearch(searchText); @@ -1101,6 +1101,26 @@ void Part::setModified(bool modified) } } +QMultiMap<QUrl, BookmarksInterface::Bookmark> Part::getBookmarks() const +{ + QMultiMap<QUrl, BookmarksInterface::Bookmark> bookmarks; + + const QList<QUrl> files = m_document->bookmarkManager()->files(); + for (const QUrl &file : files) { + const KBookmark::List &bookmarkList = m_document->bookmarkManager()->bookmarks(file); + for (const KBookmark &bookmark : bookmarkList) { + bookmarks.insert(file, {bookmark.text(), bookmark.url()}); + } + } + + return bookmarks; +} + +void Part::openBookmark(const QUrl &bookmark) +{ + openUrlFromBookmarks(bookmark); +} + void Part::slotHandleActivatedSourceReference(const QString &absFileName, int line, int col, bool *handled) { Q_EMIT openSourceReference(absFileName, line, col); diff --git a/part/part.h b/part/part.h index f6e99f01437e6251f3475c98a6a4aa8767ce44f6..3f200ed292726103fd499d552ad490d7039ef11a 100644 --- a/part/part.h +++ b/part/part.h @@ -26,7 +26,6 @@ #include <QList> #include <QPointer> #include <QProcess> -#include <QUrl> #include <KCompressionDevice> #include <KIO/Job> @@ -36,6 +35,7 @@ #include "../core/document.h" #include "../core/observer.h" +#include "../interfaces/bookmarksinterface.h" #include "../interfaces/viewerinterface.h" #include "../kdocumentviewer.h" @@ -110,12 +110,13 @@ enum EmbedMode { * @author Wilco Greven <greven@kde.org> * @version 0.2 */ -class OKULARPART_EXPORT Part : public KParts::ReadWritePart, public Okular::DocumentObserver, public KDocumentViewer, public Okular::ViewerInterface +class OKULARPART_EXPORT Part : public KParts::ReadWritePart, public Okular::DocumentObserver, public KDocumentViewer, public Okular::ViewerInterface, public Okular::BookmarksInterface { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.okular") Q_INTERFACES(KDocumentViewer) Q_INTERFACES(Okular::ViewerInterface) + Q_INTERFACES(Okular::BookmarksInterface) friend class PartTest; @@ -155,6 +156,10 @@ public: void setModified(bool modified) override; + // Okular::BookmarksInterface + QMultiMap<QUrl, BookmarksInterface::Bookmark> getBookmarks() const override; + void openBookmark(const QUrl &bookmark) override; + public Q_SLOTS: // dbus Q_SCRIPTABLE Q_NOREPLY void goToPage(uint page) override; Q_SCRIPTABLE Q_NOREPLY void openDocument(const QString &doc); @@ -188,6 +193,9 @@ Q_SIGNALS: void urlsDropped(const QList<QUrl> &urls); void fitWindowToPage(const QSize pageViewPortSize, const QSize pageSize); + // Okular::BookmarksInterface + void bookmarksChanged(); + protected: // reimplemented from KParts::ReadWritePart bool openFile() override; diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index 6aabd71475259c9bd7cb4a6ba230e1a21e5df6d5..2c92a5abdb60d2d2bce11d0b4b7ad4bcfb8a3424 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -11,14 +11,15 @@ set(okular_SRCS okular_main.cpp shell.cpp shellutils.cpp - recentitemsmodel.cpp - welcomescreen.cpp + welcomeview/welcomeview.cpp + welcomeview/recentfilesmodel.cpp + welcomeview/bookmarksmodel.cpp shell.qrc ) ki18n_wrap_ui(okular_SRCS - welcomescreen.ui) + welcomeview/welcomeview.ui) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../icons/*-apps-okular.png") ecm_add_app_icon(okular_SRCS ICONS ${ICONS_SRCS}) diff --git a/shell/recentitemsmodel.cpp b/shell/recentitemsmodel.cpp deleted file mode 100644 index 7f4d15a4423494e40ee52445c7c6fbb820984c50..0000000000000000000000000000000000000000 --- a/shell/recentitemsmodel.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - SPDX-FileCopyrightText: 2021 Jiří Wolker <woljiri@gmail.com> - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "recentitemsmodel.h" - -#include <QFile> -#include <QFileIconProvider> -#include <QFileInfo> -#include <QIcon> - -#include <KConfigGroup> - -RecentItemsModel::RecentItemsModel() -{ -} - -RecentItemsModel::~RecentItemsModel() -{ -} - -void RecentItemsModel::loadEntries(const KConfigGroup &cg) -{ - clearEntries(); - - // Based on implementation of KRecentFilesAction::loadEntries. - - // read file list - for (int i = 1; i <= maxItems(); i++) { - const QString key = QStringLiteral("File%1").arg(i); - const QString value = cg.readPathEntry(key, QString()); - if (value.isEmpty()) { - continue; - } - const QUrl url = QUrl::fromUserInput(value); - - // Don't restore if file doesn't exist anymore - if (url.isLocalFile() && !QFile::exists(url.toLocalFile())) { - continue; - } - - const QString nameKey = QStringLiteral("Name%1").arg(i); - const QString nameValue = cg.readPathEntry(nameKey, url.fileName()); - m_recentItems.append(RecentItem {nameValue, url}); - } - - Q_EMIT layoutChanged(); -} - -void RecentItemsModel::clearEntries() -{ - m_recentItems.clear(); - - Q_EMIT layoutChanged(); -} - -int RecentItemsModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - - return m_recentItems.size(); -} - -QVariant RecentItemsModel::data(const QModelIndex &index, int role) const -{ - const RecentItemsModel::RecentItem *item = getItem(index); - - if (item != nullptr) { - switch (role) { - case Qt::ItemDataRole::DisplayRole: - if (item->name.isEmpty()) { - if (item->url.isLocalFile()) { - return item->url.toLocalFile(); - } else { - return item->url.toString(); - } - } else { - return item->name; - } - - case Qt::ItemDataRole::ToolTipRole: - if (item->url.isLocalFile()) { - return item->url.toLocalFile(); - } else { - return item->url.toString(); - } - - case Qt::ItemDataRole::DecorationRole: - if (item->url.isLocalFile()) { - return m_iconProvider.icon(QFileInfo(item->url.toLocalFile())); - } else { - // Fallback icon for remote files. - return QIcon::fromTheme(QStringLiteral("network-server")); - } - - default: - return QVariant(); - } - } else { - return QVariant(); - } -} - -RecentItemsModel::RecentItem const *RecentItemsModel::getItem(int index) const -{ - if (m_recentItems.size() > index && index >= 0) { - // We reverse the order of items. - return &m_recentItems[m_recentItems.size() - index - 1]; - } else { - return nullptr; - } -} - -RecentItemsModel::RecentItem const *RecentItemsModel::getItem(const QModelIndex &index) const -{ - return getItem(index.row()); -} diff --git a/shell/recentitemsmodel.h b/shell/recentitemsmodel.h deleted file mode 100644 index 0725ca62943170195cec6a8bf79226a36184665a..0000000000000000000000000000000000000000 --- a/shell/recentitemsmodel.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - SPDX-FileCopyrightText: 2021 Jiří Wolker <woljiri@gmail.com> - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef RECENTITEMSMODEL_H -#define RECENTITEMSMODEL_H - -#include <QAbstractListModel> -#include <QFileIconProvider> -#include <QList> -#include <QModelIndex> -#include <QString> -#include <QUrl> - -class KConfigGroup; - -/** - * @todo write docs - */ -class RecentItemsModel : public QAbstractListModel -{ - Q_OBJECT - -public: - struct RecentItem { - QString name; - QUrl url; - }; - - /** - * Default constructor - */ - RecentItemsModel(); - - /** - * Destructor - */ - ~RecentItemsModel() override; - - void loadEntries(const KConfigGroup &cg); - void clearEntries(); - - int maxItems() const - { - return m_maxItems; - } - - RecentItemsModel::RecentItem const *getItem(const QModelIndex &) const; - RecentItemsModel::RecentItem const *getItem(int index) const; - - // Model implementation: - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::ItemDataRole::DisplayRole) const override; - -private: - QList<RecentItemsModel::RecentItem> m_recentItems; - - int m_maxItems = 20; - QFileIconProvider m_iconProvider; -}; - -#endif // RECENTITEMSMODEL_H diff --git a/shell/shell.cpp b/shell/shell.cpp index 9074a16037cfd34c61eb9a221a8aa508716a5c47..87cb72cefd5a17560c8338f565aade2fa4d09f0f 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -61,9 +61,11 @@ #include <kxmlgui_version.h> // local includes +#include "../interfaces/bookmarksinterface.h" #include "../interfaces/viewerinterface.h" #include "kdocumentviewer.h" #include "shellutils.h" +#include "welcomeview/welcomeview.h" static const char *shouldShowMenuBarComingFromFullScreen = "shouldShowMenuBarComingFromFullScreen"; static const char *shouldShowToolBarComingFromFullScreen = "shouldShowToolBarComingFromFullScreen"; @@ -220,16 +222,24 @@ Shell::Shell(const QString &serializedOptions) m_centralStackedWidget = new ResizableStackedWidget(); setCentralWidget(m_centralStackedWidget); + m_sidebar = new Sidebar; + m_sidebar->setObjectName(QStringLiteral("okular_sidebar")); + m_sidebar->setContextMenuPolicy(Qt::ActionsContextMenu); + m_sidebar->setWindowTitle(i18n("Sidebar")); + connect(m_sidebar, &QDockWidget::visibilityChanged, this, [this](bool visible) { + // sync sidebar visibility with the m_showSidebarAction only if welcome screen is hidden + if (m_showSidebarAction && m_centralStackedWidget->currentWidget() != m_welcomeScreen) { + m_showSidebarAction->setChecked(visible); + } + }); + addDockWidget(Qt::LeftDockWidgetArea, m_sidebar); + + setupActions(); + // Setup the welcome screen - m_welcomeScreen = new WelcomeScreen(this); - connect(m_welcomeScreen, &WelcomeScreen::openClicked, this, &Shell::fileOpen); - connect(m_welcomeScreen, &WelcomeScreen::closeClicked, this, &Shell::hideWelcomeScreen); - connect(m_welcomeScreen, &WelcomeScreen::recentItemClicked, this, [this](const QUrl &url) { openUrl(url); }); - connect(m_welcomeScreen, &WelcomeScreen::forgetRecentItem, this, &Shell::forgetRecentItem); + m_welcomeScreen = new WelcomeView(this, firstPart); m_centralStackedWidget->addWidget(m_welcomeScreen); - m_welcomeScreen->installEventFilter(this); - // Setup tab bar m_tabWidget = new QTabWidget(this); m_tabWidget->setTabsClosable(true); @@ -239,34 +249,17 @@ Shell::Shell(const QString &serializedOptions) m_tabWidget->setMovable(true); m_tabWidget->setAcceptDrops(true); + + m_welcomeScreen->installEventFilter(this); m_tabWidget->tabBar()->installEventFilter(this); m_centralStackedWidget->addWidget(m_tabWidget); + m_centralStackedWidget->setCurrentWidget(m_tabWidget); connect(m_tabWidget, &QTabWidget::currentChanged, this, &Shell::setActiveTab); connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &Shell::closeTab); connect(m_tabWidget->tabBar(), &QTabBar::tabMoved, this, &Shell::moveTabData); - m_sidebar = new Sidebar; - m_sidebar->setObjectName(QStringLiteral("okular_sidebar")); - m_sidebar->setContextMenuPolicy(Qt::ActionsContextMenu); - m_sidebar->setWindowTitle(i18n("Sidebar")); - connect(m_sidebar, &QDockWidget::visibilityChanged, this, [this](bool visible) { - // sync sidebar visibility with the m_showSidebarAction only if welcome screen is hidden - if (m_showSidebarAction && m_centralStackedWidget->currentWidget() != m_welcomeScreen) { - m_showSidebarAction->setChecked(visible); - } - if (m_centralStackedWidget->currentWidget() == m_welcomeScreen) { - // MainWindow tries hard to make its child dockwidgets shown, but during - // welcome screen we don't want to see the sidebar, - // so try a bit more to actually hide it. - m_sidebar->hide(); - } - }); - addDockWidget(Qt::LeftDockWidgetArea, m_sidebar); - - // then, setup our actions - setupActions(); connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); // and integrate the part's GUI with the shell's setupGUI(Keys | ToolBar | Save); @@ -411,6 +404,11 @@ bool Shell::openDocument(const QUrl &url, const QString &serializedOptions) return true; } +KRecentFilesAction *Shell::recentFilesAction() const +{ + return m_recent; +} + bool Shell::openDocument(const QString &urlString, const QString &serializedOptions) { return openDocument(QUrl(urlString), serializedOptions); @@ -479,6 +477,18 @@ void Shell::openUrl(const QUrl &url, const QString &serializedOptions) } } +void Shell::openBookmark(const QUrl &url) +{ + hideWelcomeScreen(); + + const int activeTab = m_tabWidget->currentIndex(); + if (activeTab >= 0 && activeTab < m_tabs.size()) { + auto activePart = qobject_cast<Okular::BookmarksInterface *>(m_tabs[activeTab].part); + Q_ASSERT(activePart); + activePart->openBookmark(url); + } +} + void Shell::closeUrl() { closeTab(m_tabWidget->currentIndex()); @@ -548,8 +558,6 @@ void Shell::setupActions() m_recent = KStandardAction::openRecent(this, SLOT(openUrl(QUrl)), actionCollection()); m_recent->setToolBarMode(KRecentFilesAction::MenuMode); connect(m_recent, &QAction::triggered, this, &Shell::showOpenRecentMenu); - connect(m_recent, &KRecentFilesAction::recentListCleared, this, &Shell::refreshRecentsOnWelcomeScreen); - connect(m_welcomeScreen, &WelcomeScreen::forgetAllRecents, m_recent, &KRecentFilesAction::clear); m_recent->setToolTip(i18n("Click to open a file\nClick and hold to open a recent file")); m_recent->setWhatsThis(i18n("<b>Click</b> to open a file or <b>Click and hold</b> to select a recent file")); m_printAction = KStandardAction::print(this, SLOT(print()), actionCollection()); @@ -588,6 +596,12 @@ void Shell::setupActions() m_lockSidebarAction->setText(i18n("Lock Sidebar")); connect(m_lockSidebarAction, &QAction::triggered, m_sidebar, &Sidebar::setLocked); m_sidebar->addAction(m_lockSidebarAction); + + QAction *showWelcomeScreenAction = actionCollection()->addAction(QStringLiteral("help_welcome_page")); + showWelcomeScreenAction->setText(i18n("Welcome Page")); + showWelcomeScreenAction->setIcon(qApp->windowIcon()); + showWelcomeScreenAction->setWhatsThis(i18n("Show the welcome page")); + connect(showWelcomeScreenAction, &QAction::triggered, this, [this]() { showWelcomeScreen(true); }); } void Shell::saveProperties(KConfigGroup &group) @@ -872,6 +886,8 @@ void Shell::setActiveTab(int tab) } m_sidebar->setCurrentWidget(sideContainer); + m_tabs[tab].part->widget()->setFocus(); + m_showSidebarAction = m_tabs[tab].part->actionCollection()->action(QStringLiteral("show_leftpanel")); Q_ASSERT(m_showSidebarAction); m_showSidebarAction->disconnect(); @@ -1118,28 +1134,19 @@ void Shell::hideWelcomeScreen() m_showSidebarAction->setEnabled(true); } -void Shell::showWelcomeScreen() +void Shell::showWelcomeScreen(bool force) { + if (!force) { + const KConfigGroup configGroup = KSharedConfig::openConfig()->group(QStringLiteral("General")); + if (!configGroup.readEntry("ShowWelcomeScreenOnStartup", true)) { + return; + } + } + m_showSidebarAction->setEnabled(false); m_centralStackedWidget->setCurrentWidget(m_welcomeScreen); + m_welcomeScreen->findChild<QPushButton *>()->setFocus(); m_sidebar->setVisible(false); - - refreshRecentsOnWelcomeScreen(); -} - -void Shell::refreshRecentsOnWelcomeScreen() -{ - saveRecents(); - m_welcomeScreen->loadRecents(); -} - -void Shell::forgetRecentItem(QUrl const &url) -{ - if (m_recent != nullptr) { - m_recent->removeUrl(url); - saveRecents(); - refreshRecentsOnWelcomeScreen(); - } } #include "shell.moc" diff --git a/shell/shell.h b/shell/shell.h index 3ac9709a471638b60c6b251c23aab2a66239e4c8..aefcf9645c67b887f6fa2d38cb435cef9a6bd2f0 100644 --- a/shell/shell.h +++ b/shell/shell.h @@ -27,9 +27,8 @@ #endif #include <QStackedWidget> -#include "welcomescreen.h" - class Sidebar; +class WelcomeView; class KRecentFilesAction; class KToggleAction; class QTabWidget; @@ -70,6 +69,7 @@ public: bool isValid() const; bool openDocument(const QUrl &url, const QString &serializedOptions); + KRecentFilesAction *recentFilesAction() const; public Q_SLOTS: Q_SCRIPTABLE Q_NOREPLY void tryRaise(const QString &startupId); @@ -114,13 +114,18 @@ protected: void showEvent(QShowEvent *event) override; void keyPressEvent(QKeyEvent *) override; -private Q_SLOTS: +public Q_SLOTS: void fileOpen(); + void openUrl(const QUrl &url, const QString &serializedOptions = QString()); + void openBookmark(const QUrl &url); + + void hideWelcomeScreen(); + void showWelcomeScreen(bool force = false); +private Q_SLOTS: void slotUpdateFullScreen(); void slotShowMenubar(); - void openUrl(const QUrl &url, const QString &serializedOptions = QString()); void showOpenRecentMenu(); void closeUrl(); void print(); @@ -139,12 +144,6 @@ private Q_SLOTS: void slotFitWindowToPage(const QSize pageViewSize, const QSize pageSize); - void hideWelcomeScreen(); - void showWelcomeScreen(); - void refreshRecentsOnWelcomeScreen(); - - void forgetRecentItem(QUrl const &url); - Q_SIGNALS: void moveSplitter(int sideWidgetSize); @@ -174,7 +173,7 @@ private: bool m_unique; QTabWidget *m_tabWidget; KToggleAction *m_openInTab; - WelcomeScreen *m_welcomeScreen; + WelcomeView *m_welcomeScreen; QStackedWidget *m_centralStackedWidget; Sidebar *m_sidebar = nullptr; diff --git a/shell/shell.qrc b/shell/shell.qrc index 73705f2287fce8424c8f61ddcf91a9355dca11d5..a5637261819d6c69789a006a78e2559279eccf60 100644 --- a/shell/shell.qrc +++ b/shell/shell.qrc @@ -2,5 +2,6 @@ <RCC version="1.0"> <qresource prefix="/kxmlgui5/okular"> <file>shell.rc</file> + <file alias="okular.svgz">../icons/hisc-apps-okular.svgz</file> </qresource> </RCC> diff --git a/shell/shell.rc b/shell/shell.rc index d54f12715417e23fea2d240cdab733e35aefe295..81b230a41770062bc7476615bffc600948464452 100644 --- a/shell/shell.rc +++ b/shell/shell.rc @@ -18,6 +18,7 @@ <Merge/> <Menu name="help"> <DefineGroup append="about_merge" name="about_merge" /> + <Action name="help_welcome_page" group="about_merge"/> </Menu> </MenuBar> <ToolBar noMerge="1" name="mainToolBar" > diff --git a/shell/welcomescreen.cpp b/shell/welcomescreen.cpp deleted file mode 100644 index e7b5f996307e007831a2e1f012254cd13396f35f..0000000000000000000000000000000000000000 --- a/shell/welcomescreen.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - SPDX-FileCopyrightText: 2021 Jiří Wolker <woljiri@gmail.com> - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "welcomescreen.h" - -#include <KConfigGroup> -#include <KIO/OpenFileManagerWindowJob> -#include <KIconLoader> -#include <KSharedConfig> - -#include <QAction> -#include <QClipboard> -#include <QGraphicsOpacityEffect> -#include <QGuiApplication> -#include <QMenu> -#include <QResizeEvent> -#include <QStyledItemDelegate> - -#include "recentitemsmodel.h" - -class RecentsListItemDelegate : public QStyledItemDelegate -{ - Q_OBJECT - -public: - explicit RecentsListItemDelegate(WelcomeScreen *welcomeScreen) - : m_welcomeScreen(welcomeScreen) - { - } - - WelcomeScreen *welcomeScreen() const - { - return m_welcomeScreen; - } - - bool editorEvent(QEvent *event, QAbstractItemModel *aModel, const QStyleOptionViewItem &styleOptionViewItem, const QModelIndex &index) override - { - const RecentItemsModel *model = static_cast<RecentItemsModel *>(aModel); - const RecentItemsModel::RecentItem *item = model->getItem(index); - - QPoint menuPosition; - - if (item != nullptr) { - bool willOpenMenu = false; - if (event->type() == QEvent::ContextMenu) { - willOpenMenu = true; - menuPosition = static_cast<QContextMenuEvent *>(event)->globalPos(); - } - if (event->type() == QEvent::MouseButtonPress) { - if (static_cast<QMouseEvent *>(event)->button() == Qt::MouseButton::RightButton) { - willOpenMenu = true; - menuPosition = static_cast<QMouseEvent *>(event)->globalPosition().toPoint(); - } - } - - if (willOpenMenu) { - event->accept(); - - QMenu menu; - - QAction *copyPathAction = new QAction(i18n("&Copy Path")); - copyPathAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); - connect(copyPathAction, &QAction::triggered, this, [item]() { - QString path; - if (item->url.isLocalFile()) { - path = item->url.toLocalFile(); - } else { - path = item->url.toString(); - } - QGuiApplication::clipboard()->setText(path); - }); - menu.addAction(copyPathAction); - - QAction *showDirectoryAction = new QAction(i18n("&Open Containing Folder")); - showDirectoryAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open-folder"))); - connect(showDirectoryAction, &QAction::triggered, this, [item]() { - if (item->url.isLocalFile()) { - KIO::highlightInFileManager({item->url}); - } - }); - menu.addAction(showDirectoryAction); - if (!item->url.isLocalFile()) { - showDirectoryAction->setEnabled(false); - } - - QAction *forgetItemAction = new QAction(i18nc("recent items context menu", "&Forget This Item")); - forgetItemAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-history"))); - connect(forgetItemAction, &QAction::triggered, this, [this, item]() { Q_EMIT welcomeScreen()->forgetRecentItem(item->url); }); - menu.addAction(forgetItemAction); - - menu.exec(menuPosition); - - return true; - } - } - - return QStyledItemDelegate::editorEvent(event, aModel, styleOptionViewItem, index); - } - -private: - WelcomeScreen *m_welcomeScreen; -}; - -WelcomeScreen::WelcomeScreen(QWidget *parent) - : QWidget(parent) - , m_recentsModel(new RecentItemsModel) - , m_recentsItemDelegate(new RecentsListItemDelegate(this)) -{ - Q_ASSERT(parent); - - setupUi(this); - - connect(openButton, &QPushButton::clicked, this, &WelcomeScreen::openClicked); - connect(closeButton, &QPushButton::clicked, this, &WelcomeScreen::closeClicked); - - recentsListView->setContextMenuPolicy(Qt::DefaultContextMenu); - recentsListView->setModel(m_recentsModel); - recentsListView->setItemDelegate(m_recentsItemDelegate); - connect(recentsListView, &QListView::activated, this, &WelcomeScreen::recentsItemActivated); - - connect(m_recentsModel, &RecentItemsModel::layoutChanged, this, &WelcomeScreen::recentListChanged); - - QVBoxLayout *noRecentsLayout = new QVBoxLayout(recentsListView); - recentsListView->setLayout(noRecentsLayout); - m_noRecentsLabel = new QLabel(recentsListView); - QFont placeholderLabelFont; - // To match the size of a level 2 Heading/KTitleWidget - placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3)); - noRecentsLayout->addWidget(m_noRecentsLabel); - m_noRecentsLabel->setFont(placeholderLabelFont); - m_noRecentsLabel->setTextInteractionFlags(Qt::NoTextInteraction); - m_noRecentsLabel->setWordWrap(true); - m_noRecentsLabel->setAlignment(Qt::AlignCenter); - m_noRecentsLabel->setText(i18nc("on welcome screen", "No recent documents")); - // Match opacity of QML placeholder label component - auto *effect = new QGraphicsOpacityEffect(m_noRecentsLabel); - effect->setOpacity(0.5); - m_noRecentsLabel->setGraphicsEffect(effect); - - connect(forgetAllButton, &QToolButton::clicked, this, &WelcomeScreen::forgetAllRecents); -} - -WelcomeScreen::~WelcomeScreen() -{ - delete m_recentsModel; - delete m_recentsItemDelegate; -} - -void WelcomeScreen::showEvent(QShowEvent *e) -{ - if (appIcon->pixmap(Qt::ReturnByValue).isNull()) { - appIcon->setPixmap(QIcon::fromTheme(QStringLiteral("okular")).pixmap(KIconLoader::SizeEnormous)); - } - - QWidget::showEvent(e); -} - -void WelcomeScreen::loadRecents() -{ - m_recentsModel->loadEntries(KSharedConfig::openConfig()->group(QStringLiteral("Recent Files"))); -} - -int WelcomeScreen::recentsCount() -{ - return m_recentsModel->rowCount(); -} - -void WelcomeScreen::recentsItemActivated(const QModelIndex &index) -{ - const RecentItemsModel::RecentItem *item = m_recentsModel->getItem(index); - if (item != nullptr) { - Q_EMIT recentItemClicked(item->url); - } -} - -void WelcomeScreen::recentListChanged() -{ - if (recentsCount() == 0) { - m_noRecentsLabel->show(); - forgetAllButton->setEnabled(false); - } else { - m_noRecentsLabel->hide(); - forgetAllButton->setEnabled(true); - } -} - -#include "welcomescreen.moc" diff --git a/shell/welcomescreen.h b/shell/welcomescreen.h deleted file mode 100644 index 6c404951c5d53f8d1654f8d40ae7c200c97fc249..0000000000000000000000000000000000000000 --- a/shell/welcomescreen.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - SPDX-FileCopyrightText: 2021 Jiří Wolker <woljiri@gmail.com> - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#ifndef WELCOMESCREEN_H -#define WELCOMESCREEN_H - -#include "shell/ui_welcomescreen.h" - -#include <QFrame> -#include <QUrl> - -class KRecentFilesAction; -class QListWidgetItem; -class RecentItemsModel; -class RecentsListItemDelegate; - -class WelcomeScreen : public QWidget, Ui::WelcomeScreen -{ - Q_OBJECT -public: - explicit WelcomeScreen(QWidget *parent = nullptr); - ~WelcomeScreen() override; - - void loadRecents(); - -Q_SIGNALS: - void openClicked(); - void closeClicked(); - void recentItemClicked(QUrl const &url); - void forgetAllRecents(); - void forgetRecentItem(QUrl const &url); - -protected: - void showEvent(QShowEvent *e) override; - -private Q_SLOTS: - void recentsItemActivated(QModelIndex const &index); - void recentListChanged(); - -private: - int recentsCount(); - - RecentItemsModel *m_recentsModel; - RecentsListItemDelegate *m_recentsItemDelegate; - - QLabel *m_noRecentsLabel; -}; - -#endif // WELCOMESCREEN_H diff --git a/shell/welcomescreen.ui b/shell/welcomescreen.ui deleted file mode 100644 index 5c087836f0204cc212526f5cf79c81a38da01fec..0000000000000000000000000000000000000000 --- a/shell/welcomescreen.ui +++ /dev/null @@ -1,524 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -SPDX-FileCopyrightText: 2021 Jiří Wolker <woljiri@gmail.com> -SPDX-License-Identifier: GPL-2.0-or-later ---> -<ui version="4.0"> - <class>WelcomeScreen</class> - <widget class="QWidget" name="WelcomeScreen"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>1423</width> - <height>850</height> - </rect> - </property> - <property name="acceptDrops"> - <bool>true</bool> - </property> - <layout class="QGridLayout" name="gridLayout" rowstretch="3,5,0,3" columnstretch="1,4,1"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="spacing"> - <number>0</number> - </property> - <item row="1" column="0" rowspan="3"> - <spacer name="horizontalSpacer_8"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>48</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>48</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1" rowspan="2"> - <widget class="QWidget" name="horizontalWidget" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>256</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>700</width> - <height>16777215</height> - </size> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QFrame" name="verticalFrame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Expanding"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>192</width> - <height>16777215</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QLabel" name="label"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>40</height> - </size> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Welcome to Okular</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="margin"> - <number>0</number> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>12</width> - <height>12</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="appIcon"> - <property name="text"> - <string notr="true"/> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>12</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="sizeConstraint"> - <enum>QLayout::SetMinimumSize</enum> - </property> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>48</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="openButton"> - <property name="text"> - <string comment="on welcome screen">Open Document...</string> - </property> - <property name="icon"> - <iconset theme="document-open" /> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>48</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Maximum</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>48</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QWidget" name="verticalWidget" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="verticalLayout" stretch="1"> - <property name="spacing"> - <number>0</number> - </property> - <item> - <widget class="Line" name="line_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Maximum</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>48</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QWidget" name="recentsArea" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,1"> - <property name="spacing"> - <number>4</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QWidget" name="horizontalWidget" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>36</height> - </size> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <item> - <widget class="QLabel" name="label_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="text"> - <string comment="on welcome screen">Recent documents</string> - </property> - <property name="alignment"> - <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="forgetAllButton"> - <property name="text"> - <string comment="on welcome screen (recent document list)">Forget All</string> - </property> - <property name="icon"> - <iconset theme="edit-clear-history"/> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QListView" name="recentsListView"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>1</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>200</width> - <height>128</height> - </size> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item row="0" column="2"> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="closeButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Hide welcome screen</string> - </property> - <property name="text"> - <string comment="on welcome screen"/> - </property> - <property name="icon"> - <iconset theme="window-close"/> - </property> - <property name="flat"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="1" column="2" rowspan="3"> - <spacer name="horizontalSpacer_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="3" column="1"> - <spacer name="verticalSpacer_6"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>48</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <tabstops> - <tabstop>openButton</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/shell/welcomeview/bookmarksmodel.cpp b/shell/welcomeview/bookmarksmodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c5c513d0583735ec6bb48eca52cfe4cc40648b5 --- /dev/null +++ b/shell/welcomeview/bookmarksmodel.cpp @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2022 Eugene Popov <popov895@ukr.net> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "bookmarksmodel.h" + +#include <QFileInfo> +#include <QIcon> +#include <QMimeDatabase> + +BookmarksModel::BookmarksModel(QObject *parent) + : QStandardItemModel(parent) +{ +} + +void BookmarksModel::refresh(const QMultiMap<QUrl, Okular::BookmarksInterface::Bookmark> &bookmarks) +{ + clear(); + + const QList<QUrl> files = bookmarks.uniqueKeys(); + for (const QUrl &file : files) { + QStandardItem *item = new QStandardItem; + item->setData(file); + item->setToolTip(file.toString(QUrl::PreferLocalFile)); + + if (file.isLocalFile()) { + const QFileInfo fileInfo(file.toLocalFile()); + item->setIcon(QIcon::fromTheme(QMimeDatabase().mimeTypeForFile(fileInfo).iconName())); + item->setText(fileInfo.fileName()); + } else { + item->setIcon(QIcon::fromTheme(QStringLiteral("network-server"))); + item->setText(file.toString()); + } + + const QList<Okular::BookmarksInterface::Bookmark> bookmarkList = bookmarks.values(file); + for (const Okular::BookmarksInterface::Bookmark &bookmark : bookmarkList) { + QStandardItem *childItem = new QStandardItem; + childItem->setData(bookmark.url); + childItem->setText(bookmark.title); + + item->appendRow(childItem); + } + + appendRow(item); + } + + sort(0); + + Q_EMIT itemChanged(invisibleRootItem()); +} diff --git a/shell/welcomeview/bookmarksmodel.h b/shell/welcomeview/bookmarksmodel.h new file mode 100644 index 0000000000000000000000000000000000000000..dba112de217ca24a2fbd9ee8585019e0ca6eb4fa --- /dev/null +++ b/shell/welcomeview/bookmarksmodel.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2022 Eugene Popov <popov895@ukr.net> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef BOOKMARKSMODEL_H +#define BOOKMARKSMODEL_H + +#include <QStandardItemModel> + +#include <interfaces/bookmarksinterface.h> + +class BookmarksModel : public QStandardItemModel +{ + Q_OBJECT + +public: + explicit BookmarksModel(QObject *parent = nullptr); + + void refresh(const QMultiMap<QUrl, Okular::BookmarksInterface::Bookmark> &bookmarks); +}; + +#endif // BOOKMARKSMODEL_H diff --git a/shell/welcomeview/recentfilesmodel.cpp b/shell/welcomeview/recentfilesmodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c68208d3ce13dcc7396614688b48c86398d0c2c8 --- /dev/null +++ b/shell/welcomeview/recentfilesmodel.cpp @@ -0,0 +1,82 @@ +/* + SPDX-FileCopyrightText: 2022 Jiří Wolker <woljiri@gmail.com> + SPDX-FileCopyrightText: 2022 Eugene Popov <popov895@ukr.net> + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "recentfilesmodel.h" + +#include <QFileInfo> +#include <QMimeDatabase> + +RecentFilesModel::RecentFilesModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +QVariant RecentFilesModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid()) { + const int row = index.row(); + if (row >= 0 && row < m_recentFiles.count()) { + const RecentFileInfo &recentFile = m_recentFiles.at(row); + switch (role) { + case Qt::DisplayRole: + return recentFile.name; + case Qt::DecorationRole: + return recentFile.icon; + case Qt::ToolTipRole: + return recentFile.url.toString(QUrl::PreferLocalFile); + default: + break; + } + } + } + + return QVariant(); +} + +int RecentFilesModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return m_recentFiles.count(); +} + +void RecentFilesModel::refresh(const QList<QUrl> &urls) +{ + QVector<RecentFileInfo> recentFiles; + recentFiles.reserve(urls.count()); + + QIcon icon; + QString name; + for (const QUrl &url : urls) { + if (url.isLocalFile()) { + const QFileInfo fileInfo(url.toLocalFile()); + icon = QIcon::fromTheme(QMimeDatabase().mimeTypeForFile(fileInfo).iconName()); + name = fileInfo.fileName(); + } else { + icon = QIcon::fromTheme(QStringLiteral("network-server")); + name = url.toString(); + } + + recentFiles.append({icon, name, url}); + } + + beginResetModel(); + m_recentFiles = std::move(recentFiles); + endResetModel(); +} + +QUrl RecentFilesModel::url(const QModelIndex &index) const +{ + if (index.isValid()) { + const int row = index.row(); + if (row >= 0 && row < m_recentFiles.count()) { + return m_recentFiles.at(row).url; + } + } + + return QUrl(); +} diff --git a/shell/welcomeview/recentfilesmodel.h b/shell/welcomeview/recentfilesmodel.h new file mode 100644 index 0000000000000000000000000000000000000000..de55f3fc6a894272f9f0aa82a6f1036f1356a6ac --- /dev/null +++ b/shell/welcomeview/recentfilesmodel.h @@ -0,0 +1,38 @@ +/* + SPDX-FileCopyrightText: 2022 Jiří Wolker <woljiri@gmail.com> + SPDX-FileCopyrightText: 2022 Eugene Popov <popov895@ukr.net> + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef RECENTFILESMODEL_H +#define RECENTFILESMODEL_H + +#include <QAbstractListModel> +#include <QIcon> +#include <QUrl> + +class RecentFilesModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit RecentFilesModel(QObject *parent = nullptr); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + void refresh(const QList<QUrl> &urls); + QUrl url(const QModelIndex &index) const; + +private: + struct RecentFileInfo { + QIcon icon; + QString name; + QUrl url; + }; + + QVector<RecentFileInfo> m_recentFiles; +}; + +#endif // RECENTFILESMODEL_H diff --git a/shell/welcomeview/welcomeview.cpp b/shell/welcomeview/welcomeview.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1592af25d31779059f8b75090e8a4a40c0dcba00 --- /dev/null +++ b/shell/welcomeview/welcomeview.cpp @@ -0,0 +1,317 @@ +/* + SPDX-FileCopyrightText: 2022 Jiří Wolker <woljiri@gmail.com> + SPDX-FileCopyrightText: 2022 Eugene Popov <popov895@ukr.net> + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "welcomeview.h" + +#include "../shell.h" +#include "bookmarksmodel.h" +#include "recentfilesmodel.h" + +#include <KAboutData> +#include <KConfigGroup> +#include <KIO/OpenFileManagerWindowJob> +#include <KIconLoader> +#include <KRecentFilesAction> +#include <KSharedConfig> + +#include <QClipboard> +#include <QDesktopServices> +#include <QGraphicsOpacityEffect> +#include <QLabel> +#include <QMenu> +#include <QTimer> + +#include <interfaces/bookmarksinterface.h> + +class Placeholder : public QLabel // clazy:exclude=missing-qobject-macro +{ +public: + explicit Placeholder(QWidget *parent = nullptr) + : QLabel(parent) + { + setAlignment(Qt::AlignCenter); + setMargin(20); + setWordWrap(true); + // Match opacity of QML placeholder label component + QGraphicsOpacityEffect *opacityEffect = new QGraphicsOpacityEffect; + opacityEffect->setOpacity(0.5); + setGraphicsEffect(opacityEffect); + } +}; + +WelcomeView::WelcomeView(Shell *shell, KParts::ReadWritePart *part, QWidget *parent) + : QScrollArea(parent) + , m_shell(shell) + , m_bookmarks(qobject_cast<Okular::BookmarksInterface *>(part)) +{ + setupUi(this); + + const KAboutData aboutData = KAboutData::applicationData(); + labelTitle->setText(i18n("Welcome to %1", aboutData.displayName())); + labelDescription->setText(aboutData.shortDescription()); + labelIcon->setPixmap(aboutData.programLogo().value<QIcon>().pixmap(KIconLoader::SizeEnormous)); + + m_placeholderRecentFiles = new Placeholder; + m_placeholderRecentFiles->setText(i18n("No recent files")); + + QVBoxLayout *layoutPlaceholderRecentFiles = new QVBoxLayout; + layoutPlaceholderRecentFiles->addWidget(m_placeholderRecentFiles); + listViewRecentFiles->setLayout(layoutPlaceholderRecentFiles); + + m_recentFilesModel = new RecentFilesModel(this); + connect(m_recentFilesModel, &RecentFilesModel::modelReset, this, [this]() { + const bool noRecentFiles = m_recentFilesModel->rowCount() == 0; + buttonClearRecentFiles->setDisabled(noRecentFiles); + m_placeholderRecentFiles->setVisible(noRecentFiles); + }); + + KRecentFilesAction *recentFilesAction = m_shell->recentFilesAction(); + m_recentFilesModel->refresh(recentFilesAction->urls()); + recentFilesAction->menu()->installEventFilter(this); + + listViewRecentFiles->setModel(m_recentFilesModel); + connect(listViewRecentFiles, &QListView::customContextMenuRequested, this, &WelcomeView::onRecentFilesContextMenuRequested); + connect(listViewRecentFiles, &QListView::activated, this, [this](const QModelIndex &index) { + if (index.isValid()) { + const QUrl url = m_recentFilesModel->url(index); + Q_ASSERT(url.isValid()); + m_shell->openUrl(url); + } + }); + + connect(buttonOpenFile, &QPushButton::clicked, m_shell, &Shell::fileOpen); + connect(buttonImportPostScript, SIGNAL(clicked()), part, SLOT(slotImportPSFile())); // clazy:exclude=old-style-connect + connect(buttonClearRecentFiles, &QPushButton::clicked, recentFilesAction, &KRecentFilesAction::clear); + + m_placeholderBookmarks = new Placeholder; + m_placeholderBookmarks->setText(i18n("No bookmarks")); + + QVBoxLayout *layoutPlaceholderBookmarks = new QVBoxLayout; + layoutPlaceholderBookmarks->addWidget(m_placeholderBookmarks); + treeViewBookmarks->setLayout(layoutPlaceholderBookmarks); + + m_bookmarksModel = new BookmarksModel(this); + connect(m_bookmarksModel, &BookmarksModel::itemChanged, this, [this]() { + const bool noBookmarks = m_bookmarksModel->rowCount() == 0; + m_placeholderBookmarks->setVisible(noBookmarks); + }); + + connect(part, SIGNAL(bookmarksChanged()), this, SLOT(onBookmarksChanged())); // clazy:exclude=old-style-connect + onBookmarksChanged(); + + treeViewBookmarks->setModel(m_bookmarksModel); + connect(treeViewBookmarks, &QListView::customContextMenuRequested, this, &WelcomeView::onBookmarksContextMenuRequested); + connect(treeViewBookmarks, &QTreeView::activated, this, [this](const QModelIndex &index) { + if (index.isValid()) { + const QStandardItem *item = m_bookmarksModel->itemFromIndex(index); + if (item && item->parent()) { + m_shell->openBookmark(item->data().toUrl()); + } + } + }); + + connect(labelHomepage, qOverload<>(&KUrlLabel::leftClickedUrl), this, [aboutData]() { QDesktopServices::openUrl(QUrl(aboutData.homepage())); }); + connect(labelHandbook, qOverload<>(&KUrlLabel::leftClickedUrl), m_shell, &Shell::appHelpActivated); + connect(buttonClose, &QPushButton::clicked, m_shell, &Shell::hideWelcomeScreen); + + static const char showOnStartupKey[] = "ShowWelcomeScreenOnStartup"; + KConfigGroup configGroup = KSharedConfig::openConfig()->group(QStringLiteral("General")); + checkBoxShowOnStartup->setChecked(configGroup.readEntry(showOnStartupKey, true)); + connect(checkBoxShowOnStartup, &QCheckBox::toggled, this, [configGroup](bool checked) mutable { configGroup.writeEntry(showOnStartupKey, checked); }); + + updateFonts(); + updateButtons(); +} + +bool WelcomeView::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::FontChange: + updateFonts(); + updateButtons(); + break; + case QEvent::Resize: + if (updateLayout() && isVisible()) { + return true; + } + break; + default: + break; + } + + return QScrollArea::event(event); +} + +void WelcomeView::resizeEvent(QResizeEvent *event) +{ + QScrollArea::resizeEvent(event); + + updateLayout(); +} + +bool WelcomeView::eventFilter(QObject *watched, QEvent *event) +{ + KRecentFilesAction *recentFilesAction = m_shell->recentFilesAction(); + if (watched == recentFilesAction->menu()) { + switch (event->type()) { + case QEvent::ActionAdded: + case QEvent::ActionRemoved: + // since the KRecentFilesAction doesn't notify about adding or + // deleting items, we should use this workaround to find out + // the KRecentFilesAction has changed + QTimer::singleShot(0, this, [this, recentFilesAction]() { m_recentFilesModel->refresh(recentFilesAction->urls()); }); + break; + default: + break; + } + } + + return QScrollArea::eventFilter(watched, event); +} + +void WelcomeView::onBookmarksChanged() +{ + m_bookmarksModel->refresh(m_bookmarks->getBookmarks()); +} + +void WelcomeView::onRecentFilesContextMenuRequested(QPoint pos) +{ + const QModelIndex index = listViewRecentFiles->indexAt(pos); + if (!index.isValid()) { + return; + } + + const QUrl url = m_recentFilesModel->url(index); + Q_ASSERT(url.isValid()); + + QMenu contextMenu; + + QAction *action = contextMenu.addAction(i18n("Copy &Location")); + action->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy-path"))); + connect(action, &QAction::triggered, this, [url]() { qApp->clipboard()->setText(url.toString(QUrl::PreferLocalFile)); }); + + action = contextMenu.addAction(i18n("&Open Containing Folder")); + action->setEnabled(url.isLocalFile()); + action->setIcon(QIcon::fromTheme(QStringLiteral("document-open-folder"))); + connect(action, &QAction::triggered, this, [url]() { KIO::highlightInFileManager({url}); }); + + action = contextMenu.addAction(i18n("&Remove")); + action->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); + connect(action, &QAction::triggered, this, [this, url]() { + KRecentFilesAction *recentFilesAction = m_shell->recentFilesAction(); + recentFilesAction->removeUrl(url); + }); + + contextMenu.exec(listViewRecentFiles->mapToGlobal(pos)); +} + +void WelcomeView::onBookmarksContextMenuRequested(QPoint pos) +{ + if (m_bookmarksModel->rowCount() == 0) { + return; + } + + QMenu contextMenu; + + const QModelIndex index = treeViewBookmarks->indexAt(pos); + if (index.isValid()) { + const QStandardItem *item = m_bookmarksModel->itemFromIndex(index); + if (item && !item->parent()) { + const QUrl &url = item->data().toUrl(); + Q_ASSERT(url.isValid()); + + QAction *action = contextMenu.addAction(i18n("Copy &Location")); + action->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy-path"))); + connect(action, &QAction::triggered, this, [url]() { qApp->clipboard()->setText(url.toString(QUrl::PreferLocalFile)); }); + + action = contextMenu.addAction(i18n("&Open Containing Folder")); + action->setEnabled(url.isLocalFile()); + action->setIcon(QIcon::fromTheme(QStringLiteral("document-open-folder"))); + connect(action, &QAction::triggered, this, [url]() { KIO::highlightInFileManager({url}); }); + + contextMenu.addSeparator(); + } + } + + QAction *action = contextMenu.addAction(i18n("Expand All")); + action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down-double"))); + connect(action, &QAction::triggered, treeViewBookmarks, &QTreeView::expandAll); + + action = contextMenu.addAction(i18n("Collapse All")); + action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up-double"))); + connect(action, &QAction::triggered, treeViewBookmarks, &QTreeView::collapseAll); + + contextMenu.exec(treeViewBookmarks->mapToGlobal(pos)); +} + +void WelcomeView::updateButtons() +{ + QVector<QPushButton *> buttons {buttonOpenFile, buttonImportPostScript}; + const int maxWidth = std::accumulate(buttons.cbegin(), buttons.cend(), 0, [](int maxWidth, const QPushButton *button) { return std::max(maxWidth, button->sizeHint().width()); }); + for (QPushButton *button : qAsConst(buttons)) { + button->setFixedWidth(maxWidth); + } + + layoutBookmarks->setContentsMargins(maxWidth + layoutRecentFiles->horizontalSpacing(), 0, 0, 0); +} + +void WelcomeView::updateFonts() +{ + QFont titleFont = font(); + titleFont.setPointSize(titleFont.pointSize() + 6); + titleFont.setWeight(QFont::Bold); + labelTitle->setFont(titleFont); + + QFont panelTitleFont = font(); + panelTitleFont.setPointSize(panelTitleFont.pointSize() + 2); + labelRecentFiles->setFont(panelTitleFont); + labelBookmarks->setFont(panelTitleFont); + labelHelp->setFont(panelTitleFont); + + QFont placeholderFont = font(); + placeholderFont.setPointSize(qRound(placeholderFont.pointSize() * 1.3)); + m_placeholderRecentFiles->setFont(placeholderFont); + m_placeholderBookmarks->setFont(placeholderFont); +} + +bool WelcomeView::updateLayout() +{ + // Align labelHelp with labelRecentFiles + labelHelp->setMinimumHeight(labelRecentFiles->height()); + + bool result = false; + + // show/hide widgetHeader depending on the view height + if (widgetHeader->isVisible()) { + if (height() <= frameContent->height() + widgetClose->height()) { + widgetHeader->hide(); + result = true; + } + } else { + const int implicitHeight = frameContent->height() + widgetHeader->height() + layoutContent->spacing() + widgetClose->height(); + if (height() > implicitHeight) { + widgetHeader->show(); + result = true; + } + } + + // show/hide widgetHelp depending on the view height + if (widgetHelp->isVisible()) { + if (width() <= frameContent->width() + widgetClose->width()) { + widgetHelp->hide(); + result = true; + } + } else { + const int implicitWidth = frameContent->width() + widgetHelp->width() + layoutPanels->horizontalSpacing() + widgetClose->width(); + if (width() > implicitWidth) { + widgetHelp->show(); + return true; + } + } + + return result; +} diff --git a/shell/welcomeview/welcomeview.h b/shell/welcomeview/welcomeview.h new file mode 100644 index 0000000000000000000000000000000000000000..00ef5fc2bcf33cabb02191fc42c7508c147ae856 --- /dev/null +++ b/shell/welcomeview/welcomeview.h @@ -0,0 +1,59 @@ +/* + SPDX-FileCopyrightText: 2022 Jiří Wolker <woljiri@gmail.com> + SPDX-FileCopyrightText: 2022 Eugene Popov <popov895@ukr.net> + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#ifndef WELCOMEVIEW_H +#define WELCOMEVIEW_H + +#include "shell/ui_welcomeview.h" + +class BookmarksModel; +class Placeholder; +class RecentFilesModel; +class Shell; + +namespace KParts +{ +class ReadWritePart; +} + +namespace Okular +{ +class BookmarksInterface; +} + +class WelcomeView : public QScrollArea, Ui::WelcomeView +{ + Q_OBJECT + +public: + explicit WelcomeView(Shell *shell, KParts::ReadWritePart *part, QWidget *parent = nullptr); + +protected: + bool event(QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + + bool eventFilter(QObject *watched, QEvent *event) override; + +private Q_SLOTS: + void onBookmarksChanged(); + void onRecentFilesContextMenuRequested(QPoint pos); + void onBookmarksContextMenuRequested(QPoint pos); + +private: + void updateButtons(); + void updateFonts(); + bool updateLayout(); + + Shell *m_shell = nullptr; + Okular::BookmarksInterface *m_bookmarks = nullptr; + RecentFilesModel *m_recentFilesModel = nullptr; + BookmarksModel *m_bookmarksModel = nullptr; + Placeholder *m_placeholderRecentFiles = nullptr; + Placeholder *m_placeholderBookmarks = nullptr; +}; + +#endif // WELCOMEVIEW_H diff --git a/shell/welcomeview/welcomeview.ui b/shell/welcomeview/welcomeview.ui new file mode 100644 index 0000000000000000000000000000000000000000..fd76e7f8c4a5b119d6811dcf3a52257f3d98ebc5 --- /dev/null +++ b/shell/welcomeview/welcomeview.ui @@ -0,0 +1,496 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>WelcomeView</class> + <widget class="QScrollArea" name="WelcomeView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1011</width> + <height>803</height> + </rect> + </property> + <property name="acceptDrops"> + <bool>true</bool> + </property> + <property name="windowTitle"> + <string>Welcome</string> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1011</width> + <height>803</height> + </rect> + </property> + <layout class="QGridLayout" name="layoutRoot" rowstretch="3,5,3" columnstretch="3,5,3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <item row="0" column="1"> + <spacer name="spacer6"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <spacer name="spacer4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="QFrame" name="frameContent"> + <layout class="QVBoxLayout" name="layoutContent" stretch="0,1,0"> + <property name="spacing"> + <number>20</number> + </property> + <item> + <widget class="QWidget" name="widgetHeader" native="true"> + <layout class="QHBoxLayout" name="layoutHeader" stretch="1,0,0,1"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <spacer name="spacer1"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item alignment="Qt::AlignVCenter"> + <widget class="QLabel" name="labelIcon"/> + </item> + <item alignment="Qt::AlignVCenter"> + <widget class="QWidget" name="widgetAbout" native="true"> + <layout class="QVBoxLayout" name="verticalAbout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="labelTitle"/> + </item> + <item> + <widget class="QLabel" name="labelDescription"/> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="spacer2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <layout class="QGridLayout" name="layoutPanels" columnstretch="1,0"> + <property name="spacing"> + <number>20</number> + </property> + <item row="0" column="0"> + <widget class="QWidget" name="widgetRecentFiles" native="true"> + <layout class="QGridLayout" name="layoutRecentFiles" rowstretch="0,0,0,1" columnstretch="0,1,0"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="horizontalSpacing"> + <number>20</number> + </property> + <item row="1" column="1" rowspan="3" colspan="2"> + <widget class="QListView" name="listViewRecentFiles"> + <property name="minimumSize"> + <size> + <width>400</width> + <height>200</height> + </size> + </property> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="textElideMode"> + <enum>Qt::ElideMiddle</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QPushButton" name="buttonOpenFile"> + <property name="text"> + <string>Open File...</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="buttonClearRecentFiles"> + <property name="toolTip"> + <string>Clear Recent Files</string> + </property> + <property name="icon"> + <iconset theme="edit-clear-all"> + <normaloff>.</normaloff>.</iconset> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="labelRecentFiles"> + <property name="text"> + <string>Recent Files</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <spacer name="spacer3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QPushButton" name="buttonImportPostScript"> + <property name="text"> + <string>Import PostScript...</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="1" rowspan="2"> + <widget class="QWidget" name="widgetHelp" native="true"> + <layout class="QVBoxLayout" name="layoutHelp" stretch="0,0,0,1"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="labelHelp"> + <property name="text"> + <string>Help</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> + </widget> + </item> + <item alignment="Qt::AlignLeft"> + <widget class="KUrlLabel" name="labelHomepage"> + <property name="text"> + <string>Visit homepage</string> + </property> + <property name="url"> + <string/> + </property> + <property name="glowEnabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item alignment="Qt::AlignLeft"> + <widget class="KUrlLabel" name="labelHandbook"> + <property name="text"> + <string>Read handbook</string> + </property> + <property name="url"> + <string/> + </property> + <property name="glowEnabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="spacer11"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item row="1" column="0"> + <widget class="QWidget" name="widgetBookmarks" native="true"> + <layout class="QVBoxLayout" name="layoutBookmarks"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="labelBookmarks"> + <property name="text"> + <string>Bookmarks</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> + </widget> + </item> + <item> + <widget class="QTreeView" name="treeViewBookmarks"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>200</height> + </size> + </property> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="textElideMode"> + <enum>Qt::ElideMiddle</enum> + </property> + <attribute name="headerVisible"> + <bool>false</bool> + </attribute> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QWidget" name="widgetFooter" native="true"> + <layout class="QHBoxLayout" name="layoutFooter"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <spacer name="spacer9"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="checkBoxShowOnStartup"> + <property name="text"> + <string>Show on startup</string> + </property> + </widget> + </item> + <item> + <spacer name="spacer10"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item row="1" column="2"> + <spacer name="spacer5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <spacer name="spacer7"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="2" alignment="Qt::AlignRight|Qt::AlignTop"> + <widget class="QWidget" name="widgetClose" native="true"> + <layout class="QHBoxLayout" name="layoutClose"> + <item> + <widget class="QPushButton" name="buttonClose"> + <property name="toolTip"> + <string>Close Welcome Page</string> + </property> + <property name="icon"> + <iconset theme="window-close"> + <normaloff>.</normaloff>.</iconset> + </property> + <property name="flat"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + <customwidgets> + <customwidget> + <class>KUrlLabel</class> + <extends>QLabel</extends> + <header>kurllabel.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>buttonOpenFile</tabstop> + <tabstop>buttonImportPostScript</tabstop> + <tabstop>listViewRecentFiles</tabstop> + <tabstop>buttonClearRecentFiles</tabstop> + <tabstop>treeViewBookmarks</tabstop> + </tabstops> + <resources/> + <connections/> +</ui>
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor