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
remotes/origin/work/svuorela/remove-write-only-variable-1
Eugene Popov 3 years ago committed by Albert Astals Cid
parent 38438b00bf
commit 2fbab13e1f
  1. 7
      interfaces/viewerinterface.h
  2. 5
      part/part.cpp
  3. 1
      part/part.h
  4. 5
      part/sidebar.cpp
  5. 2
      part/sidebar.h
  6. 162
      shell/shell.cpp
  7. 6
      shell/shell.h
  8. 7
      shell/shell.rc

@ -79,6 +79,13 @@ public:
*/ */
virtual bool openNewFilesInTabs() const = 0; virtual bool openNewFilesInTabs() const = 0;
/**
* Returns the sidebar container.
*
* @since 23.04
*/
virtual QWidget *getSideContainer() const = 0;
// SIGNALS // SIGNALS
/** /**
* The signal 'openSourceReference' is emitted whenever the user has triggered a source * 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(); return Okular::Settings::self()->shellOpenFileInTabs();
} }
QWidget *Part::getSideContainer() const
{
return m_sidebar->getSideContainer();
}
bool Part::activateTabIfAlreadyOpenFile() const bool Part::activateTabIfAlreadyOpenFile() const
{ {
return Okular::Settings::self()->switchToTabIfOpen(); return Okular::Settings::self()->switchToTabIfOpen();

@ -147,6 +147,7 @@ public:
bool areSourceLocationsShownGraphically() const override; bool areSourceLocationsShownGraphically() const override;
void setShowSourceLocationsGraphically(bool show) override; void setShowSourceLocationsGraphically(bool show) override;
bool openNewFilesInTabs() const override; bool openNewFilesInTabs() const override;
QWidget *getSideContainer() const override;
Q_INVOKABLE bool activateTabIfAlreadyOpenFile() const; Q_INVOKABLE bool activateTabIfAlreadyOpenFile() const;
void setModified(bool modified) override; void setModified(bool modified) override;

@ -166,6 +166,11 @@ void Sidebar::moveSplitter(int sideWidgetSize)
d->splitter->setSizes(splitterSizeList); d->splitter->setSizes(splitterSizeList);
} }
QWidget *Sidebar::getSideContainer() const
{
return d->sideContainer;
}
void Sidebar::splitterMoved(int /*pos*/, int index) void Sidebar::splitterMoved(int /*pos*/, int index)
{ {
// if the side panel has been resized, save splitter sizes // if the side panel has been resized, save splitter sizes

@ -33,6 +33,8 @@ public:
void moveSplitter(int sideWidgetSize); void moveSplitter(int sideWidgetSize);
QWidget *getSideContainer() const;
Q_SIGNALS: Q_SIGNALS:
void urlsDropped(const QList<QUrl> &urls); void urlsDropped(const QList<QUrl> &urls);

@ -36,6 +36,7 @@
#include <KXMLGUIFactory> #include <KXMLGUIFactory>
#include <QApplication> #include <QApplication>
#include <QDBusConnection> #include <QDBusConnection>
#include <QDockWidget>
#include <QDragMoveEvent> #include <QDragMoveEvent>
#include <QFileDialog> #include <QFileDialog>
#include <QMenuBar> #include <QMenuBar>
@ -62,6 +63,86 @@ static const char *shouldShowToolBarComingFromFullScreen = "shouldShowToolBarCom
static const char *const SESSION_URL_KEY = "Urls"; static const char *const SESSION_URL_KEY = "Urls";
static const char *const SESSION_TAB_KEY = "ActiveTab"; 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) Shell::Shell(const QString &serializedOptions)
: KParts::MainWindow() : KParts::MainWindow()
, m_menuBarWasShown(true) , m_menuBarWasShown(true)
@ -126,12 +207,27 @@ Shell::Shell(const QString &serializedOptions)
connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &Shell::closeTab); connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &Shell::closeTab);
connect(m_tabWidget->tabBar(), &QTabBar::tabMoved, this, &Shell::moveTabData); 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 // then, setup our actions
setupActions(); setupActions();
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
// and integrate the part's GUI with the shell's // and integrate the part's GUI with the shell's
setupGUI(Keys | ToolBar | Save); 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_tabs.append(TabState(firstPart));
m_tabWidget->addTab(firstPart->widget(), QString()); // triggers setActiveTab that calls createGUI( part ) 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_menuBarWasShown = group.readEntry(shouldShowMenuBarComingFromFullScreen, true);
m_toolBarWasShown = group.readEntry(shouldShowToolBarComingFromFullScreen, 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() void Shell::writeSettings()
{ {
saveRecents(); 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"); KConfigGroup group = KSharedConfig::openConfig()->group("Desktop Entry");
group.writeEntry("FullScreen", m_fullScreenAction->isChecked()); group.writeEntry("FullScreen", m_fullScreenAction->isChecked());
if (m_fullScreenAction->isChecked()) { if (m_fullScreenAction->isChecked()) {
@ -425,6 +535,19 @@ void Shell::setupActions()
m_undoCloseTab->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo"))); m_undoCloseTab->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo")));
m_undoCloseTab->setEnabled(false); m_undoCloseTab->setEnabled(false);
connect(m_undoCloseTab, &QAction::triggered, this, &Shell::undoCloseTab); 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) void Shell::saveProperties(KConfigGroup &group)
@ -673,7 +796,24 @@ bool Shell::queryClose()
void Shell::setActiveTab(int tab) void Shell::setActiveTab(int tab)
{ {
m_tabWidget->setCurrentIndex(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); 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_printAction->setEnabled(m_tabs[tab].printEnabled);
m_closeAction->setEnabled(m_tabs[tab].closeEnabled); m_closeAction->setEnabled(m_tabs[tab].closeEnabled);
@ -689,6 +829,13 @@ void Shell::closeTab(int tab)
part->factory()->removeClient(part); part->factory()->removeClient(part);
} }
part->disconnect(); 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(); part->deleteLater();
m_tabs.removeAt(tab); m_tabs.removeAt(tab);
m_tabWidget->removeTab(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 // 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 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 // 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 connect(part, SIGNAL(fitWindowToPage(QSize,QSize)), this, SLOT(slotFitWindowToPage(QSize,QSize))); // clazy:exclude=old-style-connect
// clang-format on // 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() void Shell::print()
@ -903,12 +1056,17 @@ void Shell::slotFitWindowToPage(const QSize pageViewSize, const QSize pageSize)
void Shell::hideWelcomeScreen() void Shell::hideWelcomeScreen()
{ {
m_sidebar->setVisible(m_showSidebarAction->isChecked());
m_centralStackedWidget->setCurrentWidget(m_tabWidget); m_centralStackedWidget->setCurrentWidget(m_tabWidget);
m_showSidebarAction->setEnabled(true);
} }
void Shell::showWelcomeScreen() void Shell::showWelcomeScreen()
{ {
m_showSidebarAction->setEnabled(false);
m_centralStackedWidget->setCurrentWidget(m_welcomeScreen); m_centralStackedWidget->setCurrentWidget(m_welcomeScreen);
m_sidebar->setVisible(false);
refreshRecentsOnWelcomeScreen(); refreshRecentsOnWelcomeScreen();
} }
@ -927,4 +1085,6 @@ void Shell::forgetRecentItem(QUrl const &url)
} }
} }
#include "shell.moc"
/* kate: replace-tabs on; indent-width 4; */ /* kate: replace-tabs on; indent-width 4; */

