OSDN Git Service

reorg loglist
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / LogDlg.cpp
1 // TortoiseGit - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseGit\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "TortoiseProc.h"\r
21 #include "cursor.h"\r
22 #include "InputDlg.h"\r
23 #include "PropDlg.h"\r
24 #include "SVNProgressDlg.h"\r
25 #include "ProgressDlg.h"\r
26 //#include "RepositoryBrowser.h"\r
27 //#include "CopyDlg.h"\r
28 //#include "StatGraphDlg.h"\r
29 #include "Logdlg.h"\r
30 #include "MessageBox.h"\r
31 #include "Registry.h"\r
32 #include "AppUtils.h"\r
33 #include "PathUtils.h"\r
34 #include "StringUtils.h"\r
35 #include "UnicodeUtils.h"\r
36 #include "TempFile.h"\r
37 //#include "GitInfo.h"\r
38 //#include "GitDiff.h"\r
39 #include "IconMenu.h"\r
40 //#include "RevisionRangeDlg.h"\r
41 //#include "BrowseFolder.h"\r
42 //#include "BlameDlg.h"\r
43 //#include "Blame.h"\r
44 //#include "GitHelpers.h"\r
45 #include "GitStatus.h"\r
46 //#include "LogDlgHelper.h"\r
47 //#include "CachedLogInfo.h"\r
48 //#include "RepositoryInfo.h"\r
49 //#include "EditPropertiesDlg.h"\r
50 #include "FileDiffDlg.h"\r
51 \r
52 \r
53 const UINT CLogDlg::m_FindDialogMessage = RegisterWindowMessage(FINDMSGSTRING);\r
54 \r
55 \r
56 \r
57 \r
58 IMPLEMENT_DYNAMIC(CLogDlg, CResizableStandAloneDialog)\r
59 CLogDlg::CLogDlg(CWnd* pParent /*=NULL*/)\r
60         : CResizableStandAloneDialog(CLogDlg::IDD, pParent)\r
61         , m_logcounter(0)\r
62         , m_nSearchIndex(0)\r
63         , m_wParam(0)\r
64         , m_nSelectedFilter(LOGFILTER_ALL)\r
65         , m_bNoDispUpdates(FALSE)\r
66         , m_currentChangedArray(NULL)\r
67         , m_nSortColumn(0)\r
68         , m_bShowedAll(false)\r
69         , m_bSelect(false)\r
70         , m_regLastStrict(_T("Software\\TortoiseGit\\LastLogStrict"), FALSE)\r
71         , m_regMaxBugIDColWidth(_T("Software\\TortoiseGit\\MaxBugIDColWidth"), 200)\r
72         , m_bSelectionMustBeContinuous(false)\r
73         , m_bShowBugtraqColumn(false)\r
74         , m_lowestRev(_T(""))\r
75         , m_bStrictStopped(false)\r
76         , m_sLogInfo(_T(""))\r
77         , m_pFindDialog(NULL)\r
78         , m_bCancelled(FALSE)\r
79         , m_pNotifyWindow(NULL)\r
80         , m_bThreadRunning(FALSE)\r
81         , m_bAscending(FALSE)\r
82         , m_pStoreSelection(NULL)\r
83         , m_limit(0)\r
84         , m_childCounter(0)\r
85         , m_maxChild(0)\r
86         , m_bIncludeMerges(FALSE)\r
87         , m_hAccel(NULL)\r
88         , m_bVista(false)\r
89 {\r
90         m_bFilterWithRegex = !!CRegDWORD(_T("Software\\TortoiseGit\\UseRegexFilter"), TRUE);\r
91         // use the default GUI font, create a copy of it and\r
92         // change the copy to BOLD (leave the rest of the font\r
93         // the same)\r
94         HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);\r
95         LOGFONT lf = {0};\r
96         GetObject(hFont, sizeof(LOGFONT), &lf);\r
97         lf.lfWeight = FW_BOLD;\r
98         m_boldFont = CreateFontIndirect(&lf);\r
99 }\r
100 \r
101 CLogDlg::~CLogDlg()\r
102 {\r
103         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
104     m_CurrentFilteredChangedArray.RemoveAll();\r
105         m_logEntries.ClearAll();\r
106 \r
107         if ( m_pStoreSelection )\r
108         {\r
109                 delete m_pStoreSelection;\r
110                 m_pStoreSelection = NULL;\r
111         }\r
112         if (m_boldFont)\r
113                 DeleteObject(m_boldFont);\r
114 }\r
115 \r
116 void CLogDlg::DoDataExchange(CDataExchange* pDX)\r
117 {\r
118         CResizableStandAloneDialog::DoDataExchange(pDX);\r
119         DDX_Control(pDX, IDC_LOGLIST, m_LogList);\r
120         DDX_Control(pDX, IDC_LOGMSG, m_ChangedFileListCtrl);\r
121         DDX_Control(pDX, IDC_PROGRESS, m_LogProgress);\r
122         DDX_Control(pDX, IDC_SPLITTERTOP, m_wndSplitter1);\r
123         DDX_Control(pDX, IDC_SPLITTERBOTTOM, m_wndSplitter2);\r
124         DDX_Check(pDX, IDC_CHECK_STOPONCOPY, m_bStrict);\r
125         DDX_Text(pDX, IDC_SEARCHEDIT, m_sFilterText);\r
126         DDX_Control(pDX, IDC_DATEFROM, m_DateFrom);\r
127         DDX_Control(pDX, IDC_DATETO, m_DateTo);\r
128         DDX_Control(pDX, IDC_HIDEPATHS, m_cHidePaths);\r
129         DDX_Control(pDX, IDC_GETALL, m_btnShow);\r
130         DDX_Text(pDX, IDC_LOGINFO, m_sLogInfo);\r
131         DDX_Check(pDX, IDC_INCLUDEMERGE, m_bIncludeMerges);\r
132         DDX_Control(pDX, IDC_SEARCHEDIT, m_cFilter);\r
133 }\r
134 \r
135 BEGIN_MESSAGE_MAP(CLogDlg, CResizableStandAloneDialog)\r
136         ON_REGISTERED_MESSAGE(m_FindDialogMessage, OnFindDialogMessage) \r
137         ON_BN_CLICKED(IDC_GETALL, OnBnClickedGetall)\r
138         ON_NOTIFY(NM_DBLCLK, IDC_LOGMSG, OnNMDblclkChangedFileList)\r
139         ON_WM_CONTEXTMENU()\r
140         ON_WM_SETCURSOR()\r
141         ON_BN_CLICKED(IDHELP, OnBnClickedHelp)\r
142         ON_NOTIFY(LVN_ITEMCHANGED, IDC_LOGLIST, OnLvnItemchangedLoglist)\r
143         ON_NOTIFY(EN_LINK, IDC_MSGVIEW, OnEnLinkMsgview)\r
144         ON_BN_CLICKED(IDC_STATBUTTON, OnBnClickedStatbutton)\r
145         //ON_NOTIFY(NM_CUSTOMDRAW, IDC_LOGLIST, OnNMCustomdrawLoglist)\r
146         ON_MESSAGE(WM_FILTEREDIT_INFOCLICKED, OnClickedInfoIcon)\r
147         ON_MESSAGE(WM_FILTEREDIT_CANCELCLICKED, OnClickedCancelFilter)\r
148         //ON_NOTIFY(LVN_GETDISPINFO, IDC_LOGLIST, OnLvnGetdispinfoLoglist)\r
149         ON_EN_CHANGE(IDC_SEARCHEDIT, OnEnChangeSearchedit)\r
150         ON_WM_TIMER()\r
151         ON_NOTIFY(DTN_DATETIMECHANGE, IDC_DATETO, OnDtnDatetimechangeDateto)\r
152         ON_NOTIFY(DTN_DATETIMECHANGE, IDC_DATEFROM, OnDtnDatetimechangeDatefrom)\r
153         ON_BN_CLICKED(IDC_NEXTHUNDRED, OnBnClickedNexthundred)\r
154         ON_NOTIFY(NM_CUSTOMDRAW, IDC_LOGMSG, OnNMCustomdrawChangedFileList)\r
155         ON_NOTIFY(LVN_GETDISPINFO, IDC_LOGMSG, OnLvnGetdispinfoChangedFileList)\r
156         ON_NOTIFY(LVN_COLUMNCLICK,IDC_LOGLIST   , OnLvnColumnclick)\r
157         ON_NOTIFY(LVN_COLUMNCLICK, IDC_LOGMSG, OnLvnColumnclickChangedFileList)\r
158         ON_BN_CLICKED(IDC_HIDEPATHS, OnBnClickedHidepaths)\r
159         \r
160         ON_BN_CLICKED(IDC_CHECK_STOPONCOPY, &CLogDlg::OnBnClickedCheckStoponcopy)\r
161         ON_NOTIFY(DTN_DROPDOWN, IDC_DATEFROM, &CLogDlg::OnDtnDropdownDatefrom)\r
162         ON_NOTIFY(DTN_DROPDOWN, IDC_DATETO, &CLogDlg::OnDtnDropdownDateto)\r
163         ON_WM_SIZE()\r
164         ON_BN_CLICKED(IDC_INCLUDEMERGE, &CLogDlg::OnBnClickedIncludemerge)\r
165         ON_BN_CLICKED(IDC_REFRESH, &CLogDlg::OnBnClickedRefresh)\r
166         ON_COMMAND(ID_LOGDLG_REFRESH,&CLogDlg::OnRefresh)\r
167         ON_COMMAND(ID_LOGDLG_FIND,&CLogDlg::OnFind)\r
168         ON_COMMAND(ID_LOGDLG_FOCUSFILTER,&CLogDlg::OnFocusFilter)\r
169         ON_COMMAND(ID_EDIT_COPY, &CLogDlg::OnEditCopy)\r
170 END_MESSAGE_MAP()\r
171 \r
172 void CLogDlg::SetParams(const CTGitPath& path, GitRev pegrev, GitRev startrev, GitRev endrev, int limit, BOOL bStrict /* = FALSE */, BOOL bSaveStrict /* = TRUE */)\r
173 {\r
174         m_path = path;\r
175         m_pegrev = pegrev;\r
176         m_startrev = startrev;\r
177         m_LogRevision = startrev;\r
178         m_endrev = endrev;\r
179         m_hasWC = !path.IsUrl();\r
180         m_bStrict = bStrict;\r
181         m_bSaveStrict = bSaveStrict;\r
182         m_limit = limit;\r
183         if (::IsWindow(m_hWnd))\r
184                 UpdateData(FALSE);\r
185 }\r
186 \r
187 BOOL CLogDlg::OnInitDialog()\r
188 {\r
189         CResizableStandAloneDialog::OnInitDialog();\r
190 \r
191         m_hAccel = LoadAccelerators(AfxGetResourceHandle(),MAKEINTRESOURCE(IDR_ACC_LOGDLG));\r
192 \r
193         OSVERSIONINFOEX inf;\r
194         SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
195         inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
196         GetVersionEx((OSVERSIONINFO *)&inf);\r
197         WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
198         m_bVista = (fullver >= 0x0600);\r
199 \r
200         // use the state of the "stop on copy/rename" option from the last time\r
201         if (!m_bStrict)\r
202                 m_bStrict = m_regLastStrict;\r
203         UpdateData(FALSE);\r
204         CString temp;\r
205         if (m_limit)\r
206                 temp.Format(IDS_LOG_SHOWNEXT, m_limit);\r
207         else\r
208                 temp.Format(IDS_LOG_SHOWNEXT, (int)(DWORD)CRegDWORD(_T("Software\\TortoiseGit\\NumberOfLogs"), 100));\r
209 \r
210         SetDlgItemText(IDC_NEXTHUNDRED, temp);\r
211 \r
212         // set the font to use in the log message view, configured in the settings dialog\r
213         CAppUtils::CreateFontForLogs(m_logFont);\r
214         GetDlgItem(IDC_MSGVIEW)->SetFont(&m_logFont);\r
215         // automatically detect URLs in the log message and turn them into links\r
216         GetDlgItem(IDC_MSGVIEW)->SendMessage(EM_AUTOURLDETECT, TRUE, NULL);\r
217         // make the log message rich edit control send a message when the mouse pointer is over a link\r
218         GetDlgItem(IDC_MSGVIEW)->SendMessage(EM_SETEVENTMASK, NULL, ENM_LINK);\r
219         //m_LogList.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_SUBITEMIMAGES);\r
220 \r
221         // the "hide unrelated paths" checkbox should be indeterminate\r
222         m_cHidePaths.SetCheck(BST_INDETERMINATE);\r
223 \r
224         \r
225         // if there is a working copy, load the project properties\r
226         // to get information about the bugtraq: integration\r
227         if (m_hasWC)\r
228                 m_ProjectProperties.ReadProps(m_path);\r
229 \r
230         // the bugtraq issue id column is only shown if the bugtraq:url or bugtraq:regex is set\r
231         if ((!m_ProjectProperties.sUrl.IsEmpty())||(!m_ProjectProperties.sCheckRe.IsEmpty()))\r
232                 m_bShowBugtraqColumn = true;\r
233 \r
234         theme.SetWindowTheme(m_LogList.GetSafeHwnd(), L"Explorer", NULL);\r
235         theme.SetWindowTheme(m_ChangedFileListCtrl.GetSafeHwnd(), L"Explorer", NULL);\r
236 \r
237         // set up the columns\r
238         m_LogList.DeleteAllItems();\r
239 #if 0\r
240         int c = ((CHeaderCtrl*)(m_LogList.GetDlgItem(0)))->GetItemCount()-1;\r
241         \r
242         while (c>=0)\r
243                 m_LogList.DeleteColumn(c--);\r
244         temp.LoadString(IDS_LOG_GRAPH);\r
245 \r
246         m_LogList.InsertColumn(this->LOGLIST_GRAPH, temp);\r
247         \r
248 #if 0   \r
249         // make the revision column right aligned\r
250         LVCOLUMN Column;\r
251         Column.mask = LVCF_FMT;\r
252         Column.fmt = LVCFMT_RIGHT;\r
253         m_LogList.SetColumn(0, &Column); \r
254 #endif  \r
255 //      CString log;\r
256 //      g_Git.GetLog(log);\r
257 \r
258         temp.LoadString(IDS_LOG_ACTIONS);\r
259         m_LogList.InsertColumn(this->LOGLIST_ACTION, temp);\r
260         \r
261         temp.LoadString(IDS_LOG_MESSAGE);\r
262         m_LogList.InsertColumn(this->LOGLIST_MESSAGE, temp);\r
263         \r
264         temp.LoadString(IDS_LOG_AUTHOR);\r
265         m_LogList.InsertColumn(this->LOGLIST_AUTHOR, temp);\r
266         \r
267         temp.LoadString(IDS_LOG_DATE);\r
268         m_LogList.InsertColumn(this->LOGLIST_DATE, temp);\r
269         \r
270 \r
271         if (m_bShowBugtraqColumn)\r
272         {\r
273                 temp = m_ProjectProperties.sLabel;\r
274                 if (temp.IsEmpty())\r
275                         temp.LoadString(IDS_LOG_BUGIDS);\r
276                 m_LogList.InsertColumn(this->LOGLIST_BUG, temp);\r
277 \r
278         }\r
279         \r
280         m_LogList.SetRedraw(false);\r
281         ResizeAllListCtrlCols();\r
282         m_LogList.SetRedraw(true);\r
283 #endif\r
284         m_ChangedFileListCtrl.SetExtendedStyle ( LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER );\r
285         m_ChangedFileListCtrl.DeleteAllItems();\r
286         c = ((CHeaderCtrl*)(m_ChangedFileListCtrl.GetDlgItem(0)))->GetItemCount()-1;\r
287         while (c>=0)\r
288                 m_ChangedFileListCtrl.DeleteColumn(c--);\r
289         temp.LoadString(IDS_PROGRS_ACTION);\r
290         m_ChangedFileListCtrl.InsertColumn(this->FILELIST_ACTION, temp);\r
291         temp.LoadString(IDS_LOG_FILE_LINE_ADD);\r
292         m_ChangedFileListCtrl.InsertColumn(this->FILELIST_ADD, temp);\r
293         temp.LoadString(IDS_LOG_FILE_LINE_DEL);\r
294         m_ChangedFileListCtrl.InsertColumn(this->FILELIST_DEL, temp);\r
295         temp.LoadString(IDS_PROGRS_PATH);\r
296         m_ChangedFileListCtrl.InsertColumn(this->FILELIST_PATH, temp);\r
297         \r
298         m_ChangedFileListCtrl.SetRedraw(false);\r
299         CAppUtils::ResizeAllListCtrlCols(&m_ChangedFileListCtrl);\r
300         m_ChangedFileListCtrl.SetRedraw(true);\r
301 \r
302 \r
303         GetDlgItem(IDC_LOGLIST)->UpdateData(FALSE);\r
304 \r
305         m_logcounter = 0;\r
306         m_sMessageBuf.Preallocate(100000);\r
307 \r
308         // set the dialog title to "Log - path/to/whatever/we/show/the/log/for"\r
309         SetDlgTitle(false);\r
310 \r
311         m_tooltips.Create(this);\r
312         CheckRegexpTooltip();\r
313 \r
314         SetSplitterRange();\r
315         \r
316         // the filter control has a 'cancel' button (the red 'X'), we need to load its bitmap\r
317         m_cFilter.SetCancelBitmaps(IDI_CANCELNORMAL, IDI_CANCELPRESSED);\r
318         m_cFilter.SetInfoIcon(IDI_LOGFILTER);\r
319         m_cFilter.SetValidator(this);\r
320         \r
321         AdjustControlSize(IDC_HIDEPATHS);\r
322         AdjustControlSize(IDC_CHECK_STOPONCOPY);\r
323         AdjustControlSize(IDC_INCLUDEMERGE);\r
324 \r
325         GetClientRect(m_DlgOrigRect);\r
326         m_LogList.GetClientRect(m_LogListOrigRect);\r
327         GetDlgItem(IDC_MSGVIEW)->GetClientRect(m_MsgViewOrigRect);\r
328         m_ChangedFileListCtrl.GetClientRect(m_ChgOrigRect);\r
329 \r
330         m_DateFrom.SendMessage(DTM_SETMCSTYLE, 0, MCS_WEEKNUMBERS|MCS_NOTODAY|MCS_NOTRAILINGDATES|MCS_NOSELCHANGEONNAV);\r
331         m_DateTo.SendMessage(DTM_SETMCSTYLE, 0, MCS_WEEKNUMBERS|MCS_NOTODAY|MCS_NOTRAILINGDATES|MCS_NOSELCHANGEONNAV);\r
332 \r
333         // resizable stuff\r
334         AddAnchor(IDC_FROMLABEL, TOP_LEFT);\r
335         AddAnchor(IDC_DATEFROM, TOP_LEFT);\r
336         AddAnchor(IDC_TOLABEL, TOP_LEFT);\r
337         AddAnchor(IDC_DATETO, TOP_LEFT);\r
338 \r
339         SetFilterCueText();\r
340         AddAnchor(IDC_SEARCHEDIT, TOP_LEFT, TOP_RIGHT);\r
341         \r
342         AddAnchor(IDC_LOGLIST, TOP_LEFT, TOP_RIGHT);\r
343         AddAnchor(IDC_SPLITTERTOP, TOP_LEFT, TOP_RIGHT);\r
344         AddAnchor(IDC_MSGVIEW, TOP_LEFT, BOTTOM_RIGHT);\r
345         AddAnchor(IDC_SPLITTERBOTTOM, BOTTOM_LEFT, BOTTOM_RIGHT);\r
346         AddAnchor(IDC_LOGMSG, BOTTOM_LEFT, BOTTOM_RIGHT);\r
347 \r
348         AddAnchor(IDC_LOGINFO, BOTTOM_LEFT, BOTTOM_RIGHT);      \r
349         AddAnchor(IDC_HIDEPATHS, BOTTOM_LEFT);  \r
350         AddAnchor(IDC_CHECK_STOPONCOPY, BOTTOM_LEFT);\r
351         AddAnchor(IDC_INCLUDEMERGE, BOTTOM_LEFT);\r
352         AddAnchor(IDC_GETALL, BOTTOM_LEFT);\r
353         AddAnchor(IDC_NEXTHUNDRED, BOTTOM_LEFT);\r
354         AddAnchor(IDC_REFRESH, BOTTOM_LEFT);\r
355         AddAnchor(IDC_STATBUTTON, BOTTOM_RIGHT);\r
356         AddAnchor(IDC_PROGRESS, BOTTOM_LEFT, BOTTOM_RIGHT);\r
357         AddAnchor(IDOK, BOTTOM_RIGHT);\r
358         AddAnchor(IDCANCEL, BOTTOM_RIGHT);\r
359         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
360 \r
361 //      SetPromptParentWindow(m_hWnd);\r
362 \r
363         if (hWndExplorer)\r
364                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
365         EnableSaveRestore(_T("LogDlg"));\r
366 \r
367         DWORD yPos1 = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\LogDlgSizer1"));\r
368         DWORD yPos2 = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\LogDlgSizer2"));\r
369         RECT rcDlg, rcLogList, rcChgMsg;\r
370         GetClientRect(&rcDlg);\r
371         m_LogList.GetWindowRect(&rcLogList);\r
372         ScreenToClient(&rcLogList);\r
373         m_ChangedFileListCtrl.GetWindowRect(&rcChgMsg);\r
374         ScreenToClient(&rcChgMsg);\r
375         if (yPos1)\r
376         {\r
377                 RECT rectSplitter;\r
378                 m_wndSplitter1.GetWindowRect(&rectSplitter);\r
379                 ScreenToClient(&rectSplitter);\r
380                 int delta = yPos1 - rectSplitter.top;\r
381 \r
382                 if ((rcLogList.bottom + delta > rcLogList.top)&&(rcLogList.bottom + delta < rcChgMsg.bottom - 30))\r
383                 {\r
384                         m_wndSplitter1.SetWindowPos(NULL, 0, yPos1, 0, 0, SWP_NOSIZE);\r
385                         DoSizeV1(delta);\r
386                 }\r
387         }\r
388         if (yPos2)\r
389         {\r
390                 RECT rectSplitter;\r
391                 m_wndSplitter2.GetWindowRect(&rectSplitter);\r
392                 ScreenToClient(&rectSplitter);\r
393                 int delta = yPos2 - rectSplitter.top;\r
394 \r
395                 if ((rcChgMsg.top + delta < rcChgMsg.bottom)&&(rcChgMsg.top + delta > rcLogList.top + 30))\r
396                 {\r
397                         m_wndSplitter2.SetWindowPos(NULL, 0, yPos2, 0, 0, SWP_NOSIZE);\r
398                         DoSizeV2(delta);\r
399                 }\r
400         }\r
401 \r
402         \r
403         if (m_bSelect)\r
404         {\r
405                 // the dialog is used to select revisions\r
406                 if (m_bSelectionMustBeContinuous)\r
407                         DialogEnableWindow(IDOK, (m_LogList.GetSelectedCount()!=0)&&(IsSelectionContinuous()));\r
408                 else\r
409                         DialogEnableWindow(IDOK, m_LogList.GetSelectedCount()!=0);\r
410         }\r
411         else\r
412         {\r
413                 // the dialog is used to just view log messages\r
414                 GetDlgItemText(IDOK, temp);\r
415                 SetDlgItemText(IDCANCEL, temp);\r
416                 GetDlgItem(IDOK)->ShowWindow(SW_HIDE);\r
417         }\r
418         \r
419         // set the choices for the "Show All" button\r
420         temp.LoadString(IDS_LOG_SHOWALL);\r
421         m_btnShow.AddEntry(temp);\r
422         temp.LoadString(IDS_LOG_SHOWRANGE);\r
423         m_btnShow.AddEntry(temp);\r
424         m_btnShow.SetCurrentEntry((LONG)CRegDWORD(_T("Software\\TortoiseGit\\ShowAllEntry")));\r
425 \r
426         m_mergedRevs.clear();\r
427 \r
428         // first start a thread to obtain the log messages without\r
429         // blocking the dialog\r
430         m_tTo = 0;\r
431         m_tFrom = (DWORD)-1;\r
432         InterlockedExchange(&m_bThreadRunning, TRUE);\r
433         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
434         if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
435         {\r
436                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
437                 InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
438                 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
439         }\r
440         GetDlgItem(IDC_LOGLIST)->SetFocus();\r
441         return FALSE;\r
442 }\r
443 \r
444 void CLogDlg::SetDlgTitle(bool bOffline)\r
445 {\r
446         if (m_sTitle.IsEmpty())\r
447                 GetWindowText(m_sTitle);\r
448 \r
449         if (bOffline)\r
450         {\r
451                 CString sTemp;\r
452                 if (m_path.IsUrl())\r
453                         sTemp.Format(IDS_LOG_DLGTITLEOFFLINE, (LPCTSTR)m_sTitle, (LPCTSTR)m_path.GetUIPathString());\r
454                 else if (m_path.IsDirectory())\r
455                         sTemp.Format(IDS_LOG_DLGTITLEOFFLINE, (LPCTSTR)m_sTitle, (LPCTSTR)m_path.GetWinPathString());\r
456                 else\r
457                         sTemp.Format(IDS_LOG_DLGTITLEOFFLINE, (LPCTSTR)m_sTitle, (LPCTSTR)m_path.GetFilename());\r
458                 SetWindowText(sTemp);\r
459         }\r
460         else\r
461         {\r
462                 if (m_path.IsUrl())\r
463                         SetWindowText(m_sTitle + _T(" - ") + m_path.GetUIPathString());\r
464                 else if (m_path.IsDirectory())\r
465                         SetWindowText(m_sTitle + _T(" - ") + m_path.GetWinPathString());\r
466                 else\r
467                         SetWindowText(m_sTitle + _T(" - ") + m_path.GetFilename());\r
468         }\r
469 }\r
470 \r
471 void CLogDlg::CheckRegexpTooltip()\r
472 {\r
473         CWnd *pWnd = GetDlgItem(IDC_SEARCHEDIT);\r
474         // Since tooltip describes regexp features, show it only if regexps are enabled.\r
475         if (m_bFilterWithRegex)\r
476         {\r
477                 m_tooltips.AddTool(pWnd, IDS_LOG_FILTER_REGEX_TT);\r
478         }\r
479         else\r
480                 m_tooltips.DelTool(pWnd);\r
481 }\r
482 \r
483 void CLogDlg::EnableOKButton()\r
484 {\r
485         if (m_bSelect)\r
486         {\r
487                 // the dialog is used to select revisions\r
488                 if (m_bSelectionMustBeContinuous)\r
489                         DialogEnableWindow(IDOK, (m_LogList.GetSelectedCount()!=0)&&(IsSelectionContinuous()));\r
490                 else\r
491                         DialogEnableWindow(IDOK, m_LogList.GetSelectedCount()!=0);\r
492         }\r
493         else\r
494                 DialogEnableWindow(IDOK, TRUE);\r
495 }\r
496 \r
497 void CLogDlg::FillLogMessageCtrl(bool bShow /* = true*/)\r
498 {\r
499         // we fill here the log message rich edit control,\r
500         // and also populate the changed files list control\r
501         // according to the selected revision(s).\r
502 \r
503         CWnd * pMsgView = GetDlgItem(IDC_MSGVIEW);\r
504         // empty the log message view\r
505         pMsgView->SetWindowText(_T(" "));\r
506         // empty the changed files list\r
507         m_ChangedFileListCtrl.SetRedraw(FALSE);\r
508         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
509         m_currentChangedArray = NULL;\r
510         m_ChangedFileListCtrl.SetExtendedStyle ( LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER );\r
511         m_ChangedFileListCtrl.DeleteAllItems();\r
512         m_ChangedFileListCtrl.SetItemCountEx(0);\r
513 \r
514         // if we're not here to really show a selected revision, just\r
515         // get out of here after clearing the views, which is what is intended\r
516         // if that flag is not set.\r
517         if (!bShow)\r
518         {\r
519                 // force a redraw\r
520                 m_ChangedFileListCtrl.Invalidate();\r
521                 InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
522                 m_ChangedFileListCtrl.SetRedraw(TRUE);\r
523                 return;\r
524         }\r
525 \r
526         // depending on how many revisions are selected, we have to do different\r
527         // tasks.\r
528         int selCount = m_LogList.GetSelectedCount();\r
529         if (selCount == 0)\r
530         {\r
531                 // if nothing is selected, we have nothing more to do\r
532                 InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
533                 m_ChangedFileListCtrl.SetRedraw(TRUE);\r
534                 return;\r
535         }\r
536         else if (selCount == 1)\r
537         {\r
538                 // if one revision is selected, we have to fill the log message view\r
539                 // with the corresponding log message, and also fill the changed files\r
540                 // list fully.\r
541                 POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
542                 int selIndex = m_LogList.GetNextSelectedItem(pos);\r
543                 if (selIndex >= m_arShownList.GetCount())\r
544                 {\r
545                         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
546                         m_ChangedFileListCtrl.SetRedraw(TRUE);\r
547                         return;\r
548                 }\r
549                 GitRev* pLogEntry = reinterpret_cast<GitRev *>(m_arShownList.GetAt(selIndex));\r
550 \r
551                 // set the log message text\r
552                 pMsgView->SetWindowText(_T("*")+pLogEntry->m_Subject+_T("\n\n")+pLogEntry->m_Body);\r
553                 // turn bug ID's into links if the bugtraq: properties have been set\r
554                 // and we can find a match of those in the log message\r
555                 m_ProjectProperties.FindBugID(pLogEntry->m_Body, pMsgView);\r
556                 CAppUtils::FormatTextInRichEditControl(pMsgView);\r
557                 m_currentChangedArray = &(pLogEntry->m_Files);\r
558                 if (m_currentChangedArray == NULL)\r
559                 {\r
560                         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
561                         m_ChangedFileListCtrl.SetRedraw(TRUE);\r
562                         return;\r
563                 }\r
564 #if 0\r
565                 // fill in the changed files list control\r
566                 if ((m_cHidePaths.GetState() & 0x0003)==BST_CHECKED)\r
567                 {\r
568                         m_CurrentFilteredChangedArray.RemoveAll();\r
569                         for (INT_PTR c = 0; c < m_currentChangedArray->GetCount(); ++c)\r
570                         {\r
571                                 LogChangedPath * cpath = m_currentChangedArray->GetAt(c);\r
572                                 if (cpath == NULL)\r
573                                         continue;\r
574                                 if (m_currentChangedArray->GetAt(c)->sPath.Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)==0)\r
575                                 {\r
576                                         m_CurrentFilteredChangedArray.Add(cpath);\r
577                                 }\r
578                         }\r
579                         m_currentChangedArray = &m_CurrentFilteredChangedArray;\r
580                 }\r
581 #endif\r
582         }\r
583         else\r
584         {\r
585                 // more than one revision is selected:\r
586                 // the log message view must be emptied\r
587                 // the changed files list contains all the changed paths from all\r
588                 // selected revisions, with 'doubles' removed\r
589                 m_currentChangedPathList = GetChangedPathsFromSelectedRevisions(true);\r
590         }\r
591         \r
592         // redraw the views\r
593         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
594         if (m_currentChangedArray)\r
595         {\r
596                 m_ChangedFileListCtrl.SetItemCountEx(m_currentChangedArray->GetCount());\r
597                 m_ChangedFileListCtrl.RedrawItems(0, m_currentChangedArray->GetCount());\r
598         }\r
599         else if (m_currentChangedPathList.GetCount())\r
600         {\r
601                 m_ChangedFileListCtrl.SetItemCountEx(m_currentChangedPathList.GetCount());\r
602                 m_ChangedFileListCtrl.RedrawItems(0, m_currentChangedPathList.GetCount());\r
603         }\r
604         else\r
605         {\r
606                 m_ChangedFileListCtrl.SetItemCountEx(0);\r
607                 m_ChangedFileListCtrl.Invalidate();\r
608         }\r
609         CAppUtils::ResizeAllListCtrlCols(&m_ChangedFileListCtrl);\r
610         // sort according to the settings\r
611         if (m_nSortColumnPathList > 0)\r
612                 SetSortArrow(&m_ChangedFileListCtrl, m_nSortColumnPathList, m_bAscendingPathList);\r
613         else\r
614                 SetSortArrow(&m_ChangedFileListCtrl, -1, false);\r
615         m_ChangedFileListCtrl.SetRedraw(TRUE);\r
616 \r
617 }\r
618 \r
619 void CLogDlg::OnBnClickedGetall()\r
620 {\r
621         GetAll();\r
622 }\r
623 \r
624 void CLogDlg::GetAll(bool bForceAll /* = false */)\r
625 {\r
626 #if 0\r
627         // fetch all requested log messages, either the specified range or\r
628         // really *all* available log messages.\r
629         UpdateData();\r
630         INT_PTR entry = m_btnShow.GetCurrentEntry();\r
631         if (bForceAll)\r
632                 entry = 0;\r
633 \r
634         switch (entry)\r
635         {\r
636         case 0: // show all\r
637         \r
638                 m_endrev = 0;\r
639                 m_startrev = m_LogRevision;\r
640                 if (m_bStrict)\r
641                         m_bShowedAll = true;\r
642 \r
643                 break;\r
644         case 1: // show range\r
645                 {\r
646 \r
647                         // ask for a revision range\r
648                         CRevisionRangeDlg dlg;\r
649                         dlg.SetStartRevision(m_startrev);\r
650                         dlg.SetEndRevision( (m_endrev>=0) ? m_endrev : 0);\r
651                         if (dlg.DoModal()!=IDOK)\r
652                         {\r
653                                 return;\r
654                         }\r
655                         m_endrev = dlg.GetEndRevision();\r
656                         m_startrev = dlg.GetStartRevision();\r
657                         if (((m_endrev.IsNumber())&&(m_startrev.IsNumber()))||\r
658                                 (m_endrev.IsHead()||m_startrev.IsHead()))\r
659                         {\r
660                                 if (((LONG)m_startrev < (LONG)m_endrev)||\r
661                                         (m_endrev.IsHead()))\r
662                                 {\r
663                                         git_revnum_t temp = m_startrev;\r
664                                         m_startrev = m_endrev;\r
665                                         m_endrev = temp;\r
666                                 }\r
667                         }\r
668                         m_bShowedAll = false;\r
669                 }\r
670 \r
671                 break;\r
672         }\r
673         m_ChangedFileListCtrl.SetItemCountEx(0);\r
674         m_ChangedFileListCtrl.Invalidate();\r
675         // We need to create CStoreSelection on the heap or else\r
676         // the variable will run out of the scope before the\r
677         // thread ends. Therefore we let the thread delete\r
678         // the instance.\r
679         m_pStoreSelection = new CStoreSelection(this);\r
680         m_LogList.SetItemCountEx(0);\r
681         m_LogList.Invalidate();\r
682         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
683         CWnd * pMsgView = GetDlgItem(IDC_MSGVIEW);\r
684         pMsgView->SetWindowText(_T(""));\r
685 \r
686         SetSortArrow(&m_LogList, -1, true);\r
687 \r
688         m_LogList.DeleteAllItems();\r
689         m_arShownList.RemoveAll();\r
690         m_logEntries.ClearAll();\r
691 \r
692         m_logcounter = 0;\r
693         m_bCancelled = FALSE;\r
694         m_tTo = 0;\r
695         m_tFrom = (DWORD)-1;\r
696         m_limit = 0;\r
697 \r
698         InterlockedExchange(&m_bThreadRunning, TRUE);\r
699         if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
700         {\r
701                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
702                 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
703         }\r
704         GetDlgItem(IDC_LOGLIST)->UpdateData(FALSE);\r
705         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
706 #endif\r
707 }\r
708 \r
709 void CLogDlg::OnBnClickedRefresh()\r
710 {\r
711         m_limit = 0;\r
712         Refresh (true);\r
713 }\r
714 \r
715 void CLogDlg::Refresh (bool autoGoOnline)\r
716 {\r
717 #if 0\r
718         // refreshing means re-downloading the already shown log messages\r
719         UpdateData();\r
720         m_maxChild = 0;\r
721         m_childCounter = 0;\r
722 \r
723         if ((m_limit == 0)||(m_bStrict)||(int(m_logEntries.size()-1) > m_limit))\r
724         {\r
725                 if (m_logEntries.size() != 0)\r
726                 {\r
727                         m_endrev = m_logEntries[m_logEntries.size()-1]->Rev;\r
728                 }\r
729         }\r
730         m_startrev = -1;\r
731         m_bCancelled = FALSE;\r
732 \r
733         // We need to create CStoreSelection on the heap or else\r
734         // the variable will run out of the scope before the\r
735         // thread ends. Therefore we let the thread delete\r
736         // the instance.\r
737         m_pStoreSelection = new CStoreSelection(this);\r
738         m_ChangedFileListCtrl.SetItemCountEx(0);\r
739         m_ChangedFileListCtrl.Invalidate();\r
740         m_LogList.SetItemCountEx(0);\r
741         m_LogList.Invalidate();\r
742         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
743         CWnd * pMsgView = GetDlgItem(IDC_MSGVIEW);\r
744         pMsgView->SetWindowText(_T(""));\r
745 \r
746         SetSortArrow(&m_LogList, -1, true);\r
747 \r
748         m_LogList.DeleteAllItems();\r
749         m_arShownList.RemoveAll();\r
750         m_logEntries.ClearAll();\r
751 \r
752     // reset the cached HEAD property & go on-line\r
753 \r
754     if (autoGoOnline)\r
755     {\r
756             SetDlgTitle (false);\r
757         logCachePool.GetRepositoryInfo().ResetHeadRevision (m_sUUID, m_sRepositoryRoot);\r
758     }\r
759 \r
760         InterlockedExchange(&m_bThreadRunning, TRUE);\r
761         if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
762         {\r
763                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
764                 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
765         }\r
766         GetDlgItem(IDC_LOGLIST)->UpdateData(FALSE);\r
767         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
768 #endif\r
769 }\r
770 \r
771 void CLogDlg::OnBnClickedNexthundred()\r
772 {\r
773 #if 0\r
774         UpdateData();\r
775         // we have to fetch the next X log messages.\r
776         if (m_logEntries.size() < 1)\r
777         {\r
778                 // since there weren't any log messages fetched before, just\r
779                 // fetch all since we don't have an 'anchor' to fetch the 'next'\r
780                 // messages from.\r
781                 return GetAll(true);\r
782         }\r
783         git_revnum_t rev = m_logEntries[m_logEntries.size()-1]->Rev;\r
784 \r
785         if (rev < 1)\r
786                 return;         // do nothing! No more revisions to get\r
787 \r
788         m_startrev = rev;\r
789         m_endrev = 0;\r
790         m_bCancelled = FALSE;\r
791 \r
792     // rev is is revision we already have and we will receive it again\r
793     // -> fetch one extra revision to get NumberOfLogs *new* revisions\r
794 \r
795         m_limit = (int)(DWORD)CRegDWORD(_T("Software\\TortoiseGit\\NumberOfLogs"), 100) +1;\r
796         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
797         SetSortArrow(&m_LogList, -1, true);\r
798         InterlockedExchange(&m_bThreadRunning, TRUE);\r
799         // We need to create CStoreSelection on the heap or else\r
800         // the variable will run out of the scope before the\r
801         // thread ends. Therefore we let the thread delete\r
802         // the instance.\r
803         m_pStoreSelection = new CStoreSelection(this);\r
804 \r
805         // since we fetch the log from the last revision we already have,\r
806         // we have to remove that revision entry to avoid getting it twice\r
807         m_logEntries.pop_back();\r
808         if (AfxBeginThread(LogThreadEntry, this)==NULL)\r
809         {\r
810                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
811                 CMessageBox::Show(NULL, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
812         }\r
813         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
814         GetDlgItem(IDC_LOGLIST)->UpdateData(FALSE);\r
815 #endif\r
816 }\r
817 \r
818 BOOL CLogDlg::Cancel()\r
819 {\r
820         return m_bCancelled;\r
821 }\r
822 \r
823 void CLogDlg::SaveSplitterPos()\r
824 {\r
825         if (!IsIconic())\r
826         {\r
827                 CRegDWORD regPos1 = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\LogDlgSizer1"));\r
828                 CRegDWORD regPos2 = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\LogDlgSizer2"));\r
829                 RECT rectSplitter;\r
830                 m_wndSplitter1.GetWindowRect(&rectSplitter);\r
831                 ScreenToClient(&rectSplitter);\r
832                 regPos1 = rectSplitter.top;\r
833                 m_wndSplitter2.GetWindowRect(&rectSplitter);\r
834                 ScreenToClient(&rectSplitter);\r
835                 regPos2 = rectSplitter.top;\r
836         }\r
837 }\r
838 \r
839 void CLogDlg::OnCancel()\r
840 {\r
841         // canceling means stopping the working thread if it's still running.\r
842         // we do this by using the Subversion cancel callback.\r
843         // But canceling can also mean just to close the dialog, depending on the\r
844         // text shown on the cancel button (it could simply read "OK").\r
845         CString temp, temp2;\r
846         GetDlgItemText(IDOK, temp);\r
847         temp2.LoadString(IDS_MSGBOX_CANCEL);\r
848         if ((temp.Compare(temp2)==0)||(m_bThreadRunning))\r
849         {\r
850                 m_bCancelled = true;\r
851                 return;\r
852         }\r
853         UpdateData();\r
854         if (m_bSaveStrict)\r
855                 m_regLastStrict = m_bStrict;\r
856         CRegDWORD reg = CRegDWORD(_T("Software\\TortoiseGit\\ShowAllEntry"));\r
857         reg = m_btnShow.GetCurrentEntry();\r
858         SaveSplitterPos();\r
859         __super::OnCancel();\r
860 }\r
861 \r
862 CString CLogDlg::MakeShortMessage(const CString& message)\r
863 {\r
864         bool bFoundShort = true;\r
865         CString sShortMessage = m_ProjectProperties.GetLogSummary(message);\r
866         if (sShortMessage.IsEmpty())\r
867         {\r
868                 bFoundShort = false;\r
869                 sShortMessage = message;\r
870         }\r
871         // Remove newlines and tabs 'cause those are not shown nicely in the list control\r
872         sShortMessage.Replace(_T("\r"), _T(""));\r
873         sShortMessage.Replace(_T("\t"), _T(" "));\r
874         \r
875         // Suppose the first empty line separates 'summary' from the rest of the message.\r
876         int found = sShortMessage.Find(_T("\n\n"));\r
877         // To avoid too short 'short' messages \r
878         // (e.g. if the message looks something like "Bugfix:\n\n*done this\n*done that")\r
879         // only use the empty newline as a separator if it comes after at least 15 chars.\r
880         if ((!bFoundShort)&&(found >= 15))\r
881         {\r
882                 sShortMessage = sShortMessage.Left(found);\r
883         }\r
884         sShortMessage.Replace('\n', ' ');\r
885         return sShortMessage;\r
886 }\r
887 \r
888 BOOL CLogDlg::Log(git_revnum_t rev, const CString& author, const CString& date, const CString& message, LogChangedPathArray * cpaths,  int filechanges, BOOL copies, DWORD actions, BOOL haschildren)\r
889 {\r
890 #if 0\r
891         if (rev == SVN_INVALID_REVNUM)\r
892         {\r
893                 m_childCounter--;\r
894                 return TRUE;\r
895         }\r
896 \r
897         // this is the callback function which receives the data for every revision we ask the log for\r
898         // we store this information here one by one.\r
899         m_logcounter += 1;\r
900         if (m_startrev == -1)\r
901                 m_startrev = rev;\r
902         if (m_limit != 0)\r
903         {\r
904                 m_limitcounter--;\r
905                 m_LogProgress.SetPos(m_limit - m_limitcounter);\r
906         }\r
907         else if (m_startrev.IsNumber() && m_startrev.IsNumber())\r
908                 m_LogProgress.SetPos((git_revnum_t)m_startrev-rev+(git_revnum_t)m_endrev);\r
909         __time64_t ttime = time/1000000L;\r
910         if (m_tTo < (DWORD)ttime)\r
911                 m_tTo = (DWORD)ttime;\r
912         if (m_tFrom > (DWORD)ttime)\r
913                 m_tFrom = (DWORD)ttime;\r
914         if ((m_lowestRev > rev)||(m_lowestRev < 0))\r
915                 m_lowestRev = rev;\r
916         // Add as many characters from the log message to the list control\r
917         PLOGENTRYDATA pLogItem = new LOGENTRYDATA;\r
918         pLogItem->bCopies = !!copies;\r
919         \r
920         // find out if this item was copied in the revision\r
921         BOOL copiedself = FALSE;\r
922         if (copies)\r
923         {\r
924                 for (INT_PTR cpPathIndex = 0; cpPathIndex < cpaths->GetCount(); ++cpPathIndex)\r
925                 {\r
926                         LogChangedPath * cpath = cpaths->GetAt(cpPathIndex);\r
927                         if (!cpath->sCopyFromPath.IsEmpty() && (cpath->sPath.Compare(m_sSelfRelativeURL) == 0))\r
928                         {\r
929                                 // note: this only works if the log is fetched top-to-bottom\r
930                                 // but since we do that, it shouldn't be a problem\r
931                                 m_sSelfRelativeURL = cpath->sCopyFromPath;\r
932                                 copiedself = TRUE;\r
933                                 break;\r
934                         }\r
935                 }\r
936         }\r
937         pLogItem->bCopiedSelf = copiedself;\r
938         pLogItem->tmDate = ttime;\r
939         pLogItem->sAuthor = author;\r
940         pLogItem->sDate = date;\r
941         pLogItem->sShortMessage = MakeShortMessage(message);\r
942         pLogItem->dwFileChanges = filechanges;\r
943         pLogItem->actions = actions;\r
944         pLogItem->haschildren = haschildren;\r
945         pLogItem->childStackDepth = m_childCounter;\r
946         m_maxChild = max(m_childCounter, m_maxChild);\r
947         if (haschildren)\r
948                 m_childCounter++;\r
949         pLogItem->sBugIDs = m_ProjectProperties.FindBugID(message).Trim();\r
950         \r
951         // split multi line log entries and concatenate them\r
952         // again but this time with \r\n as line separators\r
953         // so that the edit control recognizes them\r
954         try\r
955         {\r
956                 if (message.GetLength()>0)\r
957                 {\r
958                         m_sMessageBuf = message;\r
959                         m_sMessageBuf.Replace(_T("\n\r"), _T("\n"));\r
960                         m_sMessageBuf.Replace(_T("\r\n"), _T("\n"));\r
961                         if (m_sMessageBuf.Right(1).Compare(_T("\n"))==0)\r
962                                 m_sMessageBuf = m_sMessageBuf.Left(m_sMessageBuf.GetLength()-1);\r
963                 }\r
964                 else\r
965                         m_sMessageBuf.Empty();\r
966         pLogItem->sMessage = m_sMessageBuf;\r
967         pLogItem->Rev = rev;\r
968 \r
969         // move-construct path array\r
970 \r
971         pLogItem->pArChangedPaths = new LogChangedPathArray (*cpaths);\r
972         cpaths->RemoveAll();\r
973         }\r
974         catch (CException * e)\r
975         {\r
976                 ::MessageBox(NULL, _T("not enough memory!"), _T("TortoiseGit"), MB_ICONERROR);\r
977                 e->Delete();\r
978                 m_bCancelled = TRUE;\r
979         }\r
980         m_logEntries.push_back(pLogItem);\r
981         m_arShownList.Add(pLogItem);\r
982 #endif\r
983         return TRUE;\r
984 }\r
985 \r
986 //this is the thread function which calls the subversion function\r
987 UINT CLogDlg::LogThreadEntry(LPVOID pVoid)\r
988 {\r
989         return ((CLogDlg*)pVoid)->LogThread();\r
990 }\r
991 \r
992 GitRev g_rev;\r
993 //this is the thread function which calls the subversion function\r
994 UINT CLogDlg::LogThread()\r
995 {\r
996 \r
997         InterlockedExchange(&m_bThreadRunning, TRUE);\r
998 \r
999     //does the user force the cache to refresh (shift or control key down)?\r
1000     bool refresh =    (GetKeyState (VK_CONTROL) < 0) \r
1001                    || (GetKeyState (VK_SHIFT) < 0);\r
1002 \r
1003         //disable the "Get All" button while we're receiving\r
1004         //log messages.\r
1005         DialogEnableWindow(IDC_GETALL, FALSE);\r
1006         DialogEnableWindow(IDC_NEXTHUNDRED, FALSE);\r
1007         DialogEnableWindow(IDC_CHECK_STOPONCOPY, FALSE);\r
1008         DialogEnableWindow(IDC_INCLUDEMERGE, FALSE);\r
1009         DialogEnableWindow(IDC_STATBUTTON, FALSE);\r
1010         DialogEnableWindow(IDC_REFRESH, FALSE);\r
1011         \r
1012         CString temp;\r
1013         temp.LoadString(IDS_PROGRESSWAIT);\r
1014         m_LogList.ShowText(temp, true);\r
1015         // change the text of the close button to "Cancel" since now the thread\r
1016         // is running, and simply closing the dialog doesn't work.\r
1017         if (!GetDlgItem(IDOK)->IsWindowVisible())\r
1018         {\r
1019                 temp.LoadString(IDS_MSGBOX_CANCEL);\r
1020                 SetDlgItemText(IDCANCEL, temp);\r
1021         }\r
1022         // We use a progress bar while getting the logs\r
1023         m_LogProgress.SetRange32(0, 100);\r
1024         m_LogProgress.SetPos(0);\r
1025         GetDlgItem(IDC_PROGRESS)->ShowWindow(TRUE);\r
1026 //      git_revnum_t r = -1;\r
1027         \r
1028         // get the repository root url, because the changed-files-list has the\r
1029         // paths shown there relative to the repository root.\r
1030 //      CTGitPath rootpath;\r
1031 //  BOOL succeeded = GetRootAndHead(m_path, rootpath, r);\r
1032 \r
1033 //    m_sRepositoryRoot = rootpath.GetGitPathString();\r
1034 //    m_sURL = m_path.GetGitPathString();\r
1035 \r
1036     // we need the UUID to unambigously identify the log cache\r
1037 //    if (logCachePool.IsEnabled())\r
1038 //        m_sUUID = logCachePool.GetRepositoryInfo().GetRepositoryUUID (rootpath);\r
1039 \r
1040     // if the log dialog is started from a working copy, we need to turn that\r
1041     // local path into an url here\r
1042 //    if (succeeded)\r
1043 //    {\r
1044 //        if (!m_path.IsUrl())\r
1045 //        {\r
1046 //              m_sURL = GetURLFromPath(m_path);\r
1047 \r
1048                 // The URL is escaped because Git::logReceiver\r
1049                 // returns the path in a native format\r
1050 //              m_sURL = CPathUtils::PathUnescape(m_sURL);\r
1051   //      }\r
1052 //        m_sRelativeRoot = m_sURL.Mid(CPathUtils::PathUnescape(m_sRepositoryRoot).GetLength());\r
1053 //              m_sSelfRelativeURL = m_sRelativeRoot;\r
1054   //  }\r
1055 #if 0\r
1056     if (succeeded && !m_mergePath.IsEmpty() && m_mergedRevs.empty())\r
1057     {\r
1058             // in case we got a merge path set, retrieve the merge info\r
1059             // of that path and check whether one of the merge URLs\r
1060             // match the URL we show the log for.\r
1061             GitPool localpool(pool);\r
1062             git_error_clear(Err);\r
1063             apr_hash_t * mergeinfo = NULL;\r
1064             if (git_client_mergeinfo_get_merged (&mergeinfo, m_mergePath.GetGitApiPath(localpool), GitRev(GitRev::REV_WC), m_pctx, localpool) == NULL)\r
1065             {\r
1066                     // now check the relative paths\r
1067                     apr_hash_index_t *hi;\r
1068                     const void *key;\r
1069                     void *val;\r
1070 \r
1071                     if (mergeinfo)\r
1072                     {\r
1073                             for (hi = apr_hash_first(localpool, mergeinfo); hi; hi = apr_hash_next(hi))\r
1074                             {\r
1075                                     apr_hash_this(hi, &key, NULL, &val);\r
1076                                     if (m_sURL.Compare(CUnicodeUtils::GetUnicode((char*)key)) == 0)\r
1077                                     {\r
1078                                             apr_array_header_t * arr = (apr_array_header_t*)val;\r
1079                                             if (val)\r
1080                                             {\r
1081                                                     for (long i=0; i<arr->nelts; ++i)\r
1082                                                     {\r
1083                                                             git_merge_range_t * pRange = APR_ARRAY_IDX(arr, i, git_merge_range_t*);\r
1084                                                             if (pRange)\r
1085                                                             {\r
1086                                                                     for (git_revnum_t r=pRange->start+1; r<=pRange->end; ++r)\r
1087                                                                     {\r
1088                                                                             m_mergedRevs.insert(r);\r
1089                                                                     }\r
1090                                                             }\r
1091                                                     }\r
1092                                             }\r
1093                                             break;\r
1094                                     }\r
1095                             }\r
1096                     }\r
1097             }\r
1098     }\r
1099 \r
1100     m_LogProgress.SetPos(1);\r
1101     if (m_startrev == GitRev::REV_HEAD)\r
1102     {\r
1103             m_startrev = r;\r
1104     }\r
1105     if (m_endrev == GitRev::REV_HEAD)\r
1106     {\r
1107             m_endrev = r;\r
1108     }\r
1109 \r
1110     if (m_limit != 0)\r
1111     {\r
1112             m_limitcounter = m_limit;\r
1113             m_LogProgress.SetRange32(0, m_limit);\r
1114     }\r
1115     else\r
1116             m_LogProgress.SetRange32(m_endrev, m_startrev);\r
1117         \r
1118     if (!m_pegrev.IsValid())\r
1119             m_pegrev = m_startrev;\r
1120     size_t startcount = m_logEntries.size();\r
1121     m_lowestRev = -1;\r
1122     m_bStrictStopped = false;\r
1123 \r
1124     if (succeeded)\r
1125     {\r
1126         succeeded = ReceiveLog (CTGitPathList(m_path), m_pegrev, m_startrev, m_endrev, m_limit, m_bStrict, m_bIncludeMerges, refresh);\r
1127         if ((!succeeded)&&(!m_path.IsUrl()))\r
1128         {\r
1129                 // try again with REV_WC as the start revision, just in case the path doesn't\r
1130                 // exist anymore in HEAD\r
1131                 succeeded = ReceiveLog(CTGitPathList(m_path), GitRev(), GitRev::REV_WC, m_endrev, m_limit, m_bStrict, m_bIncludeMerges, refresh);\r
1132         }\r
1133     }\r
1134         m_LogList.ClearText();\r
1135     if (!succeeded)\r
1136         {\r
1137                 m_LogList.ShowText(GetLastErrorMessage(), true);\r
1138         }\r
1139         else\r
1140         {\r
1141                 if (!m_wcRev.IsValid())\r
1142                 {\r
1143                         // fetch the revision the wc path is on so we can mark it\r
1144                         CTGitPath revWCPath = m_ProjectProperties.GetPropsPath();\r
1145                         if (!m_path.IsUrl())\r
1146                                 revWCPath = m_path;\r
1147                         if (DWORD(CRegDWORD(_T("Software\\TortoiseGit\\RecursiveLogRev"), FALSE)))\r
1148                         {\r
1149                                 git_revnum_t minrev, maxrev;\r
1150                                 bool switched, modified, sparse;\r
1151                                 GetWCRevisionStatus(revWCPath, true, minrev, maxrev, switched, modified, sparse);\r
1152                                 if (maxrev)\r
1153                                         m_wcRev = maxrev;\r
1154                         }\r
1155                         else\r
1156                         {\r
1157                                 CTGitPath dummypath;\r
1158                                 GitStatus status;\r
1159                                 git_wc_status2_t * stat = status.GetFirstFileStatus(revWCPath, dummypath, false, git_depth_empty);\r
1160                                 if (stat && stat->entry && stat->entry->cmt_rev)\r
1161                                         m_wcRev = stat->entry->cmt_rev;\r
1162                                 if (stat && stat->entry && (stat->entry->kind == git_node_dir))\r
1163                                         m_wcRev = stat->entry->revision;\r
1164                         }\r
1165                 }\r
1166         }\r
1167     if (m_bStrict && (m_lowestRev>1) && ((m_limit>0) ? ((startcount + m_limit)>m_logEntries.size()) : (m_endrev<m_lowestRev)))\r
1168                 m_bStrictStopped = true;\r
1169         m_LogList.SetItemCountEx(ShownCountWithStopped());\r
1170 \r
1171         m_timFrom = (__time64_t(m_tFrom));\r
1172         m_timTo = (__time64_t(m_tTo));\r
1173         m_DateFrom.SetRange(&m_timFrom, &m_timTo);\r
1174         m_DateTo.SetRange(&m_timFrom, &m_timTo);\r
1175         m_DateFrom.SetTime(&m_timFrom);\r
1176         m_DateTo.SetTime(&m_timTo);\r
1177 #endif\r
1178         DialogEnableWindow(IDC_GETALL, TRUE);\r
1179         m_LogList.ClearText();\r
1180 \r
1181         this->m_logEntries.ClearAll();\r
1182         this->m_logEntries.ParserFromLog();\r
1183         m_LogList.SetItemCountEx(this->m_logEntries.size());\r
1184 \r
1185         this->m_arShownList.RemoveAll();\r
1186 \r
1187         for(int i=0;i<m_logEntries.size();i++)\r
1188                 this->m_arShownList.Add(&m_logEntries[i]);\r
1189         \r
1190 #if 0   \r
1191         if (!m_bShowedAll)\r
1192                 DialogEnableWindow(IDC_NEXTHUNDRED, TRUE);\r
1193 #endif\r
1194         DialogEnableWindow(IDC_CHECK_STOPONCOPY, TRUE);\r
1195         DialogEnableWindow(IDC_INCLUDEMERGE, TRUE);\r
1196         DialogEnableWindow(IDC_STATBUTTON, TRUE);\r
1197         DialogEnableWindow(IDC_REFRESH, TRUE);\r
1198 \r
1199 #if 0\r
1200         LogCache::CRepositoryInfo& cachedProperties = logCachePool.GetRepositoryInfo();\r
1201         SetDlgTitle(cachedProperties.IsOffline (m_sUUID, m_sRepositoryRoot, false));\r
1202 \r
1203         GetDlgItem(IDC_PROGRESS)->ShowWindow(FALSE);\r
1204         m_bCancelled = true;\r
1205 #endif\r
1206         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1207         m_LogList.RedrawItems(0, m_arShownList.GetCount());\r
1208         m_LogList.SetRedraw(false);\r
1209         ResizeAllListCtrlCols();\r
1210         m_LogList.SetRedraw(true);\r
1211         if ( m_pStoreSelection )\r
1212         {\r
1213                 // Deleting the instance will restore the\r
1214                 // selection of the CLogDlg.\r
1215                 delete m_pStoreSelection;\r
1216                 m_pStoreSelection = NULL;\r
1217         }\r
1218         else\r
1219         {\r
1220                 // If no selection has been set then this must be the first time\r
1221                 // the revisions are shown. Let's preselect the topmost revision.\r
1222                 if ( m_LogList.GetItemCount()>0 )\r
1223                 {\r
1224                         m_LogList.SetSelectionMark(0);\r
1225                         m_LogList.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED);\r
1226                 }\r
1227         }\r
1228 \r
1229         if (!GetDlgItem(IDOK)->IsWindowVisible())\r
1230         {\r
1231                 temp.LoadString(IDS_MSGBOX_OK);\r
1232                 SetDlgItemText(IDCANCEL, temp);\r
1233         }\r
1234 \r
1235         RefreshCursor();\r
1236         // make sure the filter is applied (if any) now, after we refreshed/fetched\r
1237         // the log messages\r
1238         PostMessage(WM_TIMER, LOGFILTER_TIMER);\r
1239 \r
1240         return 0;\r
1241 }\r
1242 \r
1243 \r
1244 \r
1245 void CLogDlg::CopyChangedSelectionToClipBoard()\r
1246 {\r
1247 #if 0\r
1248         POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
1249         if (pos == NULL)\r
1250                 return; // nothing is selected, get out of here\r
1251 \r
1252         CString sPaths;\r
1253 \r
1254         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
1255         if (pos)\r
1256         {\r
1257                 POSITION pos = m_ChangedFileListCtrl.GetFirstSelectedItemPosition();\r
1258                 while (pos)\r
1259                 {\r
1260                         int nItem = m_ChangedFileListCtrl.GetNextSelectedItem(pos);\r
1261                         sPaths += m_currentChangedPathList[nItem].GetGitPathString();\r
1262                         sPaths += _T("\r\n");\r
1263                 }\r
1264         }\r
1265         else\r
1266         {\r
1267                 // only one revision is selected in the log dialog top pane\r
1268                 // but multiple items could be selected  in the changed items list\r
1269                 POSITION pos = m_ChangedFileListCtrl.GetFirstSelectedItemPosition();\r
1270                 while (pos)\r
1271                 {\r
1272                         int nItem = m_ChangedFileListCtrl.GetNextSelectedItem(pos);\r
1273                         LogChangedPath * changedlogpath = pLogEntry->pArChangedPaths->GetAt(nItem);\r
1274 \r
1275                         if ((m_cHidePaths.GetState() & 0x0003)==BST_CHECKED)\r
1276                         {\r
1277                                 // some items are hidden! So find out which item the user really selected\r
1278                                 INT_PTR selRealIndex = -1;\r
1279                                 for (INT_PTR hiddenindex=0; hiddenindex<pLogEntry->pArChangedPaths->GetCount(); ++hiddenindex)\r
1280                                 {\r
1281                                         if (pLogEntry->pArChangedPaths->GetAt(hiddenindex)->sPath.Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)==0)\r
1282                                                 selRealIndex++;\r
1283                                         if (selRealIndex == nItem)\r
1284                                         {\r
1285                                                 changedlogpath = pLogEntry->pArChangedPaths->GetAt(hiddenindex);\r
1286                                                 break;\r
1287                                         }\r
1288                                 }\r
1289                         }\r
1290                         if (changedlogpath)\r
1291                         {\r
1292                                 sPaths += changedlogpath->sPath;\r
1293                                 sPaths += _T("\r\n");\r
1294                         }\r
1295                 }\r
1296         }\r
1297         sPaths.Trim();\r
1298         CStringUtils::WriteAsciiStringToClipboard(sPaths, GetSafeHwnd());\r
1299 #endif\r
1300 }\r
1301 \r
1302 BOOL CLogDlg::IsDiffPossible(LogChangedPath * changedpath, git_revnum_t rev)\r
1303 {\r
1304 #if 0\r
1305         CString added, deleted;\r
1306         if (changedpath == NULL)\r
1307                 return false;\r
1308 \r
1309         if ((rev > 1)&&(changedpath->action != LOGACTIONS_DELETED))\r
1310         {\r
1311                 if (changedpath->action == LOGACTIONS_ADDED) // file is added\r
1312                 {\r
1313                         if (changedpath->lCopyFromRev == 0)\r
1314                                 return FALSE; // but file was not added with history\r
1315                 }\r
1316                 return TRUE;\r
1317         }\r
1318 #endif\r
1319         return FALSE;\r
1320 }\r
1321 \r
1322 void CLogDlg::OnContextMenu(CWnd* pWnd, CPoint point)\r
1323 {\r
1324         // we have two separate context menus:\r
1325         // one shown on the log message list control,\r
1326         // the other shown in the changed-files list control\r
1327         int selCount = m_LogList.GetSelectedCount();\r
1328         if (pWnd == &m_LogList)\r
1329         {\r
1330                 ShowContextMenuForRevisions(pWnd, point);\r
1331         }\r
1332         else if (pWnd == &m_ChangedFileListCtrl)\r
1333         {\r
1334                 ShowContextMenuForChangedpaths(pWnd, point);\r
1335         }\r
1336         else if ((selCount == 1)&&(pWnd == GetDlgItem(IDC_MSGVIEW)))\r
1337         {\r
1338                 POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
1339                 int selIndex = -1;\r
1340                 if (pos)\r
1341                         selIndex = m_LogList.GetNextSelectedItem(pos);\r
1342                 if ((point.x == -1) && (point.y == -1))\r
1343                 {\r
1344                         CRect rect;\r
1345                         GetDlgItem(IDC_MSGVIEW)->GetClientRect(&rect);\r
1346                         ClientToScreen(&rect);\r
1347                         point = rect.CenterPoint();\r
1348                 }\r
1349                 CString sMenuItemText;\r
1350                 CMenu popup;\r
1351                 if (popup.CreatePopupMenu())\r
1352                 {\r
1353                         // add the 'default' entries\r
1354                         sMenuItemText.LoadString(IDS_SCIEDIT_COPY);\r
1355                         popup.AppendMenu(MF_STRING | MF_ENABLED, WM_COPY, sMenuItemText);\r
1356                         sMenuItemText.LoadString(IDS_SCIEDIT_SELECTALL);\r
1357                         popup.AppendMenu(MF_STRING | MF_ENABLED, EM_SETSEL, sMenuItemText);\r
1358 \r
1359                         if (selIndex >= 0)\r
1360                         {\r
1361                                 popup.AppendMenu(MF_SEPARATOR);\r
1362                                 sMenuItemText.LoadString(IDS_LOG_POPUP_EDITLOG);\r
1363                                 popup.AppendMenu(MF_STRING | MF_ENABLED, ID_EDITAUTHOR, sMenuItemText);\r
1364                         }\r
1365 \r
1366                         int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
1367                         switch (cmd)\r
1368                         {\r
1369                         case 0:\r
1370                                 break;  // no command selected\r
1371                         case EM_SETSEL:\r
1372                         case WM_COPY:\r
1373                                 ::SendMessage(GetDlgItem(IDC_MSGVIEW)->GetSafeHwnd(), cmd, 0, -1);\r
1374                                 break;\r
1375                         case ID_EDITAUTHOR:\r
1376                                 EditLogMessage(selIndex);\r
1377                                 break;\r
1378                         }\r
1379                 }\r
1380         }\r
1381 }\r
1382 \r
1383 \r
1384 LRESULT CLogDlg::OnFindDialogMessage(WPARAM /*wParam*/, LPARAM /*lParam*/)\r
1385 {\r
1386 #if 0\r
1387     ASSERT(m_pFindDialog != NULL);\r
1388 \r
1389     if (m_pFindDialog->IsTerminating())\r
1390     {\r
1391             // invalidate the handle identifying the dialog box.\r
1392         m_pFindDialog = NULL;\r
1393         return 0;\r
1394     }\r
1395 \r
1396     if(m_pFindDialog->FindNext())\r
1397     {\r
1398         //read data from dialog\r
1399         CString FindText = m_pFindDialog->GetFindString();\r
1400         bool bMatchCase = (m_pFindDialog->MatchCase() == TRUE);\r
1401                 bool bFound = false;\r
1402                 tr1::wregex pat;\r
1403                 bool bRegex = ValidateRegexp(FindText, pat, bMatchCase);\r
1404 \r
1405                 tr1::regex_constants::match_flag_type flags = tr1::regex_constants::match_not_null;\r
1406 \r
1407                 int i;\r
1408                 for (i = this->m_nSearchIndex; i<m_arShownList.GetCount()&&!bFound; i++)\r
1409                 {\r
1410                         if (bRegex)\r
1411                         {\r
1412                                 PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(i));\r
1413 \r
1414                                 if (regex_search(wstring((LPCTSTR)pLogEntry->sMessage), pat, flags))\r
1415                                 {\r
1416                                         bFound = true;\r
1417                                         break;\r
1418                                 }\r
1419                                 LogChangedPathArray * cpatharray = pLogEntry->pArChangedPaths;\r
1420                                 for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount(); ++cpPathIndex)\r
1421                                 {\r
1422                                         LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
1423                                         if (regex_search(wstring((LPCTSTR)cpath->sCopyFromPath), pat, flags))\r
1424                                         {\r
1425                                                 bFound = true;\r
1426                                                 --i;\r
1427                                                 break;\r
1428                                         }\r
1429                                         if (regex_search(wstring((LPCTSTR)cpath->sPath), pat, flags))\r
1430                                         {\r
1431                                                 bFound = true;\r
1432                                                 --i;\r
1433                                                 break;\r
1434                                         }\r
1435                                 }\r
1436                         }\r
1437                         else\r
1438                         {\r
1439                                 if (bMatchCase)\r
1440                                 {\r
1441                                         if (m_logEntries[i]->sMessage.Find(FindText) >= 0)\r
1442                                         {\r
1443                                                 bFound = true;\r
1444                                                 break;\r
1445                                         }\r
1446                                         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(i));\r
1447                                         LogChangedPathArray * cpatharray = pLogEntry->pArChangedPaths;\r
1448                                         for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount(); ++cpPathIndex)\r
1449                                         {\r
1450                                                 LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
1451                                                 if (cpath->sCopyFromPath.Find(FindText)>=0)\r
1452                                                 {\r
1453                                                         bFound = true;\r
1454                                                         --i;\r
1455                                                         break;\r
1456                                                 }\r
1457                                                 if (cpath->sPath.Find(FindText)>=0)\r
1458                                                 {\r
1459                                                         bFound = true;\r
1460                                                         --i;\r
1461                                                         break;\r
1462                                                 }\r
1463                                         }\r
1464                                 }\r
1465                                 else\r
1466                                 {\r
1467                                     PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(i));\r
1468                                         CString msg = pLogEntry->sMessage;\r
1469                                         msg = msg.MakeLower();\r
1470                                         CString find = FindText.MakeLower();\r
1471                                         if (msg.Find(find) >= 0)\r
1472                                         {\r
1473                                                 bFound = TRUE;\r
1474                                                 break;\r
1475                                         }\r
1476                                         LogChangedPathArray * cpatharray = pLogEntry->pArChangedPaths;\r
1477                                         for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount(); ++cpPathIndex)\r
1478                                         {\r
1479                                                 LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
1480                                                 CString lowerpath = cpath->sCopyFromPath;\r
1481                                                 lowerpath.MakeLower();\r
1482                                                 if (lowerpath.Find(find)>=0)\r
1483                                                 {\r
1484                                                         bFound = TRUE;\r
1485                                                         --i;\r
1486                                                         break;\r
1487                                                 }\r
1488                                                 lowerpath = cpath->sPath;\r
1489                                                 lowerpath.MakeLower();\r
1490                                                 if (lowerpath.Find(find)>=0)\r
1491                                                 {\r
1492                                                         bFound = TRUE;\r
1493                                                         --i;\r
1494                                                         break;\r
1495                                                 }\r
1496                                         }\r
1497                                 } \r
1498                         }\r
1499                 } // for (i = this->m_nSearchIndex; i<m_arShownList.GetItemCount()&&!bFound; i++)\r
1500                 if (bFound)\r
1501                 {\r
1502                         this->m_nSearchIndex = (i+1);\r
1503                         m_LogList.EnsureVisible(i, FALSE);\r
1504                         m_LogList.SetItemState(m_LogList.GetSelectionMark(), 0, LVIS_SELECTED);\r
1505                         m_LogList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);\r
1506                         m_LogList.SetSelectionMark(i);\r
1507                         FillLogMessageCtrl();\r
1508                         UpdateData(FALSE);\r
1509                         m_nSearchIndex++;\r
1510                         if (m_nSearchIndex >= m_arShownList.GetCount())\r
1511                                 m_nSearchIndex = (int)m_arShownList.GetCount()-1;\r
1512                 }\r
1513     } // if(m_pFindDialog->FindNext()) \r
1514         UpdateLogInfoLabel();\r
1515 #endif\r
1516     return 0;\r
1517 }\r
1518 \r
1519 void CLogDlg::OnOK()\r
1520 {\r
1521 #if 0 \r
1522         // since the log dialog is also used to select revisions for other\r
1523         // dialogs, we have to do some work before closing this dialog\r
1524         if (GetFocus() != GetDlgItem(IDOK))\r
1525                 return; // if the "OK" button doesn't have the focus, do nothing: this prevents closing the dialog when pressing enter\r
1526         if (!GetDlgItem(IDOK)->IsWindowVisible() && GetFocus() != GetDlgItem(IDCANCEL))\r
1527                 return; // the Cancel button works as the OK button. But if the cancel button has not the focus, do nothing.\r
1528 \r
1529         CString temp;\r
1530         CString buttontext;\r
1531         GetDlgItemText(IDOK, buttontext);\r
1532         temp.LoadString(IDS_MSGBOX_CANCEL);\r
1533         if (temp.Compare(buttontext) != 0)\r
1534                 __super::OnOK();        // only exit if the button text matches, and that will match only if the thread isn't running anymore\r
1535         m_bCancelled = TRUE;\r
1536         m_selectedRevs.Clear();\r
1537         m_selectedRevsOneRange.Clear();\r
1538         if (m_pNotifyWindow)\r
1539         {\r
1540                 int selIndex = m_LogList.GetSelectionMark();\r
1541                 if (selIndex >= 0)\r
1542                 {       \r
1543                     PLOGENTRYDATA pLogEntry = NULL;\r
1544                         POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
1545                         pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
1546                         m_selectedRevs.AddRevision(pLogEntry->Rev);\r
1547                         git_revnum_t lowerRev = pLogEntry->Rev;\r
1548                         git_revnum_t higherRev = lowerRev;\r
1549                         while (pos)\r
1550                         {\r
1551                             pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
1552                                 git_revnum_t rev = pLogEntry->Rev;\r
1553                                 m_selectedRevs.AddRevision(pLogEntry->Rev);\r
1554                                 if (lowerRev > rev)\r
1555                                         lowerRev = rev;\r
1556                                 if (higherRev < rev)\r
1557                                         higherRev = rev;\r
1558                         }\r
1559                         if (m_sFilterText.IsEmpty() && m_nSortColumn == 0 && IsSelectionContinuous())\r
1560                         {\r
1561                                 m_selectedRevsOneRange.AddRevRange(lowerRev, higherRev);\r
1562                         }\r
1563                         BOOL bSentMessage = FALSE;\r
1564                         if (m_LogList.GetSelectedCount() == 1)\r
1565                         {\r
1566                                 // if only one revision is selected, check if the path/url with which the dialog was started\r
1567                                 // was directly affected in that revision. If it was, then check if our path was copied from somewhere.\r
1568                                 // if it was copied, use the copy from revision as lowerRev\r
1569                                 if ((pLogEntry)&&(pLogEntry->pArChangedPaths)&&(lowerRev == higherRev))\r
1570                                 {\r
1571                                         CString sUrl = m_path.GetGitPathString();\r
1572                                         if (!m_path.IsUrl())\r
1573                                         {\r
1574                                                 sUrl = GetURLFromPath(m_path);\r
1575                                         }\r
1576                                         sUrl = sUrl.Mid(m_sRepositoryRoot.GetLength());\r
1577                                         for (int cp = 0; cp < pLogEntry->pArChangedPaths->GetCount(); ++cp)\r
1578                                         {\r
1579                                                 LogChangedPath * pData = pLogEntry->pArChangedPaths->GetAt(cp);\r
1580                                                 if (pData)\r
1581                                                 {\r
1582                                                         if (sUrl.Compare(pData->sPath) == 0)\r
1583                                                         {\r
1584                                                                 if (!pData->sCopyFromPath.IsEmpty())\r
1585                                                                 {\r
1586                                                                         lowerRev = pData->lCopyFromRev;\r
1587                                                                         m_pNotifyWindow->SendMessage(WM_REVSELECTED, m_wParam & (MERGE_REVSELECTSTART), lowerRev);\r
1588                                                                         m_pNotifyWindow->SendMessage(WM_REVSELECTED, m_wParam & (MERGE_REVSELECTEND), higherRev);\r
1589                                                                         m_pNotifyWindow->SendMessage(WM_REVLIST, m_selectedRevs.GetCount(), (LPARAM)&m_selectedRevs);\r
1590                                                                         bSentMessage = TRUE;\r
1591                                                                 }\r
1592                                                         }\r
1593                                                 }\r
1594                                         }\r
1595                                 }\r
1596                         }\r
1597                         if ( !bSentMessage )\r
1598                         {\r
1599                                 m_pNotifyWindow->SendMessage(WM_REVSELECTED, m_wParam & (MERGE_REVSELECTSTART | MERGE_REVSELECTMINUSONE), lowerRev);\r
1600                                 m_pNotifyWindow->SendMessage(WM_REVSELECTED, m_wParam & (MERGE_REVSELECTEND | MERGE_REVSELECTMINUSONE), higherRev);\r
1601                                 m_pNotifyWindow->SendMessage(WM_REVLIST, m_selectedRevs.GetCount(), (LPARAM)&m_selectedRevs);\r
1602                                 if (m_selectedRevsOneRange.GetCount())\r
1603                                         m_pNotifyWindow->SendMessage(WM_REVLISTONERANGE, 0, (LPARAM)&m_selectedRevsOneRange);\r
1604                         }\r
1605                 }\r
1606         }\r
1607         UpdateData();\r
1608         if (m_bSaveStrict)\r
1609                 m_regLastStrict = m_bStrict;\r
1610         CRegDWORD reg = CRegDWORD(_T("Software\\TortoiseGit\\ShowAllEntry"));\r
1611         reg = m_btnShow.GetCurrentEntry();\r
1612         SaveSplitterPos();\r
1613 #endif \r
1614 }\r
1615 \r
1616 void CLogDlg::OnNMDblclkChangedFileList(NMHDR * /*pNMHDR*/, LRESULT *pResult)\r
1617 {\r
1618         // a double click on an entry in the changed-files list has happened\r
1619         *pResult = 0;\r
1620 \r
1621         DiffSelectedFile();\r
1622 }\r
1623 \r
1624 void CLogDlg::DiffSelectedFile()\r
1625 {\r
1626 #if 0\r
1627         if (m_bThreadRunning)\r
1628                 return;\r
1629         UpdateLogInfoLabel();\r
1630         INT_PTR selIndex = m_ChangedFileListCtrl.GetSelectionMark();\r
1631         if (selIndex < 0)\r
1632                 return;\r
1633         if (m_ChangedFileListCtrl.GetSelectedCount() == 0)\r
1634                 return;\r
1635         // find out if there's an entry selected in the log list\r
1636         POSITION pos = m_LogList.GetFirstSelectedItemPosition();\r
1637         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
1638         git_revnum_t rev1 = pLogEntry->Rev;\r
1639         git_revnum_t rev2 = rev1;\r
1640         if (pos)\r
1641         {\r
1642                 while (pos)\r
1643                 {\r
1644                         // there's at least a second entry selected in the log list: several revisions selected!\r
1645                         pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(m_LogList.GetNextSelectedItem(pos)));\r
1646                         if (pLogEntry)\r
1647                         {\r
1648                                 rev1 = max(rev1,(long)pLogEntry->Rev);\r
1649                                 rev2 = min(rev2,(long)pLogEntry->Rev);\r
1650                         }\r
1651                 }\r
1652                 rev2--;\r
1653                 // now we have both revisions selected in the log list, so we can do a diff of the selected\r
1654                 // entry in the changed files list with these two revisions.\r
1655                 DoDiffFromLog(selIndex, rev1, rev2, false, false);\r
1656         }\r
1657         else\r
1658         {\r
1659                 rev2 = rev1-1;\r
1660                 // nothing or only one revision selected in the log list\r
1661                 LogChangedPath * changedpath = pLogEntry->pArChangedPaths->GetAt(selIndex);\r
1662 \r
1663                 if ((m_cHidePaths.GetState() & 0x0003)==BST_CHECKED)\r
1664                 {\r
1665                         // some items are hidden! So find out which item the user really clicked on\r
1666                         INT_PTR selRealIndex = -1;\r
1667                         for (INT_PTR hiddenindex=0; hiddenindex<pLogEntry->pArChangedPaths->GetCount(); ++hiddenindex)\r
1668                         {\r
1669                                 if (pLogEntry->pArChangedPaths->GetAt(hiddenindex)->sPath.Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)==0)\r
1670                                         selRealIndex++;\r
1671                                 if (selRealIndex == selIndex)\r
1672                                 {\r
1673                                         selIndex = hiddenindex;\r
1674                                         changedpath = pLogEntry->pArChangedPaths->GetAt(selIndex);\r
1675                                         break;\r
1676                                 }\r
1677                         }\r
1678                 }\r
1679 \r
1680                 if (IsDiffPossible(changedpath, rev1))\r
1681                 {\r
1682                         // diffs with renamed files are possible\r
1683                         if ((changedpath)&&(!changedpath->sCopyFromPath.IsEmpty()))\r
1684                                 rev2 = changedpath->lCopyFromRev;\r
1685                         else\r
1686                         {\r
1687                                 // if the path was modified but the parent path was 'added with history'\r
1688                                 // then we have to use the copy from revision of the parent path\r
1689                                 CTGitPath cpath = CTGitPath(changedpath->sPath);\r
1690                                 for (int flist = 0; flist < pLogEntry->pArChangedPaths->GetCount(); ++flist)\r
1691                                 {\r
1692                                         CTGitPath p = CTGitPath(pLogEntry->pArChangedPaths->GetAt(flist)->sPath);\r
1693                                         if (p.IsAncestorOf(cpath))\r
1694                                         {\r
1695                                                 if (!pLogEntry->pArChangedPaths->GetAt(flist)->sCopyFromPath.IsEmpty())\r
1696                                                         rev2 = pLogEntry->pArChangedPaths->GetAt(flist)->lCopyFromRev;\r
1697                                         }\r
1698                                 }\r
1699                         }\r
1700                         DoDiffFromLog(selIndex, rev1, rev2, false, false);\r
1701                 }\r
1702                 else \r
1703                 {\r
1704                         CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, CTGitPath(changedpath->sPath));\r
1705                         CTGitPath tempfile2 = CTempFiles::Instance().GetTempFilePath(false, CTGitPath(changedpath->sPath));\r
1706                         GitRev r = rev1;\r
1707                         // deleted files must be opened from the revision before the deletion\r
1708                         if (changedpath->action == LOGACTIONS_DELETED)\r
1709                                 r = rev1-1;\r
1710                         m_bCancelled = false;\r
1711 \r
1712                         CProgressDlg progDlg;\r
1713                         progDlg.SetTitle(IDS_APPNAME);\r
1714                         progDlg.SetAnimation(IDR_DOWNLOAD);\r
1715                         CString sInfoLine;\r
1716                         sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, (LPCTSTR)(m_sRepositoryRoot + changedpath->sPath), (LPCTSTR)r.ToString());\r
1717                         progDlg.SetLine(1, sInfoLine, true);\r
1718                         SetAndClearProgressInfo(&progDlg);\r
1719                         progDlg.ShowModeless(m_hWnd);\r
1720 \r
1721                         if (!Cat(CTGitPath(m_sRepositoryRoot + changedpath->sPath), r, r, tempfile))\r
1722                         {\r
1723                                 m_bCancelled = false;\r
1724                                 if (!Cat(CTGitPath(m_sRepositoryRoot + changedpath->sPath), GitRev::REV_HEAD, r, tempfile))\r
1725                                 {\r
1726                                         progDlg.Stop();\r
1727                                         SetAndClearProgressInfo((HWND)NULL);\r
1728                                         CMessageBox::Show(m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
1729                                         return;\r
1730                                 }\r
1731                         }\r
1732                         progDlg.Stop();\r
1733                         SetAndClearProgressInfo((HWND)NULL);\r
1734 \r
1735                         CString sName1, sName2;\r
1736                         sName1.Format(_T("%s - Revision %ld"), (LPCTSTR)CPathUtils::GetFileNameFromPath(changedpath->sPath), (git_revnum_t)rev1);\r
1737                         sName2.Format(_T("%s - Revision %ld"), (LPCTSTR)CPathUtils::GetFileNameFromPath(changedpath->sPath), (git_revnum_t)rev1-1);\r
1738                         CAppUtils::DiffFlags flags;\r
1739                         flags.AlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
1740                         if (changedpath->action == LOGACTIONS_DELETED)\r
1741                                 CAppUtils::StartExtDiff(tempfile, tempfile2, sName2, sName1, flags);\r
1742                         else\r
1743                                 CAppUtils::StartExtDiff(tempfile2, tempfile, sName2, sName1, flags);\r
1744                 }\r
1745         }\r
1746 #endif \r
1747 }\r
1748 \r
1749 \r
1750 void CLogDlg::DoDiffFromLog(INT_PTR selIndex, GitRev* rev1, GitRev* rev2, bool blame, bool unified)\r
1751 {\r
1752         DialogEnableWindow(IDOK, FALSE);\r
1753 //      SetPromptApp(&theApp);\r
1754         theApp.DoWaitCursor(1);\r
1755 \r
1756         CString temppath;\r
1757         GetTempPath(temppath);\r
1758         \r
1759         CString file1;\r
1760         file1.Format(_T("%s%s_%s%s"),\r
1761                                 temppath,                                               \r
1762                                 (*m_currentChangedArray)[selIndex].GetBaseFilename(),\r
1763                                 rev1->m_CommitHash.Left(6),\r
1764                                 (*m_currentChangedArray)[selIndex].GetFileExtension());\r
1765 \r
1766         CString file2;\r
1767         file2.Format(_T("%s\\%s_%s%s"),\r
1768                                 temppath,                                               \r
1769                                 (*m_currentChangedArray)[selIndex].GetBaseFilename(),\r
1770                                 rev2->m_CommitHash.Left(6),\r
1771                                 (*m_currentChangedArray)[selIndex].GetFileExtension());\r
1772 \r
1773         CString cmd;\r
1774 \r
1775         cmd.Format(_T("git.cmd cat-file -p %s:%s"),rev1->m_CommitHash,(*m_currentChangedArray)[selIndex].GetGitPathString());\r
1776         g_Git.RunLogFile(cmd,file1);\r
1777         cmd.Format(_T("git.cmd cat-file -p %s:%s"),rev2->m_CommitHash,(*m_currentChangedArray)[selIndex].GetGitPathString());\r
1778         g_Git.RunLogFile(cmd,file2);\r
1779 \r
1780         CAppUtils::DiffFlags flags;\r
1781         CAppUtils::StartExtDiff(file1,file2,_T("A"),_T("B"),flags);\r
1782 \r
1783 #if 0\r
1784         //get the filename\r
1785         CString filepath;\r
1786         if (Git::PathIsURL(m_path))\r
1787         {\r
1788                 filepath = m_path.GetGitPathString();\r
1789         }\r
1790         else\r
1791         {\r
1792                 filepath = GetURLFromPath(m_path);\r
1793                 if (filepath.IsEmpty())\r
1794                 {\r
1795                         theApp.DoWaitCursor(-1);\r
1796                         CString temp;\r
1797                         temp.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)filepath);\r
1798                         CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseGit"), MB_ICONERROR);\r
1799                         TRACE(_T("could not retrieve the URL of the file!\n"));\r
1800                         EnableOKButton();\r
1801                         theApp.DoWaitCursor(-11);\r
1802                         return;         //exit\r
1803                 }\r
1804         }\r
1805         m_bCancelled = FALSE;\r
1806         filepath = GetRepositoryRoot(CTGitPath(filepath));\r
1807 \r
1808         CString firstfile, secondfile;\r
1809         if (m_LogList.GetSelectedCount()==1)\r
1810         {\r
1811                 int s = m_LogList.GetSelectionMark();\r
1812                 PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(s));\r
1813                 LogChangedPath * changedpath = pLogEntry->pArChangedPaths->GetAt(selIndex);\r
1814                 firstfile = changedpath->sPath;\r
1815                 secondfile = firstfile;\r
1816                 if ((rev2 == rev1-1)&&(changedpath->lCopyFromRev > 0)) // is it an added file with history?\r
1817                 {\r
1818                         secondfile = changedpath->sCopyFromPath;\r
1819                         rev2 = changedpath->lCopyFromRev;\r
1820                 }\r
1821         }\r
1822         else\r
1823         {\r
1824                 firstfile = m_currentChangedPathList[selIndex].GetGitPathString();\r
1825                 secondfile = firstfile;\r
1826         }\r
1827 \r
1828         firstfile = filepath + firstfile.Trim();\r
1829         secondfile = filepath + secondfile.Trim();\r
1830 \r
1831         GitDiff diff(this, this->m_hWnd, true);\r
1832         diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
1833         diff.SetHEADPeg(m_LogRevision);\r
1834         if (unified)\r
1835         {\r
1836                 if (PromptShown())\r
1837                         diff.ShowUnifiedDiff(CTGitPath(secondfile), rev2, CTGitPath(firstfile), rev1);\r
1838                 else\r
1839                         CAppUtils::StartShowUnifiedDiff(m_hWnd, CTGitPath(secondfile), rev2, CTGitPath(firstfile), rev1, GitRev(), m_LogRevision);\r
1840         }\r
1841         else\r
1842         {\r
1843                 if (diff.ShowCompare(CTGitPath(secondfile), rev2, CTGitPath(firstfile), rev1, GitRev(), false, blame))\r
1844                 {\r
1845                         if (firstfile.Compare(secondfile)==0)\r
1846                         {\r
1847                                 git_revnum_t baseRev = 0;\r
1848                                 diff.DiffProps(CTGitPath(firstfile), rev2, rev1, baseRev);\r
1849                         }\r
1850                 }\r
1851         }\r
1852 \r
1853 #endif\r
1854 \r
1855         theApp.DoWaitCursor(-1);\r
1856         EnableOKButton();\r
1857 }\r
1858 \r
1859 BOOL CLogDlg::Open(bool bOpenWith,CString changedpath, git_revnum_t rev)\r
1860 {\r
1861 #if 0\r
1862         DialogEnableWindow(IDOK, FALSE);\r
1863         SetPromptApp(&theApp);\r
1864         theApp.DoWaitCursor(1);\r
1865         CString filepath;\r
1866         if (Git::PathIsURL(m_path))\r
1867         {\r
1868                 filepath = m_path.GetGitPathString();\r
1869         }\r
1870         else\r
1871         {\r
1872                 filepath = GetURLFromPath(m_path);\r
1873                 if (filepath.IsEmpty())\r
1874                 {\r
1875                         theApp.DoWaitCursor(-1);\r
1876                         CString temp;\r
1877                         temp.Format(IDS_ERR_NOURLOFFILE, (LPCTSTR)filepath);\r
1878                         CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseGit"), MB_ICONERROR);\r
1879                         TRACE(_T("could not retrieve the URL of the file!\n"));\r
1880                         EnableOKButton();\r
1881                         return FALSE;\r
1882                 }\r
1883         }\r
1884         m_bCancelled = false;\r
1885         filepath = GetRepositoryRoot(CTGitPath(filepath));\r
1886         filepath += changedpath;\r
1887 \r
1888         CProgressDlg progDlg;\r
1889         progDlg.SetTitle(IDS_APPNAME);\r
1890         progDlg.SetAnimation(IDR_DOWNLOAD);\r
1891         CString sInfoLine;\r
1892         sInfoLine.Format(IDS_PROGRESSGETFILEREVISION, (LPCTSTR)filepath, (LPCTSTR)GitRev(rev).ToString());\r
1893         progDlg.SetLine(1, sInfoLine, true);\r
1894         SetAndClearProgressInfo(&progDlg);\r
1895         progDlg.ShowModeless(m_hWnd);\r
1896 \r
1897         CTGitPath tempfile = CTempFiles::Instance().GetTempFilePath(false, CTGitPath(filepath), rev);\r
1898         m_bCancelled = false;\r
1899         if (!Cat(CTGitPath(filepath), GitRev(rev), rev, tempfile))\r
1900         {\r
1901                 progDlg.Stop();\r
1902                 SetAndClearProgressInfo((HWND)NULL);\r
1903                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
1904                 EnableOKButton();\r
1905                 theApp.DoWaitCursor(-1);\r
1906                 return FALSE;\r
1907         }\r
1908         progDlg.Stop();\r
1909         SetAndClearProgressInfo((HWND)NULL);\r
1910         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
1911         if (!bOpenWith)\r
1912         {\r
1913                 int ret = (int)ShellExecute(this->m_hWnd, NULL, tempfile.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
1914                 if (ret <= HINSTANCE_ERROR)\r
1915                         bOpenWith = true;\r
1916         }\r
1917         if (bOpenWith)\r
1918         {\r
1919                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
1920                 cmd += tempfile.GetWinPathString() + _T(" ");\r
1921                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
1922         }\r
1923         EnableOKButton();\r
1924         theApp.DoWaitCursor(-1);\r
1925 #endif\r
1926         return TRUE;\r
1927 }\r
1928 \r
1929 void CLogDlg::EditAuthor(const CLogDataVector& logs)\r
1930 {\r
1931 #if 0\r
1932         CString url;\r
1933         CString name;\r
1934         if (logs.size() == 0)\r
1935                 return;\r
1936         DialogEnableWindow(IDOK, FALSE);\r
1937         SetPromptApp(&theApp);\r
1938         theApp.DoWaitCursor(1);\r
1939         if (Git::PathIsURL(m_path))\r
1940                 url = m_path.GetGitPathString();\r
1941         else\r
1942         {\r
1943                 url = GetURLFromPath(m_path);\r
1944         }\r
1945         name = Git_PROP_REVISION_AUTHOR;\r
1946 \r
1947         CString value = RevPropertyGet(name, CTGitPath(url), logs[0]->Rev);\r
1948         CString sOldValue = value;\r
1949         value.Replace(_T("\n"), _T("\r\n"));\r
1950         CInputDlg dlg(this);\r
1951         dlg.m_sHintText.LoadString(IDS_LOG_AUTHOR);\r
1952         dlg.m_sInputText = value;\r
1953         dlg.m_sTitle.LoadString(IDS_LOG_AUTHOREDITTITLE);\r
1954         dlg.m_pProjectProperties = &m_ProjectProperties;\r
1955         dlg.m_bUseLogWidth = false;\r
1956         if (dlg.DoModal() == IDOK)\r
1957         {\r
1958                 dlg.m_sInputText.Replace(_T("\r"), _T(""));\r
1959 \r
1960                 LogCache::CCachedLogInfo* toUpdate \r
1961                         = GetLogCache (CTGitPath (m_sRepositoryRoot));\r
1962 \r
1963                 CProgressDlg progDlg;\r
1964                 progDlg.SetTitle(IDS_APPNAME);\r
1965                 progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROGRESSWAIT)));\r
1966                 progDlg.SetTime(true);\r
1967                 progDlg.SetShowProgressBar(true);\r
1968                 progDlg.ShowModeless(m_hWnd);\r
1969                 for (DWORD i=0; i<logs.size(); ++i)\r
1970                 {\r
1971                         if (!RevPropertySet(name, dlg.m_sInputText, sOldValue, CTGitPath(url), logs[i]->Rev))\r
1972                         {\r
1973                                 progDlg.Stop();\r
1974                                 CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
1975                                 break;\r
1976                         }\r
1977                         else\r
1978                         {\r
1979 \r
1980                                 logs[i]->sAuthor = dlg.m_sInputText;\r
1981                                 m_LogList.Invalidate();\r
1982 \r
1983                                 // update the log cache \r
1984 \r
1985                                 if (toUpdate != NULL)\r
1986                                 {\r
1987                                         // log caching is active\r
1988 \r
1989                                         LogCache::CCachedLogInfo newInfo;\r
1990                                         newInfo.Insert ( logs[i]->Rev\r
1991                                                 , (const char*) CUnicodeUtils::GetUTF8 (logs[i]->sAuthor)\r
1992                                                 , ""\r
1993                                                 , 0\r
1994                                                 , LogCache::CRevisionInfoContainer::HAS_AUTHOR);\r
1995 \r
1996                                         toUpdate->Update (newInfo);\r
1997                                 }\r
1998                         }\r
1999                         progDlg.SetProgress64(i, logs.size());\r
2000                 }\r
2001                 progDlg.Stop();\r
2002         }\r
2003         theApp.DoWaitCursor(-1);\r
2004         EnableOKButton();\r
2005 #endif\r
2006 }\r
2007 \r
2008 void CLogDlg::EditLogMessage(int index)\r
2009 {\r
2010 #if 0\r
2011         CString url;\r
2012         CString name;\r
2013         DialogEnableWindow(IDOK, FALSE);\r
2014         SetPromptApp(&theApp);\r
2015         theApp.DoWaitCursor(1);\r
2016         if (Git::PathIsURL(m_path))\r
2017                 url = m_path.GetGitPathString();\r
2018         else\r
2019         {\r
2020                 url = GetURLFromPath(m_path);\r
2021         }\r
2022         name = Git_PROP_REVISION_LOG;\r
2023 \r
2024         PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(m_arShownList.GetAt(index));\r
2025         m_bCancelled = FALSE;\r
2026         CString value = RevPropertyGet(name, CTGitPath(url), pLogEntry->Rev);\r
2027         CString sOldValue = value;\r
2028         value.Replace(_T("\n"), _T("\r\n"));\r
2029         CInputDlg dlg(this);\r
2030         dlg.m_sHintText.LoadString(IDS_LOG_MESSAGE);\r
2031         dlg.m_sInputText = value;\r
2032         dlg.m_sTitle.LoadString(IDS_LOG_MESSAGEEDITTITLE);\r
2033         dlg.m_pProjectProperties = &m_ProjectProperties;\r
2034         dlg.m_bUseLogWidth = true;\r
2035         if (dlg.DoModal() == IDOK)\r
2036         {\r
2037                 dlg.m_sInputText.Replace(_T("\r"), _T(""));\r
2038                 if (!RevPropertySet(name, dlg.m_sInputText, sOldValue, CTGitPath(url), pLogEntry->Rev))\r
2039                 {\r
2040                         CMessageBox::Show(this->m_hWnd, GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
2041                 }\r
2042                 else\r
2043                 {\r
2044                         pLogEntry->sShortMessage = MakeShortMessage(dlg.m_sInputText);\r
2045                         // split multi line log entries and concatenate them\r
2046                         // again but this time with \r\n as line separators\r
2047                         // so that the edit control recognizes them\r
2048                         if (dlg.m_sInputText.GetLength()>0)\r
2049                         {\r
2050                                 m_sMessageBuf = dlg.m_sInputText;\r
2051                                 dlg.m_sInputText.Replace(_T("\n\r"), _T("\n"));\r
2052                                 dlg.m_sInputText.Replace(_T("\r\n"), _T("\n"));\r
2053                                 if (dlg.m_sInputText.Right(1).Compare(_T("\n"))==0)\r
2054                                         dlg.m_sInputText = dlg.m_sInputText.Left(dlg.m_sInputText.GetLength()-1);\r
2055                         } \r
2056                         else\r
2057                                 dlg.m_sInputText.Empty();\r
2058                         pLogEntry->sMessage = dlg.m_sInputText;\r
2059                         pLogEntry->sBugIDs = m_ProjectProperties.FindBugID(dlg.m_sInputText);\r
2060                         CWnd * pMsgView = GetDlgItem(IDC_MSGVIEW);\r
2061                         pMsgView->SetWindowText(_T(" "));\r
2062                         pMsgView->SetWindowText(dlg.m_sInputText);\r
2063                         m_ProjectProperties.FindBugID(dlg.m_sInputText, pMsgView);\r
2064                         m_LogList.Invalidate();\r
2065         \r
2066             // update the log cache \r
2067 \r
2068             LogCache::CCachedLogInfo* toUpdate \r
2069                 = GetLogCache (CTGitPath (m_sRepositoryRoot));\r
2070             if (toUpdate != NULL)\r
2071             {\r
2072                 // log caching is active\r
2073 \r
2074                 LogCache::CCachedLogInfo newInfo;\r
2075                 newInfo.Insert ( pLogEntry->Rev\r
2076                                , ""\r
2077                                , (const char*) CUnicodeUtils::GetUTF8 (pLogEntry->sMessage)\r
2078                                , 0\r
2079                                , LogCache::CRevisionInfoContainer::HAS_COMMENT);\r
2080 \r
2081                 toUpdate->Update (newInfo);\r
2082             }\r
2083         }\r
2084         }\r
2085         theApp.DoWaitCursor(-1);\r
2086         EnableOKButton();\r
2087 #endif\r
2088 }\r
2089 \r
2090 BOOL CLogDlg::PreTranslateMessage(MSG* pMsg)\r
2091 {\r
2092         // Skip Ctrl-C when copying text out of the log message or search filter\r
2093         BOOL bSkipAccelerator = ( pMsg->message == WM_KEYDOWN && pMsg->wParam=='C' && (GetFocus()==GetDlgItem(IDC_MSGVIEW) || GetFocus()==GetDlgItem(IDC_SEARCHEDIT) ) && GetKeyState(VK_CONTROL)&0x8000 );\r
2094         if (pMsg->message == WM_KEYDOWN && pMsg->wParam=='\r')\r
2095         {\r
2096                 if (GetFocus()==GetDlgItem(IDC_LOGLIST))\r
2097                 {\r
2098                         if (CRegDWORD(_T("Software\\TortoiseGit\\DiffByDoubleClickInLog"), FALSE))\r
2099                         {\r
2100                                 DiffSelectedRevWithPrevious();\r
2101                                 return TRUE;\r
2102                         }\r
2103                 }\r
2104                 if (GetFocus()==GetDlgItem(IDC_LOGMSG))\r
2105                 {\r
2106                         DiffSelectedFile();\r
2107                         return TRUE;\r
2108                 }\r
2109         }\r
2110         if (m_hAccel && !bSkipAccelerator)\r
2111         {\r
2112                 int ret = TranslateAccelerator(m_hWnd, m_hAccel, pMsg);\r
2113                 if (ret)\r
2114                         return TRUE;\r
2115         }\r
2116         \r
2117         m_tooltips.RelayEvent(pMsg);\r
2118         return __super::PreTranslateMessage(pMsg);\r
2119 }\r
2120 \r
2121 BOOL CLogDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)\r
2122 {\r
2123         if (m_bThreadRunning)\r
2124         {\r
2125                 // only show the wait cursor over the list control\r
2126                 if ((pWnd)&&\r
2127                         ((pWnd == GetDlgItem(IDC_LOGLIST))||\r
2128                         (pWnd == GetDlgItem(IDC_MSGVIEW))||\r
2129                         (pWnd == GetDlgItem(IDC_LOGMSG))))\r
2130                 {\r
2131                         HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));\r
2132                         SetCursor(hCur);\r
2133                         return TRUE;\r
2134                 }\r
2135         }\r
2136         if ((pWnd) && (pWnd == GetDlgItem(IDC_MSGVIEW)))\r
2137                 return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);\r
2138 \r
2139         HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));\r
2140         SetCursor(hCur);\r
2141         return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);\r
2142 }\r
2143 \r
2144 void CLogDlg::OnBnClickedHelp()\r
2145 {\r
2146         OnHelp();\r
2147 }\r
2148 \r
2149 void CLogDlg::OnLvnItemchangedLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
2150 {\r
2151         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
2152         *pResult = 0;\r
2153         if (m_bThreadRunning)\r
2154                 return;\r
2155         if (pNMLV->iItem >= 0)\r
2156         {\r
2157                 m_nSearchIndex = pNMLV->iItem;\r
2158                 if (pNMLV->iSubItem != 0)\r
2159                         return;\r
2160                 if ((pNMLV->iItem == m_arShownList.GetCount())&&(m_bStrict)&&(m_bStrictStopped))\r
2161                 {\r
2162                         // remove the selected state\r
2163                         if (pNMLV->uChanged & LVIF_STATE)\r
2164                         {\r
2165                                 m_LogList.SetItemState(pNMLV->iItem, 0, LVIS_SELECTED);\r
2166                                 FillLogMessageCtrl();\r
2167                                 UpdateData(FALSE);\r
2168                                 UpdateLogInfoLabel();\r
2169                         }\r
2170                         return;\r
2171                 }\r
2172                 if (pNMLV->uChanged & LVIF_STATE)\r
2173                 {\r
2174                         FillLogMessageCtrl();\r
2175                         UpdateData(FALSE);\r
2176                 }\r
2177         }\r
2178         else\r
2179         {\r
2180                 FillLogMessageCtrl();\r
2181                 UpdateData(FALSE);\r
2182         }\r
2183         EnableOKButton();\r
2184         UpdateLogInfoLabel();\r
2185 }\r
2186 \r
2187 void CLogDlg::OnEnLinkMsgview(NMHDR *pNMHDR, LRESULT *pResult)\r
2188 {\r
2189         ENLINK *pEnLink = reinterpret_cast<ENLINK *>(pNMHDR);\r
2190         if (pEnLink->msg == WM_LBUTTONUP)\r
2191         {\r
2192                 CString url, msg;\r
2193                 GetDlgItemText(IDC_MSGVIEW, msg);\r
2194                 msg.Replace(_T("\r\n"), _T("\n"));\r
2195                 url = msg.Mid(pEnLink->chrg.cpMin, pEnLink->chrg.cpMax-pEnLink->chrg.cpMin);\r
2196                 if (!::PathIsURL(url))\r
2197                 {\r
2198                         url = m_ProjectProperties.GetBugIDUrl(url);\r
2199                         url = GetAbsoluteUrlFromRelativeUrl(url);\r
2200                 }\r
2201                 if (!url.IsEmpty())\r
2202                         ShellExecute(this->m_hWnd, _T("open"), url, NULL, NULL, SW_SHOWDEFAULT);\r
2203         }\r
2204         *pResult = 0;\r
2205 }\r
2206 \r
2207 void CLogDlg::OnBnClickedStatbutton()\r
2208 {\r
2209 #if 0\r
2210         if (m_bThreadRunning)\r
2211                 return;\r
2212         if (m_arShownList.IsEmpty())\r
2213                 return;         // nothing is shown, so no statistics.\r
2214         // the statistics dialog expects the log entries to be sorted by date\r
2215         SortByColumn(3, false);\r
2216         CPtrArray shownlist;\r
2217         RecalculateShownList(&shownlist);\r
2218         // create arrays which are aware of the current filter\r
2219         CStringArray m_arAuthorsFiltered;\r
2220         CDWordArray m_arDatesFiltered;\r
2221         CDWordArray m_arFileChangesFiltered;\r
2222         for (INT_PTR i=0; i<shownlist.GetCount(); ++i)\r
2223         {\r
2224                 PLOGENTRYDATA pLogEntry = reinterpret_cast<PLOGENTRYDATA>(shownlist.GetAt(i));\r
2225                 CString strAuthor = pLogEntry->sAuthor;\r
2226                 if ( strAuthor.IsEmpty() )\r
2227                 {\r
2228                         strAuthor.LoadString(IDS_STATGRAPH_EMPTYAUTHOR);\r
2229                 }\r
2230                 m_arAuthorsFiltered.Add(strAuthor);\r
2231                 m_arDatesFiltered.Add(static_cast<DWORD>(pLogEntry->tmDate));\r
2232                 m_arFileChangesFiltered.Add(pLogEntry->dwFileChanges);\r
2233         }\r
2234         CStatGraphDlg dlg;\r
2235         dlg.m_parAuthors = &m_arAuthorsFiltered;\r
2236         dlg.m_parDates = &m_arDatesFiltered;\r
2237         dlg.m_parFileChanges = &m_arFileChangesFiltered;\r
2238         dlg.m_path = m_path;\r
2239         dlg.DoModal();\r
2240         // restore the previous sorting\r
2241         SortByColumn(m_nSortColumn, m_bAscending);\r
2242         OnTimer(LOGFILTER_TIMER);\r
2243 #endif\r
2244 }\r
2245 \r
2246 #if 0\r
2247 void CLogDlg::OnNMCustomdrawLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
2248 {\r
2249 \r
2250         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
2251         // Take the default processing unless we set this to something else below.\r
2252         *pResult = CDRF_DODEFAULT;\r
2253 \r
2254         if (m_bNoDispUpdates)\r
2255                 return;\r
2256 \r
2257         switch (pLVCD->nmcd.dwDrawStage)\r
2258         {\r
2259         case CDDS_PREPAINT:\r
2260                 {\r
2261                         *pResult = CDRF_NOTIFYITEMDRAW;\r
2262                         return;\r
2263                 }\r
2264                 break;\r
2265         case CDDS_ITEMPREPAINT:\r
2266                 {\r
2267                         // This is the prepaint stage for an item. Here's where we set the\r
2268                         // item's text color. \r
2269                         \r
2270                         // Tell Windows to send draw notifications for each subitem.\r
2271                         *pResult = CDRF_NOTIFYSUBITEMDRAW;\r
2272 \r
2273                         COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
2274 \r
2275                         if (m_arShownList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
2276                         {\r
2277                                 GitRev* data = (GitRev*)m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec);\r
2278                                 if (data)\r
2279                                 {\r
2280 #if 0\r
2281                                         if (data->bCopiedSelf)\r
2282                                         {\r
2283                                                 // only change the background color if the item is not 'hot' (on vista with themes enabled)\r
2284                                                 if (!theme.IsAppThemed() || !m_bVista || ((pLVCD->nmcd.uItemState & CDIS_HOT)==0))\r
2285                                                         pLVCD->clrTextBk = GetSysColor(COLOR_MENU);\r
2286                                         }\r
2287 \r
2288                                         if (data->bCopies)\r
2289                                                 crText = m_Colors.GetColor(CColors::Modified);\r
2290 #endif\r
2291 //                                      if ((data->childStackDepth)||(m_mergedRevs.find(data->Rev) != m_mergedRevs.end()))\r
2292 //                                              crText = GetSysColor(COLOR_GRAYTEXT);\r
2293 //                                      if (data->Rev == m_wcRev)\r
2294 //                                      {\r
2295 //                                              SelectObject(pLVCD->nmcd.hdc, m_boldFont);\r
2296                                                 // We changed the font, so we're returning CDRF_NEWFONT. This\r
2297                                                 // tells the control to recalculate the extent of the text.\r
2298 //                                              *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;\r
2299 //                                      }\r
2300                                 }\r
2301                         }\r
2302                         if (m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
2303                         {\r
2304                                 if (m_bStrictStopped)\r
2305                                         crText = GetSysColor(COLOR_GRAYTEXT);\r
2306                         }\r
2307                         // Store the color back in the NMLVCUSTOMDRAW struct.\r
2308                         pLVCD->clrText = crText;\r
2309                         return;\r
2310                 }\r
2311                 break;\r
2312         case CDDS_ITEMPREPAINT|CDDS_ITEM|CDDS_SUBITEM:\r
2313                 {\r
2314                         if ((m_bStrictStopped)&&(m_arShownList.GetCount() == (INT_PTR)pLVCD->nmcd.dwItemSpec))\r
2315                         {\r
2316                                 pLVCD->nmcd.uItemState &= ~(CDIS_SELECTED|CDIS_FOCUS);\r
2317                         }\r
2318                         if (pLVCD->iSubItem == 1)\r
2319                         {\r
2320                                 *pResult = CDRF_DODEFAULT;\r
2321 \r
2322                                 if (m_arShownList.GetCount() <= (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
2323                                         return;\r
2324 \r
2325                                 int             nIcons = 0;\r
2326                                 int             iconwidth = ::GetSystemMetrics(SM_CXSMICON);\r
2327                                 int             iconheight = ::GetSystemMetrics(SM_CYSMICON);\r
2328 \r
2329                                 GitRev* pLogEntry = reinterpret_cast<GitRev *>(m_arShownList.GetAt(pLVCD->nmcd.dwItemSpec));\r
2330 \r
2331                                 // Get the selected state of the\r
2332                                 // item being drawn.\r
2333                                 LVITEM   rItem;\r
2334                                 SecureZeroMemory(&rItem, sizeof(LVITEM));\r
2335                                 rItem.mask  = LVIF_STATE;\r
2336                                 rItem.iItem = pLVCD->nmcd.dwItemSpec;\r
2337                                 rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;\r
2338                                 m_LogList.GetItem(&rItem);\r
2339 \r
2340                                 CRect rect;\r
2341                                 m_LogList.GetSubItemRect(pLVCD->nmcd.dwItemSpec, pLVCD->iSubItem, LVIR_BOUNDS, rect);\r
2342 \r
2343                                 // Fill the background\r
2344                                 if (theme.IsAppThemed() && m_bVista)\r
2345                                 {\r
2346                                         theme.Open(m_hWnd, L"Explorer");\r
2347                                         int state = LISS_NORMAL;\r
2348                                         if (rItem.state & LVIS_SELECTED)\r
2349                                         {\r
2350                                                 if (::GetFocus() == m_LogList.m_hWnd)\r
2351                                                         state |= LISS_SELECTED;\r
2352                                                 else\r
2353                                                         state |= LISS_SELECTEDNOTFOCUS;\r
2354                                         }\r
2355                                         else\r
2356                                         {\r
2357 #if 0\r
2358                                                 if (pLogEntry->bCopiedSelf)\r
2359                                                 {\r
2360                                                         // unfortunately, the pLVCD->nmcd.uItemState does not contain valid\r
2361                                                         // information at this drawing stage. But we can check the whether the\r
2362                                                         // previous stage changed the background color of the item\r
2363                                                         if (pLVCD->clrTextBk == GetSysColor(COLOR_MENU))\r
2364                                                         {\r
2365                                                                 HBRUSH brush;\r
2366                                                                 brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
2367                                                                 if (brush)\r
2368                                                                 {\r
2369                                                                         ::FillRect(pLVCD->nmcd.hdc, &rect, brush);\r
2370                                                                         ::DeleteObject(brush);\r
2371                                                                 }\r
2372                                                         }\r
2373                                                 }\r
2374 #endif\r
2375                                         }\r
2376 \r
2377                                         if (theme.IsBackgroundPartiallyTransparent(LVP_LISTDETAIL, state))\r
2378                                                 theme.DrawParentBackground(m_hWnd, pLVCD->nmcd.hdc, &rect);\r
2379 \r
2380                                         theme.DrawBackground(pLVCD->nmcd.hdc, LVP_LISTDETAIL, state, &rect, NULL);\r
2381                                 }\r
2382                                 else\r
2383                                 {\r
2384                                         HBRUSH brush;\r
2385                                         if (rItem.state & LVIS_SELECTED)\r
2386                                         {\r
2387                                                 if (::GetFocus() == m_LogList.m_hWnd)\r
2388                                                         brush = ::CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT));\r
2389                                                 else\r
2390                                                         brush = ::CreateSolidBrush(::GetSysColor(COLOR_BTNFACE));\r
2391                                         }\r
2392                                         else\r
2393                                         {\r
2394                                                 //if (pLogEntry->bCopiedSelf)\r
2395                                                 //      brush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));\r
2396                                                 //else\r
2397                                                         brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));\r
2398                                         }\r
2399                                         if (brush == NULL)\r
2400                                                 return;\r
2401 \r
2402                                         ::FillRect(pLVCD->nmcd.hdc, &rect, brush);\r
2403                                         ::DeleteObject(brush);\r
2404                                 }\r
2405 \r
2406                                 // Draw the icon(s) into the compatible DC\r
2407                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_MODIFIED)\r
2408                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left + ICONITEMBORDER, rect.top, m_hModifiedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
2409                                 nIcons++;\r
2410 \r
2411                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_ADDED)\r
2412                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hAddedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
2413                                 nIcons++;\r
2414 \r
2415                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_DELETED)\r
2416                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hDeletedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
2417                                 nIcons++;\r
2418 \r
2419                                 if (pLogEntry->m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
2420                                         ::DrawIconEx(pLVCD->nmcd.hdc, rect.left+nIcons*iconwidth + ICONITEMBORDER, rect.top, m_hReplacedIcon, iconwidth, iconheight, 0, NULL, DI_NORMAL);\r
2421                                 nIcons++;\r
2422                                 *pResult = CDRF_SKIPDEFAULT;\r
2423                                 return;\r
2424                         }\r
2425                 }\r
2426                 break;\r
2427         }\r
2428         *pResult = CDRF_DODEFAULT;\r
2429 \r
2430 }\r
2431 #endif\r
2432 \r
2433 void CLogDlg::OnNMCustomdrawChangedFileList(NMHDR *pNMHDR, LRESULT *pResult)\r
2434 {\r
2435 \r
2436         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
2437         // Take the default processing unless we set this to something else below.\r
2438         *pResult = CDRF_DODEFAULT;\r
2439 \r
2440         if (m_bNoDispUpdates)\r
2441                 return;\r
2442 \r
2443         // First thing - check the draw stage. If it's the control's prepaint\r
2444         // stage, then tell Windows we want messages for every item.\r
2445 \r
2446         if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )\r
2447         {\r
2448                 *pResult = CDRF_NOTIFYITEMDRAW;\r
2449         }\r
2450         else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )\r
2451         {\r
2452                 // This is the prepaint stage for an item. Here's where we set the\r
2453                 // item's text color. Our return value will tell Windows to draw the\r
2454                 // item itself, but it will use the new color we set here.\r
2455 \r
2456                 // Tell Windows to paint the control itself.\r
2457                 *pResult = CDRF_DODEFAULT;\r
2458 \r
2459                 COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
2460                 bool bGrayed = false;\r
2461 #if 0\r
2462                 if ((m_cHidePaths.GetState() & 0x0003)==BST_INDETERMINATE)\r
2463                 {\r
2464                         if ((m_currentChangedArray)&&((m_currentChangedArray->GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)))\r
2465                         {\r
2466                                 //if ((*m_currentChangedArray)[(pLVCD->nmcd.dwItemSpec)]sPath.Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)!=0)\r
2467                                 {\r
2468                                         crText = GetSysColor(COLOR_GRAYTEXT);\r
2469                                         bGrayed = true;\r
2470                                 }\r
2471                         }\r
2472                         else if (m_currentChangedPathList.GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec)\r
2473                         {\r
2474                                 //if (m_currentChangedPathList[pLVCD->nmcd.dwItemSpec].GetGitPathString().Left(m_sRelativeRoot.GetLength()).Compare(m_sRelativeRoot)!=0)\r
2475                                 {\r
2476                                         crText = GetSysColor(COLOR_GRAYTEXT);\r
2477                                         bGrayed = true;\r
2478                                 }\r
2479                         }\r
2480                 }\r
2481 \r
2482 #endif\r
2483                 if ((!bGrayed)&&(m_currentChangedArray)&&(m_currentChangedArray->GetCount() > (INT_PTR)pLVCD->nmcd.dwItemSpec))\r
2484                 {\r
2485                         DWORD action = ((*m_currentChangedArray)[pLVCD->nmcd.dwItemSpec]).m_Action;\r
2486                         if (action == CTGitPath::LOGACTIONS_MODIFIED)\r
2487                                 crText = m_Colors.GetColor(CColors::Modified);\r
2488                         if (action == CTGitPath::LOGACTIONS_REPLACED)\r
2489                                 crText = m_Colors.GetColor(CColors::Deleted);\r
2490                         if (action == CTGitPath::LOGACTIONS_ADDED)\r
2491                                 crText = m_Colors.GetColor(CColors::Added);\r
2492                         if (action == CTGitPath::LOGACTIONS_DELETED)\r
2493                                 crText = m_Colors.GetColor(CColors::Deleted);\r
2494                 }\r
2495 \r
2496                 // Store the color back in the NMLVCUSTOMDRAW struct.\r
2497                 pLVCD->clrText = crText;\r
2498         }\r
2499 }\r
2500 \r
2501 void CLogDlg::DoSizeV1(int delta)\r
2502 {\r
2503 \r
2504         RemoveAnchor(IDC_LOGLIST);\r
2505         RemoveAnchor(IDC_SPLITTERTOP);\r
2506         RemoveAnchor(IDC_MSGVIEW);\r
2507         RemoveAnchor(IDC_SPLITTERBOTTOM);\r
2508         RemoveAnchor(IDC_LOGMSG);\r
2509         CSplitterControl::ChangeHeight(&m_LogList, delta, CW_TOPALIGN);\r
2510         CSplitterControl::ChangeHeight(GetDlgItem(IDC_MSGVIEW), -delta, CW_BOTTOMALIGN);\r
2511         AddAnchor(IDC_LOGLIST, TOP_LEFT, TOP_RIGHT);\r
2512         AddAnchor(IDC_SPLITTERTOP, TOP_LEFT, TOP_RIGHT);\r
2513         AddAnchor(IDC_MSGVIEW, TOP_LEFT, BOTTOM_RIGHT);\r
2514         AddAnchor(IDC_SPLITTERBOTTOM, BOTTOM_LEFT, BOTTOM_RIGHT);\r
2515         AddAnchor(IDC_LOGMSG, BOTTOM_LEFT, BOTTOM_RIGHT);\r
2516         ArrangeLayout();\r
2517         AdjustMinSize();\r
2518         SetSplitterRange();\r
2519         m_LogList.Invalidate();\r
2520         GetDlgItem(IDC_MSGVIEW)->Invalidate();\r
2521 \r
2522 }\r
2523 \r
2524 void CLogDlg::DoSizeV2(int delta)\r
2525 {\r
2526 \r
2527         RemoveAnchor(IDC_LOGLIST);\r
2528         RemoveAnchor(IDC_SPLITTERTOP);\r
2529         RemoveAnchor(IDC_MSGVIEW);\r
2530         RemoveAnchor(IDC_SPLITTERBOTTOM);\r
2531         RemoveAnchor(IDC_LOGMSG);\r
2532         CSplitterControl::ChangeHeight(GetDlgItem(IDC_MSGVIEW), delta, CW_TOPALIGN);\r
2533         CSplitterControl::ChangeHeight(&m_ChangedFileListCtrl, -delta, CW_BOTTOMALIGN);\r
2534         AddAnchor(IDC_LOGLIST, TOP_LEFT, TOP_RIGHT);\r
2535         AddAnchor(IDC_SPLITTERTOP, TOP_LEFT, TOP_RIGHT);\r
2536         AddAnchor(IDC_MSGVIEW, TOP_LEFT, BOTTOM_RIGHT);\r
2537         AddAnchor(IDC_SPLITTERBOTTOM, BOTTOM_LEFT, BOTTOM_RIGHT);\r
2538         AddAnchor(IDC_LOGMSG, BOTTOM_LEFT, BOTTOM_RIGHT);\r
2539         ArrangeLayout();\r
2540         AdjustMinSize();\r
2541         SetSplitterRange();\r
2542         GetDlgItem(IDC_MSGVIEW)->Invalidate();\r
2543         m_ChangedFileListCtrl.Invalidate();\r
2544 \r
2545 }\r
2546 \r
2547 void CLogDlg::AdjustMinSize()\r
2548 {\r
2549         // adjust the minimum size of the dialog to prevent the resizing from\r
2550         // moving the list control too far down.\r
2551         CRect rcChgListView;\r
2552         m_ChangedFileListCtrl.GetClientRect(rcChgListView);\r
2553         CRect rcLogList;\r
2554         m_LogList.GetClientRect(rcLogList);\r
2555 \r
2556         SetMinTrackSize(CSize(m_DlgOrigRect.Width(), \r
2557                 m_DlgOrigRect.Height()-m_ChgOrigRect.Height()-m_LogListOrigRect.Height()-m_MsgViewOrigRect.Height()\r
2558                 +rcChgListView.Height()+rcLogList.Height()+60));\r
2559 }\r
2560 \r
2561 LRESULT CLogDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) \r
2562 {\r
2563         switch (message) {\r
2564         case WM_NOTIFY:\r
2565                 if (wParam == IDC_SPLITTERTOP)\r
2566                 { \r
2567                         SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;\r
2568                         DoSizeV1(pHdr->delta);\r
2569                 }\r
2570                 else if (wParam == IDC_SPLITTERBOTTOM)\r
2571                 { \r
2572                         SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;\r
2573                         DoSizeV2(pHdr->delta);\r
2574                 }\r
2575                 break;\r
2576         }\r
2577 \r
2578         return CResizableDialog::DefWindowProc(message, wParam, lParam);\r
2579 }\r
2580 \r
2581 void CLogDlg::SetSplitterRange()\r
2582 {\r
2583         if ((m_LogList)&&(m_ChangedFileListCtrl))\r
2584         {\r
2585                 CRect rcTop;\r
2586                 m_LogList.GetWindowRect(rcTop);\r
2587                 ScreenToClient(rcTop);\r
2588                 CRect rcMiddle;\r
2589                 GetDlgItem(IDC_MSGVIEW)->GetWindowRect(rcMiddle);\r
2590                 ScreenToClient(rcMiddle);\r
2591                 m_wndSplitter1.SetRange(rcTop.top+30, rcMiddle.bottom-20);\r
2592                 CRect rcBottom;\r
2593                 m_ChangedFileListCtrl.GetWindowRect(rcBottom);\r
2594                 ScreenToClient(rcBottom);\r
2595                 m_wndSplitter2.SetRange(rcMiddle.top+30, rcBottom.bottom-20);\r
2596         }\r
2597 }\r
2598 \r
2599 LRESULT CLogDlg::OnClickedInfoIcon(WPARAM /*wParam*/, LPARAM lParam)\r
2600 {\r
2601         RECT * rect = (LPRECT)lParam;\r
2602         CPoint point;\r
2603         CString temp;\r
2604         point = CPoint(rect->left, rect->bottom);\r
2605 #define LOGMENUFLAGS(x) (MF_STRING | MF_ENABLED | (m_nSelectedFilter == x ? MF_CHECKED : MF_UNCHECKED))\r
2606         CMenu popup;\r
2607         if (popup.CreatePopupMenu())\r
2608         {\r
2609                 temp.LoadString(IDS_LOG_FILTER_ALL);\r
2610                 popup.AppendMenu(LOGMENUFLAGS(LOGFILTER_ALL), LOGFILTER_ALL, temp);\r
2611 \r
2612                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
2613                 \r
2614                 temp.LoadString(IDS_LOG_FILTER_MESSAGES);\r
2615                 popup.AppendMenu(LOGMENUFLAGS(LOGFILTER_MESSAGES), LOGFILTER_MESSAGES, temp);\r
2616                 temp.LoadString(IDS_LOG_FILTER_PATHS);\r
2617                 popup.AppendMenu(LOGMENUFLAGS(LOGFILTER_PATHS), LOGFILTER_PATHS, temp);\r
2618                 temp.LoadString(IDS_LOG_FILTER_AUTHORS);\r
2619                 popup.AppendMenu(LOGMENUFLAGS(LOGFILTER_AUTHORS), LOGFILTER_AUTHORS, temp);\r
2620                 temp.LoadString(IDS_LOG_FILTER_REVS);\r
2621                 popup.AppendMenu(LOGMENUFLAGS(LOGFILTER_REVS), LOGFILTER_REVS, temp);\r
2622                 temp.LoadString(IDS_LOG_FILTER_BUGIDS);\r
2623                 popup.AppendMenu(LOGMENUFLAGS(LOGFILTER_BUGID), LOGFILTER_BUGID, temp);\r
2624                 \r
2625                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
2626 \r
2627                 temp.LoadString(IDS_LOG_FILTER_REGEX);\r
2628                 popup.AppendMenu(MF_STRING | MF_ENABLED | (m_bFilterWithRegex ? MF_CHECKED : MF_UNCHECKED), LOGFILTER_REGEX, temp);\r
2629 \r
2630                 m_tooltips.Pop();\r
2631                 int selection = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
2632                 if (selection != 0)\r
2633                 {\r
2634 \r
2635                         if (selection == LOGFILTER_REGEX)\r
2636                         {\r
2637                                 m_bFilterWithRegex = !m_bFilterWithRegex;\r
2638                                 CRegDWORD b = CRegDWORD(_T("Software\\TortoiseGit\\UseRegexFilter"), TRUE);\r
2639                                 b = m_bFilterWithRegex;\r
2640                                 CheckRegexpTooltip();\r
2641                         }\r
2642                         else\r
2643                         {\r
2644                                 m_nSelectedFilter = selection;\r
2645                                 SetFilterCueText();\r
2646                         }\r
2647                         SetTimer(LOGFILTER_TIMER, 1000, NULL);\r
2648                 }\r
2649         }\r
2650         return 0L;\r
2651 }\r
2652 \r
2653 LRESULT CLogDlg::OnClickedCancelFilter(WPARAM /*wParam*/, LPARAM /*lParam*/)\r
2654 {\r
2655 #if 0\r
2656         KillTimer(LOGFILTER_TIMER);\r
2657 \r
2658         m_sFilterText.Empty();\r
2659         UpdateData(FALSE);\r
2660         theApp.DoWaitCursor(1);\r
2661         CStoreSelection storeselection(this);\r
2662         FillLogMessageCtrl(false);\r
2663         InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
2664         m_arShownList.RemoveAll();\r
2665 \r
2666         // reset the time filter too\r
2667         m_timFrom = (__time64_t(m_tFrom));\r
2668         m_timTo = (__time64_t(m_tTo));\r
2669         m_DateFrom.SetTime(&m_timFrom);\r
2670         m_DateTo.SetTime(&m_timTo);\r
2671         m_DateFrom.SetRange(&m_timFrom, &m_timTo);\r
2672         m_DateTo.SetRange(&m_timFrom, &m_timTo);\r
2673 \r
2674         for (DWORD i=0; i<m_logEntries.size(); ++i)\r
2675         {\r
2676                 m_arShownList.Add(m_logEntries[i]);\r
2677         }\r
2678         InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
2679         m_LogList.DeleteAllItems();\r
2680         m_LogList.SetItemCountEx(ShownCountWithStopped());\r
2681         m_LogList.RedrawItems(0, ShownCountWithStopped());\r
2682         m_LogList.SetRedraw(false);\r
2683         ResizeAllListCtrlCols();\r
2684         m_LogList.SetRedraw(true);\r
2685         theApp.DoWaitCursor(-1);\r
2686         GetDlgItem(IDC_SEARCHEDIT)->ShowWindow(SW_HIDE);\r
2687         GetDlgItem(IDC_SEARCHEDIT)->ShowWindow(SW_SHOW);\r
2688         GetDlgItem(IDC_SEARCHEDIT)->SetFocus();\r
2689         UpdateLogInfoLabel();\r
2690 #endif\r
2691         return 0L;      \r
2692 }\r
2693 \r
2694 \r
2695 void CLogDlg::SetFilterCueText()\r
2696 {\r
2697         CString temp;\r
2698         switch (m_nSelectedFilter)\r
2699         {\r
2700         case LOGFILTER_ALL:\r
2701                 temp.LoadString(IDS_LOG_FILTER_ALL);\r
2702                 break;\r
2703         case LOGFILTER_MESSAGES:\r
2704                 temp.LoadString(IDS_LOG_FILTER_MESSAGES);\r
2705                 break;\r
2706         case LOGFILTER_PATHS:\r
2707                 temp.LoadString(IDS_LOG_FILTER_PATHS);\r
2708                 break;\r
2709         case LOGFILTER_AUTHORS:\r
2710                 temp.LoadString(IDS_LOG_FILTER_AUTHORS);\r
2711                 break;\r
2712         case LOGFILTER_REVS:\r
2713                 temp.LoadString(IDS_LOG_FILTER_REVS);\r
2714                 break;\r
2715         }\r
2716         // to make the cue banner text appear more to the right of the edit control\r
2717         temp = _T("   ")+temp;\r
2718         m_cFilter.SetCueBanner(temp);\r
2719 }\r
2720 #if 0\r
2721 void CLogDlg::OnLvnGetdispinfoLoglist(NMHDR *pNMHDR, LRESULT *pResult)\r
2722 {\r
2723         NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);\r
2724 \r
2725         // Create a pointer to the item\r
2726         LV_ITEM* pItem = &(pDispInfo)->item;\r
2727 \r
2728         // Do the list need text information?\r
2729         if (!(pItem->mask & LVIF_TEXT))\r
2730                 return;\r
2731 \r
2732         // By default, clear text buffer.\r
2733         lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
2734 \r
2735         bool bOutOfRange = pItem->iItem >= ShownCountWithStopped();\r
2736         \r
2737         *pResult = 0;\r
2738         if (m_bNoDispUpdates || m_bThreadRunning || bOutOfRange)\r
2739                 return;\r
2740 \r
2741         // Which item number?\r
2742         int itemid = pItem->iItem;\r
2743         GitRev * pLogEntry = NULL;\r
2744         if (itemid < m_arShownList.GetCount())\r
2745                 pLogEntry = reinterpret_cast<GitRev*>(m_arShownList.GetAt(pItem->iItem));\r
2746     \r
2747         // Which column?\r
2748         switch (pItem->iSubItem)\r
2749         {\r
2750         case this->LOGLIST_GRAPH:       //Graphic\r
2751                 if (pLogEntry)\r
2752                 {\r
2753                 }\r
2754                 break;\r
2755         case this->LOGLIST_ACTION: //action -- no text in the column\r
2756                 break;\r
2757         case this->LOGLIST_MESSAGE: //Message\r
2758                 if (pLogEntry)\r
2759                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_Subject, pItem->cchTextMax);\r
2760                 break;\r
2761         case this->LOGLIST_AUTHOR: //Author\r
2762                 if (pLogEntry)\r
2763                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorName, pItem->cchTextMax);\r
2764                 break;\r
2765         case this->LOGLIST_DATE: //Date\r
2766                 if (pLogEntry)\r
2767                         lstrcpyn(pItem->pszText, (LPCTSTR)pLogEntry->m_AuthorDate.Format(_T("%Y-%m-%d %H:%M")), pItem->cchTextMax);\r
2768                 break;\r
2769                 \r
2770         case 5:\r
2771 \r
2772                 break;\r
2773         default:\r
2774                 ASSERT(false);\r
2775         }\r
2776 }\r
2777 #endif\r
2778 void CLogDlg::OnLvnGetdispinfoChangedFileList(NMHDR *pNMHDR, LRESULT *pResult)\r
2779 {\r
2780 \r
2781         NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);\r
2782 \r
2783         //Create a pointer to the item\r
2784         LV_ITEM* pItem= &(pDispInfo)->item;\r
2785 \r
2786         *pResult = 0;\r
2787         if ((m_bNoDispUpdates)||(m_bThreadRunning))\r
2788         {\r
2789                 if (pItem->mask & LVIF_TEXT)\r
2790                         lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
2791                 return;\r
2792         }\r
2793         if ((m_currentChangedArray!=NULL)&&(pItem->iItem >= m_currentChangedArray->GetCount()))\r
2794         {\r
2795                 if (pItem->mask & LVIF_TEXT)\r
2796                         lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
2797                 return;\r
2798         }\r
2799         if ((m_currentChangedArray==NULL)&&(pItem->iItem >= m_currentChangedPathList.GetCount()))\r
2800         {\r
2801                 if (pItem->mask & LVIF_TEXT)\r
2802                         lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
2803                 return;\r
2804         }\r
2805         CTGitPath lcpath = NULL;\r
2806         if (m_currentChangedArray)\r
2807                 lcpath = (*m_currentChangedArray)[pItem->iItem];\r
2808         //Does the list need text information?\r
2809         if (pItem->mask & LVIF_TEXT)\r
2810         {\r
2811                 //Which column?\r
2812                 switch (pItem->iSubItem)\r
2813                 {\r
2814                 case this->FILELIST_ACTION:     //Action\r
2815 #if 0\r
2816                         if (lcpath)\r
2817                                 lstrcpyn(pItem->pszText, (LPCTSTR)lcpath->GetAction(), pItem->cchTextMax);\r
2818                         else\r
2819                                 lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);                            \r
2820 #endif\r
2821                         lstrcpyn(pItem->pszText, (LPCTSTR)lcpath.GetActionName(), pItem->cchTextMax);\r
2822 \r
2823                         break;\r
2824 \r
2825                 case this->FILELIST_ADD: //add\r
2826 #if 0\r
2827                         if (lcpath)\r
2828                                 lstrcpyn(pItem->pszText, (LPCTSTR)lcpath->sPath, pItem->cchTextMax);\r
2829                         else\r
2830                                 lstrcpyn(pItem->pszText, (LPCTSTR)m_currentChangedPathList[pItem->iItem].GetGitPathString(), pItem->cchTextMax);\r
2831 #endif\r
2832                         lstrcpyn(pItem->pszText, (LPCTSTR)lcpath.m_StatAdd, pItem->cchTextMax);\r
2833                         break;\r
2834 \r
2835                 case this->FILELIST_DEL: //del\r
2836 #if 0\r
2837                         if (lcpath)\r
2838                                 lstrcpyn(pItem->pszText, (LPCTSTR)lcpath->sCopyFromPath, pItem->cchTextMax);\r
2839                         else\r
2840                                 lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
2841 #endif\r
2842                         lstrcpyn(pItem->pszText, (LPCTSTR)lcpath.m_StatDel, pItem->cchTextMax);\r
2843                         break;\r
2844                 case this->FILELIST_PATH: //path\r
2845 #if 0\r
2846                         if ((lcpath==NULL)||(lcpath->sCopyFromPath.IsEmpty()))\r
2847                                 lstrcpyn(pItem->pszText, _T(""), pItem->cchTextMax);\r
2848                         else\r
2849                                 _stprintf_s(pItem->pszText, pItem->cchTextMax, _T("%ld"), lcpath->lCopyFromRev);\r
2850 #endif\r
2851                         lstrcpyn(pItem->pszText, (LPCTSTR)lcpath.GetGitPathString(), pItem->cchTextMax);\r
2852                         break;\r
2853                 }\r
2854         }\r
2855 \r
2856         *pResult = 0;\r
2857 }\r
2858 \r
2859 void CLogDlg::OnEnChangeSearchedit()\r
2860 {\r
2861 #if 0\r
2862         UpdateData();\r
2863         if (m_sFilterText.IsEmpty())\r
2864         {\r
2865                 CStoreSelection storeselection(this);\r
2866                 // clear the filter, i.e. make all entries appear\r
2867                 theApp.DoWaitCursor(1);\r
2868                 KillTimer(LOGFILTER_TIMER);\r
2869                 FillLogMessageCtrl(false);\r
2870                 InterlockedExchange(&m_bNoDispUpdates, TRUE);\r
2871                 m_arShownList.RemoveAll();\r
2872                 for (DWORD i=0; i<m_logEntries.size(); ++i)\r
2873                 {\r
2874                         if (IsEntryInDateRange(i))\r
2875                                 m_arShownList.Add(m_logEntries[i]);\r
2876                 }\r
2877                 InterlockedExchange(&m_bNoDispUpdates, FALSE);\r
2878                 m_LogList.DeleteAllItems();\r
2879                 m_LogList.SetItemCountEx(ShownCountWithStopped());\r
2880                 m_LogList.RedrawItems(0, ShownCountWithStopped());\r
2881                 m_LogList.SetRedraw(false);\r
2882                 ResizeAllListCtrlCols();\r
2883                 m_LogList.SetRedraw(true);\r
2884                 theApp.DoWaitCursor(-1);\r
2885                 GetDlgItem(IDC_SEARCHEDIT)->ShowWindow(SW_HIDE);\r
2886                 GetDlgItem(IDC_SEARCHEDIT)->ShowWindow(SW_SHOW);\r
2887                 GetDlgItem(IDC_SEARCHEDIT)->SetFocus();\r
2888                 DialogEnableWindow(IDC_STATBUTTON, !(((m_bThreadRunning)||(m_arShownList.IsEmpty()))));\r
2889                 return;\r
2890         }\r
2891         if (Validate(m_sFilterText))\r
2892                 SetTimer(LOGFILTER_TIMER, 1000, NULL);\r
2893         else\r
2894                 KillTimer(LOGFILTER_TIMER);\r
2895 #endif\r
2896 }\r
2897 \r
2898 bool CLogDlg::ValidateRegexp(LPCTSTR regexp_str, tr1::wregex& pat, bool bMatchCase /* = false */)\r
2899 {\r
2900         try\r
2901         {\r
2902                 tr1::regex_constants::syntax_option_type type = tr1::regex_constants::ECMAScript;\r
2903                 if (!bMatchCase)\r
2904                         type |= tr1::regex_constants::icase;\r
2905                 pat = tr1::wregex(regexp_str, type);\r
2906                 return true;\r
2907         }\r
2908         catch (exception) {}\r
2909         return false;\r
2910 }\r
2911 \r
2912 bool CLogDlg::Validate(LPCTSTR string)\r
2913 {\r
2914         if (!m_bFilterWithRegex)\r
2915                 return true;\r
2916         tr1::wregex pat;\r
2917         return ValidateRegexp(string, pat, false);\r
2918 }\r
2919 \r
2920 void CLogDlg::RecalculateShownList(CPtrArray * pShownlist)\r
2921 {\r
2922 #if 0\r
2923         pShownlist->RemoveAll();\r
2924         tr1::wregex pat;//(_T("Remove"), tr1::regex_constants::icase);\r
2925         bool bRegex = false;\r
2926         if (m_bFilterWithRegex)\r
2927                 bRegex = ValidateRegexp(m_sFilterText, pat, false);\r
2928 \r
2929         tr1::regex_constants::match_flag_type flags = tr1::regex_constants::match_any;\r
2930         CString sRev;\r
2931         for (DWORD i=0; i<m_logEntries.size(); ++i)\r
2932         {\r
2933                 if ((bRegex)&&(m_bFilterWithRegex))\r
2934                 {\r
2935                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_BUGID))\r
2936                         {\r
2937                                 ATLTRACE(_T("bugID = \"%s\"\n"), (LPCTSTR)m_logEntries[i]->sBugIDs);\r
2938                                 if (regex_search(wstring((LPCTSTR)m_logEntries[i]->sBugIDs), pat, flags)&&IsEntryInDateRange(i))\r
2939                                 {\r
2940                                         pShownlist->Add(m_logEntries[i]);\r
2941                                         continue;\r
2942                                 }\r
2943                         }\r
2944                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_MESSAGES))\r
2945                         {\r
2946                                 ATLTRACE(_T("messge = \"%s\"\n"), (LPCTSTR)m_logEntries[i]->sMessage);\r
2947                                 if (regex_search(wstring((LPCTSTR)m_logEntries[i]->sMessage), pat, flags)&&IsEntryInDateRange(i))\r
2948                                 {\r
2949                                         pShownlist->Add(m_logEntries[i]);\r
2950                                         continue;\r
2951                                 }\r
2952                         }\r
2953                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_PATHS))\r
2954                         {\r
2955                                 LogChangedPathArray * cpatharray = m_logEntries[i]->pArChangedPaths;\r
2956 \r
2957                                 bool bGoing = true;\r
2958                                 for (INT_PTR cpPathIndex = 0; cpPathIndex<cpatharray->GetCount() && bGoing; ++cpPathIndex)\r
2959                                 {\r
2960                                         LogChangedPath * cpath = cpatharray->GetAt(cpPathIndex);\r
2961                                         if (regex_search(wstring((LPCTSTR)cpath->sCopyFromPath), pat, flags)&&IsEntryInDateRange(i))\r
2962                                         {\r
2963                                                 pShownlist->Add(m_logEntries[i]);\r
2964                                                 bGoing = false;\r
2965                                                 continue;\r
2966                                         }\r
2967                                         if (regex_search(wstring((LPCTSTR)cpath->sPath), pat, flags)&&IsEntryInDateRange(i))\r
2968                                         {\r
2969                                                 pShownlist->Add(m_logEntries[i]);\r
2970                                                 bGoing = false;\r
2971                                                 continue;\r
2972                                         }\r
2973                                         if (regex_search(wstring((LPCTSTR)cpath->GetAction()), pat, flags)&&IsEntryInDateRange(i))\r
2974                                         {\r
2975                                                 pShownlist->Add(m_logEntries[i]);\r
2976                                                 bGoing = false;\r
2977                                                 continue;\r
2978                                         }\r
2979                                 }\r
2980                                 if (!bGoing)\r
2981                                         continue;\r
2982                         }\r
2983                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_AUTHORS))\r
2984                         {\r
2985                                 if (regex_search(wstring((LPCTSTR)m_logEntries[i]->sAuthor), pat, flags)&&IsEntryInDateRange(i))\r
2986                                 {\r
2987                                         pShownlist->Add(m_logEntries[i]);\r
2988                                         continue;\r
2989                                 }\r
2990                         }\r
2991                         if ((m_nSelectedFilter == LOGFILTER_ALL)||(m_nSelectedFilter == LOGFILTER_REVS))\r
2992                         {\r
2993                                 sRev.Format(_T("%ld"), m_logEntries[i]->Rev);\r
2994                                 if (regex_search(wstring((LPCTSTR)sRev), pat, flags)&&IsEntryInDateRange(i))\r
2995                                 {\r
2996                                         pShownlist->Add(m_logEntries[i]);\r
2997                                         continue;\r
2998                                 }\r
2999                         }\r