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,
297 if( tree_data.size() != 1 )
300 wxString prj_filename = tree_data[0]->GetFileName();
302 m_Parent->LoadProject( prj_filename );
314 wxString curr_dir = item_data->GetDir();
316 if( curr_dir.IsEmpty() )
319 curr_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
322 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
325 if( !curr_dir.IsEmpty() )
326 curr_dir += wxFileName::GetPathSeparator();
341 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
344 wxString curr_dir = item_data->GetDir();
346 if( curr_dir.IsEmpty() )
349 wxString new_dir = wxGetTextFromUser(
_(
"Directory name:" ),
_(
"Create New Directory" ) );
351 if( new_dir.IsEmpty() )
354 wxString full_dirname = curr_dir + wxFileName::GetPathSeparator() + new_dir;
356 if( !wxMkdir( full_dirname ) )
404 return wxEmptyString;
410 std::vector<wxString> projects;
411 wxString dir_filename;
412 bool haveFile = dir.GetFirst( &dir_filename );
416 wxFileName file( dir_filename );
420 projects.push_back( file.GetName() );
422 haveFile = dir.GetNext( &dir_filename );
433 const wxTreeItemId& aParent,
434 std::vector<wxString>* aProjectNames,
438 wxFileName fn( aName );
441 return wxTreeItemId();
443 if( wxDirExists( aName ) )
451 bool addFile =
false;
453 for(
const wxString& m_filter :
m_filters )
455 wxCHECK2_MSG( reg.Compile( m_filter, wxRE_ICASE ),
continue,
456 wxString::Format(
"Regex %s failed to compile.", m_filter ) );
458 if( reg.Matches( aName ) )
466 return wxTreeItemId();
473 if( ext == wxT(
"" ) )
476 if( reg.Compile( wxString::FromAscii(
"^.*\\." ) + ext + wxString::FromAscii(
"$" ), wxRE_ICASE )
477 && reg.Matches( aName ) )
485 wxString file = wxFileNameFromPath( aName );
486 wxFileName currfile( file );
488 bool showAllSchematics =
m_TreeProject->GetGitRepo() !=
nullptr;
492 && ( currfile.GetName().CmpNoCase(
project.GetName() ) == 0 ) )
494 return wxTreeItemId();
503 return wxTreeItemId();
509 if( !parentTreeItem )
510 return wxTreeItemId();
512 wxDir parentDir( parentTreeItem->
GetDir() );
513 std::vector<wxString> projects =
getProjects( parentDir );
516 return wxTreeItemId();
521 wxTreeItemIdValue cookie;
522 wxTreeItemId kid =
m_TreeProject->GetFirstChild( aParent, cookie );
529 return itemData->GetId();
550 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
556 return wxTreeItemId();
562 return wxTreeItemId();
589 wxTreeItemId newItemId =
m_TreeProject->AppendItem( aParent, file );
596 wxString fileName = currfile.GetName().Lower();
597 wxString projName =
project.GetName().Lower();
599 if( fileName == projName || fileName.StartsWith( projName +
"-" ) )
603 bool subdir_populated =
false;
614 std::vector<wxString> projects =
getProjects( dir );
615 wxString dir_filename;
616 bool haveFile = dir.GetFirst( &dir_filename );
621 subdir_populated = aRecurse;
627 wxString
path = aName + wxFileName::GetPathSeparator() + dir_filename;
630 haveFile = dir.GetNext( &dir_filename );
639 if( subdir_populated )
653 while(
tp.get_tasks_running() )
655 tp.wait_for( std::chrono::milliseconds( 250 ) );
663 wxString pro_dir =
m_Parent->GetProjectFileName();
681 wxFileName fn = pro_dir;
682 bool prjReset =
false;
693 bool prjOpened = fn.FileExists();
696 if(
Pgm().GetCommonSettings()->m_Git.enableGit
697 && !
Prj().GetLocalSettings().m_GitIntegrationDisabled )
703 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
705 if( canonicalWorkDir )
708 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
712 m_TreeProject->GitCommon()->SetUsername(
Prj().GetLocalSettings().m_GitRepoUsername );
713 m_TreeProject->GitCommon()->SetSSHKey(
Prj().GetLocalSettings().m_GitSSHKey );
720 if( !prjOpened && !prjReset )
723 prjOpened = fn.FileExists();
743 pro_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
744 wxDir dir( pro_dir );
748 std::vector<wxString> projects =
getProjects( dir );
750 bool haveFile = dir.GetFirst( &filename );
754 if( filename != fn.GetFullName() )
756 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
763 haveFile = dir.GetNext( &filename );
780 wxLogTrace(
traceGit,
"PROJECT_TREE_PANE::ReCreateTreePrj: starting timers" );
799 wxTreeItemId curr_item = Event.GetItem();
806 wxFileName prj_dir(
Prj().GetProjectPath(), wxEmptyString );
808 prj_dir.Normalize( wxPATH_NORM_ABSOLUTE | wxPATH_NORM_CASE | wxPATH_NORM_DOTS
809 | wxPATH_NORM_ENV_VARS | wxPATH_NORM_TILDE );
810 git_dir.Normalize( wxPATH_NORM_ABSOLUTE | wxPATH_NORM_CASE | wxPATH_NORM_DOTS
811 | wxPATH_NORM_ENV_VARS | wxPATH_NORM_TILDE );
812 wxString prj_name = prj_dir.GetFullPath();
813 wxString git_name = git_dir.GetFullPath();
815 bool can_switch_to_project =
true;
816 bool can_create_new_directory =
true;
817 bool can_open_this_directory =
true;
818 bool can_edit =
true;
819 bool can_rename =
true;
820 bool can_delete =
true;
821 bool run_jobs =
false;
825 bool vcs_can_init = !vcs_has_repo;
828 bool vcs_can_remove = ( vcs_has_repo && git_name.StartsWith( prj_name ) ) || gitIntegrationDisabled;
831 bool vcs_can_pull = vcs_can_fetch;
832 bool vcs_can_switch = vcs_has_repo;
838 vcs_menu &= libgit_init;
840 if( selection.size() == 0 )
844 if( selection.size() != 1 )
846 can_switch_to_project =
false;
847 can_create_new_directory =
false;
856 can_switch_to_project =
false;
862 can_delete = item->CanDelete();
863 can_rename = item->CanRename();
865 switch( item->GetType() )
873 can_switch_to_project =
false;
877 can_create_new_directory =
false;
878 can_open_this_directory =
false;
883 can_switch_to_project =
false;
890 can_switch_to_project =
false;
891 can_create_new_directory =
false;
892 can_open_this_directory =
false;
905 can_switch_to_project =
false;
906 can_create_new_directory =
false;
907 can_open_this_directory =
false;
917 if( can_switch_to_project )
920 _(
"Close all editors, and switch to the selected project" ),
922 popup_menu.AppendSeparator();
925 if( can_create_new_directory )
931 if( can_open_this_directory )
933 if( selection.size() == 1 )
936 text =
_(
"Reveal in Finder" );
937 help_text =
_(
"Reveals the directory in a Finder window" );
939 text =
_(
"Open Directory in File Explorer" );
940 help_text =
_(
"Opens the directory in the default system file manager" );
946 text =
_(
"Reveal in Finder" );
947 help_text =
_(
"Reveals the directories in a Finder window" );
949 text =
_(
"Open Directories in File Explorer" );
950 help_text =
_(
"Opens the directories in the default system file manager" );
960 if( selection.size() == 1 )
961 help_text =
_(
"Open the file in a Text Editor" );
963 help_text =
_(
"Open files in a Text Editor" );
969 if( run_jobs && selection.size() == 1 )
977 if( selection.size() == 1 )
979 text =
_(
"Rename File..." );
980 help_text =
_(
"Rename file" );
984 text =
_(
"Rename Files..." );
985 help_text =
_(
"Rename files" );
994 if( selection.size() == 1 )
995 help_text =
_(
"Delete the file and its content" );
997 help_text =
_(
"Delete the files and their contents" );
999 if( can_switch_to_project
1000 || can_create_new_directory
1001 || can_open_this_directory
1005 popup_menu.AppendSeparator();
1019 wxMenu* vcs_submenu =
new wxMenu();
1020 wxMenu* branch_submenu =
new wxMenu();
1021 wxMenuItem* vcs_menuitem =
nullptr;
1024 _(
"Add Project to Version Control..." ),
1025 _(
"Initialize a new repository" ) );
1026 vcs_menuitem->Enable( vcs_can_init );
1030 _(
"Commit changes to the local repository" ) );
1031 vcs_menuitem->Enable( vcs_can_commit );
1033 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PUSH,
_(
"Push" ),
1034 _(
"Push committed local changes to remote repository" ) );
1035 vcs_menuitem->Enable( vcs_can_push );
1037 vcs_menuitem = vcs_submenu->Append(
ID_GIT_PULL,
_(
"Pull" ),
1038 _(
"Pull changes from remote repository into local" ) );
1039 vcs_menuitem->Enable( vcs_can_pull );
1041 vcs_submenu->AppendSeparator();
1044 _(
"Commit changes to the local repository" ) );
1045 vcs_menuitem->Enable( vcs_can_commit );
1047 vcs_submenu->AppendSeparator();
1053 std::vector<wxString> branchNames =
m_TreeProject->GitCommon()->GetBranchNames();
1056 for(
size_t ii = 1; ii < branchNames.size() && ii < 6; ++ii )
1058 wxString msg =
_(
"Switch to branch " ) + branchNames[ii];
1060 vcs_menuitem->Enable( vcs_can_switch );
1064 _(
"Switch to a different branch" ) );
1065 vcs_menuitem->Enable( vcs_can_switch );
1069 vcs_submenu->AppendSeparator();
1071 if( gitIntegrationDisabled )
1073 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Enable Git Integration" ),
1074 _(
"Re-enable Git integration for this project" ) );
1078 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Disable Git Integration" ),
1079 _(
"Disable Git integration for this project" ) );
1082 vcs_menuitem->Enable( vcs_can_remove );
1084 popup_menu.AppendSeparator();
1085 popup_menu.AppendSubMenu( vcs_submenu,
_(
"Version Control" ) );
1088 if( popup_menu.GetMenuItemCount() > 0 )
1089 PopupMenu( &popup_menu );
1097 if( editorname.IsEmpty() )
1099 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
1107 wxString fullFileName = item_data->GetFileName();
1109 if( !fullFileName.IsEmpty() )
1111 ExecuteFile( editorname, fullFileName.wc_str(),
nullptr,
false );
1122 item_data->Delete();
1132 if( tree_data.size() != 1 )
1136 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
1137 tree_data[0]->GetFileName() );
1138 wxTextEntryDialog dlg( wxGetTopLevelParent(
this ), msg,
_(
"Change filename" ), buffer );
1140 if( dlg.ShowModal() != wxID_OK )
1143 buffer = dlg.GetValue();
1144 buffer.Trim(
true );
1145 buffer.Trim(
false );
1147 if( buffer.IsEmpty() )
1150 tree_data[0]->Rename( buffer,
true );
1159 if( tree_data.size() != 1 )
1182 std::vector<wxTreeItemId> validItemIds;
1185 for( wxTreeItemId
id : validItemIds )
1204 wxTreeItemId itemId = Event.GetItem();
1214 wxTreeItemIdValue cookie;
1215 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
1218 bool subdir_populated =
false;
1221 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
1232 wxDir dir( fileName );
1234 if( dir.IsOpened() )
1236 std::vector<wxString> projects =
getProjects( dir );
1237 wxString dir_filename;
1238 bool haveFile = dir.GetFirst( &dir_filename );
1243 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
1246 haveFile = dir.GetNext( &dir_filename );
1252 subdir_populated =
true;
1261 if( subdir_populated )
1269 wxArrayTreeItemIds selection;
1270 std::vector<PROJECT_TREE_ITEM*> data;
1274 for(
const wxTreeItemId itemId : selection )
1280 wxLogTrace(
traceGit, wxS(
"Null tree item returned for selection, dynamic_cast failed?" ) );
1284 data.push_back( item );
1299 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1303 if( prj_dir == aSubDir )
1307 wxTreeItemIdValue cookie;
1308 wxTreeItemId root_id =
m_root;
1309 std::stack<wxTreeItemId> subdirs_id;
1311 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
1315 if( ! child.IsOk() )
1317 if( subdirs_id.empty() )
1324 root_id = subdirs_id.top();
1345 subdirs_id.push( child );
1363 if( !( event.GetChangeType() & ( wxFSW_EVENT_CREATE |
1364 wxFSW_EVENT_DELETE |
1365 wxFSW_EVENT_RENAME |
1366 wxFSW_EVENT_MODIFY ) ) )
1371 const wxFileName& pathModified =
event.GetPath();
1374 if( pathModified.GetFullPath().Contains( wxS(
".history" ) ) )
1377 wxString subdir = pathModified.GetPath();
1378 wxString fn = pathModified.GetFullPath();
1381 if( pathModified.GetFullName().IsEmpty() )
1383 subdir = subdir.BeforeLast(
'/' );
1384 fn = fn.BeforeLast(
'/' );
1389 if( !root_id.IsOk() )
1392 CallAfter( [
this] ()
1394 wxLogTrace(
traceGit, wxS(
"File system event detected, updating tree cache" ) );
1398 wxTreeItemIdValue cookie;
1399 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1401 switch( event.GetChangeType() )
1403 case wxFSW_EVENT_CREATE:
1418 case wxFSW_EVENT_DELETE:
1432 case wxFSW_EVENT_RENAME :
1434 const wxFileName& newpath =
event.GetNewPath();
1435 wxString newdir = newpath.GetPath();
1436 wxString newfn = newpath.GetFullPath();
1460 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1466 if( newitem.IsOk() )
1487 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1489#if defined( _WIN32 )
1498 m_Parent->m_FileWatcherInfo =
_(
"Network path: not monitoring folder changes" );
1504 m_Parent->m_FileWatcherInfo =
_(
"Local path: monitoring folder changes" );
1522 class WatcherLogHandler :
public wxLog
1525 explicit WatcherLogHandler(
bool* err ) :
1533 void DoLogTextAtLevel( wxLogLevel level,
const wxString&
text )
override
1535 if( m_err && ( level == wxLOG_Error || level == wxLOG_FatalError ) )
1543 bool watcherHasError =
false;
1544 WatcherLogHandler tmpLog( &watcherHasError );
1545 wxLog* oldLog = wxLog::SetActiveTarget( &tmpLog );
1551 wxLog::SetActiveTarget( oldLog );
1553 if( watcherHasError )
1561 fn.AssignDir( prj_dir );
1562 fn.DontFollowLink();
1576 TO_UTF8( fn.GetFullPath() ) );
1584 TO_UTF8( fn.GetFullPath() ) );
1589 if( m_TreeProject->IsEmpty() )
1593 wxTreeItemIdValue cookie;
1594 wxTreeItemId root_id = m_root;
1596 std::stack < wxTreeItemId > subdirs_id;
1598 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1599 int total_watch_count = 0;
1605 if( subdirs_id.empty() )
1611 root_id = subdirs_id.top();
1613 kid = m_TreeProject->GetFirstChild( root_id, cookie );
1628 if(
path.Contains( wxS(
".history" ) ) )
1630 kid = m_TreeProject->GetNextChild( root_id, cookie );
1636 if( wxFileName::IsDirReadable(
path ) )
1641 fn.AssignDir(
path );
1642 m_watcher->Add( fn );
1643 total_watch_count++;
1647 if( itemData->
IsPopulated() && m_TreeProject->GetChildrenCount( kid ) )
1648 subdirs_id.push( kid );
1652 kid = m_TreeProject->GetNextChild( root_id, cookie );
1659#if defined(DEBUG) && 1
1660 wxArrayString paths;
1661 m_watcher->GetWatchedPaths( &paths );
1664 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1683 std::unique_lock<std::mutex> lock(
m_TreeProject->GitCommon()->m_gitActionMutex, std::try_to_lock );
1685 if( !lock.owns_lock() )
1689 wxProgressDialog progress(
_(
"Please wait" ),
_(
"Waiting for Git operations to finish..." ),
1690 100,
this, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_SMOOTH );
1693 while ( !lock.try_lock() )
1696 std::this_thread::sleep_for( std::chrono::milliseconds(100) );
1722 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1723 wxPaintDC dc(
this );
1725 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1726 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1728 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1729 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1743 wxString dir = tree_data->
GetDir();
1747 wxLogError(
"Failed to initialize git project: project directory is empty." );
1752 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1757 _(
"The selected directory is already a Git project." ) );
1772 dlg.SetTitle(
_(
"Set default remote" ) );
1827 handler.
SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
1850 handler.
SetProgressReporter( std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
1870 wxString branchName;
1879 if( retval == wxID_ADD )
1881 else if( retval != wxID_OK )
1886 std::vector<wxString> branches =
m_TreeProject->GitCommon()->GetBranchNames();
1889 if( branchIndex < 0 ||
static_cast<size_t>( branchIndex ) >= branches.size() )
1892 branchName = branches[branchIndex];
1895 wxLogTrace(
traceGit, wxS(
"onGitSwitchBranch: Switching to branch '%s'" ), branchName );
1910 wxLogTrace(
traceGit, wxS(
"onGitRemoveVCS: Git integration %s" ),
1920 std::stack<wxTreeItemId> items;
1923 while( !items.empty() )
1925 wxTreeItemId current = items.top();
1928 m_TreeProject->SetItemState( current, wxTREE_ITEMSTATE_NONE );
1930 wxTreeItemIdValue cookie;
1931 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
1933 while( child.IsOk() )
1935 items.push( child );
1943 wxFileName fn(
Prj().GetProjectPath() );
1948 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
1950 if( canonicalWorkDir )
1953 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
1954 m_TreeProject->GitCommon()->SetProjectDir( symlinkWorkDir );
1969 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Updating git status icons" ) );
1972 if( !lock.owns_lock() )
1974 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Failed to acquire lock for git status icon update" ) );
1981 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git is disabled or tree control is null" ) );
1985 std::stack<wxTreeItemId> items;
1988 while( !items.empty() )
1990 wxTreeItemId current = items.top();
1995 wxTreeItemIdValue cookie;
1996 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
1998 while( child.IsOk() )
2000 items.push( child );
2004 m_TreeProject->SetItemState( child,
static_cast<int>( it->second ) );
2019 wxString filename = wxFileNameFromPath( rootItem->
GetFileName() );
2025 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git status icons updated" ) );
2031 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Updating tree cache" ) );
2035 if( !lock.owns_lock() )
2037 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Failed to acquire lock for tree cache update" ) );
2043 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Tree control is null" ) );
2054 std::stack<wxTreeItemId> items;
2057 while( !items.empty() )
2069 gitAbsPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2073 wxTreeItemIdValue cookie;
2074 wxTreeItemId child =
m_TreeProject->GetFirstChild( kid, cookie );
2076 while( child.IsOk() )
2078 items.push( child );
2087 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updating git status icons" ) );
2088#if defined( _WIN32 )
2111 if( !lock1.owns_lock() || !lock2.owns_lock() )
2113 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire locks for git status icon update" ) );
2119 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: No git repository found" ) );
2125 std::unique_lock<std::mutex> gitLock(
m_TreeProject->GitCommon()->m_gitActionMutex, std::try_to_lock );
2127 if( !gitLock.owns_lock() )
2129 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire git action mutex" ) );
2136 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Cancelled" ) );
2143 wxFileName rootFilename(
Prj().GetProjectFullName() );
2146 wxFileName relative = rootFilename;
2147 relative.MakeRelativeTo( repoWorkDir );
2148 wxString pathspecStr = relative.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
2151 pathspecStr.Replace( wxS(
"\\" ), wxS(
"/" ) );
2155 auto fileStatusMap = statusHandler.
GetFileStatus( pathspecStr );
2156 auto [localChanges, remoteChanges] =
m_TreeProject->GitCommon()->GetDifferentFiles();
2159 bool updated =
false;
2162 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2167 wxLogTrace(
traceGit, wxS(
"File '%s' not found in tree cache" ), absPath );
2171 auto [it, inserted] =
m_gitStatusIcons.try_emplace( iter->second, fileStatus.status );
2172 if( inserted || it->second != fileStatus.status )
2174 it->second = fileStatus.status;
2180 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updated git status icons" ) );
2200 if( repo ==
nullptr )
2202 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2214 std::map<wxString, int> modifiedFiles;
2215 std::set<wxString> selected_files;
2220 selected_files.emplace( item->GetFileName() );
2225 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2235 wxFileName fn( absPath );
2238 wxString relativePath = absPath;
2239 if( relativePath.StartsWith( repoWorkDir ) )
2241 relativePath = relativePath.Mid( repoWorkDir.length() );
2243 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2249 if( !absPath.StartsWith( projectPath ) )
2264 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2269 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2271 else if( selected_files.count( absPath ) )
2273 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2282 if( ret != wxID_OK )
2289 wxMessageBox(
_(
"Discarding commit due to empty commit message." ) );
2295 wxMessageBox(
_(
"Discarding commit due to empty file selection." ) );
2305 wxMessageBox( wxString::Format(
_(
"Failed to create commit: %s" ),
2310 wxLogTrace(
traceGit, wxS(
"Created commit" ) );
2330 for(
const auto& [filePath, fileStatus] : fileStatusMap )
2332 if( filePath.EndsWith( aFile ) || filePath == aFile )
2346 wxLogTrace(
traceGit,
"Syncing project" );
2351 wxLogTrace(
traceGit,
"sync: No git repository found" );
2418 wxLogTrace(
traceGit,
"onGitSyncTimer" );
2432 wxLogTrace(
traceGit,
"onGitSyncTimer: No git repository found" );
2439 wxLogTrace(
traceGit,
"onGitSyncTimer: Cancelled" );
2453 wxLogTrace(
traceGit,
"onGitSyncTimer: Restarting git sync timer" );
2476 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 wxString ComputeSymlinkPreservingWorkDir(const wxString &aUserProjectPath, const wxString &aCanonicalWorkDir)
Compute a working directory path that preserves symlinks from the user's project path.
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
std::future< void > m_gitSyncTask
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
std::future< void > m_gitStatusIconTask
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 CsvFileExtension
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.