30#include <wx/stdpaths.h>
33#include <wx/textdlg.h>
35#include <wx/wupdlock.h>
56#include <wx/dcclient.h>
57#include <wx/progdlg.h>
58#include <wx/settings.h>
107 wxT(
"^.*\\.kicad_pro$" ),
110 wxT(
"^.*\\.kicad_sch$" ),
111 wxT(
"^[^$].*\\.brd$" ),
112 wxT(
"^[^$].*\\.kicad_pcb$" ),
113 wxT(
"^[^$].*\\.kicad_dru$" ),
114 wxT(
"^[^$].*\\.kicad_wks$" ),
115 wxT(
"^[^$].*\\.kicad_mod$" ),
119 wxT(
"^.*\\.kicad_sym$" ),
124 wxT(
"^.*\\.gbrjob$" ),
125 wxT(
"^.*\\.gb[alops]$" ),
126 wxT(
"^.*\\.gt[alops]$" ),
127 wxT(
"^.*\\.g[0-9]{1,2}$" ),
128 wxT(
"^.*\\.gm[0-9]{1,2}$" ),
132 wxT(
"^.*\\.html$" ),
143 wxT(
"^.*\\.kicad_jobset" ),
226 wxSashLayoutWindow( parent,
ID_LEFT_FRAME, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL )
237 Bind( wxEVT_FSWATCHER,
240 Bind( wxEVT_SYS_COLOUR_CHANGED,
254 m_filters.emplace_back( wxT(
"^no KiCad files found" ) );
262 Unbind( wxEVT_FSWATCHER,
264 Unbind( wxEVT_SYS_COLOUR_CHANGED,
291 if( tree_data.size() != 1 )
294 wxString prj_filename = tree_data[0]->GetFileName();
296 m_Parent->LoadProject( prj_filename );
308 wxString curr_dir = item_data->GetDir();
310 if( curr_dir.IsEmpty() )
313 curr_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
316 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
319 if( !curr_dir.IsEmpty() )
320 curr_dir += wxFileName::GetPathSeparator();
335 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
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 ) )
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 ) )
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();
466 if( ext == wxT(
"" ) )
469 if( reg.Compile( wxString::FromAscii(
"^.*\\." ) + ext + wxString::FromAscii(
"$" ), wxRE_ICASE )
470 && reg.Matches( aName ) )
478 wxString file = wxFileNameFromPath( aName );
479 wxFileName currfile( file );
481 bool showAllSchematics =
m_TreeProject->GetGitRepo() !=
nullptr;
485 && ( currfile.GetName().CmpNoCase(
project.GetName() ) == 0 ) )
487 return wxTreeItemId();
496 return wxTreeItemId();
502 if( !parentTreeItem )
503 return wxTreeItemId();
505 wxDir parentDir( parentTreeItem->
GetDir() );
506 std::vector<wxString> projects =
getProjects( parentDir );
509 return wxTreeItemId();
514 wxTreeItemIdValue cookie;
515 wxTreeItemId kid =
m_TreeProject->GetFirstChild( aParent, cookie );
522 return itemData->GetId();
543 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
549 return wxTreeItemId();
555 return wxTreeItemId();
582 wxTreeItemId newItemId =
m_TreeProject->AppendItem( aParent, file );
589 wxString fileName = currfile.GetName().Lower();
590 wxString projName =
project.GetName().Lower();
592 if( fileName == projName || fileName.StartsWith( projName +
"-" ) )
596 bool subdir_populated =
false;
607 std::vector<wxString> projects =
getProjects( dir );
608 wxString dir_filename;
609 bool haveFile = dir.GetFirst( &dir_filename );
614 subdir_populated = aRecurse;
620 wxString
path = aName + wxFileName::GetPathSeparator() + dir_filename;
623 haveFile = dir.GetNext( &dir_filename );
632 if( subdir_populated )
646 while(
tp.get_tasks_running() )
648 tp.wait_for( std::chrono::milliseconds( 250 ) );
656 wxString pro_dir =
m_Parent->GetProjectFileName();
674 wxFileName fn = pro_dir;
675 bool prjReset =
false;
686 bool prjOpened = fn.FileExists();
689 if(
Pgm().GetCommonSettings()->m_Git.enableGit
690 && !
Prj().GetLocalSettings().m_GitIntegrationDisabled )
696 m_TreeProject->GitCommon()->SetUsername(
Prj().GetLocalSettings().m_GitRepoUsername );
697 m_TreeProject->GitCommon()->SetSSHKey(
Prj().GetLocalSettings().m_GitSSHKey );
704 if( !prjOpened && !prjReset )
707 prjOpened = fn.FileExists();
727 pro_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
728 wxDir dir( pro_dir );
732 std::vector<wxString> projects =
getProjects( dir );
734 bool haveFile = dir.GetFirst( &filename );
738 if( filename != fn.GetFullName() )
740 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
747 haveFile = dir.GetNext( &filename );
764 wxLogTrace(
traceGit,
"PROJECT_TREE_PANE::ReCreateTreePrj: starting timers" );
783 wxTreeItemId curr_item = Event.GetItem();
790 wxFileName prj_dir(
Prj().GetProjectPath(), wxEmptyString );
792 prj_dir.Normalize( wxPATH_NORM_ABSOLUTE | wxPATH_NORM_CASE | wxPATH_NORM_DOTS
793 | wxPATH_NORM_ENV_VARS | wxPATH_NORM_TILDE );
794 git_dir.Normalize( wxPATH_NORM_ABSOLUTE | wxPATH_NORM_CASE | wxPATH_NORM_DOTS
795 | wxPATH_NORM_ENV_VARS | wxPATH_NORM_TILDE );
796 wxString prj_name = prj_dir.GetFullPath();
797 wxString git_name = git_dir.GetFullPath();
799 bool can_switch_to_project =
true;
800 bool can_create_new_directory =
true;
801 bool can_open_this_directory =
true;
802 bool can_edit =
true;
803 bool can_rename =
true;
804 bool can_delete =
true;
805 bool run_jobs =
false;
809 bool vcs_can_init = !vcs_has_repo;
812 bool vcs_can_remove = ( vcs_has_repo && git_name.StartsWith( prj_name ) ) || gitIntegrationDisabled;
815 bool vcs_can_pull = vcs_can_fetch;
816 bool vcs_can_switch = vcs_has_repo;
822 vcs_menu &= libgit_init;
824 if( selection.size() == 0 )
828 if( selection.size() != 1 )
830 can_switch_to_project =
false;
831 can_create_new_directory =
false;
840 can_switch_to_project =
false;
846 can_delete = item->CanDelete();
847 can_rename = item->CanRename();
849 switch( item->GetType() )
857 can_switch_to_project =
false;
861 can_create_new_directory =
false;
862 can_open_this_directory =
false;
867 can_switch_to_project =
false;
874 can_switch_to_project =
false;
875 can_create_new_directory =
false;
876 can_open_this_directory =
false;
889 can_switch_to_project =
false;
890 can_create_new_directory =
false;
891 can_open_this_directory =
false;
901 if( can_switch_to_project )
904 _(
"Close all editors, and switch to the selected project" ),
906 popup_menu.AppendSeparator();
909 if( can_create_new_directory )
915 if( can_open_this_directory )
917 if( selection.size() == 1 )
920 text =
_(
"Reveal in Finder" );
921 help_text =
_(
"Reveals the directory in a Finder window" );
923 text =
_(
"Open Directory in File Explorer" );
924 help_text =
_(
"Opens the directory in the default system file manager" );
930 text =
_(
"Reveal in Finder" );
931 help_text =
_(
"Reveals the directories in a Finder window" );
933 text =
_(
"Open Directories in File Explorer" );
934 help_text =
_(
"Opens the directories in the default system file manager" );
944 if( selection.size() == 1 )
945 help_text =
_(
"Open the file in a Text Editor" );
947 help_text =
_(
"Open files in a Text Editor" );
953 if( run_jobs && selection.size() == 1 )
961 if( selection.size() == 1 )
963 text =
_(
"Rename File..." );
964 help_text =
_(
"Rename file" );
968 text =
_(
"Rename Files..." );
969 help_text =
_(
"Rename files" );
978 if( selection.size() == 1 )
979 help_text =
_(
"Delete the file and its content" );
981 help_text =
_(
"Delete the files and their contents" );
983 if( can_switch_to_project
984 || can_create_new_directory
985 || can_open_this_directory
989 popup_menu.AppendSeparator();
1003 wxMenu* vcs_submenu =
new wxMenu();
1004 wxMenu* branch_submenu =
new wxMenu();
1005 wxMenuItem* vcs_menuitem =
nullptr;
1008 _(
"Add Project to Version Control..." ),
1009 _(
"Initialize a new repository" ) );
1010 vcs_menuitem->Enable( vcs_can_init );
1014 _(
"Commit changes to the local repository" ) );
1015 vcs_menuitem->Enable( vcs_can_commit );
1017 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PUSH,
_(
"Push" ),
1018 _(
"Push committed local changes to remote repository" ) );
1019 vcs_menuitem->Enable( vcs_can_push );
1021 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PULL,
_(
"Pull" ),
1022 _(
"Pull changes from remote repository into local" ) );
1023 vcs_menuitem->Enable( vcs_can_pull );
1025 vcs_submenu->AppendSeparator();
1028 _(
"Commit changes to the local repository" ) );
1029 vcs_menuitem->Enable( vcs_can_commit );
1031 vcs_submenu->AppendSeparator();
1037 std::vector<wxString> branchNames =
m_TreeProject->GitCommon()->GetBranchNames();
1040 for(
size_t ii = 1; ii < branchNames.size() && ii < 6; ++ii )
1042 wxString msg =
_(
"Switch to branch " ) + branchNames[ii];
1044 vcs_menuitem->Enable( vcs_can_switch );
1048 _(
"Switch to a different branch" ) );
1049 vcs_menuitem->Enable( vcs_can_switch );
1053 vcs_submenu->AppendSeparator();
1055 if( gitIntegrationDisabled )
1057 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Enable Git Integration" ),
1058 _(
"Re-enable Git integration for this project" ) );
1062 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Disable Git Integration" ),
1063 _(
"Disable Git integration for this project" ) );
1066 vcs_menuitem->Enable( vcs_can_remove );
1068 popup_menu.AppendSeparator();
1069 popup_menu.AppendSubMenu( vcs_submenu,
_(
"Version Control" ) );
1072 if( popup_menu.GetMenuItemCount() > 0 )
1073 PopupMenu( &popup_menu );
1081 if( editorname.IsEmpty() )
1083 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
1091 wxString fullFileName = item_data->GetFileName();
1093 if( !fullFileName.IsEmpty() )
1095 ExecuteFile( editorname, fullFileName.wc_str(),
nullptr,
false );
1106 item_data->Delete();
1116 if( tree_data.size() != 1 )
1120 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
1121 tree_data[0]->GetFileName() );
1122 wxTextEntryDialog dlg( wxGetTopLevelParent(
this ), msg,
_(
"Change filename" ), buffer );
1124 if( dlg.ShowModal() != wxID_OK )
1127 buffer = dlg.GetValue();
1128 buffer.Trim(
true );
1129 buffer.Trim(
false );
1131 if( buffer.IsEmpty() )
1134 tree_data[0]->Rename( buffer,
true );
1143 if( tree_data.size() != 1 )
1166 std::vector<wxTreeItemId> validItemIds;
1169 for( wxTreeItemId
id : validItemIds )
1188 wxTreeItemId itemId = Event.GetItem();
1198 wxTreeItemIdValue cookie;
1199 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
1202 bool subdir_populated =
false;
1205 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
1216 wxDir dir( fileName );
1218 if( dir.IsOpened() )
1220 std::vector<wxString> projects =
getProjects( dir );
1221 wxString dir_filename;
1222 bool haveFile = dir.GetFirst( &dir_filename );
1227 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
1230 haveFile = dir.GetNext( &dir_filename );
1236 subdir_populated =
true;
1245 if( subdir_populated )
1253 wxArrayTreeItemIds selection;
1254 std::vector<PROJECT_TREE_ITEM*> data;
1258 for(
const wxTreeItemId itemId : selection )
1264 wxLogTrace(
traceGit, wxS(
"Null tree item returned for selection, dynamic_cast failed?" ) );
1268 data.push_back( item );
1283 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1287 if( prj_dir == aSubDir )
1291 wxTreeItemIdValue cookie;
1292 wxTreeItemId root_id =
m_root;
1293 std::stack<wxTreeItemId> subdirs_id;
1295 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
1299 if( ! child.IsOk() )
1301 if( subdirs_id.empty() )
1308 root_id = subdirs_id.top();
1329 subdirs_id.push( child );
1347 if( !( event.GetChangeType() & ( wxFSW_EVENT_CREATE |
1348 wxFSW_EVENT_DELETE |
1349 wxFSW_EVENT_RENAME |
1350 wxFSW_EVENT_MODIFY ) ) )
1355 const wxFileName& pathModified =
event.GetPath();
1356 wxString subdir = pathModified.GetPath();
1357 wxString fn = pathModified.GetFullPath();
1360 if( pathModified.GetFullName().IsEmpty() )
1362 subdir = subdir.BeforeLast(
'/' );
1363 fn = fn.BeforeLast(
'/' );
1368 if( !root_id.IsOk() )
1371 CallAfter( [
this] ()
1373 wxLogTrace(
traceGit, wxS(
"File system event detected, updating tree cache" ) );
1377 wxTreeItemIdValue cookie;
1378 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1380 switch( event.GetChangeType() )
1382 case wxFSW_EVENT_CREATE:
1397 case wxFSW_EVENT_DELETE:
1411 case wxFSW_EVENT_RENAME :
1413 const wxFileName& newpath =
event.GetNewPath();
1414 wxString newdir = newpath.GetPath();
1415 wxString newfn = newpath.GetFullPath();
1439 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1445 if( newitem.IsOk() )
1466 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1468#if defined( _WIN32 )
1477 m_Parent->m_FileWatcherInfo =
_(
"Network path: not monitoring folder changes" );
1483 m_Parent->m_FileWatcherInfo =
_(
"Local path: monitoring folder changes" );
1501 class WatcherLogHandler :
public wxLog
1504 explicit WatcherLogHandler(
bool* err ) :
1512 void DoLogTextAtLevel( wxLogLevel level,
const wxString&
text )
override
1514 if( m_err && ( level == wxLOG_Error || level == wxLOG_FatalError ) )
1522 bool watcherHasError =
false;
1523 WatcherLogHandler tmpLog( &watcherHasError );
1524 wxLog* oldLog = wxLog::SetActiveTarget( &tmpLog );
1530 wxLog::SetActiveTarget( oldLog );
1532 if( watcherHasError )
1540 fn.AssignDir( prj_dir );
1541 fn.DontFollowLink();
1555 TO_UTF8( fn.GetFullPath() ) );
1563 TO_UTF8( fn.GetFullPath() ) );
1568 if( m_TreeProject->IsEmpty() )
1572 wxTreeItemIdValue cookie;
1573 wxTreeItemId root_id = m_root;
1575 std::stack < wxTreeItemId > subdirs_id;
1577 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1578 int total_watch_count = 0;
1584 if( subdirs_id.empty() )
1590 root_id = subdirs_id.top();
1592 kid = m_TreeProject->GetFirstChild( root_id, cookie );
1608 if( wxFileName::IsDirReadable(
path ) )
1613 fn.AssignDir(
path );
1614 m_watcher->Add( fn );
1615 total_watch_count++;
1619 if( itemData->
IsPopulated() && m_TreeProject->GetChildrenCount( kid ) )
1620 subdirs_id.push( kid );
1624 kid = m_TreeProject->GetNextChild( root_id, cookie );
1631#if defined(DEBUG) && 1
1632 wxArrayString paths;
1633 m_watcher->GetWatchedPaths( &paths );
1636 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1655 std::unique_lock<std::mutex> lock(
m_TreeProject->GitCommon()->m_gitActionMutex, std::try_to_lock );
1657 if( !lock.owns_lock() )
1661 wxProgressDialog progress(
_(
"Please wait" ),
_(
"Waiting for Git operations to finish..." ),
1662 100,
this, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH );
1665 while ( !lock.try_lock() )
1668 std::this_thread::sleep_for( std::chrono::milliseconds(100) );
1694 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1695 wxPaintDC dc(
this );
1697 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1698 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1700 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1701 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1715 wxString dir = tree_data->
GetDir();
1719 wxLogError(
"Failed to initialize git project: project directory is empty." );
1724 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1729 _(
"The selected directory is already a Git project." ) );
1744 dlg.SetTitle(
_(
"Set default remote" ) );
1799 handler.
SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
1822 handler.
SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
1842 wxString branchName;
1851 if( retval == wxID_ADD )
1853 else if( retval != wxID_OK )
1858 std::vector<wxString> branches =
m_TreeProject->GitCommon()->GetBranchNames();
1861 if( branchIndex < 0 ||
static_cast<size_t>( branchIndex ) >= branches.size() )
1864 branchName = branches[branchIndex];
1867 wxLogTrace(
traceGit, wxS(
"onGitSwitchBranch: Switching to branch '%s'" ), branchName );
1882 wxLogTrace(
traceGit, wxS(
"onGitRemoveVCS: Git integration %s" ),
1892 std::stack<wxTreeItemId> items;
1895 while( !items.empty() )
1897 wxTreeItemId current = items.top();
1900 m_TreeProject->SetItemState( current, wxTREE_ITEMSTATE_NONE );
1902 wxTreeItemIdValue cookie;
1903 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
1905 while( child.IsOk() )
1907 items.push( child );
1915 wxFileName fn(
Prj().GetProjectPath() );
1932 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Updating git status icons" ) );
1935 if( !lock.owns_lock() )
1937 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Failed to acquire lock for git status icon update" ) );
1944 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git is disabled or tree control is null" ) );
1948 std::stack<wxTreeItemId> items;
1951 while( !items.empty() )
1953 wxTreeItemId current = items.top();
1958 wxTreeItemIdValue cookie;
1959 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
1961 while( child.IsOk() )
1963 items.push( child );
1967 m_TreeProject->SetItemState( child,
static_cast<int>( it->second ) );
1982 wxString filename = wxFileNameFromPath( rootItem->
GetFileName() );
1988 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git status icons updated" ) );
1994 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Updating tree cache" ) );
1998 if( !lock.owns_lock() )
2000 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Failed to acquire lock for tree cache update" ) );
2006 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Tree control is null" ) );
2017 std::stack<wxTreeItemId> items;
2020 while( !items.empty() )
2032 gitAbsPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2036 wxTreeItemIdValue cookie;
2037 wxTreeItemId child =
m_TreeProject->GetFirstChild( kid, cookie );
2039 while( child.IsOk() )
2041 items.push( child );
2050 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updating git status icons" ) );
2051#if defined( _WIN32 )
2074 if( !lock1.owns_lock() || !lock2.owns_lock() )
2076 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire locks for git status icon update" ) );
2082 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: No git repository found" ) );
2088 std::unique_lock<std::mutex> gitLock(
m_TreeProject->GitCommon()->m_gitActionMutex, std::try_to_lock );
2090 if( !gitLock.owns_lock() )
2092 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire git action mutex" ) );
2099 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Cancelled" ) );
2106 wxFileName rootFilename(
Prj().GetProjectFullName() );
2109 wxFileName relative = rootFilename;
2110 relative.MakeRelativeTo( repoWorkDir );
2111 wxString pathspecStr = relative.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
2114 pathspecStr.Replace( wxS(
"\\" ), wxS(
"/" ) );
2118 auto fileStatusMap = statusHandler.
GetFileStatus( pathspecStr );
2119 auto [localChanges, remoteChanges] =
m_TreeProject->GitCommon()->GetDifferentFiles();
2122 bool updated =
false;
2125 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2130 wxLogTrace(
traceGit, wxS(
"File '%s' not found in tree cache" ), absPath );
2134 auto [it, inserted] =
m_gitStatusIcons.try_emplace( iter->second, fileStatus.status );
2135 if( inserted || it->second != fileStatus.status )
2137 it->second = fileStatus.status;
2143 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updated git status icons" ) );
2163 if( repo ==
nullptr )
2165 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2177 std::map<wxString, int> modifiedFiles;
2178 std::set<wxString> selected_files;
2183 selected_files.emplace( item->GetFileName() );
2188 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2198 wxFileName fn( absPath );
2201 wxString relativePath = absPath;
2202 if( relativePath.StartsWith( repoWorkDir ) )
2204 relativePath = relativePath.Mid( repoWorkDir.length() );
2206 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2212 if( !absPath.StartsWith( projectPath ) )
2227 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2232 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2234 else if( selected_files.count( absPath ) )
2236 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2245 if( ret != wxID_OK )
2252 wxMessageBox(
_(
"Discarding commit due to empty commit message." ) );
2258 wxMessageBox(
_(
"Discarding commit due to empty file selection." ) );
2268 wxMessageBox( wxString::Format(
_(
"Failed to create commit: %s" ),
2273 wxLogTrace(
traceGit, wxS(
"Created commit" ) );
2293 for(
const auto& [filePath, fileStatus] : fileStatusMap )
2295 if( filePath.EndsWith( aFile ) || filePath == aFile )
2309 wxLogTrace(
traceGit,
"Syncing project" );
2314 wxLogTrace(
traceGit,
"sync: No git repository found" );
2381 wxLogTrace(
traceGit,
"onGitSyncTimer" );
2389 tp.detach_task( [
this]()
2395 wxLogTrace(
traceGit,
"onGitSyncTimer: No git repository found" );
2402 wxLogTrace(
traceGit,
"onGitSyncTimer: Cancelled" );
2416 wxLogTrace(
traceGit,
"onGitSyncTimer: Restarting git sync timer" );
2439 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
virtual bool IsLibraryAvailable()=0
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.
PROJECT_TREE_PANE * m_leftWin
void OnChangeWatchedPaths(wxCommandEvent &aEvent)
Called by sending a event with id = ID_INIT_WATCHED_PATHS rebuild the list of watched paths.
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.
wxString GetGitRootDirectory() const
bool HasPushAndPullRemote() const
bool HasLocalCommits() const
wxString GetErrorString()
git_repository * GetRepo() const
Get a pointer to the git repository.
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.
The project local settings are things that are attached to a particular project, but also might be pa...
bool m_GitIntegrationDisabled
If true, KiCad will not use Git integration for this project even if a .git directory exists.
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
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
PROJECT_TREE_PANE(KICAD_MANAGER_FRAME *parent)
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.
virtual const wxString GetProjectPath() const
Return the full path of the project.
virtual PROJECT_LOCAL_SETTINGS & GetLocalSettings() const
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.
GIT_BACKEND * GetGitBackend()
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 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.
wxDECLARE_EVENT(wxCUSTOM_PANEL_SHOWN_EVENT, wxCommandEvent)
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[]
#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
wxString result
Test unit parsing edge cases and error handling.
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
BS::priority_thread_pool thread_pool
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.