PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/TortoiseProc/Settings/SetSavedDataPage.cpp

https://gitlab.com/hussinhassan80/tortoisegit
C++ | 402 lines | 369 code | 16 blank | 17 comment | 8 complexity | 8055c7d4ffedcabc13eee8e820ab203f MD5 | raw file
  1. // TortoiseGit - a Windows shell extension for easy version control
  2. // Copyright (C) 2012-2019-2021 - TortoiseGit
  3. // Copyright (C) 2003-2008,2014 - TortoiseSVN
  4. // This program is free software; you can redistribute it and/or
  5. // modify it under the terms of the GNU General Public License
  6. // as published by the Free Software Foundation; either version 2
  7. // of the License, or (at your option) any later version.
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. // You should have received a copy of the GNU General Public License
  13. // along with this program; if not, write to the Free Software Foundation,
  14. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. //
  16. #include "stdafx.h"
  17. #include "TortoiseProc.h"
  18. #include "registry.h"
  19. #include "PathUtils.h"
  20. #include "AppUtils.h"
  21. #include "DirFileEnum.h"
  22. #include "SetSavedDataPage.h"
  23. #include "MessageBox.h"
  24. #include "StringUtils.h"
  25. #include "Git.h"
  26. #include "WindowsCredentialsStore.h"
  27. IMPLEMENT_DYNAMIC(CSetSavedDataPage, ISettingsPropPage)
  28. CSetSavedDataPage::CSetSavedDataPage()
  29. : ISettingsPropPage(CSetSavedDataPage::IDD)
  30. , m_maxLines(0)
  31. {
  32. m_regMaxLines = CRegDWORD(L"Software\\TortoiseGit\\MaxLinesInLogfile", 4000);
  33. m_maxLines = m_regMaxLines;
  34. }
  35. CSetSavedDataPage::~CSetSavedDataPage()
  36. {
  37. }
  38. void CSetSavedDataPage::DoDataExchange(CDataExchange* pDX)
  39. {
  40. ISettingsPropPage::DoDataExchange(pDX);
  41. DDX_Control(pDX, IDC_URLHISTCLEAR, m_btnUrlHistClear);
  42. DDX_Control(pDX, IDC_LOGHISTCLEAR, m_btnLogHistClear);
  43. DDX_Control(pDX, IDC_RESIZABLEHISTCLEAR, m_btnResizableHistClear);
  44. DDX_Control(pDX, IDC_AUTHHISTCLEAR, m_btnAuthHistClear);
  45. DDX_Control(pDX, IDC_REPOLOGCLEAR, m_btnRepoLogClear);
  46. DDX_Text(pDX, IDC_MAXLINES, m_maxLines);
  47. DDX_Control(pDX, IDC_ACTIONLOGSHOW, m_btnActionLogShow);
  48. DDX_Control(pDX, IDC_ACTIONLOGCLEAR, m_btnActionLogClear);
  49. }
  50. static void RecursivelyCount(const CString& base, const CString& key, std::set<CString>& wcs, INT_PTR& historyNums)
  51. {
  52. CRegistryKey regurlhistlist(L"Software\\TortoiseGit\\History\\" + base + key);
  53. CStringList values;
  54. regurlhistlist.getValues(values);
  55. historyNums += values.GetCount();
  56. if (!key.IsEmpty() && !values.IsEmpty())
  57. wcs.insert(key);
  58. CStringList subkeys;
  59. regurlhistlist.getSubKeys(subkeys);
  60. for (POSITION subkeypos = subkeys.GetHeadPosition(); subkeypos;)
  61. {
  62. CString repo = key + L'\\' + subkeys.GetNext(subkeypos);
  63. RecursivelyCount(base, repo, wcs, historyNums);
  64. }
  65. }
  66. BOOL CSetSavedDataPage::OnInitDialog()
  67. {
  68. ISettingsPropPage::OnInitDialog();
  69. // find out how many log messages and URLs we've stored
  70. int nLogHistWC = 0;
  71. INT_PTR nLogHistMsg = 0;
  72. int nUrlHistWC = 0;
  73. INT_PTR nUrlHistItems = 0;
  74. int nLogHistRepo = 0;
  75. CRegistryKey regloghist(L"Software\\TortoiseGit\\History");
  76. CStringList loghistlist;
  77. regloghist.getSubKeys(loghistlist);
  78. for (POSITION pos = loghistlist.GetHeadPosition(); pos; )
  79. {
  80. CString sHistName = loghistlist.GetNext(pos);
  81. if (CStringUtils::StartsWithI(sHistName, L"commit") || CStringUtils::StartsWithI(sHistName, L"merge"))
  82. {
  83. nLogHistWC++;
  84. CRegistryKey regloghistwc(L"Software\\TortoiseGit\\History\\"+sHistName);
  85. CStringList loghistlistwc;
  86. regloghistwc.getValues(loghistlistwc);
  87. nLogHistMsg += loghistlistwc.GetCount();
  88. }
  89. }
  90. std::set<CString> wcs;
  91. for (CString key : { L"repoURLS", L"FormatPatchURLS", L"PullURLS", L"PushURLS", L"SubModuleRepoURLS", L"SyncURL" })
  92. {
  93. RecursivelyCount(key, L"", wcs, nUrlHistItems);
  94. }
  95. nUrlHistWC = static_cast<int>(wcs.size());
  96. // find out how many dialog sizes / positions we've stored
  97. INT_PTR nResizableDialogs = 0;
  98. CRegistryKey regResizable(L"Software\\TortoiseGit\\TortoiseProc\\ResizableState");
  99. CStringList resizablelist;
  100. regResizable.getValues(resizablelist);
  101. nResizableDialogs += resizablelist.GetCount();
  102. // find out how many auth data we've stored
  103. int nSimple = 0;
  104. int nSSL = 0;
  105. int nUsername = 0;
  106. CString sFile;
  107. bool bIsDir = false;
  108. if (CComHeapPtr<WCHAR> pszPath; SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, nullptr, &pszPath) == S_OK)
  109. {
  110. CString path { static_cast<LPCWSTR>(pszPath) };
  111. path += L"\\Subversion\\auth\\";
  112. CString sSimple = path + L"svn.simple";
  113. CString sSSL = path + L"svn.ssl.server";
  114. CString sUsername = path + L"svn.username";
  115. CDirFileEnum simpleenum(sSimple);
  116. while (simpleenum.NextFile(sFile, &bIsDir))
  117. nSimple++;
  118. CDirFileEnum sslenum(sSSL);
  119. while (sslenum.NextFile(sFile, &bIsDir))
  120. nSSL++;
  121. CDirFileEnum userenum(sUsername);
  122. while (userenum.NextFile(sFile, &bIsDir))
  123. nUsername++;
  124. }
  125. CStringList credStore;
  126. CWindowsCredentialsStore::ListCredentials(L"git:*", credStore);
  127. nSimple += static_cast<int>(credStore.GetCount());
  128. CDirFileEnum logenum(CPathUtils::GetAppDataDirectory() + L"logcache");
  129. while (logenum.NextFile(sFile, &bIsDir))
  130. nLogHistRepo++;
  131. // the "Repositories.dat" is not a cache file
  132. nLogHistRepo--;
  133. BOOL bActionLog = PathFileExists(CPathUtils::GetLocalAppDataDirectory() + L"logfile.txt");
  134. m_btnLogHistClear.EnableWindow(nLogHistMsg || nLogHistWC);
  135. m_btnUrlHistClear.EnableWindow(nUrlHistItems || nUrlHistWC);
  136. m_btnResizableHistClear.EnableWindow(nResizableDialogs > 0);
  137. m_btnAuthHistClear.EnableWindow(nSimple || nSSL || nUsername);
  138. m_btnRepoLogClear.EnableWindow(nLogHistRepo >= 0);
  139. m_btnActionLogClear.EnableWindow(bActionLog);
  140. m_btnActionLogShow.EnableWindow(bActionLog);
  141. EnableToolTips();
  142. CString sTT;
  143. sTT.FormatMessage(IDS_SETTINGS_SAVEDDATA_LOGHIST_TT, nLogHistMsg, nLogHistWC);
  144. m_tooltips.AddTool(IDC_LOGHISTORY, sTT);
  145. m_tooltips.AddTool(IDC_LOGHISTCLEAR, sTT);
  146. sTT.FormatMessage(IDS_SETTINGS_SAVEDDATA_URLHIST_TT, nUrlHistItems, nUrlHistWC);
  147. m_tooltips.AddTool(IDC_URLHISTORY, sTT);
  148. m_tooltips.AddTool(IDC_URLHISTCLEAR, sTT);
  149. sTT.Format(IDS_SETTINGS_SAVEDDATA_RESIZABLE_TT, nResizableDialogs);
  150. m_tooltips.AddTool(IDC_RESIZABLEHISTORY, sTT);
  151. m_tooltips.AddTool(IDC_RESIZABLEHISTCLEAR, sTT);
  152. sTT.FormatMessage(IDS_SETTINGS_SAVEDDATA_AUTH_TT, nSimple, nSSL, nUsername);
  153. m_tooltips.AddTool(IDC_AUTHHISTORY, sTT);
  154. m_tooltips.AddTool(IDC_AUTHHISTCLEAR, sTT);
  155. sTT.Format(IDS_SETTINGS_SAVEDDATA_REPOLOGHIST_TT, nLogHistRepo);
  156. m_tooltips.AddTool(IDC_REPOLOG, sTT);
  157. m_tooltips.AddTool(IDC_REPOLOGCLEAR, sTT);
  158. sTT.LoadString(IDS_SETTINGS_SHOWACTIONLOG_TT);
  159. m_tooltips.AddTool(IDC_ACTIONLOGSHOW, sTT);
  160. sTT.LoadString(IDS_SETTINGS_MAXACTIONLOGLINES_TT);
  161. m_tooltips.AddTool(IDC_MAXLINES, sTT);
  162. sTT.LoadString(IDS_SETTINGS_CLEARACTIONLOG_TT);
  163. m_tooltips.AddTool(IDC_ACTIONLOGCLEAR, sTT);
  164. return TRUE;
  165. }
  166. BEGIN_MESSAGE_MAP(CSetSavedDataPage, ISettingsPropPage)
  167. ON_BN_CLICKED(IDC_URLHISTCLEAR, &CSetSavedDataPage::OnBnClickedUrlhistclear)
  168. ON_BN_CLICKED(IDC_LOGHISTCLEAR, &CSetSavedDataPage::OnBnClickedLoghistclear)
  169. ON_BN_CLICKED(IDC_RESIZABLEHISTCLEAR, &CSetSavedDataPage::OnBnClickedResizablehistclear)
  170. ON_BN_CLICKED(IDC_AUTHHISTCLEAR, &CSetSavedDataPage::OnBnClickedAuthhistclear)
  171. ON_BN_CLICKED(IDC_REPOLOGCLEAR, &CSetSavedDataPage::OnBnClickedRepologclear)
  172. ON_BN_CLICKED(IDC_ACTIONLOGSHOW, &CSetSavedDataPage::OnBnClickedActionlogshow)
  173. ON_BN_CLICKED(IDC_ACTIONLOGCLEAR, &CSetSavedDataPage::OnBnClickedActionlogclear)
  174. ON_BN_CLICKED(IDC_TEMPFILESCLEAR, &CSetSavedDataPage::OnBnClickedTempfileclear)
  175. ON_EN_CHANGE(IDC_MAXLINES, OnModified)
  176. ON_BN_CLICKED(IDC_STOREDDECISIONSCLEAR, &CSetSavedDataPage::OnBnClickedStoreddecisionsclear)
  177. END_MESSAGE_MAP()
  178. void CSetSavedDataPage::OnBnClickedUrlhistclear()
  179. {
  180. for (CString key : { L"repoURLS", L"FormatPatchURLS", L"PullURLS", L"PushURLS", L"SubModuleRepoURLS", L"SyncURL" })
  181. {
  182. CRegistryKey reg(L"Software\\TortoiseGit\\History\\" + key);
  183. reg.removeKey();
  184. }
  185. m_btnUrlHistClear.EnableWindow(FALSE);
  186. m_tooltips.DelTool(GetDlgItem(IDC_URLHISTCLEAR));
  187. m_tooltips.DelTool(GetDlgItem(IDC_URLHISTORY));
  188. }
  189. void CSetSavedDataPage::OnBnClickedLoghistclear()
  190. {
  191. CRegistryKey reg(L"Software\\TortoiseGit\\History");
  192. CStringList histlist;
  193. reg.getSubKeys(histlist);
  194. for (POSITION pos = histlist.GetHeadPosition(); pos; )
  195. {
  196. CString sHist = histlist.GetNext(pos);
  197. if (CStringUtils::StartsWithI(sHist, L"commit"))
  198. {
  199. CRegistryKey regkey(L"Software\\TortoiseGit\\History\\"+sHist);
  200. regkey.removeKey();
  201. }
  202. }
  203. m_btnLogHistClear.EnableWindow(FALSE);
  204. m_tooltips.DelTool(GetDlgItem(IDC_RESIZABLEHISTCLEAR));
  205. m_tooltips.DelTool(GetDlgItem(IDC_RESIZABLEHISTORY));
  206. }
  207. void CSetSavedDataPage::OnBnClickedResizablehistclear()
  208. {
  209. CRegistryKey reg(L"Software\\TortoiseGit\\TortoiseProc\\ResizableState");
  210. reg.removeKey();
  211. m_btnResizableHistClear.EnableWindow(FALSE);
  212. m_tooltips.DelTool(GetDlgItem(IDC_RESIZABLEHISTCLEAR));
  213. m_tooltips.DelTool(GetDlgItem(IDC_RESIZABLEHISTORY));
  214. }
  215. void CSetSavedDataPage::OnBnClickedAuthhistclear()
  216. {
  217. CRegStdString auth = CRegStdString(L"Software\\TortoiseGit\\Auth\\");
  218. auth.removeKey();
  219. if (CComHeapPtr<WCHAR> pszPath; SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_CREATE, nullptr, &pszPath) == S_OK)
  220. {
  221. CString path { static_cast<LPCWSTR>(pszPath) };
  222. path += L"\\Subversion\\auth\\";
  223. DeleteViaShell(path, IDS_SETTINGS_DELFILE);
  224. }
  225. CStringList credStore;
  226. CWindowsCredentialsStore::ListCredentials(L"git:*", credStore);
  227. for (POSITION pos = credStore.GetHeadPosition(); pos;)
  228. {
  229. CWindowsCredentialsStore::DeleteCredential(credStore.GetNext(pos));
  230. }
  231. m_btnAuthHistClear.EnableWindow(FALSE);
  232. m_tooltips.DelTool(GetDlgItem(IDC_AUTHHISTCLEAR));
  233. m_tooltips.DelTool(GetDlgItem(IDC_AUTHHISTORY));
  234. }
  235. void CSetSavedDataPage::OnBnClickedRepologclear()
  236. {
  237. DeleteViaShell(CPathUtils::GetAppDataDirectory() + L"logcache", IDS_SETTINGS_DELCACHE);
  238. m_btnRepoLogClear.EnableWindow(FALSE);
  239. m_tooltips.DelTool(GetDlgItem(IDC_REPOLOG));
  240. m_tooltips.DelTool(GetDlgItem(IDC_REPOLOGCLEAR));
  241. }
  242. void CSetSavedDataPage::OnBnClickedActionlogshow()
  243. {
  244. CString logfile = CPathUtils::GetLocalAppDataDirectory() + L"logfile.txt";
  245. CAppUtils::StartTextViewer(logfile);
  246. }
  247. void CSetSavedDataPage::OnBnClickedActionlogclear()
  248. {
  249. CString logfile = CPathUtils::GetLocalAppDataDirectory() + L"logfile.txt";
  250. DeleteFile(logfile);
  251. m_btnActionLogClear.EnableWindow(FALSE);
  252. m_btnActionLogShow.EnableWindow(FALSE);
  253. }
  254. void CSetSavedDataPage::OnBnClickedTempfileclear()
  255. {
  256. if (CMessageBox::Show(m_hWnd, IDS_PROC_WARNCLEARTEMP, IDS_APPNAME, 1, IDI_QUESTION, IDS_ABORTBUTTON, IDS_PROCEEDBUTTON) == 1)
  257. return;
  258. int count = 0;
  259. DWORD len = GetTortoiseGitTempPath(0, nullptr);
  260. auto path = std::make_unique<wchar_t[]>(len + 100);
  261. len = GetTortoiseGitTempPath(len + 100, path.get());
  262. if (len != 0)
  263. {
  264. int lastcount;
  265. do
  266. {
  267. lastcount = count;
  268. count = 0;
  269. CDirFileEnum finder(path.get());
  270. bool isDir;
  271. CString filepath;
  272. while (finder.NextFile(filepath, &isDir))
  273. {
  274. ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
  275. if (isDir)
  276. {
  277. if (!::RemoveDirectory(filepath))
  278. count++;
  279. }
  280. else
  281. {
  282. if (!::DeleteFile(filepath))
  283. count++;
  284. }
  285. }
  286. } while (lastcount != count);
  287. }
  288. if (count == 0)
  289. GetDlgItem(IDC_TEMPFILESCLEAR)->EnableWindow(FALSE);
  290. }
  291. void CSetSavedDataPage::OnModified()
  292. {
  293. SetModified();
  294. }
  295. BOOL CSetSavedDataPage::OnApply()
  296. {
  297. Store(m_maxLines, m_regMaxLines);
  298. return ISettingsPropPage::OnApply();
  299. }
  300. void CSetSavedDataPage::DeleteViaShell(LPCWSTR path, UINT progressText)
  301. {
  302. CString p(path);
  303. p += L"||";
  304. int len = p.GetLength();
  305. auto buf = std::make_unique<wchar_t[]>(len + 2);
  306. wcscpy_s(buf.get(), len + 2, p);
  307. CStringUtils::PipesToNulls(buf.get(), len);
  308. CString progText(MAKEINTRESOURCE(progressText));
  309. SHFILEOPSTRUCT fileop;
  310. fileop.hwnd = m_hWnd;
  311. fileop.wFunc = FO_DELETE;
  312. fileop.pFrom = buf.get();
  313. fileop.pTo = nullptr;
  314. fileop.fFlags = FOF_NO_CONNECTED_ELEMENTS | FOF_NOCONFIRMATION;
  315. fileop.lpszProgressTitle = progText;
  316. SHFileOperation(&fileop);
  317. }
  318. void CSetSavedDataPage::OnBnClickedStoreddecisionsclear()
  319. {
  320. static const CString tgitvalues[] = {
  321. L"OldMsysgitVersionWarning",
  322. L"OpenRebaseRemoteBranchEqualsHEAD",
  323. L"OpenRebaseRemoteBranchUnchanged",
  324. L"OpenRebaseRemoteBranchFastForwards",
  325. L"DaemonNoSecurityWarning",
  326. L"NothingToCommitShowUnversioned",
  327. L"NoJumpNotFoundWarning",
  328. L"HintHierarchicalConfig",
  329. L"HintStagingMode",
  330. L"TagOptNoTagsWarning",
  331. L"NoStashIncludeUntrackedWarning",
  332. L"CommitMergeHint",
  333. L"AskSetTrackedBranch",
  334. L"StashPopShowChanges",
  335. L"StashPopShowConflictChanges",
  336. L"CommitWarnOnUnresolved",
  337. L"CommitAskBeforeCancel",
  338. L"PushAllBranches",
  339. L"CommitMessageContainsConflictHint",
  340. L"MergeConflictsNeedsCommit",
  341. L"CommitMessageTemplateNotEdited",
  342. };
  343. for (const auto& value : tgitvalues)
  344. {
  345. CRegDWORD regkey(L"Software\\TortoiseGit\\" + value);
  346. regkey.removeValue();
  347. }
  348. static const CString tmergevalues[] = {
  349. L"DeleteFileWhenEmpty",
  350. };
  351. for (const auto& value : tmergevalues)
  352. {
  353. CRegDWORD regkey(L"Software\\TortoiseGitMerge\\" + value);
  354. regkey.removeValue();
  355. }
  356. // remove stored hook decisions
  357. CRegistryKey reg(L"Software\\TortoiseGit\\approvedhooks");
  358. reg.removeKey();
  359. }