浏览代码

add indicator in status bar for edit tab

Le Tan 8 年之前
父节点
当前提交
5c17f74641
共有 19 个文件被更改,包括 327 次插入132 次删除
  1. 5 2
      src/src.pro
  2. 7 8
      src/veditarea.cpp
  3. 8 4
      src/veditarea.h
  4. 15 0
      src/vedittab.cpp
  5. 9 1
      src/vedittab.h
  6. 20 0
      src/vedittabinfo.h
  7. 29 47
      src/veditwindow.cpp
  8. 11 5
      src/veditwindow.h
  9. 5 11
      src/vhtmltab.cpp
  10. 0 3
      src/vhtmltab.h
  11. 38 19
      src/vmainwindow.cpp
  12. 7 3
      src/vmainwindow.h
  13. 2 0
      src/vmdedit.h
  14. 21 12
      src/vmdtab.cpp
  15. 3 3
      src/vmdtab.h
  16. 97 0
      src/vtabindicator.cpp
  17. 32 0
      src/vtabindicator.h
  18. 16 12
      src/vvimindicator.cpp
  19. 2 2
      src/vvimindicator.h

+ 5 - 2
src/src.pro

@@ -68,7 +68,8 @@ SOURCES += main.cpp\
     utils/vvim.cpp \
     utils/veditutils.cpp \
     vvimindicator.cpp \
-    vbuttonwithwidget.cpp
+    vbuttonwithwidget.cpp \
+    vtabindicator.cpp
 
 HEADERS  += vmainwindow.h \
     vdirectorytree.h \
@@ -123,7 +124,9 @@ HEADERS  += vmainwindow.h \
     utils/vvim.h \
     utils/veditutils.h \
     vvimindicator.h \
-    vbuttonwithwidget.h
+    vbuttonwithwidget.h \
+    vedittabinfo.h \
+    vtabindicator.h
 
 RESOURCES += \
     vnote.qrc \

+ 7 - 8
src/veditarea.cpp

@@ -67,8 +67,8 @@ void VEditArea::insertSplitWindow(int idx)
 {
     VEditWindow *win = new VEditWindow(vnote, this);
     splitter->insertWidget(idx, win);
-    connect(win, &VEditWindow::tabStatusChanged,
-            this, &VEditArea::handleEditWindowStatusChanged);
+    connect(win, &VEditWindow::tabStatusUpdated,
+            this, &VEditArea::handleWindowTabStatusUpdated);
     connect(win, &VEditWindow::requestSplitWindow,
             this, &VEditArea::handleSplitWindowRequest);
     connect(win, &VEditWindow::requestRemoveSplit,
@@ -85,12 +85,10 @@ void VEditArea::insertSplitWindow(int idx)
             this, &VEditArea::handleWindowVimStatusUpdated);
 }
 
-void VEditArea::handleEditWindowStatusChanged(const VFile *p_file,
-                                              const VEditTab *p_editTab,
-                                              bool p_editMode)
+void VEditArea::handleWindowTabStatusUpdated(const VEditTabInfo &p_info)
 {
     if (splitter->widget(curWindowIndex) == sender()) {
-        emit curTabStatusChanged(p_file, p_editTab, p_editMode);
+        emit tabStatusUpdated(p_info);
     }
 }
 
@@ -216,14 +214,15 @@ void VEditArea::updateWindowStatus()
 {
     if (curWindowIndex == -1) {
         Q_ASSERT(splitter->count() == 0);
-        emit curTabStatusChanged(NULL, NULL, false);
+
+        emit tabStatusUpdated(VEditTabInfo());
         emit outlineChanged(VToc());
         emit curHeaderChanged(VAnchor());
         return;
     }
 
     VEditWindow *win = getWindow(curWindowIndex);
-    win->requestUpdateTabStatus();
+    win->updateTabStatus();
     win->requestUpdateOutline();
     win->requestUpdateCurHeader();
 }

+ 8 - 4
src/veditarea.h

@@ -60,7 +60,9 @@ public:
     bool handleKeyNavigation(int p_key, bool &p_succeed) Q_DECL_OVERRIDE;
 
 signals:
-    void curTabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode);
+    // Emit when current window's tab status updated.
+    void tabStatusUpdated(const VEditTabInfo &p_info);
+
     void outlineChanged(const VToc &toc);
     void curHeaderChanged(const VAnchor &anchor);
 
