30#include <wx/stdpaths.h>
33#include <wx/textdlg.h>
35#include <wx/wupdlock.h>
55#include <wx/dcclient.h>
56#include <wx/progdlg.h>
57#include <wx/settings.h>
105 wxT(
"^.*\\.kicad_pro$" ),
108 wxT(
"^.*\\.kicad_sch$" ),
109 wxT(
"^[^$].*\\.brd$" ),
110 wxT(
"^[^$].*\\.kicad_pcb$" ),
111 wxT(
"^[^$].*\\.kicad_dru$" ),
112 wxT(
"^[^$].*\\.kicad_wks$" ),
113 wxT(
"^[^$].*\\.kicad_mod$" ),
117 wxT(
"^.*\\.kicad_sym$" ),
122 wxT(
"^.*\\.gbrjob$" ),
123 wxT(
"^.*\\.gb[alops]$" ),
124 wxT(
"^.*\\.gt[alops]$" ),
125 wxT(
"^.*\\.g[0-9]{1,2}$" ),
126 wxT(
"^.*\\.gm[0-9]{1,2}$" ),
130 wxT(
"^.*\\.html$" ),
141 wxT(
"^.*\\.kicad_jobset" ),
223 wxSashLayoutWindow( parent,
ID_LEFT_FRAME, wxDefaultPosition, wxDefaultSize,
224 wxNO_BORDER | wxTAB_TRAVERSAL )
227 m_TreeProject =
nullptr;
228 m_isRenaming =
false;
229 m_selectedItem =
nullptr;
230 m_watcherNeedReset =
false;
231 m_gitLastError = GIT_ERROR_NONE;
233 m_gitIconsInitialized =
false;
235 Bind( wxEVT_FSWATCHER,
238 Bind( wxEVT_SYS_COLOUR_CHANGED,
241 m_gitSyncTimer.SetOwner(
this );
242 m_gitStatusTimer.SetOwner(
this );
252 m_filters.emplace_back( wxT(
"^no KiCad files found" ) );
260 Unbind( wxEVT_FSWATCHER,
262 Unbind( wxEVT_SYS_COLOUR_CHANGED,
291 if( tree_data.size() != 1 )
294 wxString prj_filename = tree_data[0]->GetFileName();
308 wxString curr_dir = item_data->GetDir();
310 if( curr_dir.IsEmpty() )
316 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
319 if( !curr_dir.IsEmpty() )
320 curr_dir += wxFileName::GetPathSeparator();
338 wxString curr_dir = item_data->GetDir();
340 if( curr_dir.IsEmpty() )
343 wxString new_dir = wxGetTextFromUser(
_(
"Directory name:" ),
_(
"Create New Directory" ) );
345 if( new_dir.IsEmpty() )
348 wxString full_dirname = curr_dir + wxFileName::GetPathSeparator() + new_dir;
350 if( !wxMkdir( full_dirname ) )
380 case TREE_FILE_TYPE::DRILL_NC:
return "nc";
381 case TREE_FILE_TYPE::DRILL_XNC:
return "xnc";
391 case TREE_FILE_TYPE::ROOT:
392 case TREE_FILE_TYPE::UNKNOWN:
393 case TREE_FILE_TYPE::MAX:
394 case TREE_FILE_TYPE::DIRECTORY:
break;
397 return wxEmptyString;
403 std::vector<wxString> projects;
404 wxString dir_filename;
405 bool haveFile = dir.GetFirst( &dir_filename );
409 wxFileName file( dir_filename );
413 projects.push_back( file.GetName() );
415 haveFile = dir.GetNext( &dir_filename );
426 const wxTreeItemId& aParent,
427 std::vector<wxString>* aProjectNames,
431 wxFileName fn( aName );
434 return wxTreeItemId();
436 if( wxDirExists( aName ) )
438 type = TREE_FILE_TYPE::DIRECTORY;
444 bool addFile =
false;
446 for(
const wxString& m_filter :
m_filters )
448 wxCHECK2_MSG( reg.Compile( m_filter, wxRE_ICASE ),
continue,
449 wxString::Format(
"Regex %s failed to compile.", m_filter ) );
451 if( reg.Matches( aName ) )
459 return wxTreeItemId();
461 for(
int i =
static_cast<int>( TREE_FILE_TYPE::LEGACY_PROJECT );
462 i < static_cast<int>( TREE_FILE_TYPE::MAX ); i++ )
466 if( ext == wxT(
"" ) )
469 if( reg.Compile( wxString::FromAscii(
"^.*\\." ) + ext + wxString::FromAscii(
"$" ),
470 wxRE_ICASE ) && reg.Matches( aName ) )
478 wxString file = wxFileNameFromPath( aName );
479 wxFileName currfile( file );
483 if( ( type == TREE_FILE_TYPE::LEGACY_PROJECT )
484 && ( currfile.GetName().CmpNoCase(
project.GetName() ) == 0 ) )
486 return wxTreeItemId();
489 if( currfile.GetExt() ==
GetFileExt( TREE_FILE_TYPE::LEGACY_SCHEMATIC )
490 || currfile.GetExt() ==
GetFileExt( TREE_FILE_TYPE::SEXPR_SCHEMATIC ) )
495 return wxTreeItemId();
500 wxDir parentDir( parentTreeItem->
GetDir() );
501 std::vector<wxString> projects =
getProjects( parentDir );
504 return wxTreeItemId();
509 wxTreeItemIdValue cookie;
510 wxTreeItemId kid =
m_TreeProject->GetFirstChild( aParent, cookie );
517 return itemData->GetId();
523 if( type == TREE_FILE_TYPE::LEGACY_PROJECT || type == TREE_FILE_TYPE::JSON_PROJECT
524 || type == TREE_FILE_TYPE::LEGACY_SCHEMATIC || type == TREE_FILE_TYPE::SEXPR_SCHEMATIC )
536 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
540 case TREE_FILE_TYPE::LEGACY_PROJECT:
541 if( itemData->
GetType() == TREE_FILE_TYPE::JSON_PROJECT )
542 return wxTreeItemId();
546 case TREE_FILE_TYPE::LEGACY_SCHEMATIC:
547 if( itemData->
GetType() == TREE_FILE_TYPE::SEXPR_SCHEMATIC )
548 return wxTreeItemId();
552 case TREE_FILE_TYPE::JSON_PROJECT:
553 if( itemData->
GetType() == TREE_FILE_TYPE::LEGACY_PROJECT )
558 case TREE_FILE_TYPE::SEXPR_SCHEMATIC:
559 if( itemData->
GetType() == TREE_FILE_TYPE::LEGACY_SCHEMATIC )
575 wxTreeItemId newItemId =
m_TreeProject->AppendItem( aParent, file );
582 wxString fileName = currfile.GetName().Lower();
583 wxString projName =
project.GetName().Lower();
585 if( fileName == projName || fileName.StartsWith( projName +
"-" ) )
589 bool subdir_populated =
false;
594 if( TREE_FILE_TYPE::DIRECTORY == type && aRecurse )
600 std::vector<wxString> projects =
getProjects( dir );
601 wxString dir_filename;
602 bool haveFile = dir.GetFirst( &dir_filename );
607 subdir_populated = aRecurse;
613 wxString
path = aName + wxFileName::GetPathSeparator() + dir_filename;
616 haveFile = dir.GetNext( &dir_filename );
625 if( subdir_populated )
663 wxFileName fn = pro_dir;
664 bool prjReset =
false;
675 bool prjOpened = fn.FileExists();
678 if(
Pgm().GetCommonSettings()->m_Git.enableGit )
692 if( !prjOpened && !prjReset )
695 prjOpened = fn.FileExists();
702 m_root =
m_TreeProject->AddRoot( fn.GetFullName(),
static_cast<int>( TREE_FILE_TYPE::ROOT ),
703 static_cast<int>( TREE_FILE_TYPE::ROOT ) );
716 wxDir dir( pro_dir );
720 std::vector<wxString> projects =
getProjects( dir );
722 bool haveFile = dir.GetFirst( &filename );
726 if( filename != fn.GetFullName() )
728 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
735 haveFile = dir.GetNext( &filename );
752 wxLogTrace(
traceGit,
"PROJECT_TREE_PANE::ReCreateTreePrj: starting timers" );
771 wxTreeItemId curr_item = Event.GetItem();
778 wxFileName prj_dir(
Prj().GetProjectPath(), wxEmptyString );
780 prj_dir.Normalize( wxPATH_NORM_ABSOLUTE | wxPATH_NORM_CASE | wxPATH_NORM_DOTS
781 | wxPATH_NORM_ENV_VARS | wxPATH_NORM_TILDE );
782 git_dir.Normalize( wxPATH_NORM_ABSOLUTE | wxPATH_NORM_CASE | wxPATH_NORM_DOTS
783 | wxPATH_NORM_ENV_VARS | wxPATH_NORM_TILDE );
784 wxString prj_name = prj_dir.GetFullPath();
785 wxString git_name = git_dir.GetFullPath();
787 bool can_switch_to_project =
true;
788 bool can_create_new_directory =
true;
789 bool can_open_this_directory =
true;
790 bool can_edit =
true;
791 bool can_rename =
true;
792 bool can_delete =
true;
793 bool run_jobs =
false;
797 bool vcs_can_init = !vcs_has_repo;
798 bool vcs_can_remove = vcs_has_repo && git_name.StartsWith( prj_name );
801 bool vcs_can_pull = vcs_can_fetch;
802 bool vcs_can_switch = vcs_has_repo;
806#if ( LIBGIT2_VER_MAJOR >= 1 ) || ( LIBGIT2_VER_MINOR >= 99 )
807 int major, minor, rev;
808 bool libgit_init = ( git_libgit2_version( &major, &minor, &rev ) == GIT_OK );
811 bool libgit_init =
true;
814 vcs_menu &= libgit_init;
816 if( selection.size() == 0 )
820 if( selection.size() != 1 )
822 can_switch_to_project =
false;
823 can_create_new_directory =
false;
832 can_switch_to_project =
false;
838 can_delete = item->CanDelete();
839 can_rename = item->CanRename();
841 switch( item->GetType() )
843 case TREE_FILE_TYPE::JSON_PROJECT:
844 case TREE_FILE_TYPE::LEGACY_PROJECT:
849 can_switch_to_project =
false;
853 can_create_new_directory =
false;
854 can_open_this_directory =
false;
858 case TREE_FILE_TYPE::DIRECTORY:
859 can_switch_to_project =
false;
863 case TREE_FILE_TYPE::ZIP_ARCHIVE:
864 case TREE_FILE_TYPE::PDF:
866 can_switch_to_project =
false;
867 can_create_new_directory =
false;
868 can_open_this_directory =
false;
871 case TREE_FILE_TYPE::JOBSET_FILE:
876 case TREE_FILE_TYPE::SEXPR_SCHEMATIC:
877 case TREE_FILE_TYPE::SEXPR_PCB:
881 can_switch_to_project =
false;
882 can_create_new_directory =
false;
883 can_open_this_directory =
false;
893 if( can_switch_to_project )
896 _(
"Close all editors, and switch to the selected project" ),
897 KiBitmap( BITMAPS::open_project ) );
898 popup_menu.AppendSeparator();
901 if( can_create_new_directory )
904 _(
"Create a New Directory" ),
KiBitmap( BITMAPS::directory ) );
907 if( can_open_this_directory )
909 if( selection.size() == 1 )
912 text =
_(
"Reveal in Finder" );
913 help_text =
_(
"Reveals the directory in a Finder window" );
915 text =
_(
"Open Directory in File Explorer" );
916 help_text =
_(
"Opens the directory in the default system file manager" );
922 text =
_(
"Reveal in Finder" );
923 help_text =
_(
"Reveals the directories in a Finder window" );
925 text =
_(
"Open Directories in File Explorer" );
926 help_text =
_(
"Opens the directories in the default system file manager" );
931 KiBitmap( BITMAPS::directory_browser ) );
936 if( selection.size() == 1 )
937 help_text =
_(
"Open the file in a Text Editor" );
939 help_text =
_(
"Open files in a Text Editor" );
945 if( run_jobs && selection.size() == 1 )
953 if( selection.size() == 1 )
955 text =
_(
"Rename File..." );
956 help_text =
_(
"Rename file" );
960 text =
_(
"Rename Files..." );
961 help_text =
_(
"Rename files" );
970 if( selection.size() == 1 )
971 help_text =
_(
"Delete the file and its content" );
973 help_text =
_(
"Delete the files and their contents" );
975 if( can_switch_to_project
976 || can_create_new_directory
977 || can_open_this_directory
981 popup_menu.AppendSeparator();
995 wxMenu* vcs_submenu =
new wxMenu();
996 wxMenu* branch_submenu =
new wxMenu();
997 wxMenuItem* vcs_menuitem =
nullptr;
1000 _(
"Add Project to Version Control..." ),
1001 _(
"Initialize a new repository" ) );
1002 vcs_menuitem->Enable( vcs_can_init );
1006 _(
"Commit changes to the local repository" ) );
1007 vcs_menuitem->Enable( vcs_can_commit );
1009 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PUSH,
_(
"Push" ),
1010 _(
"Push committed local changes to remote repository" ) );
1011 vcs_menuitem->Enable( vcs_can_push );
1013 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PULL,
_(
"Pull" ),
1014 _(
"Pull changes from remote repository into local" ) );
1015 vcs_menuitem->Enable( vcs_can_pull );
1017 vcs_submenu->AppendSeparator();
1020 _(
"Commit changes to the local repository" ) );
1021 vcs_menuitem->Enable( vcs_can_commit );
1023 vcs_submenu->AppendSeparator();
1032 for(
size_t ii = 1; ii < branchNames.size() && ii < 6; ++ii )
1034 wxString msg =
_(
"Switch to branch " ) + branchNames[ii];
1036 vcs_menuitem->Enable( vcs_can_switch );
1040 _(
"Switch to a different branch" ) );
1041 vcs_menuitem->Enable( vcs_can_switch );
1045 vcs_submenu->AppendSeparator();
1047 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Remove Version Control" ),
1048 _(
"Delete all version control files from the project directory." ) );
1049 vcs_menuitem->Enable( vcs_can_remove );
1051 popup_menu.AppendSeparator();
1052 popup_menu.AppendSubMenu( vcs_submenu,
_(
"Version Control" ) );
1055 if( popup_menu.GetMenuItemCount() > 0 )
1056 PopupMenu( &popup_menu );
1064 if( editorname.IsEmpty() )
1066 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
1074 wxString fullFileName = item_data->GetFileName();
1076 if( !fullFileName.IsEmpty() )
1078 ExecuteFile( editorname, fullFileName.wc_str(),
nullptr,
false );
1089 item_data->Delete();
1099 if( tree_data.size() != 1 )
1103 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
1104 tree_data[0]->GetFileName() );
1105 wxTextEntryDialog dlg( wxGetTopLevelParent(
this ), msg,
_(
"Change filename" ), buffer );
1107 if( dlg.ShowModal() != wxID_OK )
1110 buffer = dlg.GetValue();
1111 buffer.Trim(
true );
1112 buffer.Trim(
false );
1114 if( buffer.IsEmpty() )
1117 tree_data[0]->Rename( buffer,
true );
1126 if( tree_data.size() != 1 )
1149 std::vector<wxTreeItemId> validItemIds;
1152 for( wxTreeItemId
id : validItemIds )
1171 wxTreeItemId itemId = Event.GetItem();
1177 if( tree_data->
GetType() != TREE_FILE_TYPE::DIRECTORY )
1181 wxTreeItemIdValue cookie;
1182 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
1185 bool subdir_populated =
false;
1188 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
1192 if( !itemData || itemData->
GetType() != TREE_FILE_TYPE::DIRECTORY )
1199 wxDir dir( fileName );
1201 if( dir.IsOpened() )
1203 std::vector<wxString> projects =
getProjects( dir );
1204 wxString dir_filename;
1205 bool haveFile = dir.GetFirst( &dir_filename );
1210 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
1213 haveFile = dir.GetNext( &dir_filename );
1219 subdir_populated =
true;
1228 if( subdir_populated )
1236 wxArrayTreeItemIds selection;
1237 std::vector<PROJECT_TREE_ITEM*> data;
1241 for(
const wxTreeItemId itemId : selection )
1247 wxLogTrace(
traceGit, wxS(
"Null tree item returned for selection, dynamic_cast failed?" ) );
1251 data.push_back( item );
1270 if( prj_dir == aSubDir )
1274 wxTreeItemIdValue cookie;
1275 wxTreeItemId root_id =
m_root;
1276 std::stack<wxTreeItemId> subdirs_id;
1278 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
1282 if( ! child.IsOk() )
1284 if( subdirs_id.empty() )
1291 root_id = subdirs_id.top();
1302 if( itemData && ( itemData->
GetType() == TREE_FILE_TYPE::DIRECTORY ) )
1312 subdirs_id.push( child );
1330 if( !( event.GetChangeType() & ( wxFSW_EVENT_CREATE |
1331 wxFSW_EVENT_DELETE |
1332 wxFSW_EVENT_RENAME |
1333 wxFSW_EVENT_MODIFY ) ) )
1338 const wxFileName& pathModified =
event.GetPath();
1339 wxString subdir = pathModified.GetPath();
1340 wxString fn = pathModified.GetFullPath();
1343 if( pathModified.GetFullName().IsEmpty() )
1345 subdir = subdir.BeforeLast(
'/' );
1346 fn = fn.BeforeLast(
'/' );
1351 if( !root_id.IsOk() )
1354 CallAfter( [
this] ()
1356 wxLogTrace(
traceGit, wxS(
"File system event detected, updating tree cache" ) );
1360 wxTreeItemIdValue cookie;
1361 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1363 switch( event.GetChangeType() )
1365 case wxFSW_EVENT_CREATE:
1380 case wxFSW_EVENT_DELETE:
1394 case wxFSW_EVENT_RENAME :
1396 const wxFileName& newpath =
event.GetNewPath();
1397 wxString newdir = newpath.GetPath();
1398 wxString newfn = newpath.GetFullPath();
1422 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1428 if( newitem.IsOk() )
1451#if defined( _WIN32 )
1484 fn.AssignDir( prj_dir );
1485 fn.DontFollowLink();
1499 TO_UTF8( fn.GetFullPath() ) );
1507 TO_UTF8( fn.GetFullPath() ) );
1512 if( m_TreeProject->IsEmpty() )
1516 wxTreeItemIdValue cookie;
1517 wxTreeItemId root_id = m_root;
1519 std::stack < wxTreeItemId > subdirs_id;
1521 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1522 int total_watch_count = 0;
1528 if( subdirs_id.empty() )
1534 root_id = subdirs_id.top();
1536 kid = m_TreeProject->GetFirstChild( root_id, cookie );
1552 if( wxFileName::IsDirReadable(
path ) )
1557 fn.AssignDir(
path );
1558 m_watcher->Add( fn );
1559 total_watch_count++;
1563 if( itemData->
IsPopulated() && m_TreeProject->GetChildrenCount( kid ) )
1564 subdirs_id.push( kid );
1568 kid = m_TreeProject->GetNextChild( root_id, cookie );
1575#if defined(DEBUG) && 1
1576 wxArrayString paths;
1577 m_watcher->GetWatchedPaths( &paths );
1580 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1601 if( !lock.owns_lock() )
1605 wxProgressDialog progress(
_(
"Please wait" ),
_(
"Waiting for Git operations to finish..." ),
1606 100,
this, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH );
1609 while ( !lock.try_lock() )
1612 std::this_thread::sleep_for( std::chrono::milliseconds(100) );
1638 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1639 wxPaintDC dc(
this );
1641 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1642 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1644 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1645 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1659 wxString dir = tree_data->
GetDir();
1663 wxLogError(
"Failed to initialize git project: project directory is empty." );
1668 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1673 _(
"The selected directory is already a Git project." ) );
1678 if( result != InitResult::Success )
1688 dlg.SetTitle(
_(
"Set default remote" ) );
1743 handler.
SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
1766 handler.
SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
1769 if( handler.
PerformPush() != PushResult::Success )
1786 wxString branchName;
1795 if( retval == wxID_ADD )
1797 else if( retval != wxID_OK )
1805 if( branchIndex < 0 ||
static_cast<size_t>( branchIndex ) >= branches.size() )
1808 branchName = branches[branchIndex];
1811 wxLogTrace(
traceGit, wxS(
"onGitSwitchBranch: Switching to branch '%s'" ), branchName );
1812 if( branchHandler.
SwitchToBranch( branchName ) != BranchResult::Success )
1824 || !
IsOK( wxGetTopLevelParent(
this ),
1825 _(
"Are you sure you want to remove Git tracking from this project?" ) ) )
1831 wxLogTrace(
traceGit, wxS(
"onGitRemoveVCS: Removing VCS from project" ) );
1843 std::stack<wxTreeItemId> items;
1846 while( !items.empty() )
1848 wxTreeItemId current = items.top();
1852 m_TreeProject->SetItemState( current, wxTREE_ITEMSTATE_NONE );
1854 wxTreeItemIdValue cookie;
1855 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
1857 while( child.IsOk() )
1859 items.push( child );
1868 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Updating git status icons" ) );
1871 if( !lock.owns_lock() )
1873 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Failed to acquire lock for git status icon update" ) );
1880 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git is disabled or tree control is null" ) );
1884 std::stack<wxTreeItemId> items;
1887 while( !items.empty() )
1889 wxTreeItemId current = items.top();
1894 wxTreeItemIdValue cookie;
1895 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
1897 while( child.IsOk() )
1899 items.push( child );
1903 m_TreeProject->SetItemState( child,
static_cast<int>( it->second ) );
1915 wxString filename = wxFileNameFromPath( rootItem->
GetFileName() );
1920 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git status icons updated" ) );
1926 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Updating tree cache" ) );
1930 if( !lock.owns_lock() )
1932 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Failed to acquire lock for tree cache update" ) );
1938 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Tree control is null" ) );
1949 std::stack<wxTreeItemId> items;
1952 while( !items.empty() )
1961 gitAbsPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
1965 wxTreeItemIdValue cookie;
1966 wxTreeItemId child =
m_TreeProject->GetFirstChild( kid, cookie );
1968 while( child.IsOk() )
1970 items.push( child );
1979 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updating git status icons" ) );
1980#if defined( _WIN32 )
2003 if( !lock1.owns_lock() || !lock2.owns_lock() )
2005 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire locks for git status icon update" ) );
2011 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: No git repository found" ) );
2018 wxFileName rootFilename(
Prj().GetProjectFullName() );
2021 wxFileName relative = rootFilename;
2022 relative.MakeRelativeTo( repoWorkDir );
2023 wxString pathspecStr = relative.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
2026 pathspecStr.Replace( wxS(
"\\" ), wxS(
"/" ) );
2030 auto fileStatusMap = statusHandler.
GetFileStatus( pathspecStr );
2034 bool updated =
false;
2037 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2042 wxLogTrace(
traceGit, wxS(
"File '%s' not found in tree cache" ), absPath );
2046 auto [it, inserted] =
m_gitStatusIcons.try_emplace( iter->second, fileStatus.status );
2047 if( inserted || it->second != fileStatus.status )
2049 it->second = fileStatus.status;
2055 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updated git status icons" ) );
2075 if( repo ==
nullptr )
2077 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2089 std::map<wxString, int> modifiedFiles;
2090 std::set<wxString> selected_files;
2094 if( item->GetType() != TREE_FILE_TYPE::DIRECTORY )
2095 selected_files.emplace( item->GetFileName() );
2100 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2110 wxFileName fn( absPath );
2113 wxString relativePath = absPath;
2114 if( relativePath.StartsWith( repoWorkDir ) )
2116 relativePath = relativePath.Mid( repoWorkDir.length() );
2118 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2124 if( !absPath.StartsWith( projectPath ) )
2140 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2145 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2147 else if( selected_files.count( absPath ) )
2149 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2158 if( ret != wxID_OK )
2165 wxMessageBox(
_(
"Discarding commit due to empty commit message." ) );
2171 wxMessageBox(
_(
"Discarding commit due to empty file selection." ) );
2181 wxMessageBox( wxString::Format(
_(
"Failed to create commit: %s" ),
2186 wxLogTrace(
traceGit, wxS(
"Created commit" ) );
2206 for(
const auto& [filePath, fileStatus] : fileStatusMap )
2208 if( filePath.EndsWith( aFile ) || filePath == aFile )
2222 wxLogTrace(
traceGit,
"Syncing project" );
2227 wxLogTrace(
traceGit,
"sync: No git repository found" );
2294 wxLogTrace(
traceGit,
"onGitSyncTimer" );
2309 wxLogTrace(
traceGit,
"onGitSyncTimer: No git repository found" );
2324 wxLogTrace(
traceGit,
"onGitSyncTimer: Restarting git sync timer" );
2345 wxLogTrace(
traceGit,
"onGitStatusTimer" );
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 GetRepoSSHPath() const
wxString GetRepoURL() const
wxString GetUsername() const
wxString GetPassword() const
void SetSkipButtonLabel(const wxString &aLabel)
wxString GetBranchName() const
BranchResult SwitchToBranch(const wxString &aBranchName)
Switch to the specified branch.
CommitResult PerformCommit(const std::vector< wxString > &aFiles, const wxString &aMessage, const wxString &aAuthorName, const wxString &aAuthorEmail)
wxString GetErrorString() const
GitUserConfig GetUserConfig()
Get user configuration (name and email) from git config Falls back to common settings if not found in...
bool IsRepository(const wxString &aPath)
Check if a directory is already a git repository.
InitResult InitializeRepository(const wxString &aPath)
Initialize a new git repository in the specified directory.
bool SetupRemote(const RemoteConfig &aConfig)
Set up a remote for the repository.
void SetProgressReporter(std::unique_ptr< WX_PROGRESS_REPORTER > aProgressReporter)
bool PerformFetch(bool aSkipLock=false)
void PerformRemoveFromIndex()
bool PerformResolveConflict()
wxString GetCurrentBranchName()
Get the current branch name.
void UpdateRemoteStatus(const std::set< wxString > &aLocalChanges, const std::set< wxString > &aRemoteChanges, std::map< wxString, FileStatus > &aFileStatus)
Get status for modified files based on local/remote changes.
wxString GetWorkingDirectory()
Get the repository working directory path.
bool HasChangedFiles()
Check if the repository has any changed files.
std::map< wxString, FileStatus > GetFileStatus(const wxString &aPathspec=wxEmptyString)
Get detailed file status for all files in the specified path.
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)
static git_repository * GetRepositoryForFile(const char *aFilename)
Discover and open the repository that contains the given file.
static bool RemoveVCS(git_repository *&aRepo, const wxString &aProjectPath=wxEmptyString, bool aRemoveGitDir=false, wxString *aErrors=nullptr)
Remove version control from a directory by freeing the repository and optionally removing the ....
static int CreateBranch(git_repository *aRepo, const wxString &aBranchName)
Create a new branch based on HEAD.
std::mutex m_gitActionMutex
std::vector< wxString > GetBranchNames() const
wxString GetGitRootDirectory() const
void SetSSHKey(const wxString &aSSHKey)
void SetUsername(const wxString &aUsername)
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
void UpdateCurrentBranchInfo()
bool HasLocalCommits() const
void SetCancelled(bool aCancel)
wxString GetErrorString()
git_repository * GetRepo() const
Get a pointer to the git repository.
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.
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_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
std::unordered_map< wxString, wxTreeItemId > m_gitTreeCache
void onGitFetch(wxCommandEvent &event)
Fetch the latest changes from the git repository.
std::map< wxTreeItemId, KIGIT_COMMON::GIT_STATUS > m_gitStatusIcons
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 ...
wxString m_gitCurrentBranchName
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
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 onGitSyncTimer(wxTimerEvent &event)
void onIdle(wxIdleEvent &aEvent)
Idle event handler, used process the selected items at a point in time when all other events have bee...
void updateTreeCache()
Updates the map of the wxtreeitemid to the name of each file for use in the thread.
void gitStatusTimerHandler()
std::mutex m_gitStatusMutex
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 onRunSelectedJobsFile(wxCommandEvent &event)
Run a selected jobs file.
void onGitCompare(wxCommandEvent &event)
Compare the current project to a different branch in the git repository.
void onGitStatusTimer(wxTimerEvent &event)
void shutdownFileWatcher()
Shutdown the file watcher.
std::mutex m_gitTreeCacheMutex
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.
bool m_gitIconsInitialized
void updateGitStatusIconMap()
This is a threaded call that will change the map of git status icons for use in the main thread.
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
void GetItemsRecursively(const wxTreeItemId &aParentId, std::vector< wxTreeItemId > &aItems)
KIGIT_COMMON * GitCommon() const
void SetGitRepo(git_repository *aRepo)
virtual const wxString GetProjectPath() const
Return the full path of the project.
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 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.
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
This file is part of the common library.
EVT_MENU_RANGE(ID_GERBVIEW_DRILL_FILE1, ID_GERBVIEW_DRILL_FILEMAX, GERBVIEW_FRAME::OnDrlFileHistory) EVT_MENU_RANGE(ID_GERBVIEW_ZIP_FILE1
int ExecuteFile(const wxString &aEditorName, const wxString &aFileName, wxProcess *aCallback, bool aFileForKicad)
Call the executable file aEditorName with the parameter aFileName.
int m_GitIconRefreshInterval
The interval in milliseconds to refresh the git icons in the project tree.
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 LockFileExtension
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 LockFilePrefix
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 BackupFileSuffix
static const std::string AutoSaveFilePrefix
static const std::string KiCadJobSetFileExtension
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.
const wxChar *const traceGit
Flag to enable Git debugging output.
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 wxBitmapBundle &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
project_tree_ids
The frame that shows the tree list of files and subdirectories inside the working directory.
@ ID_PROJECT_SWITCH_TO_OTHER
@ ID_GIT_REMOVE_FROM_INDEX
@ ID_GIT_RESOLVE_CONFLICT
@ ID_GIT_INITIALIZE_PROJECT
std::vector< wxString > getProjects(const wxDir &dir)
static const wxChar * s_allowedExtensionsToList[]
wxDECLARE_EVENT(UPDATE_ICONS, wxCommandEvent)
#define wxFileSystemWatcher
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
KIGIT_COMMON::GIT_CONN_TYPE connType
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::thread_pool thread_pool
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.