1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2017, 2019, 2022 - 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.
21 #include "TortoiseProc.h"
22 #include "SubmoduleUpdateDlg.h"
24 #include "UnicodeUtils.h"
26 IMPLEMENT_DYNAMIC(CSubmoduleUpdateDlg
, CResizableStandAloneDialog
)
28 bool CSubmoduleUpdateDlg::s_bSortLogical
= true;
30 CSubmoduleUpdateDlg::CSubmoduleUpdateDlg(CWnd
* pParent
/*=nullptr*/)
31 : CResizableStandAloneDialog(CSubmoduleUpdateDlg::IDD
, pParent
)
39 , m_bWholeProject(FALSE
)
40 , m_bAllSubmodulesSelected(false)
42 s_bSortLogical
= !CRegDWORD(L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\NoStrCmpLogical", 0, false, HKEY_CURRENT_USER
);
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
);
66 BEGIN_MESSAGE_MAP(CSubmoduleUpdateDlg
, CResizableStandAloneDialog
)
67 ON_BN_CLICKED(IDC_SELECTALL
, OnBnClickedSelectall
)
68 ON_BN_CLICKED(IDC_WHOLE_PROJECT
, OnBnClickedShowWholeProject
)
69 ON_BN_CLICKED(IDOK
, &CSubmoduleUpdateDlg::OnBnClickedOk
)
70 ON_LBN_SELCHANGE(IDC_LIST_PATH
, &CSubmoduleUpdateDlg::OnLbnSelchangeListPath
)
73 static int SubmoduleCallback(git_submodule
*sm
, const char * /*name*/, void *payload
)
75 auto list
= *static_cast<STRING_VECTOR
**>(payload
);
76 auto prefixList
= *(static_cast<STRING_VECTOR
**>(payload
) + 1);
77 CString path
= CUnicodeUtils::GetUnicode(git_submodule_path(sm
));
78 if (prefixList
->empty())
79 list
->push_back(path
);
82 for (size_t i
= 0; i
< prefixList
->size(); ++i
)
84 CString prefix
= prefixList
->at(i
) + L
'/';
85 if (CStringUtils::StartsWith(path
, prefix
))
86 list
->push_back(path
);
92 int LogicalComparePredicate(const CString
&left
, const CString
&right
)
94 if (CSubmoduleUpdateDlg::s_bSortLogical
)
95 return StrCmpLogicalW(left
, right
) < 0;
96 return StrCmpI(left
, right
) < 0;
99 static void GetSubmodulePathList(STRING_VECTOR
&list
, STRING_VECTOR
&prefixList
)
101 CAutoRepository
repo(g_Git
.GetGitRepository());
104 MessageBox(nullptr, CGit::GetLibGit2LastErr(L
"Could not open repository."), L
"TortoiseGit", MB_ICONERROR
);
108 STRING_VECTOR
*listParams
[] = { &list
, &prefixList
};
109 if (git_submodule_foreach(repo
, SubmoduleCallback
, &listParams
))
111 MessageBox(nullptr, CGit::GetLibGit2LastErr(L
"Could not get submodule list."), L
"TortoiseGit", MB_ICONERROR
);
115 std::sort(list
.begin(), list
.end(), LogicalComparePredicate
);
118 BOOL
CSubmoduleUpdateDlg::OnInitDialog()
120 CResizableStandAloneDialog::OnInitDialog();
121 CAppUtils::MarkWindowAsUnpinnable(m_hWnd
);
123 AdjustControlSize(IDC_CHECK_SUBMODULE_INIT
);
124 AdjustControlSize(IDC_CHECK_SUBMODULE_RECURSIVE
);
125 AdjustControlSize(IDC_CHECK_SUBMODULE_NOFETCH
);
126 AdjustControlSize(IDC_CHECK_SUBMODULE_MERGE
);
127 AdjustControlSize(IDC_CHECK_SUBMODULE_REBASE
);
129 AddAnchor(IDOK
, BOTTOM_RIGHT
);
130 AddAnchor(IDCANCEL
, BOTTOM_RIGHT
);
131 AddAnchor(IDHELP
, BOTTOM_RIGHT
);
132 AddAnchor(static_cast<UINT
>(IDC_STATIC
), TOP_LEFT
);
133 AddAnchor(IDC_LIST_PATH
, TOP_LEFT
, BOTTOM_RIGHT
);
134 AddAnchor(IDC_SELECTALL
, BOTTOM_LEFT
);
135 AddAnchor(IDC_WHOLE_PROJECT
, BOTTOM_LEFT
);
136 AddAnchor(IDC_GROUP_INFO
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
137 AddAnchor(IDC_CHECK_SUBMODULE_INIT
, BOTTOM_LEFT
);
138 AddAnchor(IDC_CHECK_SUBMODULE_RECURSIVE
, BOTTOM_LEFT
);
139 AddAnchor(IDC_FORCE
, BOTTOM_LEFT
);
140 AddAnchor(IDC_CHECK_SUBMODULE_REMOTE
, BOTTOM_LEFT
);
141 AddAnchor(IDC_CHECK_SUBMODULE_NOFETCH
, BOTTOM_RIGHT
);
142 AddAnchor(IDC_CHECK_SUBMODULE_MERGE
, BOTTOM_RIGHT
);
143 AddAnchor(IDC_CHECK_SUBMODULE_REBASE
, BOTTOM_RIGHT
);
145 CString
str(g_Git
.m_CurrentDir
);
146 str
.Replace(L
':', L
'_');
147 m_regShowWholeProject
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\ShowWholeProject\\" + str
, FALSE
);
148 m_bWholeProject
= m_regShowWholeProject
;
150 m_regInit
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\" + str
+ L
"\\init", TRUE
);
152 m_regRecursive
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\" + str
+ L
"\\recursive", FALSE
);
153 m_bRecursive
= m_regRecursive
;
154 m_regForce
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\" + str
+ L
"\\force", FALSE
);
155 m_bForce
= m_regForce
;
156 m_regRemote
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\" + str
+ L
"\\remote", FALSE
);
157 m_bRemote
= m_regRemote
;
158 m_regNoFetch
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\" + str
+ L
"\\nofetch", FALSE
);
159 m_bNoFetch
= m_regNoFetch
;
160 m_regMerge
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\" + str
+ L
"\\merge", FALSE
);
161 m_bMerge
= m_regMerge
;
162 m_regRebase
= CRegDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SubmoduleUpdate\\" + str
+ L
"\\rebase", FALSE
);
163 m_bRebase
= m_regRebase
;
165 DialogEnableWindow(IDC_WHOLE_PROJECT
, !(m_PathFilterList
.empty() || (m_PathFilterList
.size() == 1 && m_PathFilterList
[0].IsEmpty())));
169 EnableSaveRestore(L
"SubmoduleUpdateDlg");
177 void CSubmoduleUpdateDlg::SetDlgTitle()
179 if (m_sTitle
.IsEmpty())
180 GetWindowText(m_sTitle
);
181 CString dir
= g_Git
.m_CurrentDir
;
182 if (!m_bWholeProject
)
184 if (!m_PathFilterList
.empty())
185 dir
+= (CStringUtils::EndsWith(g_Git
.m_CurrentDir
, L
'\\') ? L
"" : L
"\\") + CTGitPath(m_PathFilterList
[0]).GetWinPathString();
186 if (m_PathFilterList
.size() > 1)
189 CAppUtils::SetWindowTitle(m_hWnd
, dir
, m_sTitle
);
192 void CSubmoduleUpdateDlg::OnBnClickedOk()
194 CResizableStandAloneDialog::UpdateData(TRUE
);
198 for (int i
= 0; i
< m_PathListBox
.GetCount(); ++i
)
200 if (m_PathListBox
.GetSel(i
))
202 if (!selected
.IsEmpty())
203 selected
.AppendChar(L
'|');
205 m_PathListBox
.GetText(i
, text
);
206 m_PathList
.push_back(text
);
207 selected
.Append(text
);
210 m_bAllSubmodulesSelected
= (static_cast<size_t>(m_PathListBox
.GetCount()) == m_PathList
.size());
211 m_regPath
= selected
;
214 m_regRecursive
= m_bRecursive
;
215 m_regForce
= m_bForce
;
216 m_regRemote
= m_bRemote
;
217 m_regNoFetch
= m_bNoFetch
;
218 m_regMerge
= m_bMerge
;
219 m_regRebase
= m_bRebase
;
221 CResizableStandAloneDialog::OnOK();
224 void CSubmoduleUpdateDlg::OnLbnSelchangeListPath()
226 GetDlgItem(IDOK
)->EnableWindow(m_PathListBox
.GetSelCount() > 0 ? TRUE
: FALSE
);
227 if (m_PathListBox
.GetSelCount() == 0)
228 m_SelectAll
.SetCheck(BST_UNCHECKED
);
229 else if (m_PathListBox
.GetSelCount() < m_PathListBox
.GetCount())
230 m_SelectAll
.SetCheck(BST_INDETERMINATE
);
232 m_SelectAll
.SetCheck(BST_CHECKED
);
235 void CSubmoduleUpdateDlg::OnBnClickedSelectall()
237 UINT state
= (m_SelectAll
.GetState() & 0x0003);
238 if (state
== BST_INDETERMINATE
)
240 // It is not at all useful to manually place the checkbox into the indeterminate state...
241 // We will force this on to the unchecked state
242 state
= BST_UNCHECKED
;
243 m_SelectAll
.SetCheck(state
);
245 if (state
== BST_UNCHECKED
)
247 for (int i
= 0; i
< m_PathListBox
.GetCount(); ++i
)
248 m_PathListBox
.SetSel(i
, FALSE
);
252 for (int i
= 0; i
< m_PathListBox
.GetCount(); ++i
)
253 m_PathListBox
.SetSel(i
, TRUE
);
255 OnLbnSelchangeListPath();
258 void CSubmoduleUpdateDlg::OnBnClickedShowWholeProject()
261 m_regShowWholeProject
= m_bWholeProject
;
266 void CSubmoduleUpdateDlg::Refresh()
268 while (m_PathListBox
.GetCount() > 0)
269 m_PathListBox
.DeleteString(m_PathListBox
.GetCount() - 1);
271 CString WorkingDir
= g_Git
.m_CurrentDir
;
272 WorkingDir
.Replace(L
':', L
'_');
274 m_regPath
= CRegString(L
"Software\\TortoiseGit\\History\\SubmoduleUpdatePath\\" + WorkingDir
);
275 CString path
= m_regPath
;
276 STRING_VECTOR emptylist
;
278 GetSubmodulePathList(list
, m_bWholeProject
? emptylist
: m_PathFilterList
);
279 STRING_VECTOR selected
;
280 if (m_PathList
.empty())
285 CString part
= path
.Tokenize(L
"|", pos
);
287 selected
.push_back(part
);
292 for (size_t i
= 0; i
< m_PathList
.size(); ++i
)
293 selected
.push_back(m_PathList
[i
]);
296 for (size_t i
= 0; i
< list
.size(); ++i
)
298 m_PathListBox
.AddString(list
[i
]);
299 if (selected
.size() == 0)
300 m_PathListBox
.SetSel(static_cast<int>(i
));
303 for (size_t j
= 0; j
< selected
.size(); ++j
)
305 if (selected
[j
] == list
[i
])
306 m_PathListBox
.SetSel(static_cast<int>(i
));
311 OnLbnSelchangeListPath();