@@ -98,9 +100,9 @@ private slots:
     void handleReplaceAll(const QString &p_text, uint p_options,
                           const QString &p_replaceText);
     void handleFindDialogClosed();
-    void handleEditWindowStatusChanged(const VFile *p_file,
-                                       const VEditTab *p_editTab,
-                                       bool p_editMode);
+
+    // Hanle the status update of current tab within a VEditWindow.
+    void handleWindowTabStatusUpdated(const VEditTabInfo &p_info);
 
     // Handle the statusMessage signal of VEditWindow.
     void handleWindowStatusMessage(const QString &p_msg);
@@ -117,6 +119,8 @@ private:
     inline VEditWindow *getWindow(int windowIndex) const;
     void insertSplitWindow(int idx);
     void removeSplitWindow(VEditWindow *win);
+
+    // Update status of current window.
     void updateWindowStatus();
 
     VNote *vnote;

+ 15 - 0
src/vedittab.cpp

@@ -77,3 +77,18 @@ void VEditTab::wheelEvent(QWheelEvent *p_event)
 
     p_event->ignore();
 }
+
+void VEditTab::updateStatus()
+{
+    m_modified = m_file->isModified();
+
+    emit statusUpdated(createEditTabInfo());
+}
+
+VEditTabInfo VEditTab::createEditTabInfo()
+{
+    VEditTabInfo info;
+    info.m_editTab = this;
+
+    return info;
+}

+ 9 - 1
src/vedittab.h

@@ -7,6 +7,7 @@
 #include "vtoc.h"
 #include "vfile.h"
 #include "utils/vvim.h"
+#include "vedittabinfo.h"
 
 class VEditArea;
 
@@ -71,6 +72,9 @@ public slots:
     // Enter edit mode
     virtual void editFile() = 0;
 
+    // Update status of current tab. Emit statusUpdated().
+    virtual void updateStatus();
+
 protected:
     void wheelEvent(QWheelEvent *p_event) Q_DECL_OVERRIDE;
 
@@ -80,6 +84,9 @@ protected:
     // Called to zoom in/out content.
     virtual void zoom(bool p_zoomIn, qreal p_step = 0.25) = 0;
 
+    // Create a filled VEditTabInfo.
+    virtual VEditTabInfo createEditTabInfo();
+
     // File related to this tab.
     QPointer<VFile> m_file;
     bool m_isEditMode;
@@ -95,7 +102,8 @@ signals:
 
     void curHeaderChanged(const VAnchor &p_anchor);
 
-    void statusChanged();
+    // The status of current tab has updates.
+    void statusUpdated(const VEditTabInfo &p_info);
 
     // Emit when want to show message in status bar.
     void statusMessage(const QString &p_msg);

+ 20 - 0
src/vedittabinfo.h

@@ -0,0 +1,20 @@
+#ifndef VEDITTABINFO_H
+#define VEDITTABINFO_H
+
+class VEditTab;
+
+struct VEditTabInfo
+{
+    VEditTabInfo()
+        : m_editTab(NULL), m_cursorBlockNumber(-1), m_cursorPositionInBlock(-1),
+          m_blockCount(-1) {}
+
+    VEditTab *m_editTab;
+
+    // Cursor information. -1 for invalid info.
+    int m_cursorBlockNumber;
+    int m_cursorPositionInBlock;
+    int m_blockCount;
+};
+
+#endif // VEDITTABINFO_H

+ 29 - 47
src/veditwindow.cpp

@@ -166,7 +166,7 @@ bool VEditWindow::closeFile(const VFile *p_file, bool p_forced)
     Q_ASSERT(editor);
     if (!p_forced) {
         setCurrentIndex(idx);
-        noticeStatus(idx);
+        updateTabStatus(idx);
     }
     // Even p_forced is true we need to delete unused images.
     bool ok = editor->closeFile(p_forced);
@@ -226,7 +226,7 @@ bool VEditWindow::closeAllFiles(bool p_forced)
 
         if (!p_forced) {
             setCurrentIndex(0);
-            noticeStatus(0);
+            updateTabStatus(0);
         }
         // Even p_forced is true we need to delete unused images.
         bool ok = editor->closeFile(p_forced);
@@ -266,8 +266,8 @@ int VEditWindow::openFileInTab(VFile *p_file, OpenFileMode p_mode)
             this, &VEditWindow::handleOutlineChanged);
     connect(editor, &VEditTab::curHeaderChanged,
             this, &VEditWindow::handleCurHeaderChanged);
