mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
678 lines
18 KiB
C++
678 lines
18 KiB
C++
#ifndef VEDITOR_H
|
|
#define VEDITOR_H
|
|
|
|
#include <QPointer>
|
|
#include <QVector>
|
|
#include <QList>
|
|
#include <QTextEdit>
|
|
#include <QColor>
|
|
#include <QSharedPointer>
|
|
|
|
#include "veditconfig.h"
|
|
#include "vconstants.h"
|
|
#include "vfile.h"
|
|
#include "vwordcountinfo.h"
|
|
#include "vtexteditcompleter.h"
|
|
#include "vsearchconfig.h"
|
|
|
|
class QWidget;
|
|
class VEditorObject;
|
|
class VEditOperations;
|
|
class QTimer;
|
|
class QLabel;
|
|
class VVim;
|
|
enum class VimMode;
|
|
class QMouseEvent;
|
|
|
|
|
|
enum class SelectionId {
|
|
CurrentLine = 0,
|
|
SelectedWord,
|
|
SearchedKeyword,
|
|
SearchedKeywordUnderCursor,
|
|
IncrementalSearchedKeyword,
|
|
TrailingSpace,
|
|
Tab,
|
|
MaxSelection
|
|
};
|
|
|
|
|
|
// Abstract class for an edit.
|
|
// Should inherit this class as well as QPlainTextEdit or QTextEdit.
|
|
// Will replace VEdit eventually.
|
|
class VEditor
|
|
{
|
|
public:
|
|
explicit VEditor(VFile *p_file,
|
|
QWidget *p_editor,
|
|
const QSharedPointer<VTextEditCompleter> &p_completer);
|
|
|
|
virtual ~VEditor();
|
|
|
|
void highlightCurrentLine();
|
|
|
|
virtual void beginEdit() = 0;
|
|
|
|
virtual void endEdit() = 0;
|
|
|
|
// Save buffer content to VFile.
|
|
virtual void saveFile() = 0;
|
|
|
|
virtual void reloadFile() = 0;
|
|
|
|
virtual bool scrollToBlock(int p_blockNumber) = 0;
|
|
|
|
bool isModified() const;
|
|
|
|
void setModified(bool p_modified);
|
|
|
|
// User requests to insert an image.
|
|
void insertImage();
|
|
|
|
// User requests to insert a link.
|
|
void insertLink();
|
|
|
|
// User requests to insert a table.
|
|
virtual void insertTable() = 0;
|
|
|
|
// Used for incremental search.
|
|
// User has enter the content to search, but does not enter the "find" button yet.
|
|
bool peekText(const QString &p_text, uint p_options, bool p_forward = true);
|
|
|
|
// If @p_cursor is not null, set the position of @p_cursor instead of current
|
|
// cursor.
|
|
bool findText(const QString &p_text,
|
|
uint p_options,
|
|
bool p_forward,
|
|
QTextCursor *p_cursor = nullptr,
|
|
QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor,
|
|
bool p_useLeftSideOfCursor = false);
|
|
|
|
bool findText(const VSearchToken &p_token, bool p_forward, bool p_fromStart);
|
|
|
|
// Constrain the scope.
|
|
bool findTextInRange(const QString &p_text,
|
|
uint p_options,
|
|
bool p_forward,
|
|
int p_start,
|
|
int p_end);
|
|
|
|
void replaceText(const QString &p_text,
|
|
uint p_options,
|
|
const QString &p_replaceText,
|
|
bool p_findNext);
|
|
|
|
void replaceTextAll(const QString &p_text,
|
|
uint p_options,
|
|
const QString &p_replaceText);
|
|
|
|
// Use m_findInfo to find next match.
|
|
void nextMatch(bool p_forward = false);
|
|
|
|
// Scroll the content to make @p_block visible.
|
|
// If the @p_block is too long to hold in one page, just let it occupy the
|
|
// whole page.
|
|
// Will not change current cursor.
|
|
virtual void makeBlockVisible(const QTextBlock &p_block) = 0;
|
|
|
|
// Clear IncrementalSearchedKeyword highlight.
|
|
void clearIncrementalSearchedWordHighlight(bool p_now = true);
|
|
|
|
// Clear SearchedKeyword highlight.
|
|
void clearSearchedWordHighlight();
|
|
|
|
// Clear SearchedKeywordUnderCursor Highlight.
|
|
void clearSearchedWordUnderCursorHighlight(bool p_now = true);
|
|
|
|
// Evaluate selected text or cursor word as magic words.
|
|
void evaluateMagicWords();
|
|
|
|
VFile *getFile() const;
|
|
|
|
VEditConfig &getConfig();
|
|
|
|
// Request to update Vim status.
|
|
void requestUpdateVimStatus();
|
|
|
|
// Jump to a title.
|
|
// @p_forward: jump forward or backward.
|
|
// @p_relativeLevel: 0 for the same level as current header;
|
|
// negative value for upper level;
|
|
// positive value is ignored.
|
|
// Returns true if the jump succeeded.
|
|
virtual bool jumpTitle(bool p_forward, int p_relativeLevel, int p_repeat) = 0;
|
|
|
|
void setInputMethodEnabled(bool p_enabled);
|
|
|
|
// Insert decoration markers or decorate selected text.
|
|
void decorateText(TextDecoration p_decoration, int p_level);
|
|
|
|
virtual bool isBlockVisible(const QTextBlock &p_block) = 0;
|
|
|
|
VEditorObject *object() const;
|
|
|
|
QWidget *getEditor() const;
|
|
|
|
// Scroll block @p_blockNum into the visual window.
|
|
// @p_dest is the position of the window: 0 for top, 1 for center, 2 for bottom.
|
|
// @p_blockNum is based on 0.
|
|
// Will set the cursor to the block.
|
|
virtual void scrollBlockInPage(int p_blockNum, int p_dest, int p_margin = 0) = 0;
|
|
|
|
// Update config according to global configurations.
|
|
virtual void updateConfig();
|
|
|
|
void setVimMode(VimMode p_mode);
|
|
|
|
VVim *getVim() const;
|
|
|
|
virtual QString getContent() const = 0;
|
|
|
|
// @p_modified: if true, delete the whole content and insert the new content.
|
|
virtual void setContent(const QString &p_content, bool p_modified = false) = 0;
|
|
|
|
virtual VWordCountInfo fetchWordCountInfo() const = 0;
|
|
|
|
virtual bool setCursorPosition(int p_blockNumber, int p_posInBlock);
|
|
|
|
QString fetchCompletionPrefix() const;
|
|
|
|
// Request text completion.
|
|
virtual void requestCompletion(bool p_reversed);
|
|
|
|
virtual bool isCompletionActivated() const;
|
|
|
|
virtual void insertCompletion(const QString &p_prefix, const QString &p_completion);
|
|
|
|
QFont getFont() const;
|
|
|
|
virtual void updateFontAndPalette() = 0;
|
|
|
|
// Wrapper functions for QPlainTextEdit/QTextEdit.
|
|
// Ends with W to distinguish it from the original interfaces.
|
|
public:
|
|
virtual void setExtraSelectionsW(const QList<QTextEdit::ExtraSelection> &p_selections) = 0;
|
|
|
|
virtual QTextDocument *documentW() const = 0;
|
|
|
|
virtual int tabStopWidthW() const = 0;
|
|
|
|
virtual void setTabStopWidthW(int p_width) = 0;
|
|
|
|
virtual QTextCursor textCursorW() const = 0;
|
|
|
|
virtual void setTextCursorW(const QTextCursor &p_cursor) = 0;
|
|
|
|
virtual void moveCursorW(QTextCursor::MoveOperation p_operation,
|
|
QTextCursor::MoveMode p_mode = QTextCursor::MoveAnchor) = 0;
|
|
|
|
virtual QScrollBar *verticalScrollBarW() const = 0;
|
|
|
|
virtual QScrollBar *horizontalScrollBarW() const = 0;
|
|
|
|
virtual bool findW(const QString &p_exp,
|
|
QTextDocument::FindFlags p_options = QTextDocument::FindFlags()) = 0;
|
|
|
|
virtual bool findW(const QRegExp &p_exp,
|
|
QTextDocument::FindFlags p_options = QTextDocument::FindFlags()) = 0;
|
|
|
|
virtual bool isReadOnlyW() const = 0;
|
|
virtual void setReadOnlyW(bool p_ro) = 0;
|
|
|
|
virtual QWidget *viewportW() const = 0;
|
|
|
|
virtual void insertPlainTextW(const QString &p_text) = 0;
|
|
|
|
virtual void undoW() = 0;
|
|
|
|
virtual void redoW() = 0;
|
|
|
|
// Whether display cursor as block.
|
|
virtual void setCursorBlockModeW(CursorBlock p_mode) = 0;
|
|
|
|
virtual void zoomInW(int p_range = 1) = 0;
|
|
|
|
virtual void zoomOutW(int p_range = 1) = 0;
|
|
|
|
virtual void ensureCursorVisibleW() = 0;
|
|
|
|
virtual QRect cursorRectW() = 0;
|
|
|
|
virtual QRect cursorRectW(const QTextCursor &p_cursor) = 0;
|
|
|
|
protected:
|
|
void init();
|
|
|
|
// Update m_config according to VConfigManager.
|
|
void updateEditConfig();
|
|
|
|
// Do some highlight on cursor position changed.
|
|
void highlightOnCursorPositionChanged();
|
|
|
|
void updateTimeStamp();
|
|
|
|
// Highlight selected text.
|
|
void highlightSelectedWord();
|
|
|
|
bool wordInSearchedSelection(const QString &p_text);
|
|
|
|
// Set read-only property and highlight current line.
|
|
void setReadOnlyAndHighlightCurrentLine(bool p_readonly);
|
|
|
|
// Handle the mouse press event of m_editor.
|
|
// Returns true if no further process is needed.
|
|
bool handleMousePressEvent(QMouseEvent *p_event);
|
|
|
|
bool handleMouseReleaseEvent(QMouseEvent *p_event);
|
|
|
|
bool handleMouseMoveEvent(QMouseEvent *p_event);
|
|
|
|
bool handleInputMethodQuery(Qt::InputMethodQuery p_query,
|
|
QVariant &p_var) const;
|
|
|
|
bool handleWheelEvent(QWheelEvent *p_event);
|
|
|
|
virtual int lineNumberAreaWidth() const = 0;
|
|
|
|
void addTempFile(const QString &p_file);
|
|
|
|
// Paste plain text.
|
|
void pastePlainText();
|
|
|
|
// Scroll cursor line if in need.
|
|
void scrollCursorLineIfNecessary();
|
|
|
|
QWidget *m_editor;
|
|
|
|
VEditorObject *m_object;
|
|
|
|
QPointer<VFile> m_file;
|
|
|
|
VEditOperations *m_editOps;
|
|
|
|
VEditConfig m_config;
|
|
|
|
private:
|
|
friend class VEditorObject;
|
|
|
|
// Info about one find-in-page.
|
|
struct FindInfo
|
|
{
|
|
FindInfo()
|
|
: m_start(0),
|
|
m_end(-1),
|
|
m_useToken(false),
|
|
m_options(0),
|
|
m_cacheValid(false)
|
|
{
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
m_start = 0;
|
|
m_end = -1;
|
|
|
|
m_useToken = false;
|
|
|
|
m_text.clear();
|
|
m_options = 0;
|
|
|
|
m_token.clear();
|
|
|
|
m_cacheValid = false;
|
|
m_result.clear();
|
|
}
|
|
|
|
void clearResult()
|
|
{
|
|
m_cacheValid = false;
|
|
m_result.clear();
|
|
}
|
|
|
|
bool isCached(const QString &p_text,
|
|
uint p_options,
|
|
int p_start = 0,
|
|
int p_end = -1) const
|
|
{
|
|
return m_cacheValid
|
|
&& !m_useToken
|
|
&& m_text == p_text
|
|
&& m_options == p_options
|
|
&& m_start == p_start
|
|
&& m_end == p_end;
|
|
}
|
|
|
|
bool isCached(const VSearchToken &p_token,
|
|
int p_start = 0,
|
|
int p_end = -1) const
|
|
{
|
|
return m_cacheValid
|
|
&& m_useToken
|
|
&& m_token == p_token
|
|
&& m_start == p_start
|
|
&& m_end == p_end;
|
|
}
|
|
|
|
void update(const QString &p_text,
|
|
uint p_options,
|
|
int p_start,
|
|
int p_end,
|
|
const QList<QTextCursor> &p_result)
|
|
{
|
|
m_start = p_start;
|
|
m_end = p_end;
|
|
|
|
m_useToken = false;
|
|
|
|
m_text = p_text;
|
|
m_options = p_options;
|
|
|
|
m_cacheValid = true;
|
|
m_result = p_result;
|
|
|
|
m_token.clear();
|
|
}
|
|
|
|
void update(const VSearchToken &p_token,
|
|
int p_start,
|
|
int p_end,
|
|
const QList<QTextCursor> &p_result)
|
|
{
|
|
m_start = p_start;
|
|
m_end = p_end;
|
|
|
|
m_useToken = true;
|
|
|
|
m_token = p_token;
|
|
|
|
m_cacheValid = true;
|
|
m_result = p_result;
|
|
|
|
m_text.clear();
|
|
m_options = 0;
|
|
}
|
|
|
|
bool isNull() const
|
|
{
|
|
if (m_useToken) {
|
|
return m_token.isEmpty();
|
|
} else {
|
|
return m_text.isEmpty();
|
|
}
|
|
}
|
|
|
|
// Find in [m_start, m_end).
|
|
int m_start;
|
|
int m_end;
|
|
|
|
bool m_useToken;
|
|
|
|
// Use text and options to search.
|
|
QString m_text;
|
|
uint m_options;
|
|
|
|
// Use token to search.
|
|
VSearchToken m_token;
|
|
|
|
bool m_cacheValid;
|
|
|
|
QList<QTextCursor> m_result;
|
|
};
|
|
|
|
// Filter out the trailing space right before cursor.
|
|
void filterTrailingSpace(QList<QTextEdit::ExtraSelection> &p_selects,
|
|
const QList<QTextEdit::ExtraSelection> &p_src);
|
|
|
|
// Trigger the timer to request highlight.
|
|
// If @p_now is true, stop the timer and highlight immediately.
|
|
void highlightExtraSelections(bool p_now = false);
|
|
|
|
// @p_fileter: a function to filter out highlight results.
|
|
void highlightTextAll(const QString &p_text,
|
|
uint p_options,
|
|
SelectionId p_id,
|
|
QTextCharFormat p_format,
|
|
void (*p_filter)(VEditor *,
|
|
QList<QTextEdit::ExtraSelection> &) = NULL);
|
|
|
|
// Find all the occurences of @p_text.
|
|
QList<QTextCursor> findTextAll(const QString &p_text,
|
|
uint p_options,
|
|
int p_start = 0,
|
|
int p_end = -1);
|
|
|
|
QList<QTextCursor> findTextAll(const VSearchToken &p_token,
|
|
int p_start = 0,
|
|
int p_end = -1);
|
|
|
|
const QList<QTextCursor> &findTextAllCached(const QString &p_text,
|
|
uint p_options,
|
|
int p_start = 0,
|
|
int p_end = -1);
|
|
|
|
const QList<QTextCursor> &findTextAllCached(const VSearchToken &p_token,
|
|
int p_start = 0,
|
|
int p_end = -1);
|
|
|
|
// Highlight @p_cursor as the incremental searched keyword.
|
|
void highlightIncrementalSearchedWord(const QTextCursor &p_cursor);
|
|
|
|
// Find @p_text in the document starting from @p_start.
|
|
// Returns true if @p_text is found and set @p_cursor to indicate
|
|
// the position.
|
|
// Will NOT change current cursor.
|
|
bool findTextHelper(const QString &p_text,
|
|
uint p_options,
|
|
bool p_forward,
|
|
int p_start,
|
|
bool &p_wrapped,
|
|
QTextCursor &p_cursor);
|
|
|
|
void showWrapLabel();
|
|
|
|
void highlightSearchedWord(const QList<QTextCursor> &p_matches);
|
|
|
|
// Highlight @p_cursor as the searched keyword under cursor.
|
|
void highlightSearchedWordUnderCursor(const QTextCursor &p_cursor);
|
|
|
|
QStringList generateCompletionCandidates(bool p_reversed) const;
|
|
|
|
void cleanUp();
|
|
|
|
bool findTextOne(const QString &p_text, uint p_options, bool p_forward);
|
|
|
|
// @p_end, -1 indicates the end of doc.
|
|
static QList<QTextCursor> findTextAllInRange(const QTextDocument *p_doc,
|
|
const QString &p_text,
|
|
QTextDocument::FindFlags p_flags,
|
|
int p_start = 0,
|
|
int p_end = -1);
|
|
|
|
static QList<QTextCursor> findTextAllInRange(const QTextDocument *p_doc,
|
|
const QRegExp &p_reg,
|
|
QTextDocument::FindFlags p_flags,
|
|
int p_start = 0,
|
|
int p_end = -1);
|
|
|
|
bool findTextInRange(const QString &p_text,
|
|
uint p_options,
|
|
bool p_forward,
|
|
QTextCursor *p_cursor = nullptr,
|
|
QTextCursor::MoveMode p_moveMode = QTextCursor::MoveAnchor,
|
|
bool p_useLeftSideOfCursor = false,
|
|
int p_start = 0,
|
|
int p_end = -1);
|
|
|
|
void updateTrailingSpaceAndTabHighlights();
|
|
|
|
bool needUpdateTrailingSpaceAndTabHighlights();
|
|
|
|
QLabel *m_wrapLabel;
|
|
QTimer *m_labelTimer;
|
|
|
|
QTextDocument *m_document;
|
|
|
|
// doHighlightExtraSelections() will highlight these selections.
|
|
// Selections are indexed by SelectionId.
|
|
QVector<QList<QTextEdit::ExtraSelection> > m_extraSelections;
|
|
|
|
QColor m_selectedWordFg;
|
|
QColor m_selectedWordBg;
|
|
|
|
QColor m_searchedWordFg;
|
|
QColor m_searchedWordBg;
|
|
|
|
QColor m_searchedWordCursorFg;
|
|
QColor m_searchedWordCursorBg;
|
|
|
|
QColor m_incrementalSearchedWordFg;
|
|
QColor m_incrementalSearchedWordBg;
|
|
|
|
QColor m_trailingSpaceColor;
|
|
QColor m_tabColor;
|
|
|
|
// Timer for extra selections highlight.
|
|
QTimer *m_highlightTimer;
|
|
|
|
// Timer for update trailing space.
|
|
QTimer *m_trailingSpaceTimer;
|
|
|
|
bool m_readyToScroll;
|
|
bool m_mouseMoveScrolled;
|
|
int m_oriMouseX;
|
|
int m_oriMouseY;
|
|
|
|
// Whether enable input method.
|
|
bool m_enableInputMethod;
|
|
|
|
TimeStamp m_timeStamp;
|
|
|
|
TimeStamp m_trailingSpaceSelectionTS;
|
|
|
|
QSharedPointer<VTextEditCompleter> m_completer;
|
|
|
|
// Temp files needed to be delete.
|
|
QStringList m_tempFiles;
|
|
|
|
FindInfo m_findInfo;
|
|
|
|
bool m_trailingSpaceHighlightEnabled;
|
|
bool m_tabHighlightEnabled;
|
|
|
|
// Functions for private slots.
|
|
private:
|
|
void labelTimerTimeout();
|
|
|
|
// Do the real work to highlight extra selections.
|
|
void doHighlightExtraSelections();
|
|
|
|
void doUpdateTrailingSpaceAndTabHighlights();
|
|
|
|
void clearFindCache();
|
|
};
|
|
|
|
|
|
// Since one class could not inherit QObject multiple times, we use this class
|
|
// for VEditor to signal/slot.
|
|
class VEditorObject : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit VEditorObject(VEditor *p_editor, QObject *p_parent = nullptr)
|
|
: QObject(p_parent), m_editor(p_editor)
|
|
{
|
|
}
|
|
|
|
signals:
|
|
// Emit when editor config has been updated.
|
|
void configUpdated();
|
|
|
|
// Emit when want to show message in status bar.
|
|
void statusMessage(const QString &p_msg);
|
|
|
|
// Request VEditTab to save and exit edit mode.
|
|
void saveAndRead();
|
|
|
|
// Request VEditTab to discard and exit edit mode.
|
|
void discardAndRead();
|
|
|
|
// Request VEditTab to edit current note.
|
|
void editNote();
|
|
|
|
// Request VEditTab to save this file.
|
|
void saveNote();
|
|
|
|
// Emit when Vim status updated.
|
|
void vimStatusUpdated(const VVim *p_vim);
|
|
|
|
// Emit when all initialization is ready.
|
|
void ready();
|
|
|
|
// Request the edit tab to close find and replace dialog.
|
|
void requestCloseFindReplaceDialog();
|
|
|
|
void mouseMoved(QMouseEvent *p_event);
|
|
|
|
void mousePressed(QMouseEvent *p_event);
|
|
|
|
void mouseReleased(QMouseEvent *p_event);
|
|
|
|
void mouseDoubleClicked(QMouseEvent *p_event);
|
|
|
|
void cursorPositionChanged();
|
|
|
|
private slots:
|
|
// Timer for find-wrap label.
|
|
void labelTimerTimeout()
|
|
{
|
|
m_editor->labelTimerTimeout();
|
|
}
|
|
|
|
// Do the real work to highlight extra selections.
|
|
void doHighlightExtraSelections()
|
|
{
|
|
m_editor->doHighlightExtraSelections();
|
|
}
|
|
|
|
void doUpdateTrailingSpaceAndTabHighlights()
|
|
{
|
|
m_editor->doUpdateTrailingSpaceAndTabHighlights();
|
|
}
|
|
|
|
void clearFindCache()
|
|
{
|
|
m_editor->clearFindCache();
|
|
}
|
|
|
|
private:
|
|
friend class VEditor;
|
|
|
|
VEditor *m_editor;
|
|
};
|
|
|
|
inline VFile *VEditor::getFile() const
|
|
{
|
|
return m_file;
|
|
}
|
|
|
|
inline VEditConfig &VEditor::getConfig()
|
|
{
|
|
return m_config;
|
|
}
|
|
|
|
inline VEditorObject *VEditor::object() const
|
|
{
|
|
return m_object;
|
|
}
|
|
|
|
inline QWidget *VEditor::getEditor() const
|
|
{
|
|
return m_editor;
|
|
}
|
|
|
|
inline void VEditor::addTempFile(const QString &p_file)
|
|
{
|
|
m_tempFiles.append(p_file);
|
|
}
|
|
#endif // VEDITOR_H
|