mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -28,9 +28,8 @@ VMainWindow::VMainWindow(QWidget *parent)
|
|||||||
initDockWindows();
|
initDockWindows();
|
||||||
initAvatar();
|
initAvatar();
|
||||||
|
|
||||||
setContextMenuPolicy(Qt::NoContextMenu);
|
|
||||||
|
|
||||||
restoreStateAndGeometry();
|
restoreStateAndGeometry();
|
||||||
|
setContextMenuPolicy(Qt::NoContextMenu);
|
||||||
|
|
||||||
notebookSelector->update();
|
notebookSelector->update();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user