Drop unused msysgit dialog of installer
[TortoiseGit.git] / src / TortoiseProc / GitRefCompareList.cpp
blob619f12d684bb4569af2fb3e629c2a1eef92dad20
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013-2014 - 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 // GitRefCompareList.cpp : implementation file
21 #include "stdafx.h"
22 #include "resource.h"
23 #include "GitRefCompareList.h"
24 #include "registry.h"
25 #include "UnicodeUtils.h"
26 #include "MessageBox.h"
27 #include "IconMenu.h"
28 #include "AppUtils.h"
29 #include "..\TortoiseShell\resource.h"
31 IMPLEMENT_DYNAMIC(CGitRefCompareList, CHintListCtrl)
33 BEGIN_MESSAGE_MAP(CGitRefCompareList, CHintListCtrl)
34 ON_WM_CONTEXTMENU()
35 END_MESSAGE_MAP()
37 BOOL CGitRefCompareList::m_bSortLogical = FALSE;
39 enum IDGITRCL
41 IDGITRCL_DUMMY,
42 IDGITRCL_OLDLOG,
43 IDGITRCL_NEWLOG,
44 IDGITRCL_REFLOG,
47 enum IDGITRCLH
49 IDGITRCLH_DUMMY,
50 IDGITRCLH_HIDEUNCHANGED,
53 CGitRefCompareList::CGitRefCompareList()
54 : CHintListCtrl()
55 , m_Repository(nullptr)
56 , colRef(0)
57 , colChange(0)
58 , colOldHash(0)
59 , colOldMessage(0)
60 , colNewHash(0)
61 , colNewMessage(0)
63 m_bSortLogical = !CRegDWORD(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\NoStrCmpLogical", 0, false, HKEY_CURRENT_USER);
64 if (m_bSortLogical)
65 m_bSortLogical = !CRegDWORD(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\NoStrCmpLogical", 0, false, HKEY_LOCAL_MACHINE);
66 m_bHideUnchanged = CRegDWORD(_T("Software\\TortoiseGit\\RefCompareHideUnchanged"), FALSE);
69 void CGitRefCompareList::Init()
71 int index = 0;
72 colRef = InsertColumn(index++, CString(MAKEINTRESOURCE(IDS_REF)));
73 colChange = InsertColumn(index++, CString(MAKEINTRESOURCE(IDS_CHANGETYPE)));
74 colOldHash = InsertColumn(index++, CString(MAKEINTRESOURCE(IDS_OLDHASH)));
75 colOldMessage = InsertColumn(index++, CString(MAKEINTRESOURCE(IDS_OLDMESSAGE)));
76 colNewHash = InsertColumn(index++, CString(MAKEINTRESOURCE(IDS_NEWHASH)));
77 colNewMessage = InsertColumn(index++,CString(MAKEINTRESOURCE(IDS_NEWMESSAGE)));
78 for (int i = 0; i < index; ++i)
79 SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER);
80 SetColumnWidth(colRef, 130);
82 CImageList *imagelist = new CImageList();
83 imagelist->Create(IDB_BITMAP_REFTYPE, 16, 3, RGB(255, 255, 255));
84 SetImageList(imagelist, LVSIL_SMALL);
86 SetWindowTheme(m_hWnd, L"Explorer", NULL);
89 int CGitRefCompareList::OpenRepository()
91 m_Repository = nullptr;
92 CStringA gitdir = CUnicodeUtils::GetMulti(CTGitPath(g_Git.m_CurrentDir).GetGitPathString(), CP_UTF8);
93 if (git_repository_open(&m_Repository, gitdir))
95 CMessageBox::Show(m_hWnd, CGit::GetLibGit2LastErr(_T("Could not open repository.")), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
96 return -1;
99 return 0;
102 void CGitRefCompareList::CloseRepository()
104 if (m_Repository)
105 git_repository_free(m_Repository);
106 m_Repository = nullptr;
109 int CGitRefCompareList::AddEntry(CString ref, CGitHash *oldHash, CGitHash *newHash)
111 RefEntry entry;
112 entry.fullName = ref;
113 entry.shortName = CGit::GetShortName(ref, &entry.refType);
114 if (oldHash)
115 entry.oldHash = oldHash->ToString().Left(g_Git.GetShortHASHLength());
116 if (newHash)
117 entry.newHash = newHash->ToString().Left(g_Git.GetShortHASHLength());
119 git_commit *oldCommit = nullptr;
120 if (oldHash)
122 if (!git_commit_lookup(&oldCommit, m_Repository, (const git_oid *)&oldHash->m_hash))
123 entry.oldMessage = GetCommitMessage(oldCommit);
126 git_commit *newCommit = nullptr;
127 if (newHash)
129 if (!git_commit_lookup(&newCommit, m_Repository, (const git_oid *)&newHash->m_hash))
130 entry.newMessage = GetCommitMessage(newCommit);
133 if (oldHash && newHash)
135 if (*oldHash == *newHash)
137 entry.change = CString(MAKEINTRESOURCE(IDS_SAME));
138 entry.changeType = ChangeType::Same;
140 else
142 size_t ahead = 0, behind = 0;
143 if (!git_graph_ahead_behind(&ahead, &behind, m_Repository, (const git_oid *)&oldHash->m_hash, (const git_oid *)&newHash->m_hash))
145 CString change;
146 if (ahead > 0 && behind == 0)
148 entry.change.Format(IDS_FORWARDN, ahead);
149 entry.changeType = ChangeType::FastForward;
151 else if (ahead == 0 && behind > 0)
153 entry.change.Format(IDS_REWINDN, behind);
154 entry.changeType = ChangeType::Rewind;
156 else
158 git_time_t oldTime = git_commit_committer(oldCommit)->when.time;
159 git_time_t newTime = git_commit_committer(newCommit)->when.time;
160 if (oldTime < newTime)
162 entry.change = CString(MAKEINTRESOURCE(IDS_SUBMODULEDIFF_NEWERTIME));
163 entry.changeType = ChangeType::NewerTime;
165 else if (oldTime > newTime)
167 entry.change = CString(MAKEINTRESOURCE(IDS_SUBMODULEDIFF_OLDERTIME));
168 entry.changeType = ChangeType::OlderTime;
170 else
172 entry.change = CString(MAKEINTRESOURCE(IDS_SUBMODULEDIFF_SAMETIME));
173 entry.changeType = ChangeType::SameTime;
179 else if (oldHash)
181 entry.change = CString(MAKEINTRESOURCE(IDS_DELETED));
182 entry.changeType = ChangeType::Deleted;
184 else if (newHash)
186 entry.change = CString(MAKEINTRESOURCE(IDS_NEW));
187 entry.changeType = ChangeType::New;
190 if (oldCommit)
191 git_commit_free(oldCommit);
192 if (newCommit)
193 git_commit_free(newCommit);
195 m_RefList.push_back(entry);
196 return (int)m_RefList.size() - 1;
199 void CGitRefCompareList::Show()
201 DeleteAllItems();
202 std::sort(m_RefList.begin(), m_RefList.end(), SortPredicate);
203 int index = 0;
204 for (auto entry = m_RefList.begin(); entry != m_RefList.end(); ++entry)
206 if (entry->changeType == ChangeType::Same && m_bHideUnchanged)
207 continue;
209 int nImage = -1;
210 if (entry->refType == CGit::REF_TYPE::LOCAL_BRANCH)
211 nImage = 1;
212 else if (entry->refType == CGit::REF_TYPE::REMOTE_BRANCH)
213 nImage = 2;
214 else if (entry->refType == CGit::REF_TYPE::TAG)
215 nImage = 0;
216 InsertItem(index, entry->shortName, nImage);
217 SetItemText(index, colChange, entry->change);
218 SetItemText(index, colOldHash, entry->oldHash);
219 SetItemText(index, colOldMessage, entry->oldMessage);
220 SetItemText(index, colNewHash, entry->newHash);
221 SetItemText(index, colNewMessage, entry->newMessage);
222 index++;
226 void CGitRefCompareList::Clear()
228 m_RefList.clear();
229 DeleteAllItems();
232 void CGitRefCompareList::OnContextMenu(CWnd *pWnd, CPoint point)
234 if (pWnd == this)
236 OnContextMenuList(pWnd, point);
238 else if (pWnd == GetHeaderCtrl())
240 OnContextMenuHeader(pWnd, point);
244 void CGitRefCompareList::OnContextMenuList(CWnd * /*pWnd*/, CPoint point)
246 int selIndex = GetSelectionMark();
247 if (selIndex < 0 || selIndex >= m_RefList.size())
248 return;
250 CString refName = m_RefList[selIndex].fullName;
251 CString oldHash = m_RefList[selIndex].oldHash;
252 CString newHash = m_RefList[selIndex].newHash;
253 CIconMenu popup;
254 popup.CreatePopupMenu();
255 CString logStr;
256 if (!oldHash.IsEmpty())
258 logStr.Format(IDS_SHOWLOG_OF, oldHash);
259 popup.AppendMenuIcon(IDGITRCL_OLDLOG, logStr, IDI_LOG);
261 if (!newHash.IsEmpty() && oldHash != newHash)
263 logStr.Format(IDS_SHOWLOG_OF, newHash);
264 popup.AppendMenuIcon(IDGITRCL_NEWLOG, logStr, IDI_LOG);
266 popup.AppendMenuIcon(IDGITRCL_REFLOG, IDS_MENUREFLOG, IDI_LOG);
268 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);
269 AfxGetApp()->DoWaitCursor(1);
270 switch (cmd)
272 case IDGITRCL_OLDLOG:
273 case IDGITRCL_NEWLOG:
275 CString sCmd;
276 sCmd.Format(_T("/command:log /path:\"%s\" /endrev:\"%s\""), g_Git.m_CurrentDir, cmd == IDGITRCL_OLDLOG ? oldHash : newHash);
277 CAppUtils::RunTortoiseGitProc(sCmd);
278 break;
280 case IDGITRCL_REFLOG:
282 CString sCmd;
283 sCmd.Format(_T("/command:reflog /path:\"%s\" /ref:\"%s\""), g_Git.m_CurrentDir, refName);
284 CAppUtils::RunTortoiseGitProc(sCmd);
285 break;
288 AfxGetApp()->DoWaitCursor(-1);
291 static void AppendMenuChecked(CMenu &menu, UINT nTextID, UINT_PTR nItemID, BOOL checked = FALSE, BOOL enabled = TRUE)
293 CString text;
294 text.LoadString(nTextID);
295 menu.AppendMenu(MF_STRING | (enabled ? MF_ENABLED : MF_DISABLED) | (checked ? MF_CHECKED : MF_UNCHECKED), nItemID, text);
298 void CGitRefCompareList::OnContextMenuHeader(CWnd * /*pWnd*/, CPoint point)
300 CMenu popup;
301 if (popup.CreatePopupMenu())
303 AppendMenuChecked(popup, IDS_HIDEUNCHANGED, IDGITRCLH_HIDEUNCHANGED, m_bHideUnchanged);
305 int selection = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);
306 switch (selection)
308 case IDGITRCLH_HIDEUNCHANGED:
309 m_bHideUnchanged = !m_bHideUnchanged;
310 Show();
311 break;
316 CString CGitRefCompareList::GetCommitMessage(git_commit *commit)
318 int encode = CP_UTF8;
319 const char *encodingString = git_commit_message_encoding(commit);
320 if (encodingString != nullptr)
322 CString str;
323 g_Git.StringAppend(&str, (BYTE*)encodingString, CP_UTF8);
324 encode = CUnicodeUtils::GetCPCode(str);
327 CString message;
328 g_Git.StringAppend(&message, (BYTE*)git_commit_message(commit), encode);
329 int start = 0;
330 message = message.Tokenize(_T("\n"), start);
331 return message;
334 bool CGitRefCompareList::SortPredicate(const RefEntry &e1, const RefEntry &e2)
336 if (e1.changeType < e2.changeType)
337 return true;
338 if (e1.changeType > e2.changeType)
339 return false;
340 if (m_bSortLogical)
341 return StrCmpLogicalW(e1.fullName, e2.fullName) < 0;
342 return e1.fullName.Compare(e2.fullName) < 0;