KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_git_remotes.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include <memory>
23
24#include <wx/datetime.h>
25
26#include <confirm.h>
30#include <eda_base_frame.h>
32#include <project.h>
33
34
36 PANEL_GIT_REMOTES_BASE( aParent ),
37 m_dialog( aDialog ),
38 m_frame( aFrame )
39{
40 m_remotesList->AppendColumn( _( "Name" ), wxLIST_FORMAT_LEFT, FromDIP( 110 ) );
41 m_remotesList->AppendColumn( _( "URL" ), wxLIST_FORMAT_LEFT, FromDIP( 340 ) );
42
44
45 // The detail pane appears once a remote is selected.
46 m_remoteSashPos = FromDIP( 460 );
48
49 m_remotesList->Bind( wxEVT_LIST_ITEM_SELECTED,
50 [this]( wxListEvent& aEvent )
51 {
52 if( !m_fillingRemotes )
53 showRemoteDetail( m_remotesList->GetItemText( aEvent.GetIndex(), 0 ) );
54 } );
55
56 m_remotesList->Bind( wxEVT_LIST_ITEM_DESELECTED,
57 [this]( wxListEvent& )
58 {
60 && m_remotesList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ) == -1 )
61 {
63 }
64 } );
65
66 m_editUrlButton->Bind( wxEVT_BUTTON,
67 [this]( wxCommandEvent& )
68 {
70 } );
71 m_removeRemoteButton->Bind( wxEVT_BUTTON,
72 [this]( wxCommandEvent& )
73 {
75 } );
76 m_addRemoteButton->Bind( wxEVT_BUTTON,
77 [this]( wxCommandEvent& )
78 {
80 } );
81}
82
83
85{
86 if( !m_dialog->SessionStillCurrent() )
87 return;
88
89 struct OUTCOME
90 {
91 std::vector<std::pair<wxString, wxString>> remotes;
92 wxDateTime fetched;
93 };
94
95 auto outcome = std::make_shared<OUTCOME>();
96
97 m_listQuery.Run(
98 m_frame->Prj().GetGitCommon(),
99 [outcome]( KIGIT_COMMON& aCommon )
100 {
101 outcome->remotes = aCommon.GetRemotes();
102 outcome->fetched = aCommon.GetLastFetchTime();
103 },
104 [this, outcome]()
105 {
106 if( !m_dialog->SessionStillCurrent() )
107 return;
108
109 wxString selected = KIGIT::SelectedText( m_remotesList, 0 );
110 long selectRow = wxNOT_FOUND;
111
112 m_fillingRemotes = true;
113 m_remotesList->DeleteAllItems();
114 m_lastFetched = outcome->fetched;
115
116 for( const auto& [name, url] : outcome->remotes )
117 {
118 long idx = m_remotesList->InsertItem( m_remotesList->GetItemCount(), name );
119 m_remotesList->SetItem( idx, 1, url );
120
121 // Keep the selection where it was, or start on the first remote.
122 if( name == selected || ( selected.IsEmpty() && idx == 0 ) )
123 selectRow = idx;
124 }
125
126 int shown = m_remotesList->GetItemCount();
127 m_remoteCount->SetLabel( shown == 1 ? _( "1 remote" ) : wxString::Format( _( "%d remotes" ), shown ) );
128
129 if( selectRow != wxNOT_FOUND )
130 {
131 m_remotesList->SetItemState( selectRow, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
132 showRemoteDetail( m_remotesList->GetItemText( selectRow, 0 ) );
133 }
134 else
135 {
137 }
138
139 m_fillingRemotes = false;
140 } );
141}
142
143
144void PANEL_GIT_REMOTES::showRemoteDetail( const wxString& aRemote )
145{
146 if( aRemote.IsEmpty() )
147 {
149 return;
150 }
151
152 // FETCH_HEAD belongs to the repository, so every remote shares the listing's timestamp.
154}
155
156
157void PANEL_GIT_REMOTES::fillRemoteDetail( const wxString& aRemote, const wxDateTime& aFetched )
158{
159 // The list already holds the address.
160 wxString url;
161
162 for( long row = 0; row < m_remotesList->GetItemCount(); ++row )
163 {
164 if( m_remotesList->GetItemText( row, 0 ) == aRemote )
165 url = m_remotesList->GetItemText( row, 1 );
166 }
167
168 m_remoteTitle->SetLabel( wxString::Format( _( "Remote: %s" ), aRemote ) );
169 m_remoteUrl->ChangeValue( url );
170
171 // Git records fetches in FETCH_HEAD and nothing about pulls or pushes, so only that one
172 // can be shown.
173 m_remoteFetched->SetLabel( aFetched.IsValid()
174 ? wxString::Format( _( "Last fetch: %s" ), KIGIT::RelativeDate( aFetched ) )
175 : _( "Not fetched yet." ) );
176
177 if( !m_remotesSplitter->IsSplit() )
179
180 m_remoteDetail->Layout();
181}
182
183
188
189
190void PANEL_GIT_REMOTES::runRemoteAction( const std::function<bool( KIGIT_COMMON& )>& aMutation, const wxString& aError )
191{
192 m_dialog->RunGitAction(
193 [&aMutation]( KIGIT_COMMON& aCommon )
194 {
195 if( !aMutation( aCommon ) )
196 return false;
197
198 // Refresh the cached URL and credentials, so a later push does not reach the new
199 // remote authenticating as the old one.
200 aCommon.UpdateCurrentBranchInfo();
201 return true;
202 },
203 aError );
204}
205
206
208{
209 if( !m_dialog->SessionStillCurrent() )
210 return;
211
212 DIALOG_GIT_REMOTE dlg( this );
213
214 if( dlg.ShowModal() != wxID_OK )
215 return;
216
217 wxString name = dlg.GetName();
218 wxString url = dlg.GetUrl();
219
221 [name, url]( KIGIT_COMMON& aCommon )
222 {
223 return aCommon.AddRemote( name, url );
224 },
225 wxString::Format( _( "Could not add remote '%s'." ), name ) );
226}
227
228
230{
231 if( !m_dialog->SessionStillCurrent() )
232 return;
233
234 wxString name = KIGIT::SelectedText( m_remotesList, 0 );
235
236 if( name.IsEmpty() )
237 return;
238
239 wxString current = KIGIT::SelectedText( m_remotesList, 1 );
240 DIALOG_GIT_REMOTE dlg( this, name, current );
241
242 if( dlg.ShowModal() != wxID_OK )
243 return;
244
245 wxString url = dlg.GetUrl();
246
247 // The list shows the address with any user:password removed, so writing it back unchanged
248 // would delete credentials the config still holds.
249 if( url == current )
250 return;
251
253 [name, url]( KIGIT_COMMON& aCommon )
254 {
255 return aCommon.SetRemoteUrl( name, url );
256 },
257 wxString::Format( _( "Could not update remote '%s'." ), name ) );
258}
259
260
262{
263 if( !m_dialog->SessionStillCurrent() )
264 return;
265
266 wxString name = KIGIT::SelectedText( m_remotesList, 0 );
267
268 if( name.IsEmpty() )
269 return;
270
271 if( !IsOK( this, wxString::Format( _( "Remove remote '%s'?" ), name ) ) )
272 return;
273
275 [name]( KIGIT_COMMON& aCommon )
276 {
277 return aCommon.RemoveRemote( name );
278 },
279 wxString::Format( _( "Could not remove remote '%s'." ), name ) );
280}
const char * name
Ask for a remote's name and URL, for adding one or for editing the URL of one that exists.
wxString GetName() const
wxString GetUrl() const
int ShowModal() override
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...
The project's git session.
bool RemoveRemote(const wxString &aName)
bool AddRemote(const wxString &aName, const wxString &aUrl)
bool SetRemoteUrl(const wxString &aName, const wxString &aUrl)
wxSplitterWindow * m_remotesSplitter
PANEL_GIT_REMOTES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
GIT_ADVANCED_DIALOG * m_dialog
PANEL_GIT_REMOTES(wxWindow *aParent, GIT_ADVANCED_DIALOG *aDialog, EDA_BASE_FRAME *aFrame)
KIGIT_QUERY m_listQuery
The list and its shared fetch timestamp are read together on a worker.
bool m_fillingRemotes
True while the list is being refilled, when its selection events are its own.
int m_remoteSashPos
Where the user left the sash between the list and its detail pane.
EDA_BASE_FRAME * m_frame
void Populate()
Fill the list from the repository's remotes. The repository is read on a worker.
void fillRemoteDetail(const wxString &aRemote, const wxDateTime &aFetched)
void runRemoteAction(const std::function< bool(KIGIT_COMMON &)> &aMutation, const wxString &aError)
Run a change to the remotes, then refresh the cached remote so a later push uses it.
void showRemoteDetail(const wxString &aRemote)
Fill the detail pane with aRemote, or hide it when the name is empty.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
This file is part of the common library.
#define _(s)
Base window classes and related definitions.
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.
wxString SelectedText(wxListCtrl *aList, int aColumn)
The text of the selected row in a report list, or empty when nothing is selected.
wxString RelativeDate(const wxDateTime &aWhen)
"just now", "3 hours ago", or the ISO date once it is more than a month old.
void MarkDestructive(wxButton *aButton)
Paint a button's text the diff's red, for one that throws something away.