mirror of
https://invent.kde.org/graphics/okular
synced 2024-09-28 20:24:09 +00:00
Port sidebar to QDockWidget
With this MR, the sidebar can now be (if not locked): * docked to the left or right side * undocked and floated as an independent window * closed with the close button in the header BUG: 455013
This commit is contained in:
parent
38438b00bf
commit
2fbab13e1f
|
@ -79,6 +79,13 @@ public:
|
|||
*/
|
||||
virtual bool openNewFilesInTabs() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the sidebar container.
|
||||
*
|
||||
* @since 23.04
|
||||
*/
|
||||
virtual QWidget *getSideContainer() const = 0;
|
||||
|
||||
// SIGNALS
|
||||
/**
|
||||
* The signal 'openSourceReference' is emitted whenever the user has triggered a source
|
||||
|
|
|
@ -1107,6 +1107,11 @@ bool Part::openNewFilesInTabs() const
|
|||
return Okular::Settings::self()->shellOpenFileInTabs();
|
||||
}
|
||||
|
||||
QWidget *Part::getSideContainer() const
|
||||
{
|
||||
return m_sidebar->getSideContainer();
|
||||
}
|
||||
|
||||
bool Part::activateTabIfAlreadyOpenFile() const
|
||||
{
|
||||
return Okular::Settings::self()->switchToTabIfOpen();
|
||||
|
|
|
@ -147,6 +147,7 @@ public:
|
|||
bool areSourceLocationsShownGraphically() const override;
|
||||
void setShowSourceLocationsGraphically(bool show) override;
|
||||
bool openNewFilesInTabs() const override;
|
||||
QWidget *getSideContainer() const override;
|
||||
Q_INVOKABLE bool activateTabIfAlreadyOpenFile() const;
|
||||
|
||||
void setModified(bool modified) override;
|
||||
|
|
|
@ -166,6 +166,11 @@ void Sidebar::moveSplitter(int sideWidgetSize)
|
|||
d->splitter->setSizes(splitterSizeList);
|
||||
}
|
||||
|
||||
QWidget *Sidebar::getSideContainer() const
|
||||
{
|
||||
return d->sideContainer;
|
||||
}
|
||||
|
||||
void Sidebar::splitterMoved(int /*pos*/, int index)
|
||||
{
|
||||
// if the side panel has been resized, save splitter sizes
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
|
||||
void moveSplitter(int sideWidgetSize);
|
||||
|
||||
QWidget *getSideContainer() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void urlsDropped(const QList<QUrl> &urls);
|
||||
|
||||
|
|
162
shell/shell.cpp
162
shell/shell.cpp
|
@ -36,6 +36,7 @@
|
|||
#include <KXMLGUIFactory>
|
||||
#include <QApplication>
|
||||
#include <QDBusConnection>
|
||||
#include <QDockWidget>
|
||||
#include <QDragMoveEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QMenuBar>
|
||||
|
@ -62,6 +63,86 @@ static const char *shouldShowToolBarComingFromFullScreen = "shouldShowToolBarCom
|
|||
static const char *const SESSION_URL_KEY = "Urls";
|
||||
static const char *const SESSION_TAB_KEY = "ActiveTab";
|
||||
|
||||
static constexpr char SIDEBAR_LOCKED_KEY[] = "LockSidebar";
|
||||
static constexpr char SIDEBAR_VISIBLE_KEY[] = "ShowSidebar";
|
||||
|
||||
/**
|
||||
* Groups sidebar containers in a QDockWidget.
|
||||
*
|
||||
* This control groups all the sidebar containers provided by each tab (the Part object),
|
||||
* allowing the user to dock it to the left and right sides of the window,
|
||||
* or detach it from the window altogether.
|
||||
*/
|
||||
class Sidebar : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Sidebar(QWidget *parent = nullptr)
|
||||
: QDockWidget(parent)
|
||||
{
|
||||
setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||
setFeatures(defaultFeatures());
|
||||
|
||||
m_stackedWidget = new QStackedWidget;
|
||||
setWidget(m_stackedWidget);
|
||||
}
|
||||
|
||||
bool isLocked() const
|
||||
{
|
||||
return features().testFlag(NoDockWidgetFeatures);
|
||||
}
|
||||
|
||||
void setLocked(bool locked)
|
||||
{
|
||||
setFeatures(locked ? NoDockWidgetFeatures : defaultFeatures());
|
||||
|
||||
// show titlebar only if not locked
|
||||
if (locked) {
|
||||
if (!m_dumbTitleWidget) {
|
||||
m_dumbTitleWidget = new QWidget;
|
||||
}
|
||||
setTitleBarWidget(m_dumbTitleWidget);
|
||||
} else {
|
||||
setTitleBarWidget(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
int indexOf(QWidget *widget) const
|
||||
{
|
||||
return m_stackedWidget->indexOf(widget);
|
||||
}
|
||||
|
||||
void addWidget(QWidget *widget)
|
||||
{
|
||||
m_stackedWidget->addWidget(widget);
|
||||
}
|
||||
|
||||
void removeWidget(QWidget *widget)
|
||||
{
|
||||
m_stackedWidget->removeWidget(widget);
|
||||
}
|
||||
|
||||
void setCurrentWidget(QWidget *widget)
|
||||
{
|
||||
m_stackedWidget->setCurrentWidget(widget);
|
||||
}
|
||||
|
||||
private:
|
||||
static DockWidgetFeatures defaultFeatures()
|
||||
{
|
||||
DockWidgetFeatures dockFeatures = DockWidgetClosable | DockWidgetMovable;
|
||||
if (!KWindowSystem::isPlatformWayland()) { // TODO : Remove this check when QTBUG-87332 is fixed
|
||||
dockFeatures |= DockWidgetFloatable;
|
||||
}
|
||||
|
||||
return dockFeatures;
|
||||
}
|
||||
|
||||
QStackedWidget *m_stackedWidget = nullptr;
|
||||
QWidget *m_dumbTitleWidget = nullptr;
|
||||
};
|
||||
|
||||
Shell::Shell(const QString &serializedOptions)
|
||||
: KParts::MainWindow()
|
||||
, m_menuBarWasShown(true)
|
||||
|
@ -126,12 +207,27 @@ Shell::Shell(const QString &serializedOptions)
|
|||
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);
|
||||
}
|
||||
});
|
||||
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);
|
||||
|
||||
// NOTE : apply default sidebar width only after calling setupGUI(...)
|
||||
resizeDocks({m_sidebar}, {200}, Qt::Horizontal);
|
||||
|
||||
m_tabs.append(TabState(firstPart));
|
||||
m_tabWidget->addTab(firstPart->widget(), QString()); // triggers setActiveTab that calls createGUI( part )
|
||||
|
||||
|
@ -367,11 +463,25 @@ void Shell::readSettings()
|
|||
m_menuBarWasShown = group.readEntry(shouldShowMenuBarComingFromFullScreen, true);
|
||||
m_toolBarWasShown = group.readEntry(shouldShowToolBarComingFromFullScreen, true);
|
||||
}
|
||||
|
||||
const KConfigGroup sidebarGroup = KSharedConfig::openConfig()->group("General");
|
||||
m_sidebar->setVisible(sidebarGroup.readEntry(SIDEBAR_VISIBLE_KEY, true));
|
||||
m_sidebar->setLocked(sidebarGroup.readEntry(SIDEBAR_LOCKED_KEY, true));
|
||||
|
||||
m_showSidebarAction->setChecked(m_sidebar->isVisibleTo(this));
|
||||
m_lockSidebarAction->setChecked(m_sidebar->isLocked());
|
||||
}
|
||||
|
||||
void Shell::writeSettings()
|
||||
{
|
||||
saveRecents();
|
||||
|
||||
KConfigGroup sidebarGroup = KSharedConfig::openConfig()->group("General");
|
||||
sidebarGroup.writeEntry(SIDEBAR_LOCKED_KEY, m_sidebar->isLocked());
|
||||
// NOTE : Consider whether the m_showSidebarAction is checked, because
|
||||
// the sidebar can be forcibly hidden if the welcome screen is displayed
|
||||
sidebarGroup.writeEntry(SIDEBAR_VISIBLE_KEY, m_sidebar->isVisibleTo(this) || m_showSidebarAction->isChecked());
|
||||
|
||||
KConfigGroup group = KSharedConfig::openConfig()->group("Desktop Entry");
|
||||
group.writeEntry("FullScreen", m_fullScreenAction->isChecked());
|
||||
if (m_fullScreenAction->isChecked()) {
|
||||
|
@ -425,6 +535,19 @@ void Shell::setupActions()
|
|||
m_undoCloseTab->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo")));
|
||||
m_undoCloseTab->setEnabled(false);
|
||||
connect(m_undoCloseTab, &QAction::triggered, this, &Shell::undoCloseTab);
|
||||
|
||||
m_showSidebarAction = actionCollection()->addAction(QStringLiteral("okular_show_sidebar"));
|
||||
m_showSidebarAction->setCheckable(true);
|
||||
m_showSidebarAction->setIcon(QIcon::fromTheme(QStringLiteral("sidebar-show-symbolic")));
|
||||
m_showSidebarAction->setText(i18n("Show Sidebar"));
|
||||
connect(m_showSidebarAction, &QAction::triggered, m_sidebar, &Sidebar::setVisible);
|
||||
|
||||
m_lockSidebarAction = actionCollection()->addAction(QStringLiteral("okular_lock_sidebar"));
|
||||
m_lockSidebarAction->setCheckable(true);
|
||||
m_lockSidebarAction->setIcon(QIcon::fromTheme(QStringLiteral("lock")));
|
||||
m_lockSidebarAction->setText(i18n("Lock Sidebar"));
|
||||
connect(m_lockSidebarAction, &QAction::triggered, m_sidebar, &Sidebar::setLocked);
|
||||
m_sidebar->addAction(m_lockSidebarAction);
|
||||
}
|
||||
|
||||
void Shell::saveProperties(KConfigGroup &group)
|
||||
|
@ -673,7 +796,24 @@ bool Shell::queryClose()
|
|||
void Shell::setActiveTab(int tab)
|
||||
{
|
||||
m_tabWidget->setCurrentIndex(tab);
|
||||
|
||||
// NOTE : createGUI(...) breaks the visibility of the sidebar, so we need
|
||||
// to save and restore it
|
||||
const bool isSidebarVisible = m_sidebar->isVisible();
|
||||
createGUI(m_tabs[tab].part);
|
||||
m_sidebar->setVisible(isSidebarVisible);
|
||||
|
||||
// dock KPart's sidebar if new and make it current
|
||||
Okular::ViewerInterface *iPart = qobject_cast<Okular::ViewerInterface *>(m_tabs[tab].part);
|
||||
Q_ASSERT(iPart);
|
||||
QWidget *sideContainer = iPart->getSideContainer();
|
||||
if (m_sidebar->indexOf(sideContainer) == -1) {
|
||||
m_sidebar->addWidget(sideContainer);
|
||||
if (m_sidebar->maximumWidth() > sideContainer->maximumWidth()) {
|
||||
m_sidebar->setMaximumWidth(sideContainer->maximumWidth());
|
||||
}
|
||||
}
|
||||
m_sidebar->setCurrentWidget(sideContainer);
|
||||
|
||||
m_printAction->setEnabled(m_tabs[tab].printEnabled);
|
||||
m_closeAction->setEnabled(m_tabs[tab].closeEnabled);
|
||||
|
@ -689,6 +829,13 @@ void Shell::closeTab(int tab)
|
|||
part->factory()->removeClient(part);
|
||||
}
|
||||
part->disconnect();
|
||||
|
||||
Okular::ViewerInterface *iPart = qobject_cast<Okular::ViewerInterface *>(m_tabs[tab].part);
|
||||
Q_ASSERT(iPart);
|
||||
QWidget *sideContainer = iPart->getSideContainer();
|
||||
m_sidebar->removeWidget(sideContainer);
|
||||
connect(part, &QObject::destroyed, sideContainer, &QObject::deleteLater);
|
||||
|
||||
part->deleteLater();
|
||||
m_tabs.removeAt(tab);
|
||||
m_tabWidget->removeTab(tab);
|
||||
|
@ -776,7 +923,7 @@ void Shell::applyOptionsToPart(QObject *part, const QString &serializedOptions)
|
|||
}
|
||||
}
|
||||
|
||||
void Shell::connectPart(QObject *part)
|
||||
void Shell::connectPart(const KParts::ReadWritePart *part)
|
||||
{
|
||||
// We're abusing the fact we know the part is our part here
|
||||
connect(this, SIGNAL(moveSplitter(int)), part, SLOT(moveSplitter(int))); // clazy:exclude=old-style-connect
|
||||
|
@ -788,6 +935,12 @@ void Shell::connectPart(QObject *part)
|
|||
// Otherwise the QSize,QSize gets turned into QSize, QSize that is not normalized signals and is slightly slower
|
||||
connect(part, SIGNAL(fitWindowToPage(QSize,QSize)), this, SLOT(slotFitWindowToPage(QSize,QSize))); // clazy:exclude=old-style-connect
|
||||
// clang-format on
|
||||
|
||||
// since sidebar is now docked to main window, we use another action
|
||||
// to show/hide it, so we should hide a similar KPart's action
|
||||
if (QAction *action = part->actionCollection()->action(QStringLiteral("show_leftpanel"))) {
|
||||
action->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Shell::print()
|
||||
|
@ -903,12 +1056,17 @@ void Shell::slotFitWindowToPage(const QSize pageViewSize, const QSize pageSize)
|
|||
|
||||
void Shell::hideWelcomeScreen()
|
||||
{
|
||||
m_sidebar->setVisible(m_showSidebarAction->isChecked());
|
||||
m_centralStackedWidget->setCurrentWidget(m_tabWidget);
|
||||
m_showSidebarAction->setEnabled(true);
|
||||
}
|
||||
|
||||
void Shell::showWelcomeScreen()
|
||||
{
|
||||
m_showSidebarAction->setEnabled(false);
|
||||
m_centralStackedWidget->setCurrentWidget(m_welcomeScreen);
|
||||
m_sidebar->setVisible(false);
|
||||
|
||||
refreshRecentsOnWelcomeScreen();
|
||||
}
|
||||
|
||||
|
@ -927,4 +1085,6 @@ void Shell::forgetRecentItem(QUrl const &url)
|
|||
}
|
||||
}
|
||||
|
||||
#include "shell.moc"
|
||||
|
||||
/* kate: replace-tabs on; indent-width 4; */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "welcomescreen.h"
|
||||
|
||||
class Sidebar;
|
||||
class KRecentFilesAction;
|
||||
class KToggleAction;
|
||||
class QTabWidget;
|
||||
|
@ -155,7 +156,7 @@ private:
|
|||
void setupActions();
|
||||
void openNewTab(const QUrl &url, const QString &serializedOptions);
|
||||
void applyOptionsToPart(QObject *part, const QString &serializedOptions);
|
||||
void connectPart(QObject *part);
|
||||
void connectPart(const KParts::ReadWritePart *part);
|
||||
int findTabIndex(QObject *sender) const;
|
||||
int findTabIndex(const QUrl &url) const;
|
||||
|
||||
|
@ -177,6 +178,7 @@ private:
|
|||
KToggleAction *m_openInTab;
|
||||
WelcomeScreen *m_welcomeScreen;
|
||||
QStackedWidget *m_centralStackedWidget;
|
||||
Sidebar *m_sidebar = nullptr;
|
||||
|
||||
struct TabState {
|
||||
explicit TabState(KParts::ReadWritePart *p)
|
||||
|
@ -194,6 +196,8 @@ private:
|
|||
QAction *m_nextTabAction;
|
||||
QAction *m_prevTabAction;
|
||||
QAction *m_undoCloseTab;
|
||||
QAction *m_showSidebarAction = nullptr;
|
||||
QAction *m_lockSidebarAction = nullptr;
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
KActivities::ResourceInstance *m_activityResource;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE gui SYSTEM "kpartgui.dtd">
|
||||
<gui version="9" name="okular_shell" >
|
||||
<gui version="10" name="okular_shell" >
|
||||
<MenuBar>
|
||||
<Menu name="file" >
|
||||
<DefineGroup append="open_merge" name="file_open" />
|
||||
|
@ -13,6 +13,7 @@
|
|||
</Menu-->
|
||||
<Menu name="settings" >
|
||||
<DefineGroup append="show_merge" name="show_merge" />
|
||||
<Action name="okular_show_sidebar" append="show_merge" />
|
||||
<DefineGroup append="configure_merge" name="configure_merge" />
|
||||
</Menu>
|
||||
<Merge/>
|
||||
|
@ -21,8 +22,12 @@
|
|||
</Menu>
|
||||
</MenuBar>
|
||||
<ToolBar noMerge="1" name="mainToolBar" >
|
||||
<Action name="okular_show_sidebar" />
|
||||
<text>Main Toolbar</text>
|
||||
<!--Action name="file_open_recent" /-->
|
||||
<!--Action name="file_print" /-->
|
||||
</ToolBar>
|
||||
<ActionProperties scheme="Default">
|
||||
<Action priority="0" name="okular_show_sidebar"/>
|
||||
</ActionProperties>
|
||||
</gui>
|
||||
|
|
Loading…
Reference in a new issue