@ -24,6 +24,7 @@
#include "welcomescreen.h" #include "welcomescreen.h"
class Sidebar;
class KRecentFilesAction; class KRecentFilesAction;
class KToggleAction; class KToggleAction;
class QTabWidget; class QTabWidget;
@ -155,7 +156,7 @@ private:
void setupActions(); void setupActions();
void openNewTab(const QUrl &url, const QString &serializedOptions); void openNewTab(const QUrl &url, const QString &serializedOptions);
void applyOptionsToPart(QObject *part, 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(QObject *sender) const;
int findTabIndex(const QUrl &url) const; int findTabIndex(const QUrl &url) const;
@ -177,6 +178,7 @@ private:
KToggleAction *m_openInTab; KToggleAction *m_openInTab;
WelcomeScreen *m_welcomeScreen; WelcomeScreen *m_welcomeScreen;
QStackedWidget *m_centralStackedWidget; QStackedWidget *m_centralStackedWidget;
Sidebar *m_sidebar = nullptr;
struct TabState { struct TabState {
explicit TabState(KParts::ReadWritePart *p) explicit TabState(KParts::ReadWritePart *p)
@ -194,6 +196,8 @@ private:
QAction *m_nextTabAction; QAction *m_nextTabAction;
QAction *m_prevTabAction; QAction *m_prevTabAction;
QAction *m_undoCloseTab; QAction *m_undoCloseTab;
QAction *m_showSidebarAction = nullptr;
QAction *m_lockSidebarAction = nullptr;
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
KActivities::ResourceInstance *m_activityResource; KActivities::ResourceInstance *m_activityResource;

@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!DOCTYPE gui SYSTEM "kpartgui.dtd"> <!DOCTYPE gui SYSTEM "kpartgui.dtd">
<gui version="9" name="okular_shell" > <gui version="10" name="okular_shell" >
<MenuBar> <MenuBar>
<Menu name="file" > <Menu name="file" >
<DefineGroup append="open_merge" name="file_open" /> <DefineGroup append="open_merge" name="file_open" />
@ -13,6 +13,7 @@
</Menu--> </Menu-->
<Menu name="settings" > <Menu name="settings" >
<DefineGroup append="show_merge" name="show_merge" /> <DefineGroup append="show_merge" name="show_merge" />
<Action name="okular_show_sidebar" append="show_merge" />
<DefineGroup append="configure_merge" name="configure_merge" /> <DefineGroup append="configure_merge" name="configure_merge" />
</Menu> </Menu>
<Merge/> <Merge/>
@ -21,8 +22,12 @@
</Menu> </Menu>
</MenuBar> </MenuBar>
<ToolBar noMerge="1" name="mainToolBar" > <ToolBar noMerge="1" name="mainToolBar" >
<Action name="okular_show_sidebar" />
<text>Main Toolbar</text> <text>Main Toolbar</text>
<!--Action name="file_open_recent" /--> <!--Action name="file_open_recent" /-->
<!--Action name="file_print" /--> <!--Action name="file_print" /-->
</ToolBar> </ToolBar>
<ActionProperties scheme="Default">
<Action priority="0" name="okular_show_sidebar"/>
</ActionProperties>
</gui> </gui>

Loading…
Cancel
Save