30#include <wx/stdpaths.h>
33#include <wx/textdlg.h>
52#include <wx/dcclient.h>
53#include <wx/settings.h>
99 wxT(
"^.*\\.kicad_pro$" ),
102 wxT(
"^.*\\.kicad_sch$" ),
103 wxT(
"^[^$].*\\.brd$" ),
104 wxT(
"^[^$].*\\.kicad_pcb$" ),
105 wxT(
"^[^$].*\\.kicad_dru$" ),
106 wxT(
"^[^$].*\\.kicad_wks$" ),
107 wxT(
"^[^$].*\\.kicad_mod$" ),
111 wxT(
"^.*\\.kicad_sym$" ),
116 wxT(
"^.*\\.gbrjob$" ),
117 wxT(
"^.*\\.gb[alops]$" ),
118 wxT(
"^.*\\.gt[alops]$" ),
119 wxT(
"^.*\\.g[0-9]{1,2}$" ),
120 wxT(
"^.*\\.gm[0-9]{1,2}$" ),
124 wxT(
"^.*\\.html$" ),
179 wxSashLayoutWindow( parent,
ID_LEFT_FRAME, wxDefaultPosition, wxDefaultSize,
180 wxNO_BORDER | wxTAB_TRAVERSAL )
183 m_TreeProject =
nullptr;
184 m_isRenaming =
false;
185 m_selectedItem =
nullptr;
186 m_watcherNeedReset =
false;
187 m_lastGitStatusUpdate = wxDateTime::Now();
188 m_gitLastError = GIT_ERROR_NONE;
191 Connect( wxEVT_FSWATCHER,
194 Bind( wxEVT_SYS_COLOUR_CHANGED,
204 m_filters.emplace_back( wxT(
"^no KiCad files found" ) );
233 if( tree_data.size() != 1 )
236 wxString prj_filename = tree_data[0]->GetFileName();
250 wxString curr_dir = item_data->GetDir();
252 if( curr_dir.IsEmpty() )
258 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
261 if( !curr_dir.IsEmpty() )
262 curr_dir += wxFileName::GetPathSeparator();
280 wxString curr_dir = item_data->GetDir();
282 if( curr_dir.IsEmpty() )
285 wxString new_dir = wxGetTextFromUser(
_(
"Directory name:" ),
_(
"Create New Directory" ) );
287 if( new_dir.IsEmpty() )
290 wxString full_dirname = curr_dir + wxFileName::GetPathSeparator() + new_dir;
292 if( !wxMkdir( full_dirname ) )
322 case TREE_FILE_TYPE::DRILL_NC:
return "nc";
323 case TREE_FILE_TYPE::DRILL_XNC:
return "xnc";
332 case TREE_FILE_TYPE::ROOT:
333 case TREE_FILE_TYPE::UNKNOWN:
334 case TREE_FILE_TYPE::MAX:
335 case TREE_FILE_TYPE::DIRECTORY:
break;
338 return wxEmptyString;
344 std::vector<wxString> projects;
345 wxString dir_filename;
346 bool haveFile = dir.GetFirst( &dir_filename );
350 wxFileName file( dir_filename );
354 projects.push_back( file.GetName() );
356 haveFile = dir.GetNext( &dir_filename );
364 git_repository* repo =
nullptr;
368 if( git_repository_discover( &repo_path, filename, 0, NULL ) )
371 printf(
"get_git_repository_for_file: %s\n", git_error_last()->message ); fflush( 0 );
376 if( git_repository_open( &repo, repo_path.ptr ) )
378 git_buf_free( &repo_path );
383 git_buf_free( &repo_path );
390 const wxTreeItemId& aParent,
391 std::vector<wxString>* aProjectNames,
395 wxFileName fn( aName );
398 return wxTreeItemId();
400 if( wxDirExists( aName ) )
402 type = TREE_FILE_TYPE::DIRECTORY;
408 bool addFile =
false;
410 for(
const wxString& m_filter :
m_filters )
412 wxCHECK2_MSG( reg.Compile( m_filter, wxRE_ICASE ),
continue,
413 wxString::Format(
"Regex %s failed to compile.", m_filter ) );
415 if( reg.Matches( aName ) )
423 return wxTreeItemId();
425 for(
int i =
static_cast<int>( TREE_FILE_TYPE::LEGACY_PROJECT );
426 i < static_cast<int>( TREE_FILE_TYPE::MAX ); i++ )
430 if( ext == wxT(
"" ) )
433 if( reg.Compile( wxString::FromAscii(
"^.*\\." ) + ext + wxString::FromAscii(
"$" ),
434 wxRE_ICASE ) && reg.Matches( aName ) )
442 wxString file = wxFileNameFromPath( aName );
443 wxFileName currfile( file );
447 if( ( type == TREE_FILE_TYPE::LEGACY_PROJECT )
448 && ( currfile.GetName().CmpNoCase(
project.GetName() ) == 0 ) )
450 return wxTreeItemId();
453 if( currfile.GetExt() ==
GetFileExt( TREE_FILE_TYPE::LEGACY_SCHEMATIC )
454 || currfile.GetExt() ==
GetFileExt( TREE_FILE_TYPE::SEXPR_SCHEMATIC ) )
459 return wxTreeItemId();
464 wxDir parentDir( parentTreeItem->
GetDir() );
465 std::vector<wxString> projects =
getProjects( parentDir );
468 return wxTreeItemId();
473 wxTreeItemIdValue cookie;
474 wxTreeItemId kid =
m_TreeProject->GetFirstChild( aParent, cookie );
481 return itemData->GetId();
487 if( type == TREE_FILE_TYPE::LEGACY_PROJECT || type == TREE_FILE_TYPE::JSON_PROJECT
488 || type == TREE_FILE_TYPE::LEGACY_SCHEMATIC || type == TREE_FILE_TYPE::SEXPR_SCHEMATIC )
500 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
504 case TREE_FILE_TYPE::LEGACY_PROJECT:
505 if( itemData->
GetType() == TREE_FILE_TYPE::JSON_PROJECT )
506 return wxTreeItemId();
510 case TREE_FILE_TYPE::LEGACY_SCHEMATIC:
511 if( itemData->
GetType() == TREE_FILE_TYPE::SEXPR_SCHEMATIC )
512 return wxTreeItemId();
516 case TREE_FILE_TYPE::JSON_PROJECT:
517 if( itemData->
GetType() == TREE_FILE_TYPE::LEGACY_PROJECT )
522 case TREE_FILE_TYPE::SEXPR_SCHEMATIC:
523 if( itemData->
GetType() == TREE_FILE_TYPE::LEGACY_SCHEMATIC )
539 wxTreeItemId newItemId =
m_TreeProject->AppendItem( aParent, file );
546 wxString fileName = currfile.GetName().Lower();
547 wxString projName =
project.GetName().Lower();
549 if( fileName == projName || fileName.StartsWith( projName +
"-" ) )
553 bool subdir_populated =
false;
558 if( TREE_FILE_TYPE::DIRECTORY == type && aRecurse )
564 std::vector<wxString> projects =
getProjects( dir );
565 wxString dir_filename;
566 bool haveFile = dir.GetFirst( &dir_filename );
571 subdir_populated = aRecurse;
577 wxString
path = aName + wxFileName::GetPathSeparator() + dir_filename;
580 haveFile = dir.GetNext( &dir_filename );
589 if( subdir_populated )
615 wxFileName fn = pro_dir;
616 bool prjReset =
false;
627 bool prjOpened = fn.FileExists();
639 if( conn_type ==
"https" )
641 else if( conn_type ==
"ssh" )
649 if( !prjOpened && !prjReset )
652 prjOpened = fn.FileExists();
659 m_root =
m_TreeProject->AddRoot( fn.GetFullName(),
static_cast<int>( TREE_FILE_TYPE::ROOT ),
660 static_cast<int>( TREE_FILE_TYPE::ROOT ) );
673 wxDir dir( pro_dir );
677 std::vector<wxString> projects =
getProjects( dir );
679 bool haveFile = dir.GetFirst( &filename );
683 if( filename != fn.GetFullName() )
685 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
691 haveFile = dir.GetNext( &filename );
715 git_status_options opts = GIT_STATUS_OPTIONS_INIT;
717 opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
718 opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
719 | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
721 git_status_list* status_list =
nullptr;
722 int error = git_status_list_new( &status_list, repo, &opts );
724 if( error != GIT_OK )
727 bool has_changed_files = git_status_list_entrycount( status_list ) > 0;
728 git_status_list_free( status_list );
729 return has_changed_files;
735 wxTreeItemId curr_item = Event.GetItem();
742 bool can_switch_to_project =
true;
743 bool can_create_new_directory =
true;
744 bool can_open_this_directory =
true;
745 bool can_edit =
true;
746 bool can_rename =
true;
747 bool can_delete =
true;
751 bool vcs_can_init = !vcs_has_repo;
752 bool vcs_can_remove = vcs_has_repo;
755 bool vcs_can_pull = vcs_can_fetch;
756 bool vcs_can_switch = vcs_has_repo;
760#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 )
761 int major, minor, rev;
762 bool libgit_init = ( git_libgit2_version( &major, &minor, &rev ) == GIT_OK );
765 bool libgit_init =
true;
768 vcs_menu &= libgit_init;
770 if( selection.size() == 0 )
774 if( selection.size() != 1 )
776 can_switch_to_project =
false;
777 can_create_new_directory =
false;
786 can_switch_to_project =
false;
792 can_delete = item->CanDelete();
793 can_rename = item->CanRename();
795 switch( item->GetType() )
797 case TREE_FILE_TYPE::JSON_PROJECT:
798 case TREE_FILE_TYPE::LEGACY_PROJECT:
803 can_switch_to_project =
false;
807 can_create_new_directory =
false;
808 can_open_this_directory =
false;
812 case TREE_FILE_TYPE::DIRECTORY:
813 can_switch_to_project =
false;
817 case TREE_FILE_TYPE::SEXPR_SCHEMATIC:
818 case TREE_FILE_TYPE::SEXPR_PCB:
822 can_switch_to_project =
false;
823 can_create_new_directory =
false;
824 can_open_this_directory =
false;
834 if( can_switch_to_project )
837 _(
"Close all editors, and switch to the selected project" ),
838 KiBitmap( BITMAPS::open_project ) );
839 popup_menu.AppendSeparator();
842 if( can_create_new_directory )
845 _(
"Create a New Directory" ),
KiBitmap( BITMAPS::directory ) );
848 if( can_open_this_directory )
850 if( selection.size() == 1 )
853 text =
_(
"Reveal in Finder" );
854 help_text =
_(
"Reveals the directory in a Finder window" );
856 text =
_(
"Open Directory in File Explorer" );
857 help_text =
_(
"Opens the directory in the default system file manager" );
863 text =
_(
"Reveal in Finder" );
864 help_text =
_(
"Reveals the directories in a Finder window" );
866 text =
_(
"Open Directories in File Explorer" );
867 help_text =
_(
"Opens the directories in the default system file manager" );
872 KiBitmap( BITMAPS::directory_browser ) );
877 if( selection.size() == 1 )
878 help_text =
_(
"Open the file in a Text Editor" );
880 help_text =
_(
"Open files in a Text Editor" );
888 if( selection.size() == 1 )
890 text =
_(
"Rename File..." );
891 help_text =
_(
"Rename file" );
895 text =
_(
"Rename Files..." );
896 help_text =
_(
"Rename files" );
905 if( selection.size() == 1 )
906 help_text =
_(
"Delete the file and its content" );
908 help_text =
_(
"Delete the files and their contents" );
910 if( can_switch_to_project
911 || can_create_new_directory
912 || can_open_this_directory
916 popup_menu.AppendSeparator();
930 wxMenu* vcs_submenu =
new wxMenu();
931 wxMenu* branch_submenu =
new wxMenu();
932 wxMenuItem* vcs_menuitem =
nullptr;
935 _(
"Add Project to Version Control..." ),
936 _(
"Initialize a new repository" ) );
937 vcs_menuitem->Enable( vcs_can_init );
941 _(
"Commit changes to the local repository" ) );
942 vcs_menuitem->Enable( vcs_can_commit );
944 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PUSH,
_(
"Push" ),
945 _(
"Push committed local changes to remote repository" ) );
946 vcs_menuitem->Enable( vcs_can_push );
948 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PULL,
_(
"Pull" ),
949 _(
"Pull changes from remote repository into local" ) );
950 vcs_menuitem->Enable( vcs_can_pull );
952 vcs_submenu->AppendSeparator();
955 _(
"Commit changes to the local repository" ) );
956 vcs_menuitem->Enable( vcs_can_commit );
958 vcs_submenu->AppendSeparator();
967 for(
size_t ii = 1; ii < branchNames.size() && ii < 6; ++ii )
969 wxString msg =
_(
"Switch to branch " ) + branchNames[ii];
971 vcs_menuitem->Enable( vcs_can_switch );
975 _(
"Switch to a different branch" ) );
976 vcs_menuitem->Enable( vcs_can_switch );
980 vcs_submenu->AppendSeparator();
983 _(
"Delete all version control files from the project directory." ) );
984 vcs_menuitem->Enable( vcs_can_remove );
986 popup_menu.AppendSeparator();
987 popup_menu.AppendSubMenu( vcs_submenu,
_(
"Version Control" ) );
990 if( popup_menu.GetMenuItemCount() > 0 )
991 PopupMenu( &popup_menu );
999 if( editorname.IsEmpty() )
1001 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
1009 wxString fullFileName = item_data->GetFileName();
1011 if( !fullFileName.IsEmpty() )
1013 ExecuteFile( editorname, fullFileName.wc_str(),
nullptr,
false );
1024 item_data->Delete();
1034 if( tree_data.size() != 1 )
1038 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
1039 tree_data[0]->GetFileName() );
1040 wxTextEntryDialog dlg( wxGetTopLevelParent(
this ), msg,
_(
"Change filename" ), buffer );
1042 if( dlg.ShowModal() != wxID_OK )
1045 buffer = dlg.GetValue();
1046 buffer.Trim(
true );
1047 buffer.Trim(
false );
1049 if( buffer.IsEmpty() )
1052 tree_data[0]->Rename( buffer,
true );
1061 if( tree_data.size() != 1 )
1098 wxTreeItemId itemId = Event.GetItem();
1104 if( tree_data->
GetType() != TREE_FILE_TYPE::DIRECTORY )
1108 wxTreeItemIdValue cookie;
1109 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
1112 bool subdir_populated =
false;
1115 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
1119 if( !itemData || itemData->
GetType() != TREE_FILE_TYPE::DIRECTORY )
1126 wxDir dir( fileName );
1128 if( dir.IsOpened() )
1130 std::vector<wxString> projects =
getProjects( dir );
1131 wxString dir_filename;
1132 bool haveFile = dir.GetFirst( &dir_filename );
1137 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
1140 haveFile = dir.GetNext( &dir_filename );
1146 subdir_populated =
true;
1155 if( subdir_populated )
1163 wxArrayTreeItemIds selection;
1164 std::vector<PROJECT_TREE_ITEM*> data;
1168 for(
auto it = selection.begin(); it != selection.end(); it++ )
1173 wxLogDebug(
"Null tree item returned for selection, dynamic_cast failed?" );
1177 data.push_back( item );
1196 if( prj_dir == aSubDir )
1200 wxTreeItemIdValue cookie;
1201 wxTreeItemId root_id =
m_root;
1202 std::stack<wxTreeItemId> subdirs_id;
1204 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
1208 if( ! child.IsOk() )
1210 if( subdirs_id.empty() )
1217 root_id = subdirs_id.top();
1228 if( itemData && ( itemData->
GetType() == TREE_FILE_TYPE::DIRECTORY ) )
1238 subdirs_id.push( child );
1254 const wxFileName& pathModified =
event.GetPath();
1255 wxString subdir = pathModified.GetPath();
1256 wxString fn = pathModified.GetFullPath();
1258 switch( event.GetChangeType() )
1260 case wxFSW_EVENT_DELETE:
1261 case wxFSW_EVENT_CREATE:
1262 case wxFSW_EVENT_RENAME:
1266 case wxFSW_EVENT_MODIFY:
1269 case wxFSW_EVENT_ACCESS:
1276 if( !root_id.IsOk() )
1279 wxTreeItemIdValue cookie;
1280 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1282 switch( event.GetChangeType() )
1284 case wxFSW_EVENT_CREATE:
1286 wxTreeItemId newitem =
1300 case wxFSW_EVENT_DELETE:
1314 case wxFSW_EVENT_RENAME :
1316 const wxFileName& newpath =
event.GetNewPath();
1317 wxString newdir = newpath.GetPath();
1318 wxString newfn = newpath.GetFullPath();
1342 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1348 if( newitem.IsOk() )
1368#if defined( _WIN32 )
1401 fn.AssignDir( prj_dir );
1402 fn.DontFollowLink();
1419 wxTreeItemIdValue cookie;
1420 wxTreeItemId root_id =
m_root;
1422 std::stack < wxTreeItemId > subdirs_id;
1424 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1430 if( subdirs_id.empty() )
1436 root_id = subdirs_id.top();
1447 if( itemData && itemData->
GetType() == TREE_FILE_TYPE::DIRECTORY )
1454 if( wxFileName::IsDirReadable(
path ) )
1456 fn.AssignDir(
path );
1461 subdirs_id.push( kid );
1469#if defined(DEBUG) && 1
1470 wxArrayString paths;
1474 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1508 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1509 wxPaintDC dc(
this );
1511 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1512 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1514 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1515 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1529 wxString dir = tree_data->
GetDir();
1533 wxLogError(
"Failed to initialize git project: project directory is empty." );
1538 git_repository* repo =
nullptr;
1539 int error = git_repository_open(&repo, dir.mb_str());
1544 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1547 _(
"The selected directory is already a git project." ) );
1548 git_repository_free( repo );
1554 error = git_repository_init( &repo, dir.mb_str(), 0 );
1558 git_repository_free( repo );
1564 git_error_last()->message );
1578 dlg.SetTitle(
_(
"Set default remote" ) );
1580 if( dlg.ShowModal() != wxID_OK )
1590 git_remote* remote =
nullptr;
1599 fullURL = dlg.
GetRepoURL().StartsWith(
"https" ) ?
"https://" :
"http://";
1607 fullURL.append( wxS(
":" ) );
1611 fullURL.append( wxS(
"@" ) );
1622 error = git_remote_create_with_fetchspec( &remote, repo,
"origin",
1623 fullURL.ToStdString().c_str(),
1624 "+refs/heads/*:refs/remotes/origin/*" );
1626 if( error != GIT_OK )
1632 git_error_last()->message );
1648 _(
"Fetching Remote" ),
1687 _(
"Fetching Remote" ),
1709 _(
"Fetching Remote" ),
1712 if( handler.
PerformPush() != PushResult::Success )
1725 if(
int error = git_reference_name_to_id( &head_oid, aRepo,
"HEAD" ) != 0 )
1727 wxLogError(
"Failed to lookup HEAD reference" );
1732 git_commit* commit =
nullptr;
1733 if(
int error = git_commit_lookup( &commit, aRepo, &head_oid ) != GIT_OK )
1735 wxLogError(
"Failed to lookup commit" );
1739 git_reference* branchRef =
nullptr;
1741 if( git_branch_create( &branchRef, aRepo, aBranchName.mb_str(), commit, 0 ) != 0 )
1743 wxLogError(
"Failed to create branch" );
1744 git_commit_free( commit );
1748 git_commit_free( commit );
1749 git_reference_free( branchRef );
1764 int retval = dlg.ShowModal();
1767 if( retval == wxID_ADD )
1769 else if( retval != wxID_OK )
1773 git_reference* branchRef =
nullptr;
1775 if( git_reference_lookup( &branchRef, repo, branchName.mb_str() ) != GIT_OK &&
1776 git_reference_dwim( &branchRef, repo, branchName.mb_str() ) != GIT_OK )
1778 wxString errorMessage = wxString::Format(
_(
"Failed to lookup branch '%s': %s" ),
1779 branchName, giterr_last()->message );
1784 const char* branchRefName = git_reference_name( branchRef );
1786 git_object* branchObj =
nullptr;
1788 if( git_revparse_single( &branchObj, repo, branchName.mb_str() ) != 0 )
1790 wxString errorMessage =
1791 wxString::Format(
_(
"Failed to find branch head for '%s'" ), branchName );
1793 git_reference_free( branchRef );
1799 if( git_checkout_tree( repo, branchObj,
nullptr ) != 0 )
1801 wxString errorMessage =
1802 wxString::Format(
_(
"Failed to switch to branch '%s'" ), branchName );
1804 git_reference_free( branchRef );
1805 git_object_free( branchObj );
1810 if( git_repository_set_head( repo, branchRefName ) != 0 )
1812 wxString errorMessage = wxString::Format(
1813 _(
"Failed to update HEAD reference for branch '%s'" ), branchName );
1815 git_reference_free( branchRef );
1816 git_object_free( branchObj );
1821 git_reference_free( branchRef );
1822 git_object_free( branchObj );
1831 || !
IsOK( wxGetTopLevelParent(
this ),
1832 _(
"Are you sure you want to remove git tracking from this project?" ) ) )
1838 git_repository_free( repo );
1843 fn.AppendDir(
".git" );
1853 std::stack<wxTreeItemId> items;
1856 while( !items.empty() )
1858 wxTreeItemId current = items.top();
1862 m_TreeProject->SetItemState( current, wxTREE_ITEMSTATE_NONE );
1864 wxTreeItemIdValue cookie;
1865 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
1867 while( child.IsOk() )
1869 items.push( child );
1886 if( timeSinceLastUpdate.Abs() < wxTimeSpan::Seconds( 2 ) )
1903 git_reference* currentBranchReference =
nullptr;
1904 git_repository_head( ¤tBranchReference, repo );
1907 if( currentBranchReference )
1910 wxString filename = wxFileNameFromPath( rootItem->
GetFileName() );
1911 wxString branchName = git_reference_shorthand( currentBranchReference );
1913 m_TreeProject->SetItemText( kid, filename +
" [" + branchName +
"]" );
1914 git_reference_free( currentBranchReference );
1919 wxLogError(
"Failed to lookup current branch: %s", giterr_last()->message );
1925 std::map<wxString, wxTreeItemId> branchMap;
1927 std::stack<wxTreeItemId> items;
1930 while( !items.empty() )
1939 wxTreeItemIdValue cookie;
1940 wxTreeItemId child =
m_TreeProject->GetFirstChild( kid, cookie );
1942 while( child.IsOk() )
1944 items.push( child );
1950 git_status_options status_options = GIT_STATUS_OPTIONS_INIT;
1951 status_options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
1952 status_options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
1954 git_index* index =
nullptr;
1956 if( git_repository_index( &index, repo ) != GIT_OK )
1959 wxLogDebug(
"Failed to get git index: %s", giterr_last()->message );
1963 git_status_list* status_list =
nullptr;
1965 if( git_status_list_new( &status_list, repo, &status_options ) != GIT_OK )
1967 wxLogDebug(
"Failed to get git status list: %s", giterr_last()->message );
1968 git_index_free( index );
1974 size_t count = git_status_list_entrycount( status_list );
1976 for(
size_t ii = 0; ii < count; ++ii )
1978 const git_status_entry* entry = git_status_byindex( status_list, ii );
1979 std::string
path( entry->head_to_index? entry->head_to_index->old_file.path
1980 : entry->index_to_workdir->old_file.path );
1981 wxFileName fn(
path );
1982 fn.MakeAbsolute( git_repository_workdir( repo ) );
1984 auto iter = branchMap.find( fn.GetFullPath() );
1986 if( iter == branchMap.end() )
1992 if( entry->status == GIT_STATUS_CURRENT )
1998 else if( entry->status & ( GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED ) )
2005 else if( entry->status & ( GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_NEW ) )
2012 else if( entry->status & ( GIT_STATUS_INDEX_DELETED | GIT_STATUS_WT_DELETED ) )
2021 if( localChanges.count(
path ) )
2028 else if( remoteChanges.count(
path ) )
2044 git_status_list_free( status_list );
2045 git_index_free( index );
2055 if( repo ==
nullptr )
2057 wxMessageBox(
"The selected directory is not a git project." );
2061 git_config*
config =
nullptr;
2062 git_repository_config( &
config, repo );
2065 wxString authorName;
2066 wxString authorEmail;
2069 git_config_entry* name_c =
nullptr;
2070 git_config_entry* email_c =
nullptr;
2071 int authorNameError = git_config_get_entry( &name_c,
config,
"user.name" );
2073 if( authorNameError != 0 || name_c ==
nullptr )
2079 authorName = name_c->value;
2080 git_config_entry_free( name_c );
2084 int authorEmailError = git_config_get_entry( &email_c,
config,
"user.email" );
2086 if( authorEmailError != 0 || email_c ==
nullptr )
2092 authorEmail = email_c->value;
2093 git_config_entry_free( email_c );
2097 git_config_free(
config );
2100 git_status_options status_options = GIT_STATUS_OPTIONS_INIT;
2101 status_options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
2102 status_options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED;
2104 git_status_list* status_list =
nullptr;
2105 git_status_list_new( &status_list, repo, &status_options );
2107 std::map<wxString, int> modifiedFiles;
2109 size_t count = git_status_list_entrycount( status_list );
2111 std::set<wxString> selected_files;
2115 if( item->GetType() != TREE_FILE_TYPE::DIRECTORY )
2116 selected_files.emplace( item->GetFileName() );
2119 for(
size_t i = 0; i < count; ++i )
2121 const git_status_entry* entry = git_status_byindex( status_list, i );
2124 if( entry->status == GIT_STATUS_CURRENT
2125 || ( entry->status & ( GIT_STATUS_CONFLICTED | GIT_STATUS_IGNORED ) ) )
2130 wxFileName fn( entry->index_to_workdir->old_file.path );
2131 fn.MakeAbsolute( git_repository_workdir( repo ) );
2133 wxString filePath( entry->index_to_workdir->old_file.path, wxConvUTF8 );
2137 modifiedFiles.emplace( filePath, entry->status );
2139 else if( selected_files.count( fn.GetFullPath() ) )
2141 modifiedFiles.emplace( filePath, entry->status );
2145 git_status_list_free( status_list );
2148 DIALOG_GIT_COMMIT dlg( wxGetTopLevelParent(
this ), repo, authorName, authorEmail,
2150 auto ret = dlg.ShowModal();
2152 if( ret == wxID_OK )
2156 git_tree* tree =
nullptr;
2157 git_commit* parent =
nullptr;
2158 git_index* index =
nullptr;
2164 wxMessageBox(
_(
"Discarding commit due to empty commit message." ) );
2170 wxMessageBox(
_(
"Discarding commit due to empty file selection." ) );
2174 if( git_repository_index( &index, repo ) != 0 )
2176 wxMessageBox(
_(
"Failed to get repository index: %s" ), giterr_last()->message );
2180 for( wxString& file :files )
2182 if( git_index_add_bypath( index, file.mb_str() ) != 0 )
2184 wxMessageBox(
_(
"Failed to add file to index: %s" ), giterr_last()->message );
2185 git_index_free( index );
2190 if( git_index_write( index ) != 0 )
2192 wxMessageBox(
_(
"Failed to write index: %s" ), giterr_last()->message );
2193 git_index_free( index );
2197 if (git_index_write_tree( &tree_id, index ) != 0)
2199 wxMessageBox(
_(
"Failed to write tree: %s" ), giterr_last()->message );
2200 git_index_free( index );
2204 git_index_free( index );
2206 if( git_tree_lookup( &tree, repo, &tree_id ) != 0 )
2208 wxMessageBox(
_(
"Failed to lookup tree: %s" ), giterr_last()->message );
2212 git_reference* headRef =
nullptr;
2214 if( git_repository_head( &headRef, repo ) != 0 )
2216 wxMessageBox(
_(
"Failed to get HEAD reference: %s" ), giterr_last()->message );
2217 git_index_free( index );
2221 if( git_reference_peel( (git_object**) &parent, headRef, GIT_OBJECT_COMMIT ) != 0 )
2223 wxMessageBox(
_(
"Failed to get commit: %s" ), giterr_last()->message );
2224 git_reference_free( headRef );
2225 git_index_free( index );
2229 git_reference_free( headRef );
2235 git_signature* author =
nullptr;
2237 if( git_signature_now( &author, author_name.mb_str(), author_email.mb_str() ) != 0 )
2239 wxMessageBox(
_(
"Failed to create author signature: %s" ), giterr_last()->message );
2245#if( LIBGIT2_VER_MAJOR > 1 ) || ( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR >= 8 )
2247 git_commit*
const parents[1] = { parent };
2250 const git_commit* parents[1] = { parent };
2253 if( git_commit_create( &oid, repo,
"HEAD", author, author,
nullptr, commit_msg.mb_str(), tree,
2256 wxMessageBox(
_(
"Failed to create commit: %s" ), giterr_last()->message );
2260 git_signature_free( author );
2261 git_commit_free( parent );
2262 git_tree_free( tree );
2282 if( git_repository_index( &index, repo ) != 0 )
2286 if( git_index_find( &entry_pos, index, aFile.mb_str() ) == 0 )
2288 git_index_free( index );
2292 git_index_free( index );
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
BITMAP_STORE * GetBitmapStore()
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void ThemeChanged()
Notifies the store that the icon theme has been changed by the user, so caches must be invalidated.
wxString GetCommitMessage() const
wxString GetAuthorEmail() const
std::vector< wxString > GetSelectedFiles() const
wxString GetAuthorName() const
KIGIT_COMMON::GIT_CONN_TYPE GetRepoType() const
wxString GetBareRepoURL() const
Get the Bare Repo U R L object.
wxString GetRepoSSHPath() const
wxString GetRepoURL() const
wxString GetUsername() const
wxString GetPassword() const
wxString GetBranchName() const
void SetProgressReporter(std::unique_ptr< WX_PROGRESS_REPORTER > aProgressReporter)
void PerformRemoveFromIndex()
bool PerformResolveConflict()
The main KiCad project manager frame.
wxString m_FileWatcherInfo
PROJECT_TREE_PANE * m_leftWin
const wxString GetProjectFileName() const
void OnChangeWatchedPaths(wxCommandEvent &aEvent)
Called by sending a event with id = ID_INIT_WATCHED_PATHS rebuild the list of watched paths.
void LoadProject(const wxFileName &aProjectFileName)
std::vector< wxString > GetBranchNames() const
void SetConnType(GIT_CONN_TYPE aConnType)
wxString GetSSHKey() const
void SetSSHKey(const wxString &aSSHKey)
void SetUsername(const wxString &aUsername)
GIT_CONN_TYPE GetConnType() const
wxString GetPassword() const
std::pair< std::set< wxString >, std::set< wxString > > GetDifferentFiles() const
Return a pair of sets of files that differ locally from the remote repository The first set is files ...
bool HasPushAndPullRemote() const
wxString GetUsername() const
bool HasLocalCommits() const
void SetPassword(const wxString &aPassword)
wxString GetErrorString()
KISTATUSBAR is a wxStatusBar suitable for Kicad manager.
void SetEllipsedTextField(const wxString &aText, int aFieldId)
Set the text in a field using wxELLIPSIZE_MIDDLE option to adjust the text size to the field size (un...
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
virtual COMMON_SETTINGS * GetCommonSettings() const
virtual const wxString & GetTextEditor(bool aCanShowFileChooser=true)
Return the path to the preferred text editor application.
wxString m_GitRepoPassword
wxString m_GitRepoUsername
Handle one item (a file or a directory name) for the tree file.
void SetRootFile(bool aValue)
const wxString & GetFileName() const
void SetPopulated(bool aValue)
TREE_FILE_TYPE GetType() const
const wxString GetDir() const
void Activate(PROJECT_TREE_PANE *aTreePrjFrame)
PROJECT_TREE_PANE Window to display the tree files.
PROJECT_TREE_ITEM * m_selectedItem
void onGitFetch(wxCommandEvent &event)
Fetch the latest changes from the git repository.
void onGitInitializeProject(wxCommandEvent &event)
Initialize a new git repository in the current project directory.
void onGitSyncProject(wxCommandEvent &event)
Sync the current project with the git repository.
void onDeleteFile(wxCommandEvent &event)
Function onDeleteFile Delete the selected file or directory in the tree project.
void onGitRemoveVCS(wxCommandEvent &event)
Remove the git repository from the current project directory.
void EmptyTreePrj()
Delete all m_TreeProject entries.
void FileWatcherReset()
Reinit the watched paths Should be called after opening a new project to rebuild the list of watched ...
std::vector< PROJECT_TREE_ITEM * > GetSelectedData()
Function GetSelectedData return the item data from item currently selected (highlighted) Note this is...
void onOpenDirectory(wxCommandEvent &event)
Function onOpenDirectory Handles the right-click menu for opening a directory in the current system f...
void onGitResolveConflict(wxCommandEvent &event)
Resolve conflicts in the git repository.
void onFileSystemEvent(wxFileSystemWatcherEvent &event)
called when a file or directory is modified/created/deleted The tree project is modified when a file ...
wxFileSystemWatcher * m_watcher
wxDateTime m_lastGitStatusUpdate
void onRight(wxTreeEvent &Event)
Called on a right click on an item.
void onGitCommit(wxCommandEvent &event)
Commit the current project saved changes to the git repository.
void onSelect(wxTreeEvent &Event)
Called on a double click on an item.
PROJECT_TREE * m_TreeProject
KICAD_MANAGER_FRAME * m_Parent
void onExpand(wxTreeEvent &Event)
Called on a click on the + or - button of an item with children.
void onIdle(wxIdleEvent &aEvent)
Idle event handler, used process the selected items at a point in time when all other events have bee...
void onGitRevertLocal(wxCommandEvent &event)
Revert the local repository to the last commit.
void onGitPullProject(wxCommandEvent &event)
Pull the latest changes from the git repository.
static wxString GetFileExt(TREE_FILE_TYPE type)
friend class PROJECT_TREE_ITEM
void onGitRemoveFromIndex(wxCommandEvent &event)
Remove a file from the git index.
wxTreeItemId findSubdirTreeItem(const wxString &aSubDir)
Function findSubdirTreeItem searches for the item in tree project which is the node of the subdirecto...
void ReCreateTreePrj()
Create or modify the tree showing project file names.
void onThemeChanged(wxSysColourChangedEvent &aEvent)
void onGitCompare(wxCommandEvent &event)
Compare the current project to a different branch in the git repository.
void shutdownFileWatcher()
Shutdown the file watcher.
wxTreeItemId addItemToProjectTree(const wxString &aName, const wxTreeItemId &aParent, std::vector< wxString > *aProjectNames, bool aRecurse)
Function addItemToProjectTree.
bool hasChangedFiles()
Returns true if the current project has any uncommitted changes.
void onOpenSelectedFileWithTextEditor(wxCommandEvent &event)
Function onOpenSelectedFileWithTextEditor Call the text editor to open the selected file in the tree ...
void onGitAddToIndex(wxCommandEvent &event)
Add a file to the git index.
void updateGitStatusIcons()
Updates the icons shown in the tree project to reflect the current git status.
PROJECT_TREE_ITEM * GetItemIdData(wxTreeItemId aId)
Function GetItemIdData return the item data corresponding to a wxTreeItemId identifier.
void onGitSwitchBranch(wxCommandEvent &event)
Switch to a different branch in the git repository.
void onCreateNewDirectory(wxCommandEvent &event)
Function onCreateNewDirectory Creates a new subdirectory inside the current kicad project directory t...
void onSwitchToSelectedProject(wxCommandEvent &event)
Switch to a other project selected from the tree project (by selecting an other .pro file inside the ...
void onPaint(wxPaintEvent &aEvent)
We don't have uniform borders so we have to draw them ourselves.
void onRenameFile(wxCommandEvent &event)
Function onRenameFile Rename the selected file or directory in the tree project.
void onGitPushProject(wxCommandEvent &event)
Push the current project changes to the git repository.
bool canFileBeAddedToVCS(const wxString &aFilePath)
Returns true if the file has already been added to the repository or false if it has not been added y...
std::vector< wxString > m_filters
PROJECT_TREE This is the class to show (as a tree) the files in the project directory.
git_repository * GetGitRepo() const
KIGIT_COMMON * GitCommon() const
void SetGitRepo(git_repository *aRepo)
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
This file is part of the common library.
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback, bool aFileForKicad)
Call the executable file aEditorName with the parameter aFileName.
bool RmDirRecursive(const wxString &aFileName, wxString *aErrors)
Removes the directory aDirName and all its contents including subdirectories and their files.
bool m_EnableGit
Enable git integration.
static const std::string LegacySchematicFileExtension
static const std::string HtmlFileExtension
static const wxString GerberFileExtensionsRegex
static const std::string NetlistFileExtension
static const std::string GerberJobFileExtension
static const std::string ReportFileExtension
static const std::string ProjectFileExtension
static const std::string FootprintPlaceFileExtension
static const std::string LegacyPcbFileExtension
static const std::string LegacyProjectFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string LegacySymbolLibFileExtension
static const std::string KiCadSymbolLibFileExtension
static const std::string SpiceFileExtension
static const std::string PdfFileExtension
static const std::string TextFileExtension
static const std::string DrawingSheetFileExtension
static const std::string FootprintAssignmentFileExtension
static const std::string SVGFileExtension
static const std::string DrillFileExtension
static const std::string DesignRulesFileExtension
static const std::string MarkdownFileExtension
static const std::string KiCadFootprintFileExtension
static const std::string ArchiveFileExtension
static const std::string KiCadPcbFileExtension
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
IDs used in KiCad main frame foe menuitems and tools.
@ ID_PROJECT_SWITCH_TO_OTHER
@ ID_GIT_REMOVE_FROM_INDEX
@ ID_GIT_RESOLVE_CONFLICT
@ ID_GIT_INITIALIZE_PROJECT
bool LaunchExternal(const wxString &aPath)
Launches the given file or folder in the host OS.
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
KICOMMON_API wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
PGM_BASE & Pgm()
The global Program "get" accessor.
#define NAMELESS_PROJECT
default name for nameless projects
std::vector< wxString > getProjects(const wxDir &dir)
static git_repository * get_git_repository_for_file(const char *filename)
static const wxChar * s_allowedExtensionsToList[]
static int git_create_branch(git_repository *aRepo, wxString &aBranchName)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.