-    connect(editor, &VEditTab::statusChanged,
-            this, &VEditWindow::handleTabStatusChanged);
+    connect(editor, &VEditTab::statusUpdated,
+            this, &VEditWindow::handleTabStatusUpdated);
     connect(editor, &VEditTab::statusMessage,
             this, &VEditWindow::handleTabStatusMessage);
     connect(editor, &VEditTab::vimStatusUpdated,
@@ -333,20 +333,23 @@ void VEditWindow::saveFile()
     editor->saveFile();
 }
 
-void VEditWindow::noticeTabStatus(int p_index)
+void VEditWindow::updateTabStatus(int p_index)
 {
     if (p_index == -1) {
-        emit tabStatusChanged(NULL, NULL, false);
-        return;
+        p_index = currentIndex();
     }
 
-    updateTabInfo(p_index);
-    updateAllTabsSequence();
+    if (p_index == -1) {
+        emit tabStatusUpdated(VEditTabInfo());
+        emit outlineChanged(VToc());
+        emit curHeaderChanged(VAnchor());
+        return;
+    }
 
-    VEditTab *editor = getTab(p_index);
-    const VFile *file = editor->getFile();
-    bool editMode = editor->isEditMode();
-    emit tabStatusChanged(file, editor, editMode);
+    VEditTab *tab = getTab(p_index);
+    tab->updateStatus();
+    tab->requestUpdateOutline();
+    tab->requestUpdateCurHeader();
 }
 
 void VEditWindow::updateTabInfo(int p_index)
@@ -372,12 +375,6 @@ void VEditWindow::updateAllTabsSequence()
     }
 }
 
-// Be requested to report current status
-void VEditWindow::requestUpdateTabStatus()
-{
-    noticeTabStatus(currentIndex());
-}
-
 // Be requested to report current outline
 void VEditWindow::requestUpdateOutline()
 {
@@ -492,7 +489,7 @@ void VEditWindow::tabListJump(VFile *p_file)
     int idx = findTabByFile(p_file);
     Q_ASSERT(idx >= 0);
     setCurrentIndex(idx);
-    noticeStatus(idx);
+    updateTabStatus(idx);
 }
 
 void VEditWindow::updateSplitMenu()
@@ -552,31 +549,16 @@ void VEditWindow::scrollCurTab(const VAnchor &p_anchor)
     }
 }
 
-// Update tab status, outline and current header.
-void VEditWindow::noticeStatus(int index)
+void VEditWindow::handleTabStatusUpdated(const VEditTabInfo &p_info)
 {
-    qDebug() << "tab" << index;
-    noticeTabStatus(index);
+    int idx = indexOf(dynamic_cast<QWidget *>(sender()));
 
-    if (index == -1) {
-        emit outlineChanged(VToc());
-        emit curHeaderChanged(VAnchor());
-    } else {
-        VEditTab *tab = getTab(index);
-        tab->requestUpdateOutline();
-        tab->requestUpdateCurHeader();
-    }
-}
+    updateTabInfo(idx);
+    updateAllTabsSequence();
 
-void VEditWindow::handleTabStatusChanged()
-{
-    int idx = indexOf(dynamic_cast<QWidget *>(sender()));
     if (idx == currentIndex()) {
-        noticeTabStatus(idx);
-    } else {
-        // Only update the tab status. Do no propagate upwards.
-        updateTabInfo(idx);
-        updateAllTabsSequence();
+        // Current tab. Propogate its status.
+        emit tabStatusUpdated(p_info);
     }
 }
 
@@ -603,7 +585,7 @@ void VEditWindow::updateFileInfo(const VFile *p_file)
     }
     int idx = findTabByFile(p_file);
     if (idx > -1) {
-        noticeStatus(idx);
+        updateTabStatus(idx);
     }
 }
 
@@ -618,7 +600,7 @@ void VEditWindow::updateDirectoryInfo(const VDirectory *p_dir)
         VEditTab *editor = getTab(i);
         QPointer<VFile> file = editor->getFile();
         if (p_dir->containsFile(file)) {
-            noticeStatus(i);
+            updateTabStatus(i);
         }
     }
 }
@@ -634,7 +616,7 @@ void VEditWindow::updateNotebookInfo(const VNotebook *p_notebook)
         VEditTab *editor = getTab(i);
         QPointer<VFile> file = editor->getFile();
         if (p_notebook->containsFile(file)) {
-            noticeStatus(i);
+            updateTabStatus(i);
         }
     }
 }
