diff --git a/NEWS.md b/NEWS.md index f981b5de..ea076421 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +Version 0.6.5 + - implement: export as rtf / export as html + - fix: the contents copied/exported are not correctly syntax colored + - fix: stop execution if the source file is not compiled and user choose not to compile it + Version 0.6.4 - fix: code completion popup not show after '->' inputted - fix: font styles in the color scheme settings not in effect diff --git a/RedPandaIDE/HighlighterManager.cpp b/RedPandaIDE/HighlighterManager.cpp index 0020f149..f567ea31 100644 --- a/RedPandaIDE/HighlighterManager.cpp +++ b/RedPandaIDE/HighlighterManager.cpp @@ -57,7 +57,7 @@ PSynHighlighter HighlighterManager::getCppHighlighter() highlighter->localVarAttribute()->setForeground(QColorConstants::Black); highlighter->numberAttribute()->setForeground(0x1750EB); highlighter->octAttribute()->setForeground(QColorConstants::Svg::purple); - highlighter->direcAttribute()->setForeground(0x1f542e); + highlighter->preprocessorAttribute()->setForeground(0x1f542e); highlighter->keywordAttribute()->setForeground(0x0033b3); highlighter->whitespaceAttribute()->setForeground(QColorConstants::Svg::silver); highlighter->stringAttribute()->setForeground(0x007d17); diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index d5935743..3f29ed4f 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -827,7 +827,7 @@ void Editor::onPreparePaintHighlightToken(int line, int aChar, const QString &to // qDebug()<name()<<" - "<identifierAttribute())) { + if (mParser && (attr == highlighter()->identifierAttribute())) { BufferCoord p{aChar,line}; BufferCoord pBeginPos,pEndPos; QString s= getWordAtPosition(this,p, pBeginPos,pEndPos, WordPurpose::wpInformation); @@ -1123,26 +1123,34 @@ void Editor::copyAsHTML() { if (!selAvail()) return; - SynHTMLExporter SynExporterHTML(tabWidth()); + SynHTMLExporter exporter(tabWidth()); - SynExporterHTML.setTitle(QFileInfo(mFilename).fileName()); - SynExporterHTML.setExportAsText(false); - SynExporterHTML.setUseBackground(pSettings->editor().copyHTMLUseBackground()); - SynExporterHTML.setFont(font()); + exporter.setTitle(QFileInfo(mFilename).fileName()); + exporter.setExportAsText(false); + exporter.setUseBackground(pSettings->editor().copyHTMLUseBackground()); + exporter.setFont(font()); PSynHighlighter hl = highlighter(); if (!pSettings->editor().copyHTMLUseEditorColor()) { hl = highlighterManager.copyHighlighter(highlighter()); highlighterManager.applyColorScheme(hl,pSettings->editor().copyHTMLColorScheme()); } - SynExporterHTML.setHighlighter(hl); - SynExporterHTML.setCreateHTMLFragment(true); + exporter.setHighlighter(hl); + exporter.setOnFormatToken(std::bind(&Editor::onExportedFormatToken, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5 + )); + exporter.setCreateHTMLFragment(true); - SynExporterHTML.ExportRange(lines(),blockBegin(),blockEnd()); + exporter.ExportRange(lines(),blockBegin(),blockEnd()); QMimeData * mimeData = new QMimeData; //sethtml will convert buffer to QString , which will cause encoding trouble - mimeData->setData(SynExporterHTML.clipboardFormat(),SynExporterHTML.buffer()); + mimeData->setData(exporter.clipboardFormat(),exporter.buffer()); mimeData->setText(selText()); QGuiApplication::clipboard()->clear(); @@ -2057,6 +2065,56 @@ void Editor::print() } +void Editor::exportAsRTF(const QString &rtfFilename) +{ + SynRTFExporter exporter; + exporter.setTitle(extractFileName(rtfFilename)); + exporter.setExportAsText(true); + exporter.setUseBackground(pSettings->editor().copyRTFUseBackground()); + exporter.setFont(font()); + PSynHighlighter hl = highlighter(); + if (!pSettings->editor().copyRTFUseEditorColor()) { + hl = highlighterManager.copyHighlighter(highlighter()); + highlighterManager.applyColorScheme(hl,pSettings->editor().copyRTFColorScheme()); + } + exporter.setHighlighter(hl); + exporter.setOnFormatToken(std::bind(&Editor::onExportedFormatToken, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5 + )); + exporter.ExportAll(lines()); + exporter.SaveToFile(rtfFilename); +} + +void Editor::exportAsHTML(const QString &htmlFilename) +{ + SynHTMLExporter exporter(tabWidth()); + exporter.setTitle(extractFileName(htmlFilename)); + exporter.setExportAsText(false); + exporter.setUseBackground(pSettings->editor().copyHTMLUseBackground()); + exporter.setFont(font()); + PSynHighlighter hl = highlighter(); + if (!pSettings->editor().copyHTMLUseEditorColor()) { + hl = highlighterManager.copyHighlighter(highlighter()); + highlighterManager.applyColorScheme(hl,pSettings->editor().copyHTMLColorScheme()); + } + exporter.setHighlighter(hl); + exporter.setOnFormatToken(std::bind(&Editor::onExportedFormatToken, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4, + std::placeholders::_5 + )); + exporter.ExportAll(lines()); + exporter.SaveToFile(htmlFilename); +} + void Editor::showCompletion(bool autoComplete) { if (!pSettings->codeCompletion().enabled()) @@ -2852,6 +2910,74 @@ void Editor::popUserCodeInTabStops() } } +void Editor::onExportedFormatToken(PSynHighlighter syntaxHighlighter, int Line, int column, const QString &token, PSynHighlighterAttribute& attr) +{ + if (!syntaxHighlighter) + return; + if (token.isEmpty()) + return; + //don't do this + if (mCompletionPopup->isVisible() || mHeaderCompletionPopup->isVisible()) + return; + + if (mParser && (attr == syntaxHighlighter->identifierAttribute())) { + BufferCoord p{column,Line}; + BufferCoord pBeginPos,pEndPos; + QString s= getWordAtPosition(this,p, pBeginPos,pEndPos, WordPurpose::wpInformation); +// qDebug()<findStatementOf(mFilename, + s , p.Line); + StatementKind kind = mParser->getKindOfStatement(statement); + if (kind == StatementKind::skUnknown) { + if ((pEndPos.Line>=1) + && (pEndPos.Char>=0) + && (pEndPos.Char < lines()->getString(pEndPos.Line-1).length()) + && (lines()->getString(pEndPos.Line-1)[pEndPos.Char] == '(')) { + kind = StatementKind::skFunction; + } else { + kind = StatementKind::skVariable; + } + } + SynEditCppHighlighter* cppHighlighter = dynamic_cast(syntaxHighlighter.get()); + switch(kind) { + case StatementKind::skFunction: + case StatementKind::skConstructor: + case StatementKind::skDestructor: + attr = cppHighlighter->functionAttribute(); + break; + case StatementKind::skClass: + case StatementKind::skTypedef: + case StatementKind::skAlias: + attr = cppHighlighter->classAttribute(); + break; + case StatementKind::skEnumClassType: + case StatementKind::skEnumType: + break; + case StatementKind::skLocalVariable: + case StatementKind::skParameter: + attr = cppHighlighter->localVarAttribute(); + break; + case StatementKind::skVariable: + attr = cppHighlighter->variableAttribute(); + break; + case StatementKind::skGlobalVariable: + attr = cppHighlighter->globalVarAttribute(); + break; + case StatementKind::skEnum: + case StatementKind::skPreprocessor: + attr = cppHighlighter->preprocessorAttribute(); + break; + case StatementKind::skKeyword: + attr = cppHighlighter->keywordAttribute(); + break; + case StatementKind::skNamespace: + case StatementKind::skNamespaceAlias: + attr = cppHighlighter->stringAttribute(); + break; + } + } +} + void Editor::setInProject(bool newInProject) { if (mInProject == newInProject) diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index 132dc475..6abaeeeb 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -159,6 +159,8 @@ public: void insertString(const QString& value, bool moveCursor); void insertCodeSnippet(const QString& code); void print(); + void exportAsRTF(const QString& rtfFilename); + void exportAsHTML(const QString& htmlFilename); const PCppParser &parser(); @@ -218,7 +220,8 @@ private: void updateFunctionTip(); void clearUserCodeInTabStops(); void popUserCodeInTabStops(); - + void onExportedFormatToken(PSynHighlighter syntaxHighlighter, int Line, int column, const QString& token, + PSynHighlighterAttribute &attr); private: QByteArray mEncodingOption; // the encoding type set by the user QByteArray mFileEncoding; // the real encoding of the file (auto detected) diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 0b75b285..75757e59 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -101,6 +101,11 @@ MainWindow::MainWindow(QWidget *parent) mMenuNew->addAction(ui->actionNew_Project); ui->menuFile->insertMenu(ui->actionOpen,mMenuNew); + mMenuExport = new QMenu(tr("Export")); + mMenuExport->addAction(ui->actionExport_As_RTF); + mMenuExport->addAction(ui->actionExport_As_HTML); + ui->menuFile->insertMenu(ui->actionPrint,mMenuExport); + buildEncodingMenu(); mMenuRecentProjects = new QMenu(); @@ -241,6 +246,8 @@ void MainWindow::updateEditorActions() ui->actionRedo->setEnabled(false); ui->actionSave->setEnabled(false); ui->actionSaveAs->setEnabled(false); + ui->actionExport_As_HTML->setEnabled(false); + ui->actionExport_As_RTF->setEnabled(false); ui->actionPrint->setEnabled(false); ui->actionSelectAll->setEnabled(false); ui->actionToggleComment->setEnabled(false); @@ -274,6 +281,8 @@ void MainWindow::updateEditorActions() ui->actionUndo->setEnabled(e->canUndo()); ui->actionSave->setEnabled(e->modified()); ui->actionSaveAs->setEnabled(true); + ui->actionExport_As_HTML->setEnabled(true); + ui->actionExport_As_RTF->setEnabled(true); ui->actionPrint->setEnabled(true); ui->actionSelectAll->setEnabled(e->lines()->count()>0); ui->actionToggleComment->setEnabled(!e->readOnly() && e->lines()->count()>0); @@ -960,8 +969,8 @@ void MainWindow::runExecutable(const QString &exeName,const QString &filename) +"

"+tr("Compile now?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { ui->actionCompile_Run->trigger(); - return; } + return; } else { QMessageBox::critical(this,"Error", tr("Source file is not compiled.")); @@ -977,6 +986,9 @@ void MainWindow::runExecutable(const QString &exeName,const QString &filename) ui->actionCompile_Run->trigger(); return; } + } else { + QMessageBox::warning(this,"Error", + tr("Source file is more recent than executable.")); } } } @@ -4159,3 +4171,47 @@ const PToolsManager &MainWindow::toolsManager() const return mToolsManager; } + +void MainWindow::on_actionExport_As_RTF_triggered() +{ + Editor * editor = mEditorList->getEditor(); + if (!editor) + return; + QString rtfFile = QFileDialog::getSaveFileName(editor, + tr("Export As RTF"), + extractFilePath(editor->filename()), + tr("Rich Text Format Files (*.rtf)") + ); + if (rtfFile.isEmpty()) + return; + try { + editor->exportAsRTF(rtfFile); + } catch (FileError e) { + QMessageBox::critical(editor, + "Error", + e.reason()); + } +} + + +void MainWindow::on_actionExport_As_HTML_triggered() +{ + Editor * editor = mEditorList->getEditor(); + if (!editor) + return; + QString htmlFile = QFileDialog::getSaveFileName(editor, + tr("Export As HTML"), + extractFilePath(editor->filename()), + tr("HTML Files (*.html)") + ); + if (htmlFile.isEmpty()) + return; + try { + editor->exportAsHTML(htmlFile); + } catch (FileError e) { + QMessageBox::critical(editor, + "Error", + e.reason()); + } +} + diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 8d7fa74f..4025f7aa 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -392,6 +392,10 @@ private slots: void on_actionPrint_triggered(); + void on_actionExport_As_RTF_triggered(); + + void on_actionExport_As_HTML_triggered(); + private: Ui::MainWindow *ui; EditorList *mEditorList; @@ -399,6 +403,7 @@ private: QLabel *mFileEncodingStatus; QLabel *mFileModeStatus; QMenu *mMenuEncoding; + QMenu *mMenuExport; QMenu *mMenuEncodingList; QMenu *mMenuRecentFiles; QMenu *mMenuRecentProjects; diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 601a3698..1e961071 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -1822,6 +1822,16 @@ Ctrl+P + + + Export As RTF + + + + + Export As HTML + + diff --git a/RedPandaIDE/qsynedit/exporter/synexporter.cpp b/RedPandaIDE/qsynedit/exporter/synexporter.cpp index 03df90f8..5f4a67d2 100644 --- a/RedPandaIDE/qsynedit/exporter/synexporter.cpp +++ b/RedPandaIDE/qsynedit/exporter/synexporter.cpp @@ -94,7 +94,7 @@ void SynExporter::ExportRange(PSynEditStringList ALines, BufferCoord Start, Buff QString Token = ReplaceReservedChars(token); if (mOnFormatToken) - mOnFormatToken(i, mHighlighter->getTokenPos(), mHighlighter->getToken(),attri); + mOnFormatToken(mHighlighter, i, mHighlighter->getTokenPos()+1, mHighlighter->getToken(),attri); SetTokenAttribute(attri); FormatToken(Token); mHighlighter->next(); @@ -115,13 +115,16 @@ void SynExporter::SaveToFile(const QString &AFileName) QFile file(AFileName); if (file.open(QIODevice::WriteOnly)) { SaveToStream(file); - file.close(); + } else { + throw FileError(QObject::tr("Can't open file '%1' to write!")); } } void SynExporter::SaveToStream(QIODevice &AStream) { - AStream.write(mBuffer); + if (AStream.write(mBuffer)<0) { + throw FileError(QObject::tr("Failed to write data.")); + } } bool SynExporter::exportAsText() const diff --git a/RedPandaIDE/qsynedit/exporter/synexporter.h b/RedPandaIDE/qsynedit/exporter/synexporter.h index 5802e3ff..61f9cd72 100644 --- a/RedPandaIDE/qsynedit/exporter/synexporter.h +++ b/RedPandaIDE/qsynedit/exporter/synexporter.h @@ -6,8 +6,8 @@ -using FormatTokenHandler = std::function; +using FormatTokenHandler = std::function; class SynExporter { diff --git a/RedPandaIDE/qsynedit/highlighter/cpp.cpp b/RedPandaIDE/qsynedit/highlighter/cpp.cpp index 87750889..e82f7fa4 100644 --- a/RedPandaIDE/qsynedit/highlighter/cpp.cpp +++ b/RedPandaIDE/qsynedit/highlighter/cpp.cpp @@ -138,8 +138,8 @@ SynEditCppHighlighter::SynEditCppHighlighter(): SynHighlighter() addAttribute(mNumberAttribute); mOctAttribute = std::make_shared(SYNS_AttrOctal); addAttribute(mOctAttribute); - mDirecAttribute = std::make_shared(SYNS_AttrPreprocessor); - addAttribute(mDirecAttribute); + mPreprocessorAttribute = std::make_shared(SYNS_AttrPreprocessor); + addAttribute(mPreprocessorAttribute); mKeywordAttribute = std::make_shared(SYNS_AttrReservedWord); addAttribute(mKeywordAttribute); mWhitespaceAttribute = std::make_shared(SYNS_AttrSpace); @@ -168,9 +168,9 @@ PSynHighlighterAttribute SynEditCppHighlighter::asmAttribute() const return mAsmAttribute; } -PSynHighlighterAttribute SynEditCppHighlighter::direcAttribute() const +PSynHighlighterAttribute SynEditCppHighlighter::preprocessorAttribute() const { - return mDirecAttribute; + return mPreprocessorAttribute; } PSynHighlighterAttribute SynEditCppHighlighter::invalidAttribute() const @@ -1369,7 +1369,7 @@ PSynHighlighterAttribute SynEditCppHighlighter::getTokenAttribute() const case TokenKind::Comment: return mCommentAttribute; case TokenKind::Directive: - return mDirecAttribute; + return mPreprocessorAttribute; case TokenKind::Identifier: return mIdentifierAttribute; case TokenKind::Key: diff --git a/RedPandaIDE/qsynedit/highlighter/cpp.h b/RedPandaIDE/qsynedit/highlighter/cpp.h index a40c004e..bb90e8b3 100644 --- a/RedPandaIDE/qsynedit/highlighter/cpp.h +++ b/RedPandaIDE/qsynedit/highlighter/cpp.h @@ -53,7 +53,7 @@ public: PSynHighlighterAttribute asmAttribute() const; - PSynHighlighterAttribute direcAttribute() const; + PSynHighlighterAttribute preprocessorAttribute() const; PSynHighlighterAttribute invalidAttribute() const; @@ -144,7 +144,7 @@ private: int mRightBraces; PSynHighlighterAttribute mAsmAttribute; - PSynHighlighterAttribute mDirecAttribute; + PSynHighlighterAttribute mPreprocessorAttribute; PSynHighlighterAttribute mInvalidAttribute; PSynHighlighterAttribute mNumberAttribute; PSynHighlighterAttribute mFloatAttribute; diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index d383de1b..ddd85b14 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -3,7 +3,7 @@ #include -#define DEVCPP_VERSION "0.6.4" +#define DEVCPP_VERSION "0.6.5" #ifdef Q_OS_WIN #define APP_SETTSINGS_FILENAME "redpandacpp.ini"