Make sure buffer is large enough for the nul terminator
[TortoiseGit.git] / src / TortoiseProc / SubmoduleUpdateDlg.cpp
blobff7c8e8a2352fe60870ca4f92a3c0027d6b539d0
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2015 - 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.
20 #include "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "SubmoduleUpdateDlg.h"
23 #include "AppUtils.h"
24 #include "UnicodeUtils.h"
25 #include "MessageBox.h"
27 IMPLEMENT_DYNAMIC(CSubmoduleUpdateDlg, CResizableStandAloneDialog)
29 bool CSubmoduleUpdateDlg::s_bSortLogical = true;
31 CSubmoduleUpdateDlg::CSubmoduleUpdateDlg(CWnd* pParent /*=NULL*/)
32 : CResizableStandAloneDialog(CSubmoduleUpdateDlg::IDD, pParent)
33 , m_bInit(TRUE)
34 , m_bRecursive(FALSE)
35 , m_bForce(FALSE)
36 , m_bNoFetch(FALSE)
37 , m_bMerge(FALSE)
38 , m_bRebase(FALSE)
39 , m_bRemote(FALSE)
40 , m_bWholeProject(FALSE)
42 s_bSortLogical = !CRegDWORD(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\NoStrCmpLogical", 0, false, HKEY_CURRENT_USER);
43 if (s_bSortLogical)
44 s_bSortLogical = !CRegDWORD(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\NoStrCmpLogical", 0, false, HKEY_LOCAL_MACHINE);
47 CSubmoduleUpdateDlg::~CSubmoduleUpdateDlg()
51 void CSubmoduleUpdateDlg::DoDataExchange(CDataExchange* pDX)
53 CResizableStandAloneDialog::DoDataExchange(pDX);
54 DDX_Control(pDX, IDC_LIST_PATH, m_PathListBox);
55 DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);
56 DDX_Check(pDX, IDC_WHOLE_PROJECT, m_bWholeProject);
57 DDX_Check(pDX, IDC_CHECK_SUBMODULE_INIT, m_bInit);
58 DDX_Check(pDX, IDC_CHECK_SUBMODULE_RECURSIVE, m_bRecursive);
59 DDX_Check(pDX, IDC_FORCE, m_bForce);
60 DDX_Check(pDX, IDC_CHECK_SUBMODULE_NOFETCH, m_bNoFetch);
61 DDX_Check(pDX, IDC_CHECK_SUBMODULE_MERGE, m_bMerge);
62 DDX_Check(pDX, IDC_CHECK_SUBMODULE_REBASE, m_bRebase);
63 DDX_Check(pDX, IDC_CHECK_SUBMODULE_REMOTE, m_bRemote);
67 BEGIN_MESSAGE_MAP(CSubmoduleUpdateDlg, CResizableStandAloneDialog)
68 ON_BN_CLICKED(IDC_SELECTALL, OnBnClickedSelectall)
69 ON_BN_CLICKED(IDC_WHOLE_PROJECT, OnBnClickedShowWholeProject)
70 ON_BN_CLICKED(IDOK, &CSubmoduleUpdateDlg::OnBnClickedOk)
71 ON_LBN_SELCHANGE(IDC_LIST_PATH, &CSubmoduleUpdateDlg::OnLbnSelchangeListPath)
72 END_MESSAGE_MAP()
74 static int SubmoduleCallback(git_submodule *sm, const char * /*name*/, void *payload)
76 STRING_VECTOR *list = *(STRING_VECTOR **)payload;
77 STRING_VECTOR *prefixList = *((STRING_VECTOR **)payload + 1);
78 CString path = CUnicodeUtils::GetUnicode(git_submodule_path(sm));
79 if (prefixList->empty())
81 list->push_back(path);
83 else
85 for (size_t i = 0; i < prefixList->size(); ++i)
87 CString prefix = prefixList->at(i) + _T("/");
88 if (path.Left(prefix.GetLength()) == prefix)
89 list->push_back(path);
92 return 0;
95 int LogicalComparePredicate(const CString &left, const CString &right)
97 if (CSubmoduleUpdateDlg::s_bSortLogical)
98 return StrCmpLogicalW(left, right) < 0;
99 return StrCmpI(left, right) < 0;
102 static void GetSubmodulePathList(STRING_VECTOR &list, STRING_VECTOR &prefixList)
104 CAutoRepository repo(g_Git.GetGitRepository());
105 if (!repo)
107 MessageBox(NULL, CGit::GetLibGit2LastErr(_T("Could not open repository.")), _T("TortoiseGit"), MB_ICONERROR);
108 return;
111 STRING_VECTOR *listParams[] = { &list, &prefixList };
112 if (git_submodule_foreach(repo, SubmoduleCallback, &listParams))
114 MessageBox(NULL, CGit::GetLibGit2LastErr(_T("Could not get submodule list.")), _T("TortoiseGit"), MB_ICONERROR);
115 return;
118 std::sort(list.begin(), list.end(), LogicalComparePredicate);
121 BOOL CSubmoduleUpdateDlg::OnInitDialog()
123 CResizableStandAloneDialog::OnInitDialog();
124 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
126 AddAnchor(IDOK, BOTTOM_RIGHT);
127 AddAnchor(IDCANCEL, BOTTOM_RIGHT);
128 AddAnchor(IDHELP, BOTTOM_RIGHT);
129 AddAnchor((UINT)IDC_STATIC, TOP_LEFT);
130 AddAnchor(IDC_LIST_PATH, TOP_LEFT, BOTTOM_RIGHT);
131 AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);
132 AddAnchor(IDC_WHOLE_PROJECT, BOTTOM_LEFT);
133 AddAnchor(IDC_GROUP_INFO, BOTTOM_LEFT, BOTTOM_RIGHT);
134 AddAnchor(IDC_CHECK_SUBMODULE_INIT, BOTTOM_LEFT);
135 AddAnchor(IDC_CHECK_SUBMODULE_RECURSIVE, BOTTOM_LEFT);
136 AddAnchor(IDC_FORCE, BOTTOM_LEFT);
137 AddAnchor(IDC_CHECK_SUBMODULE_REMOTE, BOTTOM_LEFT);
138 AddAnchor(IDC_CHECK_SUBMODULE_NOFETCH, BOTTOM_RIGHT);
139 AddAnchor(IDC_CHECK_SUBMODULE_MERGE, BOTTOM_RIGHT);
140 AddAnchor(IDC_CHECK_SUBMODULE_REBASE, BOTTOM_RIGHT);
142 CString str(g_Git.m_CurrentDir);
143 str.Replace(_T(":"), _T("_"));
144 m_regShowWholeProject = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ShowWholeProject\\") + str, FALSE);
145 m_bWholeProject = m_regShowWholeProject;
147 m_regInit = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\") + str + _T("\\init"), TRUE);
148 m_bInit = m_regInit;
149 m_regRecursive = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\") + str + _T("\\recursive"), FALSE);
150 m_bRecursive = m_regRecursive;
151 m_regForce = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\") + str + _T("\\force"), FALSE);
152 m_bForce = m_regForce;
153 m_regRemote = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\") + str + _T("\\remote"), FALSE);
154 m_bRemote = m_regRemote;
155 m_regNoFetch = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\") + str + _T("\\nofetch"), FALSE);
156 m_bNoFetch = m_regNoFetch;
157 m_regMerge = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\") + str + _T("\\merge"), FALSE);
158 m_bMerge = m_regMerge;
159 m_regRebase = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\") + str + _T("\\rebase"), FALSE);
160 m_bRebase = m_regRebase;
162 DialogEnableWindow(IDC_WHOLE_PROJECT, !(m_PathFilterList.empty() || (m_PathFilterList.size() == 1 && m_PathFilterList[0].IsEmpty())));
164 SetDlgTitle();
166 AdjustControlSize(IDC_CHECK_SUBMODULE_INIT);
167 AdjustControlSize(IDC_CHECK_SUBMODULE_RECURSIVE);
168 AdjustControlSize(IDC_CHECK_SUBMODULE_NOFETCH);
169 AdjustControlSize(IDC_CHECK_SUBMODULE_MERGE);
170 AdjustControlSize(IDC_CHECK_SUBMODULE_REBASE);
172 EnableSaveRestore(_T("SubmoduleUpdateDlg"));
174 Refresh();
175 UpdateData(FALSE);
177 return TRUE;
180 void CSubmoduleUpdateDlg::SetDlgTitle()
182 if (m_sTitle.IsEmpty())
183 GetWindowText(m_sTitle);
184 CString dir = g_Git.m_CurrentDir;
185 if (!m_bWholeProject)
187 if (!m_PathFilterList.empty())
188 dir += (g_Git.m_CurrentDir.Right(1) == _T('\\') ? _T("") : _T("\\")) + CTGitPath(m_PathFilterList[0]).GetWinPathString();
189 if (m_PathFilterList.size() > 1)
190 dir += _T(", ...");
192 CAppUtils::SetWindowTitle(m_hWnd, dir, m_sTitle);
195 void CSubmoduleUpdateDlg::OnBnClickedOk()
197 CResizableStandAloneDialog::UpdateData(TRUE);
198 m_PathList.clear();
199 if (m_bRemote && CAppUtils::GetMsysgitVersion() < 0x01080200)
201 CString gitver;
202 gitver.Format(IDS_GITVER_REQUIRED, _T("--remote"), _T("1.8.2"));
203 CMessageBox::Show(m_hWnd, gitver, _T("TortoiseGit"), MB_OK | MB_ICONERROR);
204 return;
207 CString selected;
208 for (int i = 0; i < m_PathListBox.GetCount(); ++i)
210 if (m_PathListBox.GetSel(i))
212 if (!selected.IsEmpty())
213 selected.Append(_T("|"));
214 CString text;
215 m_PathListBox.GetText(i, text);
216 m_PathList.push_back(text);
217 selected.Append(text);
220 m_regPath = selected;
222 m_regInit = m_bInit;
223 m_regRecursive = m_bRecursive;
224 m_regForce = m_bForce;
225 m_regRemote = m_bRemote;
226 m_regNoFetch = m_bNoFetch;
227 m_regMerge = m_bMerge;
228 m_regRebase = m_bRebase;
230 CResizableStandAloneDialog::OnOK();
233 void CSubmoduleUpdateDlg::OnLbnSelchangeListPath()
235 GetDlgItem(IDOK)->EnableWindow(m_PathListBox.GetSelCount() > 0 ? TRUE : FALSE);
236 if (m_PathListBox.GetSelCount() == 0)
237 m_SelectAll.SetCheck(BST_UNCHECKED);
238 else if ((int)m_PathListBox.GetSelCount() < m_PathListBox.GetCount())
239 m_SelectAll.SetCheck(BST_INDETERMINATE);
240 else
241 m_SelectAll.SetCheck(BST_CHECKED);
244 void CSubmoduleUpdateDlg::OnBnClickedSelectall()
246 UINT state = (m_SelectAll.GetState() & 0x0003);
247 if (state == BST_INDETERMINATE)
249 // It is not at all useful to manually place the checkbox into the indeterminate state...
250 // We will force this on to the unchecked state
251 state = BST_UNCHECKED;
252 m_SelectAll.SetCheck(state);
254 if (state == BST_UNCHECKED)
256 for (int i = 0; i < m_PathListBox.GetCount(); ++i)
257 m_PathListBox.SetSel(i, FALSE);
259 else
261 for (int i = 0; i < m_PathListBox.GetCount(); ++i)
262 m_PathListBox.SetSel(i, TRUE);
266 void CSubmoduleUpdateDlg::OnBnClickedShowWholeProject()
268 UpdateData();
269 m_regShowWholeProject = m_bWholeProject;
270 SetDlgTitle();
271 Refresh();
274 void CSubmoduleUpdateDlg::Refresh()
276 while (m_PathListBox.GetCount() > 0)
277 m_PathListBox.DeleteString(m_PathListBox.GetCount() - 1);
279 CString WorkingDir = g_Git.m_CurrentDir;
280 WorkingDir.Replace(_T(':'), _T('_'));
282 m_regPath = CRegString(CString(_T("Software\\TortoiseGit\\History\\SubmoduleUpdatePath\\") + WorkingDir));
283 CString path = m_regPath;
284 STRING_VECTOR emptylist;
285 STRING_VECTOR list;
286 GetSubmodulePathList(list, m_bWholeProject ? emptylist : m_PathFilterList);
287 STRING_VECTOR selected;
288 if (m_PathList.empty())
290 int pos = 0;
291 while (pos >= 0)
293 CString part = path.Tokenize(_T("|"), pos);
294 if (!part.IsEmpty())
295 selected.push_back(part);
298 else
300 for (size_t i = 0; i < m_PathList.size(); ++i)
301 selected.push_back(m_PathList[i]);
304 for (size_t i = 0; i < list.size(); ++i)
306 m_PathListBox.AddString(list[i]);
307 if (selected.size() == 0)
308 m_PathListBox.SetSel((int)i);
309 else
311 for (size_t j = 0; j < selected.size(); ++j)
313 if (selected[j] == list[i])
314 m_PathListBox.SetSel((int)i);
319 OnLbnSelchangeListPath();