diff --git a/src/kiwixapp.cpp b/src/kiwixapp.cpp index bdf00d69c..68bd76548 100644 --- a/src/kiwixapp.cpp +++ b/src/kiwixapp.cpp @@ -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); @@ -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) @@ -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)); @@ -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(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(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); diff --git a/src/kiwixapp.h b/src/kiwixapp.h index dd0a21801..c09a1d0de 100644 --- a/src/kiwixapp.h +++ b/src/kiwixapp.h @@ -34,7 +34,7 @@ class KiwixApp : public QtSingleApplication OpenHomePageAction, PrintAction, NewTabAction, - CloseTabAction, + CloseCurrentTabAction, ReopenClosedTabAction, BrowseLibraryAction, OpenFileAction, @@ -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); @@ -98,7 +99,7 @@ public slots: void printVersions(std::ostream& out = std::cout); protected: - void createAction(); + void createActions(); void postInit(); private: diff --git a/src/mainmenu.cpp b/src/mainmenu.cpp index 6a99d3794..e2c8cf5f9 100644 --- a/src/mainmenu.cpp +++ b/src/mainmenu.cpp @@ -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); diff --git a/src/tabbar.cpp b/src/tabbar.cpp index 6ea18e2f8..b26596528 100644 --- a/src/tabbar.cpp +++ b/src/tabbar.cpp @@ -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) { @@ -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(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(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); + } }); } @@ -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, @@ -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); @@ -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() @@ -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); } @@ -265,12 +256,13 @@ 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(mp_stackedWidget->widget(i)); - if (!zv) - continue; - if (zv->getWebView()->zimId() == id) { + if (zv && zv->getWebView()->zimId() == id) { closeTab(i); } } @@ -278,19 +270,16 @@ void TabBar::closeTabsByZimId(const QString &id) 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(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); @@ -298,15 +287,6 @@ void TabBar::closeTab(int index) 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) diff --git a/src/tabbar.h b/src/tabbar.h index f5cc2bbf6..edd02f50e 100644 --- a/src/tabbar.h +++ b/src/tabbar.h @@ -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() { @@ -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 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);