From 1f403198e50fc89a6bd3932cdec10d4625139b72 Mon Sep 17 00:00:00 2001 From: "royqh1979@gmail.com" Date: Thu, 24 Jun 2021 16:05:19 +0800 Subject: [PATCH] * work save: syntax error display in the editor --- RedPandaIDE/RedPandaIDE.pro | 2 + RedPandaIDE/common.h | 1 + RedPandaIDE/compiler/compiler.cpp | 49 +++++- RedPandaIDE/compiler/compiler.h | 1 + RedPandaIDE/compiler/compilermanager.cpp | 8 +- RedPandaIDE/compiler/compilermanager.h | 3 + RedPandaIDE/editor.cpp | 119 ++++++++++++++- RedPandaIDE/editor.h | 16 +- RedPandaIDE/editorlist.cpp | 14 +- RedPandaIDE/icons.qrc | 4 + RedPandaIDE/iconsmanager.cpp | 31 ++++ RedPandaIDE/iconsmanager.h | 32 ++++ RedPandaIDE/main.cpp | 2 + RedPandaIDE/mainwindow.cpp | 38 ++++- RedPandaIDE/mainwindow.h | 5 + RedPandaIDE/mainwindow.ui | 13 +- RedPandaIDE/qsynedit/SynEdit.cpp | 21 +++ RedPandaIDE/qsynedit/SynEdit.h | 4 + RedPandaIDE/qsynedit/TextPainter.cpp | 2 +- RedPandaIDE/settings.cpp | 143 +++++++++++++++++- RedPandaIDE/settings.h | 3 +- .../compilersetoptionwidget.cpp | 9 ++ 22 files changed, 486 insertions(+), 34 deletions(-) create mode 100644 RedPandaIDE/iconsmanager.cpp create mode 100644 RedPandaIDE/iconsmanager.h diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index 6cb1ec15..1940a878 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -17,6 +17,7 @@ SOURCES += \ compiler/filecompiler.cpp \ editor.cpp \ editorlist.cpp \ + iconsmanager.cpp \ main.cpp \ mainwindow.cpp \ qsynedit/CodeFolding.cpp \ @@ -59,6 +60,7 @@ HEADERS += \ compiler/filecompiler.h \ editor.h \ editorlist.h \ + iconsmanager.h \ mainwindow.h \ qsynedit/CodeFolding.h \ qsynedit/Constants.h \ diff --git a/RedPandaIDE/common.h b/RedPandaIDE/common.h index 88859b40..23fbdb54 100644 --- a/RedPandaIDE/common.h +++ b/RedPandaIDE/common.h @@ -15,6 +15,7 @@ struct CompileIssue { QString filename; int line; int column; + int endColumn; QString description; CompileIssueType type; }; diff --git a/RedPandaIDE/compiler/compiler.cpp b/RedPandaIDE/compiler/compiler.cpp index 618333f1..04e48b03 100644 --- a/RedPandaIDE/compiler/compiler.cpp +++ b/RedPandaIDE/compiler/compiler.cpp @@ -101,7 +101,8 @@ int Compiler::getColunmnFromOutputLine(QString &line) } if (pos>=0) { result = line.mid(0,pos).toInt(); - line.remove(0,pos+1); + if (result > 0) + line.remove(0,pos+1); } return result; } @@ -141,6 +142,7 @@ void Compiler::processOutput(QString &line) PCompileIssue issue = std::make_shared(); QString description; issue->type = CompileIssueType::Other; + issue->endColumn = -1; if (line.startsWith(inFilePrefix)) { line.remove(0,inFilePrefix.length()); issue->filename = getFileNameFromOutputLine(line); @@ -166,16 +168,54 @@ void Compiler::processOutput(QString &line) // Ignore code snippets that GCC produces // they always start with a space if (line.length()>0 && line[0] == ' ') { + if (!mLastIssue) + return; + QString s = line.trimmed(); + if (s.startsWith('|') && s.indexOf('^')) { + int pos = 0; + while (pos < s.length()) { + if (s[pos]=='^') + break; + pos++; + } + if (posendColumn = mLastIssue->column+i-pos; + emit compileIssue(mLastIssue); + mLastIssue.reset(); + } + } return; } + + if (mLastIssue) { + emit compileIssue(mLastIssue); + mLastIssue.reset(); + } + // assume regular main.cpp:line:col: message issue->filename = getFileNameFromOutputLine(line); issue->line = getLineNumberFromOutputLine(line); - if (issue->line > 0) + if (issue->line > 0) { issue->column = getColunmnFromOutputLine(line); - issue->type = getIssueTypeFromOutputLine(line); + if (issue->column>0) + issue->type = getIssueTypeFromOutputLine(line); + else + issue->type = CompileIssueType::Error; //linkage error + } else { + issue->column = -1; + issue->type = getIssueTypeFromOutputLine(line); + } issue->description = line.trimmed(); - emit compileIssue(issue); + if (issue->line<=0) { + emit compileIssue(issue); + } else + mLastIssue = issue; } void Compiler::stopCompile() @@ -316,7 +356,6 @@ void Compiler::runCommand(const QString &cmd, const QString &arguments, const Q [&](){ errorOccurred= true; }); - process.connect(&process, &QProcess::readyReadStandardError,[&process,this](){ this->error(QString::fromLocal8Bit( process.readAllStandardError())); }); diff --git a/RedPandaIDE/compiler/compiler.h b/RedPandaIDE/compiler/compiler.h index ac365d6c..3d3fd33b 100644 --- a/RedPandaIDE/compiler/compiler.h +++ b/RedPandaIDE/compiler/compiler.h @@ -56,6 +56,7 @@ protected: QString mOutputFile; int mErrorCount; int mWarningCount; + PCompileIssue mLastIssue; private: bool mStop; diff --git a/RedPandaIDE/compiler/compilermanager.cpp b/RedPandaIDE/compiler/compilermanager.cpp index 4a5443bb..b340f2ec 100644 --- a/RedPandaIDE/compiler/compilermanager.cpp +++ b/RedPandaIDE/compiler/compilermanager.cpp @@ -33,6 +33,7 @@ void CompilerManager::compile(const QString& filename, const QByteArray& encodin mCompileErrorCount = 0; mCompiler = new FileCompiler(filename,encoding,silent,onlyCheckSyntax); connect(mCompiler, &Compiler::compileFinished, this ,&CompilerManager::onCompileFinished); + connect(mCompiler, &Compiler::compileIssue, this, &CompilerManager::onCompileIssue); connect(mCompiler, &Compiler::compileFinished, pMainWindow, &MainWindow::onCompileFinished); connect(mCompiler, &Compiler::compileOutput, pMainWindow, &MainWindow::onCompileLog); connect(mCompiler, &Compiler::compileIssue, pMainWindow, &MainWindow::onCompileIssue); @@ -64,8 +65,8 @@ bool CompilerManager::canCompile(const QString &filename) void CompilerManager::onCompileFinished() { QMutexLocker locker(&compileMutex); - mCompiler=nullptr; delete mCompiler; + mCompiler=nullptr; } void CompilerManager::onRunnerTerminated() @@ -75,6 +76,11 @@ void CompilerManager::onRunnerTerminated() mRunner=nullptr; } +void CompilerManager::onCompileIssue(PCompileIssue) +{ + mCompileErrorCount ++; +} + int CompilerManager::syntaxCheckErrorCount() const { return mSyntaxCheckErrorCount; diff --git a/RedPandaIDE/compiler/compilermanager.h b/RedPandaIDE/compiler/compilermanager.h index b06b6144..e75269a7 100644 --- a/RedPandaIDE/compiler/compilermanager.h +++ b/RedPandaIDE/compiler/compilermanager.h @@ -4,6 +4,7 @@ #include #include #include "../utils.h" +#include "../common.h" class ExecutableRunner; class Compiler; @@ -26,6 +27,8 @@ public: private slots: void onCompileFinished(); void onRunnerTerminated(); + void onCompileIssue(PCompileIssue issue); + private: Compiler* mCompiler; int mCompileErrorCount; diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 9fb28700..c308077e 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -20,6 +20,8 @@ #include "qsynedit/Constants.h" #include #include +#include +#include "iconsmanager.h" using namespace std; @@ -53,7 +55,9 @@ Editor::Editor(QWidget *parent, const QString& filename, mFilename(filename), mParentPageControl(parentPageControl), mInProject(inProject), - mIsNew(isNew) + mIsNew(isNew), + mSyntaxErrorColor(QColorConstants::Red), + mSyntaxWaringColor("orange") { if (mFilename.isEmpty()) { newfileCount++; @@ -339,6 +343,92 @@ void Editor::keyPressEvent(QKeyEvent *event) } } +void Editor::onGutterPaint(QPainter &painter, int aLine, int X, int Y) +{ + // Get point where to draw marks + //X := (fText.Gutter.RealGutterWidth(fText.CharWidth) - fText.Gutter.RightOffset) div 2 - 3; + X = 5; + Y += (this->textHeight() - 16) / 2; + + PSyntaxIssueList lst = getSyntaxIssuesAtLine(aLine); + if (lst) { + bool hasError=false; + for (PSyntaxIssue issue : *lst) { + if (issue->issueType == CompileIssueType::Error) { + hasError = true; + break;; + } + } + if (hasError) { + painter.drawPixmap(X,Y,*(pIconsManager->syntaxError())); + } else { + painter.drawPixmap(X,Y,*(pIconsManager->syntaxWarning())); + } + } +// if fActiveLine = Line then begin // prefer active line over breakpoints +// dmMain.GutterImages.Draw(ACanvas, X, Y, 1); +// drawn:=True; +// end else if HasBreakpoint(Line) <> -1 then begin +// dmMain.GutterImages.Draw(ACanvas, X, Y, 0); +// drawn:=True; +// end else if fErrorLine = Line then begin +// dmMain.GutterImages.Draw(ACanvas, X, Y, 2); +// drawn:=True; +// end; +// idx := CBUtils.FastIndexOf(fErrorList, Line); +// if idx>=0 then begin +// isError := False; +// lst:=TList(fErrorList.Objects[idx]); +// for j:=0 to lst.Count-1 do begin +// if PSyntaxError(lst[j])^.errorType = setError then begin +// isError := True; +// break; +// end; +// end; +// if isError then +// dmMain.GutterImages.Draw(ACanvas, X, Y, 2) +// else if not drawn then +// dmMain.GutterImages.Draw(ACanvas, X, Y, 3); +// end; + +// Inc(Y, fText.LineHeight); +// end; + +} + +void Editor::onGetEditingAreas(int Line, SynEditingAreaList &areaList) +{ + areaList.clear(); +// if (fTabStopBegin >=0) and (fTabStopY=Line) then begin +// areaType:=eatEditing; +// System.new(p); +// spaceCount := fText.LeftSpacesEx(fLineBeforeTabStop,True); +// spaceBefore := Length(fLineBeforeTabStop) - Length(TrimLeft(fLineBeforeTabStop)); +// p.beginX := fTabStopBegin + spaceCount - spaceBefore ; +// p.endX := fTabStopEnd + spaceCount - spaceBefore ; +// p.color := dmMain.Cpp.StringAttri.Foreground; +// areaList.Add(p); +// ColBorder := dmMain.Cpp.StringAttri.Foreground; +// Exit; +// end; +// StrToThemeColor(tc,devEditor.Syntax.Values[cWN]); + PSyntaxIssueList lst = getSyntaxIssuesAtLine(Line); + if (lst) { + for (PSyntaxIssue issue: *lst) { + PSynEditingArea p=std::make_shared(); + p->beginX = issue->col; + p->endX = issue->endCol; + if (issue->issueType == CompileIssueType::Error) { + p->color = mSyntaxErrorColor; + } else { + p->color = mSyntaxWaringColor; + } + p->type = SynEditingAreaType::eatWaveUnderLine; + areaList.append(p); + } + } +} + void Editor::copyToClipboard() { if (pSettings->editor().copySizeLimit()) { @@ -409,7 +499,21 @@ void Editor::copyAsHTML() QGuiApplication::clipboard()->setMimeData(mimeData); } -void Editor::addSyntaxIssues(int line, int startChar, CompileIssueType errorType, const QString &hint) +void Editor::setCaretPosition(int line, int col) +{ + this->uncollapseAroundLine(line); + this->setCaretXYCentered(true,BufferCoord{col,line}); +} + +void Editor::setCaretPositionAndActivate(int line, int col) +{ + this->uncollapseAroundLine(line); + if (!this->hasFocus()) + this->activate(); + this->setCaretXYCentered(true,BufferCoord{col,line}); +} + +void Editor::addSyntaxIssues(int line, int startChar, int endChar, CompileIssueType errorType, const QString &hint) { PSyntaxIssue pError; BufferCoord p; @@ -426,9 +530,12 @@ void Editor::addSyntaxIssues(int line, int startChar, CompileIssueType errorType if (startChar >= lines()->getString(line-1).length()) { start = 1; token = lines()->getString(line-1); - } else { + } else if (endChar < 1) { if (!GetHighlighterAttriAtRowColEx(p,token,tokenType,tokenKind,start,attr)) return; + } else { + start = startChar; + token = lines()->getString(line-1).mid(start-1,endChar-startChar); } pError->startChar = start; pError->endChar = start + token.length(); @@ -501,16 +608,16 @@ bool Editor::hasPrevSyntaxIssue() const return false; } -Editor::PSyntaxIssueList Editor::getErrorsAtLine(int line) +Editor::PSyntaxIssueList Editor::getSyntaxIssuesAtLine(int line) { if (mSyntaxIssues.contains(line)) return mSyntaxIssues[line]; return PSyntaxIssueList(); } -Editor::PSyntaxIssue Editor::getErrorAtPosition(const BufferCoord &pos) +Editor::PSyntaxIssue Editor::getSyntaxIssueAtPosition(const BufferCoord &pos) { - PSyntaxIssueList lst = getErrorsAtLine(pos.Line); + PSyntaxIssueList lst = getSyntaxIssuesAtLine(pos.Line); for (PSyntaxIssue issue: *lst) { if (issue->startChar<=pos.Char && pos.Char<=issue->endChar) return issue; diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index 32a1adf1..b44894d4 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -97,15 +97,17 @@ public: void copyToClipboard() override; void cutToClipboard() override; void copyAsHTML(); + void setCaretPosition(int line,int col); + void setCaretPositionAndActivate(int line,int col); - void addSyntaxIssues(int line, int startChar, CompileIssueType errorType, const QString& hint); + void addSyntaxIssues(int line, int startChar, int endChar, CompileIssueType errorType, const QString& hint); void clearSyntaxIssues(); void gotoNextSyntaxIssue(); void gotoPrevSyntaxIssue(); bool hasPrevSyntaxIssue() const; bool hasNextSyntaxIssue() const; - PSyntaxIssueList getErrorsAtLine(int line); - PSyntaxIssue getErrorAtPosition(const BufferCoord& pos); + PSyntaxIssueList getSyntaxIssuesAtLine(int line); + PSyntaxIssue getSyntaxIssueAtPosition(const BufferCoord& pos); signals: @@ -139,6 +141,9 @@ private: bool mInProject; bool mIsNew; QMap mSyntaxIssues; + QColor mSyntaxErrorColor; + QColor mSyntaxWaringColor; + int mSyntaxErrorLine; // QWidget interface protected: @@ -146,6 +151,11 @@ protected: void focusInEvent(QFocusEvent *event) override; void focusOutEvent(QFocusEvent *event) override; void keyPressEvent(QKeyEvent *event) override; + + // SynEdit interface +protected: + void onGutterPaint(QPainter &painter, int aLine, int X, int Y) override; + void onGetEditingAreas(int Line, SynEditingAreaList &areaList) override; }; #endif // EDITOR_H diff --git a/RedPandaIDE/editorlist.cpp b/RedPandaIDE/editorlist.cpp index 80815970..55145e51 100644 --- a/RedPandaIDE/editorlist.cpp +++ b/RedPandaIDE/editorlist.cpp @@ -167,15 +167,17 @@ bool EditorList::closeAll(bool force) { Editor* EditorList::getOpenedEditorByFilename(const QString &filename) { + QFileInfo fileInfo(filename); + QString fullname = fileInfo.absoluteFilePath(); for (int i=0;icount();i++) { Editor* e = static_cast(mLeftPageWidget->widget(i)); - if (e->filename() == filename) { + if (e->filename() == fullname) { return e; } } for (int i=0;icount();i++) { Editor* e = static_cast(mRightPageWidget->widget(i)); - if (e->filename() == filename) { + if (e->filename() == fullname) { return e; } } @@ -184,12 +186,16 @@ Editor* EditorList::getOpenedEditorByFilename(const QString &filename) Editor *EditorList::getEditorByFilename(const QString &filename) { + QFileInfo fileInfo(filename); + QString fullname = fileInfo.absoluteFilePath(); //check if an editor is already openned - Editor* e=getOpenedEditorByFilename(filename); + Editor* e=getOpenedEditorByFilename(fullname); if (e!=nullptr) return e; //Todo: check if is in the project //Create a new editor - return newEditor(filename,ENCODING_AUTO_DETECT,false,false); + if (fileInfo.exists()) + return newEditor(fullname,ENCODING_AUTO_DETECT,false,false); + return nullptr; } diff --git a/RedPandaIDE/icons.qrc b/RedPandaIDE/icons.qrc index 5db555d9..bc92b7f2 100644 --- a/RedPandaIDE/icons.qrc +++ b/RedPandaIDE/icons.qrc @@ -450,5 +450,9 @@ images/newlook64/087-update.png images/newlook64/088-watch.png images/newlook64/089-watch-tm.png + images/editor/breakpoint.png + images/editor/currentline.png + images/editor/syntaxerror.png + images/editor/syntaxwarning.png diff --git a/RedPandaIDE/iconsmanager.cpp b/RedPandaIDE/iconsmanager.cpp new file mode 100644 index 00000000..91158bae --- /dev/null +++ b/RedPandaIDE/iconsmanager.cpp @@ -0,0 +1,31 @@ +#include "iconsmanager.h" + +IconsManager* pIconsManager; + +IconsManager::IconsManager(QObject *parent) : QObject(parent) +{ + mSyntaxError = std::make_shared(":/icons/images/editor/syntaxerror.png"); + mSyntaxWarning = std::make_shared(":/icons/images/editor/syntaxwarning.png"); + mBreakpoint = std::make_shared(":/icons/images/editor/breakpoint.png"); + mCurrentLine = std::make_shared(":/icons/images/editor/currentline.png"); +} + +PIcon IconsManager::syntaxError() const +{ + return mSyntaxError; +} + +PIcon IconsManager::syntaxWarning() const +{ + return mSyntaxWarning; +} + +PIcon IconsManager::breakpoint() const +{ + return mBreakpoint; +} + +PIcon IconsManager::currentLine() const +{ + return mCurrentLine; +} diff --git a/RedPandaIDE/iconsmanager.h b/RedPandaIDE/iconsmanager.h new file mode 100644 index 00000000..525f0277 --- /dev/null +++ b/RedPandaIDE/iconsmanager.h @@ -0,0 +1,32 @@ +#ifndef ICONSMANAGER_H +#define ICONSMANAGER_H + +#include +#include +#include + +using PIcon = std::shared_ptr; +class IconsManager : public QObject +{ + Q_OBJECT +public: + explicit IconsManager(QObject *parent = nullptr); + + PIcon syntaxError() const; + + PIcon syntaxWarning() const; + + PIcon breakpoint() const; + + PIcon currentLine() const; + +signals: +private: + PIcon mSyntaxError; + PIcon mSyntaxWarning; + PIcon mBreakpoint; + PIcon mCurrentLine; +}; + +extern IconsManager* pIconsManager; +#endif // ICONSMANAGER_H diff --git a/RedPandaIDE/main.cpp b/RedPandaIDE/main.cpp index 251440cc..0f7c68c1 100644 --- a/RedPandaIDE/main.cpp +++ b/RedPandaIDE/main.cpp @@ -11,6 +11,7 @@ #include #include "common.h" #include "colorscheme.h" +#include "iconsmanager.h" Settings* createAppSettings(const QString& filepath = QString()) { QString filename; @@ -74,6 +75,7 @@ int main(int argc, char *argv[]) //Color scheme settings must be loaded after translation pColorManager = new ColorManager(); + pIconsManager = new IconsManager(); MainWindow mainWindow; pMainWindow = &mainWindow; diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 1020b668..a8b09654 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -25,6 +25,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), mMessageControlChanged(false), + mTabMessagesTogglingState(false), mCheckSyntaxInBack(false) { ui->setupUi(this); @@ -40,7 +41,7 @@ MainWindow::MainWindow(QWidget *parent) ui->statusbar->addWidget(mFileModeStatus); mEditorList = new EditorList(ui->EditorTabsLeft, ui->EditorTabsRight, - ui->EditorPanelSplitter, + ui->splitterEditorPanel, ui->EditorPanel); setupActions(); ui->EditorTabsRight->setVisible(false); @@ -73,10 +74,12 @@ MainWindow::MainWindow(QWidget *parent) ui->actionEncode_in_ANSI->setCheckable(true); ui->actionEncode_in_UTF_8->setCheckable(true); - openCloseMessageSheet(false); - mPreviousHeight = 250; updateEditorActions(); applySettings(); + + openCloseMessageSheet(false); + mPreviousHeight = 250; + } MainWindow::~MainWindow() @@ -256,7 +259,12 @@ void MainWindow::openCloseMessageSheet(bool open) { // if Assigned(fReportToolWindow) then // Exit; - + if (mTabMessagesTogglingState) + return; + mTabMessagesTogglingState = true; + auto action = finally([this]{ + mTabMessagesTogglingState = false; + }); // Switch between open and close if (open) { QList sizes = ui->splitterMessages->sizes(); @@ -280,6 +288,7 @@ void MainWindow::openCloseMessageSheet(bool open) handle->setEnabled(open); int idxClose = ui->tabMessages->indexOf(ui->tabClose); ui->tabMessages->setTabVisible(idxClose,open); + mTabMessagesTogglingState = false; } @@ -383,7 +392,9 @@ void MainWindow::onCompileIssue(PCompileIssue issue) if (line > e->lines()->count()) return; int col = std::min(issue->column,e->lines()->getString(line-1).length()+1); - e->addSyntaxIssues(line,col,issue->type,issue->description); + if (col < 1) + col = e->lines()->getString(line-1).length()+1; + e->addSyntaxIssues(line,col,issue->endColumn,issue->type,issue->description); } } } @@ -592,8 +603,7 @@ void MainWindow::on_tableIssues_doubleClicked(const QModelIndex &index) if (editor == nullptr) return; - //editor->setCursorPosition(issue->line-1,issue->column-1); - editor->activate(); + editor->setCaretPositionAndActivate(issue->line,issue->column); } void MainWindow::on_actionEncode_in_ANSI_triggered() @@ -657,7 +667,14 @@ void MainWindow::on_actionConvert_to_UTF_8_triggered() void MainWindow::on_tabMessages_tabBarClicked(int index) { - mMessageControlChanged = false; + if (index == ui->tabMessages->currentIndex()) { + openCloseMessageSheet(!ui->splitterMessages->handle(1)->isEnabled()); + } +} + +void MainWindow::on_tabMessages_currentChanged(int index) +{ + mMessageControlChanged = true; int idxClose = ui->tabMessages->indexOf(ui->tabClose); if (index == idxClose) { openCloseMessageSheet(false); @@ -665,3 +682,8 @@ void MainWindow::on_tabMessages_tabBarClicked(int index) openCloseMessageSheet(true); } } + +void MainWindow::on_tabMessages_tabBarDoubleClicked(int index) +{ + +} diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 5c9fe428..35b84f0a 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -90,6 +90,10 @@ private slots: void on_tabMessages_tabBarClicked(int index); + void on_tabMessages_currentChanged(int index); + + void on_tabMessages_tabBarDoubleClicked(int index); + public slots: void onCompileLog(const QString& msg); void onCompileIssue(PCompileIssue issue); @@ -113,6 +117,7 @@ private: QComboBox* mCompilerSet; CompilerManager* mCompilerManager; bool mMessageControlChanged; + bool mTabMessagesTogglingState; bool mCheckSyntaxInBack; int mPreviousHeight; diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 7ded64d3..9cfe038a 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -37,6 +37,9 @@ Qt::Vertical + + 1 + false @@ -65,6 +68,9 @@ Qt::Horizontal + + 1 + false @@ -113,10 +119,13 @@ 0 - + Qt::Horizontal + + 1 + -1 @@ -164,7 +173,7 @@ QTabWidget::South - 5 + 0 diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index 0958111a..418288c5 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -275,6 +275,22 @@ void SynEdit::setCaretXYCentered(bool ForceToMiddle, const BufferCoord &value) ensureCursorPosVisibleEx(true); // but here after block has been set } +void SynEdit::uncollapseAroundLine(int line) +{ + while (true) { // Open up the closed folds around the focused line until we can see the line we're looking for + PSynEditFoldRange fold = foldHidesLine(line); + if (fold) + uncollapse(fold); + else + break; + } +} + +PSynEditFoldRange SynEdit::foldHidesLine(int line) +{ + return foldAroundLineEx(line, true, false, true); +} + void SynEdit::setInsertMode(bool value) { if (mInserting != value) { @@ -3160,6 +3176,11 @@ void SynEdit::doScrolled(int) invalidate(); } +int SynEdit::textHeight() const +{ + return mTextHeight; +} + bool SynEdit::readOnly() const { return mReadOnly; diff --git a/RedPandaIDE/qsynedit/SynEdit.h b/RedPandaIDE/qsynedit/SynEdit.h index d933a21b..8c5f1c68 100644 --- a/RedPandaIDE/qsynedit/SynEdit.h +++ b/RedPandaIDE/qsynedit/SynEdit.h @@ -208,6 +208,8 @@ public: void setCaretXY(const BufferCoord& value); void setCaretXYEx(bool CallEnsureCursorPos, BufferCoord value); void setCaretXYCentered(bool ForceToMiddle, const BufferCoord& value); + void uncollapseAroundLine(int line); + PSynEditFoldRange foldHidesLine(int line); int maxScrollWidth() const; int maxScrollHeight() const; @@ -313,6 +315,8 @@ public: bool canUndo() const; bool canRedo() const; + int textHeight() const; + signals: void Changed(); diff --git a/RedPandaIDE/qsynedit/TextPainter.cpp b/RedPandaIDE/qsynedit/TextPainter.cpp index 931f8592..a270ab14 100644 --- a/RedPandaIDE/qsynedit/TextPainter.cpp +++ b/RedPandaIDE/qsynedit/TextPainter.cpp @@ -421,7 +421,7 @@ void SynEditTextPainter::PaintEditAreas(const SynEditingAreaList &areaList) int lastX=rc.left(); int lastY=rc.bottom()-offset; int t = rc.left(); - while (t<=rc.right()) { + while (trc.right()) t = rc.right(); diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index 1b77eb63..1f90dadb 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -6,6 +6,7 @@ #include #include "systemconsts.h" #include +#include const char ValueToChar[28] = {'0', '1', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', @@ -984,9 +985,123 @@ void Settings::CompilerSet::setOption(PCompilerOption &option, char valueChar) option->value = charToValue(valueChar); } +static void checkDirs(const QStringList& dirlist, QString& gooddirs, QString& baddirs) { + gooddirs = ""; + baddirs = ""; + + for (int i=0; i0) {// we need some bin dir, so treat count=0 as an error too + checkDirs(mBinDirs,goodbin,badbin); + if (!badbin.isEmpty()) { + msg += QObject::tr("The following %1 directories don't exist:").arg( + QObject::tr("binary") + ); + msg += "
"; + msg += badbin.replace(';',"
"); + msg += "
"; + msg += "
"; + return false; + } + } else { + msg += QObject::tr("No %1 directories have been specified.").arg( + QObject::tr("binary") + ); + msg += "
"; + msg += "
"; + return false; + } + checkDirs(mCIncludeDirs,goodbin,badbin); + if (!badbin.isEmpty()) { + msg += QObject::tr("The following %1 directories don't exist:").arg( + QObject::tr("C include") + ); + msg += "
"; + msg += badbin.replace(';',"
"); + msg += "
"; + msg += "
"; + return false; + } + + checkDirs(mCppIncludeDirs,goodbin,badbin); + if (!badbin.isEmpty()) { + msg += QObject::tr("The following %1 directories don't exist:").arg( + QObject::tr("C++ include") + ); + msg += "
"; + msg += badbin.replace(';',"
"); + msg += "
"; + msg += "
"; + return false; + } + + checkDirs(mLibDirs,goodbin,badbin); + if (!badbin.isEmpty()) { + msg += QObject::tr("The following %1 directories don't exist:").arg( + QObject::tr("C++ include") + ); + msg += "
"; + msg += badbin.replace(';',"
"); + msg += "
"; + msg += "
"; + return false; + } + + if (!msg.isEmpty()) + return false; + else + return true; +} + +bool Settings::CompilerSet::validateExes(QString &msg) +{ + msg =""; + if (!QFile(mCCompiler).exists()) { + msg += QObject::tr("Cannot find the %1 \"%2\"") + .arg("C Compiler") + .arg(mCCompiler); + } + if (!QFile(mCppCompiler).exists()) { + msg += QObject::tr("Cannot find the %1 \"%2\"") + .arg("C++ Compiler") + .arg(mCppCompiler); + } + if (!QFile(mMake).exists()) { + msg += QObject::tr("Cannot find the %1 \"%2\"") + .arg("Maker") + .arg(mMake); + } + if (!QFile(mDebugger).exists()) { + msg += QObject::tr("Cannot find the %1 \"%2\"") + .arg("Maker") + .arg(mDebugger); + } + if (!msg.isEmpty()) + return false; + else + return true; } const QString &Settings::CompilerSet::CCompiler() const @@ -1766,8 +1881,30 @@ void Settings::CompilerSets::loadSets() PCompilerSet pCurrentSet = defaultSet(); if (pCurrentSet) { QString msg; - if (!pCurrentSet->dirsValid(msg)) { - + if (!pCurrentSet->dirsValid(msg) || !pCurrentSet->validateExes(msg)) { + if (QMessageBox::warning(nullptr,tr("Confirm"), + QObject::tr("The following problems were found during validation of compiler set \"%1\":") + .arg(pCurrentSet->name()) + +"

" + +msg + +"Would you like Dev-C++ to remove them for you and add the default paths to the valid paths?

Leaving those directories will lead to problems during compilation.

Unless you know exactly what you're doing, it is recommended that you click Yes.", + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Ok) { + clearSets(); + findSets(); + saveSets(); + if ( mList.size() <= mDefaultIndex) + mDefaultIndex = mList.size()-1; + } else { + return; + } + pCurrentSet = defaultSet(); + if (!pCurrentSet) { + return; + } + saveSet(mDefaultIndex); + if (pCurrentSet->binDirs().count()>0) { + pCurrentSet->setProperties(pCurrentSet->binDirs()[0]); + } } } } diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index 1c31b096..075056ef 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -370,8 +370,10 @@ public: char getOptionValue(const QString& setting); void setOption(const QString& setting, char valueChar); void setOption(PCompilerOption& option, char valueChar); + void setProperties(const QString& binDir); bool dirsValid(QString& msg); + bool validateExes(QString& msg); //properties const QString& CCompiler() const; void setCCompiler(const QString& name); @@ -427,7 +429,6 @@ public: int charToValue(char valueChar); // Initialization - void setProperties(const QString& binDir); void setExecutables(); void setDirectories(const QString& folder); void setUserInput(); diff --git a/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp b/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp index ebbf017c..52b90a7a 100644 --- a/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp +++ b/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp @@ -219,6 +219,9 @@ void CompilerSetOptionWidget::on_btnFindCompilers_pressed() pSettings->compilerSets().clearSets(); pSettings->compilerSets().findSets(); doLoad(); + if (pSettings->compilerSets().size()==0) { + QMessageBox::warning(this,tr("Failed"),tr("Can't find any compiler.")); + } } void CompilerSetOptionWidget::on_btnAddBlankCompilerSet_pressed() @@ -233,8 +236,14 @@ void CompilerSetOptionWidget::on_btnAddBlankCompilerSet_pressed() void CompilerSetOptionWidget::on_btnAddCompilerSetByFolder_pressed() { QString folder = QFileDialog::getExistingDirectory(this, tr("Compiler Set Folder")); + int oldSize = pSettings->compilerSets().size(); + pSettings->compilerSets().addSets(folder); doLoad(); + int newSize = pSettings->compilerSets().size(); + if (oldSize == newSize) { + QMessageBox::warning(this,tr("Failed"),tr("Can't find any compiler.")); + } } void CompilerSetOptionWidget::on_btnRenameCompilerSet_pressed()