KiCad PCB EDA Suite
Loading...
Searching...
No Matches
git_advanced_dialog.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <bitmaps.h>
33
34#include <memory>
35
36#include <wx/bitmap.h>
37#include <wx/bmpbndl.h>
38#include <wx/filename.h>
39#include <wx/panel.h>
40#include <wx/sizer.h>
41#include <wx/splitter.h>
42#include <wx/treectrl.h>
43
44#include <confirm.h>
45#include <eda_base_frame.h>
49#include <kiplatform/ui.h>
50#include <kiway.h>
51#include <pgm_base.h>
52#include <project.h>
55#include <thread>
57#include <widgets/ui_common.h>
58#include <widgets/wx_treebook.h>
59
60
62{
63 for( wxWindow* child : aWindow->GetChildren() )
64 {
65 if( dynamic_cast<wxTextEntry*>( child ) )
66 OptOut( child );
67
69 }
70}
71
72
74 DIALOG_GIT_ADVANCED_BASE( aParent ),
75 m_parent( aParent ),
76 m_pane( aPane ),
77 m_historyPage( nullptr ),
78 m_branchesPage( nullptr ),
79 m_remotesPage( nullptr ),
80 m_stashesPage( nullptr ),
81 m_tagsPage( nullptr ),
82 m_repositoryPage( nullptr ),
83 m_changesSplitter( nullptr ),
84 m_changesPane( nullptr ),
85 m_workingDiff( nullptr )
86{
87 m_hash_key = "GitAdvancedDialog";
88
89 m_book->SetFont( KIUI::GetControlFont( this ) );
90
91 m_repoName->SetFont( KIUI::GetControlFont( this ).Bold() );
92 m_book->SetFitToCurrentPage( true );
93
94 // One icon per page, in page order, as the About dialog does for its tabs.
95 wxVector<wxBitmapBundle> pageIcons;
96 pageIcons.push_back( KiBitmapBundleDef( BITMAPS::git_changes, 16 ) );
97 pageIcons.push_back( KiBitmapBundleDef( BITMAPS::git_history, 16 ) );
98 pageIcons.push_back( KiBitmapBundleDef( BITMAPS::git_branches, 16 ) );
99 pageIcons.push_back( KiBitmapBundleDef( BITMAPS::git_remotes, 16 ) );
100 pageIcons.push_back( KiBitmapBundleDef( BITMAPS::git_stashes, 16 ) );
101 pageIcons.push_back( KiBitmapBundleDef( BITMAPS::git_tags, 16 ) );
102 pageIcons.push_back( KiBitmapBundleDef( BITMAPS::git_repository, 16 ) );
103 m_book->SetImages( pageIcons );
104
105 m_book->AddPage( buildChangesPage( m_book ), _( "Changes" ), true, 0 );
107 m_book->AddPage( m_historyPage, _( "History" ), false, 1 );
108
110 m_book->AddPage( m_branchesPage, _( "Branches" ), false, 2 );
111
113 m_book->AddPage( m_remotesPage, _( "Remotes" ), false, 3 );
114
116 m_book->AddPage( m_stashesPage, _( "Stashes" ), false, 4 );
117
119 m_book->AddPage( m_tagsPage, _( "Tags" ), false, 5 );
120
122 m_book->AddPage( m_repositoryPage, _( "Repository" ), false, 6 );
123
124 // Pull and Push run through the docked panel, which owns the merge and its conflict handling.
128
129 m_fetchButton->Bind( wxEVT_BUTTON,
130 [this]( wxCommandEvent& )
131 {
132 onFetch();
133 } );
134 // The choice is empty until the repository is read, so without a floor the top bar lays
135 // it out at the width of nothing and the branch name arrives too late to widen it.
136 m_branchChoice->SetMinSize( FromDIP( wxSize( 110, -1 ) ) );
138
139 m_pane->SetBusyChangedHandler(
140 [this]( bool aBusy )
141 {
142 m_pullButton->Enable( !aBusy );
143 m_pushButton->Enable( !aBusy );
144 } );
145
146 m_pullButton->Bind( wxEVT_BUTTON,
147 [this]( wxCommandEvent& )
148 {
149 m_pane->Pull();
150 } );
151 m_pushButton->Bind( wxEVT_BUTTON,
152 [this]( wxCommandEvent& )
153 {
154 m_pane->Push();
155 } );
156
157 m_branchChoice->Bind( wxEVT_CHOICE,
158 [this]( wxCommandEvent& )
159 {
160 SwitchToBranch( m_branchChoice->GetStringSelection() );
161
162 // A refused switch leaves the choice on a branch the tree is not
163 // on, so put it back on the real one.
164 ReloadPages();
165 } );
166
167 SetupStandardButtons( { { wxID_CANCEL, _( "Close" ) } } );
168
169 // Every box here is filled from the repository. DIALOG_SHIM would otherwise put back the
170 // text a previous session left, keyed by where the control sits in the window, so a value
171 // saved from one page reappears in whichever page now has a box in the same place.
173
174 // The sidebar tree does not invalidate its best size when pages are added, so lay it
175 // out and pin its width, matching how PAGED_DIALOG builds its navigation.
176 m_book->GetTreeCtrl()->InvalidateBestSize();
177
178 for( size_t i = 0; i < m_book->GetPageCount(); ++i )
179 m_book->GetPage( i )->Layout();
180
181 m_book->Layout();
182 m_book->Fit();
183
184 wxSize treeSize = m_book->GetTreeCtrl()->GetSize();
185 treeSize.x += 20;
186 m_book->GetTreeCtrl()->SetMinSize( treeSize );
187
188 // A page is a bare list whose natural size is a few rows, so without a floor the first
189 // open is a stamp. A saved size still wins once there is one.
190 m_book->SetMinSize( FromDIP( wxSize( 800, 600 ) ) );
191 m_book->Layout();
192
193 Bind(
194 wxEVT_BUTTON,
195 [this]( wxCommandEvent& )
196 {
197 Close();
198 },
199 wxID_CANCEL );
200
201 ReloadPages();
202
203 // A commit, push or pull from any surface broadcasts a change, so the window never goes stale.
204 syncListener();
205
207}
208
209
210// One window per process. KiCad has one project open at a time and every frame shares it.
215
216
218{
220}
221
222
227
228
230{
231 if( !activeDialog() )
232 {
233 GIT_ADVANCED_DIALOG* dialog = new GIT_ADVANCED_DIALOG( aParent, aPane );
234
235 dialog->Bind( wxEVT_CLOSE_WINDOW,
236 [dialog]( wxCloseEvent& )
237 {
238 if( activeDialog() == dialog )
239 setActiveDialog( nullptr );
240
241 // Hiding through DIALOG_SHIM records the size for the next open. This
242 // handler takes the close event, so the base class's own save never
243 // runs.
244 dialog->Show( false );
245 dialog->Destroy();
246 } );
247
248 setActiveDialog( dialog );
249 }
250
251 activeDialog()->Show( true );
252 activeDialog()->Raise();
253}
254
255
257{
258 // Destroy() only schedules the delete, so the pointer is dropped here. Reopening before the
259 // event loop gets round to it then builds a new window instead of raising a dying one.
260 if( GIT_ADVANCED_DIALOG* dialog = activeDialog() )
261 {
262 setActiveDialog( nullptr );
263 dialog->Destroy();
264 }
265}
266
267
269{
270 if( activeDialog() && activeDialog()->m_pane == aPane )
271 {
272 aPane->SetBusyChangedHandler( nullptr );
273 aPane->SetMessageChangedHandler( nullptr );
274 activeDialog()->m_pane = nullptr;
275 CloseActive();
276 }
277}
278
279
281{
282 m_reloadQuery.Cancel();
283 m_actionQuery.Cancel();
284 m_fetchQuery.Cancel();
285
286 // The panel usually outlives this window, so it must not be left calling into it. When the
287 // panel went first it cleared this and dropped the pointer.
288 if( m_pane )
289 {
290 m_pane->SetBusyChangedHandler( nullptr );
291 m_pane->SetMessageChangedHandler( nullptr );
292 }
293
294 if( activeDialog() == this )
295 setActiveDialog( nullptr );
296
297 // A push or fetch outlives this window, and its completion refreshes the other windows, so
298 // nothing has to be reported here. The transfers stop themselves as they go.
299 m_branchesPage->StopTransfer();
300
301 if( std::shared_ptr<KIGIT_COMMON> session = m_listenerSession.lock() )
302 session->RemoveRefreshListener( this );
303}
304
305
307{
308 std::shared_ptr<KIGIT_COMMON> common = m_parent->Prj().GetGitCommon();
309
311 {
312 // Pending reads belong to the original session just as much as the displayed rows do.
313 // Never rebind this window and accept an old result into a new project's controls.
314 if( m_listenerSession.lock() != common )
316
317 return;
318 }
319
320 common->AddRefreshListener( this,
321 [this]()
322 {
323 ReloadPages();
324 } );
325 m_listenerSession = common;
326 m_listenerAttached = true;
327}
328
329
330void GIT_ADVANCED_DIALOG::SetPaneTransferBusy( bool aBusy, const wxString& aStatus )
331{
332 // Two forms on one project, so both follow the transfer.
333 if( m_changesPane )
334 m_changesPane->SetTransferBusy( aBusy, aStatus );
335
336 if( m_pane )
337 m_pane->SetTransferBusy( aBusy, aStatus );
338}
339
340
341void GIT_ADVANCED_DIALOG::ShowTransferProgress( const wxString& aText )
342{
343 if( m_changesPane )
344 m_changesPane->ShowTransferProgress( aText );
345 else if( m_pane )
346 m_pane->ShowTransferProgress( aText );
347}
348
349
351{
352 syncListener();
353
354 if( !SessionStillCurrent() )
355 return;
356
358 m_historyPage->Populate();
359 m_branchesPage->Populate();
360 m_remotesPage->Populate();
361 m_stashesPage->Populate();
362 m_tagsPage->Populate();
363 m_repositoryPage->Populate();
364}
365
366
367void GIT_ADVANCED_DIALOG::ShowHistoryForFile( EDA_BASE_FRAME* aParent, GIT_COMMIT_PANE* aPane, const wxString& aPath )
368{
369 ShowForFrame( aParent, aPane );
371}
372
373
374void GIT_ADVANCED_DIALOG::ShowHistoryForFile( const wxString& aPath )
375{
376 m_book->SetSelection( 1 );
377 m_historyPage->ShowHistoryForFile( aPath );
378}
379
380
381void GIT_ADVANCED_DIALOG::ShowAmend( const wxString& aCommitHash )
382{
383 if( !SessionStillCurrent() )
384 return;
385
386 m_book->SetSelection( 0 );
387 m_changesPane->BeginAmend( aCommitHash );
388}
389
390
391wxWindow* GIT_ADVANCED_DIALOG::buildChangesPage( wxWindow* aBook )
392{
393 wxPanel* panel = new wxPanel( aBook );
394 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
395
396 // The commit controls above, and once a file is picked, its changes below.
397 m_changesSplitter = new wxSplitterWindow( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
398 wxSP_LIVE_UPDATE | wxSP_3DSASH );
399 m_changesSplitter->SetMinimumPaneSize( panel->FromDIP( 120 ) );
400 m_changesSplitter->SetSashGravity( 0.5 );
401 m_changesSashPos = panel->FromDIP( 260 );
402
405
406 m_changesSplitter->Initialize( m_changesPane );
407 m_workingDiff->Hide();
408
409 sizer->Add( m_changesSplitter, 1, wxEXPAND | wxALL, 4 );
410 panel->SetSizer( sizer );
411
412 // The docked panel and this page are two forms on one project, so the message starts from
413 // what the panel already holds and goes back to it as the user types. This window closes
414 // with the panel, so the panel is always there to write to.
415 if( m_pane )
416 {
417 m_changesPane->SetCommitMessage( m_pane->GetCommitMessage() );
418
419 m_changesPane->SetMessageChangedHandler(
420 [this]()
421 {
422 m_pane->SetCommitMessage( m_changesPane->GetCommitMessage() );
423 } );
424
425 // SetCommitMessage writes with ChangeValue, so neither form echoes back into the other.
426 m_pane->SetMessageChangedHandler(
427 [this]()
428 {
429 m_changesPane->SetCommitMessage( m_pane->GetCommitMessage() );
430 } );
431 }
432
433 m_changesPane->SetFileSelectedHandler(
434 [this]( const wxString& aPath )
435 {
436 showWorkingDiff( aPath );
437 } );
438
439 return panel;
440}
441
442
448
449
450void GIT_ADVANCED_DIALOG::showWorkingDiff( const wxString& aPath )
451{
452 if( aPath.IsEmpty() || !m_parent->Prj().GetGitCommon()->GetRepo() )
453 {
455 return;
456 }
457
458 // The top bar already names the branch the working tree is on.
459 wxString branch = m_branchChoice->GetStringSelection();
460 wxString baseLabel = branch.IsEmpty() ? _( "BASE (HEAD)" ) : wxString::Format( _( "BASE (%s)" ), branch );
461
462 m_workingDiff->ShowFile(
463 m_parent->Prj().GetGitCommon(),
464 [path = aPath]( KIGIT_COMMON& aCommon, GIT_DIFF_WORKSPACE& aWorkspace, GIT_FILE_SIDES& aSides )
465 {
466 return MaterializeWorkingFile( aCommon, aWorkspace, path, aSides );
467 },
468 baseLabel, _( "WORKING (changes)" ) );
469
470 if( !m_changesSplitter->IsSplit() )
472}
473
474
475void GIT_ADVANCED_DIALOG::SwitchToBranch( const wxString& aBranch )
476{
477 if( !SessionStillCurrent() )
478 return;
479
481}
482
483
485{
486 struct RESULT
487 {
488 wxString current;
489 wxString root;
490 std::vector<KIGIT_BRANCH_INFO> branches;
491 };
492
493 std::shared_ptr<KIGIT_COMMON> common = m_parent->Prj().GetGitCommon();
494 auto result = std::make_shared<RESULT>();
495
496 m_reloadQuery.Run(
497 common,
498 [result]( KIGIT_COMMON& aCommon )
499 {
500 result->current = aCommon.GetCurrentBranchName();
501 result->root = aCommon.GetGitRootDirectory();
502 result->branches = aCommon.GetBranches();
504 },
505 [this, common, result]()
506 {
507 if( common != m_parent->Prj().GetGitCommon() || common->IsShuttingDown() )
508 return;
509
510 wxFileName root = wxFileName::DirName( result->root );
511 m_repoName->SetLabel( root.GetDirs().empty() ? root.GetFullPath() : root.GetDirs().Last() );
512 m_branchChoice->Clear();
513
514 // Only a local branch can be checked out here. Remote ones are on the Branches page.
515 for( const KIGIT_BRANCH_INFO& branch : result->branches )
516 {
517 if( !branch.isRemote )
518 m_branchChoice->Append( branch.name );
519 }
520
521 m_branchChoice->SetStringSelection( result->current );
522 m_historyPage->SetBranches( result->branches );
523 m_branchChoice->InvalidateBestSize();
524 Layout();
525 } );
526}
527
528
530{
531 if( !SessionStillCurrent() )
532 return;
533
534 if( m_fetch.IsBusy() || m_fetchQuery.IsBusy() )
535 {
537 return;
538 }
539
540 std::shared_ptr<KIGIT_COMMON> common = m_parent->Prj().GetGitCommon();
541 auto hasRemote = std::make_shared<bool>( false );
542
543 m_fetchButton->SetLabel( _( "Fetching..." ) );
544 m_fetchButton->Disable();
545 SetPaneTransferBusy( true, _( "Fetching..." ) );
546 Layout();
547
548 m_fetchQuery.Run(
549 common,
550 [hasRemote]( KIGIT_COMMON& aCommon )
551 {
552 *hasRemote = aCommon.HasPushAndPullRemote();
553 },
554 [this, common, hasRemote]()
555 {
556 if( !SessionStillCurrent() )
557 return;
558
559 if( !*hasRemote )
560 {
561 m_fetchButton->SetLabel( _( "Fetch" ) );
562 m_fetchButton->Enable();
563 Layout();
564 DisplayInfoMessage( this, _( "No remote is configured to get changes from." ) );
565 return;
566 }
567
568 startFetch( common );
569 } );
570}
571
572
573void GIT_ADVANCED_DIALOG::startFetch( std::shared_ptr<KIGIT_COMMON> aCommon )
574{
575 m_fetchButton->SetLabel( _( "Fetching..." ) );
576 m_fetchButton->Disable();
577 Layout();
578
579 // Carried rather than captured by reference, because Start returns before the work runs.
580 struct OUTCOME
581 {
582 bool fetched = false;
583 wxString error;
584 bool authFailure = false;
585 bool cancelled = false;
586 };
587
588 auto outcome = std::make_shared<OUTCOME>();
589
590 bool started = m_fetch.Start(
591 "git fetch",
592 [aCommon, outcome, alive = m_fetch.Alive(), dialog = this]( const KIGIT_COMMON::CANCEL_TOKEN& aToken )
593 {
594 aCommon->ClearAuthFailure();
595
596 GIT_PULL_HANDLER handler( aCommon.get() );
597 handler.SetProgressReporter( std::make_unique<KIGIT_STATUS_REPORTER>(
598 alive,
599 [dialog]( const wxString& aText )
600 {
601 dialog->ShowTransferProgress( aText );
602 } ) );
603 handler.SetCancelToken( aToken );
604 handler.SetWaitForActionLock( true );
605 outcome->fetched = handler.PerformFetch();
606 outcome->error = handler.GetErrorStrings().empty() ? wxString() : handler.GetErrorString();
607 outcome->authFailure = aCommon->WasAuthFailure();
608
609 // This operation's own token, so a fetch that never became active cannot
610 // consume a cancel belonging to the transfer that is running.
611 outcome->cancelled = handler.IsThisOperationCancelled();
612
613 // The other surfaces need this even when the window that started it has gone.
614 if( outcome->fetched && !outcome->cancelled )
615 {
617 [aCommon]()
618 {
619 aCommon->NotifyRefreshListeners();
620 } );
621 }
622 },
623 [this, aCommon, outcome]()
624 {
625 if( !SessionStillCurrent() )
626 return;
627
628 m_fetchButton->SetLabel( _( "Fetch" ) );
629 m_fetchButton->Enable();
630 SetPaneTransferBusy( false );
631 Layout();
632
633 if( outcome->cancelled || outcome->fetched )
634 return;
635
636 if( outcome->authFailure && KIGIT::PromptForCredentials( this, aCommon.get(), &m_parent->Prj() ) )
637 {
638 onFetch();
639 return;
640 }
641
642 DisplayErrorMessage( this, _( "Fetch failed." ), outcome->error );
643 } );
644
645 if( !started )
646 {
647 m_fetchButton->SetLabel( _( "Fetch" ) );
648 m_fetchButton->Enable();
649 SetPaneTransferBusy( false );
650 Layout();
651 DisplayInfoMessage( this, _( "Could not start the fetch." ) );
652 }
653}
654
655
656void GIT_ADVANCED_DIALOG::RefuseOverUncommittedWork( std::function<void( const GIT_WORKTREE_STATUS& )> aReady )
657{
658 if( !SessionStillCurrent() )
659 return;
660
662 [this, aReady]( const GIT_WORKTREE_STATUS& aStatus )
663 {
664 if( SessionStillCurrent() )
665 aReady( aStatus );
666 } );
667}
668
669
671{
672 if( !SessionStillCurrent() )
673 return false;
674
675 // Save rather than close: this window is parented to the frame hosting the panel, so a close
676 // would destroy that frame and this dialog with it, mid-call.
678 return false;
679
680 if( !SessionStillCurrent() )
681 return false;
682
684 return true;
685}
686
687
689{
690 if( !SessionStillCurrent() || !ProjectSafeToRewrite( m_parent, this, aStatus ) )
691 return false;
692
694 return true;
695}
696
697
699{
700 if( IsBeingDeleted() || m_parent->IsBeingDeleted() )
701 return false;
702
703 std::shared_ptr<KIGIT_COMMON> session = m_listenerSession.lock();
704
705 if( m_listenerAttached && session && !session->IsShuttingDown() && session == m_parent->Prj().GetGitCommon()
706 && Pgm().GetCommonSettings()->m_Git.enableGit && !m_parent->Prj().GetLocalSettings().m_GitIntegrationDisabled )
707 {
708 return true;
709 }
710
711 // A window and its pending reads belong to the session it opened with. Once it changes,
712 // close rather than act on identically named branches or files in another project.
713 m_reloadQuery.Cancel();
714 m_actionQuery.Cancel();
715 m_fetchQuery.Cancel();
716 Close();
717 return false;
718}
719
720
721void GIT_ADVANCED_DIALOG::RunGitAction( const std::function<bool( KIGIT_COMMON& )>& aFn, const wxString& aError,
722 bool aRewritesWorkingTree )
723{
725 [&aFn]( KIGIT_COMMON& aCommon, wxString& )
726 {
727 return aFn( aCommon );
728 },
729 aError, aRewritesWorkingTree );
730}
731
732
733void GIT_ADVANCED_DIALOG::RunGitAction( const std::function<bool( KIGIT_COMMON&, wxString& )>& aFn,
734 const wxString& aError, bool aRewritesWorkingTree )
735{
736 if( !SessionStillCurrent() )
737 return;
738
739 std::shared_ptr<KIGIT_COMMON> common = m_parent->Prj().GetGitCommon();
740 bool ok = false;
741 wxString detail;
742
743 {
744 // Release the lock before reloading editors and refreshing other Git views.
745 std::unique_lock<std::mutex> lock = KIGIT::TryLockAction( *common, this );
746
747 if( !lock.owns_lock() )
748 return;
749
750 ok = aFn( *common, detail );
751 }
752
753 if( !ok )
754 {
755 // A failed action can still have written files, so the editors and the panels are
756 // brought up to date first. Nothing reloads when nothing changed on disk.
757 if( aRewritesWorkingTree )
758 {
760 common->NotifyRefreshListeners();
761 }
762
763 DisplayErrorMessage( this, aError, detail.IsEmpty() ? KIGIT_COMMON::GetLastGitError() : detail );
764 return;
765 }
766
767 if( aRewritesWorkingTree )
768 {
769 // The files the editors have open were just rewritten, so pull them back in from disk.
771 }
772
773 common->NotifyRefreshListeners();
774}
775
776
wxBitmapBundle KiBitmapBundleDef(BITMAPS aBitmap, int aDefHeight)
Construct and return a bitmap bundle for the given icon ID, with the default bitmap size being aDefHe...
Definition bitmap.cpp:112
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:106
DIALOG_GIT_ADVANCED_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Advanced Git"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
bool Show(bool show) override
void OptOut(wxWindow *aWindow)
Opt out of control state saving.
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
The base frame for deriving all KiCad main window classes.
The advanced Git window: a non-modal dialog with a top bar naming the repository and branch and a sid...
EDA_BASE_FRAME * m_parent
GIT_ADVANCED_DIALOG(EDA_BASE_FRAME *aParent, GIT_COMMIT_PANE *aPane)
static void ShowHistoryForFile(EDA_BASE_FRAME *aParent, GIT_COMMIT_PANE *aPane, const wxString &aPath)
Open the window on its History page, narrowed to the commits that changed aPath.
PANEL_GIT_BRANCHES * m_branchesPage
void RefuseOverUncommittedWork(std::function< void(const GIT_WORKTREE_STATUS &)> aReady)
Check the working tree and LFS on a worker, then continue on the UI thread only when nothing is uncom...
void ShowTransferProgress(const wxString &aText)
Show a line of transfer progress on the hosted commit panel's status line.
void showWorkingDiff(const wxString &aPath)
Show the working copy of aPath against its committed version, or hide that area.
GIT_FILE_DIFF_AREA * m_workingDiff
void SwitchToBranch(const wxString &aBranch)
Switch the working tree to the named branch, after confirming, then refresh.
static void CloseForPane(GIT_COMMIT_PANE *aPane)
Close the live window if the given pane opened it, for when that pane goes away.
PANEL_GIT_REPOSITORY * m_repositoryPage
PANEL_GIT_HISTORY * m_historyPage
PANEL_GIT_REMOTES * m_remotesPage
EDITOR_SNAPSHOT m_docsBeforeChange
On-disk identity of the open documents, taken by ConfirmWorkingTreeChange() so only the documents an ...
bool ConfirmWorkingTreeChange()
After the asynchronous LFS check, save the open editors and snapshot their documents before an action...
static void CloseActive()
Close the live window, for when the project it was filled from goes away.
wxSplitterWindow * m_changesSplitter
KIGIT_QUERY m_reloadQuery
Reads the top bar and history branch choices without holding up the UI.
std::weak_ptr< KIGIT_COMMON > m_listenerSession
static GIT_ADVANCED_DIALOG * Active()
The live window, or null when none is open.
void RunGitAction(const std::function< bool(KIGIT_COMMON &)> &aFn, const wxString &aError, bool aRewritesWorkingTree=false)
Run a repository write under the action lock, then refresh every surface on success.
void startFetch(std::shared_ptr< KIGIT_COMMON > aCommon)
PANEL_GIT_STASHES * m_stashesPage
void syncListener()
Attach once to the project's session.
static void ShowForFrame(EDA_BASE_FRAME *aParent, GIT_COMMIT_PANE *aPane)
Raise the one window for this session, creating it on first use.
KIGIT_QUERY m_actionQuery
Preflight reads for actions that may replace the working tree.
GIT_COMMIT_PANE * m_pane
bool SessionStillCurrent()
True while the frame's git session is still the one this window's lists were filled from.
void onFetch()
Fetch from the remote on a worker, then refresh every surface.
void SetPaneTransferBusy(bool aBusy, const wxString &aStatus=wxEmptyString)
Put the hosted commit panel into, or out of, its transfer state, for a transfer this window or one of...
wxWindow * buildChangesPage(wxWindow *aBook)
The Changes page: the docked panel's commit controls with the selected file's diff below.
GIT_COMMIT_PANE * m_changesPane
int m_changesSashPos
Where the user left the sash between the Changes page's list and its diff area.
void optOutOfTextPersistence(wxWindow *aWindow)
Keep every text box in aWindow out of the dialog's saved control state.
void ShowAmend(const wxString &aCommitHash)
Open the Changes page to amend the selected history commit.
KIGIT_TRANSFER m_fetch
The fetch the top bar started.
PANEL_GIT_TAGS * m_tagsPage
void populateTopBar()
Fill the top bar's repository name and branch list.
Docked panel for committing: the branch to commit to, a summary and description, the commit options,...
void SetBusyChangedHandler(std::function< void(bool)> aHandler)
Called when a transfer starts and when it ends, so an owning window can follow along.
void SetMessageChangedHandler(std::function< void()> aHandler)
Called when the user edits the message, so another form can follow along.
A private scratch directory for extracting committed file versions to diff, removed when this object ...
Shows what changed in one file: the old and new drawing side by side for a schematic or board,...
The project's git session.
std::shared_ptr< std::atomic< bool > > CANCEL_TOKEN
One token per operation.
static wxString GetLastGitError()
wxString GetCurrentBranchName() const
wxString GetGitRootDirectory() const
bool HasPushAndPullRemote() const
std::vector< KIGIT_BRANCH_INFO > GetBranches() const
Local and remote branches with their tip commits.
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
The advanced git window's Branches page: a searchable list beside the selected branch's detail,...
The advanced git window's History page: filters above a list of commits beside the selected commit's ...
The advanced git window's Remotes page: the list beside the selected remote's detail,...
Show the repository's author and open the shared identity editor.
The advanced git window's Stashes page: the list beside the selected stash's detail,...
The advanced git window's Tags page: the list beside the selected tag's detail, with the actions that...
virtual std::shared_ptr< KIGIT_COMMON > GetGitCommon() const
This project's Git session, created empty on first use.
Definition project.cpp:84
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
#define _(s)
Base window classes and related definitions.
static void setActiveDialog(GIT_ADVANCED_DIALOG *aDialog)
static GIT_ADVANCED_DIALOG * activeDialog()
bool PrepareEditorsForGitOperation(EDA_BASE_FRAME *aFrame, GIT_EDITOR_PREP aPurpose, bool *aSavedEditors)
Offer to save unsaved schematic and board edits before a git operation.
EDITOR_SNAPSHOT CaptureOpenEditorDocs(KIWAY &aKiway)
Record the on-disk identity of the open documents, before an operation that may rewrite them.
void ReloadOpenEditors(KIWAY &aKiway, const EDITOR_SNAPSHOT &aBefore)
Tell the open board and schematic editors to reload from disk.
void ProjectClearOfUncommittedWork(EDA_BASE_FRAME *aFrame, wxWindow *aParent, KIGIT_QUERY &aQuery, std::function< void(const GIT_WORKTREE_STATUS &)> aReady)
Check the working tree and Git LFS on a worker, then run aReady on the UI thread when the operation c...
bool ProjectSafeToRewrite(EDA_BASE_FRAME *aFrame, wxWindow *aParent, const GIT_WORKTREE_STATUS &aStatus, bool aAllowTrackedChanges)
Combine the repository snapshot with live editor state and explain any refusal.
void SwitchProjectToBranch(EDA_BASE_FRAME *aFrame, wxWindow *aParent, const wxString &aBranch, KIGIT_QUERY &aQuery, std::function< void()> aFinished)
Check the working tree on a worker, then confirm switching to aBranch and recheck unsaved editors.
@ WORKING_TREE
The working files are about to be rewritten, by a pull, branch switch or stash.
void SortBranchesForDisplay(std::vector< KIGIT_BRANCH_INFO > &aBranches)
Put the current branch first, then local and remote branches with the newest tips first.
void UnsplitKeepingSash(wxSplitterWindow *aSplitter, wxWindow *aPane, int &aSashPos)
Close a splitter's second pane, keeping the sash where the user left it for next time.
bool PromptForCredentials(wxWindow *aParent, KIGIT_COMMON *aCommon, PROJECT *aProject=nullptr)
Ask the user for the credentials of the session's remote and apply them to the session.
void ShowBusyMessage(wxWindow *aParent)
Show a busy message for a user action. UI thread only.
std::unique_lock< std::mutex > TryLockAction(KIGIT_COMMON &aCommon, wxWindow *aParent)
Try the action lock and show a busy message if it is unavailable.
APIEXPORT wxWindow *& ActiveAdvancedGitWindow()
The advanced git window, or null when none is open.
void CallOnUi(std::function< void()> aFn)
Run aFn on the UI thread.
void EllipsizeChoiceBox(wxChoice *aChoice)
Configure a wxChoice control to ellipsize the shown text in the button with the ellipses placed at th...
Definition wxgtk/ui.cpp:407
KICOMMON_API wxFont GetControlFont(wxWindow *aWindow)
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
The two sides of one file, written out for a comparison.
Repository state used before an operation that requires a clean working tree.
std::string path
wxString result
Test unit parsing edge cases and error handling.
Functions to provide common constants and other functions to assist in making a consistent UI.