Fix typos
[TortoiseGit.git] / src / TortoiseProc / ChooseVersion.h
blobaa7a30a944290de792ad7f5aa391f7089567b258
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2020, 2023 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #pragma once
20 #include "afxwin.h"
21 #include "LogDlg.h"
22 #include "BrowseRefsDlg.h"
23 #include "MessageBox.h"
24 #include "registry.h"
25 #include "StringUtils.h"
27 static UINT WM_GUIUPDATES = RegisterWindowMessage(L"TORTOISEGIT_CHOOSEVERSION_GUIUPDATES");
29 class CChooseVersion
31 public:
32 CString m_initialRefName;
34 private:
35 CWnd* m_pWin = nullptr;
36 CWinThread* m_pLoadingThread = nullptr;
37 static UINT LoadingThreadEntry(LPVOID pVoid)
39 return static_cast<CChooseVersion*>(pVoid)->LoadingThread();
41 volatile LONG m_bLoadingThreadRunning = FALSE;
43 protected:
44 CHistoryCombo m_ChooseVersioinBranch;
45 CHistoryCombo m_ChooseVersioinTags;
46 CHistoryCombo m_ChooseVersioinVersion;
47 CButton m_RadioBranch;
48 CButton m_RadioTag;
49 CString m_pendingRefName;
50 bool m_bNotFullName = true;
51 bool m_bSkipCurrentBranch = false;
53 struct GUI_UPDATE_DATA
55 STRING_VECTOR branches;
56 int current_branch_idx = -1;
57 STRING_VECTOR tags;
60 //Notification when version changed. Can be implemented in derived classes.
61 virtual void OnVersionChanged(){}
63 afx_msg void OnBnClickedChooseRadio()
65 this->m_ChooseVersioinTags.EnableWindow(FALSE);
66 this->m_ChooseVersioinBranch.EnableWindow(FALSE);
67 this->m_ChooseVersioinVersion.EnableWindow(FALSE);
68 m_pWin->GetDlgItem(IDC_BUTTON_BROWSE_REF)->EnableWindow(FALSE);
69 m_pWin->GetDlgItem(IDC_BUTTON_SHOW)->EnableWindow(FALSE);
70 m_bIsBranch = false;
71 const int radio = m_pWin->GetCheckedRadioButton(IDC_RADIO_HEAD, IDC_RADIO_VERSION);
72 switch (radio)
74 case IDC_RADIO_HEAD:
75 break;
76 case IDC_RADIO_BRANCH:
77 this->m_ChooseVersioinBranch.EnableWindow(TRUE);
78 m_pWin->GetDlgItem(IDC_BUTTON_BROWSE_REF)->EnableWindow(TRUE);
79 m_bIsBranch = true;
80 break;
81 case IDC_RADIO_TAGS:
82 this->m_ChooseVersioinTags.EnableWindow(TRUE);
83 break;
84 case IDC_RADIO_VERSION:
85 this->m_ChooseVersioinVersion.EnableWindow(TRUE);
86 m_pWin->GetDlgItem(IDC_BUTTON_SHOW)->EnableWindow(TRUE);
87 break;
89 // enable version browse button if Version is selected
90 m_pWin->GetDlgItem(IDC_BUTTON_SHOW)->EnableWindow(radio == IDC_RADIO_VERSION);
91 OnVersionChanged();
94 void OnBnClickedChooseVersion()
96 // use the git log to allow selection of a version
97 CLogDlg dlg;
98 if (dlg.IsThreadRunning())
100 CMessageBox::Show(m_pWin->GetSafeHwnd(), IDS_PROC_LOG_ONLYONCE, IDS_APPNAME, MB_ICONEXCLAMATION);
101 return;
103 CString revision;
104 m_ChooseVersioinVersion.GetWindowText(revision);
105 dlg.SetParams(CTGitPath(), CTGitPath(), revision, revision, 0);
106 // tell the dialog to use mode for selecting revisions
107 dlg.SetSelect(true);
108 dlg.ShowWorkingTreeChanges(false);
109 // only one revision must be selected however
110 dlg.SingleSelection(true);
111 if (dlg.DoModal() == IDOK && !dlg.GetSelectedHash().empty())
113 m_ChooseVersioinVersion.SetWindowText(dlg.GetSelectedHash().at(0).ToString());
114 OnVersionChanged();
116 m_pWin->BringWindowToTop(); /* cf. issue #3493 */
119 void UpdateRevsionName()
121 const int radio = m_pWin->GetCheckedRadioButton(IDC_RADIO_HEAD, IDC_RADIO_VERSION);
122 switch (radio)
124 case IDC_RADIO_HEAD:
125 this->m_VersionName = L"HEAD";
126 break;
127 case IDC_RADIO_BRANCH:
128 this->m_VersionName=m_ChooseVersioinBranch.GetString();
129 if (!m_VersionName.IsEmpty() && !g_Git.IsBranchTagNameUnique(this->m_VersionName))
130 this->m_VersionName = L"refs/heads/" + this->m_VersionName;
131 break;
132 case IDC_RADIO_TAGS:
133 this->m_VersionName = m_ChooseVersioinTags.GetString();
134 if (!m_VersionName.IsEmpty() && !g_Git.IsBranchTagNameUnique(this->m_VersionName))
135 this->m_VersionName = L"refs/tags/" + m_ChooseVersioinTags.GetString();
136 break;
137 case IDC_RADIO_VERSION:
138 this->m_VersionName=m_ChooseVersioinVersion.GetString();
139 break;
142 void SetDefaultChoose(int id)
144 m_pWin->CheckRadioButton(IDC_RADIO_HEAD,IDC_RADIO_VERSION,id);
145 OnBnClickedChooseRadio();
148 void OnBnClickedButtonBrowseRef()
150 CString origRef;
151 UpdateRevsionName();
152 CString resultRef = CBrowseRefsDlg::PickRef(false, m_VersionName, gPickRef_All);
153 if(resultRef.IsEmpty())
155 m_pendingRefName = m_VersionName;
156 m_bNotFullName = true;
157 InitChooseVersion(false, true);
158 return;
160 m_pendingRefName = resultRef;
161 m_bNotFullName = false;
162 InitChooseVersion(false, true);
165 void SelectRef(CString refName, bool bRefNameIsPossiblyNotFullName = true)
167 if(bRefNameIsPossiblyNotFullName)
169 //Make sure refName is a full ref name first
170 CString fullRefName = g_Git.GetFullRefName(refName);
171 if(!fullRefName.IsEmpty())
172 refName = fullRefName;
175 if (CStringUtils::StartsWith(refName, L"refs/"))
176 refName = refName.Mid(static_cast<int>(wcslen(L"refs/")));
177 if (CStringUtils::StartsWith(refName, L"heads/"))
179 refName = refName.Mid(static_cast<int>(wcslen(L"heads/")));
180 SetDefaultChoose(IDC_RADIO_BRANCH);
181 m_ChooseVersioinBranch.SetCurSel(
182 m_ChooseVersioinBranch.FindStringExact(-1, refName));
184 else if (CStringUtils::StartsWith(refName, L"remotes/"))
186 SetDefaultChoose(IDC_RADIO_BRANCH);
187 m_ChooseVersioinBranch.SetCurSel(
188 m_ChooseVersioinBranch.FindStringExact(-1, refName));
190 else if (CStringUtils::StartsWith(refName, L"tags/"))
192 refName = refName.Mid(static_cast<int>(wcslen(L"refs/")));
193 if (CStringUtils::EndsWith(refName, L"^{}"))
194 refName.Truncate(refName.GetLength() - static_cast<int>(wcslen(L"^{}")));
195 SetDefaultChoose(IDC_RADIO_TAGS);
196 m_ChooseVersioinTags.SetCurSel(
197 m_ChooseVersioinTags.FindStringExact(-1, refName));
199 else
201 SetDefaultChoose(IDC_RADIO_VERSION);
202 m_ChooseVersioinVersion.AddString(refName);
204 OnVersionChanged();
207 UINT LoadingThread()
209 GUI_UPDATE_DATA data;
210 g_Git.GetBranchList(data.branches, &data.current_branch_idx, CRegDWORD(L"Software\\TortoiseGit\\BranchesIncludeFetchHead", TRUE) ? CGit::BRANCH_ALL_F : CGit::BRANCH_ALL, m_bSkipCurrentBranch);
212 g_Git.GetTagList(data.tags);
214 m_pWin->SendMessage(WM_GUIUPDATES, reinterpret_cast<WPARAM>(&data));
216 InterlockedExchange(&m_bLoadingThreadRunning, FALSE);
217 return 0;
219 void UpdateGUI(GUI_UPDATE_DATA* data = nullptr)
221 if (data)
223 m_ChooseVersioinBranch.SetList(data->branches);
224 m_ChooseVersioinBranch.SetCurSel(data->current_branch_idx);
225 m_ChooseVersioinTags.SetList(data->tags);
226 m_ChooseVersioinTags.SetCurSel(0);
227 if (auto pCurrentBranch = m_pWin->GetDlgItem(IDC_CURRENTBRANCH); pCurrentBranch)
228 pCurrentBranch->SetWindowText(g_Git.GetCurrentBranch());
231 m_RadioBranch.EnableWindow(TRUE);
232 m_RadioTag.EnableWindow(TRUE);
234 if (m_pendingRefName.IsEmpty())
235 OnVersionChanged();
236 else
237 SelectRef(m_pendingRefName, m_bNotFullName);
239 if (m_bIsFirstTimeToSetFocus)
241 if (m_pWin->GetDlgItem(IDC_COMBOBOXEX_BRANCH)->IsWindowEnabled())
242 m_pWin->GetDlgItem(IDC_COMBOBOXEX_BRANCH)->SetFocus();
243 else if (m_pWin->GetDlgItem(IDC_COMBOBOXEX_TAGS)->IsWindowEnabled())
244 m_pWin->GetDlgItem(IDC_COMBOBOXEX_TAGS)->SetFocus();
245 else if (m_pWin->GetDlgItem(IDC_COMBOBOXEX_VERSION)->IsWindowEnabled())
246 m_pWin->GetDlgItem(IDC_COMBOBOXEX_VERSION)->SetFocus();
248 m_bIsFirstTimeToSetFocus = false;
249 m_pWin->GetDlgItem(IDOK)->EnableWindow(TRUE);
251 void InitChooseVersion(bool setFocusToBranchComboBox = false, bool bReInit = false)
253 m_ChooseVersioinBranch.SetMaxHistoryItems(0x7FFFFFFF);
254 m_ChooseVersioinTags.SetMaxHistoryItems(0x7FFFFFFF);
256 m_bIsBranch = false;
257 m_RadioBranch.EnableWindow(FALSE);
258 m_RadioTag.EnableWindow(FALSE);
260 m_bIsFirstTimeToSetFocus = setFocusToBranchComboBox;
261 if (!bReInit)
263 m_pendingRefName = m_initialRefName;
264 m_bNotFullName = true;
267 m_pWin->GetDlgItem(IDOK)->EnableWindow(FALSE);
269 InterlockedExchange(&m_bLoadingThreadRunning, TRUE);
270 if ((m_pLoadingThread = AfxBeginThread(LoadingThreadEntry, this, 0, CREATE_SUSPENDED)) == nullptr)
272 InterlockedExchange(&m_bLoadingThreadRunning, FALSE);
273 CMessageBox::Show(nullptr, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
274 return;
277 m_pLoadingThread->m_bAutoDelete = FALSE;
278 m_pLoadingThread->ResumeThread();
280 void WaitForFinishLoading()
282 if(m_bLoadingThreadRunning && m_pLoadingThread)
284 const DWORD ret = ::WaitForSingleObject(m_pLoadingThread->m_hThread, 20000);
285 if(ret == WAIT_TIMEOUT)
286 ::TerminateThread(m_pLoadingThread,0);
288 delete m_pLoadingThread;
290 public:
291 CString m_VersionName;
292 bool m_bIsBranch = false;
293 bool m_bIsFirstTimeToSetFocus = false;
294 CChooseVersion(CWnd *win)
295 : m_pWin(win)
300 #define CHOOSE_VERSION_DDX \
301 DDX_Control(pDX, IDC_COMBOBOXEX_BRANCH, m_ChooseVersioinBranch); \
302 DDX_Control(pDX, IDC_COMBOBOXEX_TAGS, m_ChooseVersioinTags); \
303 DDX_Control(pDX, IDC_COMBOBOXEX_VERSION, m_ChooseVersioinVersion); \
304 DDX_Control(pDX, IDC_RADIO_BRANCH, m_RadioBranch);\
305 DDX_Control(pDX, IDC_RADIO_TAGS, m_RadioTag);
307 #define CHOOSE_VERSION_EVENT\
308 ON_REGISTERED_MESSAGE(WM_GUIUPDATES, OnUpdateGUIHost)\
309 ON_BN_CLICKED(IDC_RADIO_HEAD, OnBnClickedChooseRadioHost)\
310 ON_BN_CLICKED(IDC_RADIO_BRANCH, OnBnClickedChooseRadioHost)\
311 ON_BN_CLICKED(IDC_RADIO_TAGS, OnBnClickedChooseRadioHost)\
312 ON_BN_CLICKED(IDC_BUTTON_SHOW, OnBnClickedShow)\
313 ON_BN_CLICKED(IDC_RADIO_VERSION, OnBnClickedChooseRadioHost)\
314 ON_BN_CLICKED(IDC_BUTTON_BROWSE_REF, OnBnClickedButtonBrowseRefHost)
316 #define CHOOSE_VERSION_ADDANCHOR \
318 AddAnchor(IDC_COMBOBOXEX_BRANCH, TOP_LEFT, TOP_RIGHT); \
319 AddAnchor(IDC_COMBOBOXEX_TAGS, TOP_LEFT, TOP_RIGHT); \
320 AddAnchor(IDC_COMBOBOXEX_VERSION, TOP_LEFT, TOP_RIGHT); \
321 AddAnchor(IDC_GROUP_BASEON, TOP_LEFT, TOP_RIGHT); \
322 AddAnchor(IDC_BUTTON_SHOW,TOP_RIGHT); \
323 AddAnchor(IDC_BUTTON_BROWSE_REF,TOP_RIGHT); \
324 if (auto pCurrentBranch = GetDlgItem(IDC_CURRENTBRANCH); pCurrentBranch) \
325 AddAnchor(IDC_CURRENTBRANCH, TOP_LEFT, TOP_RIGHT); \
328 #define CHOOSE_EVENT_RADIO() \
329 LRESULT OnUpdateGUIHost(WPARAM data, LPARAM) { UpdateGUI(reinterpret_cast<GUI_UPDATE_DATA*>(data)); return 0; } \
330 afx_msg void OnBnClickedChooseRadioHost(){OnBnClickedChooseRadio();}\
331 afx_msg void OnBnClickedShow(){OnBnClickedChooseVersion();}\
332 afx_msg void OnBnClickedButtonBrowseRefHost(){OnBnClickedButtonBrowseRef();}