Skip to content

Commit

Permalink
Merge pull request #1057 from kiwix/tab_closing
Browse files Browse the repository at this point in the history
  • Loading branch information
mgautierfr authored Mar 20, 2024
2 parents 693b7b1 + 1daefcc commit 0a6fd10
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 110 deletions.
21 changes: 16 additions & 5 deletions src/kiwixapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ void KiwixApp::init()
setDesktopFileName("kiwix.desktop");
setStyleSheet(parseStyleFromFile(":/css/style.css"));

createAction();
createActions();
mp_mainWindow = new MainWindow;
getTabWidget()->setContentManagerView(mp_manager->getView());
getTabWidget()->setNewTabButton();
const auto newTabAction = getAction(KiwixApp::NewTabAction);
getTabWidget()->setNewTabButton(newTabAction);
connect(newTabAction, &QAction::triggered, this, &KiwixApp::newTab);
postInit();
mp_errorDialog = new QErrorMessage(mp_mainWindow);
setActivationWindow(mp_mainWindow);
Expand Down Expand Up @@ -128,6 +130,16 @@ KiwixApp::~KiwixApp()
}
}

void KiwixApp::newTab()
{
getTabWidget()->createNewTab(true, false);
auto& searchBar = mp_mainWindow->getTopWidget()->getSearchBar();
searchBar.setFocus(Qt::MouseFocusReason);
searchBar.clear();
searchBar.clearSuggestions();
searchBar.hideSuggestions();
}