@@ -727,11 +709,11 @@ bool VEditWindow::addEditTab(QWidget *p_widget)
             this, &VEditWindow::handleOutlineChanged);
     connect(editor, &VEditTab::curHeaderChanged,
             this, &VEditWindow::handleCurHeaderChanged);
-    connect(editor, &VEditTab::statusChanged,
-            this, &VEditWindow::handleTabStatusChanged);
+    connect(editor, &VEditTab::statusUpdated,
+            this, &VEditWindow::handleTabStatusUpdated);
     int idx = appendEditTab(editor->getFile(), editor);
     setCurrentIndex(idx);
-    noticeTabStatus(idx);
+    updateTabStatus(idx);
     return true;
 }
 

+ 11 - 5
src/veditwindow.h

@@ -32,7 +32,6 @@ public:
     void readFile();
     void saveAndReadFile();
     bool closeAllFiles(bool p_forced);
-    void requestUpdateTabStatus();
     void requestUpdateOutline();
     void requestUpdateCurHeader();
     // Focus to current tab's editor
@@ -56,11 +55,18 @@ public:
     bool alternateTab();
     VEditTab *getTab(int tabIndex) const;
 
+    // Ask tab @p_index to update its status and propogate.
+    // The status here means tab status, outline, current header.
+    // If @p_index is -1, it is current tab.
+    void updateTabStatus(int p_index = -1);
+
 protected:
     void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
 
 signals:
-    void tabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode);
+    // Status of current VEditTab has update.
+    void tabStatusUpdated(const VEditTabInfo &p_info);
+
     void requestSplitWindow(VEditWindow *curWindow);
     void requestRemoveSplit(VEditWindow *curWindow);
     // This widget or its children get the focus
@@ -84,7 +90,6 @@ private slots:
     void tabListJump(VFile *p_file);
     void handleOutlineChanged(const VToc &p_toc);
     void handleCurHeaderChanged(const VAnchor &p_anchor);
-    void handleTabStatusChanged();
     void updateSplitMenu();
     void tabbarContextMenuRequested(QPoint p_pos);
     void handleLocateAct();
@@ -97,6 +102,9 @@ private slots:
     // Handle the vimStatusUpdated() signal of VEditTab.
     void handleTabVimStatusUpdated(const VVim *p_vim);
 
+    // Handle the statusUpdated signal of VEditTab.
+    void handleTabStatusUpdated(const VEditTabInfo &p_info);
+
 private:
     void initTabActions();
     void setupCornerWidget();
@@ -104,8 +112,6 @@ private:
     int insertEditTab(int p_index, VFile *p_file, QWidget *p_page);
     int appendEditTab(VFile *p_file, QWidget *p_page);
     int openFileInTab(VFile *p_file, OpenFileMode p_mode);
-    void noticeTabStatus(int p_index);
-    void noticeStatus(int index);
     inline QString generateTooltip(const VFile *p_file) const;
     inline QString generateTabText(int p_index, const QString &p_name,
                                    bool p_modified, bool p_modifiable) const;

+ 5 - 11
src/vhtmltab.cpp

@@ -48,6 +48,7 @@ void VHtmlTab::setupUI()
 
     QVBoxLayout *mainLayout = new QVBoxLayout();
     mainLayout->addWidget(m_editor);
+    mainLayout->setContentsMargins(0, 0, 0, 0);
     setLayout(mainLayout);
 }
 
@@ -59,14 +60,7 @@ void VHtmlTab::handleTextChanged()
         return;
     }
 
-    noticeStatusChanged();
-}
-
-void VHtmlTab::noticeStatusChanged()
-{
-    m_modified = m_file->isModified();
-
-    emit statusChanged();
+    updateStatus();
 }
 
 void VHtmlTab::showFileReadMode()
@@ -75,7 +69,7 @@ void VHtmlTab::showFileReadMode()
 
     m_editor->setReadOnly(true);
 
-    noticeStatusChanged();
+    updateStatus();
 }
 
 void VHtmlTab::showFileEditMode()
@@ -89,7 +83,7 @@ void VHtmlTab::showFileEditMode()
     m_editor->beginEdit();
     m_editor->setFocus();
 
-    noticeStatusChanged();
+    updateStatus();
 }
 
 bool VHtmlTab::closeFile(bool p_forced)
