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

View File

@ -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;

View File

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

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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