Browse Source

synchronize current header in read and edit mode

Signed-off-by: Le Tan <[email protected]>
Le Tan 9 years ago
parent
commit
66c1d543c2
7 changed files with 74 additions and 16 deletions
  1. 43 7
      src/vedittab.cpp
  2. 2 1
      src/vedittab.h
  3. 1 2
      src/vmainwindow.cpp
  4. 17 3
      src/vmdedit.cpp
  5. 4 1
      src/vmdedit.h
  6. 3 0
      src/voutline.cpp
  7. 4 2
      src/vtoc.h

+ 43 - 7
src/vedittab.cpp

@@ -50,10 +50,11 @@ void VEditTab::setupUI()
         m_textEditor = new VMdEdit(m_file, this);
         connect(dynamic_cast<VMdEdit *>(m_textEditor), &VMdEdit::headersChanged,
                 this, &VEditTab::updateTocFromHeaders);
-        connect(m_textEditor, SIGNAL(curHeaderChanged(int)),
-                this, SLOT(updateCurHeader(int)));
+        connect(m_textEditor, SIGNAL(curHeaderChanged(int, int)),
+                this, SLOT(updateCurHeader(int, int)));
         connect(m_textEditor, &VEdit::textChanged,
                 this, &VEditTab::handleTextChanged);
+        m_textEditor->reloadFile();
         addWidget(m_textEditor);
 
         setupMarkdownPreview();
@@ -91,6 +92,7 @@ void VEditTab::showFileReadMode()
 {
     qDebug() << "read" << m_file->getName();
     isEditMode = false;
+    int outlineIndex = curHeader.m_outlineIndex;
     switch (m_file->getDocType()) {
     case DocType::Html:
         m_textEditor->setReadOnly(true);
@@ -98,10 +100,12 @@ void VEditTab::showFileReadMode()
     case DocType::Markdown:
         if (mdConverterType == MarkdownConverterType::Marked) {
             document.setText(m_file->getContent());
+            updateTocFromHtml(document.getToc());
         } else {
             previewByConverter();
         }
         setCurrentWidget(webPreviewer);
+        scrollPreviewToHeader(outlineIndex);
         break;
     default:
         qWarning() << "error: unknown doc type" << int(m_file->getDocType());
@@ -110,6 +114,18 @@ void VEditTab::showFileReadMode()
     noticeStatusChanged();
 }
 
+void VEditTab::scrollPreviewToHeader(int p_outlineIndex)
+{
+    Q_ASSERT(p_outlineIndex >= 0);
+    if (p_outlineIndex < tableOfContent.headers.size()) {
+        QString anchor = tableOfContent.headers[p_outlineIndex].anchor;
+        qDebug() << "scroll preview to" << p_outlineIndex << anchor;
+        if (!anchor.isEmpty()) {
+            document.scrollToAnchor(anchor.mid(1));
+        }
+    }
+}
+
 void VEditTab::previewByConverter()
 {
     VMarkdownConverter mdConverter;
@@ -126,8 +142,14 @@ void VEditTab::previewByConverter()
 void VEditTab::showFileEditMode()
 {
     isEditMode = true;
+
+    // beginEdit() may change curHeader.
+    int outlineIndex = curHeader.m_outlineIndex;
     m_textEditor->beginEdit();
     setCurrentWidget(m_textEditor);
+    if (m_file->getDocType() == DocType::Markdown) {
+        dynamic_cast<VMdEdit *>(m_textEditor)->scrollToHeader(outlineIndex);
+    }
     m_textEditor->setFocus();
     noticeStatusChanged();
 }
@@ -253,6 +275,9 @@ void VEditTab::handleFocusChanged(QWidget *old, QWidget *now)
 
 void VEditTab::updateTocFromHtml(const QString &tocHtml)
 {
+    if (isEditMode) {
+        return;
+    }
     tableOfContent.type = VHeaderType::Anchor;
     QVector<VHeader> &headers = tableOfContent.headers;
     headers.clear();
@@ -280,6 +305,9 @@ void VEditTab::updateTocFromHtml(const QString &tocHtml)
 
 void VEditTab::updateTocFromHeaders(const QVector<VHeader> &headers)
 {
+    if (!isEditMode) {
+        return;
+    }
     tableOfContent.type = VHeaderType::LineNumber;
     tableOfContent.headers = headers;
     tableOfContent.filePath = m_file->retrivePath();
@@ -379,22 +407,30 @@ void VEditTab::scrollToAnchor(const VAnchor &anchor)
 
 void VEditTab::updateCurHeader(const QString &anchor)
 {
-    if (curHeader.anchor.mid(1) == anchor) {
+    if (isEditMode || curHeader.anchor.mid(1) == anchor) {
         return;
     }
     curHeader = VAnchor(m_file->retrivePath(), "#" + anchor, -1);
     if (!anchor.isEmpty()) {
+        const QVector<VHeader> &headers = tableOfContent.headers;
+        for (int i = 0; i < headers.size(); ++i) {
+            if (headers[i].anchor == curHeader.anchor) {
+                curHeader.m_outlineIndex = i;
+                break;
+            }
+        }
         emit curHeaderChanged(curHeader);
     }
 }
 
-void VEditTab::updateCurHeader(int lineNumber)
+void VEditTab::updateCurHeader(int p_lineNumber, int p_outlineIndex)
 {
-    if (curHeader.lineNumber == lineNumber) {
+    if (!isEditMode || curHeader.lineNumber == p_lineNumber) {
         return;
     }
-    curHeader = VAnchor(m_file->retrivePath(), "", lineNumber);
-    if (lineNumber > -1) {
+    curHeader = VAnchor(m_file->retrivePath(), "", p_lineNumber);
+    curHeader.m_outlineIndex = p_outlineIndex;
+    if (p_lineNumber > -1) {
         emit curHeaderChanged(curHeader);
     }
 }

+ 2 - 1
src/vedittab.h

@@ -48,7 +48,7 @@ private slots:
     void handleFocusChanged(QWidget *old, QWidget *now);
     void updateTocFromHtml(const QString &tocHtml);
     void updateCurHeader(const QString &anchor);
-    void updateCurHeader(int lineNumber);
+    void updateCurHeader(int p_lineNumber, int p_outlineIndex);
     void updateTocFromHeaders(const QVector<VHeader> &headers);
     void handleTextChanged();
 
@@ -62,6 +62,7 @@ private:
     void parseTocUl(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
     void parseTocLi(QXmlStreamReader &xml, QVector<VHeader> &headers, int level);
     void noticeStatusChanged();
+    void scrollPreviewToHeader(int p_outlineIndex);
 
     QPointer<VFile> m_file;
     bool isEditMode;

+ 1 - 2
src/vmainwindow.cpp

@@ -28,9 +28,8 @@ VMainWindow::VMainWindow(QWidget *parent)
     initDockWindows();
     initAvatar();
 
-    setContextMenuPolicy(Qt::NoContextMenu);
-
     restoreStateAndGeometry();
+    setContextMenuPolicy(Qt::NoContextMenu);
 
     notebookSelector->update();
 }

+ 17 - 3
src/vmdedit.cpp

@@ -53,12 +53,15 @@ void VMdEdit::beginEdit()
 
     setFont(vconfig.getMdEditFont());
 
-    setPlainText(m_file->getContent());
+    Q_ASSERT(m_file->getContent() == toPlainText());
 
     initInitImages();
 
     setReadOnly(false);
     setModified(false);
+
+    // Request update outline.
+    generateEditOutline();
 }
 
 void VMdEdit::endEdit()
@@ -180,13 +183,14 @@ void VMdEdit::updateCurHeader()
     int curHeader = 0;
     QTextCursor cursor(this->textCursor());
     int curLine = cursor.block().firstLineNumber();
-    for (int i = m_headers.size() - 1; i >= 0; --i) {
+    int i = 0;
+    for (i = m_headers.size() - 1; i >= 0; --i) {
         if (m_headers[i].lineNumber <= curLine) {
             curHeader = m_headers[i].lineNumber;
             break;
         }
     }
-    emit curHeaderChanged(curHeader);
+    emit curHeaderChanged(curHeader, i == -1 ? 0 : i);
 }
 
 void VMdEdit::generateEditOutline()
@@ -209,3 +213,13 @@ void VMdEdit::generateEditOutline()
     emit headersChanged(m_headers);
     updateCurHeader();
 }
+
+void VMdEdit::scrollToHeader(int p_headerIndex)
+{
+    Q_ASSERT(p_headerIndex >= 0);
+    if (p_headerIndex < m_headers.size()) {
+        int line = m_headers[p_headerIndex].lineNumber;
+        qDebug() << "scroll editor to" << p_headerIndex << "line" << line;
+        scrollToLine(line);
+    }
+}

+ 4 - 1
src/vmdedit.h

@@ -20,9 +20,12 @@ public:
 
     void insertImage(const QString &p_name);
 
+    // Scroll to m_headers[p_headerIndex].
+    void scrollToHeader(int p_headerIndex);
+
 signals:
     void headersChanged(const QVector<VHeader> &headers);
-    void curHeaderChanged(int lineNumber);
+    void curHeaderChanged(int p_lineNumber, int p_outlineIndex);
 
 private slots:
     void generateEditOutline();

+ 3 - 0
src/voutline.cpp

@@ -53,6 +53,7 @@ void VOutline::updateTreeByLevel(const QVector<VHeader> &headers, int &index,
             QJsonObject itemJson;
             itemJson["anchor"] = header.anchor;
             itemJson["line_number"] = header.lineNumber;
+            itemJson["outline_index"] = index;
             item->setData(0, Qt::UserRole, itemJson);
             item->setText(0, header.name);
             item->setToolTip(0, header.name);
@@ -83,10 +84,12 @@ void VOutline::handleCurItemChanged(QTreeWidgetItem *p_curItem, QTreeWidgetItem
     QJsonObject itemJson = p_curItem->data(0, Qt::UserRole).toJsonObject();
     QString anchor = itemJson["anchor"].toString();
     int lineNumber = itemJson["line_number"].toInt();
+    int outlineIndex = itemJson["outline_index"].toInt();
     VAnchor tmp;
     tmp.filePath = outline.filePath;
     tmp.anchor = anchor;
     tmp.lineNumber = lineNumber;
+    tmp.m_outlineIndex = outlineIndex;
     if (tmp == curHeader) {
         return;
     }

+ 4 - 2
src/vtoc.h

@@ -23,12 +23,14 @@ struct VHeader
 
 struct VAnchor
 {
-    VAnchor() : lineNumber(-1) {}
+    VAnchor() : lineNumber(-1), m_outlineIndex(0) {}
     VAnchor(const QString filePath, const QString &anchor, int lineNumber)
-        : filePath(filePath), anchor(anchor), lineNumber(lineNumber) {}
+        : filePath(filePath), anchor(anchor), lineNumber(lineNumber), m_outlineIndex(0) {}
     QString filePath;
     QString anchor;
     int lineNumber;
+    // Index of this anchor in VToc outline.
+    int m_outlineIndex;
 
     bool operator==(const VAnchor &p_anchor) const {
         return (p_anchor.filePath == filePath