diff --git a/include/eepp/ui/uitreeview.hpp b/include/eepp/ui/uitreeview.hpp index ec97f270a..acc05ba1b 100644 --- a/include/eepp/ui/uitreeview.hpp +++ b/include/eepp/ui/uitreeview.hpp @@ -130,7 +130,7 @@ class EE_API UITreeView : public UIAbstractTableView { void traverseTree( TreeViewCallback ) const; - mutable std::map mViewMetadata; + mutable UnorderedMap mViewMetadata; virtual size_t getItemCount() const; diff --git a/src/eepp/ui/uitreeview.cpp b/src/eepp/ui/uitreeview.cpp index 84c617126..87451bf36 100644 --- a/src/eepp/ui/uitreeview.cpp +++ b/src/eepp/ui/uitreeview.cpp @@ -280,13 +280,17 @@ UIWidget* UITreeView::updateCell( const int& rowIndex, const ModelIndex& index, UIIcon* icon = getIndexMetadata( index ).open ? mExpandIcon : mContractIcon; Drawable* drawable = icon ? icon->getSize( mExpanderIconSize ) : nullptr; - image->setVisible( true ); - image->setPixelsSize( drawable ? drawable->getPixelsSize() : Sizef( 0, 0 ) ); - image->setDrawable( drawable ); - if ( !mExpandersAsIcons ) { - tcell->setIndentation( tcell->getIndentation() - - image->getPixelsSize().getWidth() - - PixelDensity::dpToPx( image->getLayoutMargin().Right ) ); + if ( drawable == nullptr ) { + image->setVisible( false ); + } else { + image->setVisible( true ); + image->setPixelsSize( drawable ? drawable->getPixelsSize() : Sizef( 0, 0 ) ); + image->setDrawable( drawable ); + if ( !mExpandersAsIcons ) { + tcell->setIndentation( + tcell->getIndentation() - image->getPixelsSize().getWidth() - + PixelDensity::dpToPx( image->getLayoutMargin().Right ) ); + } } } else { image->setVisible( false ); diff --git a/src/tools/ecode/plugins/git/git.cpp b/src/tools/ecode/plugins/git/git.cpp index da199c5ae..b2c712e41 100644 --- a/src/tools/ecode/plugins/git/git.cpp +++ b/src/tools/ecode/plugins/git/git.cpp @@ -263,6 +263,7 @@ std::string Git::inSubModule( const std::string& file, const std::string& projec Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) { static constexpr auto DIFF_CMD = "diff --numstat"; + static constexpr auto DIFF_STAGED_CMD = "diff --numstat --staged"; static constexpr auto STATUS_CMD = "-c color.status=never status -b -u -s"; Status s; std::string buf; @@ -327,11 +328,17 @@ Git::Status Git::status( bool recurseSubmodules, const std::string& projectDir ) parseNumStat(); + git( DIFF_STAGED_CMD, projectDir, buf ); + parseNumStat(); + bool submodules = hasSubmodules( projectDir ); if ( recurseSubmodules && submodules ) { gitSubmodules( DIFF_CMD, projectDir, buf ); parseNumStat(); + + gitSubmodules( DIFF_STAGED_CMD, projectDir, buf ); + parseNumStat(); } bool modifiedSubmodule = false; diff --git a/src/tools/ecode/plugins/git/git.hpp b/src/tools/ecode/plugins/git/git.hpp index 2b5822a91..7563b3e3c 100644 --- a/src/tools/ecode/plugins/git/git.hpp +++ b/src/tools/ecode/plugins/git/git.hpp @@ -65,10 +65,10 @@ class Git { }; enum class GitStatusType { + Staged, + Changed, Untracked, Unmerged, - Changed, - Staged, Ignored, }; diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 7e7e85648..9d3141dcf 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,22 @@ static const char* GIT_NOT_BOLD = "notbold"; static const std::string GIT_TAG = "tag"; static const std::string GIT_REPO = "repo"; +std::string GitPlugin::statusTypeToString( Git::GitStatusType type ) { + switch ( type ) { + case Git::GitStatusType::Untracked: + return i18n( "git_untracked", "Untracked" ); + case Git::GitStatusType::Unmerged: + return i18n( "git_unmerged", "Unmergedd" ); + case Git::GitStatusType::Changed: + return i18n( "git_changed", "Changed" ); + case Git::GitStatusType::Staged: + return i18n( "git_staged", "Staged" ); + case Git::GitStatusType::Ignored: + return i18n( "git_ignored", "Ignored" ); + } + return ""; +} + static size_t hashBranches( const std::vector& branches ) { size_t hash = 0; for ( const auto& branch : branches ) @@ -177,17 +194,64 @@ class GitStatusModel : public Model { return std::make_shared( std::move( status ), gitPlugin ); } + struct RepoStatusType; + struct RepoStatus; + + struct DiffFile : Git::DiffFile { + DiffFile( Git::DiffFile&& df, RepoStatusType* parent ) : + Git::DiffFile( df ), parent( parent ){}; + RepoStatusType* parent; + }; + + struct RepoStatusType { + std::string typeStr; + Git::GitStatusType type; + std::vector files; + RepoStatus* parent{ nullptr }; + }; + struct RepoStatus { std::string repo; - std::vector files; + std::vector type; }; enum Column { File, State, Inserted, Removed, RelativeDirectory }; GitStatusModel( Git::FilesStatus&& status, GitPlugin* gitPlugin ) : mPlugin( gitPlugin ) { - mStatus.reserve( status.size() ); + std::map> typesFound; + std::unordered_map repoPos; + std::unordered_map> repoTypePos; + for ( auto& s : status ) - mStatus.emplace_back( RepoStatus{ std::move( s.first ), std::move( s.second ) } ); + for ( auto& f : s.second ) + typesFound[s.first].insert( f.statusType ); + + for ( const auto& tf : typesFound ) { + RepoStatus rs; + rs.repo = tf.first; + size_t pos = mStatus.size(); + repoPos[rs.repo] = pos; + for ( const auto& s : tf.second ) { + RepoStatusType rt; + rt.typeStr = mPlugin->statusTypeToString( s ); + rt.type = s; + repoTypePos[pos][s] = rs.type.size(); + rs.type.emplace_back( std::move( rt ) ); + } + mStatus.emplace_back( std::move( rs ) ); + auto parent = &mStatus[mStatus.size() - 1]; + for ( auto& t : parent->type ) + t.parent = parent; + } + + for ( auto& s : status ) { + for ( auto& fv : s.second ) { + auto pos = repoPos[s.first]; + auto typePos = repoTypePos[pos][fv.statusType]; + DiffFile df( std::move( fv ), &mStatus[pos].type[typePos] ); + mStatus[pos].type[typePos].files.emplace_back( std::move( df ) ); + } + } } size_t treeColumn() const { return Column::File; } @@ -195,38 +259,88 @@ class GitStatusModel : public Model { size_t rowCount( const ModelIndex& index ) const { if ( !index.isValid() ) return mStatus.size(); - if ( index.internalId() == -1 ) - return mStatus[index.row()].files.size(); + + if ( index.internalId() == Repo ) + return mStatus[index.row()].type.size(); + + if ( index.internalId() == Status ) + return mStatus[index.parent().row()].type[index.row()].files.size(); + return 0; } size_t columnCount( const ModelIndex& ) const { return 5; } ModelIndex parentIndex( const ModelIndex& index ) const { - if ( !index.isValid() || index.internalId() == -1 ) + if ( !index.isValid() || index.internalId() == Repo ) return {}; - return createIndex( index.internalId(), index.column(), &mStatus[index.internalId()], -1 ); + + if ( index.internalId() == Status ) { + RepoStatusType* status = reinterpret_cast( index.internalData() ); + size_t f = 0; + for ( size_t i = 0; i < mStatus.size(); i++ ) { + if ( &mStatus[i] == status->parent ) { + f = i; + break; + } + } + return createIndex( f, index.column(), status->parent, Repo ); + } + + if ( index.internalId() == GitFile ) { + DiffFile* file = reinterpret_cast( index.internalData() ); + RepoStatusType* status = file->parent; + size_t f = 0; + for ( size_t i = 0; i < status->parent->type.size(); i++ ) { + if ( &status->parent->type[i] == status ) { + f = i; + break; + } + } + return createIndex( f, index.column(), status, Status ); + } + + return {}; } + enum ModelCategory { Repo, Status, GitFile }; + ModelIndex index( int row, int column, const ModelIndex& parent ) const { if ( row < 0 || column < 0 ) return {}; + if ( !parent.isValid() ) - return createIndex( row, column, &mStatus[row], -1 ); - if ( parent.internalData() ) - return createIndex( row, column, &mStatus[parent.row()].files[row], parent.row() ); + return createIndex( row, column, &mStatus[row], Repo ); + + if ( parent.internalId() == Repo ) + return createIndex( row, column, &mStatus[parent.row()].type[row], Status ); + + if ( parent.internalId() == Status ) { + size_t pprow = parent.parent().row(); + size_t prow = parent.row(); + return createIndex( row, column, &mStatus[pprow].type[prow].files[row], GitFile ); + } + return {}; } Variant data( const ModelIndex& index, ModelRole role ) const { switch ( role ) { case ModelRole::Display: { - if ( index.internalId() == -1 ) { + if ( index.internalId() == Repo ) { if ( index.column() == Column::File ) return Variant( mStatus[index.row()].repo.c_str() ); return Variant( GIT_EMPTY ); + } else if ( index.internalId() == Status ) { + if ( index.column() == Column::File ) { + return Variant( + mStatus[index.parent().row()].type[index.row()].typeStr.c_str() ); + } + return Variant( GIT_EMPTY ); } - const Git::DiffFile& s = mStatus[index.internalId()].files[index.row()]; + const Git::DiffFile& s = mStatus[index.parent().parent().row()] + .type[index.parent().row()] + .files[index.row()]; switch ( index.column() ) { case Column::File: return Variant( FileSystem::fileNameFromPath( s.file ) ); @@ -242,7 +356,7 @@ class GitStatusModel : public Model { break; } case ModelRole::Class: { - if ( index.internalId() != -1 ) { + if ( index.internalId() == GitFile ) { switch ( index.column() ) { case Column::Inserted: return Variant( GIT_SUCCESS ); @@ -254,6 +368,26 @@ class GitStatusModel : public Model { } break; } + case ModelRole::Icon: { + if ( (Int64)treeColumn() == index.column() ) { + if ( index.internalId() == Repo ) { + return Variant( + mPlugin->getManager()->getUISceneNode()->findIcon( "repo" ) ); + } else if ( index.internalId() == GitFile ) { + const Git::DiffFile& s = mStatus[index.parent().parent().row()] + .type[index.parent().row()] + .files[index.row()]; + std::string iconName = + UIIconThemeManager::getIconNameFromFileName( s.file ); + auto* scene = mPlugin->getUISceneNode(); + auto* d = scene->findIcon( iconName ); + if ( !d ) + return scene->findIcon( "file" ); + return d; + } + } + break; + } default: break; } @@ -897,7 +1031,6 @@ void GitPlugin::buildSidePanelTab() { mStatusTree->setAutoColumnsWidth( true ); mStatusTree->setHeadersVisible( false ); - mStatusTree->setIndentWidth( 0 ); } } // namespace ecode diff --git a/src/tools/ecode/plugins/git/gitplugin.hpp b/src/tools/ecode/plugins/git/gitplugin.hpp index f738262cb..3945c0c23 100644 --- a/src/tools/ecode/plugins/git/gitplugin.hpp +++ b/src/tools/ecode/plugins/git/gitplugin.hpp @@ -56,6 +56,8 @@ class GitPlugin : public PluginBase { std::string gitBranch(); + std::string statusTypeToString( Git::GitStatusType type ); + protected: std::unique_ptr mGit; std::string mGitBranch;