30#include <wx/richmsgdlg.h>
31#include <wx/stdpaths.h>
34#include <wx/textdlg.h>
36#include <wx/wupdlock.h>
64#include <wx/dcclient.h>
65#include <wx/progdlg.h>
66#include <wx/settings.h>
115 wxT(
"^.*\\.kicad_pro$" ),
118 wxT(
"^.*\\.kicad_sch$" ),
119 wxT(
"^[^$].*\\.brd$" ),
120 wxT(
"^[^$].*\\.kicad_pcb$" ),
121 wxT(
"^[^$].*\\.kicad_dru$" ),
122 wxT(
"^[^$].*\\.kicad_wks$" ),
123 wxT(
"^[^$].*\\.kicad_mod$" ),
127 wxT(
"^.*\\.kicad_sym$" ),
132 wxT(
"^.*\\.gbrjob$" ),
133 wxT(
"^.*\\.gb[alops]$" ),
134 wxT(
"^.*\\.gt[alops]$" ),
135 wxT(
"^.*\\.g[0-9]{1,2}$" ),
136 wxT(
"^.*\\.gm[0-9]{1,2}$" ),
140 wxT(
"^.*\\.html$" ),
151 wxT(
"^.*\\.kicad_jobset" ),
238 wxSashLayoutWindow( parent,
ID_LEFT_FRAME, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL )
249 Bind( wxEVT_FSWATCHER,
252 Bind( wxEVT_SYS_COLOUR_CHANGED,
268 m_filters.emplace_back( wxT(
"^no KiCad files found" ) );
276 Unbind( wxEVT_FSWATCHER,
278 Unbind( wxEVT_SYS_COLOUR_CHANGED,
314 if( tree_data.size() != 1 )
317 wxString prj_filename = tree_data[0]->GetFileName();
319 m_Parent->LoadProject( prj_filename );
331 wxString curr_dir = item_data->GetDir();
333 if( curr_dir.IsEmpty() )
336 curr_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
339 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
342 if( !curr_dir.IsEmpty() )
343 curr_dir += wxFileName::GetPathSeparator();
358 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
361 wxString curr_dir = item_data->GetDir();
363 if( curr_dir.IsEmpty() )
366 wxString new_dir = wxGetTextFromUser(
_(
"Directory name:" ),
_(
"Create New Directory" ) );
368 if( new_dir.IsEmpty() )
371 wxString full_dirname = curr_dir + wxFileName::GetPathSeparator() + new_dir;
373 if( !wxMkdir( full_dirname ) )
421 return wxEmptyString;
427 std::vector<wxString> projects;
428 wxString dir_filename;
429 bool haveFile = dir.GetFirst( &dir_filename );
433 wxFileName file( dir_filename );
437 projects.push_back( file.GetName() );
439 haveFile = dir.GetNext( &dir_filename );
450 const wxTreeItemId& aParent,
451 std::vector<wxString>* aProjectNames,
455 wxFileName fn( aName );
458 return wxTreeItemId();
460 if( wxDirExists( aName ) )
468 bool addFile =
false;
470 for(
const wxString& m_filter :
m_filters )
472 wxCHECK2_MSG( reg.Compile( m_filter, wxRE_ICASE ),
continue,
473 wxString::Format(
"Regex %s failed to compile.", m_filter ) );
475 if( reg.Matches( aName ) )
483 return wxTreeItemId();
490 if( ext == wxT(
"" ) )
493 if( reg.Compile( wxString::FromAscii(
"^.*\\." ) + ext + wxString::FromAscii(
"$" ), wxRE_ICASE )
494 && reg.Matches( aName ) )
502 wxString file = wxFileNameFromPath( aName );
503 wxFileName currfile( file );
505 bool showAllSchematics =
m_TreeProject->GetGitRepo() !=
nullptr;
509 && ( currfile.GetName().CmpNoCase(
project.GetName() ) == 0 ) )
511 return wxTreeItemId();
520 return wxTreeItemId();
526 if( !parentTreeItem )
527 return wxTreeItemId();
529 wxDir parentDir( parentTreeItem->
GetDir() );
530 std::vector<wxString> projects =
getProjects( parentDir );
533 return wxTreeItemId();
538 wxTreeItemIdValue cookie;
539 wxTreeItemId kid =
m_TreeProject->GetFirstChild( aParent, cookie );
546 return itemData->GetId();
567 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
573 return wxTreeItemId();
579 return wxTreeItemId();
606 wxTreeItemId newItemId =
m_TreeProject->AppendItem( aParent, file );
613 wxString fileName = currfile.GetName().Lower();
614 wxString projName =
project.GetName().Lower();
616 if( fileName == projName || fileName.StartsWith( projName +
"-" ) )
620 bool subdir_populated =
false;
631 std::vector<wxString> projects =
getProjects( dir );
632 wxString dir_filename;
633 bool haveFile = dir.GetFirst( &dir_filename );
638 subdir_populated = aRecurse;
644 wxString
path = aName + wxFileName::GetPathSeparator() + dir_filename;
647 haveFile = dir.GetNext( &dir_filename );
656 if( subdir_populated )
678 wxString pro_dir =
m_Parent->GetProjectFileName();
696 wxFileName fn = pro_dir;
697 bool prjReset =
false;
708 bool prjOpened = fn.FileExists();
711 if(
Pgm().GetCommonSettings()->m_Git.enableGit
712 && !
Prj().GetLocalSettings().m_GitIntegrationDisabled )
722 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
724 if( canonicalWorkDir )
727 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
731 m_TreeProject->GitCommon()->SetUsername(
Prj().GetLocalSettings().m_GitRepoUsername );
732 m_TreeProject->GitCommon()->SetSSHKey(
Prj().GetLocalSettings().m_GitSSHKey );
739 if( !prjOpened && !prjReset )
742 prjOpened = fn.FileExists();
762 pro_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
763 wxDir dir( pro_dir );
767 std::vector<wxString> projects =
getProjects( dir );
769 bool haveFile = dir.GetFirst( &filename );
773 if( filename != fn.GetFullName() )
775 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
782 haveFile = dir.GetNext( &filename );
799 wxLogTrace(
traceGit,
"PROJECT_TREE_PANE::ReCreateTreePrj: starting timers" );
818 wxTreeItemId curr_item = Event.GetItem();
826 bool can_switch_to_project =
true;
827 bool can_create_new_directory =
true;
828 bool can_open_this_directory =
true;
829 bool can_edit =
true;
830 bool can_rename =
true;
831 bool can_delete =
true;
832 bool run_jobs =
false;
836 bool vcs_can_init = !vcs_has_repo;
837 bool vcs_can_set_remote = vcs_has_repo;
838 bool vcs_can_amend = vcs_has_repo && git_repository_head_unborn(
m_TreeProject->GetGitRepo() ) == 0;
842 bool vcs_can_remove = vcs_has_repo || gitIntegrationDisabled;
845 bool vcs_can_pull = vcs_can_fetch;
846 bool vcs_can_switch = vcs_has_repo;
852 vcs_menu &= libgit_init;
854 if( selection.size() == 0 )
858 if( selection.size() != 1 )
860 can_switch_to_project =
false;
861 can_create_new_directory =
false;
870 can_switch_to_project =
false;
876 can_delete = item->CanDelete();
877 can_rename = item->CanRename();
879 switch( item->GetType() )
887 can_switch_to_project =
false;
891 can_create_new_directory =
false;
892 can_open_this_directory =
false;
897 can_switch_to_project =
false;
904 can_switch_to_project =
false;
905 can_create_new_directory =
false;
906 can_open_this_directory =
false;
919 can_switch_to_project =
false;
920 can_create_new_directory =
false;
921 can_open_this_directory =
false;
931 if( can_switch_to_project )
934 _(
"Close all editors, and switch to the selected project" ),
936 popup_menu.AppendSeparator();
939 if( can_create_new_directory )
945 if( can_open_this_directory )
947 if( selection.size() == 1 )
950 text =
_(
"Reveal in Finder" );
951 help_text =
_(
"Reveals the directory in a Finder window" );
953 text =
_(
"Open Directory in File Explorer" );
954 help_text =
_(
"Opens the directory in the default system file manager" );
960 text =
_(
"Reveal in Finder" );
961 help_text =
_(
"Reveals the directories in a Finder window" );
963 text =
_(
"Open Directories in File Explorer" );
964 help_text =
_(
"Opens the directories in the default system file manager" );
974 if( selection.size() == 1 )
975 help_text =
_(
"Open the file in a Text Editor" );
977 help_text =
_(
"Open files in a Text Editor" );
983 if( run_jobs && selection.size() == 1 )
991 if( selection.size() == 1 )
993 text =
_(
"Rename File..." );
994 help_text =
_(
"Rename file" );
998 text =
_(
"Rename Files..." );
999 help_text =
_(
"Rename files" );
1008 if( selection.size() == 1 )
1009 help_text =
_(
"Delete the file and its content" );
1011 help_text =
_(
"Delete the files and their contents" );
1013 if( can_switch_to_project
1014 || can_create_new_directory
1015 || can_open_this_directory
1019 popup_menu.AppendSeparator();
1033 wxMenu* vcs_submenu =
new wxMenu();
1034 wxMenu* branch_submenu =
new wxMenu();
1035 wxMenuItem* vcs_menuitem =
nullptr;
1038 _(
"Add Project to Version Control..." ),
1039 _(
"Initialize a new repository" ) );
1040 vcs_menuitem->Enable( vcs_can_init );
1043 _(
"Set or change the default remote URL and credentials" ) );
1044 vcs_menuitem->Enable( vcs_can_set_remote );
1047 _(
"Commit changes to the local repository" ) );
1048 vcs_menuitem->Enable( vcs_can_commit );
1051 _(
"Rewrite the most recent commit on the current branch" ) );
1052 vcs_menuitem->Enable( vcs_can_amend );
1054 wxString pushLabel =
_(
"Push" );
1055 wxString pullLabel =
_(
"Pull" );
1064 vcs_submenu->Append(
ID_GIT_PUSH, pushLabel,
_(
"Push committed local changes to remote repository" ) );
1065 vcs_menuitem->Enable( vcs_can_push );
1068 vcs_submenu->Append(
ID_GIT_PULL, pullLabel,
_(
"Pull changes from remote repository into local" ) );
1069 vcs_menuitem->Enable( vcs_can_pull );
1071 vcs_submenu->AppendSeparator();
1074 _(
"Commit changes to the local repository" ) );
1075 vcs_menuitem->Enable( vcs_can_commit );
1077 vcs_submenu->AppendSeparator();
1083 std::vector<wxString> branchNames =
m_TreeProject->GitCommon()->GetBranchNames();
1086 for(
size_t ii = 1; ii < branchNames.size() && ii < 6; ++ii )
1088 wxString msg =
_(
"Switch to branch " ) + branchNames[ii];
1090 vcs_menuitem->Enable( vcs_can_switch );
1094 _(
"Switch to a different branch" ) );
1095 vcs_menuitem->Enable( vcs_can_switch );
1099 vcs_submenu->AppendSeparator();
1101 if( gitIntegrationDisabled )
1103 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Enable Git Integration" ),
1104 _(
"Re-enable Git integration for this project" ) );
1108 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Disable Git Integration" ),
1109 _(
"Disable Git integration for this project" ) );
1112 vcs_menuitem->Enable( vcs_can_remove );
1114 popup_menu.AppendSeparator();
1115 popup_menu.AppendSubMenu( vcs_submenu,
_(
"Version Control" ) );
1118 if( popup_menu.GetMenuItemCount() > 0 )
1119 PopupMenu( &popup_menu );
1127 if( editorname.IsEmpty() )
1129 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
1137 wxString fullFileName = item_data->GetFileName();
1139 if( !fullFileName.IsEmpty() )
1141 ExecuteFile( editorname, fullFileName.wc_str(),
nullptr,
false );
1152 item_data->Delete();
1162 if( tree_data.size() != 1 )
1166 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
1167 tree_data[0]->GetFileName() );
1168 wxTextEntryDialog dlg( wxGetTopLevelParent(
this ), msg,
_(
"Change filename" ), buffer );
1170 if( dlg.ShowModal() != wxID_OK )
1173 buffer = dlg.GetValue();
1174 buffer.Trim(
true );
1175 buffer.Trim(
false );
1177 if( buffer.IsEmpty() )
1180 tree_data[0]->Rename( buffer,
true );
1189 if( tree_data.size() != 1 )
1212 std::vector<wxTreeItemId> validItemIds;
1215 for( wxTreeItemId
id : validItemIds )
1234 wxTreeItemId itemId = Event.GetItem();
1244 wxTreeItemIdValue cookie;
1245 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
1248 bool subdir_populated =
false;
1251 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
1262 wxDir dir( fileName );
1264 if( dir.IsOpened() )
1266 std::vector<wxString> projects =
getProjects( dir );
1267 wxString dir_filename;
1268 bool haveFile = dir.GetFirst( &dir_filename );
1273 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
1276 haveFile = dir.GetNext( &dir_filename );
1282 subdir_populated =
true;
1291 if( subdir_populated )
1299 wxArrayTreeItemIds selection;
1300 std::vector<PROJECT_TREE_ITEM*> data;
1304 for(
const wxTreeItemId itemId : selection )
1310 wxLogTrace(
traceGit, wxS(
"Null tree item returned for selection, dynamic_cast failed?" ) );
1314 data.push_back( item );
1329 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1333 if( prj_dir == aSubDir )
1337 wxTreeItemIdValue cookie;
1338 wxTreeItemId root_id =
m_root;
1339 std::stack<wxTreeItemId> subdirs_id;
1341 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
1345 if( ! child.IsOk() )
1347 if( subdirs_id.empty() )
1354 root_id = subdirs_id.top();
1375 subdirs_id.push( child );
1393 if( !( event.GetChangeType() & ( wxFSW_EVENT_CREATE |
1394 wxFSW_EVENT_DELETE |
1395 wxFSW_EVENT_RENAME |
1396 wxFSW_EVENT_MODIFY ) ) )
1401 const wxFileName& pathModified =
event.GetPath();
1404 if( pathModified.GetFullPath().Contains( wxS(
".history" ) ) )
1407 wxString subdir = pathModified.GetPath();
1408 wxString fn = pathModified.GetFullPath();
1411 if( pathModified.GetFullName().IsEmpty() )
1413 subdir = subdir.BeforeLast(
'/' );
1414 fn = fn.BeforeLast(
'/' );
1419 if( !root_id.IsOk() )
1422 CallAfter( [
this] ()
1424 wxLogTrace(
traceGit, wxS(
"File system event detected, updating tree cache" ) );
1428 wxTreeItemIdValue cookie;
1429 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1431 switch( event.GetChangeType() )
1433 case wxFSW_EVENT_CREATE:
1448 case wxFSW_EVENT_DELETE:
1462 case wxFSW_EVENT_RENAME :
1464 const wxFileName& newpath =
event.GetNewPath();
1465 wxString newdir = newpath.GetPath();
1466 wxString newfn = newpath.GetFullPath();
1490 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1496 if( newitem.IsOk() )
1517 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1519#if defined( _WIN32 )
1528 m_Parent->m_FileWatcherInfo =
_(
"Network path: not monitoring folder changes" );
1534 m_Parent->m_FileWatcherInfo =
_(
"Local path: monitoring folder changes" );
1552 class WatcherLogHandler :
public wxLog
1555 explicit WatcherLogHandler(
bool* err ) :
1563 void DoLogTextAtLevel( wxLogLevel level,
const wxString&
text )
override
1565 if( m_err && ( level == wxLOG_Error || level == wxLOG_FatalError ) )
1573 bool watcherHasError =
false;
1574 WatcherLogHandler tmpLog( &watcherHasError );
1575 wxLog* oldLog = wxLog::SetActiveTarget( &tmpLog );
1581 wxLog::SetActiveTarget( oldLog );
1583 if( watcherHasError )
1591 fn.AssignDir( prj_dir );
1592 fn.DontFollowLink();
1606 TO_UTF8( fn.GetFullPath() ) );
1614 TO_UTF8( fn.GetFullPath() ) );
1619 if( m_TreeProject->IsEmpty() )
1623 wxTreeItemIdValue cookie;
1624 wxTreeItemId root_id = m_root;
1626 std::stack < wxTreeItemId > subdirs_id;
1628 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1629 int total_watch_count = 0;
1635 if( subdirs_id.empty() )
1641 root_id = subdirs_id.top();
1643 kid = m_TreeProject->GetFirstChild( root_id, cookie );
1658 if(
path.Contains( wxS(
".history" ) ) )
1660 kid = m_TreeProject->GetNextChild( root_id, cookie );
1666 if( wxFileName::IsDirReadable(
path ) )
1671 fn.AssignDir(
path );
1672 m_watcher->Add( fn );
1673 total_watch_count++;
1677 if( itemData->
IsPopulated() && m_TreeProject->GetChildrenCount( kid ) )
1678 subdirs_id.push( kid );
1682 kid = m_TreeProject->GetNextChild( root_id, cookie );
1689#if defined(DEBUG) && 1
1690 wxArrayString paths;
1691 m_watcher->GetWatchedPaths( &paths );
1694 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1712 std::unique_lock<std::mutex> lock( common->
m_gitActionMutex, std::try_to_lock );
1714 constexpr auto kGraceMs = std::chrono::seconds( 2 );
1715 auto graceEnd = std::chrono::steady_clock::now() + kGraceMs;
1717 while( !lock.owns_lock() && std::chrono::steady_clock::now() < graceEnd )
1719 if( lock.try_lock() )
1721 std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
1724 constexpr auto kCheckInterval = std::chrono::seconds( 30 );
1725 bool userAbandoned =
false;
1727 while( !lock.owns_lock() && !userAbandoned )
1729 auto intervalEnd = std::chrono::steady_clock::now() + kCheckInterval;
1732 wxProgressDialog progress(
_(
"Please wait" ),
1733 _(
"Closing project..." ),
1735 wxPD_APP_MODAL | wxPD_SMOOTH );
1737 while( !lock.try_lock()
1738 && std::chrono::steady_clock::now() < intervalEnd )
1741 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
1746 if( lock.owns_lock() )
1749 wxMessageDialog ask(
this,
1750 _(
"A Git operation is still running.\n"
1751 "Keep waiting, or abandon?" ),
1752 _(
"Git Operation Delayed" ),
1753 wxYES_NO | wxICON_QUESTION );
1754 ask.SetYesNoLabels(
_(
"Keep Waiting" ),
_(
"Abandon" ) );
1756 if( ask.ShowModal() == wxID_NO )
1757 userAbandoned =
true;
1763 std::unique_ptr<KIGIT_COMMON> oldCommon =
m_TreeProject->TakeGitCommon();
1773 wxString projectDir = oldCommon ? oldCommon->GetProjectDir() : wxString();
1775 auto cleanup = [orphan, old = std::move( oldCommon )]()
mutable
1777 std::lock_guard<std::mutex> g( old->m_gitActionMutex );
1778 git_repository_free( orphan );
1785 std::string label =
"abandon close " + projectDir.ToStdString();
1822 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1823 wxPaintDC dc(
this );
1825 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1826 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1828 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1829 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1872 wxString dir = tree_data->
GetDir();
1876 wxLogError(
"Failed to initialize git project: project directory is empty." );
1881 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1886 _(
"The selected directory is already a Git project." ) );
1902 const char* canonicalWorkDir = git_repository_workdir( initHandler.
GetRepo() );
1904 if( canonicalWorkDir )
1907 dir, wxString::FromUTF8( canonicalWorkDir ) );
1908 m_TreeProject->GitCommon()->SetProjectDir( symlinkWorkDir );
1912 dlg.SetTitle(
_(
"Set default remote" ) );
1943 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
1970 git_repository* repo = common ? common->
GetRepo() :
nullptr;
1975 wxString existingURL;
1976 git_remote* remote =
nullptr;
1978 if( git_remote_lookup( &remote, repo,
"origin" ) == GIT_OK )
1982 if(
const char* url = git_remote_url( remote ) )
1983 existingURL = wxString::FromUTF8( url );
1986 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1988 dlg.SetTitle(
_(
"Configure Default Remote" ) );
2045 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
2054 switch( pullResult )
2058 : wxString::Format(
_(
"Already up to date with %s." ), upstream ) );
2063 upstream.empty() || branch.empty()
2064 ?
_(
"Pulled changes (fast-forward)." )
2065 : wxString::Format(
_(
"Pulled %s into %s (fast-forward)." ), upstream, branch ) );
2070 ?
_(
"Pulled changes." )
2071 : wxString::Format(
_(
"Pulled %s into %s." ), upstream, branch ) );
2080 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2081 _(
"Your local changes and the remote changes conflict, so the pull was "
2082 "cancelled and nothing was changed.\n\n"
2083 "You can discard your local commits and use the remote version, or "
2084 "rebase your commits on top of the remote." ),
2085 _(
"Pull Conflict" ),
2086 wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING | wxCENTER );
2088 dlg.SetYesNoCancelLabels(
_(
"&Use Remote (discard my changes)" ),
_(
"&Rebase" ),
_(
"Cancel" ) );
2090 int choice = dlg.ShowModal();
2092 if( choice == wxID_YES )
2099 else if( choice == wxID_NO )
2144 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
2154 ?
_(
"Pushed to remote." )
2155 : wxString::Format(
_(
"Pushed %s to %s." ), branch, upstream ) );
2166 wxRichMessageDialog dlg(
2167 wxGetTopLevelParent(
this ),
2168 wxString::Format(
_(
"Push rejected: your local branch and %s have diverged.\n\n"
2169 "This usually happens after amending or rewriting a commit "
2170 "that was already pushed. Force push to overwrite the remote?\n\n"
2171 "Anyone who already pulled the previous version will need to "
2172 "reset their copy." ),
2173 upstream.empty() ? wxString(
"the remote" ) : upstream ),
2174 _(
"Force Push?" ), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING | wxCENTER );
2176 dlg.SetYesNoLabels(
_(
"&Force Push" ),
_(
"Cancel" ) );
2178 if( dlg.ShowModal() == wxID_YES )
2200 wxString branchName;
2209 if( retval == wxID_ADD )
2211 else if( retval != wxID_OK )
2216 std::vector<wxString> branches =
m_TreeProject->GitCommon()->GetBranchNames();
2219 if( branchIndex < 0 ||
static_cast<size_t>( branchIndex ) >= branches.size() )
2222 branchName = branches[branchIndex];
2225 wxLogTrace(
traceGit, wxS(
"onGitSwitchBranch: Switching to branch '%s'" ), branchName );
2244 wxLogTrace(
traceGit, wxS(
"onGitRemoveVCS: Git integration %s" ),
2254 std::stack<wxTreeItemId> items;
2257 while( !items.empty() )
2259 wxTreeItemId current = items.top();
2262 m_TreeProject->SetItemState( current, wxTREE_ITEMSTATE_NONE );
2264 wxTreeItemIdValue cookie;
2265 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
2267 while( child.IsOk() )
2269 items.push( child );
2277 wxFileName fn(
Prj().GetProjectPath() );
2284 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
2286 if( canonicalWorkDir )
2289 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
2290 m_TreeProject->GitCommon()->SetProjectDir( symlinkWorkDir );
2305 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Updating git status icons" ) );
2308 if( !lock.owns_lock() )
2310 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Failed to acquire lock for git status icon update" ) );
2317 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git is disabled or tree control is null" ) );
2321 std::stack<wxTreeItemId> items;
2324 while( !items.empty() )
2326 wxTreeItemId current = items.top();
2331 wxTreeItemIdValue cookie;
2332 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
2334 while( child.IsOk() )
2336 items.push( child );
2340 m_TreeProject->SetItemState( child,
static_cast<int>( it->second ) );
2355 wxString filename = wxFileNameFromPath( rootItem->
GetFileName() );
2361 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git status icons updated" ) );
2367 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Updating tree cache" ) );
2371 if( !lock.owns_lock() )
2373 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Failed to acquire lock for tree cache update" ) );
2379 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Tree control is null" ) );
2390 std::stack<wxTreeItemId> items;
2393 while( !items.empty() )
2405 gitAbsPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2409 wxTreeItemIdValue cookie;
2410 wxTreeItemId child =
m_TreeProject->GetFirstChild( kid, cookie );
2412 while( child.IsOk() )
2414 items.push( child );
2423 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updating git status icons" ) );
2424#if defined( _WIN32 )
2447 if( !lock1.owns_lock() || !lock2.owns_lock() )
2449 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire locks for git status icon update" ) );
2455 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: No git repository found" ) );
2461 std::unique_lock<std::mutex> gitLock(
m_TreeProject->GitCommon()->m_gitActionMutex, std::try_to_lock );
2463 if( !gitLock.owns_lock() )
2465 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire git action mutex" ) );
2472 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Cancelled" ) );
2479 wxFileName rootFilename(
Prj().GetProjectFullName() );
2482 wxFileName relative = rootFilename;
2483 relative.MakeRelativeTo( repoWorkDir );
2484 wxString pathspecStr = relative.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
2487 pathspecStr.Replace( wxS(
"\\" ), wxS(
"/" ) );
2491 auto fileStatusMap = statusHandler.
GetFileStatus( pathspecStr );
2492 auto [localChanges, remoteChanges] =
m_TreeProject->GitCommon()->GetDifferentFiles();
2495 bool updated =
false;
2498 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2503 wxLogTrace(
traceGit, wxS(
"File '%s' not found in tree cache" ), absPath );
2507 auto [it, inserted] =
m_gitStatusIcons.try_emplace( iter->second, fileStatus.status );
2508 if( inserted || it->second != fileStatus.status )
2510 it->second = fileStatus.status;
2522 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updated git status icons" ) );
2542 if( repo ==
nullptr )
2544 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2558 const DirtyEditor candidates[] = {
2563 std::vector<const DirtyEditor*> dirty;
2565 for(
const DirtyEditor& d : candidates )
2570 dirty.push_back( &d );
2573 if( !dirty.empty() )
2577 for(
const DirtyEditor* d : dirty )
2578 listed += wxString::Format( wxS(
"\n • %s" ), d->label );
2580 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2581 wxString::Format(
_(
"The following editors have unsaved changes:%s\n\n"
2582 "Save them before committing?" ),
2584 _(
"Unsaved Changes" ),
2585 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
2587 dlg.SetYesNoCancelLabels(
_(
"&Save and Commit" ),
_(
"Commit &Anyway" ),
_(
"Cancel" ) );
2589 int answer = dlg.ShowModal();
2591 if( answer == wxID_CANCEL )
2594 if( answer == wxID_YES )
2596 for(
const DirtyEditor* d : dirty )
2598 std::string payload;
2599 m_Parent->Kiway().ExpressMail( d->frameType, d->saveMail, payload );
2601 if( payload !=
"success" )
2604 wxString::Format(
_(
"Could not save %s." ), d->label ) );
2611 m_Parent->GetSettingsManager()->SaveProject();
2622 std::map<wxString, int> modifiedFiles;
2623 std::set<wxString> selected_files;
2630 wxString itemPath = item->GetFileName();
2632 itemPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2634 selected_files.emplace( itemPath );
2641 projectPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2644 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2654 wxFileName fn( absPath );
2657 wxString relativePath = absPath;
2658 if( relativePath.StartsWith( repoWorkDir ) )
2660 relativePath = relativePath.Mid( repoWorkDir.length() );
2662 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2667 if( !absPath.StartsWith( projectPath ) )
2682 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2686 if( fn.IsDir() && fn.GetDirs().Last().StartsWith( wxS(
".history" ) ) )
2701 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2703 else if( selected_files.count( absPath ) )
2705 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2714 if( ret != wxID_OK )
2721 wxMessageBox(
_(
"Discarding commit due to empty commit message." ) );
2727 wxMessageBox(
_(
"Discarding commit due to empty file selection." ) );
2737 wxMessageBox( wxString::Format(
_(
"Failed to create commit: %s" ),
2742 wxLogTrace(
traceGit, wxS(
"Created commit" ) );
2751 if( repo ==
nullptr )
2753 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2762 git_repository_free( repo );
2766 if( git_repository_head_unborn( repo ) != 0 )
2768 DisplayErrorMessage( wxGetTopLevelParent(
this ),
_(
"Cannot amend: the branch has no commits yet." ) );
2774 git_reference* headRef =
nullptr;
2776 if( git_repository_head( &headRef, repo ) != GIT_OK )
2780 git_commit* headCommit =
nullptr;
2782 if( git_reference_peel( (git_object**) &headCommit, headRef, GIT_OBJECT_COMMIT ) != GIT_OK )
2786 wxString headMessage = wxString::FromUTF8( git_commit_message( headCommit ) );
2787 const git_oid* headOid = git_commit_id( headCommit );
2791 bool headIsPublished =
false;
2792 git_reference* upstreamRef =
nullptr;
2794 if( git_branch_upstream( &upstreamRef, headRef ) == GIT_OK )
2797 git_oid upstreamOid;
2799 if( git_reference_name_to_id( &upstreamOid, repo, git_reference_name( upstreamRef ) ) == GIT_OK )
2801 headIsPublished = git_oid_equal( headOid, &upstreamOid )
2802 || git_graph_descendant_of( repo, &upstreamOid, headOid ) == 1;
2806 if( headIsPublished )
2808 wxString upstreamName =
m_TreeProject->GitCommon()->GetUpstreamShorthand();
2810 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2811 wxString::Format(
_(
"The last commit has already been pushed to %s.\n\n"
2812 "Amending rewrites public history. Anyone who pulled "
2813 "this commit will need to reset their copy." ),
2815 _(
"Amend Published Commit?" ), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING | wxCENTER );
2817 dlg.SetYesNoLabels(
_(
"Amend &Anyway" ),
_(
"Cancel" ) );
2819 if( dlg.ShowModal() != wxID_YES )
2833 const DirtyEditor candidates[] = {
2838 std::vector<const DirtyEditor*> dirty;
2840 for(
const DirtyEditor& d : candidates )
2845 dirty.push_back( &d );
2848 if( !dirty.empty() )
2852 for(
const DirtyEditor* d : dirty )
2853 listed += wxString::Format( wxS(
"\n • %s" ), d->label );
2855 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2856 wxString::Format(
_(
"The following editors have unsaved changes:%s\n\n"
2857 "Save them before amending?" ),
2859 _(
"Unsaved Changes" ),
2860 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
2862 dlg.SetYesNoCancelLabels(
_(
"&Save and Amend" ),
_(
"Amend &Anyway" ),
_(
"Cancel" ) );
2864 int answer = dlg.ShowModal();
2866 if( answer == wxID_CANCEL )
2869 if( answer == wxID_YES )
2871 for(
const DirtyEditor* d : dirty )
2873 std::string payload;
2874 m_Parent->Kiway().ExpressMail( d->frameType, d->saveMail, payload );
2876 if( payload !=
"success" )
2879 wxString::Format(
_(
"Could not save %s." ), d->label ) );
2886 m_Parent->GetSettingsManager()->SaveProject();
2899 projectPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2902 std::map<wxString, int> modifiedFiles;
2904 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2913 wxFileName fn( absPath );
2914 wxString relativePath = absPath;
2916 if( relativePath.StartsWith( repoWorkDir ) )
2918 relativePath = relativePath.Mid( repoWorkDir.length() );
2920 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2924 if( !absPath.StartsWith( projectPath ) )
2935 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2938 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2941 if( git_reference* headRefForDiff =
nullptr; git_repository_head( &headRefForDiff, repo ) == GIT_OK )
2944 git_commit* lastCommit =
nullptr;
2946 if( git_reference_peel( (git_object**) &lastCommit, headRefForDiff, GIT_OBJECT_COMMIT ) == GIT_OK )
2949 git_commit* parentCommit =
nullptr;
2950 git_tree* parentTree =
nullptr;
2951 git_tree* lastTree =
nullptr;
2953 if( git_commit_parentcount( lastCommit ) > 0
2954 && git_commit_parent( &parentCommit, lastCommit, 0 ) == GIT_OK )
2956 git_commit_tree( &parentTree, parentCommit );
2962 if( git_commit_tree( &lastTree, lastCommit ) == GIT_OK )
2965 git_diff* diff =
nullptr;
2967 if( git_diff_tree_to_tree( &diff, repo, parentTree, lastTree,
nullptr ) == GIT_OK )
2971 for(
size_t ii = 0; ii < git_diff_num_deltas( diff ); ++ii )
2973 const git_diff_delta*
delta = git_diff_get_delta( diff, ii );
2979 int flag = GIT_STATUS_INDEX_MODIFIED;
2981 if(
delta->status == GIT_DELTA_ADDED )
2982 flag = GIT_STATUS_INDEX_NEW;
2983 else if(
delta->status == GIT_DELTA_DELETED )
2984 flag = GIT_STATUS_INDEX_DELETED;
2986 modifiedFiles[wxString::FromUTF8(
path )] |=
flag;
2995 dlg.SetTitle(
_(
"Amend Last Commit" ) );
3003 wxMessageBox(
_(
"Discarding amend due to empty commit message." ) );
3013 wxMessageBox( wxString::Format(
_(
"Failed to amend commit: %s" ), commitHandler.
GetErrorString() ) );
3017 wxLogTrace(
traceGit, wxS(
"Amended commit" ) );
3037 for(
const auto& [filePath, fileStatus] : fileStatusMap )
3039 if( filePath.EndsWith( aFile ) || filePath == aFile )
3053 wxLogTrace(
traceGit,
"Syncing project" );
3058 wxLogTrace(
traceGit,
"sync: No git repository found" );
3085 : wxString::Format(
_(
"Fetched from %s." ), remoteName ) );
3144 wxLogTrace(
traceGit,
"onGitSyncTimer" );
3158 wxLogTrace(
traceGit,
"onGitSyncTimer: No git repository found" );
3165 wxLogTrace(
traceGit,
"onGitSyncTimer: Cancelled" );
3179 wxLogTrace(
traceGit,
"onGitSyncTimer: Restarting git sync timer" );
3202 wxLogTrace(
traceGit,
"onGitStatusTimer" );
3215 sb->SetEllipsedTextField( aText, 0 );
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
void SetCommitMessage(const wxString &aMessage)
Pre-fill the commit message.
wxString GetAuthorEmail() const
std::vector< wxString > GetSelectedFiles() const
wxString GetAuthorName() const
KIGIT_COMMON::GIT_CONN_TYPE GetConnType() const
wxString GetPassword() const
wxString GetUsername() const
wxString GetSSHKey() const
bool SaveCredentials() 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 IsContentModified() const
Get if the contents of the frame have been modified since the last save.
virtual bool IsLibraryAvailable()=0
KIGIT_ORPHAN_REGISTRY & OrphanRegistry()
Return the process-wide orphan thread registry owned by this backend.
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
CommitResult PerformAmend(const std::vector< wxString > &aFiles, const wxString &aMessage, const wxString &aAuthorName, const wxString &aAuthorEmail)
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)
PullResult RebaseOntoUpstream()
PushResult PerformPush(bool aForce=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.
void OnChangeWatchedPaths(wxCommandEvent &aEvent)
Called by sending a event with id = ID_INIT_WATCHED_PATHS rebuild the list of watched paths.
PROJECT_TREE_PANE * m_projectTreePane
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.
std::mutex m_gitActionMutex
const wxString & GetRemote() const
GIT_CONN_TYPE GetConnType() const
bool WasAuthFailure() const
wxString GetCurrentBranchName() const
void SetSSHKey(const wxString &aSSHKey)
void SetUsername(const wxString &aUsername)
wxString GetRemoteNameOrDefault() const
Returns GetRemotename() when non-empty, otherwise "origin".
git_repository * GetRepo() const
bool HasPushAndPullRemote() const
wxString GetUsername() const
void UpdateCurrentBranchInfo()
bool HasLocalCommits() const
wxString GetUpstreamShorthand() const
Returns the upstream shorthand for the current branch (e.g.
void SetCancelled(bool aCancel)
void SetPassword(const wxString &aPassword)
wxString GetErrorString()
bool Register(const std::string &aLabel, F &&aWork)
Spawn a tracked orphan thread running aWork.
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.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
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 showGitFeedback(const wxString &aText)
Show a short message in the project status bar after a git operation.
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.
void onGitAmendCommit(wxCommandEvent &event)
Amend (rewrite) the last commit on the current branch.
void onGitFeedbackTimer(wxTimerEvent &event)
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...
wxTimer m_gitFeedbackTimer
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 onGitRemoteSettings(wxCommandEvent &event)
Configure (or change) the default remote on an already-initialized repository.
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.
wxString m_gitCurrentUpstream
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
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
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 ProjectLocalSettingsFileExtension
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 ...
MAIL_T
The set of mail types sendable via KIWAY::ExpressMail() and supplied as the aCommand parameter to tha...
std::unique_ptr< git_tree, decltype([](git_tree *aTree) { git_tree_free(aTree); })> GitTreePtr
A unique pointer for git_tree objects with automatic cleanup.
std::unique_ptr< git_commit, decltype([](git_commit *aCommit) { git_commit_free(aCommit); })> GitCommitPtr
A unique pointer for git_commit objects with automatic cleanup.
std::unique_ptr< git_reference, decltype([](git_reference *aRef) { git_reference_free(aRef); })> GitReferencePtr
A unique pointer for git_reference objects with automatic cleanup.
std::unique_ptr< git_diff, decltype([](git_diff *aDiff) { git_diff_free(aDiff); })> GitDiffPtr
A unique pointer for git_diff objects with automatic cleanup.
std::unique_ptr< git_remote, decltype([](git_remote *aRemote) { git_remote_free(aRemote); })> GitRemotePtr
A unique pointer for git_remote objects with automatic cleanup.
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[]
static bool promptForGitCredentials(wxWindow *aParent, KIGIT_COMMON *aCommon)
#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.