26#include <wx/richmsgdlg.h>
27#include <wx/stdpaths.h>
30#include <wx/textdlg.h>
32#include <wx/wupdlock.h>
60#include <wx/dcclient.h>
61#include <wx/progdlg.h>
62#include <wx/settings.h>
112 wxT(
"^.*\\.kicad_pro$" ),
115 wxT(
"^.*\\.kicad_sch$" ),
116 wxT(
"^[^$].*\\.brd$" ),
117 wxT(
"^[^$].*\\.kicad_pcb$" ),
118 wxT(
"^[^$].*\\.kicad_dru$" ),
119 wxT(
"^[^$].*\\.kicad_wks$" ),
120 wxT(
"^[^$].*\\.kicad_mod$" ),
124 wxT(
"^.*\\.kicad_sym$" ),
129 wxT(
"^.*\\.gbrjob$" ),
130 wxT(
"^.*\\.gb[alops]$" ),
131 wxT(
"^.*\\.gt[alops]$" ),
132 wxT(
"^.*\\.g[0-9]{1,2}$" ),
133 wxT(
"^.*\\.gm[0-9]{1,2}$" ),
137 wxT(
"^.*\\.html$" ),
148 wxT(
"^.*\\.kicad_jobset" ),
235 wxSashLayoutWindow( parent,
ID_LEFT_FRAME, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL )
246 Bind( wxEVT_FSWATCHER,
249 Bind( wxEVT_SYS_COLOUR_CHANGED,
265 m_filters.emplace_back( wxT(
"^no KiCad files found" ) );
273 Unbind( wxEVT_FSWATCHER,
275 Unbind( wxEVT_SYS_COLOUR_CHANGED,
311 if( tree_data.size() != 1 )
314 wxString prj_filename = tree_data[0]->GetFileName();
316 m_Parent->LoadProject( prj_filename );
328 wxString curr_dir = item_data->GetDir();
330 if( curr_dir.IsEmpty() )
333 curr_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
336 if( curr_dir.IsEmpty() || !wxFileName::DirExists( curr_dir ) )
339 if( !curr_dir.IsEmpty() )
340 curr_dir += wxFileName::GetPathSeparator();
355 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
358 wxString curr_dir = item_data->GetDir();
360 if( curr_dir.IsEmpty() )
363 wxString new_dir = wxGetTextFromUser(
_(
"Directory name:" ),
_(
"Create New Directory" ) );
365 if( new_dir.IsEmpty() )
368 wxString full_dirname = curr_dir + wxFileName::GetPathSeparator() + new_dir;
370 if( !wxMkdir( full_dirname ) )
418 return wxEmptyString;
424 std::vector<wxString> projects;
425 wxString dir_filename;
426 bool haveFile = dir.GetFirst( &dir_filename );
430 wxFileName file( dir_filename );
434 projects.push_back( file.GetName() );
436 haveFile = dir.GetNext( &dir_filename );
447 const wxTreeItemId& aParent,
448 std::vector<wxString>* aProjectNames,
452 wxFileName fn( aName );
455 return wxTreeItemId();
457 if( wxDirExists( aName ) )
465 bool addFile =
false;
467 for(
const wxString& m_filter :
m_filters )
469 wxCHECK2_MSG( reg.Compile( m_filter, wxRE_ICASE ),
continue,
470 wxString::Format(
"Regex %s failed to compile.", m_filter ) );
472 if( reg.Matches( aName ) )
480 return wxTreeItemId();
487 if( ext == wxT(
"" ) )
490 if( reg.Compile( wxString::FromAscii(
"^.*\\." ) + ext + wxString::FromAscii(
"$" ), wxRE_ICASE )
491 && reg.Matches( aName ) )
499 wxString file = wxFileNameFromPath( aName );
500 wxFileName currfile( file );
502 bool showAllSchematics =
m_TreeProject->GetGitRepo() !=
nullptr;
506 && ( currfile.GetName().CmpNoCase(
project.GetName() ) == 0 ) )
508 return wxTreeItemId();
517 return wxTreeItemId();
523 if( !parentTreeItem )
524 return wxTreeItemId();
526 wxDir parentDir( parentTreeItem->
GetDir() );
527 std::vector<wxString> projects =
getProjects( parentDir );
530 return wxTreeItemId();
535 wxTreeItemIdValue cookie;
536 wxTreeItemId kid =
m_TreeProject->GetFirstChild( aParent, cookie );
543 return itemData->GetId();
564 if( fname.GetName().CmpNoCase( currfile.GetName() ) == 0 )
570 return wxTreeItemId();
576 return wxTreeItemId();
603 wxTreeItemId newItemId =
m_TreeProject->AppendItem( aParent, file );
610 wxString fileName = currfile.GetName().Lower();
611 wxString projName =
project.GetName().Lower();
613 if( fileName == projName || fileName.StartsWith( projName +
"-" ) )
617 bool subdir_populated =
false;
628 std::vector<wxString> projects =
getProjects( dir );
629 wxString dir_filename;
630 bool haveFile = dir.GetFirst( &dir_filename );
635 subdir_populated = aRecurse;
641 wxString
path = aName + wxFileName::GetPathSeparator() + dir_filename;
644 haveFile = dir.GetNext( &dir_filename );
653 if( subdir_populated )
675 wxString pro_dir =
m_Parent->GetProjectFileName();
691 wxFileName fn = pro_dir;
692 bool prjReset =
false;
703 bool prjOpened = fn.FileExists();
706 if(
Pgm().GetCommonSettings()->m_Git.enableGit
707 && !
Prj().GetLocalSettings().m_GitIntegrationDisabled )
717 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
719 if( canonicalWorkDir )
722 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
726 m_TreeProject->GitCommon()->SetUsername(
Prj().GetLocalSettings().m_GitRepoUsername );
727 m_TreeProject->GitCommon()->SetSSHKey(
Prj().GetLocalSettings().m_GitSSHKey );
734 if( !prjOpened && !prjReset )
737 prjOpened = fn.FileExists();
757 pro_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
758 wxDir dir( pro_dir );
762 std::vector<wxString> projects =
getProjects( dir );
764 bool haveFile = dir.GetFirst( &filename );
768 if( filename != fn.GetFullName() )
770 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
777 haveFile = dir.GetNext( &filename );
794 wxLogTrace(
traceGit,
"PROJECT_TREE_PANE::ReCreateTreePrj: starting timers" );
813 wxTreeItemId curr_item = Event.GetItem();
821 bool can_switch_to_project =
true;
822 bool can_create_new_directory =
true;
823 bool can_open_this_directory =
true;
824 bool can_edit =
true;
825 bool can_rename =
true;
826 bool can_delete =
true;
827 bool run_jobs =
false;
831 bool vcs_can_init = !vcs_has_repo;
832 bool vcs_can_set_remote = vcs_has_repo;
833 bool vcs_can_amend = vcs_has_repo && git_repository_head_unborn(
m_TreeProject->GetGitRepo() ) == 0;
837 bool vcs_can_remove = vcs_has_repo || gitIntegrationDisabled;
840 bool vcs_can_pull = vcs_can_fetch;
841 bool vcs_can_switch = vcs_has_repo;
847 vcs_menu &= libgit_init;
849 if( selection.size() == 0 )
853 if( selection.size() != 1 )
855 can_switch_to_project =
false;
856 can_create_new_directory =
false;
865 can_switch_to_project =
false;
871 can_delete = item->CanDelete();
872 can_rename = item->CanRename();
874 switch( item->GetType() )
882 can_switch_to_project =
false;
886 can_create_new_directory =
false;
887 can_open_this_directory =
false;
892 can_switch_to_project =
false;
899 can_switch_to_project =
false;
900 can_create_new_directory =
false;
901 can_open_this_directory =
false;
914 can_switch_to_project =
false;
915 can_create_new_directory =
false;
916 can_open_this_directory =
false;
926 if( can_switch_to_project )
929 _(
"Close all editors, and switch to the selected project" ),
931 popup_menu.AppendSeparator();
934 if( can_create_new_directory )
940 if( can_open_this_directory )
942 if( selection.size() == 1 )
945 text =
_(
"Reveal in Finder" );
946 help_text =
_(
"Reveals the directory in a Finder window" );
948 text =
_(
"Open Directory in File Explorer" );
949 help_text =
_(
"Opens the directory in the default system file manager" );
955 text =
_(
"Reveal in Finder" );
956 help_text =
_(
"Reveals the directories in a Finder window" );
958 text =
_(
"Open Directories in File Explorer" );
959 help_text =
_(
"Opens the directories in the default system file manager" );
969 if( selection.size() == 1 )
970 help_text =
_(
"Open the file in a Text Editor" );
972 help_text =
_(
"Open files in a Text Editor" );
978 if( run_jobs && selection.size() == 1 )
986 if( selection.size() == 1 )
988 text =
_(
"Rename File..." );
989 help_text =
_(
"Rename file" );
993 text =
_(
"Rename Files..." );
994 help_text =
_(
"Rename files" );
1003 if( selection.size() == 1 )
1004 help_text =
_(
"Delete the file and its content" );
1006 help_text =
_(
"Delete the files and their contents" );
1008 if( can_switch_to_project
1009 || can_create_new_directory
1010 || can_open_this_directory
1014 popup_menu.AppendSeparator();
1028 wxMenu* vcs_submenu =
new wxMenu();
1029 wxMenu* branch_submenu =
new wxMenu();
1030 wxMenuItem* vcs_menuitem =
nullptr;
1033 _(
"Add Project to Version Control..." ),
1034 _(
"Initialize a new repository" ) );
1035 vcs_menuitem->Enable( vcs_can_init );
1038 _(
"Set or change the default remote URL and credentials" ) );
1039 vcs_menuitem->Enable( vcs_can_set_remote );
1042 _(
"Commit changes to the local repository" ) );
1043 vcs_menuitem->Enable( vcs_can_commit );
1046 _(
"Rewrite the most recent commit on the current branch" ) );
1047 vcs_menuitem->Enable( vcs_can_amend );
1049 wxString pushLabel =
_(
"Push" );
1050 wxString pullLabel =
_(
"Pull" );
1059 vcs_submenu->Append(
ID_GIT_PUSH, pushLabel,
_(
"Push committed local changes to remote repository" ) );
1060 vcs_menuitem->Enable( vcs_can_push );
1063 vcs_submenu->Append(
ID_GIT_PULL, pullLabel,
_(
"Pull changes from remote repository into local" ) );
1064 vcs_menuitem->Enable( vcs_can_pull );
1066 vcs_submenu->AppendSeparator();
1069 _(
"Commit changes to the local repository" ) );
1070 vcs_menuitem->Enable( vcs_can_commit );
1072 vcs_submenu->AppendSeparator();
1078 std::vector<wxString> branchNames =
m_TreeProject->GitCommon()->GetBranchNames();
1081 for(
size_t ii = 1; ii < branchNames.size() && ii < 6; ++ii )
1083 wxString msg =
_(
"Switch to branch " ) + branchNames[ii];
1085 vcs_menuitem->Enable( vcs_can_switch );
1089 _(
"Switch to a different branch" ) );
1090 vcs_menuitem->Enable( vcs_can_switch );
1094 vcs_submenu->AppendSeparator();
1096 if( gitIntegrationDisabled )
1098 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Enable Git Integration" ),
1099 _(
"Re-enable Git integration for this project" ) );
1103 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Disable Git Integration" ),
1104 _(
"Disable Git integration for this project" ) );
1107 vcs_menuitem->Enable( vcs_can_remove );
1109 popup_menu.AppendSeparator();
1110 popup_menu.AppendSubMenu( vcs_submenu,
_(
"Version Control" ) );
1113 if( popup_menu.GetMenuItemCount() > 0 )
1114 PopupMenu( &popup_menu );
1122 if( editorname.IsEmpty() )
1124 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
1132 wxString fullFileName = item_data->GetFileName();
1134 if( !fullFileName.IsEmpty() )
1136 ExecuteFile( editorname, fullFileName.wc_str(),
nullptr,
false );
1147 item_data->Delete();
1157 if( tree_data.size() != 1 )
1161 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
1162 tree_data[0]->GetFileName() );
1163 wxTextEntryDialog dlg( wxGetTopLevelParent(
this ), msg,
_(
"Change filename" ), buffer );
1165 if( dlg.ShowModal() != wxID_OK )
1168 buffer = dlg.GetValue();
1169 buffer.Trim(
true );
1170 buffer.Trim(
false );
1172 if( buffer.IsEmpty() )
1175 tree_data[0]->Rename( buffer,
true );
1184 if( tree_data.size() != 1 )
1207 std::vector<wxTreeItemId> validItemIds;
1210 for( wxTreeItemId
id : validItemIds )
1229 wxTreeItemId itemId = Event.GetItem();
1239 wxTreeItemIdValue cookie;
1240 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
1243 bool subdir_populated =
false;
1246 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
1257 wxDir dir( fileName );
1259 if( dir.IsOpened() )
1261 std::vector<wxString> projects =
getProjects( dir );
1262 wxString dir_filename;
1263 bool haveFile = dir.GetFirst( &dir_filename );
1268 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
1271 haveFile = dir.GetNext( &dir_filename );
1277 subdir_populated =
true;
1286 if( subdir_populated )
1294 wxArrayTreeItemIds selection;
1295 std::vector<PROJECT_TREE_ITEM*> data;
1299 for(
const wxTreeItemId itemId : selection )
1305 wxLogTrace(
traceGit, wxS(
"Null tree item returned for selection, dynamic_cast failed?" ) );
1309 data.push_back( item );
1324 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1328 if( prj_dir == aSubDir )
1332 wxTreeItemIdValue cookie;
1333 wxTreeItemId root_id =
m_root;
1334 std::stack<wxTreeItemId> subdirs_id;
1336 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
1340 if( ! child.IsOk() )
1342 if( subdirs_id.empty() )
1349 root_id = subdirs_id.top();
1370 subdirs_id.push( child );
1388 if( !( event.GetChangeType() & ( wxFSW_EVENT_CREATE |
1389 wxFSW_EVENT_DELETE |
1390 wxFSW_EVENT_RENAME |
1391 wxFSW_EVENT_MODIFY ) ) )
1396 const wxFileName& pathModified =
event.GetPath();
1399 if( pathModified.GetFullPath().Contains( wxS(
".history" ) ) )
1402 wxString subdir = pathModified.GetPath();
1403 wxString fn = pathModified.GetFullPath();
1406 if( pathModified.GetFullName().IsEmpty() )
1408 subdir = subdir.BeforeLast(
'/' );
1409 fn = fn.BeforeLast(
'/' );
1414 if( !root_id.IsOk() )
1417 CallAfter( [
this] ()
1419 wxLogTrace(
traceGit, wxS(
"File system event detected, updating tree cache" ) );
1423 wxTreeItemIdValue cookie;
1424 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1426 switch( event.GetChangeType() )
1428 case wxFSW_EVENT_CREATE:
1443 case wxFSW_EVENT_DELETE:
1457 case wxFSW_EVENT_RENAME :
1459 const wxFileName& newpath =
event.GetNewPath();
1460 wxString newdir = newpath.GetPath();
1461 wxString newfn = newpath.GetFullPath();
1485 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1491 if( newitem.IsOk() )
1512 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1514#if defined( _WIN32 )
1523 m_Parent->m_FileWatcherInfo =
_(
"Network path: not monitoring folder changes" );
1529 m_Parent->m_FileWatcherInfo =
_(
"Local path: monitoring folder changes" );
1547 class WatcherLogHandler :
public wxLog
1550 explicit WatcherLogHandler(
bool* err ) :
1558 void DoLogTextAtLevel( wxLogLevel level,
const wxString&
text )
override
1560 if( m_err && ( level == wxLOG_Error || level == wxLOG_FatalError ) )
1568 bool watcherHasError =
false;
1569 WatcherLogHandler tmpLog( &watcherHasError );
1570 wxLog* oldLog = wxLog::SetActiveTarget( &tmpLog );
1576 wxLog::SetActiveTarget( oldLog );
1578 if( watcherHasError )
1586 fn.AssignDir( prj_dir );
1587 fn.DontFollowLink();
1601 TO_UTF8( fn.GetFullPath() ) );
1609 TO_UTF8( fn.GetFullPath() ) );
1614 if( m_TreeProject->IsEmpty() )
1618 wxTreeItemIdValue cookie;
1619 wxTreeItemId root_id = m_root;
1621 std::stack < wxTreeItemId > subdirs_id;
1623 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1624 int total_watch_count = 0;
1630 if( subdirs_id.empty() )
1636 root_id = subdirs_id.top();
1638 kid = m_TreeProject->GetFirstChild( root_id, cookie );
1653 if(
path.Contains( wxS(
".history" ) ) )
1655 kid = m_TreeProject->GetNextChild( root_id, cookie );
1661 if( wxFileName::IsDirReadable(
path ) )
1666 fn.AssignDir(
path );
1667 m_watcher->Add( fn );
1668 total_watch_count++;
1672 if( itemData->
IsPopulated() && m_TreeProject->GetChildrenCount( kid ) )
1673 subdirs_id.push( kid );
1677 kid = m_TreeProject->GetNextChild( root_id, cookie );
1684#if defined(DEBUG) && 1
1685 wxArrayString paths;
1686 m_watcher->GetWatchedPaths( &paths );
1689 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1707 std::unique_lock<std::mutex> lock( common->
m_gitActionMutex, std::try_to_lock );
1709 constexpr auto kGraceMs = std::chrono::seconds( 2 );
1710 auto graceEnd = std::chrono::steady_clock::now() + kGraceMs;
1712 while( !lock.owns_lock() && std::chrono::steady_clock::now() < graceEnd )
1714 if( lock.try_lock() )
1716 std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
1719 constexpr auto kCheckInterval = std::chrono::seconds( 30 );
1720 bool userAbandoned =
false;
1722 while( !lock.owns_lock() && !userAbandoned )
1724 auto intervalEnd = std::chrono::steady_clock::now() + kCheckInterval;
1727 wxProgressDialog progress(
_(
"Please wait" ),
1728 _(
"Closing project..." ),
1730 wxPD_APP_MODAL | wxPD_SMOOTH );
1732 while( !lock.try_lock()
1733 && std::chrono::steady_clock::now() < intervalEnd )
1736 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
1741 if( lock.owns_lock() )
1744 wxMessageDialog ask(
this,
1745 _(
"A Git operation is still running.\n"
1746 "Keep waiting, or abandon?" ),
1747 _(
"Git Operation Delayed" ),
1748 wxYES_NO | wxICON_QUESTION );
1749 ask.SetYesNoLabels(
_(
"Keep Waiting" ),
_(
"Abandon" ) );
1751 if( ask.ShowModal() == wxID_NO )
1752 userAbandoned =
true;
1758 std::shared_ptr<KIGIT_COMMON> oldCommon =
m_TreeProject->TakeGitCommon();
1768 wxString projectDir = oldCommon ? oldCommon->GetProjectDir() : wxString();
1770 auto cleanup = [orphan, old = std::move( oldCommon )]()
mutable
1772 std::lock_guard<std::mutex> g( old->m_gitActionMutex );
1773 git_repository_free( orphan );
1780 std::string label =
"abandon close " + projectDir.ToStdString();
1815 std::unique_lock<std::mutex> gitLock( common->
m_gitActionMutex, std::try_to_lock );
1817 if( gitLock.owns_lock() )
1820 git_repository_free( repo );
1828 std::shared_ptr<KIGIT_COMMON> oldCommon =
m_TreeProject->TakeGitCommon();
1831 wxString projectDir = oldCommon ? oldCommon->GetProjectDir() : wxString();
1833 auto cleanup = [repo, old = std::move( oldCommon )]()
mutable
1835 std::lock_guard<std::mutex> g( old->m_gitActionMutex );
1836 git_repository_free( repo );
1843 std::string label =
"release repo " + projectDir.ToStdString();
1868 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1869 wxPaintDC dc(
this );
1871 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1872 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1874 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1875 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1918 wxString dir = tree_data->
GetDir();
1922 wxLogError(
"Failed to initialize git project: project directory is empty." );
1927 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1932 _(
"The selected directory is already a Git project." ) );
1948 const char* canonicalWorkDir = git_repository_workdir( initHandler.
GetRepo() );
1950 if( canonicalWorkDir )
1953 dir, wxString::FromUTF8( canonicalWorkDir ) );
1954 m_TreeProject->GitCommon()->SetProjectDir( symlinkWorkDir );
1958 dlg.SetTitle(
_(
"Set default remote" ) );
1989 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
2016 git_repository* repo = common ? common->
GetRepo() :
nullptr;
2021 wxString existingURL;
2022 git_remote* remote =
nullptr;
2024 if( git_remote_lookup( &remote, repo,
"origin" ) == GIT_OK )
2028 if(
const char* url = git_remote_url( remote ) )
2029 existingURL = wxString::FromUTF8( url );
2032 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
2034 dlg.SetTitle(
_(
"Configure Default Remote" ) );
2091 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
2100 switch( pullResult )
2104 : wxString::Format(
_(
"Already up to date with %s." ), upstream ) );
2109 upstream.empty() || branch.empty()
2110 ?
_(
"Pulled changes (fast-forward)." )
2111 : wxString::Format(
_(
"Pulled %s into %s (fast-forward)." ), upstream, branch ) );
2116 ?
_(
"Pulled changes." )
2117 : wxString::Format(
_(
"Pulled %s into %s." ), upstream, branch ) );
2126 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2127 _(
"Your local changes and the remote changes conflict, so the pull was "
2128 "cancelled and nothing was changed.\n\n"
2129 "You can discard your local commits and use the remote version, or "
2130 "rebase your commits on top of the remote." ),
2131 _(
"Pull Conflict" ),
2132 wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING | wxCENTER );
2134 dlg.SetYesNoCancelLabels(
_(
"&Use Remote (discard my changes)" ),
_(
"&Rebase" ),
_(
"Cancel" ) );
2136 int choice = dlg.ShowModal();
2138 if( choice == wxID_YES )
2145 else if( choice == wxID_NO )
2190 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
2200 ?
_(
"Pushed to remote." )
2201 : wxString::Format(
_(
"Pushed %s to %s." ), branch, upstream ) );
2212 wxRichMessageDialog dlg(
2213 wxGetTopLevelParent(
this ),
2214 wxString::Format(
_(
"Push rejected: your local branch and %s have diverged.\n\n"
2215 "This usually happens after amending or rewriting a commit "
2216 "that was already pushed. Force push to overwrite the remote?\n\n"
2217 "Anyone who already pulled the previous version will need to "
2218 "reset their copy." ),
2219 upstream.empty() ? wxString(
"the remote" ) : upstream ),
2220 _(
"Force Push?" ), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING | wxCENTER );
2222 dlg.SetYesNoLabels(
_(
"&Force Push" ),
_(
"Cancel" ) );
2224 if( dlg.ShowModal() == wxID_YES )
2246 wxString branchName;
2255 if( retval == wxID_ADD )
2257 else if( retval != wxID_OK )
2262 std::vector<wxString> branches =
m_TreeProject->GitCommon()->GetBranchNames();
2265 if( branchIndex < 0 ||
static_cast<size_t>( branchIndex ) >= branches.size() )
2268 branchName = branches[branchIndex];
2271 wxLogTrace(
traceGit, wxS(
"onGitSwitchBranch: Switching to branch '%s'" ), branchName );
2290 wxLogTrace(
traceGit, wxS(
"onGitRemoveVCS: Git integration %s" ),
2300 std::stack<wxTreeItemId> items;
2303 while( !items.empty() )
2305 wxTreeItemId current = items.top();
2308 m_TreeProject->SetItemState( current, wxTREE_ITEMSTATE_NONE );
2310 wxTreeItemIdValue cookie;
2311 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
2313 while( child.IsOk() )
2315 items.push( child );
2323 wxFileName fn(
Prj().GetProjectPath() );
2330 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
2332 if( canonicalWorkDir )
2335 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
2336 m_TreeProject->GitCommon()->SetProjectDir( symlinkWorkDir );
2351 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Updating git status icons" ) );
2354 if( !lock.owns_lock() )
2356 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Failed to acquire lock for git status icon update" ) );
2363 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git is disabled or tree control is null" ) );
2367 std::stack<wxTreeItemId> items;
2370 while( !items.empty() )
2372 wxTreeItemId current = items.top();
2377 wxTreeItemIdValue cookie;
2378 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
2380 while( child.IsOk() )
2382 items.push( child );
2386 m_TreeProject->SetItemState( child,
static_cast<int>( it->second ) );
2401 wxString filename = wxFileNameFromPath( rootItem->
GetFileName() );
2407 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git status icons updated" ) );
2413 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Updating tree cache" ) );
2417 if( !lock.owns_lock() )
2419 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Failed to acquire lock for tree cache update" ) );
2425 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Tree control is null" ) );
2436 std::stack<wxTreeItemId> items;
2439 while( !items.empty() )
2451 gitAbsPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2455 wxTreeItemIdValue cookie;
2456 wxTreeItemId child =
m_TreeProject->GetFirstChild( kid, cookie );
2458 while( child.IsOk() )
2460 items.push( child );
2469 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updating git status icons" ) );
2470#if defined( _WIN32 )
2493 if( !lock1.owns_lock() || !lock2.owns_lock() )
2495 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire locks for git status icon update" ) );
2503 std::shared_ptr<KIGIT_COMMON> gitCommon =
m_TreeProject->GitCommonPtr();
2505 if( !gitCommon || !gitCommon->GetRepo() )
2507 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: No git repository found" ) );
2513 std::unique_lock<std::mutex> gitLock( gitCommon->m_gitActionMutex, std::try_to_lock );
2515 if( !gitLock.owns_lock() )
2517 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire git action mutex" ) );
2522 if( gitCommon->IsCancelled() )
2524 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Cancelled" ) );
2531 wxFileName rootFilename(
Prj().GetProjectFullName() );
2534 wxFileName relative = rootFilename;
2535 relative.MakeRelativeTo( repoWorkDir );
2536 wxString pathspecStr = relative.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
2539 pathspecStr.Replace( wxS(
"\\" ), wxS(
"/" ) );
2543 auto fileStatusMap = statusHandler.
GetFileStatus( pathspecStr );
2544 auto [localChanges, remoteChanges] = gitCommon->GetDifferentFiles();
2547 bool updated =
false;
2550 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2555 wxLogTrace(
traceGit, wxS(
"File '%s' not found in tree cache" ), absPath );
2559 auto [it, inserted] =
m_gitStatusIcons.try_emplace( iter->second, fileStatus.status );
2560 if( inserted || it->second != fileStatus.status )
2562 it->second = fileStatus.status;
2574 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updated git status icons" ) );
2594 if( repo ==
nullptr )
2596 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2610 const DirtyEditor candidates[] = {
2615 std::vector<const DirtyEditor*> dirty;
2617 for(
const DirtyEditor& d : candidates )
2622 dirty.push_back( &d );
2625 if( !dirty.empty() )
2629 for(
const DirtyEditor* d : dirty )
2630 listed += wxString::Format( wxS(
"\n • %s" ), d->label );
2632 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2633 wxString::Format(
_(
"The following editors have unsaved changes:%s\n\n"
2634 "Save them before committing?" ),
2636 _(
"Unsaved Changes" ),
2637 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
2639 dlg.SetYesNoCancelLabels(
_(
"&Save and Commit" ),
_(
"Commit &Anyway" ),
_(
"Cancel" ) );
2641 int answer = dlg.ShowModal();
2643 if( answer == wxID_CANCEL )
2646 if( answer == wxID_YES )
2648 for(
const DirtyEditor* d : dirty )
2650 std::string payload;
2651 m_Parent->Kiway().ExpressMail( d->frameType, d->saveMail, payload );
2653 if( payload !=
"success" )
2656 wxString::Format(
_(
"Could not save %s." ), d->label ) );
2663 m_Parent->GetSettingsManager()->SaveProject();
2674 std::map<wxString, int> modifiedFiles;
2675 std::set<wxString> selected_files;
2682 wxString itemPath = item->GetFileName();
2684 itemPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2686 selected_files.emplace( itemPath );
2693 projectPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2696 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2706 wxFileName fn( absPath );
2709 wxString relativePath = absPath;
2710 if( relativePath.StartsWith( repoWorkDir ) )
2712 relativePath = relativePath.Mid( repoWorkDir.length() );
2714 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2734 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2738 if( fn.IsDir() && fn.GetDirs().Last().StartsWith( wxS(
".history" ) ) )
2753 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2755 else if( selected_files.count( absPath ) )
2757 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2766 if( ret != wxID_OK )
2773 wxMessageBox(
_(
"Discarding commit due to empty commit message." ) );
2779 wxMessageBox(
_(
"Discarding commit due to empty file selection." ) );
2789 wxMessageBox( wxString::Format(
_(
"Failed to create commit: %s" ),
2794 wxLogTrace(
traceGit, wxS(
"Created commit" ) );
2803 if( repo ==
nullptr )
2805 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2815 std::unique_lock<std::mutex> gitLock(
m_TreeProject->GitCommon()->m_gitActionMutex, std::try_to_lock );
2817 if( gitLock.owns_lock() )
2820 git_repository_free( repo );
2825 git_repository_free( fresh );
2829 if( git_repository_head_unborn( repo ) != 0 )
2831 DisplayErrorMessage( wxGetTopLevelParent(
this ),
_(
"Cannot amend: the branch has no commits yet." ) );
2837 git_reference* headRef =
nullptr;
2839 if( git_repository_head( &headRef, repo ) != GIT_OK )
2843 git_commit* headCommit =
nullptr;
2845 if( git_reference_peel( (git_object**) &headCommit, headRef, GIT_OBJECT_COMMIT ) != GIT_OK )
2849 wxString headMessage = wxString::FromUTF8( git_commit_message( headCommit ) );
2850 const git_oid* headOid = git_commit_id( headCommit );
2854 bool headIsPublished =
false;
2855 git_reference* upstreamRef =
nullptr;
2857 if( git_branch_upstream( &upstreamRef, headRef ) == GIT_OK )
2860 git_oid upstreamOid;
2862 if( git_reference_name_to_id( &upstreamOid, repo, git_reference_name( upstreamRef ) ) == GIT_OK )
2864 headIsPublished = git_oid_equal( headOid, &upstreamOid )
2865 || git_graph_descendant_of( repo, &upstreamOid, headOid ) == 1;
2869 if( headIsPublished )
2871 wxString upstreamName =
m_TreeProject->GitCommon()->GetUpstreamShorthand();
2873 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2874 wxString::Format(
_(
"The last commit has already been pushed to %s.\n\n"
2875 "Amending rewrites public history. Anyone who pulled "
2876 "this commit will need to reset their copy." ),
2878 _(
"Amend Published Commit?" ), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING | wxCENTER );
2880 dlg.SetYesNoLabels(
_(
"Amend &Anyway" ),
_(
"Cancel" ) );
2882 if( dlg.ShowModal() != wxID_YES )
2896 const DirtyEditor candidates[] = {
2901 std::vector<const DirtyEditor*> dirty;
2903 for(
const DirtyEditor& d : candidates )
2908 dirty.push_back( &d );
2911 if( !dirty.empty() )
2915 for(
const DirtyEditor* d : dirty )
2916 listed += wxString::Format( wxS(
"\n • %s" ), d->label );
2918 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2919 wxString::Format(
_(
"The following editors have unsaved changes:%s\n\n"
2920 "Save them before amending?" ),
2922 _(
"Unsaved Changes" ),
2923 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
2925 dlg.SetYesNoCancelLabels(
_(
"&Save and Amend" ),
_(
"Amend &Anyway" ),
_(
"Cancel" ) );
2927 int answer = dlg.ShowModal();
2929 if( answer == wxID_CANCEL )
2932 if( answer == wxID_YES )
2934 for(
const DirtyEditor* d : dirty )
2936 std::string payload;
2937 m_Parent->Kiway().ExpressMail( d->frameType, d->saveMail, payload );
2939 if( payload !=
"success" )
2942 wxString::Format(
_(
"Could not save %s." ), d->label ) );
2949 m_Parent->GetSettingsManager()->SaveProject();
2962 projectPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2965 std::map<wxString, int> modifiedFiles;
2967 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2976 wxFileName fn( absPath );
2977 wxString relativePath = absPath;
2979 if( relativePath.StartsWith( repoWorkDir ) )
2981 relativePath = relativePath.Mid( repoWorkDir.length() );
2983 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2998 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
3001 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
3004 if( git_reference* headRefForDiff =
nullptr; git_repository_head( &headRefForDiff, repo ) == GIT_OK )
3007 git_commit* lastCommit =
nullptr;
3009 if( git_reference_peel( (git_object**) &lastCommit, headRefForDiff, GIT_OBJECT_COMMIT ) == GIT_OK )
3012 git_commit* parentCommit =
nullptr;
3013 git_tree* parentTree =
nullptr;
3014 git_tree* lastTree =
nullptr;
3016 if( git_commit_parentcount( lastCommit ) > 0
3017 && git_commit_parent( &parentCommit, lastCommit, 0 ) == GIT_OK )
3019 git_commit_tree( &parentTree, parentCommit );
3025 if( git_commit_tree( &lastTree, lastCommit ) == GIT_OK )
3028 git_diff* diff =
nullptr;
3030 if( git_diff_tree_to_tree( &diff, repo, parentTree, lastTree,
nullptr ) == GIT_OK )
3035 [&modifiedFiles, &repoWorkDir, &projectPath](
const git_diff_delta& aDelta )
3037 const char*
path = aDelta.new_file.path ? aDelta.new_file.path
3038 : aDelta.old_file.path;
3045 wxString absPath = repoWorkDir + wxString::FromUTF8(
path );
3050 int flag = GIT_STATUS_INDEX_MODIFIED;
3052 if( aDelta.status == GIT_DELTA_ADDED )
3053 flag = GIT_STATUS_INDEX_NEW;
3054 else if( aDelta.status == GIT_DELTA_DELETED )
3055 flag = GIT_STATUS_INDEX_DELETED;
3057 modifiedFiles[wxString::FromUTF8(
path )] |=
flag;
3066 dlg.SetTitle(
_(
"Amend Last Commit" ) );
3075 wxMessageBox(
_(
"Discarding amend due to empty commit message." ) );
3085 wxMessageBox( wxString::Format(
_(
"Failed to amend commit: %s" ), commitHandler.
GetErrorString() ) );
3089 wxLogTrace(
traceGit, wxS(
"Amended commit" ) );
3109 for(
const auto& [filePath, fileStatus] : fileStatusMap )
3111 if( filePath.EndsWith( aFile ) || filePath == aFile )
3125 wxLogTrace(
traceGit,
"Syncing project" );
3130 wxLogTrace(
traceGit,
"sync: No git repository found" );
3157 : wxString::Format(
_(
"Fetched from %s." ), remoteName ) );
3216 wxLogTrace(
traceGit,
"onGitSyncTimer" );
3228 std::shared_ptr<KIGIT_COMMON> gitCommon =
m_TreeProject->GitCommonPtr();
3230 if( !gitCommon || !gitCommon->GetRepo() )
3232 wxLogTrace(
traceGit,
"onGitSyncTimer: No git repository found" );
3237 if( gitCommon->IsCancelled() )
3239 wxLogTrace(
traceGit,
"onGitSyncTimer: Cancelled" );
3247 if( !gitCommon->IsCancelled() )
3253 wxLogTrace(
traceGit,
"onGitSyncTimer: Restarting git sync timer" );
3276 wxLogTrace(
traceGit,
"onGitStatusTimer" );
3289 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.
void SetFileSelectionRequired(bool aRequired)
When false, OK is allowed with no files selected (e.g. amending only the message).
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 IsWithinProjectPath(const wxString &aAbsPath, const wxString &aProjectPath)
Test whether an absolute file path lives inside the current project directory.
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 releaseGitRepo()
Releases the git repository handle, deferring the free to the orphan registry while a background git ...
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.
EVT_MENU(ID_COMPARE_PROJECT_BRANCHES, KICAD_MANAGER_FRAME::OnCompareProjectBranches) KICAD_MANAGER_FRAME
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.
void CollectDiffDeltas(git_diff *aDiff, const std::function< void(const git_diff_delta &)> &aCallback)
Walk every delta in a computed diff, invoking aCallback once per delta.
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.