QString KiwixApp::findLibraryDirectory()
{
// Check for library.xml in the same directory than the executable (portable kiwix-desktop)
Expand Down Expand Up @@ -340,7 +352,7 @@ void KiwixApp::setMonitorDir(const QString &dir) {
#define HIDE_ACTION(ID) mpa_actions[ID]->setVisible(false)
#define DISABLE_ACTION(ID) mpa_actions[ID]->setDisabled(true)

void KiwixApp::createAction()
void KiwixApp::createActions()
{
CREATE_ACTION_ICON_SHORTCUT(KiwixServeAction, "share", gt("local-kiwix-server"), QKeySequence(Qt::CTRL | Qt::Key_I));

Expand Down Expand Up @@ -370,8 +382,7 @@ void KiwixApp::createAction()

CREATE_ACTION_ICON_SHORTCUT(NewTabAction,"new-tab-icon", gt("new-tab"), QKeySequence::AddTab);

CREATE_ACTION_ICON_SHORTCUTS(CloseTabAction, "close", gt("close-tab"), QList<QKeySequence>({QKeySequence(Qt::CTRL | Qt::Key_F4), QKeySequence(Qt::CTRL | Qt::Key_W)}));
mpa_actions[CloseTabAction]->setIconVisibleInMenu(false);
CREATE_ACTION_SHORTCUTS(CloseCurrentTabAction, gt("close-tab"), QList<QKeySequence>({QKeySequence(Qt::CTRL | Qt::Key_F4), QKeySequence(Qt::CTRL | Qt::Key_W)}));

CREATE_ACTION_SHORTCUT(ReopenClosedTabAction, gt("reopen-closed-tab"), QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_T));
HIDE_ACTION(ReopenClosedTabAction);
Expand Down
5 changes: 3 additions & 2 deletions src/kiwixapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class KiwixApp : public QtSingleApplication
OpenHomePageAction,
PrintAction,
NewTabAction,
CloseTabAction,
CloseCurrentTabAction,
ReopenClosedTabAction,
BrowseLibraryAction,
OpenFileAction,
Expand Down Expand Up @@ -89,6 +89,7 @@ class KiwixApp : public QtSingleApplication
QString parseStyleFromFile(QString filePath);

public slots:
void newTab();
void openZimFile(const QString& zimfile="");
void openUrl(const QString& url, bool newTab=true);
void openUrl(const QUrl& url, bool newTab=true);
Expand All @@ -98,7 +99,7 @@ public slots:
void printVersions(std::ostream& out = std::cout);

protected:
void createAction();
void createActions();
void postInit();

private:
Expand Down
2 changes: 1 addition & 1 deletion src/mainmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ MainMenu::MainMenu(QWidget *parent) :

m_fileMenu.setTitle(gt("file"));
m_fileMenu.ADD_ACTION(NewTabAction);
m_fileMenu.ADD_ACTION(CloseTabAction);
m_fileMenu.ADD_ACTION(CloseCurrentTabAction);
m_fileMenu.ADD_ACTION(ReopenClosedTabAction);
m_fileMenu.ADD_ACTION(BrowseLibraryAction);
m_fileMenu.ADD_ACTION(OpenFileAction);
Expand Down
178 changes: 79 additions & 99 deletions src/tabbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ class QMenu;
#define QUITIFNULL(VIEW) if (nullptr==(VIEW)) { return; }
#define CURRENTIFNULL(VIEW) if(nullptr==VIEW) { VIEW = currentZimView();}

namespace
{

QAction* getAction(KiwixApp::Actions action) {
return KiwixApp::instance()->getAction(action);
}

} // unnamed namespace

TabBar::TabBar(QWidget *parent) :
QTabBar(parent)
{
Expand All @@ -24,78 +33,31 @@ TabBar::TabBar(QWidget *parent) :
setMovable(true);
setIconSize(QSize(30, 30));
connect(this, &QTabBar::currentChanged, this, &TabBar::onCurrentChanged, Qt::QueuedConnection);
auto app = KiwixApp::instance();

connect(app->getAction(KiwixApp::NextTabAction), &QAction::triggered, this, &TabBar::moveToNextTab);
connect(app->getAction(KiwixApp::PreviousTabAction), &QAction::triggered, this, &TabBar::moveToPreviousTab);
connect(app->getAction(KiwixApp::NewTabAction), &QAction::triggered,
this, [=]() {
this->createNewTab(true, false);
auto topWidget = KiwixApp::instance()->getMainWindow()->getTopWidget();
topWidget->getSearchBar().setFocus(Qt::MouseFocusReason);
topWidget->getSearchBar().clear();
topWidget->getSearchBar().clearSuggestions();
topWidget->getSearchBar().hideSuggestions();
});
connect(app->getAction(KiwixApp::CloseTabAction), &QAction::triggered,
connect(getAction(KiwixApp::NextTabAction), &QAction::triggered, this, &TabBar::moveToNextTab);
connect(getAction(KiwixApp::PreviousTabAction), &QAction::triggered, this, &TabBar::moveToPreviousTab);
connect(getAction(KiwixApp::CloseCurrentTabAction), &QAction::triggered,
this, [=]() {
auto index = currentIndex();
if (index < 0)
return;

// library tab cannot be closed
QWidget *w = mp_stackedWidget->widget(index);
if (qobject_cast<ContentManagerView*>(w)) {
return;
}
this->closeTab(index);
this->closeTab(currentIndex());
});
connect(app->getAction(KiwixApp::OpenHomePageAction), &QAction::triggered,
connect(getAction(KiwixApp::OpenHomePageAction), &QAction::triggered,
this, [=]() {
auto current = this->currentWebView();
QUITIFNULL(current);
current->setUrl("zim://" + current->zimId() + ".zim/");
});
connect(app->getAction(KiwixApp::SettingAction), &QAction::triggered,
this, [=]() {
SettingsView* view = KiwixApp::instance()->getSettingsManager()->getView();
for (int i = 0 ; i < mp_stackedWidget->count(); i++) {
if (mp_stackedWidget->widget(i) == view) {
setCurrentIndex(i);
return;
}
}
int index = currentIndex() + 1;
mp_stackedWidget->insertWidget(index, view);
emit tabDisplayed(TabType::SettingsTab);
insertTab(index,QIcon(":/icons/settings.svg"), gt("settings"));
QToolButton *tb = new QToolButton(this);
tb->setDefaultAction(KiwixApp::instance()->getAction(KiwixApp::CloseTabAction));
setTabButton(index, QTabBar::RightSide, tb);
setCurrentIndex(index);
});
connect(getAction(KiwixApp::SettingAction), &QAction::triggered,
this, &TabBar::openOrSwitchToSettingsTab);

for (int i = 0 ; i <= 9 ; i++) {
QAction *a = new QAction(this);
a->setData(QVariant::fromValue(i));
QKeySequence ks(Qt::ALT | (Qt::Key_0 + i));
a->setShortcut(ks);
a->setShortcut(QKeySequence(Qt::ALT | (Qt::Key_0 + i)));
addAction(a);
connect(a, &QAction::triggered, this, [=](){
QAction *a = qobject_cast<QAction*>(QObject::sender());
if (!a)
return;

bool ok;
int tab_n = a->data().toInt(&ok);
if (tab_n==0)
tab_n=10;
if (!ok)
return;
if (tab_n >= count())
return;

setCurrentIndex(tab_n-1);
const int tabIndex = i == 0 ? 9 : i - 1;
if (tabIndex < realTabCount()) {
setCurrentIndex(tabIndex);
}
});
}

Expand All @@ -104,6 +66,23 @@ TabBar::TabBar(QWidget *parent) :
this, SLOT(onTabMoved(int,int)), Qt::DirectConnection);
}

void TabBar::openOrSwitchToSettingsTab()
{
SettingsView* view = KiwixApp::instance()->getSettingsManager()->getView();
for (int i = 0 ; i < mp_stackedWidget->count(); i++) {
if (mp_stackedWidget->widget(i) == view) {
setCurrentIndex(i);
return;
}
}
int index = currentIndex() + 1;
mp_stackedWidget->insertWidget(index, view);
emit tabDisplayed(TabType::SettingsTab);
insertTab(index,QIcon(":/icons/settings.svg"), gt("settings"));
setCloseTabButton(index);
setCurrentIndex(index);
}

void TabBar::setStackedWidget(QStackedWidget *widget) {
mp_stackedWidget = widget;
connect(this, &QTabBar::currentChanged,
Expand All @@ -119,10 +98,10 @@ void TabBar::setContentManagerView(ContentManagerView* view)
setTabButton(idx, RightSide, nullptr);
}

void TabBar::setNewTabButton()
void TabBar::setNewTabButton(QAction* newTabAction)
{
QToolButton *tb = new QToolButton();
tb->setDefaultAction(KiwixApp::instance()->getAction(KiwixApp::NewTabAction));
tb->setDefaultAction(newTabAction);
tb->setIcon(QIcon(":/icons/new-tab-icon.svg"));
int idx = addTab("");
setTabEnabled(idx, false);
Expand All @@ -131,12 +110,12 @@ void TabBar::setNewTabButton()
setTabButton(idx, QTabBar::RightSide, Q_NULLPTR);
}

// Returns the count of real tabs with content (excluding the last pseudo-tab
// that acts as a button for creating new empty tabs; BTW what is the use for
// such empty tabs?)
int TabBar::realTabCount() const
{
// The last tab is "+" in TabBar, but that isn't a real tab which displays any content hence the real count is tab count - 1
if (count() < 1)
return 0;
return count() - 1;
return count() < 1 ? 0 : count() - 1;
}

void TabBar::moveToNextTab()
Expand All @@ -151,20 +130,32 @@ void TabBar::moveToPreviousTab()
setCurrentIndex(index <= 0 ? realTabCount() - 1 : index - 1);
}

ZimView* TabBar::createNewTab(bool setCurrent, bool adjacentToCurrentTab)
void TabBar::setCloseTabButton(int index)
{
auto tab = new ZimView(this, this);
int index;
if(adjacentToCurrentTab) {
index = currentIndex() + 1;
} else {
index = realTabCount(); // for New Tab Button
}
mp_stackedWidget->insertWidget(index, tab);
index = insertTab(index, "");
Q_ASSERT(index > 0 && index < realTabCount());

QToolButton *tb = new QToolButton(this);
tb->setDefaultAction(KiwixApp::instance()->getAction(KiwixApp::CloseTabAction));
QAction *a = new QAction(QIcon(":/icons/close.svg"), gt("close-tab"), tb);
a->setToolTip(getAction(KiwixApp::CloseCurrentTabAction)->toolTip());
tb->setDefaultAction(a);
setTabButton(index, QTabBar::RightSide, tb);
connect(tb, &QToolButton::triggered, this, [=]() {
for ( int i = 0; i < realTabCount(); ++i ) {
if ( tb == tabButton(i, QTabBar::RightSide) ) {
closeTab(i);
return;
}
}
});
}

ZimView* TabBar::createNewTab(bool setCurrent, bool nextToCurrentTab)
{
auto tab = new ZimView(this, this);
const int index = nextToCurrentTab ? currentIndex() + 1 : realTabCount();
mp_stackedWidget->insertWidget(index, tab);
insertTab(index, "");
setCloseTabButton(index);
if (setCurrent) {
setCurrentIndex(index);
}
Expand Down Expand Up @@ -265,48 +256,37 @@ void TabBar::triggerWebPageAction(QWebEnginePage::WebAction action, ZimView *wid

void TabBar::closeTabsByZimId(const QString &id)
{
// the last tab is + button, skip it
for (int i = count() - 2 ; i >= 0 ; i--) {
// 0th tab is always (unless this comment becomes outdated by the time you
// read it) the library tab, so iteration could start from 1, however we
// shouldn't try to save CPU cycles at the cost of the code breaking
// should this comment indeed become outdated ;)
for (int i = 0 ; i < realTabCount() ; ++i ) {
auto *zv = qobject_cast<ZimView*>(mp_stackedWidget->widget(i));
if (!zv)
continue;
if (zv->getWebView()->zimId() == id) {
if (zv && zv->getWebView()->zimId() == id) {
closeTab(i);
}
}
}

void TabBar::closeTab(int index)
{
// the last tab is + button, cannot be closed
if (index == this->realTabCount())
// The first and last tabs (i.e. the library tab and the + (new tab) button)
// cannot be closed
if (index <= 0 || index >= this->realTabCount())
return;

setSelectionBehaviorOnRemove(index);

QWidget *view = mp_stackedWidget->widget(index);

// library tab cannot be closed
if (qobject_cast<ContentManagerView*>(view)) {
return;
if ( index == currentIndex() ) {
setCurrentIndex(index + 1 == realTabCount() ? index - 1 : index + 1);
}

QWidget *view = mp_stackedWidget->widget(index);
mp_stackedWidget->removeWidget(view);
view->setParent(nullptr);
removeTab(index);
view->close();
view->deleteLater();
}

void TabBar::setSelectionBehaviorOnRemove(int index)
{
if (index == count() - 2) {
setCurrentIndex(index - 1);
} else {
setCurrentIndex(index + 1);
}
}

void TabBar::onCurrentChanged(int index)
{
if (index == -1)
Expand Down
9 changes: 6 additions & 3 deletions src/tabbar.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class TabBar : public QTabBar
void setStackedWidget(QStackedWidget* widget);

void setContentManagerView(ContentManagerView* view);
void setNewTabButton();
void setNewTabButton(QAction* newTabAction);
ZimView* createNewTab(bool setCurrent, bool adjacentToCurrentTab);

ZimView* currentZimView() {
Expand Down Expand Up @@ -61,20 +61,23 @@ class TabBar : public QTabBar

public slots:
void closeTab(int index);
void openOrSwitchToSettingsTab();
void fullScreenRequested(QWebEngineFullScreenRequest request);
void on_webview_titleChanged(const QString& title);
void moveToNextTab();
void moveToPreviousTab();

private:
void setCloseTabButton(int index);

private:
QStackedWidget* mp_stackedWidget;
QScopedPointer<FullScreenWindow> m_fullScreenWindow;

void setSelectionBehaviorOnRemove(int index);
// The "+" (new tab) button is implemented as a tab (that is always placed at the end).
// This function returns the count of real tabs.
int realTabCount() const;

private slots:
void onTabMoved(int from, int to);
void onCurrentChanged(int index);
Expand Down

0 comments on commit 0a6fd10

Please sign in to comment.