@@ -184,7 +178,7 @@ bool VHtmlTab::saveFile()
         m_editor->setModified(true);
     }
 
-    noticeStatusChanged();
+    updateStatus();
 
     return ret;
 }

+ 0 - 3
src/vhtmltab.h

@@ -56,9 +56,6 @@ private slots:
     // Handle text changed in m_editor.
     void handleTextChanged();
 
-    // Emit statusChanged() signal to notify that status of this tab has changed.
-    void noticeStatusChanged();
-
     // m_editor requests to save changes and enter read mode.
     void saveAndRead();
 

+ 38 - 19
src/vmainwindow.cpp

@@ -21,6 +21,7 @@
 #include "vexporter.h"
 #include "vmdtab.h"
 #include "vvimindicator.h"
+#include "vtabindicator.h"
 
 extern VConfigManager vconfig;
 
@@ -108,8 +109,8 @@ void VMainWindow::setupUI()
             editArea, &VEditArea::openFile);
     connect(fileList, &VFileList::fileUpdated,
             editArea, &VEditArea::handleFileUpdated);
-    connect(editArea, &VEditArea::curTabStatusChanged,
-            this, &VMainWindow::handleCurTabStatusChanged);
+    connect(editArea, &VEditArea::tabStatusUpdated,
+            this, &VMainWindow::handleAreaTabStatusUpdated);
     connect(editArea, &VEditArea::statusMessage,
             this, &VMainWindow::showStatusMessage);
     connect(editArea, &VEditArea::vimStatusUpdated,
@@ -119,10 +120,15 @@ void VMainWindow::setupUI()
 
     setCentralWidget(mainSplitter);
 
-    // Create and show the status bar
     m_vimIndicator = new VVimIndicator(this);
     m_vimIndicator->hide();
+
+    m_tabIndicator = new VTabIndicator(this);
+    m_tabIndicator->hide();
+
+    // Create and show the status bar
     statusBar()->addPermanentWidget(m_vimIndicator);
+    statusBar()->addPermanentWidget(m_tabIndicator);
 }
 
 QWidget *VMainWindow::setupDirectoryPanel()
@@ -1108,18 +1114,26 @@ void VMainWindow::updateActionStateFromTabStatusChange(const VFile *p_file,
     }
 }
 
