RedPanda-CPP/RedPandaIDE/mainwindow.cpp

2874 lines
89 KiB
C++

#include <windows.h>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "editorlist.h"
#include "editor.h"
#include "systemconsts.h"
#include "settings.h"
#include "qsynedit/Constants.h"
#include "debugger.h"
#include "widgets/cpudialog.h"
#include "widgets/filepropertiesdialog.h"
#include "project.h"
#include <QCloseEvent>
#include <QComboBox>
#include <QDesktopServices>
#include <QDragEnterEvent>
#include <QFileDialog>
#include <QInputDialog>
#include <QLabel>
#include <QMessageBox>
#include <QMimeData>
#include <QTranslator>
#include "settingsdialog/settingsdialog.h"
#include "compiler/compilermanager.h"
#include <QGuiApplication>
#include <QClipboard>
#include <QMessageBox>
#include <QTextCodec>
#include <QDebug>
#include "cpprefacter.h"
#include <widgets/searchdialog.h>
MainWindow* pMainWindow;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWindow),
mSearchDialog(nullptr),
mQuitting(false),
mOpenClosingBottomPanel(false),
mOpenClosingLeftPanel(false),
mCheckSyntaxInBack(false),
mClosing(false),
mSystemTurnedOff(false)
{
ui->setupUi(this);
// status bar
mFileInfoStatus=new QLabel();
mFileEncodingStatus = new QLabel();
mFileModeStatus = new QLabel();
mFileInfoStatus->setStyleSheet("margin-left:10px; margin-right:10px");
mFileEncodingStatus->setStyleSheet("margin-left:10px; margin-right:10px");
mFileModeStatus->setStyleSheet("margin-left:10px; margin-right:10px");
ui->statusbar->insertPermanentWidget(0,mFileModeStatus);
ui->statusbar->insertPermanentWidget(0,mFileEncodingStatus);
ui->statusbar->insertPermanentWidget(0,mFileInfoStatus);
mEditorList = new EditorList(ui->EditorTabsLeft,
ui->EditorTabsRight,
ui->splitterEditorPanel,
ui->EditorPanel);
mProject = nullptr;
setAcceptDrops(true);
setupActions();
ui->EditorTabsRight->setVisible(false);
mCompilerSet = new QComboBox();
mCompilerSet->setMinimumWidth(200);
ui->toolbarCompilerSet->addWidget(mCompilerSet);
connect(mCompilerSet,QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &MainWindow::onCompilerSetChanged);
updateCompilerSet();
mCompilerManager = new CompilerManager(this);
mDebugger = new Debugger(this);
ui->tblBreakpoints->setModel(mDebugger->breakpointModel());
ui->tblStackTrace->setModel(mDebugger->backtraceModel());
ui->watchView->setModel(mDebugger->watchModel());
ui->actionIndent->setShortcut(Qt::Key_Tab);
ui->actionUnIndent->setShortcut(Qt::Key_Tab | Qt::ShiftModifier);
ui->tableIssues->setErrorColor(QColor("Red"));
ui->tableIssues->setWarningColor(QColor("Orange"));
mMenuEncoding = new QMenu();
mMenuEncoding->setTitle(tr("File Encoding"));
mMenuEncoding->addAction(ui->actionAuto_Detect);
mMenuEncoding->addAction(ui->actionEncode_in_ANSI);
mMenuEncoding->addAction(ui->actionEncode_in_UTF_8);
mMenuEncoding->addSeparator();
mMenuEncoding->addAction(ui->actionConvert_to_ANSI);
mMenuEncoding->addAction(ui->actionConvert_to_UTF_8);
ui->menuEdit->insertMenu(ui->actionFoldAll,mMenuEncoding);
ui->menuEdit->insertSeparator(ui->actionFoldAll);
ui->actionAuto_Detect->setCheckable(true);
ui->actionEncode_in_ANSI->setCheckable(true);
ui->actionEncode_in_UTF_8->setCheckable(true);
mMenuRecentFiles = new QMenu();
mMenuRecentFiles->setTitle(tr("Recent Files"));
ui->menuFile->insertMenu(ui->actionExit, mMenuRecentFiles);
ui->menuFile->insertSeparator(ui->actionExit);
rebuildOpenedFileHisotryMenu();
mCPUDialog = nullptr;
updateEditorActions();
updateCaretActions();
applySettings();
applyUISettings();
connect(ui->debugConsole,&QConsole::commandInput,this,&MainWindow::onDebugCommandInput);
connect(ui->cbEvaluate->lineEdit(), &QLineEdit::returnPressed,
this, &MainWindow::onDebugEvaluateInput);
mSearchResultTreeModel = std::make_shared<SearchResultTreeModel>(&mSearchResultModel);
mSearchResultListModel = std::make_shared<SearchResultListModel>(&mSearchResultModel);
mSearchViewDelegate = std::make_shared<SearchResultTreeViewDelegate>(mSearchResultTreeModel);
ui->cbSearchHistory->setModel(mSearchResultListModel.get());
ui->searchView->setModel(mSearchResultTreeModel.get());
ui->searchView->setItemDelegate(mSearchViewDelegate.get());
connect(mSearchResultTreeModel.get() , &QAbstractItemModel::modelReset,
ui->searchView,&QTreeView::expandAll);
ui->replacePanel->setVisible(false);
//class browser
ui->classBrowser->setModel(&mClassBrowserModel);
connect(&mFileSystemWatcher,&QFileSystemWatcher::fileChanged,
this, &MainWindow::onFileChanged);
mCompletionPopup = std::make_shared<CodeCompletionPopup>();
mHeaderCompletionPopup = std::make_shared<HeaderCompletionPopup>();
updateAppTitle();
connect(&mAutoSaveTimer, &QTimer::timeout,
this, &MainWindow::onAutoSaveTimeout);
resetAutoSaveTimer();
connect(ui->menuFile, &QMenu::aboutToShow,
this,&MainWindow::rebuildOpenedFileHisotryMenu);
buildContextMenus();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::updateForEncodingInfo() {
Editor * editor = mEditorList->getEditor();
if (editor!=NULL) {
mFileEncodingStatus->setText(
QString("%1(%2)")
.arg(QString(editor->encodingOption())
,QString(editor->fileEncoding())));
ui->actionAuto_Detect->setChecked(editor->encodingOption() == ENCODING_AUTO_DETECT);
ui->actionEncode_in_ANSI->setChecked(editor->encodingOption() == ENCODING_SYSTEM_DEFAULT);
ui->actionEncode_in_UTF_8->setChecked(editor->encodingOption() == ENCODING_UTF8);
} else {
mFileEncodingStatus->setText("");
ui->actionAuto_Detect->setChecked(false);
ui->actionEncode_in_ANSI->setChecked(false);
ui->actionEncode_in_UTF_8->setChecked(false);
}
}
void MainWindow::updateEditorSettings()
{
mEditorList->applySettings();
}
void MainWindow::updateEditorActions()
{
Editor* e = mEditorList->getEditor();
if (e==nullptr) {
ui->actionAuto_Detect->setEnabled(false);
ui->actionEncode_in_ANSI->setEnabled(false);
ui->actionEncode_in_UTF_8->setEnabled(false);
ui->actionConvert_to_ANSI->setEnabled(false);
ui->actionConvert_to_UTF_8->setEnabled(false);
ui->actionCopy->setEnabled(false);
ui->actionCut->setEnabled(false);
ui->actionFoldAll->setEnabled(false);
ui->actionIndent->setEnabled(false);
ui->actionPaste->setEnabled(false);
ui->actionRedo->setEnabled(false);
ui->actionSave->setEnabled(false);
ui->actionSaveAs->setEnabled(false);
ui->actionSaveAll->setEnabled(false);
ui->actionSelectAll->setEnabled(false);
ui->actionToggleComment->setEnabled(false);
ui->actionUnIndent->setEnabled(false);
ui->actionUndo->setEnabled(false);
ui->actionUnfoldAll->setEnabled(false);
ui->actionCompile->setEnabled(false);
ui->actionCompile_Run->setEnabled(false);
ui->actionRun->setEnabled(false);
ui->actionRebuild->setEnabled(false);
ui->actionStop_Execution->setEnabled(false);
ui->actionDebug->setEnabled(false);
ui->actionStep_Over->setEnabled(false);
ui->actionStep_Into->setEnabled(false);
ui->actionStep_Out->setEnabled(false);
ui->actionContinue->setEnabled(false);
ui->actionRun_To_Cursor->setEnabled(false);
ui->actionFind->setEnabled(false);
ui->actionReplace->setEnabled(false);
ui->actionFind_Next->setEnabled(false);
ui->actionFind_Previous->setEnabled(false);
//code
ui->actionReformat_Code->setEnabled(false);
ui->actionClose->setEnabled(false);
ui->actionClose_All->setEnabled(false);
} else {
ui->actionAuto_Detect->setEnabled(true);
ui->actionEncode_in_ANSI->setEnabled(true);
ui->actionEncode_in_UTF_8->setEnabled(true);
ui->actionConvert_to_ANSI->setEnabled(e->encodingOption()!=ENCODING_SYSTEM_DEFAULT && e->fileEncoding()!=ENCODING_SYSTEM_DEFAULT);
ui->actionConvert_to_UTF_8->setEnabled(e->encodingOption()!=ENCODING_UTF8 && e->fileEncoding()!=ENCODING_UTF8);
ui->actionCopy->setEnabled(e->selAvail());
ui->actionCut->setEnabled(e->selAvail());
ui->actionFoldAll->setEnabled(e->lines()->count()>0);
ui->actionIndent->setEnabled(!e->readOnly());
ui->actionPaste->setEnabled(!e->readOnly() && !QGuiApplication::clipboard()->text().isEmpty());
ui->actionRedo->setEnabled(e->canRedo());
ui->actionUndo->setEnabled(e->canUndo());
ui->actionSave->setEnabled(e->modified());
ui->actionSaveAs->setEnabled(true);
ui->actionSaveAll->setEnabled(true);
ui->actionSelectAll->setEnabled(e->lines()->count()>0);
ui->actionToggleComment->setEnabled(!e->readOnly() && e->lines()->count()>0);
ui->actionUnIndent->setEnabled(!e->readOnly() && e->lines()->count()>0);
ui->actionUnfoldAll->setEnabled(e->lines()->count()>0);
ui->actionFind->setEnabled(true);
ui->actionReplace->setEnabled(true);
ui->actionFind_Next->setEnabled(true);
ui->actionFind_Previous->setEnabled(true);
//code
ui->actionReformat_Code->setEnabled(true);
ui->actionClose->setEnabled(true);
ui->actionClose_All->setEnabled(true);
updateCompileActions();
}
}
void MainWindow::updateCompileActions()
{
Editor * e = mEditorList->getEditor();
if (!e)
return;
FileType fileType = getFileType(e->filename());
if (mCompilerManager->compiling() || mCompilerManager->running() || mDebugger->executing()
|| (fileType!= FileType::CSource
&& fileType != FileType::CppSource) ) {
ui->actionCompile->setEnabled(false);
ui->actionCompile_Run->setEnabled(false);
ui->actionRun->setEnabled(false);
ui->actionRebuild->setEnabled(false);
ui->actionDebug->setEnabled(false);
} else {
ui->actionCompile->setEnabled(true);
ui->actionCompile_Run->setEnabled(true);
ui->actionRun->setEnabled(true);
ui->actionRebuild->setEnabled(true);
ui->actionDebug->setEnabled(true);
}
ui->actionStep_Into->setEnabled(mDebugger->executing());
ui->actionStep_Out->setEnabled(mDebugger->executing());
ui->actionStep_Over->setEnabled(mDebugger->executing());
ui->actionContinue->setEnabled(mDebugger->executing());
ui->actionRun_To_Cursor->setEnabled(mDebugger->executing());
ui->actionStop_Execution->setEnabled(mCompilerManager->running() || mDebugger->executing());
}
void MainWindow::updateEditorColorSchemes()
{
mEditorList->applyColorSchemes(pSettings->editor().colorScheme());
}
void MainWindow::applySettings()
{
changeTheme(pSettings->environment().theme());
QFont font(pSettings->environment().interfaceFont(),
pSettings->environment().interfaceFontSize());
font.setStyleStrategy(QFont::PreferAntialias);
QApplication * app = dynamic_cast<QApplication*>(QApplication::instance());
app->setFont(font);
this->setFont(font);
updateDebuggerSettings();
}
void MainWindow::applyUISettings()
{
const Settings::UI& settings = pSettings->ui();
restoreGeometry(settings.mainWindowGeometry());
restoreState(settings.mainWindowState());
//we can show/hide left/bottom panels here, cause mainwindow layout is not calculated
// ui->tabMessages->setCurrentIndex(settings.bottomPanelIndex());
// if (settings.bottomPanelOpenned()) {
// mBottomPanelHeight = settings.bottomPanelHeight();
// openCloseBottomPanel(true);
// } else {
// openCloseBottomPanel(false);
// mBottomPanelHeight = settings.bottomPanelHeight();
// }
// ui->tabInfos->setCurrentIndex(settings.leftPanelIndex());
// if (settings.leftPanelOpenned()) {
// mLeftPanelWidth = settings.leftPanelWidth();
// openCloseLeftPanel(true);
// } else {
// openCloseLeftPanel(false);
// mLeftPanelWidth = settings.leftPanelWidth();
// }
}
QFileSystemWatcher *MainWindow::fileSystemWatcher()
{
return &mFileSystemWatcher;
}
void MainWindow::removeActiveBreakpoints()
{
for (int i=0;i<mEditorList->pageCount();i++) {
Editor* e= (*mEditorList)[i];
e->removeBreakpointFocus();
}
}
void MainWindow::setActiveBreakpoint(QString FileName, int Line, bool setFocus)
{
removeActiveBreakpoints();
// Then active the current line in the current file
FileName.replace('/',QDir::separator());
Editor *e = mEditorList->getEditorByFilename(FileName);
if (e!=nullptr) {
e->setActiveBreakpointFocus(Line,setFocus);
}
if (setFocus) {
this->activateWindow();
}
}
void MainWindow::updateAppTitle()
{
QString appName("Red Panda Dev-C++");
Editor *e = mEditorList->getEditor();
QCoreApplication *app = QApplication::instance();
if (e && !e->inProject()) {
QString str;
if (e->modified())
str = e->filename() + " [*]";
else
str = e->filename();
if (mDebugger->executing()) {
setWindowTitle(QString("%1 - [%2] - %3 %4")
.arg(str,tr("Debugging"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Debugging"),appName));
} else if (mCompilerManager->running()) {
setWindowTitle(QString("%1 - [%2] - %3 %4")
.arg(str,tr("Running"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Running"),appName));
} else if (mCompilerManager->compiling()) {
setWindowTitle(QString("%1 - [%2] - %3 %4")
.arg(str,tr("Compiling"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Compiling"),appName));
} else {
this->setWindowTitle(QString("%1 - %2 %3")
.arg(str,appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - %2")
.arg(str,appName));
}
} else if (e && e->inProject() && mProject) {
QString str,str2;
if (mProject->modified())
str = mProject->name() + " [*]";
else
str = mProject->name();
if (e->modified())
str2 = extractFileName(e->filename()) + " [*]";
else
str2 = extractFileName(e->filename());
if (mDebugger->executing()) {
setWindowTitle(QString("%1 - %2 [%3] - %4 %5")
.arg(str,str2,
tr("Debugging"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Debugging"),appName));
} else if (mCompilerManager->running()) {
setWindowTitle(QString("%1 - %2 [%3] - %4 %5")
.arg(str,str2,
tr("Running"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Running"),appName));
} else if (mCompilerManager->compiling()) {
setWindowTitle(QString("%1 - %2 [%3] - %4 %5")
.arg(str,str2,
tr("Compiling"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Compiling"),appName));
} else {
setWindowTitle(QString("%1 - %2 %3")
.arg(str,appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - %2")
.arg(str,appName));
}
} else if (mProject) {
QString str,str2;
if (mProject->modified())
str = mProject->name() + " [*]";
else
str = mProject->name();
if (mDebugger->executing()) {
setWindowTitle(QString("%1 - [%2] - %3 %4")
.arg(str,tr("Debugging"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Debugging"),appName));
} else if (mCompilerManager->running()) {
setWindowTitle(QString("%1 - [%2] - %3 %4")
.arg(str,tr("Running"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Running"),appName));
} else if (mCompilerManager->compiling()) {
setWindowTitle(QString("%1 - [%2] - %3 %4")
.arg(str,tr("Compiling"),appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - [%2] - %3")
.arg(str,tr("Compiling"),appName));
} else {
this->setWindowTitle(QString("%1 - %2 %3")
.arg(str,appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1 - %2")
.arg(str,appName));
}
} else {
setWindowTitle(QString("%1 %2").arg(appName,DEVCPP_VERSION));
app->setApplicationName(QString("%1").arg(appName));
}
}
void MainWindow::addDebugOutput(const QString &text)
{
if (text.isEmpty()) {
ui->debugConsole->addLine("");
} else {
ui->debugConsole->addText(text);
}
}
void MainWindow::changeDebugOutputLastline(const QString &test)
{
ui->debugConsole->changeLastLine(test);
}
void MainWindow::updateDebugEval(const QString &value)
{
ui->txtEvalOutput->clear();
ui->txtEvalOutput->appendPlainText(value);
}
void MainWindow::rebuildOpenedFileHisotryMenu()
{
mMenuRecentFiles->clear();
foreach (QAction* action,mRecentFileActions) {
action->setParent(nullptr);
action->deleteLater();
}
mRecentFileActions.clear();
if (pSettings->history().openedFiles().size()==0) {
mMenuRecentFiles->setEnabled(false);
} else {
mMenuRecentFiles->setEnabled(true);
for (const QString& filename: pSettings->history().openedFiles()) {
QAction* action = new QAction();
action->setText(filename);
connect(action, &QAction::triggered, [&filename,this](bool){
this->openFile(filename);
});
mRecentFileActions.append(action);
}
mMenuRecentFiles->addActions(mRecentFileActions);
}
}
void MainWindow::updateClassBrowserForEditor(Editor *editor)
{
if (!editor) {
mClassBrowserModel.setParser(nullptr);
mClassBrowserModel.setCurrentFile("");
mClassBrowserModel.clear();
return;
}
if (mQuitting)
return;
// if not devCodeCompletion.Enabled then
// Exit;
if ((mClassBrowserModel.currentFile() == editor->filename())
&& (mClassBrowserModel.parser() == editor->parser()))
return;
mClassBrowserModel.beginUpdate();
{
auto action = finally([this] {
mClassBrowserModel.endUpdate();
});
mClassBrowserModel.setParser(editor->parser());
// if e.InProject then begin
// ClassBrowser.StatementsType := devClassBrowsing.StatementsType;
// end else
// ClassBrowser.StatementsType := cbstFile;
mClassBrowserModel.setCurrentFile(editor->filename());
}
}
void MainWindow::resetAutoSaveTimer()
{
if (pSettings->editor().enableAutoSave()) {
//minute to milliseconds
mAutoSaveTimer.start(pSettings->editor().autoSaveInterval()*60*1000);
} else {
mAutoSaveTimer.stop();
}
}
QPlainTextEdit *MainWindow::txtLocals()
{
return ui->txtLocals;
}
void MainWindow::updateStatusbarForLineCol()
{
Editor* e = mEditorList->getEditor();
if (e!=nullptr) {
int col = e->charToColumn(e->caretY(),e->caretX());
QString msg = tr("Line:%1 Col:%2 Selected:%3 Lines:%4 Length:%5")
.arg(e->caretY(),4)
.arg(col,3)
.arg(e->selText().length(),6)
.arg(e->lines()->count(),4)
.arg(e->lines()->getTextLength(),6);
mFileInfoStatus->setText(msg);
} else {
mFileInfoStatus->setText("");
}
}
void MainWindow::updateForStatusbarModeInfo()
{
Editor* e = mEditorList->getEditor();
if (e!=nullptr) {
QString msg;
if (e->readOnly()) {
msg = tr("Read Only");
} else if (e->insertMode()) {
msg = tr("Insert");
} else {
msg = tr("Overwrite");
}
mFileModeStatus->setText(msg);
} else {
mFileModeStatus->setText("");
}
}
void MainWindow::updateStatusbarMessage(const QString &s)
{
ui->statusbar->showMessage(s);
}
void MainWindow::openFiles(const QStringList &files)
{
mEditorList->beginUpdate();
auto end = finally([this] {
this->mEditorList->endUpdate();
});
//Check if there is a project file in the list and open it
for (const QString& file:files) {
if (getFileType(file)==FileType::Project) {
openProject(file);
return;
}
}
//Didn't find a project? Open all files
for (const QString& file:files) {
openFile(file);
}
mEditorList->endUpdate();
}
void MainWindow::openFile(const QString &filename)
{
Editor* editor = mEditorList->getOpenedEditorByFilename(filename);
if (editor!=nullptr) {
editor->activate();
return;
}
try {
pSettings->history().removeFile(filename);
editor = mEditorList->newEditor(filename,ENCODING_AUTO_DETECT,
false,false);
editor->activate();
this->updateForEncodingInfo();
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
void MainWindow::openProject(const QString &filename)
{
if (!fileExists(filename)) {
return;
}
if (mProject) {
QString s;
if (mProject->name().isEmpty())
s = mProject->filename();
else
s = mProject->name();
if (QMessageBox::question(this,
tr("Close project"),
tr("Are you sure you want to close %1?")
.arg(s),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes) == QMessageBox::Yes) {
closeProject(false);
} else {
return;
}
}
ui->tabProject->setVisible(true);
ui->tabInfos->setCurrentWidget(ui->tabProject);
openCloseLeftPanel(true);
// {
// LeftPageControl.ActivePage := LeftProjectSheet;
// fLeftPageControlChanged := False;
// ClassBrowser.TabVisible:= False;
// }
// Only update class browser once
mClassBrowserModel.beginUpdate();
{
auto action = finally([this]{
mClassBrowserModel.endUpdate();
});
mProject = std::make_shared<Project>(filename,DEV_INTERNAL_OPEN);
ui->projectView->setModel(mProject->model());
pSettings->history().removeProject(filename);
// // if project manager isn't open then open it
// if not devData.ShowLeftPages then
// actProjectManager.Execute;
//checkForDllProfiling();
updateAppTitle();
updateCompilerSet();
//parse the project
// UpdateClassBrowsing;
scanActiveProject(true);
mProject->doAutoOpen();
//update editor's inproject flag
for (int i=0;i<mProject->units().count();i++) {
PProjectUnit unit = mProject->units()[i];
Editor* e = mEditorList->getOpenedEditorByFilename(unit->fileName());
if (e) {
unit->setEditor(e);
unit->setEncoding(e->encodingOption());
e->setInProject(true);
} else {
unit->setEditor(nullptr);
}
}
Editor * e = mEditorList->getEditor();
if (e) {
checkSyntaxInBack(e);
}
updateClassBrowserForEditor(e);
}
updateForEncodingInfo();
}
void MainWindow::setupActions() {
}
void MainWindow::updateCompilerSet()
{
mCompilerSet->clear();
for (size_t i=0;i<pSettings->compilerSets().list().size();i++) {
mCompilerSet->addItem(pSettings->compilerSets().list()[i]->name());
}
int index=pSettings->compilerSets().defaultIndex();
if (mProject) {
Editor *e = mEditorList->getEditor();
if ( !e || e->inProject()) {
index = mProject->options().compilerSet;
}
}
if (index < 0 || index>=mCompilerSet->count()) {
index = pSettings->compilerSets().defaultIndex();
}
mCompilerSet->setCurrentIndex(index);
}
void MainWindow::updateDebuggerSettings()
{
ui->debugConsole->setFont(QFont(
pSettings->debugger().fontName(),
pSettings->debugger().fontSize()));
}
void MainWindow::checkSyntaxInBack(Editor *e)
{
if (e==nullptr)
return;
if (!pSettings->editor().syntaxCheck()) {
return;
}
// if not devEditor.AutoCheckSyntax then
// Exit;
//not c or cpp file
if (!e->highlighter() || e->highlighter()->getName()!=SYN_HIGHLIGHTER_CPP)
return;
if (mCompilerManager->backgroundSyntaxChecking())
return;
if (mCompilerManager->compiling())
return;
if (!pSettings->compilerSets().defaultSet())
return;
if (mCheckSyntaxInBack)
return;
mCheckSyntaxInBack=true;
ui->tableIssues->clearIssues();
CompileTarget target =getCompileTarget();
if (target ==CompileTarget::Project) {
mCompilerManager->checkSyntax(e->filename(),e->lines()->text(),
e->fileEncoding() == ENCODING_ASCII, mProject);
} else {
mCompilerManager->checkSyntax(e->filename(),e->lines()->text(),
e->fileEncoding() == ENCODING_ASCII, nullptr);
}
// if not PrepareForCompile(cttStdin,True) then begin
// fCheckSyntaxInBack:=False;
// Exit;
// end;
// if e.InProject then begin
// if not assigned(MainForm.fProject) then
// Exit;
// fSyntaxChecker.Project := MainForm.fProject;
// end;
// fSyntaxChecker.CheckSyntax(True);
}
bool MainWindow::compile(bool rebuild)
{
CompileTarget target =getCompileTarget();
if (target == CompileTarget::Project) {
if (!mProject->saveUnits())
return false;
updateAppTitle();
// Check if saves have been succesful
for (int i=0; i<mEditorList->pageCount();i++) {
Editor * e= (*(mEditorList))[i];
if (e->inProject() && e->modified())
return false;
}
// Increment build number automagically
if (mProject->options().versionInfo.autoIncBuildNr) {
mProject->incrementBuildNumber();
}
mProject->buildPrivateResource();
mCompilerManager->compileProject(mProject);
} else {
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
ui->tableIssues->clearIssues();
if (editor->modified()) {
if (!editor->save(false,false))
return false;
}
if (mCompileSuccessionTask) {
mCompileSuccessionTask->filename = getCompiledExecutableName(editor->filename());
}
updateCompileActions();
openCloseBottomPanel(true);
ui->tabMessages->setCurrentWidget(ui->tabCompilerOutput);
updateAppTitle();
mCompilerManager->compile(editor->filename(),editor->fileEncoding(),rebuild);
return true;
}
}
return false;
}
void MainWindow::runExecutable(const QString &exeName,const QString &filename)
{
// Check if it exists
if (!fileExists(exeName)) {
if (ui->actionCompile_Run->isEnabled()) {
if (QMessageBox::question(this,tr("Confirm"),
tr("Source file is not compiled.")
+"<br /><br />"+tr("Compile now?"),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
ui->actionCompile_Run->trigger();
return;
}
} else {
QMessageBox::critical(this,"Error",
tr("Source file is not compiled."));
return;
}
} else {
if (!filename.isEmpty() && compareFileModifiedTime(filename,exeName)>=0) {
if (ui->actionCompile_Run->isEnabled()) {
if (QMessageBox::warning(this,tr("Confirm"),
tr("Source file is more recent than executable.")
+"<br /><br />"+tr("Recompile now?"),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
ui->actionCompile_Run->trigger();
return;
}
}
}
}
// Pause programs if they contain a console
// if devData.ConsolePause and ProgramHasConsole(FileToRun) then begin
// if fUseRunParams then
// Parameters := '"' + FileToRun + '" ' + fRunParams
// else
// Parameters := '"' + FileToRun + '"';
// FileToRun := devDirs.Exec + 'ConsolePauser.exe';
// end else begin
// if fUseRunParams then
// Parameters := fRunParams
// else
// Parameters := '';
// FileToRun := FileToRun;
// end;
updateCompileActions();
if (pSettings->executor().minimizeOnRun()) {
showMinimized();
}
updateAppTitle();
mCompilerManager->run(exeName,"",QFileInfo(exeName).absolutePath());
}
void MainWindow::runExecutable()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
if (editor->modified()) {
if (!editor->save(false,false))
return;
}
QString exeName= getCompiledExecutableName(editor->filename());
runExecutable(exeName,editor->filename());
}
}
void MainWindow::debug()
{
if (mCompilerManager->compiling())
return;
Settings::PCompilerSet compilerSet = pSettings->compilerSets().defaultSet();
if (!compilerSet) {
QMessageBox::critical(pMainWindow,
tr("No compiler set"),
tr("No compiler set is configured.")+"<BR/>"+tr("Can't start debugging."));
return;
}
bool debugEnabled;
bool stripEnabled;
QString filePath;
QFileInfo debugFile;
switch(getCompileTarget()) {
case CompileTarget::Project:
break;
// cttProject: begin
// // Check if we enabled proper options
// DebugEnabled := fProject.GetCompilerOption('-g3') <> '0';
// StripEnabled := fProject.GetCompilerOption('-s') <> '0';
// // Ask the user if he wants to enable debugging...
// if (not DebugEnabled or StripEnabled) then begin
// if (MessageDlg(Lang[ID_MSG_NODEBUGSYMBOLS], mtConfirmation, [mbYes,
// mbNo], 0) = mrYes) then begin
// // Enable debugging, disable stripping
// fProject.SetCompilerOption('-g3', '1');
// fProject.SetCompilerOption('-s', '0');
// fCompSuccessAction := csaDebug;
// actRebuildExecute(nil);
// end;
// Exit;
// end;
// // Did we compile?
// if not FileExists(fProject.Executable) then begin
// if MessageDlg(Lang[ID_ERR_PROJECTNOTCOMPILEDSUGGEST], mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin
// fCompSuccessAction := csaDebug;
// actCompileExecute(nil);
// end;
// Exit;
// end;
// // Did we choose a host application for our DLL?
// if fProject.Options.typ = dptDyn then begin
// if fProject.Options.HostApplication = '' then begin
// MessageDlg(Lang[ID_ERR_HOSTMISSING], mtWarning, [mbOK], 0);
// exit;
// end else if not FileExists(fProject.Options.HostApplication) then begin
// MessageDlg(Lang[ID_ERR_HOSTNOTEXIST], mtWarning, [mbOK], 0);
// exit;
// end;
// end;
// // Reset UI, remove invalid breakpoints
// PrepareDebugger;
// filepath := fProject.Executable;
// if (!mDebugger->start())
// return;
// fDebugger.SendCommand('file', '"' + StringReplace(filepath, '\', '/', [rfReplaceAll]) + '"');
// if fProject.Options.typ = dptDyn then
// fDebugger.SendCommand('exec-file', '"' + StringReplace(fProject.Options.HostApplication, '\', '/',
// [rfReplaceAll])
// + '"');
// for i:=0 to fProject.Units.Count-1 do begin
// fDebugger.SendCommand('dir', '"'+StringReplace(
// ExtractFilePath(fProject.Units[i].FileName),'\', '/',[rfReplaceAll])
// + '"');
// end;
// for i:=0 to fProject.Options.Includes.Count-1 do begin
// fDebugger.SendCommand('dir', '"'+StringReplace(
// fProject.Options.Includes[i],'\', '/',[rfReplaceAll])
// + '"');
// end;
// for i:=0 to fProject.Options.Libs.Count-1 do begin
// fDebugger.SendCommand('dir', '"'+StringReplace(
// fProject.Options.Includes[i],'\', '/',[rfReplaceAll])
// + '"');
// end;
// end;
case CompileTarget::File:
// Check if we enabled proper options
debugEnabled = compilerSet->getOptionValue("-g3")!='0';
stripEnabled = compilerSet->getOptionValue("-s")!='0';
// Ask the user if he wants to enable debugging...
if (((!debugEnabled) || stripEnabled) &&
(QMessageBox::question(this,
tr("Enable debugging"),
tr("You have not enabled debugging info (-g3) and/or stripped it from the executable (-s) in Compiler Options.<BR /><BR />Do you want to correct this now?")
) == QMessageBox::Yes)) {
// Enable debugging, disable stripping
compilerSet->setOption("-g3",'1');
compilerSet->setOption("-s",'0');
// Save changes to compiler set
pSettings->compilerSets().saveSet(pSettings->compilerSets().defaultIndex());
mCompileSuccessionTask=std::make_shared<CompileSuccessionTask>();
mCompileSuccessionTask->type = CompileSuccessionTaskType::Debug;
compile();
return;
}
Editor* e = mEditorList->getEditor();
if (e!=nullptr) {
// Did we saved?
if (e->modified()) {
// if file is modified,save it first
if (!e->save(false,false))
return;
}
// Did we compiled?
filePath = getCompiledExecutableName(e->filename());
debugFile.setFile(filePath);
if (!debugFile.exists()) {
if (QMessageBox::question(this,tr("Compile"),
tr("Source file is not compiled.")+"<BR /><BR />" + tr("Compile now?"),
QMessageBox::Yes|QMessageBox::No,
QMessageBox::Yes) == QMessageBox::Yes) {
mCompileSuccessionTask=std::make_shared<CompileSuccessionTask>();
mCompileSuccessionTask->type = CompileSuccessionTaskType::Debug;
compile();
return;
}
} else {
if (compareFileModifiedTime(e->filename(),filePath)>=0) {
if (QMessageBox::question(this,tr("Compile"),
tr("Source file is more recent than executable.")+"<BR /><BR />" + tr("Recompile?"),
QMessageBox::Yes|QMessageBox::No,
QMessageBox::Yes) == QMessageBox::Yes) {
mCompileSuccessionTask=std::make_shared<CompileSuccessionTask>();
mCompileSuccessionTask->type = CompileSuccessionTaskType::Debug;
compile();
return;
}
}
}
prepareDebugger();
mDebugger->setUseUTF8(e->fileEncoding() == ENCODING_UTF8 || e->fileEncoding() == ENCODING_UTF8_BOM);
if (!mDebugger->start())
return;
mDebugger->sendCommand("file", QString("\"%1\"").arg(debugFile.filePath().replace('\\','/')));
}
break;
}
updateEditorActions();
// Add library folders
foreach (QString dir,compilerSet->libDirs()) {
mDebugger->sendCommand("dir",
QString("\"%1\"").arg(dir.replace('\\','/')));
}
foreach (QString dir,compilerSet->defaultLibDirs()) {
mDebugger->sendCommand("dir",
QString("\"%1\"").arg(dir.replace('\\','/')));
}
// Add include folders
foreach (QString dir,compilerSet->CIncludeDirs()) {
mDebugger->sendCommand("dir",
QString("\"%1\"").arg(dir.replace('\\','/')));
}
foreach (QString dir,compilerSet->CppIncludeDirs()) {
mDebugger->sendCommand("dir",
QString("\"%1\"").arg(dir.replace('\\','/')));
}
foreach (QString dir,compilerSet->defaultCIncludeDirs()) {
mDebugger->sendCommand("dir",
QString("\"%1\"").arg(dir.replace('\\','/')));
}
foreach (QString dir,compilerSet->defaultCppIncludeDirs()) {
mDebugger->sendCommand("dir",
QString("\"%1\"").arg(dir.replace('\\','/')));
}
// Add breakpoints and watch vars
// for i := 0 to fDebugger.WatchVarList.Count - 1 do
// fDebugger.AddWatchVar(i);
mDebugger->sendAllWatchvarsToDebugger();
mDebugger->sendAllBreakpointsToDebugger();
// Run the debugger
mDebugger->sendCommand("set", "width 0"); // don't wrap output, very annoying
mDebugger->sendCommand("set", "new-console on");
mDebugger->sendCommand("set", "confirm off");
mDebugger->sendCommand("cd", excludeTrailingPathDelimiter(debugFile.path())); // restore working directory
if (!debugInferiorhasBreakpoint()) {
QString params;
switch(getCompileTarget()) {
case CompileTarget::None:
return;
case CompileTarget::File:
// if (mCompiler->useRunParams) {
// }
mDebugger->sendCommand("start",params);
mDebugger->updateDebugInfo();
break;
case CompileTarget::Project:
//params := '';
//if fCompiler.UseRunParams then
// params := params + ' ' + fProject.Options.CmdLineArgs;
//if fCompiler.UseInputFile then
// params := params + ' < "' + fCompiler.InputFile + '"';
//fDebugger.SendCommand('start', params);
//UpdateDebugInfo;
break;
}
} else {
QString params;
switch(getCompileTarget()) {
case CompileTarget::None:
return;
case CompileTarget::File:
// if (mCompiler->useRunParams) {
// }
mDebugger->sendCommand("run",params);
mDebugger->updateDebugInfo();
break;
case CompileTarget::Project:
//params := '';
//if fCompiler.UseRunParams then
// params := params + ' ' + fProject.Options.CmdLineArgs;
//if fCompiler.UseInputFile then
// params := params + ' < "' + fCompiler.InputFile + '"';
//fDebugger.SendCommand('run', params);
//UpdateDebugInfo;
break;
}
}
}
void MainWindow::showSearchPanel()
{
openCloseBottomPanel(true);
ui->tabMessages->setCurrentWidget(ui->tabSearch);
}
void MainWindow::openCloseBottomPanel(bool open)
{
// if Assigned(fReportToolWindow) then
// Exit;
if (mOpenClosingBottomPanel)
return;
mOpenClosingBottomPanel = true;
auto action = finally([this]{
mOpenClosingBottomPanel = false;
});
// Switch between open and close
if (open) {
QList<int> sizes = ui->splitterMessages->sizes();
int tabHeight = ui->tabMessages->tabBar()->height();
ui->tabMessages->setMinimumHeight(tabHeight+5);
int totalSize = sizes[0] + sizes[1];
sizes[1] = mBottomPanelHeight;
sizes[0] = std::max(1,totalSize - sizes[1]);
ui->splitterMessages->setSizes(sizes);
} else {
QList<int> sizes = ui->splitterMessages->sizes();
mBottomPanelHeight = sizes[1];
int totalSize = sizes[0] + sizes[1];
int tabHeight = ui->tabMessages->tabBar()->height();
ui->tabMessages->setMinimumHeight(tabHeight);
sizes[1] = tabHeight;
sizes[0] = std::max(1,totalSize - sizes[1]);
ui->splitterMessages->setSizes(sizes);
}
mBottomPanelOpenned = open;
QSplitterHandle* handle = ui->splitterMessages->handle(1);
handle->setEnabled(open);
int idxClose = ui->tabMessages->indexOf(ui->tabClose);
ui->tabMessages->setTabVisible(idxClose,open);
}
void MainWindow::openCloseLeftPanel(bool open)
{
if (mOpenClosingLeftPanel)
return;
mOpenClosingLeftPanel = true;
auto action = finally([this]{
mOpenClosingLeftPanel = false;
});
// Switch between open and close
if (open) {
QList<int> sizes = ui->splitterInfos->sizes();
int tabWidth = ui->tabInfos->tabBar()->width();
ui->tabInfos->setMinimumWidth(tabWidth+5);
int totalSize = sizes[0] + sizes[1];
sizes[0] = mLeftPanelWidth;
sizes[1] = std::max(1,totalSize - sizes[0]);
ui->splitterInfos->setSizes(sizes);
} else {
QList<int> sizes = ui->splitterInfos->sizes();
mLeftPanelWidth = sizes[0];
int totalSize = sizes[0] + sizes[1];
int tabWidth = ui->tabInfos->tabBar()->width();
ui->tabInfos->setMinimumWidth(tabWidth);
sizes[0] = tabWidth;
sizes[1] = std::max(1,totalSize - sizes[0]);
ui->splitterInfos->setSizes(sizes);
}
mLeftPanelOpenned = open;
QSplitterHandle* handle = ui->splitterInfos->handle(1);
handle->setEnabled(open);
}
void MainWindow::prepareDebugger()
{
mDebugger->stop();
// Clear logs
ui->debugConsole->clear();
ui->txtEvalOutput->clear();
// Restore when no watch vars are shown
mDebugger->setLeftPageIndexBackup(ui->tabInfos->currentIndex());
// Focus on the debugging buttons
ui->tabInfos->setCurrentWidget(ui->tabWatch);
ui->tabMessages->setCurrentWidget(ui->tabDebug);
ui->debugViews->setCurrentWidget(ui->tabDebugConsole);
openCloseBottomPanel(true);
openCloseLeftPanel(true);
// Reset watch vars
// mDebugger->deleteWatchVars(false);
}
void MainWindow::doAutoSave(Editor *e)
{
if (!e)
return;
if (!e->modified())
return;
QString filename = e->filename();
QFileInfo fileInfo(filename);
QDir parent = fileInfo.absoluteDir();
QString baseName = fileInfo.completeBaseName();
QString suffix = fileInfo.suffix();
switch(pSettings->editor().autoSaveStrategy()) {
case assOverwrite:
break;
case assAppendUnixTimestamp:
filename = parent.filePath(
QString("%1.%2.%3")
.arg(baseName)
.arg(QDateTime::currentSecsSinceEpoch())
.arg(suffix));
break;
case assAppendFormatedTimeStamp: {
QDateTime time = QDateTime::currentDateTime();
filename = parent.filePath(
QString("%1.%2.%3")
.arg(baseName)
.arg(time.toString("yyyy.MM.dd.hh.mm.ss"))
.arg(suffix));
}
}
e->saveFile(filename);
}
//static void limitActionShortCutScope(QAction* action,QWidget* scopeWidget) {
// action->setParent(scopeWidget);
// action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
//}
QAction* MainWindow::createActionFor(
const QString& text,
QWidget* parent,
QKeySequence shortcut) {
QAction* action= new QAction(text,parent);
if (!shortcut.isEmpty())
action->setShortcut(shortcut);
action->setPriority(QAction::HighPriority);
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
parent->addAction(action);
return action;
}
void MainWindow::scanActiveProject(bool parse)
{
if (!mProject)
return;
//UpdateClassBrowsing;
if (parse) {
resetCppParser(mProject->cppParser());
mProject->resetParserProjectFiles();
parseFileList(mProject->cppParser());
} else {
mProject->resetParserProjectFiles();
};
}
void MainWindow::buildContextMenus()
{
//context menu signal for the watch view
ui->watchView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->watchView,&QWidget::customContextMenuRequested,
this, &MainWindow::onWatchViewContextMenu);
//context menu signal for Editor's tabbar
ui->EditorTabsLeft->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->EditorTabsLeft->tabBar(),&QWidget::customContextMenuRequested,
this, &MainWindow::onEditorTabContextMenu);
ui->EditorTabsRight->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->EditorTabsRight->tabBar(),&QWidget::customContextMenuRequested,
this, &MainWindow::onEditorTabContextMenu);
//context menu signal for Compile Issue view
ui->tableIssues->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tableIssues,&QWidget::customContextMenuRequested,
this, &MainWindow::onTableIssuesContextMenu);
mTableIssuesCopyAction = createActionFor(
tr("Copy"),
ui->tableIssues,
QKeySequence("Ctrl+C"));
connect(mTableIssuesCopyAction,&QAction::triggered,
[this](){
QModelIndex index = ui->tableIssues->selectionModel()->currentIndex();
PCompileIssue issue = ui->tableIssues->issue(index);
if (issue) {
QClipboard* clipboard = QApplication::clipboard();
clipboard->setText(issue->description);
}
});
mTableIssuesCopyAllAction = createActionFor(
tr("Copy all"),
ui->tableIssues,
QKeySequence("Ctrl+Shift+C"));
connect(mTableIssuesCopyAllAction,&QAction::triggered,
[this](){
QClipboard* clipboard=QGuiApplication::clipboard();
QMimeData * mimeData = new QMimeData();
mimeData->setText(ui->tableIssues->toTxt());
mimeData->setHtml(ui->tableIssues->toHtml());
clipboard->clear();
clipboard->setMimeData(mimeData);
});
mTableIssuesClearAction = createActionFor(
tr("Clear"),
ui->tableIssues);
connect(mTableIssuesClearAction,&QAction::triggered,
[this](){
ui->tableIssues->clearIssues();
});
//context menu signal for search view
ui->searchHistoryPanel->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->searchHistoryPanel, &QWidget::customContextMenuRequested,
this, &MainWindow::onSearchViewContextMenu);
mSearchViewClearAction = createActionFor(
tr("Remove this search"),
ui->searchHistoryPanel);
connect(mSearchViewClearAction, &QAction::triggered,
[this](){
int index = ui->cbSearchHistory->currentIndex();
if (index>=0) {
mSearchResultModel.removeSearchResults(index);
}
});
mSearchViewClearAllAction = createActionFor(
tr("Clear all searches"),
ui->searchHistoryPanel);
connect(mSearchViewClearAllAction,&QAction::triggered,
[this]() {
mSearchResultModel.clear();
});
//context menu signal for breakpoints view
ui->tblBreakpoints->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tblBreakpoints,&QWidget::customContextMenuRequested,
this, &MainWindow::onBreakpointsViewContextMenu);
mBreakpointViewPropertyAction = createActionFor(
tr("Breakpoint condition..."),
ui->tblBreakpoints);
connect(mBreakpointViewPropertyAction,&QAction::triggered,
[this](){
int index =ui->tblBreakpoints->selectionModel()->currentIndex().row();
PBreakpoint breakpoint = debugger()->breakpointModel()->breakpoint(
index
);
if (breakpoint) {
bool isOk;
QString s=QInputDialog::getText(this,
tr("Break point condition"),
tr("Enter the condition of the breakpoint:"),
QLineEdit::Normal,
breakpoint->condition,&isOk);
if (isOk) {
pMainWindow->debugger()->setBreakPointCondition(index,s);
}
}
});
mBreakpointViewRemoveAllAction = createActionFor(
tr("Remove all breakpoints"),
ui->tblBreakpoints);
connect(mBreakpointViewRemoveAllAction,&QAction::triggered,
[this](){
pMainWindow->debugger()->deleteBreakpoints();
});
}
void MainWindow::maximizeEditor()
{
if (mLeftPanelOpenned || mBottomPanelOpenned) {
openCloseBottomPanel(false);
openCloseLeftPanel(false);
} else {
openCloseBottomPanel(true);
openCloseLeftPanel(true);
}
}
void MainWindow::openShell(const QString &folder, const QString &shellCommand)
{
QProcess process;
process.setWorkingDirectory(folder);
process.setProgram(shellCommand);
process.setCreateProcessArgumentsModifier([](QProcess::CreateProcessArguments * args){
args->flags |= CREATE_NEW_CONSOLE;
args->startupInfo->dwFlags &= ~STARTF_USESTDHANDLES; //
});
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString path = env.value("PATH");
if (pSettings->compilerSets().defaultSet()) {
foreach(const QString& dir, pSettings->compilerSets().defaultSet()->binDirs()) {
#ifdef Q_OS_WIN
path+=";";
#else
path+=":";
#endif
path+=dir;
}
}
#ifdef Q_OS_WIN
path+=";";
#else
path+=":";
#endif
path+=pSettings->dirs().app();
env.insert("PATH",path);
process.setProcessEnvironment(env);
process.startDetached();
}
void MainWindow::onAutoSaveTimeout()
{
if (!pSettings->editor().enableAutoSave())
return;
int updateCount = 0;
switch (pSettings->editor().autoSaveTarget()) {
case astCurrentFile: {
Editor *e = mEditorList->getEditor();
doAutoSave(e);
updateCount++;
}
break;
case astAllOpennedFiles:
for (int i=0;i<mEditorList->pageCount();i++) {
Editor *e = (*mEditorList)[i];
doAutoSave(e);
updateCount++;
}
break;
case astAllProjectFiles:
//todo: auto save project files
break;
}
updateStatusbarMessage(tr("%1 files autosaved").arg(updateCount));
}
void MainWindow::onWatchViewContextMenu(const QPoint &pos)
{
QMenu menu(this);
menu.addAction(ui->actionAdd_Watch);
menu.addAction(ui->actionRemove_Watch);
menu.addAction(ui->actionRemove_All_Watches);
menu.addAction(ui->actionModify_Watch);
menu.exec(ui->watchView->mapToGlobal(pos));
}
void MainWindow::onTableIssuesContextMenu(const QPoint &pos)
{
QMenu menu(this);
menu.addAction(mTableIssuesCopyAction);
menu.addAction(mTableIssuesCopyAllAction);
menu.addSeparator();
menu.addAction(mTableIssuesClearAction);
menu.exec(ui->tableIssues->mapToGlobal(pos));
}
void MainWindow::onSearchViewContextMenu(const QPoint &pos)
{
QMenu menu(this);
menu.addAction(mSearchViewClearAction);
menu.addAction(mSearchViewClearAllAction);
menu.exec(ui->searchHistoryPanel->mapToGlobal(pos));
}
void MainWindow::onBreakpointsViewContextMenu(const QPoint &pos)
{
QMenu menu(this);
menu.addAction(mBreakpointViewPropertyAction);
menu.addAction(mBreakpointViewRemoveAllAction);
menu.exec(ui->tblBreakpoints->mapToGlobal(pos));
}
void MainWindow::onEditorContextMenu(const QPoint &pos)
{
Editor * editor = mEditorList->getEditor();
if (!editor)
return;
QMenu menu(this);
BufferCoord p;
mEditorContextMenuPos = pos;
if (editor->GetPositionOfMouse(p)) {
//mouse on editing area
menu.addAction(ui->actionCompile_Run);
menu.addAction(ui->actionDebug);
menu.addSeparator();
menu.addAction(ui->actionGoto_Declaration);
menu.addAction(ui->actionGoto_Definition);
menu.addAction(ui->actionFind_references);
menu.addSeparator();
menu.addAction(ui->actionOpen_Containing_Folder);
menu.addAction(ui->actionOpen_Terminal);
menu.addSeparator();
menu.addAction(ui->actionReformat_Code);
menu.addSeparator();
menu.addAction(ui->actionCut);
menu.addAction(ui->actionCopy);
menu.addAction(ui->actionPaste);
menu.addAction(ui->actionSelectAll);
menu.addSeparator();
menu.addAction(ui->actionAdd_Watch);
menu.addAction(ui->actionToggle_Breakpoint);
menu.addAction(ui->actionClear_all_breakpoints);
menu.addSeparator();
menu.addAction(ui->actionFile_Properties);
//these actions needs parser
ui->actionGoto_Declaration->setEnabled(!editor->parser()->parsing());
ui->actionGoto_Definition->setEnabled(!editor->parser()->parsing());
ui->actionFind_references->setEnabled(!editor->parser()->parsing());
} else {
//mouse on gutter
int line;
if (!editor->GetLineOfMouse(line))
line=-1;
menu.addAction(ui->actionToggle_Breakpoint);
menu.addAction(ui->actionBreakpoint_property);
menu.addAction(ui->actionClear_all_breakpoints);
ui->actionBreakpoint_property->setEnabled(editor->hasBreakpoint(line));
}
menu.exec(editor->viewport()->mapToGlobal(pos));
}
void MainWindow::onEditorTabContextMenu(const QPoint &pos)
{
int index = ui->EditorTabsLeft->tabBar()->tabAt(pos);
if (index<0)
return;
ui->EditorTabsLeft->setCurrentIndex(index);
QMenu menu(this);
QTabBar* tabBar = ui->EditorTabsLeft->tabBar();
menu.addAction(ui->actionClose);
menu.addAction(ui->actionClose_All);
menu.addSeparator();
menu.addAction(ui->actionOpen_Containing_Folder);
menu.addAction(ui->actionOpen_Terminal);
menu.addSeparator();
menu.addAction(ui->actionFile_Properties);
menu.exec(tabBar->mapToGlobal(pos));
}
void MainWindow::closeProject(bool refreshEditor)
{
// Stop executing program
on_actionStop_Execution_triggered();
// Only update file monitor once (and ignore updates)
bool oldBlock= mFileSystemWatcher.blockSignals(true);
{
auto action = finally([&,this]{
mFileSystemWatcher.blockSignals(oldBlock);
});
// TODO: should we save watches?
if (mProject->modified()) {
QString s;
if (mProject->name().isEmpty()) {
s = mProject->filename();
} else {
s = mProject->name();
}
if (mSystemTurnedOff) {
mProject->saveAll();
} else {
int answer = QMessageBox::question(
this,
tr("Save project"),
tr("The project '%1' has modifications.").arg(s)
+ "<br />"
+ tr("Do you want to save it?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
QMessageBox::Yes);
switch (answer) {
case QMessageBox::Yes:
mProject->saveAll();
break;
case QMessageBox::No:
mProject->setModified(false);
mProject->saveLayout();
break;
case QMessageBox::Cancel:
mProject->saveLayout();
return;
}
}
} else
mProject->saveLayout(); // always save layout, but not when SaveAll has been called
mClassBrowserModel.beginUpdate();
{
auto action2 = finally([this]{
mClassBrowserModel.endUpdate();
});
// Remember it
pSettings->history().addToOpenedProjects(mProject->filename());
mEditorList->beginUpdate();
{
auto action3 = finally([this]{
mEditorList->endUpdate();
});
mProject.reset();
if (!mQuitting && refreshEditor) {
//reset Class browsing
ui->tabInfos->setCurrentWidget(ui->tabStructure);
Editor * e = mEditorList->getEditor();
updateClassBrowserForEditor(e);
} else {
mClassBrowserModel.setParser(nullptr);
mClassBrowserModel.setCurrentFile("");
}
}
}
if (!mQuitting) {
// Clear project browser
ui->projectView->setModel(nullptr);
// Clear error browser
ui->tableIssues->clearIssues();
ui->tabProject->setVisible(false);
}
}
}
void MainWindow::onFileChanged(const QString &path)
{
Editor *e = mEditorList->getOpenedEditorByFilename(path);
if (e) {
if (fileExists(path)) {
e->activate();
if (QMessageBox::question(this,tr("Compile"),
tr("File '%1' was changed.").arg(path)+"<BR /><BR />" + tr("Reload its content from disk?"),
QMessageBox::Yes|QMessageBox::No,
QMessageBox::No) == QMessageBox::Yes) {
try {
e->loadFile();
} catch(FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
} else {
if (QMessageBox::question(this,tr("Compile"),
tr("File '%1' was removed.").arg(path)+"<BR /><BR />" + tr("Keep it open?"),
QMessageBox::Yes|QMessageBox::No,
QMessageBox::Yes) == QMessageBox::No) {
mEditorList->closeEditor(e);
} else {
e->setModified(true);
e->updateCaption();
}
}
}
}
const std::shared_ptr<HeaderCompletionPopup> &MainWindow::headerCompletionPopup() const
{
return mHeaderCompletionPopup;
}
const std::shared_ptr<CodeCompletionPopup> &MainWindow::completionPopup() const
{
return mCompletionPopup;
}
SearchDialog *MainWindow::searchDialog() const
{
return mSearchDialog;
}
SearchResultModel *MainWindow::searchResultModel()
{
return &mSearchResultModel;
}
EditorList *MainWindow::editorList() const
{
return mEditorList;
}
Debugger *MainWindow::debugger() const
{
return mDebugger;
}
CPUDialog *MainWindow::cpuDialog() const
{
return mCPUDialog;
}
void MainWindow::on_actionNew_triggered()
{
try {
Editor * editor=mEditorList->newEditor("",ENCODING_AUTO_DETECT,false,true);
editor->activate();
updateForEncodingInfo();
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
void MainWindow::on_EditorTabsLeft_tabCloseRequested(int index)
{
Editor* editor = mEditorList->getEditor(index,ui->EditorTabsLeft);
mEditorList->closeEditor(editor);
}
void MainWindow::on_actionOpen_triggered()
{
try {
QString selectedFileFilter;
selectedFileFilter = pSystemConsts->defaultAllFileFilter();
QStringList files = QFileDialog::getOpenFileNames(pMainWindow,
tr("Open"), QString(), pSystemConsts->defaultFileFilters().join(";;"),
&selectedFileFilter);
openFiles(files);
} catch (FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
void MainWindow::closeEvent(QCloseEvent *event) {
Settings::UI& settings = pSettings->ui();
settings.setMainWindowState(saveState());
settings.setMainWindowGeometry(saveGeometry());
settings.setBottomPanelHeight(mBottomPanelHeight);
settings.setBottomPanelIndex(ui->tabMessages->currentIndex());
settings.setBottomPanelOpenned(mBottomPanelOpenned);
settings.setLeftPanelWidth(mLeftPanelWidth);
settings.setLeftPanelIndex(ui->tabInfos->currentIndex());
settings.setLeftPanelOpenned(mLeftPanelOpenned);
settings.save();
if (!mEditorList->closeAll(false)) {
event->ignore();
return ;
}
delete mEditorList;
event->accept();
return;
}
void MainWindow::showEvent(QShowEvent *event)
{
const Settings::UI& settings = pSettings->ui();
ui->tabMessages->setCurrentIndex(settings.bottomPanelIndex());
if (settings.bottomPanelOpenned()) {
mBottomPanelHeight = settings.bottomPanelHeight();
openCloseBottomPanel(true);
} else {
openCloseBottomPanel(false);
mBottomPanelHeight = settings.bottomPanelHeight();
}
ui->tabInfos->setCurrentIndex(settings.leftPanelIndex());
if (settings.leftPanelOpenned()) {
mLeftPanelWidth = settings.leftPanelWidth();
openCloseLeftPanel(true);
} else {
openCloseLeftPanel(false);
mLeftPanelWidth = settings.leftPanelWidth();
}
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()){
event->acceptProposedAction();
}
}
void MainWindow::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasUrls()) {
foreach(const QUrl& url, event->mimeData()->urls()){
if (!url.isLocalFile())
continue;
QString file = url.toLocalFile();
if (getFileType(file)==FileType::Project) {
openProject(file);
return;
}
}
foreach(const QUrl& url, event->mimeData()->urls()){
if (!url.isLocalFile())
continue;
QString file = url.toLocalFile();
openFile(file);
}
}
}
void MainWindow::on_actionSave_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL) {
try {
editor->save();
if (editor->inProject() && (mProject))
mProject->saveAll();
} catch(FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
}
void MainWindow::on_actionSaveAs_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL) {
try {
editor->saveAs();
} catch(FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
}
void MainWindow::on_actionOptions_triggered()
{
bool oldCodeCompletion = pSettings->codeCompletion().enabled();
SettingsDialog settingsDialog;
settingsDialog.exec();
bool newCodeCompletion = pSettings->codeCompletion().enabled();
if (!oldCodeCompletion && newCodeCompletion) {
Editor *e = mEditorList->getEditor();
if (mProject && !e) {
scanActiveProject(true);
} else if (mProject && e && e->inProject()) {
scanActiveProject(true);
} else if (e) {
e->reparse();
}
}
}
void MainWindow::onCompilerSetChanged(int index)
{
if (index<0)
return;
pSettings->compilerSets().setDefaultIndex(index);
pSettings->compilerSets().saveDefaultIndex();
}
void MainWindow::onCompileLog(const QString &msg)
{
ui->txtCompilerOutput->appendPlainText(msg);
}
void MainWindow::onCompileIssue(PCompileIssue issue)
{
ui->tableIssues->addIssue(issue);
// Update tab caption
// if CompilerOutput.Items.Count = 1 then
// CompSheet.Caption := Lang[ID_SHEET_COMP] + ' (' + IntToStr(CompilerOutput.Items.Count) + ')';
if (issue->type == CompileIssueType::Error || issue->type ==
CompileIssueType::Warning) {
Editor* e = mEditorList->getOpenedEditorByFilename(issue->filename);
if (e!=nullptr && (issue->line>0)) {
int line = issue->line;
if (line > e->lines()->count())
return;
int col = std::min(issue->column,e->lines()->getString(line-1).length()+1);
if (col < 1)
col = e->lines()->getString(line-1).length()+1;
e->addSyntaxIssues(line,col,issue->endColumn,issue->type,issue->description);
}
}
}
void MainWindow::onCompileFinished()
{
// Update tab caption
int i = ui->tabMessages->indexOf(ui->tabIssues);
if (i==-1)
return;
ui->tabMessages->setTabText(i, tr("Issues") +
QString(" (%1)").arg(ui->tableIssues->model()->rowCount()));
// Close it if there's nothing to show
if (mCheckSyntaxInBack) {
// check syntax in back, don't change message panel
} else if (
(ui->tableIssues->count() == 0)
// and (ResourceOutput.Items.Count = 0)
// and devData.AutoCloseProgress
) {
openCloseBottomPanel(false);
// Or open it if there is anything to show
} else {
if (ui->tableIssues->count() > 0) {
if (ui->tabMessages->currentIndex() != i) {
ui->tabMessages->setCurrentIndex(i);
}
// end else if (ResourceOutput.Items.Count > 0) then begin
// if MessageControl.ActivePage <> ResSheet then begin
// MessageControl.ActivePage := ResSheet;
// fMessageControlChanged := False;
// end;
// end;
openCloseBottomPanel(true);
}
}
Editor * e = mEditorList->getEditor();
if (e!=nullptr) {
e->invalidate();
}
// Jump to problem location, sorted by significance
if ((mCompilerManager->compileErrorCount() > 0) && (!mCheckSyntaxInBack)) {
// First try to find errors
for (int i=0;i<ui->tableIssues->count();i++) {
PCompileIssue issue = ui->tableIssues->issue(i);
if (issue->type == CompileIssueType::Error) {
if (e && e->filename() != issue->filename)
continue;
ui->tableIssues->selectRow(i);
QModelIndex index =ui->tableIssues->model()->index(i,0);
emit ui->tableIssues->doubleClicked(index);
break;
}
}
// Then try to find warnings
for (int i=0;i<ui->tableIssues->count();i++) {
PCompileIssue issue = ui->tableIssues->issue(i);
if (issue->type == CompileIssueType::Warning) {
if (e && e->filename() != issue->filename)
continue;
ui->tableIssues->selectRow(i);
QModelIndex index =ui->tableIssues->model()->index(i,0);
emit ui->tableIssues->doubleClicked(index);
}
}
// Then try to find anything with a line number...
// for I := 0 to CompilerOutput.Items.Count - 1 do begin
// if not SameStr(CompilerOutput.Items[I].Caption, '') then begin
// CompilerOutput.Selected := CompilerOutput.Items[I];
// CompilerOutput.Selected.MakeVisible(False);
// CompilerOutputDblClick(CompilerOutput);
// Exit;
// end;
// end;
// Then try to find a resource error
// if ResourceOutput.Items.Count > 0 then begin
// ResourceOutput.Selected := ResourceOutput.Items[0];
// ResourceOutput.Selected.MakeVisible(False);
// CompilerOutputDblClick(ResourceOutput);
// end;
} else {
if (mCompileSuccessionTask) {
switch (mCompileSuccessionTask->type) {
case MainWindow::CompileSuccessionTaskType::Run:
runExecutable(mCompileSuccessionTask->filename);
break;
case MainWindow::CompileSuccessionTaskType::Debug:
debug();
break;
}
mCompileSuccessionTask.reset();
}
}
mCheckSyntaxInBack=false;
updateCompileActions();
updateAppTitle();
}
void MainWindow::onCompileErrorOccured(const QString &reason)
{
QMessageBox::critical(this,tr("Compile Failed"),reason);
}
void MainWindow::onRunErrorOccured(const QString &reason)
{
QMessageBox::critical(this,tr("Run Failed"),reason);
}
void MainWindow::onRunFinished()
{
updateCompileActions();
if (pSettings->executor().minimizeOnRun()) {
showNormal();
}
updateAppTitle();
}
void MainWindow::cleanUpCPUDialog()
{
CPUDialog* ptr=mCPUDialog;
mCPUDialog=nullptr;
ptr->deleteLater();
}
void MainWindow::onDebugCommandInput(const QString &command)
{
if (mDebugger->executing()) {
mDebugger->sendCommand(command,"");
}
}
void MainWindow::on_actionCompile_triggered()
{
mCompileSuccessionTask.reset();
compile();
}
void MainWindow::on_actionRun_triggered()
{
runExecutable();
}
void MainWindow::on_actionUndo_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->undo();
}
}
void MainWindow::on_actionRedo_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->redo();
}
}
void MainWindow::on_actionCut_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->cutToClipboard();
}
}
void MainWindow::on_actionSelectAll_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->selectAll();
}
}
void MainWindow::on_actionCopy_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->copyToClipboard();
}
}
void MainWindow::on_actionPaste_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->pasteFromClipboard();
}
}
void MainWindow::on_actionIndent_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->tab();
}
}
void MainWindow::on_actionUnIndent_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->untab();
}
}
void MainWindow::on_actionToggleComment_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
editor->toggleComment();
}
}
void MainWindow::on_actionUnfoldAll_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
//editor->clearFolds();
}
}
void MainWindow::on_actionFoldAll_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
//editor->clearFolds();
//editor->foldAll();
}
}
void MainWindow::on_tableIssues_doubleClicked(const QModelIndex &index)
{
PCompileIssue issue = ui->tableIssues->issue(index);
if (!issue)
return;
Editor * editor = mEditorList->getEditorByFilename(issue->filename);
if (editor == nullptr)
return;
editor->setCaretPositionAndActivate(issue->line,issue->column);
}
void MainWindow::on_actionEncode_in_ANSI_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor == nullptr)
return;
try {
editor->setEncodingOption(ENCODING_SYSTEM_DEFAULT);
} catch(FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
void MainWindow::on_actionEncode_in_UTF_8_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor == nullptr)
return;
try {
editor->setEncodingOption(ENCODING_UTF8);
} catch(FileError e) {
QMessageBox::critical(this,tr("Error"),e.reason());
}
}
void MainWindow::on_actionAuto_Detect_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor == nullptr)
return;
editor->setEncodingOption(ENCODING_AUTO_DETECT);
}
void MainWindow::on_actionConvert_to_ANSI_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor == nullptr)
return;
if (QMessageBox::warning(this,tr("Confirm Convertion"),
tr("The editing file will be saved using %1 encoding. <br />This operation can't be reverted. <br />Are you sure to continue?")
.arg(QString(QTextCodec::codecForLocale()->name())),
QMessageBox::Yes, QMessageBox::No)!=QMessageBox::Yes)
return;
editor->convertToEncoding(ENCODING_SYSTEM_DEFAULT);
}
void MainWindow::on_actionConvert_to_UTF_8_triggered()
{
Editor * editor = mEditorList->getEditor();
if (editor == nullptr)
return;
if (QMessageBox::warning(this,tr("Confirm Convertion"),
tr("The editing file will be saved using %1 encoding. <br />This operation can't be reverted. <br />Are you sure to continue?")
.arg(ENCODING_UTF8),
QMessageBox::Yes, QMessageBox::No)!=QMessageBox::Yes)
return;
editor->convertToEncoding(ENCODING_UTF8);
}
void MainWindow::on_tabMessages_tabBarClicked(int index)
{
if (index == ui->tabMessages->currentIndex()) {
openCloseBottomPanel(!mBottomPanelOpenned);
}
}
void MainWindow::on_tabMessages_currentChanged(int index)
{
int idxClose = ui->tabMessages->indexOf(ui->tabClose);
if (index == idxClose) {
openCloseBottomPanel(false);
} else {
openCloseBottomPanel(true);
}
}
void MainWindow::on_tabMessages_tabBarDoubleClicked(int index)
{
}
void MainWindow::on_actionCompile_Run_triggered()
{
mCompileSuccessionTask = std::make_shared<CompileSuccessionTask>();
mCompileSuccessionTask->type = CompileSuccessionTaskType::Run;
compile();
}
void MainWindow::on_actionRebuild_triggered()
{
mCompileSuccessionTask.reset();
compile(true);
}
void MainWindow::on_actionStop_Execution_triggered()
{
mCompilerManager->stopRun();
mDebugger->stop();
}
void MainWindow::on_actionDebug_triggered()
{
debug();
}
CompileTarget MainWindow::getCompileTarget()
{
// Check if the current file belongs to a project
CompileTarget target = CompileTarget::None;
Editor* e = mEditorList->getEditor();
if (e!=nullptr) {
// Treat makefiles as InProject files too
if (mProject
&& (e->inProject() || (mProject->makeFileName() == e->filename()))
) {
target = CompileTarget::Project;
} else {
target = CompileTarget::File;
}
// No editors have been opened. Check if a project is open
} else if (mProject) {
target = CompileTarget::Project;
}
return target;
}
bool MainWindow::debugInferiorhasBreakpoint()
{
Editor * e = mEditorList->getEditor();
if (e==nullptr)
return false;
if (!e->inProject()) {
for (const PBreakpoint& breakpoint:mDebugger->breakpointModel()->breakpoints()) {
if (e->filename() == breakpoint->filename) {
return true;
}
}
} else {
for (const PBreakpoint& breakpoint:mDebugger->breakpointModel()->breakpoints()) {
Editor* e1 = mEditorList->getOpenedEditorByFilename(breakpoint->filename);
if (e1->inProject()) {
return true;
}
}
}
return false;
}
void MainWindow::on_actionStep_Over_triggered()
{
if (mDebugger->executing()) {
//WatchView.Items.BeginUpdate();
mDebugger->invalidateAllVars();
mDebugger->sendCommand("next", "");
mDebugger->updateDebugInfo();
mDebugger->refreshWatchVars();
}
}
void MainWindow::on_actionStep_Into_triggered()
{
if (mDebugger->executing()) {
//WatchView.Items.BeginUpdate();
mDebugger->invalidateAllVars();
mDebugger->sendCommand("step", "");
mDebugger->updateDebugInfo();
mDebugger->refreshWatchVars();
}
}
void MainWindow::on_actionStep_Out_triggered()
{
if (mDebugger->executing()) {
//WatchView.Items.BeginUpdate();
mDebugger->invalidateAllVars();
mDebugger->sendCommand("finish", "");
mDebugger->updateDebugInfo();
mDebugger->refreshWatchVars();
}
}
void MainWindow::on_actionRun_To_Cursor_triggered()
{
if (mDebugger->executing()) {
Editor *e=mEditorList->getEditor();
if (e!=nullptr) {
//WatchView.Items.BeginUpdate();
mDebugger->invalidateAllVars();
mDebugger->sendCommand("tbreak", QString(" %1").arg(e->caretY()));
mDebugger->sendCommand("continue", "");
mDebugger->updateDebugInfo();
mDebugger->refreshWatchVars();
}
}
}
void MainWindow::on_actionContinue_triggered()
{
if (mDebugger->executing()) {
//WatchView.Items.BeginUpdate();
mDebugger->invalidateAllVars();
mDebugger->sendCommand("continue", "");
mDebugger->updateDebugInfo();
mDebugger->refreshWatchVars();
}
}
void MainWindow::on_actionAdd_Watch_triggered()
{
QString s = "";
Editor *e = mEditorList->getEditor();
if (e==nullptr)
return;
if (e->selAvail()) {
s = e->selText();
} else {
s = e->WordAtCursor();
}
bool isOk;
s=QInputDialog::getText(this,
tr("New Watch Expression"),
tr("Enter Watch Expression (it is recommended to use 'this->' for class members):"),
QLineEdit::Normal,
s,&isOk);
if (!isOk)
return;
s = s.trimmed();
if (!s.isEmpty()) {
mDebugger->addWatchVar(s);
}
}
void MainWindow::on_actionView_CPU_Window_triggered()
{
if (mCPUDialog==nullptr) {
mCPUDialog = new CPUDialog(this);
connect(mCPUDialog, &CPUDialog::closed, this, &MainWindow::cleanUpCPUDialog);
}
mCPUDialog->show();
}
void MainWindow::on_actionExit_triggered()
{
close();
}
void MainWindow::onDebugEvaluateInput()
{
QString s=ui->cbEvaluate->currentText().trimmed();
if (!s.isEmpty()) {
connect(mDebugger, &Debugger::evalValueReady,
this, &MainWindow::onEvalValueReady);
mDebugger->sendCommand("print",s,false);
}
}
void MainWindow::onParserProgress(const QString &fileName, int total, int current)
{
// Mention every 5% progress
int showStep = total / 20;
// For Total = 1, avoid division by zero
if (showStep == 0)
showStep = 1;
// Only show if needed (it's a very slow operation)
if (current ==1 || current % showStep==0) {
updateStatusbarMessage(tr("Parsing file %1 of %2: \"%3\"")
.arg(current).arg(total).arg(fileName));
}
}
void MainWindow::onStartParsing()
{
mParserTimer.restart();
}
void MainWindow::onEndParsing(int total, int)
{
double parseTime = mParserTimer.elapsed() / 1000.0;
double parsingFrequency;
if (total > 1) {
if (parseTime>0) {
parsingFrequency = total / parseTime;
} else {
parsingFrequency = 999;
}
updateStatusbarMessage(tr("Done parsing %1 files in %2 seconds")
.arg(total).arg(parseTime)
+ " "
+ tr("(%1 files per second)")
.arg(parsingFrequency));
} else {
updateStatusbarMessage(tr("Done parsing %1 files in %2 seconds")
.arg(total).arg(parseTime));
}
}
void MainWindow::onEvalValueReady(const QString &value)
{
updateDebugEval(value);
disconnect(mDebugger, &Debugger::evalValueReady,
this, &MainWindow::onEvalValueReady);
}
void MainWindow::on_actionFind_triggered()
{
Editor *e = mEditorList->getEditor();
if (!e)
return;
if (mSearchDialog==nullptr) {
mSearchDialog = new SearchDialog(this);
}
QString s = e->WordAtCursor();
mSearchDialog->find(s);
}
void MainWindow::on_actionFind_in_files_triggered()
{
if (mSearchDialog==nullptr) {
mSearchDialog = new SearchDialog(this);
}
Editor *e = mEditorList->getEditor();
if (e) {
QString s = e->WordAtCursor();
mSearchDialog->findInFiles(s);
} else {
mSearchDialog->findInFiles("");
}
}
void MainWindow::on_actionReplace_triggered()
{
Editor *e = mEditorList->getEditor();
if (!e)
return;
if (mSearchDialog==nullptr) {
mSearchDialog = new SearchDialog(this);
}
QString s = e->WordAtCursor();
mSearchDialog->replace(s,s);
}
void MainWindow::on_actionFind_Next_triggered()
{
Editor *e = mEditorList->getEditor();
if (e==nullptr)
return;
if (mSearchDialog==nullptr)
return;
mSearchDialog->findNext();
}
void MainWindow::on_actionFind_Previous_triggered()
{
Editor *e = mEditorList->getEditor();
if (e==nullptr)
return;
if (mSearchDialog==nullptr)
return;
mSearchDialog->findPrevious();
}
void MainWindow::on_cbSearchHistory_currentIndexChanged(int index)
{
mSearchResultModel.setCurrentIndex(index);
PSearchResults results = mSearchResultModel.results(index);
if (results && results->searchType == SearchType::Search) {
ui->btnSearchAgin->setEnabled(true);
} else {
ui->btnSearchAgin->setEnabled(false);
}
}
void MainWindow::on_btnSearchAgin_clicked()
{
if (mSearchDialog==nullptr) {
mSearchDialog = new SearchDialog(this);
}
PSearchResults results=mSearchResultModel.currentResults();
if (results){
mSearchDialog->findInFiles(results->keyword,
results->scope,
results->options);
}
}
void MainWindow::on_actionRemove_Watch_triggered()
{
QModelIndex index =ui->watchView->currentIndex();
QModelIndex parent;
while (true) {
parent = ui->watchView->model()->parent(index);
if (parent.isValid()) {
index=parent;
} else {
break;
}
}
mDebugger->removeWatchVar(index);
}
void MainWindow::on_actionRemove_All_Watches_triggered()
{
mDebugger->removeWatchVars(true);
}
void MainWindow::on_actionModify_Watch_triggered()
{
}
void MainWindow::on_actionReformat_Code_triggered()
{
Editor* e = mEditorList->getEditor();
if (e) {
e->reformat();
e->activate();
}
}
CaretList &MainWindow::caretList()
{
return mCaretList;
}
void MainWindow::updateCaretActions()
{
ui->actionBack->setEnabled(mCaretList.hasPrevious());
ui->actionForward->setEnabled(mCaretList.hasNext());
}
void MainWindow::on_actionBack_triggered()
{
PEditorCaret caret = mCaretList.gotoAndGetPrevious();
mCaretList.pause();
if (caret) {
caret->editor->setCaretPositionAndActivate(caret->line,caret->aChar);
}
mCaretList.unPause();
updateCaretActions();
}
void MainWindow::on_actionForward_triggered()
{
PEditorCaret caret = mCaretList.gotoAndGetNext();
mCaretList.pause();
if (caret) {
caret->editor->setCaretPositionAndActivate(caret->line,caret->aChar);
}
mCaretList.unPause();
updateCaretActions();
}
void MainWindow::on_tabInfos_tabBarClicked(int index)
{
if (index == ui->tabInfos->currentIndex()) {
openCloseLeftPanel(!mLeftPanelOpenned);
}
}
void MainWindow::on_splitterInfos_splitterMoved(int, int)
{
QList<int> sizes = ui->splitterMessages->sizes();
mLeftPanelWidth = sizes[0];
}
void MainWindow::on_splitterMessages_splitterMoved(int, int)
{
QList<int> sizes = ui->splitterMessages->sizes();
mBottomPanelHeight = sizes[1];
}
void MainWindow::on_EditorTabsLeft_tabBarDoubleClicked(int index)
{
maximizeEditor();
}
void MainWindow::on_actionClose_triggered()
{
mClosing = true;
Editor* e = mEditorList->getEditor();
if (e) {
mEditorList->closeEditor(e);
}
mClosing = false;
}
void MainWindow::on_actionClose_All_triggered()
{
mClosing = true;
mEditorList->closeAll(mSystemTurnedOff);
mClosing = false;
}
void MainWindow::on_actionMaximize_Editor_triggered()
{
maximizeEditor();
}
void MainWindow::on_actionNext_Editor_triggered()
{
mEditorList->selectNextPage();
}
void MainWindow::on_actionPrevious_Editor_triggered()
{
mEditorList->selectPreviousPage();
}
void MainWindow::on_actionToggle_Breakpoint_triggered()
{
Editor * editor = mEditorList->getEditor();
int line;
if (editor && editor->PointToLine(mEditorContextMenuPos,line))
editor->toggleBreakpoint(line);
}
void MainWindow::on_actionClear_all_breakpoints_triggered()
{
Editor *e=mEditorList->getEditor();
if (!e)
return;
if (QMessageBox::question(this,
tr("Clear all breakpoints"),
tr("Do you really want to clear all breakpoints in this file?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) == QMessageBox::Yes) {
e->clearBreakpoints();
}
}
void MainWindow::on_actionBreakpoint_property_triggered()
{
Editor * editor = mEditorList->getEditor();
int line;
if (editor && editor->PointToLine(mEditorContextMenuPos,line)) {
if (editor->hasBreakpoint(line))
editor->modifyBreakpointProperty(line);
}
}
void MainWindow::on_actionGoto_Declaration_triggered()
{
Editor * editor = mEditorList->getEditor();
BufferCoord pos;
if (editor && editor->PointToCharLine(mEditorContextMenuPos,pos)) {
editor->gotoDeclaration(pos);
}
}
void MainWindow::on_actionGoto_Definition_triggered()
{
Editor * editor = mEditorList->getEditor();
BufferCoord pos;
if (editor && editor->PointToCharLine(mEditorContextMenuPos,pos)) {
editor->gotoDefinition(pos);
}
}
void MainWindow::on_actionFind_references_triggered()
{
Editor * editor = mEditorList->getEditor();
BufferCoord pos;
if (editor && editor->PointToCharLine(mEditorContextMenuPos,pos)) {
CppRefacter refactor;
refactor.findOccurence(editor,pos);
ui->tabMessages->setCurrentWidget(ui->tabSearch);
openCloseBottomPanel(true);
}
}
void MainWindow::on_actionOpen_Containing_Folder_triggered()
{
Editor* editor = mEditorList->getEditor();
if (editor) {
QFileInfo info(editor->filename());
if (!info.path().isEmpty()) {
QDesktopServices::openUrl(info.path());
}
}
}
void MainWindow::on_actionOpen_Terminal_triggered()
{
Editor* editor = mEditorList->getEditor();
if (editor) {
QFileInfo info(editor->filename());
if (!info.path().isEmpty()) {
openShell(info.path(),"cmd.exe");
}
}
}
void MainWindow::on_actionFile_Properties_triggered()
{
Editor* editor = mEditorList->getEditor();
if (editor) {
FilePropertiesDialog dialog(editor,this);
dialog.exec();
dialog.setParent(nullptr);
}
}
void MainWindow::on_searchView_doubleClicked(const QModelIndex &index)
{
QString filename;
int line;
int start;
if (mSearchResultTreeModel->getItemFileAndLineChar(
index,filename,line,start)) {
Editor *e = mEditorList->getEditorByFilename(filename);
if (e) {
e->setCaretPositionAndActivate(line,start);
}
}
}
void MainWindow::on_tblStackTrace_doubleClicked(const QModelIndex &index)
{
PTrace trace = mDebugger->backtraceModel()->backtrace(index.row());
if (trace) {
Editor *e = mEditorList->getEditorByFilename(trace->filename);
if (e) {
e->setCaretPositionAndActivate(trace->line,1);
}
}
}
void MainWindow::on_tblBreakpoints_doubleClicked(const QModelIndex &index)
{
PBreakpoint breakpoint = mDebugger->breakpointModel()->breakpoint(index.row());
if (breakpoint) {
Editor * e = mEditorList->getEditorByFilename(breakpoint->filename);
if (e) {
e->setCaretPositionAndActivate(breakpoint->line,1);
}
}
}
std::shared_ptr<Project> MainWindow::project()
{
return mProject;
}
void MainWindow::on_projectView_doubleClicked(const QModelIndex &index)
{
if (!index.isValid())
return;
FolderNode * node = static_cast<FolderNode*>(index.internalPointer());
if (!node)
return;
if (node->unitIndex>=0) {
mProject->openUnit(node->unitIndex);
}
}
void MainWindow::on_actionClose_Project_triggered()
{
mClosing = true;
closeProject(true);
mClosing = false;
}