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();
693 wxFileName fn = pro_dir;
694 bool prjReset =
false;
705 bool prjOpened = fn.FileExists();
708 if(
Pgm().GetCommonSettings()->m_Git.enableGit
709 && !
Prj().GetLocalSettings().m_GitIntegrationDisabled )
719 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
721 if( canonicalWorkDir )
724 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
728 m_TreeProject->GitCommon()->SetUsername(
Prj().GetLocalSettings().m_GitRepoUsername );
729 m_TreeProject->GitCommon()->SetSSHKey(
Prj().GetLocalSettings().m_GitSSHKey );
736 if( !prjOpened && !prjReset )
739 prjOpened = fn.FileExists();
759 pro_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
760 wxDir dir( pro_dir );
764 std::vector<wxString> projects =
getProjects( dir );
766 bool haveFile = dir.GetFirst( &filename );
770 if( filename != fn.GetFullName() )
772 wxString
name = dir.GetName() + wxFileName::GetPathSeparator() + filename;
779 haveFile = dir.GetNext( &filename );
796 wxLogTrace(
traceGit,
"PROJECT_TREE_PANE::ReCreateTreePrj: starting timers" );
815 wxTreeItemId curr_item = Event.GetItem();
823 bool can_switch_to_project =
true;
824 bool can_create_new_directory =
true;
825 bool can_open_this_directory =
true;
826 bool can_edit =
true;
827 bool can_rename =
true;
828 bool can_delete =
true;
829 bool run_jobs =
false;
833 bool vcs_can_init = !vcs_has_repo;
834 bool vcs_can_set_remote = vcs_has_repo;
835 bool vcs_can_amend = vcs_has_repo && git_repository_head_unborn(
m_TreeProject->GetGitRepo() ) == 0;
839 bool vcs_can_remove = vcs_has_repo || gitIntegrationDisabled;
842 bool vcs_can_pull = vcs_can_fetch;
843 bool vcs_can_switch = vcs_has_repo;
849 vcs_menu &= libgit_init;
851 if( selection.size() == 0 )
855 if( selection.size() != 1 )
857 can_switch_to_project =
false;
858 can_create_new_directory =
false;
867 can_switch_to_project =
false;
873 can_delete = item->CanDelete();
874 can_rename = item->CanRename();
876 switch( item->GetType() )
884 can_switch_to_project =
false;
888 can_create_new_directory =
false;
889 can_open_this_directory =
false;
894 can_switch_to_project =
false;
901 can_switch_to_project =
false;
902 can_create_new_directory =
false;
903 can_open_this_directory =
false;
916 can_switch_to_project =
false;
917 can_create_new_directory =
false;
918 can_open_this_directory =
false;
928 if( can_switch_to_project )
931 _(
"Close all editors, and switch to the selected project" ),
933 popup_menu.AppendSeparator();
936 if( can_create_new_directory )
942 if( can_open_this_directory )
944 if( selection.size() == 1 )
947 text =
_(
"Reveal in Finder" );
948 help_text =
_(
"Reveals the directory in a Finder window" );
950 text =
_(
"Open Directory in File Explorer" );
951 help_text =
_(
"Opens the directory in the default system file manager" );
957 text =
_(
"Reveal in Finder" );
958 help_text =
_(
"Reveals the directories in a Finder window" );
960 text =
_(
"Open Directories in File Explorer" );
961 help_text =
_(
"Opens the directories in the default system file manager" );
971 if( selection.size() == 1 )
972 help_text =
_(
"Open the file in a Text Editor" );
974 help_text =
_(
"Open files in a Text Editor" );
980 if( run_jobs && selection.size() == 1 )
988 if( selection.size() == 1 )
990 text =
_(
"Rename File..." );
991 help_text =
_(
"Rename file" );
995 text =
_(
"Rename Files..." );
996 help_text =
_(
"Rename files" );
1005 if( selection.size() == 1 )
1006 help_text =
_(
"Delete the file and its content" );
1008 help_text =
_(
"Delete the files and their contents" );
1010 if( can_switch_to_project
1011 || can_create_new_directory
1012 || can_open_this_directory
1016 popup_menu.AppendSeparator();
1030 wxMenu* vcs_submenu =
new wxMenu();
1031 wxMenu* branch_submenu =
new wxMenu();
1032 wxMenuItem* vcs_menuitem =
nullptr;
1035 _(
"Add Project to Version Control..." ),
1036 _(
"Initialize a new repository" ) );
1037 vcs_menuitem->Enable( vcs_can_init );
1040 _(
"Set or change the default remote URL and credentials" ) );
1041 vcs_menuitem->Enable( vcs_can_set_remote );
1044 _(
"Commit changes to the local repository" ) );
1045 vcs_menuitem->Enable( vcs_can_commit );
1048 _(
"Rewrite the most recent commit on the current branch" ) );
1049 vcs_menuitem->Enable( vcs_can_amend );
1051 wxString pushLabel =
_(
"Push" );
1052 wxString pullLabel =
_(
"Pull" );
1061 vcs_submenu->Append(
ID_GIT_PUSH, pushLabel,
_(
"Push committed local changes to remote repository" ) );
1062 vcs_menuitem->Enable( vcs_can_push );
1065 vcs_submenu->Append(
ID_GIT_PULL, pullLabel,
_(
"Pull changes from remote repository into local" ) );
1066 vcs_menuitem->Enable( vcs_can_pull );
1068 vcs_submenu->AppendSeparator();
1071 _(
"Commit changes to the local repository" ) );
1072 vcs_menuitem->Enable( vcs_can_commit );
1074 vcs_submenu->AppendSeparator();
1080 std::vector<wxString> branchNames =
m_TreeProject->GitCommon()->GetBranchNames();
1083 for(
size_t ii = 1; ii < branchNames.size() && ii < 6; ++ii )
1085 wxString msg =
_(
"Switch to branch " ) + branchNames[ii];
1087 vcs_menuitem->Enable( vcs_can_switch );
1091 _(
"Switch to a different branch" ) );
1092 vcs_menuitem->Enable( vcs_can_switch );
1096 vcs_submenu->AppendSeparator();
1098 if( gitIntegrationDisabled )
1100 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Enable Git Integration" ),
1101 _(
"Re-enable Git integration for this project" ) );
1105 vcs_menuitem = vcs_submenu->Append(
ID_GIT_REMOVE_VCS,
_(
"Disable Git Integration" ),
1106 _(
"Disable Git integration for this project" ) );
1109 vcs_menuitem->Enable( vcs_can_remove );
1111 popup_menu.AppendSeparator();
1112 popup_menu.AppendSubMenu( vcs_submenu,
_(
"Version Control" ) );
1115 if( popup_menu.GetMenuItemCount() > 0 )
1116 PopupMenu( &popup_menu );
1124 if( editorname.IsEmpty() )
1126 wxMessageBox(
_(
"No text editor selected in KiCad. Please choose one." ) );
1134 wxString fullFileName = item_data->GetFileName();
1136 if( !fullFileName.IsEmpty() )
1138 ExecuteFile( editorname, fullFileName.wc_str(),
nullptr,
false );
1149 item_data->Delete();
1159 if( tree_data.size() != 1 )
1163 wxString msg = wxString::Format(
_(
"Change filename: '%s'" ),
1164 tree_data[0]->GetFileName() );
1165 wxTextEntryDialog dlg( wxGetTopLevelParent(
this ), msg,
_(
"Change filename" ), buffer );
1167 if( dlg.ShowModal() != wxID_OK )
1170 buffer = dlg.GetValue();
1171 buffer.Trim(
true );
1172 buffer.Trim(
false );
1174 if( buffer.IsEmpty() )
1177 tree_data[0]->Rename( buffer,
true );
1186 if( tree_data.size() != 1 )
1209 std::vector<wxTreeItemId> validItemIds;
1212 for( wxTreeItemId
id : validItemIds )
1231 wxTreeItemId itemId = Event.GetItem();
1241 wxTreeItemIdValue cookie;
1242 wxTreeItemId kid =
m_TreeProject->GetFirstChild( itemId, cookie );
1245 bool subdir_populated =
false;
1248 for( ; kid.IsOk(); kid =
m_TreeProject->GetNextChild( itemId, cookie ) )
1259 wxDir dir( fileName );
1261 if( dir.IsOpened() )
1263 std::vector<wxString> projects =
getProjects( dir );
1264 wxString dir_filename;
1265 bool haveFile = dir.GetFirst( &dir_filename );
1270 wxString
name = fileName + wxFileName::GetPathSeparator() + dir_filename;
1273 haveFile = dir.GetNext( &dir_filename );
1279 subdir_populated =
true;
1288 if( subdir_populated )
1296 wxArrayTreeItemIds selection;
1297 std::vector<PROJECT_TREE_ITEM*> data;
1301 for(
const wxTreeItemId itemId : selection )
1307 wxLogTrace(
traceGit, wxS(
"Null tree item returned for selection, dynamic_cast failed?" ) );
1311 data.push_back( item );
1326 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1330 if( prj_dir == aSubDir )
1334 wxTreeItemIdValue cookie;
1335 wxTreeItemId root_id =
m_root;
1336 std::stack<wxTreeItemId> subdirs_id;
1338 wxTreeItemId child =
m_TreeProject->GetFirstChild( root_id, cookie );
1342 if( ! child.IsOk() )
1344 if( subdirs_id.empty() )
1351 root_id = subdirs_id.top();
1372 subdirs_id.push( child );
1390 if( !( event.GetChangeType() & ( wxFSW_EVENT_CREATE |
1391 wxFSW_EVENT_DELETE |
1392 wxFSW_EVENT_RENAME |
1393 wxFSW_EVENT_MODIFY ) ) )
1398 const wxFileName& pathModified =
event.GetPath();
1401 if( pathModified.GetFullPath().Contains( wxS(
".history" ) ) )
1404 wxString subdir = pathModified.GetPath();
1405 wxString fn = pathModified.GetFullPath();
1408 if( pathModified.GetFullName().IsEmpty() )
1410 subdir = subdir.BeforeLast(
'/' );
1411 fn = fn.BeforeLast(
'/' );
1416 if( !root_id.IsOk() )
1419 CallAfter( [
this] ()
1421 wxLogTrace(
traceGit, wxS(
"File system event detected, updating tree cache" ) );
1425 wxTreeItemIdValue cookie;
1426 wxTreeItemId kid =
m_TreeProject->GetFirstChild( root_id, cookie );
1428 switch( event.GetChangeType() )
1430 case wxFSW_EVENT_CREATE:
1445 case wxFSW_EVENT_DELETE:
1459 case wxFSW_EVENT_RENAME :
1461 const wxFileName& newpath =
event.GetNewPath();
1462 wxString newdir = newpath.GetPath();
1463 wxString newfn = newpath.GetFullPath();
1487 if( rootData && newpath.Exists() && ( newfn != rootData->
GetFileName() ) )
1493 if( newitem.IsOk() )
1514 wxString prj_dir = wxPathOnly(
m_Parent->GetProjectFileName() );
1516#if defined( _WIN32 )
1525 m_Parent->m_FileWatcherInfo =
_(
"Network path: not monitoring folder changes" );
1531 m_Parent->m_FileWatcherInfo =
_(
"Local path: monitoring folder changes" );
1549 class WatcherLogHandler :
public wxLog
1552 explicit WatcherLogHandler(
bool* err ) :
1560 void DoLogTextAtLevel( wxLogLevel level,
const wxString&
text )
override
1562 if( m_err && ( level == wxLOG_Error || level == wxLOG_FatalError ) )
1570 bool watcherHasError =
false;
1571 WatcherLogHandler tmpLog( &watcherHasError );
1572 wxLog* oldLog = wxLog::SetActiveTarget( &tmpLog );
1578 wxLog::SetActiveTarget( oldLog );
1580 if( watcherHasError )
1588 fn.AssignDir( prj_dir );
1589 fn.DontFollowLink();
1603 TO_UTF8( fn.GetFullPath() ) );
1611 TO_UTF8( fn.GetFullPath() ) );
1616 if( m_TreeProject->IsEmpty() )
1620 wxTreeItemIdValue cookie;
1621 wxTreeItemId root_id = m_root;
1623 std::stack < wxTreeItemId > subdirs_id;
1625 wxTreeItemId kid = m_TreeProject->GetFirstChild( root_id, cookie );
1626 int total_watch_count = 0;
1632 if( subdirs_id.empty() )
1638 root_id = subdirs_id.top();
1640 kid = m_TreeProject->GetFirstChild( root_id, cookie );
1655 if(
path.Contains( wxS(
".history" ) ) )
1657 kid = m_TreeProject->GetNextChild( root_id, cookie );
1663 if( wxFileName::IsDirReadable(
path ) )
1668 fn.AssignDir(
path );
1669 m_watcher->Add( fn );
1670 total_watch_count++;
1674 if( itemData->
IsPopulated() && m_TreeProject->GetChildrenCount( kid ) )
1675 subdirs_id.push( kid );
1679 kid = m_TreeProject->GetNextChild( root_id, cookie );
1686#if defined(DEBUG) && 1
1687 wxArrayString paths;
1688 m_watcher->GetWatchedPaths( &paths );
1691 for(
unsigned ii = 0; ii < paths.GetCount(); ii++ )
1709 std::unique_lock<std::mutex> lock( common->
m_gitActionMutex, std::try_to_lock );
1711 constexpr auto kGraceMs = std::chrono::seconds( 2 );
1712 auto graceEnd = std::chrono::steady_clock::now() + kGraceMs;
1714 while( !lock.owns_lock() && std::chrono::steady_clock::now() < graceEnd )
1716 if( lock.try_lock() )
1718 std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) );
1721 constexpr auto kCheckInterval = std::chrono::seconds( 30 );
1722 bool userAbandoned =
false;
1724 while( !lock.owns_lock() && !userAbandoned )
1726 auto intervalEnd = std::chrono::steady_clock::now() + kCheckInterval;
1729 wxProgressDialog progress(
_(
"Please wait" ),
1730 _(
"Closing project..." ),
1732 wxPD_APP_MODAL | wxPD_SMOOTH );
1734 while( !lock.try_lock()
1735 && std::chrono::steady_clock::now() < intervalEnd )
1738 std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
1743 if( lock.owns_lock() )
1746 wxMessageDialog ask(
this,
1747 _(
"A Git operation is still running.\n"
1748 "Keep waiting, or abandon?" ),
1749 _(
"Git Operation Delayed" ),
1750 wxYES_NO | wxICON_QUESTION );
1751 ask.SetYesNoLabels(
_(
"Keep Waiting" ),
_(
"Abandon" ) );
1753 if( ask.ShowModal() == wxID_NO )
1754 userAbandoned =
true;
1760 std::unique_ptr<KIGIT_COMMON> oldCommon =
m_TreeProject->TakeGitCommon();
1770 wxString projectDir = oldCommon ? oldCommon->GetProjectDir() : wxString();
1772 auto cleanup = [orphan, old = std::move( oldCommon )]()
mutable
1774 std::lock_guard<std::mutex> g( old->m_gitActionMutex );
1775 git_repository_free( orphan );
1782 std::string label =
"abandon close " + projectDir.ToStdString();
1819 wxRect rect( wxPoint( 0, 0 ), GetClientSize() );
1820 wxPaintDC dc(
this );
1822 dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
1823 dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_ACTIVEBORDER ), 1 ) );
1825 dc.DrawLine( rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetBottom() );
1826 dc.DrawLine( rect.GetRight(), rect.GetTop(), rect.GetRight(), rect.GetBottom() );
1869 wxString dir = tree_data->
GetDir();
1873 wxLogError(
"Failed to initialize git project: project directory is empty." );
1878 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1883 _(
"The selected directory is already a Git project." ) );
1899 const char* canonicalWorkDir = git_repository_workdir( initHandler.
GetRepo() );
1901 if( canonicalWorkDir )
1904 dir, wxString::FromUTF8( canonicalWorkDir ) );
1905 m_TreeProject->GitCommon()->SetProjectDir( symlinkWorkDir );
1909 dlg.SetTitle(
_(
"Set default remote" ) );
1940 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
1967 git_repository* repo = common ? common->
GetRepo() :
nullptr;
1972 wxString existingURL;
1973 git_remote* remote =
nullptr;
1975 if( git_remote_lookup( &remote, repo,
"origin" ) == GIT_OK )
1979 if(
const char* url = git_remote_url( remote ) )
1980 existingURL = wxString::FromUTF8( url );
1983 wxWindow* topLevelParent = wxGetTopLevelParent(
this );
1985 dlg.SetTitle(
_(
"Configure Default Remote" ) );
2042 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
2051 switch( pullResult )
2055 : wxString::Format(
_(
"Already up to date with %s." ), upstream ) );
2060 upstream.empty() || branch.empty()
2061 ?
_(
"Pulled changes (fast-forward)." )
2062 : wxString::Format(
_(
"Pulled %s into %s (fast-forward)." ), upstream, branch ) );
2067 ?
_(
"Pulled changes." )
2068 : wxString::Format(
_(
"Pulled %s into %s." ), upstream, branch ) );
2077 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2078 _(
"Your local changes and the remote changes conflict, so the pull was "
2079 "cancelled and nothing was changed.\n\n"
2080 "You can discard your local commits and use the remote version, or "
2081 "rebase your commits on top of the remote." ),
2082 _(
"Pull Conflict" ),
2083 wxYES_NO | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING | wxCENTER );
2085 dlg.SetYesNoCancelLabels(
_(
"&Use Remote (discard my changes)" ),
_(
"&Rebase" ),
_(
"Cancel" ) );
2087 int choice = dlg.ShowModal();
2089 if( choice == wxID_YES )
2096 else if( choice == wxID_NO )
2141 std::make_unique<WX_PROGRESS_REPORTER>(
this,
_(
"Fetch Remote" ), 1,
PR_NO_ABORT ) );
2151 ?
_(
"Pushed to remote." )
2152 : wxString::Format(
_(
"Pushed %s to %s." ), branch, upstream ) );
2163 wxRichMessageDialog dlg(
2164 wxGetTopLevelParent(
this ),
2165 wxString::Format(
_(
"Push rejected: your local branch and %s have diverged.\n\n"
2166 "This usually happens after amending or rewriting a commit "
2167 "that was already pushed. Force push to overwrite the remote?\n\n"
2168 "Anyone who already pulled the previous version will need to "
2169 "reset their copy." ),
2170 upstream.empty() ? wxString(
"the remote" ) : upstream ),
2171 _(
"Force Push?" ), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING | wxCENTER );
2173 dlg.SetYesNoLabels(
_(
"&Force Push" ),
_(
"Cancel" ) );
2175 if( dlg.ShowModal() == wxID_YES )
2197 wxString branchName;
2206 if( retval == wxID_ADD )
2208 else if( retval != wxID_OK )
2213 std::vector<wxString> branches =
m_TreeProject->GitCommon()->GetBranchNames();
2216 if( branchIndex < 0 ||
static_cast<size_t>( branchIndex ) >= branches.size() )
2219 branchName = branches[branchIndex];
2222 wxLogTrace(
traceGit, wxS(
"onGitSwitchBranch: Switching to branch '%s'" ), branchName );
2241 wxLogTrace(
traceGit, wxS(
"onGitRemoveVCS: Git integration %s" ),
2251 std::stack<wxTreeItemId> items;
2254 while( !items.empty() )
2256 wxTreeItemId current = items.top();
2259 m_TreeProject->SetItemState( current, wxTREE_ITEMSTATE_NONE );
2261 wxTreeItemIdValue cookie;
2262 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
2264 while( child.IsOk() )
2266 items.push( child );
2274 wxFileName fn(
Prj().GetProjectPath() );
2281 const char* canonicalWorkDir = git_repository_workdir(
m_TreeProject->GetGitRepo() );
2283 if( canonicalWorkDir )
2286 fn.GetPath(), wxString::FromUTF8( canonicalWorkDir ) );
2287 m_TreeProject->GitCommon()->SetProjectDir( symlinkWorkDir );
2302 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Updating git status icons" ) );
2305 if( !lock.owns_lock() )
2307 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Failed to acquire lock for git status icon update" ) );
2314 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git is disabled or tree control is null" ) );
2318 std::stack<wxTreeItemId> items;
2321 while( !items.empty() )
2323 wxTreeItemId current = items.top();
2328 wxTreeItemIdValue cookie;
2329 wxTreeItemId child =
m_TreeProject->GetFirstChild( current, cookie );
2331 while( child.IsOk() )
2333 items.push( child );
2337 m_TreeProject->SetItemState( child,
static_cast<int>( it->second ) );
2352 wxString filename = wxFileNameFromPath( rootItem->
GetFileName() );
2358 wxLogTrace(
traceGit, wxS(
"updateGitStatusIcons: Git status icons updated" ) );
2364 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Updating tree cache" ) );
2368 if( !lock.owns_lock() )
2370 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Failed to acquire lock for tree cache update" ) );
2376 wxLogTrace(
traceGit, wxS(
"updateTreeCache: Tree control is null" ) );
2387 std::stack<wxTreeItemId> items;
2390 while( !items.empty() )
2402 gitAbsPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2406 wxTreeItemIdValue cookie;
2407 wxTreeItemId child =
m_TreeProject->GetFirstChild( kid, cookie );
2409 while( child.IsOk() )
2411 items.push( child );
2420 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updating git status icons" ) );
2421#if defined( _WIN32 )
2444 if( !lock1.owns_lock() || !lock2.owns_lock() )
2446 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire locks for git status icon update" ) );
2452 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: No git repository found" ) );
2458 std::unique_lock<std::mutex> gitLock(
m_TreeProject->GitCommon()->m_gitActionMutex, std::try_to_lock );
2460 if( !gitLock.owns_lock() )
2462 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Failed to acquire git action mutex" ) );
2469 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Cancelled" ) );
2476 wxFileName rootFilename(
Prj().GetProjectFullName() );
2479 wxFileName relative = rootFilename;
2480 relative.MakeRelativeTo( repoWorkDir );
2481 wxString pathspecStr = relative.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR );
2484 pathspecStr.Replace( wxS(
"\\" ), wxS(
"/" ) );
2488 auto fileStatusMap = statusHandler.
GetFileStatus( pathspecStr );
2489 auto [localChanges, remoteChanges] =
m_TreeProject->GitCommon()->GetDifferentFiles();
2492 bool updated =
false;
2495 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2500 wxLogTrace(
traceGit, wxS(
"File '%s' not found in tree cache" ), absPath );
2504 auto [it, inserted] =
m_gitStatusIcons.try_emplace( iter->second, fileStatus.status );
2505 if( inserted || it->second != fileStatus.status )
2507 it->second = fileStatus.status;
2519 wxLogTrace(
traceGit, wxS(
"updateGitStatusIconMap: Updated git status icons" ) );
2539 if( repo ==
nullptr )
2541 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2555 const DirtyEditor candidates[] = {
2560 std::vector<const DirtyEditor*> dirty;
2562 for(
const DirtyEditor& d : candidates )
2567 dirty.push_back( &d );
2570 if( !dirty.empty() )
2574 for(
const DirtyEditor* d : dirty )
2575 listed += wxString::Format( wxS(
"\n • %s" ), d->label );
2577 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2578 wxString::Format(
_(
"The following editors have unsaved changes:%s\n\n"
2579 "Save them before committing?" ),
2581 _(
"Unsaved Changes" ),
2582 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
2584 dlg.SetYesNoCancelLabels(
_(
"&Save and Commit" ),
_(
"Commit &Anyway" ),
_(
"Cancel" ) );
2586 int answer = dlg.ShowModal();
2588 if( answer == wxID_CANCEL )
2591 if( answer == wxID_YES )
2593 for(
const DirtyEditor* d : dirty )
2595 std::string payload;
2596 m_Parent->Kiway().ExpressMail( d->frameType, d->saveMail, payload );
2598 if( payload !=
"success" )
2601 wxString::Format(
_(
"Could not save %s." ), d->label ) );
2608 m_Parent->GetSettingsManager()->SaveProject();
2619 std::map<wxString, int> modifiedFiles;
2620 std::set<wxString> selected_files;
2627 wxString itemPath = item->GetFileName();
2629 itemPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2631 selected_files.emplace( itemPath );
2638 projectPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2641 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2651 wxFileName fn( absPath );
2654 wxString relativePath = absPath;
2655 if( relativePath.StartsWith( repoWorkDir ) )
2657 relativePath = relativePath.Mid( repoWorkDir.length() );
2659 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2664 if( !absPath.StartsWith( projectPath ) )
2679 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2683 if( fn.IsDir() && fn.GetDirs().Last().StartsWith( wxS(
".history" ) ) )
2698 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2700 else if( selected_files.count( absPath ) )
2702 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2711 if( ret != wxID_OK )
2718 wxMessageBox(
_(
"Discarding commit due to empty commit message." ) );
2724 wxMessageBox(
_(
"Discarding commit due to empty file selection." ) );
2734 wxMessageBox( wxString::Format(
_(
"Failed to create commit: %s" ),
2739 wxLogTrace(
traceGit, wxS(
"Created commit" ) );
2748 if( repo ==
nullptr )
2750 wxMessageBox(
_(
"The selected directory is not a Git project." ) );
2759 git_repository_free( repo );
2763 if( git_repository_head_unborn( repo ) != 0 )
2765 DisplayErrorMessage( wxGetTopLevelParent(
this ),
_(
"Cannot amend: the branch has no commits yet." ) );
2771 git_reference* headRef =
nullptr;
2773 if( git_repository_head( &headRef, repo ) != GIT_OK )
2777 git_commit* headCommit =
nullptr;
2779 if( git_reference_peel( (git_object**) &headCommit, headRef, GIT_OBJECT_COMMIT ) != GIT_OK )
2783 wxString headMessage = wxString::FromUTF8( git_commit_message( headCommit ) );
2784 const git_oid* headOid = git_commit_id( headCommit );
2788 bool headIsPublished =
false;
2789 git_reference* upstreamRef =
nullptr;
2791 if( git_branch_upstream( &upstreamRef, headRef ) == GIT_OK )
2794 git_oid upstreamOid;
2796 if( git_reference_name_to_id( &upstreamOid, repo, git_reference_name( upstreamRef ) ) == GIT_OK )
2798 headIsPublished = git_oid_equal( headOid, &upstreamOid )
2799 || git_graph_descendant_of( repo, &upstreamOid, headOid ) == 1;
2803 if( headIsPublished )
2805 wxString upstreamName =
m_TreeProject->GitCommon()->GetUpstreamShorthand();
2807 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2808 wxString::Format(
_(
"The last commit has already been pushed to %s.\n\n"
2809 "Amending rewrites public history. Anyone who pulled "
2810 "this commit will need to reset their copy." ),
2812 _(
"Amend Published Commit?" ), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING | wxCENTER );
2814 dlg.SetYesNoLabels(
_(
"Amend &Anyway" ),
_(
"Cancel" ) );
2816 if( dlg.ShowModal() != wxID_YES )
2830 const DirtyEditor candidates[] = {
2835 std::vector<const DirtyEditor*> dirty;
2837 for(
const DirtyEditor& d : candidates )
2842 dirty.push_back( &d );
2845 if( !dirty.empty() )
2849 for(
const DirtyEditor* d : dirty )
2850 listed += wxString::Format( wxS(
"\n • %s" ), d->label );
2852 wxRichMessageDialog dlg( wxGetTopLevelParent(
this ),
2853 wxString::Format(
_(
"The following editors have unsaved changes:%s\n\n"
2854 "Save them before amending?" ),
2856 _(
"Unsaved Changes" ),
2857 wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_WARNING | wxCENTER );
2859 dlg.SetYesNoCancelLabels(
_(
"&Save and Amend" ),
_(
"Amend &Anyway" ),
_(
"Cancel" ) );
2861 int answer = dlg.ShowModal();
2863 if( answer == wxID_CANCEL )
2866 if( answer == wxID_YES )
2868 for(
const DirtyEditor* d : dirty )
2870 std::string payload;
2871 m_Parent->Kiway().ExpressMail( d->frameType, d->saveMail, payload );
2873 if( payload !=
"success" )
2876 wxString::Format(
_(
"Could not save %s." ), d->label ) );
2883 m_Parent->GetSettingsManager()->SaveProject();
2896 projectPath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2899 std::map<wxString, int> modifiedFiles;
2901 for(
const auto& [absPath, fileStatus] : fileStatusMap )
2910 wxFileName fn( absPath );
2911 wxString relativePath = absPath;
2913 if( relativePath.StartsWith( repoWorkDir ) )
2915 relativePath = relativePath.Mid( repoWorkDir.length() );
2917 relativePath.Replace( wxS(
"\\" ), wxS(
"/" ) );
2921 if( !absPath.StartsWith( projectPath ) )
2932 if( fn.GetPath().Contains(
Prj().GetProjectName() + wxT(
"-backups" ) ) )
2935 modifiedFiles.emplace( relativePath, fileStatus.gitStatus );
2938 if( git_reference* headRefForDiff =
nullptr; git_repository_head( &headRefForDiff, repo ) == GIT_OK )
2941 git_commit* lastCommit =
nullptr;
2943 if( git_reference_peel( (git_object**) &lastCommit, headRefForDiff, GIT_OBJECT_COMMIT ) == GIT_OK )
2946 git_commit* parentCommit =
nullptr;
2947 git_tree* parentTree =
nullptr;
2948 git_tree* lastTree =
nullptr;
2950 if( git_commit_parentcount( lastCommit ) > 0
2951 && git_commit_parent( &parentCommit, lastCommit, 0 ) == GIT_OK )
2953 git_commit_tree( &parentTree, parentCommit );
2959 if( git_commit_tree( &lastTree, lastCommit ) == GIT_OK )
2962 git_diff* diff =
nullptr;
2964 if( git_diff_tree_to_tree( &diff, repo, parentTree, lastTree,
nullptr ) == GIT_OK )
2969 [&modifiedFiles](
const git_diff_delta& aDelta )
2971 const char*
path = aDelta.new_file.path ? aDelta.new_file.path
2972 : aDelta.old_file.path;
2977 int flag = GIT_STATUS_INDEX_MODIFIED;
2979 if( aDelta.status == GIT_DELTA_ADDED )
2980 flag = GIT_STATUS_INDEX_NEW;
2981 else if( aDelta.status == GIT_DELTA_DELETED )
2982 flag = GIT_STATUS_INDEX_DELETED;
2984 modifiedFiles[wxString::FromUTF8(
path )] |=
flag;
2993 dlg.SetTitle(
_(
"Amend Last Commit" ) );
3001 wxMessageBox(
_(
"Discarding amend due to empty commit message." ) );
3011 wxMessageBox( wxString::Format(
_(
"Failed to amend commit: %s" ), commitHandler.
GetErrorString() ) );
3015 wxLogTrace(
traceGit, wxS(
"Amended commit" ) );
3035 for(
const auto& [filePath, fileStatus] : fileStatusMap )
3037 if( filePath.EndsWith( aFile ) || filePath == aFile )
3051 wxLogTrace(
traceGit,
"Syncing project" );
3056 wxLogTrace(
traceGit,
"sync: No git repository found" );
3083 : wxString::Format(
_(
"Fetched from %s." ), remoteName ) );
3142 wxLogTrace(
traceGit,
"onGitSyncTimer" );
3156 wxLogTrace(
traceGit,
"onGitSyncTimer: No git repository found" );
3163 wxLogTrace(
traceGit,
"onGitSyncTimer: Cancelled" );
3177 wxLogTrace(
traceGit,
"onGitSyncTimer: Restarting git sync timer" );
3200 wxLogTrace(
traceGit,
"onGitStatusTimer" );
3213 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.
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.