KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_git_switch.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, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24
25#include "dialog_git_switch.h"
26
28#include <trace_helpers.h>
29
30#include <wx/button.h>
31#include <wx/checkbox.h>
32#include <wx/listctrl.h>
33#include <wx/log.h>
34#include <wx/event.h>
35#include <wx/sizer.h>
36#include <wx/timer.h>
37#include <wx/stattext.h>
38#include <wx/textctrl.h>
39
40#include <git2.h>
41
42
43// Strip the "* " / " " prefix used to mark the current branch in the list.
44static wxString stripBranchMarker( const wxString& aName )
45{
46 if( aName.StartsWith( wxS( "* " ) ) || aName.StartsWith( wxS( " " ) ) )
47 return aName.Mid( 2 );
48
49 return aName;
50}
51
52
53DIALOG_GIT_SWITCH::DIALOG_GIT_SWITCH( wxWindow* aParent, git_repository* aRepository ) :
54 DIALOG_SHIM( aParent, wxID_ANY, _( "Git Branch Switch" ), wxDefaultPosition, wxDefaultSize,
55 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
56 m_timer( this ), m_repository( aRepository )
57{
58 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
59
60 // Add explanation text
61 wxStaticText* explanationText =
62 new wxStaticText( this, wxID_ANY, _( "Select or enter a branch name:" ) );
63 sizer->Add( explanationText, 0, wxALL, 10 );
64
65 // Add branch list with three columns
66 m_branchList = new wxListView( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
67 wxLC_REPORT | wxLC_SINGLE_SEL );
68 m_branchList->InsertColumn( 0, _( "Branch" ) );
69 m_branchList->InsertColumn( 1, _( "Last Commit" ) );
70 m_branchList->InsertColumn( 2, _( "Last Updated" ) );
71 sizer->Add( m_branchList, 1, wxALL | wxEXPAND, 10 );
72
73 // Add branch name text box
74 m_branchNameText = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition,
75 wxDefaultSize, wxTE_PROCESS_ENTER );
76 sizer->Add( m_branchNameText, 0, wxALL | wxEXPAND, 10 );
77
78 // Add buttons
79 wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
80 m_switchButton = new wxButton( this, wxID_OK, _( "Switch" ) );
81 buttonSizer->AddButton( m_switchButton );
82 m_switchButton->Disable();
83 wxButton* cancelButton = new wxButton( this, wxID_CANCEL, _( "Cancel" ) );
84 buttonSizer->AddButton( cancelButton );
85 buttonSizer->Realize();
86 sizer->Add( buttonSizer, 0, wxALIGN_RIGHT | wxALL, 10 );
87
88 // Bind events
89 Bind( wxEVT_LIST_ITEM_SELECTED, &DIALOG_GIT_SWITCH::OnBranchListSelection, this, m_branchList->GetId() );
90 Bind( wxEVT_LIST_ITEM_ACTIVATED, &DIALOG_GIT_SWITCH::OnBranchListDClick, this, m_branchList->GetId() );
91 Bind( wxEVT_BUTTON, &DIALOG_GIT_SWITCH::OnSwitchButton, this, m_switchButton->GetId() );
92 Bind( wxEVT_BUTTON, &DIALOG_GIT_SWITCH::OnCancelButton, this, cancelButton->GetId() );
93 Bind( wxEVT_TEXT, &DIALOG_GIT_SWITCH::OnTextChanged, this, m_branchNameText->GetId() );
94 Bind( wxEVT_TIMER, &DIALOG_GIT_SWITCH::OnTimer, this, m_timer.GetId() );
95
96 // Populate branch list
98
99 // Set sizer for the dialog
100 SetSizerAndFit( sizer );
101
103
104 m_existingBranch = false;
105}
106
108{
109 StopTimer();
110 Unbind( wxEVT_TIMER, &DIALOG_GIT_SWITCH::OnTimer, this, m_timer.GetId() );
111}
112
114{
115 m_branchList->DeleteAllItems();
116
117 // Get the branches
118 GetBranches();
119
120 long currentIndex = -1;
121
122 // Populate the list
123 for( auto& [ name, data ] : m_branches )
124 {
125 wxDateTime lastUpdated( data.lastUpdated );
126 wxString lastUpdatedString = lastUpdated.Format();
127 wxString displayName = ( name == m_currentBranch ? wxS( "* " ) : wxS( " " ) ) + name;
128
129 long itemIndex = m_branchList->InsertItem( m_branchList->GetItemCount(), displayName );
130 m_branchList->SetItem( itemIndex, 1, data.commitString );
131 m_branchList->SetItem( itemIndex, 2, lastUpdatedString );
132
133 if( name == m_currentBranch )
134 currentIndex = itemIndex;
135 }
136
137 m_branchList->SetColumnWidth( 0, wxLIST_AUTOSIZE );
138 m_branchList->SetColumnWidth( 1, wxLIST_AUTOSIZE );
139 m_branchList->SetColumnWidth( 2, wxLIST_AUTOSIZE );
140
141 if( currentIndex >= 0 )
142 {
143 m_branchList->Select( currentIndex );
144 m_branchList->EnsureVisible( currentIndex );
146 }
147}
148
149
150void DIALOG_GIT_SWITCH::OnBranchListDClick( wxListEvent& aEvent )
151{
152 int selection = aEvent.GetIndex();
153
154 if( selection != wxNOT_FOUND )
155 {
156 wxString branchName = stripBranchMarker( m_branchList->GetItemText( selection ) );
157 m_branchNameText->SetValue( branchName );
158
159 if( branchName != m_currentBranch )
160 EndModal( wxID_OK );
161 }
162}
163
164
166{
167 int selection = aEvent.GetIndex();
168
169 if( selection != wxNOT_FOUND )
170 {
171 wxString branchName = stripBranchMarker( m_branchList->GetItemText( selection ) );
172 m_branchNameText->SetValue( branchName );
173 m_switchButton->SetLabel( _( "Switch" ) );
174 m_switchButton->Enable( branchName != m_currentBranch );
175 }
176 else
177 {
178 // Deselect all elements in the list
179 for( int ii = 0; ii < m_branchList->GetItemCount(); ++ii )
180 m_branchList->SetItemState( ii, 0, 0 );
181 }
182}
183
184void DIALOG_GIT_SWITCH::OnSwitchButton(wxCommandEvent& aEvent)
185{
186 wxString branchName = m_branchNameText->GetValue();
187
188 // Check if the branch name exists
189 bool branchExists = m_branches.count(branchName);
190
191 if (branchExists)
192 {
193 EndModal(wxID_OK); // Return Switch code
194 }
195 else
196 {
197 EndModal(wxID_ADD); // Return Add code
198 }
199}
200
201
202void DIALOG_GIT_SWITCH::OnCancelButton(wxCommandEvent& aEvent)
203{
204 EndModal(wxID_CANCEL); // Return Cancel code
205}
206
207
209{
210 return m_branchNameText->GetValue();
211}
212
213
215{
216 m_timer.Start( 500, true );
217}
218
219
221{
222 m_timer.Stop();
223}
224
225
226void DIALOG_GIT_SWITCH::OnTimer( wxTimerEvent& aEvt )
227{
228 wxString branchName = m_branchNameText->GetValue();
229
230 if( branchName == m_lastEnteredText )
231 return;
232
233 m_lastEnteredText = branchName;
234
235 // Check if the branch name exists
236 bool branchExists = m_branches.count( branchName );
237
238 if( branchExists )
239 {
240 m_switchButton->SetLabel( _( "Switch" ) );
241 m_switchButton->Enable( branchName != m_currentBranch );
242 }
243 else
244 {
245 m_switchButton->SetLabel( _( "Add" ) );
246 m_switchButton->Enable();
247 }
248}
249
250
251void DIALOG_GIT_SWITCH::OnTextChanged( wxCommandEvent& aEvt )
252{
253 StartTimer();
254}
255
256
258{
259 // Clear the branch list
260 m_branches.clear();
261
262 git_branch_iterator* branchIterator = nullptr;
263 git_branch_t branchType;
264
265 // Get Current Branch
266 git_reference* currentBranchReference = nullptr;
267 git_repository_head( &currentBranchReference, m_repository );
268
269 if( !currentBranchReference )
270 {
271 wxLogTrace( traceGit, "Failed to get current branch" );
272 return;
273 }
274
275 KIGIT::GitReferencePtr currentBranch( currentBranchReference );
276 m_currentBranch = git_reference_shorthand( currentBranchReference );
277
278 // Initialize branch iterator
279 git_branch_iterator_new( &branchIterator, m_repository, GIT_BRANCH_ALL );
280 KIGIT::GitBranchIteratorPtr branchIteratorPtr( branchIterator );
281
282 // Iterate over local branches
283 git_reference* branchReference = nullptr;
284 while( git_branch_next( &branchReference, &branchType, branchIterator ) == 0 )
285 {
286 KIGIT::GitReferencePtr branchReferencePtr( branchReference );
287
288 // Get the branch OID
289 const git_oid* branchOid = git_reference_target( branchReference );
290
291 // Skip this branch if it doesn't have an OID
292 if( !branchOid )
293 continue;
294
295 git_commit* commit = nullptr;
296
297 if( git_commit_lookup( &commit, m_repository, branchOid ) )
298 {
299 // Skip this branch if it doesn't have a commit
300 continue;
301 }
302
303 KIGIT::GitCommitPtr commitPtr( commit );
304
305 // Retrieve commit details
306 BranchData branchData;
307 branchData.commitString = git_commit_message( commit );
308 branchData.lastUpdated = static_cast<time_t>( git_commit_time( commit ) );
309 branchData.isRemote = branchType == GIT_BRANCH_REMOTE;
310
311 m_branches[git_reference_shorthand( branchReference )] = branchData;
312 }
313}
const char * name
DIALOG_GIT_SWITCH(wxWindow *aParent, git_repository *aRepository)
wxListView * m_branchList
git_repository * m_repository
wxString GetBranchName() const
void OnTextChanged(wxCommandEvent &event)
std::map< wxString, BranchData > m_branches
void OnCancelButton(wxCommandEvent &event)
wxTextCtrl * m_branchNameText
void OnBranchListSelection(wxListEvent &event)
void OnBranchListDClick(wxListEvent &event)
void OnTimer(wxTimerEvent &event)
void OnSwitchButton(wxCommandEvent &event)
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
DIALOG_SHIM(wxWindow *aParent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, const wxString &name=wxDialogNameStr)
static wxString stripBranchMarker(const wxString &aName)
#define _(s)
const wxChar *const traceGit
Flag to enable Git debugging output.
std::unique_ptr< git_commit, decltype([](git_commit *aCommit) { git_commit_free(aCommit); })> GitCommitPtr
A unique pointer for git_commit objects with automatic cleanup.
std::unique_ptr< git_reference, decltype([](git_reference *aRef) { git_reference_free(aRef); })> GitReferencePtr
A unique pointer for git_reference objects with automatic cleanup.
std::unique_ptr< git_branch_iterator, decltype([](git_branch_iterator *aIter) { git_branch_iterator_free(aIter); })> GitBranchIteratorPtr
A unique pointer for git_branch_iterator objects with automatic cleanup.
wxString commitString
wxLogTrace helper definitions.