Create welcome screen

This screen is similar to the one in Ark, but also shows you a list of
recently-opened documents.
This commit is contained in:
Jiří Wolker 2021-05-07 19:07:44 +02:00 committed by Nate Graham
parent 293337d994
commit f24aa63a97
9 changed files with 1038 additions and 7 deletions

View file

@ -110,7 +110,7 @@ ecm_add_test(calculatetexttest.cpp
)
if(KF5Activities_FOUND AND BUILD_DESKTOP)
ecm_add_test(mainshelltest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp closedialoghelper.cpp
ecm_add_test(mainshelltest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp ../shell/welcomescreen.cpp ../shell/recentitemsmodel.cpp closedialoghelper.cpp
TEST_NAME "mainshelltest"
LINK_LIBRARIES Qt5::Test KF5::Activities okularpart okularcore
)
@ -118,7 +118,7 @@ if(KF5Activities_FOUND AND BUILD_DESKTOP)
endif()
if(BUILD_DESKTOP)
ecm_add_test(annotationtoolbartest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp closedialoghelper.cpp
ecm_add_test(annotationtoolbartest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp ../shell/welcomescreen.cpp ../shell/recentitemsmodel.cpp closedialoghelper.cpp
TEST_NAME "annotationtoolbartest"
LINK_LIBRARIES Qt5::Test okularpart
)

View file

@ -11,14 +11,19 @@ set(okular_SRCS
okular_main.cpp
shell.cpp
shellutils.cpp
recentitemsmodel.cpp
welcomescreen.cpp
)
ki18n_wrap_ui(okular_SRCS
welcomescreen.ui)
file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../icons/*-apps-okular.png")
ecm_add_app_icon(okular_SRCS ICONS ${ICONS_SRCS})
add_executable(okular ${okular_SRCS})
target_link_libraries(okular KF5::I18n KF5::Parts KF5::WindowSystem KF5::Crash Qt5::DBus)
target_link_libraries(okular KF5::I18n KF5::Parts KF5::WindowSystem KF5::Crash KF5::IconThemes Qt5::DBus)
if(TARGET KF5::Activities)
target_compile_definitions(okular PUBLIC -DWITH_KACTIVITIES=1)

125
shell/recentitemsmodel.cpp Normal file
View file

@ -0,0 +1,125 @@
/*
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.
QString key;
QString value;
QString nameKey;
QString nameValue;
QUrl url;
// read file list
for (int i = 1; i <= maxItems(); i++) {
key = QStringLiteral("File%1").arg(i);
value = cg.readPathEntry(key, QString());
if (value.isEmpty()) {
continue;
}
url = QUrl::fromUserInput(value);
// Don't restore if file doesn't exist anymore
if (url.isLocalFile() && !QFile::exists(url.toLocalFile())) {
continue;
}
nameKey = QStringLiteral("Name%1").arg(i);
nameValue = cg.readPathEntry(nameKey, url.fileName());
m_recentItems.append(RecentItem {.name = nameValue, .url = 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());
}

64
shell/recentitemsmodel.h Normal file
View file

@ -0,0 +1,64 @@
/*
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

View file

@ -95,6 +95,20 @@ Shell::Shell(const QString &serializedOptions)
// now that the Part plugin is loaded, create the part
KParts::ReadWritePart *const firstPart = m_partFactory->create<KParts::ReadWritePart>(this);
if (firstPart) {
// Setup the central widget
m_centralStackedWidget = new QStackedWidget();
setCentralWidget(m_centralStackedWidget);
// 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_centralStackedWidget->addWidget(m_welcomeScreen);
m_welcomeScreen->installEventFilter(this);
// Setup tab bar
m_tabWidget = new QTabWidget(this);
m_tabWidget->setTabsClosable(true);
@ -106,12 +120,12 @@ Shell::Shell(const QString &serializedOptions)
m_tabWidget->setAcceptDrops(true);
m_tabWidget->tabBar()->installEventFilter(this);
m_centralStackedWidget->addWidget(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);
setCentralWidget(m_tabWidget);
// then, setup our actions
setupActions();
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
@ -146,6 +160,9 @@ Shell::Shell(const QString &serializedOptions)
}
QDBusConnection::sessionBus().registerObject(QStringLiteral("/okularshell"), this, QDBusConnection::ExportScriptableSlots);
// Make sure that the welcome scren is visible on startup.
showWelcomeScreen();
} else {
m_isValid = false;
KMessageBox::error(this, i18n("Unable to find the Okular component."));
@ -233,6 +250,8 @@ bool Shell::openDocument(const QUrl &url, const QString &serializedOptions)
if (m_tabs.size() <= 0)
return false;
hideWelcomeScreen();
KParts::ReadWritePart *const part = m_tabs[0].part;
// Return false if we can't open new tabs and the only part is occupied
@ -270,6 +289,8 @@ bool Shell::canOpenDocs(int numDocs, int desktop)
void Shell::openUrl(const QUrl &url, const QString &serializedOptions)
{
hideWelcomeScreen();
const int activeTab = m_tabWidget->currentIndex();
if (activeTab < m_tabs.size()) {
KParts::ReadWritePart *const activePart = m_tabs[activeTab].part;
@ -343,7 +364,7 @@ void Shell::readSettings()
void Shell::writeSettings()
{
m_recent->saveEntries(KSharedConfig::openConfig()->group("Recent Files"));
saveRecents();
KConfigGroup group = KSharedConfig::openConfig()->group("Desktop Entry");
group.writeEntry("FullScreen", m_fullScreenAction->isChecked());
if (m_fullScreenAction->isChecked()) {
@ -353,12 +374,19 @@ void Shell::writeSettings()
KSharedConfig::openConfig()->sync();
}
void Shell::saveRecents()
{
m_recent->saveEntries(KSharedConfig::openConfig()->group("Recent Files"));
}
void Shell::setupActions()
{
KStandardAction::open(this, SLOT(fileOpen()), actionCollection());
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());
@ -652,7 +680,8 @@ void Shell::closeTab(int tab)
{
KParts::ReadWritePart *const part = m_tabs[tab].part;
QUrl url = part->url();
if (part->closeUrl() && m_tabs.count() > 1) {
bool closeSuccess = part->closeUrl();
if (closeSuccess && m_tabs.count() > 1) {
if (part->factory())
part->factory()->removeClient(part);
part->disconnect();
@ -667,6 +696,10 @@ void Shell::closeTab(int tab)
m_nextTabAction->setEnabled(false);
m_prevTabAction->setEnabled(false);
}
} else if (closeSuccess && m_tabs.count() == 1) {
// Show welcome screen when the last tab is closed.
showWelcomeScreen();
}
}
@ -675,6 +708,8 @@ void Shell::openNewTab(const QUrl &url, const QString &serializedOptions)
const int previousActiveTab = m_tabWidget->currentIndex();
KParts::ReadWritePart *const activePart = m_tabs[previousActiveTab].part;
hideWelcomeScreen();
bool activateTabIfAlreadyOpen;
QMetaObject::invokeMethod(activePart, "activateTabIfAlreadyOpenFile", Q_RETURN_ARG(bool, activateTabIfAlreadyOpen));
@ -853,4 +888,30 @@ void Shell::slotFitWindowToPage(const QSize pageViewSize, const QSize pageSize)
emit moveSplitter(pageSize.width());
}
void Shell::hideWelcomeScreen()
{
m_centralStackedWidget->setCurrentWidget(m_tabWidget);
}
void Shell::showWelcomeScreen()
{
m_centralStackedWidget->setCurrentWidget(m_welcomeScreen);
refreshRecentsOnWelcomeScreen();
}
void Shell::refreshRecentsOnWelcomeScreen()
{
saveRecents();
m_welcomeScreen->loadRecents();
}
void Shell::forgetRecentItem(QUrl const &url)
{
if (m_recent != nullptr) {
m_recent->removeUrl(url);
saveRecents();
refreshRecentsOnWelcomeScreen();
}
}
/* kate: replace-tabs on; indent-width 4; */

View file

@ -19,8 +19,11 @@
#include <kparts/mainwindow.h>
#include <kparts/readwritepart.h>
#include <QStackedWidget>
#include <QtDBus> // krazy:exclude=includes
#include "welcomescreen.h"
class KRecentFilesAction;
class KToggleAction;
class QTabWidget;
@ -137,10 +140,17 @@ 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);
private:
void saveRecents();
void setupAccel();
void setupActions();
void openNewTab(const QUrl &url, const QString &serializedOptions);
@ -165,6 +175,8 @@ private:
bool m_unique;
QTabWidget *m_tabWidget;
KToggleAction *m_openInTab;
WelcomeScreen *m_welcomeScreen;
QStackedWidget *m_centralStackedWidget;
struct TabState {
explicit TabState(KParts::ReadWritePart *p)

189
shell/welcomescreen.cpp Normal file
View file

@ -0,0 +1,189 @@
/*
SPDX-FileCopyrightText: 2021 Jiří Wolker <woljiri@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "welcomescreen.h"
#include <KConfigGroup>
#include <KIconLoader>
#include <KSharedConfig>
#include <QAction>
#include <QClipboard>
#include <QDesktopServices>
#include <QDir>
#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);
bool willOpenMenu = false;
QPoint menuPosition;
if (item != nullptr) {
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)->globalPos();
}
}
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()) {
QFileInfo fileInfo(item->url.toLocalFile());
QDir parentDir = fileInfo.dir();
QUrl parentDirUrl = QUrl::fromLocalFile(parentDir.absolutePath());
QDesktopServices::openUrl(parentDirUrl);
}
});
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);
KIconLoader loader;
appIcon->setPixmap(loader.loadIcon(QStringLiteral("okular"), KIconLoader::Group::Desktop, KIconLoader::SizeEnormous));
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::loadRecents()
{
m_recentsModel->loadEntries(KSharedConfig::openConfig()->group("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"

49
shell/welcomescreen.h Normal file
View file

@ -0,0 +1,49 @@
/*
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);
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

526
shell/welcomescreen.ui Normal file
View file

@ -0,0 +1,526 @@
<?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>
<property name="windowTitle">
<string>Form</string>
</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="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<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="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">
<normaloff>.</normaloff>.</iconset>
</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>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="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>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<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">
<normaloff>.</normaloff>.</iconset>
</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>