-void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode)
+void VMainWindow::handleAreaTabStatusUpdated(const VEditTabInfo &p_info)
 {
-    updateActionStateFromTabStatusChange(p_file, p_editMode);
-    if (p_file) {
-        m_findReplaceDialog->updateState(p_file->getDocType(), p_editMode);
+    bool editMode = false;
+    m_curTab = p_info.m_editTab;
+    if (m_curTab) {
+        m_curFile = m_curTab->getFile();
+        editMode = m_curTab->isEditMode();
+    } else {
+        m_curFile = NULL;
     }
 
+    updateActionStateFromTabStatusChange(m_curFile, editMode);
+
     QString title;
-    if (p_file) {
-        title = QString("[%1] %2").arg(p_file->getNotebookName()).arg(p_file->retrivePath());
-        if (p_file->isModifiable()) {
-            if (p_file->isModified()) {
+    if (m_curFile) {
+        m_findReplaceDialog->updateState(m_curFile->getDocType(), editMode);
+
+        title = QString("[%1] %2").arg(m_curFile->getNotebookName()).arg(m_curFile->retrivePath());
+        if (m_curFile->isModifiable()) {
+            if (m_curFile->isModified()) {
                 title.append('*');
             }
         } else {
@@ -1128,10 +1142,7 @@ void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, const VEditTab
     }
 
     updateWindowTitle(title);
-    m_curFile = const_cast<VFile *>(p_file);
-    m_curTab = const_cast<VEditTab *>(p_editTab);
-
-    updateStatusInfo(p_editMode);
+    updateStatusInfo(p_info);
 }
 
 void VMainWindow::onePanelView()
@@ -1505,12 +1516,20 @@ void VMainWindow::showStatusMessage(const QString &p_msg)
     statusBar()->showMessage(p_msg, timeout);
 }
 
-void VMainWindow::updateStatusInfo(bool p_editMode)
+void VMainWindow::updateStatusInfo(const VEditTabInfo &p_info)
 {
-    if (!p_editMode || !m_curTab) {
-        m_vimIndicator->hide();
+    if (m_curTab) {
+        m_tabIndicator->update(p_info);
+        m_tabIndicator->show();
+
+        if (m_curTab->isEditMode()) {
+            m_curTab->requestUpdateVimStatus();
+        } else {
+            m_vimIndicator->hide();
+        }
     } else {
-        m_curTab->requestUpdateVimStatus();
+        m_tabIndicator->hide();
+        m_vimIndicator->hide();
     }
 }
 

+ 7 - 3
src/vmainwindow.h

@@ -30,6 +30,7 @@ class VAvatar;
 class VFindReplaceDialog;
 class VCaptain;
 class VVimIndicator;
+class VTabIndicator;
 
 class VMainWindow : public QMainWindow
 {
@@ -61,7 +62,6 @@ private slots:
     void changeHighlightSelectedWord(bool p_checked);
     void changeHighlightSearchedWord(bool p_checked);
     void changeHighlightTrailingSapce(bool p_checked);
-    void handleCurTabStatusChanged(const VFile *p_file, const VEditTab *p_editTab, bool p_editMode);
     void onePanelView();
     void twoPanelView();
     void expandPanelView(bool p_checked);
@@ -92,6 +92,9 @@ private slots:
     // Handle Vim status updated.
     void handleVimStatusUpdated(const VVim *p_vim);
 
+    // Handle the status update of the current tab of VEditArea.
+    void handleAreaTabStatusUpdated(const VEditTabInfo &p_info);
+
 protected:
     void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
     void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
@@ -131,8 +134,8 @@ private:
     void toggleOnePanelView();
     void closeCurrentFile();
 
-    // Update status bar information according to m_curTab and m_curFile.
-    void updateStatusInfo(bool p_editMode);
+    // Update status bar information.
+    void updateStatusInfo(const VEditTabInfo &p_info);
 
     // Wrapper to create a QAction.
     QAction *newAction(const QIcon &p_icon,
@@ -158,6 +161,7 @@ private:
     VAvatar *m_avatar;
     VFindReplaceDialog *m_findReplaceDialog;
     VVimIndicator *m_vimIndicator;
+    VTabIndicator *m_tabIndicator;
 
     // Whether it is one panel or two panles.
     bool m_onePanel;

+ 2 - 0
src/vmdedit.h

@@ -45,6 +45,8 @@ signals:
     // Signal when current header change.
     void curHeaderChanged(VAnchor p_anchor);
 
+    // Signal when the status of VMdEdit changed.
+    // Will be emitted by VImagePreviewer for now.
     void statusChanged();
 
 private slots:

+ 21 - 12
src/vmdtab.cpp

@@ -49,11 +49,13 @@ void VMdTab::setupUI()
         connect(dynamic_cast<VMdEdit *>(m_editor), &VMdEdit::headersChanged,
                 this, &VMdTab::updateTocFromHeaders);
         connect(dynamic_cast<VMdEdit *>(m_editor), &VMdEdit::statusChanged,
-                this, &VMdTab::noticeStatusChanged);
+                this, &VMdTab::updateStatus);
         connect(m_editor, SIGNAL(curHeaderChanged(VAnchor)),
                 this, SLOT(updateCurHeader(VAnchor)));
         connect(m_editor, &VEdit::textChanged,
                 this, &VMdTab::handleTextChanged);
+        connect(m_editor, &VEdit::cursorPositionChanged,
+                this, &VMdTab::updateStatus);
         connect(m_editor, &VEdit::saveAndRead,
                 this, &VMdTab::saveAndRead);
         connect(m_editor, &VEdit::discardAndRead,
@@ -82,14 +84,7 @@ void VMdTab::handleTextChanged()
         return;
     }
 
-    noticeStatusChanged();
-}
-
-void VMdTab::noticeStatusChanged()
-{
-    m_modified = m_file->isModified();
-
-    emit statusChanged();
+    updateStatus();
 }
 
 void VMdTab::showFileReadMode()
@@ -110,7 +105,7 @@ void VMdTab::showFileReadMode()
 
     scrollWebViewToHeader(outlineIndex);
 
-    noticeStatusChanged();
+    updateStatus();
 }
 
 void VMdTab::scrollWebViewToHeader(int p_outlineIndex)
@@ -173,7 +168,7 @@ void VMdTab::showFileEditMode()
 
     mdEdit->setFocus();
 
-    noticeStatusChanged();
+    updateStatus();
 }
 
 bool VMdTab::closeFile(bool p_forced)
@@ -268,7 +263,7 @@ bool VMdTab::saveFile()
         m_editor->setModified(true);
     }
 
-    noticeStatusChanged();
+    updateStatus();
 
     return ret;
 }
@@ -656,3 +651,17 @@ void VMdTab::requestUpdateVimStatus()
         emit vimStatusUpdated(NULL);
     }
 }
