From bf8bf9cc4fb26a1996f4fe826fc461a0d53df184 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Mon, 26 Jun 2017 19:38:57 +0800 Subject: [PATCH] refine context menu of edit tab 1. "Move one split left/right" will create a new split if needed; 2. Add "Close Tab", "Close Other Tabs", and "Close Tabs To The Right" actions. --- src/veditarea.cpp | 24 +++++++---- src/veditarea.h | 5 ++- src/veditwindow.cpp | 97 ++++++++++++++++++++++++++++++++++++++++----- src/veditwindow.h | 27 +++++++++++-- 4 files changed, 132 insertions(+), 21 deletions(-) diff --git a/src/veditarea.cpp b/src/veditarea.cpp index 98754eb2..51f9839f 100644 --- a/src/veditarea.cpp +++ b/src/veditarea.cpp @@ -70,7 +70,7 @@ void VEditArea::insertSplitWindow(int idx) connect(win, &VEditWindow::tabStatusUpdated, this, &VEditArea::handleWindowTabStatusUpdated); connect(win, &VEditWindow::requestSplitWindow, - this, &VEditArea::handleSplitWindowRequest); + this, &VEditArea::splitWindow); connect(win, &VEditWindow::requestRemoveSplit, this, &VEditArea::handleRemoveSplitRequest); connect(win, &VEditWindow::getFocused, @@ -338,21 +338,31 @@ void VEditArea::saveAndReadFile() win->saveAndReadFile(); } -void VEditArea::handleSplitWindowRequest(VEditWindow *curWindow) +void VEditArea::splitWindow(VEditWindow *p_window, bool p_right) { - if (!curWindow) { + if (!p_window) { return; } - int idx = splitter->indexOf(curWindow); - qDebug() << "window" << idx << "requests split itself"; - insertSplitWindow(++idx); + + int idx = splitter->indexOf(p_window); + Q_ASSERT(idx > -1); + if (p_right) { + ++idx; + } else { + --idx; + if (idx < 0) { + idx = 0; + } + } + + insertSplitWindow(idx); setCurrentWindow(idx, true); } void VEditArea::splitCurrentWindow() { if (curWindowIndex > -1) { - handleSplitWindowRequest(getWindow(curWindowIndex)); + splitWindow(getWindow(curWindowIndex)); } } diff --git a/src/veditarea.h b/src/veditarea.h index d58e57f7..acbd368e 100644 --- a/src/veditarea.h +++ b/src/veditarea.h @@ -87,7 +87,10 @@ public slots: void handleNotebookUpdated(const VNotebook *p_notebook); private slots: - void handleSplitWindowRequest(VEditWindow *curWindow); + // Split @curWindow via inserting a new window around it. + // @p_right: insert the new window on the right side. + void splitWindow(VEditWindow *p_window, bool p_right = true); + void handleRemoveSplitRequest(VEditWindow *curWindow); void handleWindowFocused(); void handleOutlineChanged(const VToc &toc); diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index 86c4ef10..bef8448b 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -33,7 +33,7 @@ VEditWindow::VEditWindow(VNote *vnote, VEditArea *editArea, QWidget *parent) this, &VEditWindow::tabbarContextMenuRequested); connect(this, &VEditWindow::tabCloseRequested, - this, &VEditWindow::handleTabCloseRequest); + this, &VEditWindow::closeTab); connect(this, &VEditWindow::tabBarClicked, this, &VEditWindow::handleTabbarClicked); connect(this, &VEditWindow::currentChanged, @@ -61,6 +61,55 @@ void VEditWindow::initTabActions() m_moveRightAct->setToolTip(tr("Move current tab to the split on the right")); connect(m_moveRightAct, &QAction::triggered, this, &VEditWindow::handleMoveRightAct); + + m_closeTabAct = new QAction(tr("Close Tab"), this); + m_closeTabAct->setToolTip(tr("Close current note tab")); + connect(m_closeTabAct, &QAction::triggered, + this, [this](){ + int tab = this->m_closeTabAct->data().toInt(); + Q_ASSERT(tab != -1); + closeTab(tab); + }); + + m_closeOthersAct = new QAction(tr("Close Other Tabs"), this); + m_closeOthersAct->setToolTip(tr("Close all other note tabs")); + connect(m_closeOthersAct, &QAction::triggered, + this, [this](){ + int tab = this->m_closeTabAct->data().toInt(); + Q_ASSERT(tab != -1); + + for (int i = tab - 1; i >= 0; --i) { + this->setCurrentIndex(i); + this->updateTabStatus(i); + if (this->closeTab(i)) { + --tab; + } + } + + for (int i = tab + 1; i < this->count();) { + this->setCurrentIndex(i); + this->updateTabStatus(i); + if (!this->closeTab(i)) { + ++i; + } + } + }); + + m_closeRightAct = new QAction(tr("Close Tabs To The Right"), this); + m_closeRightAct->setToolTip(tr("Close all the note tabs to the right of current tab")); + connect(m_closeRightAct, &QAction::triggered, + this, [this](){ + int tab = this->m_closeTabAct->data().toInt(); + Q_ASSERT(tab != -1); + + for (int i = tab + 1; i < this->count();) { + this->setCurrentIndex(i); + this->updateTabStatus(i); + if (!this->closeTab(i)) { + ++i; + } + } + }); } void VEditWindow::setupCornerWidget() @@ -103,9 +152,9 @@ void VEditWindow::setupCornerWidget() this, &VEditWindow::updateSplitMenu); } -void VEditWindow::splitWindow() +void VEditWindow::splitWindow(bool p_right) { - emit requestSplitWindow(this); + emit requestSplitWindow(this, p_right); } void VEditWindow::removeSplit() @@ -288,13 +337,13 @@ int VEditWindow::findTabByFile(const VFile *p_file) const return -1; } -bool VEditWindow::handleTabCloseRequest(int index) +bool VEditWindow::closeTab(int p_index) { - VEditTab *editor = getTab(index); + VEditTab *editor = getTab(p_index); Q_ASSERT(editor); bool ok = editor->closeFile(false); if (ok) { - removeEditTab(index); + removeEditTab(p_index); } // User clicks the close button. We should make this window @@ -458,23 +507,42 @@ void VEditWindow::tabbarContextMenuRequested(QPoint p_pos) if (tab == -1) { return; } + m_locateAct->setData(tab); VEditTab *editor = getTab(tab); QPointer file = editor->getFile(); if (file->getType() == FileType::Normal) { + // Locate to folder. menu.addAction(m_locateAct); } int totalWin = m_editArea->windowCount(); - if (totalWin > 1) { + // When there is only one tab and one split window, there is no need to + // display these two actions. + if (totalWin > 1 || count() > 1) { menu.addSeparator(); m_moveLeftAct->setData(tab); + // Move one split left. menu.addAction(m_moveLeftAct); m_moveRightAct->setData(tab); + // Move one split right. menu.addAction(m_moveRightAct); } + // Close tab, or other tabs, or tabs to the right. + menu.addSeparator(); + m_closeTabAct->setData(tab); + menu.addAction(m_closeTabAct); + if (count() > 1) { + m_closeOthersAct->setData(tab); + menu.addAction(m_closeOthersAct); + if (tab < count() - 1) { + m_closeRightAct->setData(tab); + menu.addAction(m_closeRightAct); + } + } + if (!menu.actions().isEmpty()) { menu.exec(bar->mapToGlobal(p_pos)); } @@ -657,10 +725,19 @@ void VEditWindow::handleMoveRightAct() void VEditWindow::moveTabOneSplit(int p_tabIdx, bool p_right) { Q_ASSERT(p_tabIdx > -1 && p_tabIdx < count()); - int totalWin = m_editArea->windowCount(); - if (totalWin < 2) { - return; + // Add split window if needed. + if (m_editArea->windowCount() < 2) { + // Request VEditArea to split window. + splitWindow(p_right); + + // Though the signal and slot will behave like a function call. We wait + // here until the window split finished. + while (m_editArea->windowCount() < 2) { + VUtils::sleepWait(100); + } } + + int totalWin = m_editArea->windowCount(); int idx = m_editArea->windowIndex(this); int newIdx = p_right ? idx + 1 : idx - 1; if (newIdx >= totalWin) { diff --git a/src/veditwindow.h b/src/veditwindow.h index 82f529dd..caf6c99a 100644 --- a/src/veditwindow.h +++ b/src/veditwindow.h @@ -67,7 +67,9 @@ signals: // Status of current VEditTab has update. void tabStatusUpdated(const VEditTabInfo &p_info); - void requestSplitWindow(VEditWindow *curWindow); + // Requst VEditArea to split this window. + void requestSplitWindow(VEditWindow *p_window, bool p_right = true); + void requestRemoveSplit(VEditWindow *curWindow); // This widget or its children get the focus void getFocused(); @@ -81,8 +83,12 @@ signals: void vimStatusUpdated(const VVim *p_vim); private slots: - bool handleTabCloseRequest(int index); - void splitWindow(); + // Close tab @p_index. + bool closeTab(int p_index); + + // Split this window on the right/left. + void splitWindow(bool p_right = true); + void removeSplit(); void handleTabbarClicked(int p_index); void handleCurrentIndexChanged(int p_index); @@ -116,7 +122,13 @@ private: inline QString generateTabText(int p_index, const QString &p_name, bool p_modified, bool p_modifiable) const; bool canRemoveSplit(); + + // Move tab at @p_tabIdx one split window. + // @p_right: move right or left. + // If there is only one split window, it will request to split current window + // and move the tab to the new split. void moveTabOneSplit(int p_tabIdx, bool p_right); + void updateTabInfo(int p_idx); // Update the sequence number of all the tabs. void updateAllTabsSequence(); @@ -140,6 +152,15 @@ private: QAction *m_locateAct; QAction *m_moveLeftAct; QAction *m_moveRightAct; + + // Close current tab action in tab menu. + QAction *m_closeTabAct; + + // Close other tabs action in tab menu. + QAction *m_closeOthersAct; + + // Close tabs to the right in tab menu. + QAction *m_closeRightAct; }; inline QString VEditWindow::generateTooltip(const VFile *p_file) const