Browse Source

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.
Le Tan 8 years ago
parent
commit
bf8bf9cc4f
4 changed files with 132 additions and 21 deletions
  1. 17 7
      src/veditarea.cpp
  2. 4 1
      src/veditarea.h
  3. 87 10
      src/veditwindow.cpp
  4. 24 3
      src/veditwindow.h

+ 17 - 7
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));
     }
 }
 

+ 4 - 1
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);

+ 87 - 10
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<VFile> 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) {

+ 24 - 3
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