+
+VEditTabInfo VMdTab::createEditTabInfo()
+{
+    VEditTabInfo info = VEditTab::createEditTabInfo();
+
+    if (m_editor) {
+        QTextCursor cursor = m_editor->textCursor();
+        info.m_cursorBlockNumber = cursor.block().blockNumber();
+        info.m_cursorPositionInBlock = cursor.positionInBlock();
+        info.m_blockCount = m_editor->document()->blockCount();
+    }
+
+    return info;
+}

+ 3 - 3
src/vmdtab.h

@@ -65,9 +65,6 @@ private slots:
     // Handle text changed in m_editor.
     void handleTextChanged();
 
-    // Emit statusChanged() signal to notify that status of this tab has changed.
-    void noticeStatusChanged();
-
     // Update m_toc according to @p_tocHtml for read mode.
     void updateTocFromHtml(const QString &p_tocHtml);
 
@@ -122,6 +119,9 @@ private:
     // Focus the proper child widget.
     void focusChild() Q_DECL_OVERRIDE;
 
+    // Create a filled VEditTabInfo.
+    VEditTabInfo createEditTabInfo() Q_DECL_OVERRIDE;
+
     VEdit *m_editor;
     VWebView *m_webViewer;
     VDocument *m_document;

+ 97 - 0
src/vtabindicator.cpp

@@ -0,0 +1,97 @@
+#include "vtabindicator.h"
+
+#include <QLabel>
+#include <QHBoxLayout>
+
+#include "vedittab.h"
+
+VTabIndicator::VTabIndicator(QWidget *p_parent)
+    : QWidget(p_parent)
+{
+    setupUI();
+}
+
+void VTabIndicator::setupUI()
+{
+    m_docTypeLabel = new QLabel(this);
+    m_readonlyLabel = new QLabel(tr("<span style=\"font-weight:bold; color:red;\">ReadOnly</span>"),
+                                 this);
+    m_cursorLabel = new QLabel(this);
+
+    QHBoxLayout *mainLayout = new QHBoxLayout(this);
+    mainLayout->addWidget(m_cursorLabel);
+    mainLayout->addWidget(m_readonlyLabel);
+    mainLayout->addWidget(m_docTypeLabel);
+    mainLayout->setContentsMargins(0, 0, 0, 0);
+
+    setLayout(mainLayout);
+}
+
+static QString docTypeToString(DocType p_type)
+{
+    QString str;
+
+    switch (p_type) {
+    case DocType::Html:
+        str = "HTML";
+        break;
+
+    case DocType::Markdown:
+        str = "Markdown";
+        break;
+
+    case DocType::List:
+        str = "List";
+        break;
+
+    case DocType::Container:
+        str = "Container";
+        break;
+
+    default:
+        str = "Unknown";
+        break;
+    }
+
+    return str;
+}
+
+void VTabIndicator::update(const VEditTabInfo &p_info)
+{
+    const VEditTab *editTab = NULL;
+    const VFile *file = NULL;
+    DocType docType = DocType::Html;
+    bool readonly = true;
+    QString cursorStr;
+
+    if (p_info.m_editTab)
+    {
+        editTab = p_info.m_editTab;
+        file = editTab->getFile();
+        docType = file->getDocType();
+        readonly = !file->isModifiable();
+
+        if (editTab->isEditMode()) {
+            int line = p_info.m_cursorBlockNumber + 1;
+            int col = p_info.m_cursorPositionInBlock;
+            if (col < 0) {
+                col = 0;
+            }
+
+            int lineCount = p_info.m_blockCount < 1 ? 1 : p_info.m_blockCount;
+
+            QString cursorText = tr("<span><span style=\"font-weight:bold;\">Line</span>: %1 - %2(%3%)  "
+                                    "<span style=\"font-weight:bold;\">Col</span>: %4</span>")
+                                   .arg(line).arg(lineCount)
+                                   .arg((int)(line * 1.0 / lineCount * 100), 2)
+                                   .arg(col, 3);
+            m_cursorLabel->setText(cursorText);
+            m_cursorLabel->show();
+        } else {
+            m_cursorLabel->hide();
+        }
+    }
+
+    m_docTypeLabel->setText(docTypeToString(docType));
+    m_readonlyLabel->setVisible(readonly);
+}

