mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 05:49:53 +08:00
synchronize current header in read and edit mode
Signed-off-by: Le Tan <tamlokveer@gmail.com>
This commit is contained in:
parent
a884991150
commit
66c1d543c2
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -28,9 +28,8 @@ VMainWindow::VMainWindow(QWidget *parent)
|
||||
initDockWindows();
|
||||
initAvatar();
|
||||
|
||||
setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
restoreStateAndGeometry();
|
||||
setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
notebookSelector->update();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user