From 664922a301aa397ba4a351dce62bf59c0e4cb860 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Tue, 15 Feb 2022 00:01:50 +0800 Subject: [PATCH] - fix: convert to encoding setting in compiler set option not correctly handled work save: git repository class --- NEWS.md | 4 + RedPandaIDE/compiler/compiler.cpp | 3 +- RedPandaIDE/customfileiconprovider.cpp | 48 +++--- RedPandaIDE/customfileiconprovider.h | 6 +- RedPandaIDE/editor.cpp | 2 +- RedPandaIDE/main.cpp | 5 + RedPandaIDE/mainwindow.cpp | 142 +++++++++++++++++- RedPandaIDE/mainwindow.h | 10 +- RedPandaIDE/mainwindow.ui | 7 +- RedPandaIDE/project.cpp | 17 ++- RedPandaIDE/project.h | 6 +- RedPandaIDE/settings.cpp | 57 ++++++- RedPandaIDE/settings.h | 5 + .../compilersetoptionwidget.cpp | 2 +- RedPandaIDE/settingsdialog/toolsgitwidget.cpp | 2 + RedPandaIDE/systemconsts.h | 2 + RedPandaIDE/utils.cpp | 2 + RedPandaIDE/vcs/gitmanager.cpp | 123 ++++++++++++++- RedPandaIDE/vcs/gitmanager.h | 9 +- RedPandaIDE/vcs/gitrepository.cpp | 62 +++++--- RedPandaIDE/vcs/gitrepository.h | 37 ++++- RedPandaIDE/widgets/customfilesystemmodel.cpp | 8 - RedPandaIDE/widgets/customfilesystemmodel.h | 5 - 23 files changed, 479 insertions(+), 85 deletions(-) diff --git a/NEWS.md b/NEWS.md index 0ce389c3..9f962658 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,11 +1,15 @@ - change: rename "compile log" panel to "tools output" - fix: debug panel can't be correctly show/hide - enhancement: redesign tools output's context menu, add "clear" menu item + - enhancement: tools -> git in the options dialog + - enhancement: auto detect git in PATH + - enhancement: basic git commands Red Panda C++ Version 0.14.3 - fix: wrong code completion font size, when screen dpi changed - enhancement: replace Files View Panel's path lineedit control with combo box - enhancement: custome icons for project view + - fix: convert to encoding setting in compiler set option not correctly handled Red Panda C++ Version 0.14.2 - enhancement: file system view mode for project diff --git a/RedPandaIDE/compiler/compiler.cpp b/RedPandaIDE/compiler/compiler.cpp index 7114bd31..a84fa2cb 100644 --- a/RedPandaIDE/compiler/compiler.cpp +++ b/RedPandaIDE/compiler/compiler.cpp @@ -292,8 +292,7 @@ QString Compiler::getCharsetArgument(const QByteArray& encoding) } else { encodingName = encoding; } - if (compilerSetExecCharset == ENCODING_SYSTEM_DEFAULT - || compilerSetExecCharset.isEmpty()) { + if (compilerSetExecCharset == ENCODING_SYSTEM_DEFAULT || compilerSetExecCharset.isEmpty()) { execEncodingName = systemEncodingName; } else { execEncodingName = compilerSetExecCharset; diff --git a/RedPandaIDE/customfileiconprovider.cpp b/RedPandaIDE/customfileiconprovider.cpp index 3a11b57a..9610c5ea 100644 --- a/RedPandaIDE/customfileiconprovider.cpp +++ b/RedPandaIDE/customfileiconprovider.cpp @@ -1,15 +1,25 @@ #include "customfileiconprovider.h" #include "iconsmanager.h" -#include "vcs/gitmanager.h" +#include "vcs/gitrepository.h" CustomFileIconProvider::CustomFileIconProvider() { - mVCSManager = new GitManager(); + mVCSRepository = new GitRepository(""); } CustomFileIconProvider::~CustomFileIconProvider() { - delete mVCSManager; + delete mVCSRepository; +} + +void CustomFileIconProvider::setRootFolder(const QString &folder) +{ + mVCSRepository->setFolder(folder); +} + +void CustomFileIconProvider::update() +{ + mVCSRepository->update(); } QIcon CustomFileIconProvider::icon(IconType type) const @@ -27,50 +37,50 @@ QIcon CustomFileIconProvider::icon(const QFileInfo &info) const { QIcon icon; if (info.isDir()) { - if (mVCSManager && mVCSManager->isFileInRepository(info)) { - if (mVCSManager->isFileInStaged(info)) + if (mVCSRepository->isFileInRepository(info)) { + if (mVCSRepository->isFileStaged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_FOLDER_VCS_STAGED); - else if (mVCSManager->isFileChanged(info)) + else if (mVCSRepository->isFileChanged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_FOLDER_VCS_CHANGED); else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_FOLDER_VCS_NOCHANGE); } else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_FOLDER); - } if (isHFile(info.fileName())) { - if (mVCSManager && mVCSManager->isFileInRepository(info)) { - if (mVCSManager->isFileInStaged(info)) + } else if (isHFile(info.fileName())) { + if (mVCSRepository->isFileInRepository(info)) { + if (mVCSRepository->isFileStaged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_HFILE_VCS_STAGED); - else if (mVCSManager->isFileChanged(info)) + else if (mVCSRepository->isFileChanged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_HFILE_VCS_CHANGED); else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_HFILE_VCS_NOCHANGE); } else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_HFILE); } else if (isCppFile(info.fileName())) { - if (mVCSManager && mVCSManager->isFileInRepository(info)) { - if (mVCSManager->isFileInStaged(info)) + if (mVCSRepository->isFileInRepository(info)) { + if (mVCSRepository->isFileStaged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CPPFILE_VCS_STAGED); - else if (mVCSManager->isFileChanged(info)) + else if (mVCSRepository->isFileChanged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CPPFILE_VCS_CHANGED); else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CPPFILE_VCS_NOCHANGE); } else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CPPFILE); } else if (isCFile(info.fileName())) { - if (mVCSManager && mVCSManager->isFileInRepository(info)) { - if (mVCSManager->isFileInStaged(info)) + if (mVCSRepository->isFileInRepository(info)) { + if (mVCSRepository->isFileStaged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CFILE_VCS_STAGED); - else if (mVCSManager->isFileChanged(info)) + else if (mVCSRepository->isFileChanged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CFILE_VCS_CHANGED); else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CFILE_VCS_NOCHANGE); } else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_CFILE); } else if (info.suffix()=="dev") { - if (mVCSManager && mVCSManager->isFileInRepository(info)) { - if (mVCSManager->isFileInStaged(info)) + if (mVCSRepository->isFileInRepository(info)) { + if (mVCSRepository->isFileStaged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_PROJECTFILE_VCS_STAGED); - else if (mVCSManager->isFileChanged(info)) + else if (mVCSRepository->isFileChanged(info)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_PROJECTFILE_VCS_CHANGED); else icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_PROJECTFILE_VCS_NOCHANGE); diff --git a/RedPandaIDE/customfileiconprovider.h b/RedPandaIDE/customfileiconprovider.h index c5e339f2..5e79a45a 100644 --- a/RedPandaIDE/customfileiconprovider.h +++ b/RedPandaIDE/customfileiconprovider.h @@ -3,14 +3,16 @@ #include -class GitManager; +class GitRepository; class CustomFileIconProvider : public QFileIconProvider { public: CustomFileIconProvider(); ~CustomFileIconProvider(); + void setRootFolder(const QString& folder); + void update(); private: - GitManager* mVCSManager; + GitRepository* mVCSRepository; // QFileIconProvider interface public: QIcon icon(IconType type) const override; diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 638614bd..e0a4b75f 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -68,7 +68,7 @@ const char* SaveException::what() const noexcept { } Editor::Editor(QWidget *parent): - Editor(parent,QObject::tr("untitled"),ENCODING_SYSTEM_DEFAULT,false,true,nullptr) + Editor(parent,QObject::tr("untitled"),ENCODING_AUTO_DETECT,false,true,nullptr) { } diff --git a/RedPandaIDE/main.cpp b/RedPandaIDE/main.cpp index 4097dc21..7e6e1803 100644 --- a/RedPandaIDE/main.cpp +++ b/RedPandaIDE/main.cpp @@ -162,6 +162,11 @@ int main(int argc, char *argv[]) //set default open folder QDir::setCurrent(pSettings->environment().defaultOpenFolder()); + //auto detect git in path + if (!pSettings->vcs().gitOk()) { + pSettings->vcs().detectGitInPath(); + } + MainWindow mainWindow; pMainWindow = &mainWindow; if (app.arguments().count()>1) { diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 3ffc4cdf..c893fe5e 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -39,6 +39,7 @@ #include "iconsmanager.h" #include "widgets/newclassdialog.h" #include "widgets/newheaderdialog.h" +#include "vcs/gitmanager.h" #include #include @@ -287,7 +288,7 @@ MainWindow::MainWindow(QWidget *parent) //files view ui->treeFiles->setModel(&mFileSystemModel); mFileSystemModel.setReadOnly(false); - mFileSystemModel.setIconProvider(&mFileIconProvider); + mFileSystemModel.setIconProvider(&mFileSystemModelIconProvider); setFilesViewRoot(pSettings->environment().currentFolder()); for (int i=1;itreeFiles->hideColumn(i); @@ -324,6 +325,9 @@ MainWindow::MainWindow(QWidget *parent) ui->actionEGE_Manual->setVisible(pSettings->environment().language()=="zh_CN"); + //git menu + connect(ui->menuGit, &QMenu::aboutToShow, + this, &MainWindow::updateVCSActions); buildContextMenus(); updateAppTitle(); //applySettings(); @@ -425,7 +429,8 @@ void MainWindow::updateEditorActions() 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_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()); @@ -663,6 +668,8 @@ void MainWindow::applySettings() // ui->cbFilesPath->setItemIcon(i,pIconsManager->getIcon(IconsManager::FILESYSTEM_GIT)); // } + ui->menuGit->menuAction()->setVisible(pSettings->vcs().gitOk()); + } void MainWindow::applyUISettings() @@ -2968,7 +2975,12 @@ void MainWindow::onProjectViewContextMenu(const QPoint &pos) onRoot = true; } } + GitManager vcsManager; + QString branch; + bool hasRepository = vcsManager.hasRepository(mProject->folder(),branch); + QMenu menu(this); + QMenu vcsMenu(this); updateProjectActions(); menu.addAction(ui->actionProject_New_File); menu.addAction(ui->actionNew_Class); @@ -2981,6 +2993,15 @@ void MainWindow::onProjectViewContextMenu(const QPoint &pos) menu.addAction(mProject_Rename_Unit); } menu.addSeparator(); + if (pSettings->vcs().gitOk()) { + if (hasRepository) { + menu.addMenu(&vcsMenu); + } else { + ui->actionGit_Create_Repository->setEnabled(true); + menu.addAction(ui->actionGit_Create_Repository); + } + menu.addSeparator(); + } if (onFolder && mProject->modelType()==ProjectModelType::Custom) { menu.addAction(mProject_Add_Folder); if (!onRoot) { @@ -3001,6 +3022,18 @@ void MainWindow::onProjectViewContextMenu(const QPoint &pos) } menu.addAction(ui->actionProject_options); + if (pSettings->vcs().gitOk() && hasRepository) { + vcsMenu.setTitle(tr("VCS")); + if (ui->projectView->selectionModel()->hasSelection()) + vcsMenu.addAction(ui->actionGit_Add_Files); + vcsMenu.addAction(ui->actionGit_Commit); + vcsMenu.addAction(ui->actionGit_Reset); + vcsMenu.addAction(ui->actionGit_Revert); + + ui->actionGit_Commit->setEnabled(true); + ui->actionGit_Reset->setEnabled(true); + ui->actionGit_Revert->setEnabled(true); + } menu.exec(ui->projectView->mapToGlobal(pos)); } @@ -3054,12 +3087,24 @@ void MainWindow::onFileEncodingContextMenu(const QPoint &pos) void MainWindow::onFilesViewContextMenu(const QPoint &pos) { - + GitManager vcsManager; + QString branch; + bool hasRepository = vcsManager.hasRepository(pSettings->environment().currentFolder(),branch); QMenu menu(this); + QMenu vcsMenu(this); menu.addAction(ui->actionOpen_Folder); menu.addSeparator(); menu.addAction(mFilesView_CreateFolder); menu.addSeparator(); + if (pSettings->vcs().gitOk()) { + if (hasRepository) { + menu.addMenu(&vcsMenu); + } else { + ui->actionGit_Create_Repository->setEnabled(true); + menu.addAction(ui->actionGit_Create_Repository); + } + menu.addSeparator(); + } menu.addAction(mFilesView_Open); menu.addAction(mFilesView_OpenWithExternal); menu.addSeparator(); @@ -3071,6 +3116,19 @@ void MainWindow::onFilesViewContextMenu(const QPoint &pos) mFilesView_OpenWithExternal->setEnabled(info.isFile()); mFilesView_OpenInTerminal->setEnabled(!path.isEmpty()); mFilesView_OpenInExplorer->setEnabled(!path.isEmpty()); + + if (pSettings->vcs().gitOk() && hasRepository) { + vcsMenu.setTitle(tr("VCS")); + if (ui->treeFiles->selectionModel()->hasSelection()) + vcsMenu.addAction(ui->actionGit_Add_Files); + vcsMenu.addAction(ui->actionGit_Commit); + vcsMenu.addAction(ui->actionGit_Reset); + vcsMenu.addAction(ui->actionGit_Revert); + + ui->actionGit_Commit->setEnabled(true); + ui->actionGit_Reset->setEnabled(true); + ui->actionGit_Revert->setEnabled(true); + } menu.exec(ui->treeFiles->mapToGlobal(pos)); } @@ -5501,6 +5559,7 @@ void MainWindow::newProjectUnitFile() PProjectUnit newUnit = mProject->newUnit( mProject->pointerToNode(node),newFileName); idx = mProject->units().count()-1; + mProject->rebuildNodes(); mProject->saveUnits(); updateProjectView(); Editor * editor = mProject->openUnit(idx); @@ -5528,6 +5587,27 @@ void MainWindow::doFilesViewRemoveFile(const QModelIndex &index) } } +void MainWindow::updateVCSActions() +{ + bool hasRepository = false; + bool shouldEnable = false; + if (ui->projectView->isVisible()) { + GitManager vcsManager; + QString branch; + hasRepository = vcsManager.hasRepository(mProject->folder(),branch); + shouldEnable = true; + } else if (ui->treeFiles->isVisible()) { + GitManager vcsManager; + QString branch; + hasRepository = vcsManager.hasRepository(pSettings->environment().currentFolder(),branch); + shouldEnable = true; + } + ui->actionGit_Create_Repository->setEnabled(!hasRepository && shouldEnable); + ui->actionGit_Commit->setEnabled(hasRepository && shouldEnable); + ui->actionGit_Reset->setEnabled(hasRepository && shouldEnable); + ui->actionGit_Revert->setEnabled(hasRepository && shouldEnable); +} + void MainWindow::invalidateProjectProxyModel() { mProjectProxyModel->invalidate(); @@ -5663,6 +5743,7 @@ void MainWindow::showSearchReplacePanel(bool show) void MainWindow::setFilesViewRoot(const QString &path) { + mFileSystemModelIconProvider.setRootFolder(path); mFileSystemModel.setRootPath(path); ui->treeFiles->setRootIndex(mFileSystemModel.index(path)); pSettings->environment().setCurrentFolder(path); @@ -6450,3 +6531,58 @@ void MainWindow::on_actionNew_Class_triggered() pSettings->ui().setNewHeaderDialogHeight(dialog.height()); } + +void MainWindow::on_actionGit_Create_Repository_triggered() +{ + if (ui->treeFiles->isVisible()) { + GitManager vcsManager; + vcsManager.createRepository(pSettings->environment().currentFolder()); + int pos = ui->cbFilesPath->findText(pSettings->environment().currentFolder()); + if (pos>=0) { + ui->cbFilesPath->setItemIcon(pos, pIconsManager->getIcon(IconsManager::FILESYSTEM_GIT)); + } + } else if (ui->projectView->isVisible()) { + GitManager vcsManager; + vcsManager.createRepository(mProject->folder()); + mProject->model()->beginUpdate(); + mProject->model()->endUpdate(); + } +} + + +void MainWindow::on_actionGit_Add_Files_triggered() +{ + if (ui->treeFiles->isVisible()) { + GitManager vcsManager; + QModelIndexList indices = ui->treeFiles->selectionModel()->selectedRows(); + foreach (const QModelIndex index,indices) { + QFileInfo info = mFileSystemModel.fileInfo(index); + vcsManager.add(info.absolutePath(),info.fileName()); + } + //update icons in files view + mFileSystemModelIconProvider.update(); + mFileSystemModel.setIconProvider(&mFileSystemModelIconProvider); + } else if (ui->projectView->isVisible()) { + GitManager vcsManager; + QModelIndexList indices = ui->projectView->selectionModel()->selectedRows(); + foreach (const QModelIndex index,indices) { + QModelIndex realIndex = mProjectProxyModel->mapToSource(index); + ProjectModelNode * node = static_cast(realIndex.internalPointer()); + PProjectModelNode folderNode = mProject->pointerToNode(node); + if (!folderNode) + continue; + if (folderNode->unitIndex>=0) { + PProjectUnit unit = mProject->units()[folderNode->unitIndex]; + QFileInfo info(unit->fileName()); + vcsManager.add(info.absolutePath(),info.fileName()); + } + } + //update icons in project view + mProject->model()->beginUpdate(); + mProject->model()->endUpdate(); + //update icons in files view too + mFileSystemModelIconProvider.update(); + mFileSystemModel.setIconProvider(&mFileSystemModelIconProvider); + } +} + diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 169736a0..214c52cf 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -38,6 +38,7 @@ #include "widgets/labelwithmenu.h" #include "widgets/bookmarkmodel.h" #include "widgets/ojproblemsetmodel.h" +#include "widgets/customfilesystemmodel.h" #include "customfileiconprovider.h" @@ -253,6 +254,7 @@ private: void doFilesViewRemoveFile(const QModelIndex& index); private slots: + void updateVCSActions(); void invalidateProjectProxyModel(); void onEditorRenamed(const QString& oldFilename, const QString& newFilename, bool firstSave); void onAutoSaveTimeout(); @@ -576,6 +578,10 @@ private slots: void on_actionNew_Header_triggered(); + void on_actionGit_Create_Repository_triggered(); + + void on_actionGit_Add_Files_triggered(); + private: Ui::MainWindow *ui; EditorList *mEditorList; @@ -615,8 +621,8 @@ private: PCodeSnippetManager mCodeSnippetManager; PTodoParser mTodoParser; PToolsManager mToolsManager; - QFileSystemModel mFileSystemModel; - CustomFileIconProvider mFileIconProvider; + CustomFileSystemModel mFileSystemModel; + CustomFileIconProvider mFileSystemModelIconProvider; OJProblemSetModel mOJProblemSetModel; OJProblemModel mOJProblemModel; int mOJProblemSetNameCounter; diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 7f07ab76..35a5c356 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -229,7 +229,7 @@ - 0 + 2 0 @@ -2774,6 +2774,11 @@ Reset + + + Add Files + + diff --git a/RedPandaIDE/project.cpp b/RedPandaIDE/project.cpp index 2ff7d963..1d166bf5 100644 --- a/RedPandaIDE/project.cpp +++ b/RedPandaIDE/project.cpp @@ -1910,12 +1910,14 @@ ProjectModel::ProjectModel(Project *project, QObject *parent): mProject(project) { mUpdateCount = 0; - mVCSManager = new GitManager(); + mVCSRepository = new GitRepository(""); + mIconProvider = new CustomFileIconProvider(); } ProjectModel::~ProjectModel() { - delete mVCSManager; + delete mVCSRepository; + delete mIconProvider; } void ProjectModel::beginUpdate() @@ -1930,6 +1932,8 @@ void ProjectModel::endUpdate() { mUpdateCount--; if (mUpdateCount==0) { + mVCSRepository->setFolder(mProject->folder()); + mIconProvider->setRootFolder(mProject->folder()); endResetModel(); } } @@ -1990,21 +1994,20 @@ QVariant ProjectModel::data(const QModelIndex &index, int role) const if (role == Qt::DisplayRole) { if (p == mProject->rootNode().get()) { QString branch; - if (mVCSManager->hasRepository(mProject->folder(),branch)) + if (mVCSRepository->hasRepository(branch)) return QString("%1 [%2]").arg(p->text,branch); } return p->text; } else if (role==Qt::EditRole) { return p->text; } else if (role == Qt::DecorationRole) { - CustomFileIconProvider provider; QIcon icon; if (p->unitIndex>=0) { - icon = provider.icon(mProject->units()[p->unitIndex]->fileName()); + icon = mIconProvider->icon(mProject->units()[p->unitIndex]->fileName()); } else { if (p == mProject->rootNode().get()) { QString branch; - if (mVCSManager->hasRepository(mProject->folder(),branch)) + if (mVCSRepository->hasRepository(branch)) icon = pIconsManager->getIcon(IconsManager::FILESYSTEM_GIT); } else { switch(p->folderNodeType) { @@ -2019,7 +2022,7 @@ QVariant ProjectModel::data(const QModelIndex &index, int role) const } } if (icon.isNull()) - icon = provider.icon(QFileIconProvider::Folder); + icon = mIconProvider->icon(QFileIconProvider::Folder); } return icon; } diff --git a/RedPandaIDE/project.h b/RedPandaIDE/project.h index d55477b7..063dc19e 100644 --- a/RedPandaIDE/project.h +++ b/RedPandaIDE/project.h @@ -101,7 +101,8 @@ private: using PProjectUnit = std::shared_ptr; -class GitManager; +class GitRepository; +class CustomFileIconProvider; class ProjectModel : public QAbstractItemModel { Q_OBJECT public: @@ -111,8 +112,9 @@ public: void endUpdate(); private: Project* mProject; - GitManager *mVCSManager; + GitRepository *mVCSRepository; int mUpdateCount; + CustomFileIconProvider* mIconProvider; // QAbstractItemModel interface diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index 6b79d874..d0d7d47c 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -5083,9 +5083,9 @@ void Settings::UI::doLoad() mNewHeaderDialogHeight = intValue("new_header_dialog_height", 300*qApp->desktop()->height()/1080); } -Settings::VCS::VCS(Settings *settings):_Base(settings,SETTING_VCS) +Settings::VCS::VCS(Settings *settings):_Base(settings,SETTING_VCS), + mGitOk(false) { - } void Settings::VCS::doSave() @@ -5095,7 +5095,7 @@ void Settings::VCS::doSave() void Settings::VCS::doLoad() { - mGitPath = stringValue("git_path", ""); + setGitPath(stringValue("git_path", "")); } const QString &Settings::VCS::gitPath() const @@ -5105,5 +5105,54 @@ const QString &Settings::VCS::gitPath() const void Settings::VCS::setGitPath(const QString &newGitPath) { - mGitPath = newGitPath; + if (mGitPath!=newGitPath) { + mGitPath = newGitPath; + validateGit(); + } +} + +void Settings::VCS::validateGit() +{ + mGitOk = false; + QFileInfo fileInfo(mGitPath); + if (!fileInfo.exists()) { + return; + } + QStringList args; + args.append("--version"); + QString output = runAndGetOutput( + fileInfo.fileName(), + fileInfo.absolutePath(), + args); + mGitOk = output.startsWith("git version"); +} + +bool Settings::VCS::gitOk() const +{ + return mGitOk; +} + +void Settings::VCS::detectGitInPath() +{ + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString path = env.value("PATH"); + QStringList pathList = path.split(PATH_SEPARATOR); + QSet searched; + foreach (const QString& s, pathList){ + if (searched.contains(s)) + continue;; + searched.insert(s); + QDir dir(s); + if (dir.exists(GIT_PROGRAM)) { + QString oldPath = mGitPath; + setGitPath(dir.filePath(GIT_PROGRAM)); + if (mGitOk) { + doSave(); + return; + } else { + mGitPath = oldPath; + } + } + + } } diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index d331b159..1b198018 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -887,8 +887,13 @@ public: explicit VCS(Settings *settings); const QString &gitPath() const; void setGitPath(const QString &newGitPath); + bool gitOk() const; + void detectGitInPath(); + private: + void validateGit(); private: QString mGitPath; + bool mGitOk; protected: void doSave() override; void doLoad() override; diff --git a/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp b/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp index 5a8a535f..e3850d49 100644 --- a/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp +++ b/RedPandaIDE/settingsdialog/compilersetoptionwidget.cpp @@ -246,7 +246,7 @@ void CompilerSetOptionWidget::saveCurrentCompilerSet() if (ui->cbEncodingDetails->isVisible()) { pSet->setExecCharset(ui->cbEncodingDetails->currentText()); } else { - pSet->setExecCharset(ui->cbEncoding->currentText()); + pSet->setExecCharset(ui->cbEncoding->currentData().toString()); } //read values in the options widget diff --git a/RedPandaIDE/settingsdialog/toolsgitwidget.cpp b/RedPandaIDE/settingsdialog/toolsgitwidget.cpp index 780ff259..2be01b35 100644 --- a/RedPandaIDE/settingsdialog/toolsgitwidget.cpp +++ b/RedPandaIDE/settingsdialog/toolsgitwidget.cpp @@ -4,6 +4,7 @@ #include "../settings.h" #include "../systemconsts.h" #include "../utils.h" +#include "../mainwindow.h" #include @@ -29,6 +30,7 @@ void ToolsGitWidget::doSave() { pSettings->vcs().setGitPath(ui->txtGitPath->text()); pSettings->vcs().save(); + pMainWindow->applySettings(); } void ToolsGitWidget::updateIcons(const QSize &size) diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index e60b313f..498821d6 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -31,6 +31,7 @@ #define GPROF_PROGRAM "gprof.exe" #define CLEAN_PROGRAM "del /q /f" #define CPP_PROGRAM "cpp.exe" +#define GIT_PROGRAM "git.exe" #elif defined(Q_OS_LINUX) #define GCC_PROGRAM "gcc" #define GPP_PROGRAM "g++" @@ -42,6 +43,7 @@ #define GPROF_PROGRAM "gprof" #define CLEAN_PROGRAM "rm -rf" #define CPP_PROGRAM "cpp" +#define GIT_PROGRAM "git" #else #error "Only support windows and linux now!" #endif diff --git a/RedPandaIDE/utils.cpp b/RedPandaIDE/utils.cpp index 5e6ef97c..4b0bd02e 100644 --- a/RedPandaIDE/utils.cpp +++ b/RedPandaIDE/utils.cpp @@ -1140,3 +1140,5 @@ void copyFolder(const QString &fromDir, const QString &toDir) } } } + + diff --git a/RedPandaIDE/vcs/gitmanager.cpp b/RedPandaIDE/vcs/gitmanager.cpp index 9454887e..c77ae6a5 100644 --- a/RedPandaIDE/vcs/gitmanager.cpp +++ b/RedPandaIDE/vcs/gitmanager.cpp @@ -2,6 +2,7 @@ #include "../utils.h" #include "../settings.h" +#include #include GitManager::GitManager(QObject *parent) : QObject(parent) @@ -16,6 +17,16 @@ void GitManager::createRepository(const QString &folder) QStringList args; args.append("init"); runGit(folder,args); + + QStringList contents; + contents.append(".git"); + contents.append("*.o"); + contents.append("*.exe"); + contents.append("*."); + + QDir dir(folder); + stringsToFile(contents,dir.filePath(".gitignore")); + add(folder,".gitignore"); } bool GitManager::hasRepository(const QString &folder, QString& currentBranch) @@ -50,7 +61,7 @@ bool GitManager::isFileInRepository(const QFileInfo& fileInfo) return output.trimmed() == fileInfo.fileName(); } -bool GitManager::isFileInStaged(const QFileInfo &fileInfo) +bool GitManager::isFileStaged(const QFileInfo &fileInfo) { QStringList args; args.append("diff"); @@ -111,6 +122,23 @@ QStringList GitManager::listFiles(const QString &folder) return textToLines(runGit(folder,args)); } +QStringList GitManager::listStagedFiles(const QString &folder) +{ + QStringList args; + args.append("diff"); + args.append("--staged"); + args.append("--name-only"); + return textToLines(runGit(folder,args)); +} + +QStringList GitManager::listChangedFiles(const QString &folder) +{ + QStringList args; + args.append("diff"); + args.append("--name-only"); + return textToLines(runGit(folder,args)); +} + void GitManager::clone(const QString &folder, const QString &url) { QStringList args; @@ -161,8 +189,15 @@ void GitManager::reset(const QString &folder, const QString &commit, GitResetStr runGit(folder,args); } +bool GitManager::isValid() +{ + return pSettings->vcs().gitOk(); +} + QString GitManager::runGit(const QString& workingFolder, const QStringList &args) { + if (!isValid()) + return ""; QFileInfo fileInfo(pSettings->vcs().gitPath()); if (!fileInfo.exists()) return "fatal: git doesn't exist"; @@ -174,12 +209,98 @@ QString GitManager::runGit(const QString& workingFolder, const QStringList &args fileInfo.absoluteFilePath(), workingFolder, args); + output = escapeUTF8String(output.toUtf8()); emit gitCmdFinished(output); // if (output.startsWith("fatal:")) // throw GitError(output); return output; } +QString GitManager::escapeUTF8String(const QByteArray &rawString) +{ + QByteArray stringValue; + int p = 0; + while (p=rawString.length() || + rawString[p+i]<'0' || rawString[p+i]>'7') + break; + } + bool ok; + unsigned char ch = rawString.mid(p,i).toInt(&ok,8); + stringValue+=ch; + p+=i; + break; + } + } + } else { + if (ch!='\"') + stringValue+=ch; + p++; + } + } + return QString::fromUtf8(stringValue); +} + GitError::GitError(const QString &reason):BaseError(reason) { diff --git a/RedPandaIDE/vcs/gitmanager.h b/RedPandaIDE/vcs/gitmanager.h index 05373d9f..4cf1a204 100644 --- a/RedPandaIDE/vcs/gitmanager.h +++ b/RedPandaIDE/vcs/gitmanager.h @@ -3,6 +3,7 @@ #include #include +#include #include "utils.h" #include "gitrepository.h" @@ -22,7 +23,7 @@ public: bool hasRepository(const QString& folder, QString& currentBranch); bool isFileInRepository(const QFileInfo& fileInfo); - bool isFileInStaged(const QFileInfo& fileInfo); + bool isFileStaged(const QFileInfo& fileInfo); bool isFileChanged(const QFileInfo& fileInfo); void add(const QString& folder, const QString& path); @@ -30,17 +31,23 @@ public: void rename(const QString& folder, const QString& oldName, const QString& newName); void restore(const QString& folder, const QString& path); QStringList listFiles(const QString& folder); + QStringList listStagedFiles(const QString& folder); + QStringList listChangedFiles(const QString& folder); void clone(const QString& folder, const QString& url); void commit(const QString& folder, const QString& message); void revert(const QString& folder); void reset(const QString& folder, const QString& commit, GitResetStrategy strategy); + bool isValid(); + signals: void gitCmdRunning(const QString& gitCmd); void gitCmdFinished(const QString& message); private: QString runGit(const QString& workingFolder, const QStringList& args); + + QString escapeUTF8String(const QByteArray& rawString); private: }; diff --git a/RedPandaIDE/vcs/gitrepository.cpp b/RedPandaIDE/vcs/gitrepository.cpp index 3134c764..f6e6a70e 100644 --- a/RedPandaIDE/vcs/gitrepository.cpp +++ b/RedPandaIDE/vcs/gitrepository.cpp @@ -1,12 +1,17 @@ #include "gitrepository.h" #include "gitmanager.h" -GitRepository::GitRepository(const QString& folder, GitManager *manager, QObject *parent) +GitRepository::GitRepository(const QString& folder, QObject *parent) : QObject{parent}, - mFolder(folder), - mManager(manager) + mInRepository(false) { - Q_ASSERT(manager!=nullptr); + mManager = new GitManager(); + setFolder(folder); +} + +GitRepository::~GitRepository() +{ + delete mManager; } const QString &GitRepository::folder() const @@ -21,7 +26,8 @@ void GitRepository::createRepository() bool GitRepository::hasRepository(QString& currentBranch) { - return mManager->hasRepository(mFolder, currentBranch); + currentBranch = mBranch; + return mInRepository; } void GitRepository::add(const QString &path) @@ -44,12 +50,11 @@ void GitRepository::restore(const QString &path) mManager->restore(mFolder, path); } -QStringList GitRepository::listFiles(bool refresh) +QSet GitRepository::listFiles(bool refresh) { - if (refresh || mFiles.isEmpty()) { - mFiles = mManager->listFiles(mFolder); - } - return mFiles; + if (refresh) + update(); + return mFilesInRepositories; } void GitRepository::clone(const QString &url) @@ -72,18 +77,33 @@ void GitRepository::reset(const QString &commit, GitResetStrategy strategy) mManager->reset(mFolder,commit,strategy); } -GitManager *GitRepository::manager() const -{ - return mManager; -} - -void GitRepository::setManager(GitManager *newManager) -{ - Q_ASSERT(newManager!=nullptr); - mManager = newManager; -} - void GitRepository::setFolder(const QString &newFolder) { mFolder = newFolder; + update(); } + +void GitRepository::update() +{ + if (!mManager->isValid()) { + mInRepository = false; + mBranch = ""; + mFilesInRepositories.clear(); + mChangedFiles.clear(); + mStagedFiles.clear(); + } else { + mInRepository = mManager->hasRepository(mFolder,mBranch); + convertFilesListToSet(mManager->listFiles(mFolder),mFilesInRepositories); + convertFilesListToSet(mManager->listChangedFiles(mFolder),mChangedFiles); + convertFilesListToSet(mManager->listStagedFiles(mFolder),mStagedFiles); + } +} + +void GitRepository::convertFilesListToSet(const QStringList &filesList, QSet &set) +{ + set.clear(); + foreach (const QString& s, filesList) { + set.insert(includeTrailingPathDelimiter(mFolder)+s); + } +} + diff --git a/RedPandaIDE/vcs/gitrepository.h b/RedPandaIDE/vcs/gitrepository.h index 96cf84ab..7b6e1db0 100644 --- a/RedPandaIDE/vcs/gitrepository.h +++ b/RedPandaIDE/vcs/gitrepository.h @@ -1,7 +1,9 @@ #ifndef GITREPOSITORY_H #define GITREPOSITORY_H +#include #include +#include #include enum class GitResetStrategy { @@ -17,34 +19,59 @@ class GitRepository : public QObject { Q_OBJECT public: - explicit GitRepository(const QString& folder, GitManager* manager, QObject *parent = nullptr); + explicit GitRepository(const QString& folder, QObject *parent = nullptr); + ~GitRepository(); const QString &folder() const; void createRepository(); bool hasRepository(QString& currentBranch); + bool isFileInRepository(const QFileInfo& fileInfo) { + return isFileInRepository(fileInfo.absoluteFilePath()); + } + bool isFileInRepository(const QString& filePath) { + return mFilesInRepositories.contains(filePath); + } + bool isFileStaged(const QFileInfo& fileInfo) { + return isFileStaged(fileInfo.absoluteFilePath()); + } + bool isFileStaged(const QString& filePath) { + return mStagedFiles.contains(filePath); + } + bool isFileChanged(const QFileInfo& fileInfo) { + return isFileChanged(fileInfo.absoluteFilePath()); + } + bool isFileChanged(const QString& filePath) { + return mChangedFiles.contains(filePath); + } + void add(const QString& path); void remove(const QString& path); void rename(const QString& oldName, const QString& newName); void restore(const QString& path); - QStringList listFiles(bool refresh); + QSet listFiles(bool refresh); void clone(const QString& url); void commit(const QString& message); void revert(); void reset(const QString& commit, GitResetStrategy strategy); - GitManager *manager() const; - void setManager(GitManager *newManager); void setFolder(const QString &newFolder); + void update(); signals: private: QString mFolder; + bool mInRepository; + QString mBranch; GitManager* mManager; - QStringList mFiles; + QSet mFilesInRepositories; + QSet mChangedFiles; + QSet mStagedFiles; +private: + void convertFilesListToSet(const QStringList& filesList,QSet& set); }; #endif // GITREPOSITORY_H diff --git a/RedPandaIDE/widgets/customfilesystemmodel.cpp b/RedPandaIDE/widgets/customfilesystemmodel.cpp index 34c6fc62..6bf3e517 100644 --- a/RedPandaIDE/widgets/customfilesystemmodel.cpp +++ b/RedPandaIDE/widgets/customfilesystemmodel.cpp @@ -4,10 +4,6 @@ CustomFileSystemModel::CustomFileSystemModel(QObject *parent) : QFileSystemModel(parent) { - mGitManager = new GitManager(this); - mGitRepository = new GitRepository("",mGitManager,mGitManager); - connect(this,&QFileSystemModel::rootPathChanged, - this, &CustomFileSystemModel::onRootPathChanged); } QVariant CustomFileSystemModel::data(const QModelIndex &index, int role) const @@ -15,7 +11,3 @@ QVariant CustomFileSystemModel::data(const QModelIndex &index, int role) const return QFileSystemModel::data(index,role); } -void CustomFileSystemModel::onRootPathChanged(const QString &folder) -{ - mGitRepository->setFolder(folder); -} diff --git a/RedPandaIDE/widgets/customfilesystemmodel.h b/RedPandaIDE/widgets/customfilesystemmodel.h index 04762279..a87730ed 100644 --- a/RedPandaIDE/widgets/customfilesystemmodel.h +++ b/RedPandaIDE/widgets/customfilesystemmodel.h @@ -15,11 +15,6 @@ public: // QAbstractItemModel interface public: QVariant data(const QModelIndex &index, int role) const override; -private slots: - void onRootPathChanged(const QString& folder); -private: - GitRepository *mGitRepository; - GitManager *mGitManager; }; #endif // CUSTOMFILESYSTEMMODEL_H