+ 32 - 0
src/vtabindicator.h

@@ -0,0 +1,32 @@
+#ifndef VTABINDICATOR_H
+#define VTABINDICATOR_H
+
+#include <QWidget>
+#include "vedittabinfo.h"
+
+class QLabel;
+
+class VTabIndicator : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit VTabIndicator(QWidget *p_parent = 0);
+
+    // Update indicator.
+    void update(const VEditTabInfo &p_info);
+
+private:
+    void setupUI();
+
+    // Indicate the doc type.
+    QLabel *m_docTypeLabel;
+
+    // Indicate the readonly property.
+    QLabel *m_readonlyLabel;
+
+    // Indicate the position of current cursor.
+    QLabel *m_cursorLabel;
+};
+
+#endif // VTABINDICATOR_H

+ 16 - 12
src/vvimindicator.cpp

@@ -13,8 +13,8 @@
 
 extern VConfigManager vconfig;
 
-VVimIndicator::VVimIndicator(QWidget *parent)
-    : QWidget(parent), m_vim(NULL)
+VVimIndicator::VVimIndicator(QWidget *p_parent)
+    : QWidget(p_parent), m_vim(NULL)
 {
     setupUI();
 }
@@ -26,6 +26,7 @@ void VVimIndicator::setupUI()
     m_regBtn = new VButtonWithWidget(QIcon(":/resources/icons/arrow_dropup.svg"),
                                      "\"",
                                      this);
+    m_regBtn->setToolTip(tr("Registers"));
     m_regBtn->setProperty("StatusBtn", true);
     m_regBtn->setFocusPolicy(Qt::NoFocus);
     QTreeWidget *regTree = new QTreeWidget(this);
@@ -41,6 +42,7 @@ void VVimIndicator::setupUI()
     m_markBtn = new VButtonWithWidget(QIcon(":/resources/icons/arrow_dropup.svg"),
                                       "[]",
                                       this);
+    m_markBtn->setToolTip(tr("Marks"));
     m_markBtn->setProperty("StatusBtn", true);
     m_markBtn->setFocusPolicy(Qt::NoFocus);
     QTreeWidget *markTree = new QTreeWidget(this);
@@ -154,16 +156,18 @@ static void fillTreeItemsWithRegisters(QTreeWidget *p_tree,
 
 void VVimIndicator::update(const VVim *p_vim)
 {
-    if (!p_vim) {
-        m_vim = p_vim;
-        return;
-    }
-
     m_vim = p_vim;
 
-    VimMode mode = p_vim->getMode();
-    QChar curRegName = p_vim->getCurrentRegisterName();
-    QChar lastUsedMark = p_vim->getMarks().getLastUsedMark();
+    VimMode mode = VimMode::Normal;
+    QChar curRegName(' ');
+    QChar lastUsedMark;
+    QString pendingKeys;
+    if (p_vim) {
+        mode = p_vim->getMode();
+        curRegName = p_vim->getCurrentRegisterName();
+        lastUsedMark = p_vim->getMarks().getLastUsedMark();
+        pendingKeys = p_vim->getPendingKeys();
+    }
 
     QString style = QString("QLabel { padding: 0px 2px 0px 2px; font: bold; background-color: %1; }")
                            .arg(modeBackgroundColor(mode));
@@ -176,8 +180,8 @@ void VVimIndicator::update(const VVim *p_vim)
                               .arg(lastUsedMark.isNull() ? QChar(' ') : lastUsedMark);
     m_markBtn->setText(markText);
 
-    QString keyText = QString("<span style=\"font-weight:bold;\">%1</span>")
-                             .arg(p_vim->getPendingKeys());
+    QString keyText = QString("<span style=\"font-weight:bold; color: %1;\">%2</span>")
+                             .arg("#15AE67").arg(pendingKeys);
     m_keyLabel->setText(keyText);
 }
 

+ 2 - 2
src/vvimindicator.h

@@ -12,9 +12,9 @@ class VVimIndicator : public QWidget
     Q_OBJECT
 
 public:
-    explicit VVimIndicator(QWidget *parent = 0);
+    explicit VVimIndicator(QWidget *p_parent = 0);
 
-public slots:
+    // Update indicator according to @p_vim.
     void update(const VVim *p_vim);
 
 private slots: