synchronize current header in read and edit mode

Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
Le Tan 2016-12-12 21:58:53 +08:00
parent a884991150
commit 66c1d543c2
7 changed files with 74 additions and 16 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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