From aea51d21e48b4c7c407478e32d22b365dc751964 Mon Sep 17 00:00:00 2001 From: "royqh1979@gmail.com" Date: Thu, 10 Jun 2021 09:34:59 +0800 Subject: [PATCH] * work save; add rtf exporter --- RedPandaIDE/RedPandaIDE.pro | 2 + RedPandaIDE/editor.cpp | 95 +++++++ RedPandaIDE/editor.h | 1 + RedPandaIDE/mainwindow.cpp | 2 +- RedPandaIDE/qsynedit/SynEdit.cpp | 4 +- RedPandaIDE/qsynedit/SynEdit.h | 2 +- RedPandaIDE/qsynedit/exporter/synexporter.cpp | 252 ++++++++++++++++++ RedPandaIDE/qsynedit/exporter/synexporter.h | 220 +++++++++++++++ 8 files changed, 574 insertions(+), 4 deletions(-) create mode 100644 RedPandaIDE/qsynedit/exporter/synexporter.cpp create mode 100644 RedPandaIDE/qsynedit/exporter/synexporter.h diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index d9be5851..4412f62b 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -26,6 +26,7 @@ SOURCES += \ qsynedit/SynEdit.cpp \ qsynedit/TextBuffer.cpp \ qsynedit/TextPainter.cpp \ + qsynedit/exporter/synexporter.cpp \ qsynedit/highlighter/base.cpp \ qsynedit/highlighter/composition.cpp \ qsynedit/highlighter/cpp.cpp \ @@ -59,6 +60,7 @@ HEADERS += \ qsynedit/TextBuffer.h \ qsynedit/TextPainter.h \ qsynedit/Types.h \ + qsynedit/exporter/synexporter.h \ qsynedit/highlighter/base.h \ qsynedit/highlighter/composition.h \ qsynedit/highlighter/cpp.h \ diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 74bc0f18..0e184885 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -73,6 +73,8 @@ Editor::Editor(QWidget *parent, const QString& filename, } applySettings(); + + connect(this,&SynEdit::statusChanged,this,&Editor::onStatusChanged); } Editor::~Editor() { @@ -258,6 +260,99 @@ void Editor::onLinesChanged(int startLine, int count) { qDebug()< fLineCount) +// and (fText.Lines.Count <> 0) and ((fLineCount>0) or (fText.Lines.Count>1)) then begin +// if devCodeCompletion.Enabled +// and SameStr(mainForm.ClassBrowser.CurrentFile,FileName) // Don't reparse twice +// then begin +// Reparse; +// end; +// if fText.Focused and devEditor.AutoCheckSyntax and devEditor.CheckSyntaxWhenReturn +// and (fText.Highlighter = dmMain.Cpp) then begin +// mainForm.CheckSyntaxInBack(self); +// end; +// end; +// fLineCount := fText.Lines.Count; +// // scModified is only fired when the modified state changes + if (changes.testFlag(scModified)) { + updateCaption(); + } + +// if (fTabStopBegin >=0) and (fTabStopY=fText.CaretY) then begin +// if StartsStr(fLineBeforeTabStop,fText.LineText) and EndsStr(fLineAfterTabStop, fText.LineText) then +// fTabStopBegin := Length(fLineBeforeTabStop); +// if fLineAfterTabStop = '' then +// fTabStopEnd := Length(fText.LineText)+1 +// else +// fTabStopEnd := Length(fText.LineText) - Length(fLineAfterTabStop); +// fXOffsetSince := fTabStopEnd - fText.CaretX; +// if (fText.CaretX < fTabStopBegin) or (fText.CaretX > (fTabStopEnd+1)) then begin +// fTabStopBegin :=-1; +// end; +// end; + + // scSelection includes anything caret related + if (changes.testFlag(SynStatusChange::scSelection)) { + //MainForm.SetStatusbarLineCol; + + +// // Update the function tip +// fFunctionTip.ForceHide := false; +// if Assigned(fFunctionTipTimer) then begin +// if fFunctionTip.Activated and FunctionTipAllowed then begin +// fFunctionTip.Parser := fParser; +// fFunctionTip.FileName := fFileName; +// fFunctionTip.Show; +// end else begin // Reset the timer +// fFunctionTipTimer.Enabled := false; +// fFunctionTipTimer.Enabled := true; +// end; + } + +// // Remove error line colors +// if not fIgnoreCaretChange then begin +// if (fErrorLine <> -1) and not fText.SelAvail then begin +// fText.InvalidateLine(fErrorLine); +// fText.InvalidateGutterLine(fErrorLine); +// fErrorLine := -1; +// end; +// end else +// fIgnoreCaretChange := false; + +// if fText.SelAvail then begin +// if fText.GetWordAtRowCol(fText.CaretXY) = fText.SelText then begin +// fSelChanged:=True; +// BeginUpdate; +// EndUpdate; +// end else if fSelChanged then begin +// fSelChanged:=False; //invalidate to unhighlight others +// BeginUpdate; +// EndUpdate; +// end; +// end else if fSelChanged then begin +// fSelChanged:=False; //invalidate to unhighlight others +// BeginUpdate; +// EndUpdate; +// end; +// end; + +// if scInsertMode in Changes then begin +// with MainForm.Statusbar do begin +// // Set readonly / insert / overwrite +// if fText.ReadOnly then +// Panels[2].Text := Lang[ID_READONLY] +// else if fText.InsertMode then +// Panels[2].Text := Lang[ID_INSERT] +// else +// Panels[2].Text := Lang[ID_OVERWRITE]; +// end; +// end; + +// mainForm.CaretList.AddCaret(self,fText.CaretY,fText.CaretX); +} + void Editor::applySettings() { SynEditorOptions options = eoAltSetsColumnMode | diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index e9e24e95..4a1e253a 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -72,6 +72,7 @@ protected slots: void onModificationChanged(bool status) ; void onCursorPositionChanged(int line, int index) ; void onLinesChanged(int startLine, int count) ; + void onStatusChanged(SynStatusChanges changes); private: static int newfileCount; diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 030aca35..61a84b90 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -143,7 +143,7 @@ void MainWindow::on_actionOpen_triggered() } void MainWindow::closeEvent(QCloseEvent *event) { - if (!mEditorList->closeAll(true)) { + if (!mEditorList->closeAll(false)) { event->ignore(); return ; } diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index 77dc0595..6b2e029f 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -58,8 +58,8 @@ SynEdit::SynEdit(QWidget *parent) : QAbstractScrollArea(parent) mCaretColor = QColorConstants::Red; mActiveLineColor = QColorConstants::Svg::lightblue; - mSelectedBackground = QColorConstants::Svg::lightgray; - mSelectedForeground = palette().color(QPalette::Text); + mSelectedBackground = palette().color(QPalette::Highlight); + mSelectedForeground = palette().color(QPalette::HighlightedText); mBookMarkOpt.connect(&mBookMarkOpt, &SynBookMarkOpt::changed, this, &SynEdit::bookMarkOptionsChanged); // fRightEdge has to be set before FontChanged is called for the first time diff --git a/RedPandaIDE/qsynedit/SynEdit.h b/RedPandaIDE/qsynedit/SynEdit.h index a96085e6..4ea0746d 100644 --- a/RedPandaIDE/qsynedit/SynEdit.h +++ b/RedPandaIDE/qsynedit/SynEdit.h @@ -31,7 +31,7 @@ enum class SynEditCaretType { ctVerticalLine=0, ctHorizontalLine=1, ctHalfBlock=2, ctBlock=3 }; -enum class SynStatusChange { +enum SynStatusChange { scNone = 0, scAll = 0x0001, scCaretX = 0x0002, diff --git a/RedPandaIDE/qsynedit/exporter/synexporter.cpp b/RedPandaIDE/qsynedit/exporter/synexporter.cpp new file mode 100644 index 00000000..8b9047a3 --- /dev/null +++ b/RedPandaIDE/qsynedit/exporter/synexporter.cpp @@ -0,0 +1,252 @@ +#include "synexporter.h" + +#include +#include +#include +#include + +SynExporter::SynExporter() +{ + mClipboardFormat = "text/plain"; + mFont = QGuiApplication::font(); + mBackgroundColor = QGuiApplication::palette().color(QPalette::Base); + mForegroundColor = QGuiApplication::palette().color(QPalette::Text); + mUseBackground = false; + mExportAsText = false; + clear(); + setTitle(""); +} + +void SynExporter::clear() +{ + mBuffer.clear(); + mLastStyle = SynFontStyle::fsNone; + mLastBG = QGuiApplication::palette().color(QPalette::Base); + mLastFG = QGuiApplication::palette().color(QPalette::Text); +} + +void SynExporter::CopyToClipboard() +{ + if (mExportAsText) { + CopyToClipboardFormat("text/plain"); + } else + CopyToClipboardFormat(clipboardFormat()); +} + +bool SynExporter::exportAsText() const +{ + return mExportAsText; +} + +void SynExporter::setExportAsText(bool Value) +{ + if (mExportAsText != Value) { + mExportAsText = Value; + clear(); + } +} + +QFont SynExporter::font() const +{ + return mFont; +} + +void SynExporter::setFont(const QFont &font) +{ + mFont = font; +} + +PSynHighlighter SynExporter::highlighter() const +{ + return mHighlighter; +} + +void SynExporter::setHighlighter(PSynHighlighter Value) +{ + if (mHighlighter != Value) { + mHighlighter = Value; + clear(); + if ((mHighlighter) && (mHighlighter->whitespaceAttribute()) && mUseBackground) + mBackgroundColor = mHighlighter->whitespaceAttribute()->background(); + } +} + +QString SynExporter::title() const +{ + return mTitle; +} + +void SynExporter::setTitle(const QString &Value) +{ + if (mTitle != Value) { + if (!Value.isEmpty()) + mTitle = Value; + else + mTitle = QObject::tr("Untitled"); + } +} + +bool SynExporter::useBackground() const +{ + return mUseBackground; +} + +void SynExporter::setUseBackground(bool Value) +{ + if (mUseBackground != Value) { + mUseBackground = Value; + clear(); + if ((mHighlighter) && (mHighlighter->whitespaceAttribute()) && mUseBackground) + mBackgroundColor = mHighlighter->whitespaceAttribute()->background(); + } +} + +FileEndingType SynExporter::fileEndingType() const +{ + return mFileEndingType; +} + +void SynExporter::setFileEndingType(const FileEndingType &fileEndingType) +{ + mFileEndingType = fileEndingType; +} + +QColor SynExporter::foregroundColor() const +{ + return mForegroundColor; +} + +void SynExporter::setForegroundColor(const QColor &value) +{ + if (mForegroundColor != value) { + mForegroundColor = value; + } +} + +QColor SynExporter::backgroundColor() const +{ + return mBackgroundColor; +} + +void SynExporter::setBackgroundColor(const QColor &value) +{ + if (mBackgroundColor != value) { + mBackgroundColor = value; + } +} + +QByteArray SynExporter::charset() const +{ + return mCharset; +} + +void SynExporter::setCharset(const QByteArray &charset) +{ + mCharset = charset; +} + +void SynExporter::AddData(const QString &AText) +{ + if (!AText.isEmpty()) { + QTextCodec* codec = QTextCodec::codecForName(mCharset); + mBuffer.append(codec->fromUnicode(AText)); + } +} + +void SynExporter::AddDataNewLine(const QString &AText) +{ + AddData(AText); + AddNewLine(); +} + +void SynExporter::AddNewLine() +{ + switch(mFileEndingType) { + case FileEndingType::Linux: + AddData("\n"); + case FileEndingType::Windows: + AddData("\r\n"); + case FileEndingType::Mac: + AddData("\r"); + } +} + +void SynExporter::CopyToClipboardFormat(QByteArray AFormat) +{ + QClipboard* clipboard = QGuiApplication::clipboard(); + QMimeData * mimeData = new QMimeData(); + mimeData->setData(AFormat,mBuffer); + clipboard->setMimeData(mimeData); +} + +void SynExporter::FormatToken(QString &Token) +{ + AddData(Token); +} + +int SynExporter::GetBufferSize() +{ + return mBuffer.size(); +} + +void SynExporter::InsertData(int APos, const QString &AText) +{ + if (!AText.isEmpty()) { + QTextCodec* codec = QTextCodec::codecForName(mCharset); + mBuffer.insert(APos,codec->fromUnicode(AText)); + } +} + +QString SynExporter::ReplaceReservedChars(QString &AToken) +{ + if (AToken.isEmpty()) + return ""; + QString result; + for (QChar ch:AToken) { + if (mReplaceReserved.contains(ch)) { + result += mReplaceReserved[ch]; + } else { + result += ch; + } + } + return result; +} + +static QColor ValidatedColor(const QColor& color, const QColor& defaultColor) { + if (color.isValid()) + return color; + else + return defaultColor; +} +void SynExporter::SetTokenAttribute(PSynHighlighterAttribute Attri) +{ + if (mFirstAttribute) { + mFirstAttribute = false; + mLastBG = ValidatedColor(Attri->background(), mBackgroundColor); + mLastFG = ValidatedColor(Attri->foreground(), mForegroundColor); + mLastStyle = Attri->styles(); + FormatBeforeFirstAttribute( + mUseBackground && (mLastBG != mBackgroundColor), + mLastFG != mForegroundColor, Attri->styles()); + } else { + bool ChangedBG = mUseBackground && + (mLastBG != ValidatedColor(Attri->background(), mBackgroundColor)); + bool ChangedFG = (mLastFG != ValidatedColor(Attri->foreground(), mForegroundColor)); + if (ChangedBG || ChangedFG || (mLastStyle != Attri->styles())) { + // which font style bits are to reset? + SynFontStyles ChangedStyles = mLastStyle & ~(Attri->styles()); + FormatAttributeDone(ChangedBG, ChangedFG, ChangedStyles); + // which font style bits are to set? + ChangedStyles = Attri->styles() & ~(mLastStyle); + mLastBG = ValidatedColor(Attri->background(), mBackgroundColor); + mLastFG = ValidatedColor(Attri->foreground(), mForegroundColor); + mLastStyle = Attri->styles(); + FormatAttributeInit(ChangedBG, ChangedFG, ChangedStyles); + } + } +} + +QByteArray SynExporter::clipboardFormat() +{ + return this->mClipboardFormat; +} diff --git a/RedPandaIDE/qsynedit/exporter/synexporter.h b/RedPandaIDE/qsynedit/exporter/synexporter.h new file mode 100644 index 00000000..7333472f --- /dev/null +++ b/RedPandaIDE/qsynedit/exporter/synexporter.h @@ -0,0 +1,220 @@ +#ifndef SYNEXPORTER_H +#define SYNEXPORTER_H + +#include +#include "../SynEdit.h" + + + +using FormatTokenHandler = std::function; +class SynExporter +{ +public: + explicit SynExporter(); + + /** + * @brief Clears the output buffer and any internal data that relates to the last + * exported text. + */ + virtual void clear(); + /** + * @brief Copies the output buffer contents to the clipboard, as the native format + * or as text depending on the ExportAsText property. + */ + void CopyToClipboard(); + /** + * @brief Exports everything in the strings parameter to the output buffer. + * @param ALines + */ + void ExportAll(const SynEditStringList& ALines); + + /** + * @brief Exports the given range of the strings parameter to the output buffer. + * @param ALines + * @param Start + * @param Stop + */ + void ExportRange(const SynEditStringList& ALines, + const BufferCoord& Start, const BufferCoord& Stop); + /** + * @brief Saves the contents of the output buffer to a file. + * @param AFileName + */ + void SaveToFile(const QString& AFileName); + /** + * @brief Saves the contents of the output buffer to a stream. + * @param AStream + */ + void SaveToStream(const QIODevice& AStream); + bool exportAsText() const; + void setExportAsText(bool Value); + + QFont font() const; + void setFont(const QFont &font); + + PSynHighlighter highlighter() const; + void setHighlighter(PSynHighlighter Value); + + QString title() const; + void setTitle(const QString &Value); + + bool useBackground() const; + void setUseBackground(bool Value); + + FileEndingType fileEndingType() const; + void setFileEndingType(const FileEndingType &fileEndingType); + + /** + * @brief The clipboard format the exporter creates as native format. + * @return + */ + virtual QByteArray clipboardFormat(); + + QColor foregroundColor() const; + void setForegroundColor(const QColor &value); + + QColor backgroundColor() const; + void setBackgroundColor(const QColor &value); + + QByteArray charset() const; + void setCharset(const QByteArray &charset); + +protected: + QByteArray mCharset; + QColor mBackgroundColor; + QColor mForegroundColor; + QByteArray mClipboardFormat; + QString mDefaultFilter; + bool mExportAsText; + QFont mFont; + PSynHighlighter mHighlighter; + QColor mLastBG; + QColor mLastFG; + SynFontStyles mLastStyle; + QMap mReplaceReserved; + QString mTitle; + bool mUseBackground; + FileEndingType mFileEndingType; + + /** + * @brief Adds a string to the output buffer. + * @param AText + */ + void AddData(const QString& AText); + + /** + * @brief Adds a string and a trailing newline to the output buffer. + * @param AText + */ + void AddDataNewLine(const QString& AText); + + /** + * @brief Adds a newline to the output buffer. + */ + void AddNewLine(); + + + /** + * @brief Copies the data under this format to the clipboard. The clipboard has to + * be opened explicitly when more than one format is to be set. + */ + void CopyToClipboardFormat(QByteArray AFormat); + + /** + * @brief Has to be overridden in descendant classes to add the closing format + * strings to the output buffer. The parameters can be used to track what + * changes are made for the next token. + * @param BackgroundChanged + * @param ForegroundChanged + * @param FontStylesChanged + */ + virtual void FormatAttributeDone(bool BackgroundChanged, bool ForegroundChanged, + SynFontStyles FontStylesChanged) = 0; + + /** + * @brief Has to be overridden in descendant classes to add the opening format + * strings to the output buffer. The parameters can be used to track what + * changes have been made in respect to the previous token. + * @param BackgroundChanged + * @param ForegroundChanged + * @param FontStylesChanged + */ + virtual void FormatAttributeInit(bool BackgroundChanged, bool ForegroundChanged, + SynFontStyles FontStylesChanged) = 0; + /** + * @brief Has to be overridden in descendant classes to add the closing format + * strings to the output buffer after the last token has been written. + */ + virtual void FormatAfterLastAttribute() = 0; + + /** + * @brief Has to be overridden in descendant classes to add the opening format + * strings to the output buffer when the first token is about to be written. + * @param BackgroundChanged + * @param ForegroundChanged + * @param FontStylesChanged + */ + virtual void FormatBeforeFirstAttribute(bool BackgroundChanged, bool ForegroundChanged, + SynFontStyles FontStylesChanged) = 0; + /** + * @brief Can be overridden in descendant classes to add the formatted text of + * the actual token text to the output buffer. + */ + virtual void FormatToken(QString& Token) ; + /** + * @brief Has to be overridden in descendant classes to add a newline in the output + * format to the output buffer. + */ + virtual void FormatNewLine() = 0; + /** + * @brief Returns the size of the formatted text in the output buffer, to be used + * in the format header or footer. + * @return + */ + int GetBufferSize(); + /** + * @brief Has to be overridden in descendant classes to return the correct output + * format footer. + * @return + */ + virtual QString GetFooter() = 0; + /** + * @brief Has to be overridden in descendant classes to return the name of the + * output format. + * @return + */ + virtual QString GetFormatName() = 0; + /** + * @brief Has to be overridden in descendant classes to return the correct output + * format header. + * @return + */ + virtual QString GetHeader() = 0; + /** + * @brief Inserts a data block at the given position into the output buffer. Is + * used to insert the format header after the exporting, since some header + * data may be known only after the conversion is done. + * @param APos + * @param AText + */ + void InsertData(int APos, const QString& AText); + /** + * @brief Returns a string that has all the invalid chars of the output format + * replaced with the entries in the replacement array. + */ + QString ReplaceReservedChars(QString &AToken); + /** + * @brief Sets the token attribute of the next token to determine the changes + * of colors and font styles so the properties of the next token can be + * added to the output buffer. + * @param Attri + */ + virtual void SetTokenAttribute(PSynHighlighterAttribute Attri); +private: + QByteArray mBuffer; + bool mFirstAttribute; + FormatTokenHandler mOnFormatToken; +}; + +#endif // SYNEXPORTER_H