OSDN Git Service

b616560eb2b26e9e9130344581147bc0512a7edb
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / AppUtils.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 "resource.h"\r
21 #include "TortoiseProc.h"\r
22 #include "PathUtils.h"\r
23 #include "AppUtils.h"\r
24 //#include "GitProperties.h"\r
25 #include "StringUtils.h"\r
26 #include "MessageBox.h"\r
27 #include "Registry.h"\r
28 #include "TGitPath.h"\r
29 #include "Git.h"\r
30 //#include "RepositoryBrowser.h"\r
31 //#include "BrowseFolder.h"\r
32 #include "UnicodeUtils.h"\r
33 #include "ExportDlg.h"\r
34 #include "ProgressDlg.h"\r
35 #include "GitAdminDir.h"\r
36 #include "ProgressDlg.h"\r
37 #include "BrowseFolder.h"\r
38 #include "DirFileEnum.h"\r
39 #include "MessageBox.h"\r
40 #include "GitStatus.h"\r
41 #include "CreateBranchTagDlg.h"\r
42 #include "GitSwitchDlg.h"\r
43 #include "ResetDlg.h"\r
44 \r
45 CAppUtils::CAppUtils(void)\r
46 {\r
47 }\r
48 \r
49 CAppUtils::~CAppUtils(void)\r
50 {\r
51 }\r
52 \r
53 bool CAppUtils::GetMimeType(const CTGitPath& file, CString& mimetype)\r
54 {\r
55 #if 0\r
56         GitProperties props(file, GitRev::REV_WC, false);\r
57         for (int i = 0; i < props.GetCount(); ++i)\r
58         {\r
59                 if (props.GetItemName(i).compare(_T("svn:mime-type"))==0)\r
60                 {\r
61                         mimetype = props.GetItemValue(i).c_str();\r
62                         return true;\r
63                 }\r
64         }\r
65 #endif\r
66         return false;\r
67 }\r
68 \r
69 BOOL CAppUtils::StartExtMerge(\r
70         const CTGitPath& basefile, const CTGitPath& theirfile, const CTGitPath& yourfile, const CTGitPath& mergedfile,\r
71         const CString& basename, const CString& theirname, const CString& yourname, const CString& mergedname, bool bReadOnly)\r
72 {\r
73 \r
74         CRegString regCom = CRegString(_T("Software\\TortoiseGit\\Merge"));\r
75         CString ext = mergedfile.GetFileExtension();\r
76         CString com = regCom;\r
77         bool bInternal = false;\r
78 \r
79         CString mimetype;\r
80         if (ext != "")\r
81         {\r
82                 // is there an extension specific merge tool?\r
83                 CRegString mergetool(_T("Software\\TortoiseGit\\MergeTools\\") + ext.MakeLower());\r
84                 if (CString(mergetool) != "")\r
85                 {\r
86                         com = mergetool;\r
87                 }\r
88         }\r
89         if (GetMimeType(yourfile, mimetype) || GetMimeType(theirfile, mimetype) || GetMimeType(basefile, mimetype))\r
90         {\r
91                 // is there a mime type specific merge tool?\r
92                 CRegString mergetool(_T("Software\\TortoiseGit\\MergeTools\\") + mimetype);\r
93                 if (CString(mergetool) != "")\r
94                 {\r
95                         com = mergetool;\r
96                 }\r
97         }\r
98         \r
99         if (com.IsEmpty()||(com.Left(1).Compare(_T("#"))==0))\r
100         {\r
101                 // use TortoiseMerge\r
102                 bInternal = true;\r
103                 CRegString tortoiseMergePath(_T("Software\\TortoiseGit\\TMergePath"), _T(""), false, HKEY_LOCAL_MACHINE);\r
104                 com = tortoiseMergePath;\r
105                 if (com.IsEmpty())\r
106                 {\r
107                         com = CPathUtils::GetAppDirectory();\r
108                         com += _T("TortoiseMerge.exe");\r
109                 }\r
110                 com = _T("\"") + com + _T("\"");\r
111                 com = com + _T(" /base:%base /theirs:%theirs /mine:%mine /merged:%merged");\r
112                 com = com + _T(" /basename:%bname /theirsname:%tname /minename:%yname /mergedname:%mname");\r
113         }\r
114         // check if the params are set. If not, just add the files to the command line\r
115         if ((com.Find(_T("%merged"))<0)&&(com.Find(_T("%base"))<0)&&(com.Find(_T("%theirs"))<0)&&(com.Find(_T("%mine"))<0))\r
116         {\r
117                 com += _T(" \"")+basefile.GetWinPathString()+_T("\"");\r
118                 com += _T(" \"")+theirfile.GetWinPathString()+_T("\"");\r
119                 com += _T(" \"")+yourfile.GetWinPathString()+_T("\"");\r
120                 com += _T(" \"")+mergedfile.GetWinPathString()+_T("\"");\r
121         }\r
122         if (basefile.IsEmpty())\r
123         {\r
124                 com.Replace(_T("/base:%base"), _T(""));\r
125                 com.Replace(_T("%base"), _T(""));               \r
126         }\r
127         else\r
128                 com.Replace(_T("%base"), _T("\"") + basefile.GetWinPathString() + _T("\""));\r
129         if (theirfile.IsEmpty())\r
130         {\r
131                 com.Replace(_T("/theirs:%theirs"), _T(""));\r
132                 com.Replace(_T("%theirs"), _T(""));\r
133         }\r
134         else\r
135                 com.Replace(_T("%theirs"), _T("\"") + theirfile.GetWinPathString() + _T("\""));\r
136         if (yourfile.IsEmpty())\r
137         {\r
138                 com.Replace(_T("/mine:%mine"), _T(""));\r
139                 com.Replace(_T("%mine"), _T(""));\r
140         }\r
141         else\r
142                 com.Replace(_T("%mine"), _T("\"") + yourfile.GetWinPathString() + _T("\""));\r
143         if (mergedfile.IsEmpty())\r
144         {\r
145                 com.Replace(_T("/merged:%merged"), _T(""));\r
146                 com.Replace(_T("%merged"), _T(""));\r
147         }\r
148         else\r
149                 com.Replace(_T("%merged"), _T("\"") + mergedfile.GetWinPathString() + _T("\""));\r
150         if (basename.IsEmpty())\r
151         {\r
152                 if (basefile.IsEmpty())\r
153                 {\r
154                         com.Replace(_T("/basename:%bname"), _T(""));\r
155                         com.Replace(_T("%bname"), _T(""));\r
156                 }\r
157                 else\r
158                 {\r
159                         com.Replace(_T("%bname"), _T("\"") + basefile.GetUIFileOrDirectoryName() + _T("\""));\r
160                 }\r
161         }\r
162         else\r
163                 com.Replace(_T("%bname"), _T("\"") + basename + _T("\""));\r
164         if (theirname.IsEmpty())\r
165         {\r
166                 if (theirfile.IsEmpty())\r
167                 {\r
168                         com.Replace(_T("/theirsname:%tname"), _T(""));\r
169                         com.Replace(_T("%tname"), _T(""));\r
170                 }\r
171                 else\r
172                 {\r
173                         com.Replace(_T("%tname"), _T("\"") + theirfile.GetUIFileOrDirectoryName() + _T("\""));\r
174                 }\r
175         }\r
176         else\r
177                 com.Replace(_T("%tname"), _T("\"") + theirname + _T("\""));\r
178         if (yourname.IsEmpty())\r
179         {\r
180                 if (yourfile.IsEmpty())\r
181                 {\r
182                         com.Replace(_T("/minename:%yname"), _T(""));\r
183                         com.Replace(_T("%yname"), _T(""));\r
184                 }\r
185                 else\r
186                 {\r
187                         com.Replace(_T("%yname"), _T("\"") + yourfile.GetUIFileOrDirectoryName() + _T("\""));\r
188                 }\r
189         }\r
190         else\r
191                 com.Replace(_T("%yname"), _T("\"") + yourname + _T("\""));\r
192         if (mergedname.IsEmpty())\r
193         {\r
194                 if (mergedfile.IsEmpty())\r
195                 {\r
196                         com.Replace(_T("/mergedname:%mname"), _T(""));\r
197                         com.Replace(_T("%mname"), _T(""));\r
198                 }\r
199                 else\r
200                 {\r
201                         com.Replace(_T("%mname"), _T("\"") + mergedfile.GetUIFileOrDirectoryName() + _T("\""));\r
202                 }\r
203         }\r
204         else\r
205                 com.Replace(_T("%mname"), _T("\"") + mergedname + _T("\""));\r
206 \r
207         if ((bReadOnly)&&(bInternal))\r
208                 com += _T(" /readonly");\r
209 \r
210         if(!LaunchApplication(com, IDS_ERR_EXTMERGESTART, false))\r
211         {\r
212                 return FALSE;\r
213         }\r
214 \r
215         return TRUE;\r
216 }\r
217 \r
218 BOOL CAppUtils::StartExtPatch(const CTGitPath& patchfile, const CTGitPath& dir, const CString& sOriginalDescription, const CString& sPatchedDescription, BOOL bReversed, BOOL bWait)\r
219 {\r
220         CString viewer;\r
221         // use TortoiseMerge\r
222         viewer = CPathUtils::GetAppDirectory();\r
223         viewer += _T("TortoiseMerge.exe");\r
224 \r
225         viewer = _T("\"") + viewer + _T("\"");\r
226         viewer = viewer + _T(" /diff:\"") + patchfile.GetWinPathString() + _T("\"");\r
227         viewer = viewer + _T(" /patchpath:\"") + dir.GetWinPathString() + _T("\"");\r
228         if (bReversed)\r
229                 viewer += _T(" /reversedpatch");\r
230         if (!sOriginalDescription.IsEmpty())\r
231                 viewer = viewer + _T(" /patchoriginal:\"") + sOriginalDescription + _T("\"");\r
232         if (!sPatchedDescription.IsEmpty())\r
233                 viewer = viewer + _T(" /patchpatched:\"") + sPatchedDescription + _T("\"");\r
234         if(!LaunchApplication(viewer, IDS_ERR_DIFFVIEWSTART, !!bWait))\r
235         {\r
236                 return FALSE;\r
237         }\r
238         return TRUE;\r
239 }\r
240 \r
241 CString CAppUtils::PickDiffTool(const CTGitPath& file1, const CTGitPath& file2)\r
242 {\r
243         // Is there a mime type specific diff tool?\r
244         CString mimetype;\r
245         if (GetMimeType(file1, mimetype) ||  GetMimeType(file2, mimetype))\r
246         {\r
247                 CString difftool = CRegString(_T("Software\\TortoiseGit\\DiffTools\\") + mimetype);\r
248                 if (!difftool.IsEmpty())\r
249                         return difftool;\r
250         }\r
251         \r
252         // Is there an extension specific diff tool?\r
253         CString ext = file2.GetFileExtension().MakeLower();\r
254         if (!ext.IsEmpty())\r
255         {\r
256                 CString difftool = CRegString(_T("Software\\TortoiseGit\\DiffTools\\") + ext);\r
257                 if (!difftool.IsEmpty())\r
258                         return difftool;\r
259                 // Maybe we should use TortoiseIDiff?\r
260                 if ((ext == _T(".jpg")) || (ext == _T(".jpeg")) ||\r
261                         (ext == _T(".bmp")) || (ext == _T(".gif"))  ||\r
262                         (ext == _T(".png")) || (ext == _T(".ico"))  ||\r
263                         (ext == _T(".dib")) || (ext == _T(".emf")))\r
264                 {\r
265                         return\r
266                                 _T("\"") + CPathUtils::GetAppDirectory() + _T("TortoiseIDiff.exe") + _T("\"") +\r
267                                 _T(" /left:%base /right:%mine /lefttitle:%bname /righttitle:%yname");\r
268                 }\r
269         }\r
270         \r
271         // Finally, pick a generic external diff tool\r
272         CString difftool = CRegString(_T("Software\\TortoiseGit\\Diff"));\r
273         return difftool;\r
274 }\r
275 \r
276 bool CAppUtils::StartExtDiff(\r
277         const CString& file1,  const CString& file2,\r
278         const CString& sName1, const CString& sName2, \r
279         const DiffFlags& flags)\r
280 {\r
281         CString viewer;\r
282 \r
283         CRegDWORD blamediff(_T("Software\\TortoiseGit\\DiffBlamesWithTortoiseMerge"), FALSE);\r
284         if (!flags.bBlame || !(DWORD)blamediff)\r
285         {\r
286                 viewer = PickDiffTool(file1, file2);\r
287                 // If registry entry for a diff program is commented out, use TortoiseMerge.\r
288                 bool bCommentedOut = viewer.Left(1) == _T("#");\r
289                 if (flags.bAlternativeTool)\r
290                 {\r
291                         // Invert external vs. internal diff tool selection.\r
292                         if (bCommentedOut)\r
293                                 viewer.Delete(0); // uncomment\r
294                         else\r
295                                 viewer = "";\r
296                 }\r
297                 else if (bCommentedOut)\r
298                         viewer = "";\r
299         }\r
300 \r
301         bool bInternal = viewer.IsEmpty();\r
302         if (bInternal)\r
303         {\r
304                 viewer =\r
305                         _T("\"") + CPathUtils::GetAppDirectory() + _T("TortoiseMerge.exe") + _T("\"") +\r
306                         _T(" /base:%base /mine:%mine /basename:%bname /minename:%yname");\r
307                 if (flags.bBlame)\r
308                         viewer += _T(" /blame");\r
309         }\r
310         // check if the params are set. If not, just add the files to the command line\r
311         if ((viewer.Find(_T("%base"))<0)&&(viewer.Find(_T("%mine"))<0))\r
312         {\r
313                 viewer += _T(" \"")+file1+_T("\"");\r
314                 viewer += _T(" \"")+file2+_T("\"");\r
315         }\r
316         if (viewer.Find(_T("%base")) >= 0)\r
317         {\r
318                 viewer.Replace(_T("%base"),  _T("\"")+file1+_T("\""));\r
319         }\r
320         if (viewer.Find(_T("%mine")) >= 0)\r
321         {\r
322                 viewer.Replace(_T("%mine"),  _T("\"")+file2+_T("\""));\r
323         }\r
324 \r
325         if (sName1.IsEmpty())\r
326                 viewer.Replace(_T("%bname"), _T("\"") + file1 + _T("\""));\r
327         else\r
328                 viewer.Replace(_T("%bname"), _T("\"") + sName1 + _T("\""));\r
329 \r
330         if (sName2.IsEmpty())\r
331                 viewer.Replace(_T("%yname"), _T("\"") + file2 + _T("\""));\r
332         else\r
333                 viewer.Replace(_T("%yname"), _T("\"") + sName2 + _T("\""));\r
334 \r
335         if (flags.bReadOnly && bInternal)\r
336                 viewer += _T(" /readonly");\r
337 \r
338         return LaunchApplication(viewer, IDS_ERR_EXTDIFFSTART, flags.bWait);\r
339 }\r
340 \r
341 BOOL CAppUtils::StartExtDiffProps(const CTGitPath& file1, const CTGitPath& file2, const CString& sName1, const CString& sName2, BOOL bWait, BOOL bReadOnly)\r
342 {\r
343         CRegString diffpropsexe(_T("Software\\TortoiseGit\\DiffProps"));\r
344         CString viewer = diffpropsexe;\r
345         bool bInternal = false;\r
346         if (viewer.IsEmpty()||(viewer.Left(1).Compare(_T("#"))==0))\r
347         {\r
348                 //no registry entry (or commented out) for a diff program\r
349                 //use TortoiseMerge\r
350                 bInternal = true;\r
351                 viewer = CPathUtils::GetAppDirectory();\r
352                 viewer += _T("TortoiseMerge.exe");\r
353                 viewer = _T("\"") + viewer + _T("\"");\r
354                 viewer = viewer + _T(" /base:%base /mine:%mine /basename:%bname /minename:%yname");\r
355         }\r
356         // check if the params are set. If not, just add the files to the command line\r
357         if ((viewer.Find(_T("%base"))<0)&&(viewer.Find(_T("%mine"))<0))\r
358         {\r
359                 viewer += _T(" \"")+file1.GetWinPathString()+_T("\"");\r
360                 viewer += _T(" \"")+file2.GetWinPathString()+_T("\"");\r
361         }\r
362         if (viewer.Find(_T("%base")) >= 0)\r
363         {\r
364                 viewer.Replace(_T("%base"),  _T("\"")+file1.GetWinPathString()+_T("\""));\r
365         }\r
366         if (viewer.Find(_T("%mine")) >= 0)\r
367         {\r
368                 viewer.Replace(_T("%mine"),  _T("\"")+file2.GetWinPathString()+_T("\""));\r
369         }\r
370 \r
371         if (sName1.IsEmpty())\r
372                 viewer.Replace(_T("%bname"), _T("\"") + file1.GetUIFileOrDirectoryName() + _T("\""));\r
373         else\r
374                 viewer.Replace(_T("%bname"), _T("\"") + sName1 + _T("\""));\r
375 \r
376         if (sName2.IsEmpty())\r
377                 viewer.Replace(_T("%yname"), _T("\"") + file2.GetUIFileOrDirectoryName() + _T("\""));\r
378         else\r
379                 viewer.Replace(_T("%yname"), _T("\"") + sName2 + _T("\""));\r
380 \r
381         if ((bReadOnly)&&(bInternal))\r
382                 viewer += _T(" /readonly");\r
383 \r
384         if(!LaunchApplication(viewer, IDS_ERR_EXTDIFFSTART, !!bWait))\r
385         {\r
386                 return FALSE;\r
387         }\r
388         return TRUE;\r
389 }\r
390 \r
391 BOOL CAppUtils::StartUnifiedDiffViewer(const CString& patchfile, const CString& title, BOOL bWait)\r
392 {\r
393         CString viewer;\r
394         CRegString v = CRegString(_T("Software\\TortoiseGit\\DiffViewer"));\r
395         viewer = v;\r
396         if (viewer.IsEmpty() || (viewer.Left(1).Compare(_T("#"))==0))\r
397         {\r
398                 // use TortoiseUDiff\r
399                 viewer = CPathUtils::GetAppDirectory();\r
400                 viewer += _T("TortoiseUDiff.exe");\r
401                 // enquote the path to TortoiseUDiff\r
402                 viewer = _T("\"") + viewer + _T("\"");\r
403                 // add the params\r
404                 viewer = viewer + _T(" /patchfile:%1 /title:\"%title\"");\r
405 \r
406         }\r
407         if (viewer.Find(_T("%1"))>=0)\r
408         {\r
409                 if (viewer.Find(_T("\"%1\"")) >= 0)\r
410                         viewer.Replace(_T("%1"), patchfile);\r
411                 else\r
412                         viewer.Replace(_T("%1"), _T("\"") + patchfile + _T("\""));\r
413         }\r
414         else\r
415                 viewer += _T(" \"") + patchfile + _T("\"");\r
416         if (viewer.Find(_T("%title")) >= 0)\r
417         {\r
418                 viewer.Replace(_T("%title"), title);\r
419         }\r
420 \r
421         if(!LaunchApplication(viewer, IDS_ERR_DIFFVIEWSTART, !!bWait))\r
422         {\r
423                 return FALSE;\r
424         }\r
425         return TRUE;\r
426 }\r
427 \r
428 BOOL CAppUtils::StartTextViewer(CString file)\r
429 {\r
430         CString viewer;\r
431         CRegString txt = CRegString(_T(".txt\\"), _T(""), FALSE, HKEY_CLASSES_ROOT);\r
432         viewer = txt;\r
433         viewer = viewer + _T("\\Shell\\Open\\Command\\");\r
434         CRegString txtexe = CRegString(viewer, _T(""), FALSE, HKEY_CLASSES_ROOT);\r
435         viewer = txtexe;\r
436 \r
437         DWORD len = ExpandEnvironmentStrings(viewer, NULL, 0);\r
438         TCHAR * buf = new TCHAR[len+1];\r
439         ExpandEnvironmentStrings(viewer, buf, len);\r
440         viewer = buf;\r
441         delete [] buf;\r
442         len = ExpandEnvironmentStrings(file, NULL, 0);\r
443         buf = new TCHAR[len+1];\r
444         ExpandEnvironmentStrings(file, buf, len);\r
445         file = buf;\r
446         delete [] buf;\r
447         file = _T("\"")+file+_T("\"");\r
448         if (viewer.IsEmpty())\r
449         {\r
450                 OPENFILENAME ofn = {0};                         // common dialog box structure\r
451                 TCHAR szFile[MAX_PATH] = {0};           // buffer for file name. Explorer can't handle paths longer than MAX_PATH.\r
452                 // Initialize OPENFILENAME\r
453                 ofn.lStructSize = sizeof(OPENFILENAME);\r
454                 ofn.hwndOwner = NULL;\r
455                 ofn.lpstrFile = szFile;\r
456                 ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);\r
457                 CString sFilter;\r
458                 sFilter.LoadString(IDS_PROGRAMSFILEFILTER);\r
459                 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];\r
460                 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);\r
461                 // Replace '|' delimiters with '\0's\r
462                 TCHAR *ptr = pszFilters + _tcslen(pszFilters);  //set ptr at the NULL\r
463                 while (ptr != pszFilters)\r
464                 {\r
465                         if (*ptr == '|')\r
466                                 *ptr = '\0';\r
467                         ptr--;\r
468                 }\r
469                 ofn.lpstrFilter = pszFilters;\r
470                 ofn.nFilterIndex = 1;\r
471                 ofn.lpstrFileTitle = NULL;\r
472                 ofn.nMaxFileTitle = 0;\r
473                 ofn.lpstrInitialDir = NULL;\r
474                 CString temp;\r
475                 temp.LoadString(IDS_UTILS_SELECTTEXTVIEWER);\r
476                 CStringUtils::RemoveAccelerators(temp);\r
477                 ofn.lpstrTitle = temp;\r
478                 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;\r
479 \r
480                 // Display the Open dialog box. \r
481 \r
482                 if (GetOpenFileName(&ofn)==TRUE)\r
483                 {\r
484                         delete [] pszFilters;\r
485                         viewer = CString(ofn.lpstrFile);\r
486                 }\r
487                 else\r
488                 {\r
489                         delete [] pszFilters;\r
490                         return FALSE;\r
491                 }\r
492         }\r
493         if (viewer.Find(_T("\"%1\"")) >= 0)\r
494         {\r
495                 viewer.Replace(_T("\"%1\""), file);\r
496         }\r
497         else if (viewer.Find(_T("%1")) >= 0)\r
498         {\r
499                 viewer.Replace(_T("%1"),  file);\r
500         }\r
501         else\r
502         {\r
503                 viewer += _T(" ");\r
504                 viewer += file;\r
505         }\r
506 \r
507         if(!LaunchApplication(viewer, IDS_ERR_TEXTVIEWSTART, false))\r
508         {\r
509                 return FALSE;\r
510         }\r
511         return TRUE;\r
512 }\r
513 \r
514 BOOL CAppUtils::CheckForEmptyDiff(const CTGitPath& sDiffPath)\r
515 {\r
516         DWORD length = 0;\r
517         HANDLE hFile = ::CreateFile(sDiffPath.GetWinPath(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);\r
518         if (hFile == INVALID_HANDLE_VALUE)\r
519                 return TRUE;\r
520         length = ::GetFileSize(hFile, NULL);\r
521         ::CloseHandle(hFile);\r
522         if (length < 4)\r
523                 return TRUE;\r
524         return FALSE;\r
525 \r
526 }\r
527 \r
528 void CAppUtils::CreateFontForLogs(CFont& fontToCreate)\r
529 {\r
530         LOGFONT logFont;\r
531         HDC hScreenDC = ::GetDC(NULL);\r
532         logFont.lfHeight         = -MulDiv((DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8), GetDeviceCaps(hScreenDC, LOGPIXELSY), 72);\r
533         ::ReleaseDC(NULL, hScreenDC);\r
534         logFont.lfWidth          = 0;\r
535         logFont.lfEscapement     = 0;\r
536         logFont.lfOrientation    = 0;\r
537         logFont.lfWeight         = FW_NORMAL;\r
538         logFont.lfItalic         = 0;\r
539         logFont.lfUnderline      = 0;\r
540         logFont.lfStrikeOut      = 0;\r
541         logFont.lfCharSet        = DEFAULT_CHARSET;\r
542         logFont.lfOutPrecision   = OUT_DEFAULT_PRECIS;\r
543         logFont.lfClipPrecision  = CLIP_DEFAULT_PRECIS;\r
544         logFont.lfQuality        = DRAFT_QUALITY;\r
545         logFont.lfPitchAndFamily = FF_DONTCARE | FIXED_PITCH;\r
546         _tcscpy_s(logFont.lfFaceName, 32, (LPCTSTR)(CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")));\r
547         VERIFY(fontToCreate.CreateFontIndirect(&logFont));\r
548 }\r
549 \r
550 bool CAppUtils::LaunchApplication(const CString& sCommandLine, UINT idErrMessageFormat, bool bWaitForStartup)\r
551 {\r
552         STARTUPINFO startup;\r
553         PROCESS_INFORMATION process;\r
554         memset(&startup, 0, sizeof(startup));\r
555         startup.cb = sizeof(startup);\r
556         memset(&process, 0, sizeof(process));\r
557 \r
558         CString cleanCommandLine(sCommandLine);\r
559 \r
560         if (CreateProcess(NULL, const_cast<TCHAR*>((LPCTSTR)cleanCommandLine), NULL, NULL, FALSE, 0, 0, sOrigCWD, &startup, &process)==0)\r
561         {\r
562                 if(idErrMessageFormat != 0)\r
563                 {\r
564                         LPVOID lpMsgBuf;\r
565                         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
566                                 FORMAT_MESSAGE_FROM_SYSTEM | \r
567                                 FORMAT_MESSAGE_IGNORE_INSERTS,\r
568                                 NULL,\r
569                                 GetLastError(),\r
570                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
571                                 (LPTSTR) &lpMsgBuf,\r
572                                 0,\r
573                                 NULL \r
574                                 );\r
575                         CString temp;\r
576                         temp.Format(idErrMessageFormat, lpMsgBuf);\r
577                         CMessageBox::Show(NULL, temp, _T("TortoiseGit"), MB_OK | MB_ICONINFORMATION);\r
578                         LocalFree( lpMsgBuf );\r
579                 }\r
580                 return false;\r
581         }\r
582 \r
583         if (bWaitForStartup)\r
584         {\r
585                 WaitForInputIdle(process.hProcess, 10000);\r
586         }\r
587 \r
588         CloseHandle(process.hThread);\r
589         CloseHandle(process.hProcess);\r
590         return true;\r
591 }\r
592 \r
593 /**\r
594 * Launch the external blame viewer\r
595 */\r
596 bool CAppUtils::LaunchTortoiseBlame(const CString& sBlameFile,CString Rev,const CString& sParams)\r
597 {\r
598         CString viewer = CPathUtils::GetAppDirectory();\r
599         viewer += _T("TortoiseGitBlame.exe");\r
600         viewer += _T(" \"") + sBlameFile + _T("\"");\r
601         //viewer += _T(" \"") + sLogFile + _T("\"");\r
602         //viewer += _T(" \"") + sOriginalFile + _T("\"");\r
603         if(!Rev.IsEmpty())\r
604                 viewer += CString(_T(" /rev:"))+Rev;\r
605         viewer += _T(" ")+sParams;\r
606         \r
607         return LaunchApplication(viewer, IDS_ERR_EXTDIFFSTART, false);\r
608 }\r
609 \r
610 bool CAppUtils::FormatTextInRichEditControl(CWnd * pWnd)\r
611 {\r
612         CString sText;\r
613         if (pWnd == NULL)\r
614                 return false;\r
615         bool bStyled = false;\r
616         pWnd->GetWindowText(sText);\r
617         // the rich edit control doesn't count the CR char!\r
618         // to be exact: CRLF is treated as one char.\r
619         sText.Replace(_T("\r"), _T(""));\r
620 \r
621         // style each line separately\r
622         int offset = 0;\r
623         int nNewlinePos;\r
624         do \r
625         {\r
626                 nNewlinePos = sText.Find('\n', offset);\r
627                 CString sLine = sText.Mid(offset);\r
628                 if (nNewlinePos>=0)\r
629                         sLine = sLine.Left(nNewlinePos-offset);\r
630                 int start = 0;\r
631                 int end = 0;\r
632                 while (FindStyleChars(sLine, '*', start, end))\r
633                 {\r
634                         CHARRANGE range = {(LONG)start+offset, (LONG)end+offset};\r
635                         pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);\r
636                         CHARFORMAT2 format;\r
637                         SecureZeroMemory(&format, sizeof(CHARFORMAT2));\r
638                         format.cbSize = sizeof(CHARFORMAT2);\r
639                         format.dwMask = CFM_BOLD;\r
640                         format.dwEffects = CFE_BOLD;\r
641                         pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);\r
642                         bStyled = true;\r
643                         start = end;\r
644                 }\r
645                 start = 0;\r
646                 end = 0;\r
647                 while (FindStyleChars(sLine, '^', start, end))\r
648                 {\r
649                         CHARRANGE range = {(LONG)start+offset, (LONG)end+offset};\r
650                         pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);\r
651                         CHARFORMAT2 format;\r
652                         SecureZeroMemory(&format, sizeof(CHARFORMAT2));\r
653                         format.cbSize = sizeof(CHARFORMAT2);\r
654                         format.dwMask = CFM_ITALIC;\r
655                         format.dwEffects = CFE_ITALIC;\r
656                         pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);\r
657                         bStyled = true;\r
658                         start = end;\r
659                 }\r
660                 start = 0;\r
661                 end = 0;\r
662                 while (FindStyleChars(sLine, '_', start, end))\r
663                 {\r
664                         CHARRANGE range = {(LONG)start+offset, (LONG)end+offset};\r
665                         pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);\r
666                         CHARFORMAT2 format;\r
667                         SecureZeroMemory(&format, sizeof(CHARFORMAT2));\r
668                         format.cbSize = sizeof(CHARFORMAT2);\r
669                         format.dwMask = CFM_UNDERLINE;\r
670                         format.dwEffects = CFE_UNDERLINE;\r
671                         pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);\r
672                         bStyled = true;\r
673                         start = end;\r
674                 }\r
675                 offset = nNewlinePos+1;\r
676         } while(nNewlinePos>=0);\r
677         return bStyled; \r
678 }\r
679 \r
680 bool CAppUtils::FindStyleChars(const CString& sText, TCHAR stylechar, int& start, int& end)\r
681 {\r
682         int i=start;\r
683         bool bFoundMarker = false;\r
684         // find a starting marker\r
685         while (sText[i] != 0)\r
686         {\r
687                 if (sText[i] == stylechar)\r
688                 {\r
689                         if (((i+1)<sText.GetLength())&&(IsCharAlphaNumeric(sText[i+1])) &&\r
690                                 (((i>0)&&(!IsCharAlphaNumeric(sText[i-1])))||(i==0)))\r
691                         {\r
692                                 start = i+1;\r
693                                 i++;\r
694                                 bFoundMarker = true;\r
695                                 break;\r
696                         }\r
697                 }\r
698                 i++;\r
699         }\r
700         if (!bFoundMarker)\r
701                 return false;\r
702         // find ending marker\r
703         bFoundMarker = false;\r
704         while (sText[i] != 0)\r
705         {\r
706                 if (sText[i] == stylechar)\r
707                 {\r
708                         if ((IsCharAlphaNumeric(sText[i-1])) &&\r
709                                 ((((i+1)<sText.GetLength())&&(!IsCharAlphaNumeric(sText[i+1])))||(i+1)==sText.GetLength()))\r
710                         {\r
711                                 end = i;\r
712                                 i++;\r
713                                 bFoundMarker = true;\r
714                                 break;\r
715                         }\r
716                 }\r
717                 i++;\r
718         }\r
719         return bFoundMarker;\r
720 }\r
721 \r
722 bool CAppUtils::BrowseRepository(CHistoryCombo& combo, CWnd * pParent, GitRev& rev)\r
723 {\r
724 #if 0\r
725         CString strUrl;\r
726         combo.GetWindowText(strUrl);\r
727         strUrl.Replace('\\', '/');\r
728         strUrl.Replace(_T("%"), _T("%25"));\r
729         strUrl = CUnicodeUtils::GetUnicode(CPathUtils::PathEscape(CUnicodeUtils::GetUTF8(strUrl)));\r
730         if (strUrl.Left(7) == _T("file://"))\r
731         {\r
732                 CString strFile(strUrl);\r
733                 Git::UrlToPath(strFile);\r
734 \r
735                 Git svn;\r
736                 if (svn.IsRepository(CTGitPath(strFile)))\r
737                 {\r
738                         // browse repository - show repository browser\r
739                         Git::preparePath(strUrl);\r
740                         CRepositoryBrowser browser(strUrl, rev, pParent);\r
741                         if (browser.DoModal() == IDOK)\r
742                         {\r
743                                 combo.SetCurSel(-1);\r
744                                 combo.SetWindowText(browser.GetPath());\r
745                                 rev = browser.GetRevision();\r
746                                 return true;\r
747                         }\r
748                 }\r
749                 else\r
750                 {\r
751                         // browse local directories\r
752                         CBrowseFolder folderBrowser;\r
753                         folderBrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;\r
754                         // remove the 'file:///' so the shell can recognize the local path\r
755                         Git::UrlToPath(strUrl);\r
756                         if (folderBrowser.Show(pParent->GetSafeHwnd(), strUrl) == CBrowseFolder::OK)\r
757                         {\r
758                                 Git::PathToUrl(strUrl);\r
759 \r
760                                 combo.SetCurSel(-1);\r
761                                 combo.SetWindowText(strUrl);\r
762                                 return true;\r
763                         }\r
764                 }\r
765         }\r
766         else if ((strUrl.Left(7) == _T("http://")\r
767                 ||(strUrl.Left(8) == _T("https://"))\r
768                 ||(strUrl.Left(6) == _T("svn://"))\r
769                 ||(strUrl.Left(4) == _T("svn+"))) && strUrl.GetLength() > 6)\r
770         {\r
771                 // browse repository - show repository browser\r
772                 CRepositoryBrowser browser(strUrl, rev, pParent);\r
773                 if (browser.DoModal() == IDOK)\r
774                 {\r
775                         combo.SetCurSel(-1);\r
776                         combo.SetWindowText(browser.GetPath());\r
777                         rev = browser.GetRevision();\r
778                         return true;\r
779                 }\r
780         }\r
781         else\r
782         {\r
783                 // browse local directories\r
784                 CBrowseFolder folderBrowser;\r
785                 folderBrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;\r
786                 if (folderBrowser.Show(pParent->GetSafeHwnd(), strUrl) == CBrowseFolder::OK)\r
787                 {\r
788                         Git::PathToUrl(strUrl);\r
789 \r
790                         combo.SetCurSel(-1);\r
791                         combo.SetWindowText(strUrl);\r
792                         return true;\r
793                 }\r
794         }\r
795 #endif\r
796         return false;\r
797 }\r
798 \r
799 bool CAppUtils::FileOpenSave(CString& path, int * filterindex, UINT title, UINT filter, bool bOpen, HWND hwndOwner)\r
800 {\r
801         OPENFILENAME ofn = {0};                         // common dialog box structure\r
802         TCHAR szFile[MAX_PATH] = {0};           // buffer for file name. Explorer can't handle paths longer than MAX_PATH.\r
803         ofn.lStructSize = sizeof(OPENFILENAME);\r
804         ofn.hwndOwner = hwndOwner;\r
805         _tcscpy_s(szFile, MAX_PATH, (LPCTSTR)path);\r
806         ofn.lpstrFile = szFile;\r
807         ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);\r
808         CString sFilter;\r
809         TCHAR * pszFilters = NULL;\r
810         if (filter)\r
811         {\r
812                 sFilter.LoadString(filter);\r
813                 pszFilters = new TCHAR[sFilter.GetLength()+4];\r
814                 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);\r
815                 // Replace '|' delimiters with '\0's\r
816                 TCHAR *ptr = pszFilters + _tcslen(pszFilters);  //set ptr at the NULL\r
817                 while (ptr != pszFilters)\r
818                 {\r
819                         if (*ptr == '|')\r
820                                 *ptr = '\0';\r
821                         ptr--;\r
822                 }\r
823                 ofn.lpstrFilter = pszFilters;\r
824         }\r
825         ofn.nFilterIndex = 1;\r
826         ofn.lpstrFileTitle = NULL;\r
827         ofn.nMaxFileTitle = 0;\r
828         ofn.lpstrInitialDir = NULL;\r
829         CString temp;\r
830         if (title)\r
831         {\r
832                 temp.LoadString(title);\r
833                 CStringUtils::RemoveAccelerators(temp);\r
834         }\r
835         ofn.lpstrTitle = temp;\r
836         if (bOpen)\r
837                 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER;\r
838         else\r
839                 ofn.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER;\r
840 \r
841 \r
842         // Display the Open dialog box. \r
843         bool bRet = false;\r
844         if (bOpen)\r
845         {\r
846                 bRet = !!GetOpenFileName(&ofn);\r
847         }\r
848         else\r
849         {\r
850                 bRet = !!GetSaveFileName(&ofn);\r
851         }\r
852         if (bRet)\r
853         {\r
854                 if (pszFilters)\r
855                         delete [] pszFilters;\r
856                 path = CString(ofn.lpstrFile);\r
857                 if (filterindex)\r
858                         *filterindex = ofn.nFilterIndex;\r
859                 return true;\r
860         }\r
861         if (pszFilters)\r
862                 delete [] pszFilters;\r
863         return false;\r
864 }\r
865 \r
866 bool CAppUtils::SetListCtrlBackgroundImage(HWND hListCtrl, UINT nID, int width /* = 128 */, int height /* = 128 */)\r
867 {\r
868         ListView_SetTextBkColor(hListCtrl, CLR_NONE);\r
869         COLORREF bkColor = ListView_GetBkColor(hListCtrl);\r
870         // create a bitmap from the icon\r
871         HICON hIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(nID), IMAGE_ICON, width, height, LR_DEFAULTCOLOR);\r
872         if (!hIcon)\r
873                 return false;\r
874 \r
875         RECT rect = {0};\r
876         rect.right = width;\r
877         rect.bottom = height;\r
878         HBITMAP bmp = NULL;\r
879 \r
880         HWND desktop = ::GetDesktopWindow();\r
881         if (desktop)\r
882         {\r
883                 HDC screen_dev = ::GetDC(desktop);\r
884                 if (screen_dev)\r
885                 {\r
886                         // Create a compatible DC\r
887                         HDC dst_hdc = ::CreateCompatibleDC(screen_dev);\r
888                         if (dst_hdc)\r
889                         {\r
890                                 // Create a new bitmap of icon size\r
891                                 bmp = ::CreateCompatibleBitmap(screen_dev, rect.right, rect.bottom);\r
892                                 if (bmp)\r
893                                 {\r
894                                         // Select it into the compatible DC\r
895                                         HBITMAP old_dst_bmp = (HBITMAP)::SelectObject(dst_hdc, bmp);\r
896                                         // Fill the background of the compatible DC with the given color\r
897                                         ::SetBkColor(dst_hdc, bkColor);\r
898                                         ::ExtTextOut(dst_hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);\r
899 \r
900                                         // Draw the icon into the compatible DC\r
901                                         ::DrawIconEx(dst_hdc, 0, 0, hIcon, rect.right, rect.bottom, 0, NULL, DI_NORMAL);\r
902                                         ::SelectObject(dst_hdc, old_dst_bmp);\r
903                                 }\r
904                                 ::DeleteDC(dst_hdc);\r
905                         }\r
906                 }\r
907                 ::ReleaseDC(desktop, screen_dev); \r
908         }\r
909 \r
910         // Restore settings\r
911         DestroyIcon(hIcon);\r
912 \r
913         if (bmp == NULL)\r
914                 return false;\r
915 \r
916         LVBKIMAGE lv;\r
917         lv.ulFlags = LVBKIF_TYPE_WATERMARK;\r
918         lv.hbm = bmp;\r
919         lv.xOffsetPercent = 100;\r
920         lv.yOffsetPercent = 100;\r
921         ListView_SetBkImage(hListCtrl, &lv);\r
922         return true;\r
923 }\r
924 \r
925 CString CAppUtils::GetProjectNameFromURL(CString url)\r
926 {\r
927         CString name;\r
928         while (name.IsEmpty() || (name.CompareNoCase(_T("branches"))==0) ||\r
929                 (name.CompareNoCase(_T("tags"))==0) ||\r
930                 (name.CompareNoCase(_T("trunk"))==0))\r
931         {\r
932                 name = url.Mid(url.ReverseFind('/')+1);\r
933                 url = url.Left(url.ReverseFind('/'));\r
934         }\r
935         if ((name.Compare(_T("svn")) == 0)||(name.Compare(_T("svnroot")) == 0))\r
936         {\r
937                 // a name of svn or svnroot indicates that it's not really the project name. In that\r
938                 // case, we try the first part of the URL\r
939                 // of course, this won't work in all cases (but it works for Google project hosting)\r
940                 url.Replace(_T("http://"), _T(""));\r
941                 url.Replace(_T("https://"), _T(""));\r
942                 url.Replace(_T("svn://"), _T(""));\r
943                 url.Replace(_T("svn+ssh://"), _T(""));\r
944                 url.TrimLeft(_T("/"));\r
945                 name = url.Left(url.Find('.'));\r
946         }\r
947         return name;\r
948 }\r
949 \r
950 bool CAppUtils::StartShowUnifiedDiff(HWND hWnd, const CTGitPath& url1, const git_revnum_t& rev1, \r
951                                                                                                 const CTGitPath& url2, const git_revnum_t& rev2, \r
952                                                                          //const GitRev& peg /* = GitRev */, const GitRev& headpeg /* = GitRev */,  \r
953                                                                                                 bool bAlternateDiff /* = false */, bool bIgnoreAncestry /* = false */, bool /* blame = false */)\r
954 {\r
955 \r
956         CString tempfile=GetTempFile();\r
957         CString cmd;\r
958         if(rev1 == GitRev::GetWorkingCopy())\r
959         {\r
960                 cmd.Format(_T("git.exe diff --stat -p %s"),rev2);\r
961         }else\r
962         {       \r
963                 cmd.Format(_T("git.exe diff-tree -r -p --stat %s %s"),rev1,rev2);\r
964         }\r
965         g_Git.RunLogFile(cmd,tempfile);\r
966         CAppUtils::StartUnifiedDiffViewer(tempfile,rev1.Left(6)+_T(":")+rev2.Left(6));\r
967 \r
968 \r
969 #if 0\r
970         CString sCmd;\r
971         sCmd.Format(_T("%s /command:showcompare /unified"),\r
972                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")));\r
973         sCmd += _T(" /url1:\"") + url1.GetGitPathString() + _T("\"");\r
974         if (rev1.IsValid())\r
975                 sCmd += _T(" /revision1:") + rev1.ToString();\r
976         sCmd += _T(" /url2:\"") + url2.GetGitPathString() + _T("\"");\r
977         if (rev2.IsValid())\r
978                 sCmd += _T(" /revision2:") + rev2.ToString();\r
979         if (peg.IsValid())\r
980                 sCmd += _T(" /pegrevision:") + peg.ToString();\r
981         if (headpeg.IsValid())\r
982                 sCmd += _T(" /headpegrevision:") + headpeg.ToString();\r
983 \r
984         if (bAlternateDiff)\r
985                 sCmd += _T(" /alternatediff");\r
986 \r
987         if (bIgnoreAncestry)\r
988                 sCmd += _T(" /ignoreancestry");\r
989 \r
990         if (hWnd)\r
991         {\r
992                 sCmd += _T(" /hwnd:");\r
993                 TCHAR buf[30];\r
994                 _stprintf_s(buf, 30, _T("%d"), hWnd);\r
995                 sCmd += buf;\r
996         }\r
997 \r
998         return CAppUtils::LaunchApplication(sCmd, NULL, false);\r
999 #endif\r
1000         return TRUE;\r
1001 }\r
1002 \r
1003 bool CAppUtils::StartShowCompare(HWND hWnd, const CTGitPath& url1, const GitRev& rev1, \r
1004                                                                  const CTGitPath& url2, const GitRev& rev2, \r
1005                                                                  const GitRev& peg /* = GitRev */, const GitRev& headpeg /* = GitRev */, \r
1006                                                                  bool bAlternateDiff /* = false */, bool bIgnoreAncestry /* = false */, bool blame /* = false */)\r
1007 {\r
1008 #if 0\r
1009         CString sCmd;\r
1010         sCmd.Format(_T("%s /command:showcompare"),\r
1011                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")));\r
1012         sCmd += _T(" /url1:\"") + url1.GetGitPathString() + _T("\"");\r
1013         if (rev1.IsValid())\r
1014                 sCmd += _T(" /revision1:") + rev1.ToString();\r
1015         sCmd += _T(" /url2:\"") + url2.GetGitPathString() + _T("\"");\r
1016         if (rev2.IsValid())\r
1017                 sCmd += _T(" /revision2:") + rev2.ToString();\r
1018         if (peg.IsValid())\r
1019                 sCmd += _T(" /pegrevision:") + peg.ToString();\r
1020         if (headpeg.IsValid())\r
1021                 sCmd += _T(" /headpegrevision:") + headpeg.ToString();\r
1022         if (bAlternateDiff)\r
1023                 sCmd += _T(" /alternatediff");\r
1024         if (bIgnoreAncestry)\r
1025                 sCmd += _T(" /ignoreancestry");\r
1026         if (blame)\r
1027                 sCmd += _T(" /blame");\r
1028 \r
1029         if (hWnd)\r
1030         {\r
1031                 sCmd += _T(" /hwnd:");\r
1032                 TCHAR buf[30];\r
1033                 _stprintf_s(buf, 30, _T("%d"), hWnd);\r
1034                 sCmd += buf;\r
1035         }\r
1036 \r
1037         return CAppUtils::LaunchApplication(sCmd, NULL, false);\r
1038 #endif\r
1039         return true;\r
1040 }\r
1041 \r
1042 bool CAppUtils::Export(CString *BashHash)\r
1043 {\r
1044         bool bRet = false;\r
1045 \r
1046                 // ask from where the export has to be done\r
1047         CExportDlg dlg;\r
1048         if(BashHash)\r
1049                 dlg.m_Revision=*BashHash;\r
1050 \r
1051         if (dlg.DoModal() == IDOK)\r
1052         {\r
1053                 CString cmd;\r
1054                 cmd.Format(_T("git.exe archive --format=zip --verbose %s"),\r
1055                                         dlg.m_VersionName);\r
1056 \r
1057                 //g_Git.RunLogFile(cmd,dlg.m_strExportDirectory);\r
1058                 CProgressDlg pro;\r
1059                 pro.m_GitCmd=cmd;\r
1060                 pro.m_LogFile=dlg.m_strExportDirectory;\r
1061                 pro.DoModal();\r
1062                 return TRUE;\r
1063         }\r
1064         return bRet;\r
1065 }\r
1066 \r
1067 bool CAppUtils::CreateBranchTag(bool IsTag,CString *CommitHash)\r
1068 {\r
1069         CCreateBranchTagDlg dlg;\r
1070         dlg.m_bIsTag=IsTag;\r
1071         if(CommitHash)\r
1072                 dlg.m_Base = *CommitHash;\r
1073 \r
1074         if(dlg.DoModal()==IDOK)\r
1075         {\r
1076                 CString cmd;\r
1077                 CString force;\r
1078                 CString track;\r
1079                 if(dlg.m_bTrack)\r
1080                         track=_T("--track");\r
1081 \r
1082                 if(dlg.m_bForce)\r
1083                         force=_T("-f");\r
1084 \r
1085                 if(IsTag)\r
1086                 {\r
1087                         cmd.Format(_T("git.exe tag %s %s %s %s"),\r
1088                                 track,\r
1089                                 force,\r
1090                                 dlg.m_BranchTagName,\r
1091                                 dlg.m_VersionName\r
1092                                 );\r
1093 \r
1094         \r
1095                 }else\r
1096                 {\r
1097                         cmd.Format(_T("git.exe branch %s %s %s %s"),\r
1098                                 track,\r
1099                                 force,\r
1100                                 dlg.m_BranchTagName,\r
1101                                 dlg.m_VersionName\r
1102                                 );\r
1103                 }\r
1104                 CString out;\r
1105                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
1106                 {\r
1107                         CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
1108                 }\r
1109                 if( !IsTag  &&  dlg.m_bSwitch )\r
1110                 {\r
1111                         // it is a new branch and the user has requested to switch to it\r
1112                         cmd.Format(_T("git.exe checkout %s"), dlg.m_BranchTagName);\r
1113                         g_Git.Run(cmd,&out,CP_UTF8);\r
1114                         CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
1115                 }\r
1116                 \r
1117                 return TRUE;\r
1118                 \r
1119         }\r
1120         return FALSE;\r
1121 }\r
1122 \r
1123 bool CAppUtils::Switch(CString *CommitHash)\r
1124 {\r
1125         CGitSwitchDlg dlg;\r
1126         if(CommitHash)\r
1127                 dlg.m_Base=*CommitHash;\r
1128         \r
1129         if (dlg.DoModal() == IDOK)\r
1130         {\r
1131                 CString cmd;\r
1132                 CString track;\r
1133                 CString base;\r
1134                 CString force;\r
1135                 CString branch;\r
1136 \r
1137                 if(dlg.m_bBranch)\r
1138                         branch.Format(_T("-b %s"),dlg.m_NewBranch);\r
1139                 if(dlg.m_bForce)\r
1140                         force=_T("-f");\r
1141                 if(dlg.m_bTrack)\r
1142                         track=_T("--track");\r
1143 \r
1144                 cmd.Format(_T("git.exe checkout %s %s %s %s"),\r
1145                          force,\r
1146                          track,\r
1147                          branch,\r
1148                          dlg.m_VersionName);\r
1149 \r
1150                 CProgressDlg progress;\r
1151                 progress.m_GitCmd=cmd;\r
1152                 if(progress.DoModal()==IDOK)\r
1153                         return TRUE;\r
1154 \r
1155         }\r
1156         return FALSE;\r
1157 }\r
1158 \r
1159 bool CAppUtils::IgnoreFile(CTGitPath &path,bool IsMask)\r
1160 {\r
1161         CString ignorefile;\r
1162         ignorefile=g_Git.m_CurrentDir;\r
1163         ignorefile+=path.GetDirectory().GetWinPathString()+_T("\\.gitignore");\r
1164 \r
1165         CStdioFile file;\r
1166         if(!file.Open(ignorefile,CFile::modeCreate|CFile::modeWrite))\r
1167         {\r
1168                 CMessageBox::Show(NULL,ignorefile+_T(" Open Failure"),_T("TortoiseGit"),MB_OK);\r
1169                 return FALSE;\r
1170         }\r
1171 \r
1172         CString ignorelist;\r
1173         file.ReadString(ignorelist);\r
1174 \r
1175         if(IsMask)\r
1176         {\r
1177                 ignorelist+=_T("\n*.")+path.GetFileExtension();\r
1178         }else\r
1179         {\r
1180                 ignorelist+=_T("\n")+path.GetBaseFilename();\r
1181         }\r
1182         file.WriteString(ignorelist);\r
1183 \r
1184         file.Close();\r
1185         return TRUE;\r
1186 }\r
1187 \r
1188 bool CAppUtils::GitReset(CString *CommitHash,int type)\r
1189 {\r
1190         CResetDlg dlg;\r
1191         dlg.m_ResetType=type;\r
1192         if (dlg.DoModal() == IDOK)\r
1193         {\r
1194                 CString cmd;\r
1195                 CString type;\r
1196                 switch(dlg.m_ResetType)\r
1197                 {\r
1198                 case 0:\r
1199                         type=_T("--soft");\r
1200                         break;\r
1201                 case 1:\r
1202                         type=_T("--mixed");\r
1203                         break;\r
1204                 case 2:\r
1205                         type=_T("--hard");\r
1206                         break;\r
1207                 default:\r
1208                         type=_T("--mixed");\r
1209                         break;\r
1210                 }\r
1211                 cmd.Format(_T("git.exe reset %s %s"),type, *CommitHash);\r
1212 \r
1213                 CProgressDlg progress;\r
1214                 progress.m_GitCmd=cmd;\r
1215                 if(progress.DoModal()==IDOK)\r
1216                         return TRUE;\r
1217 \r
1218         }\r
1219         return FALSE;\r
1220 }\r
1221 \r
1222 bool CAppUtils::ConflictEdit(CTGitPath &path,bool bAlternativeTool)\r
1223 {\r
1224         bool bRet = false;\r
1225 \r
1226         CTGitPath merge=path;\r
1227         CTGitPath directory = merge.GetDirectory();\r
1228         \r
1229         \r
1230 \r
1231         // we have the conflicted file (%merged)\r
1232         // now look for the other required files\r
1233         //GitStatus stat;\r
1234         //stat.GetStatus(merge);\r
1235         //if (stat.status == NULL)\r
1236         //      return false;\r
1237 \r
1238         BYTE_VECTOR vector;\r
1239 \r
1240         CString cmd;\r
1241         cmd.Format(_T("git.exe ls-files -u -t -z -- \"%s\""),merge.GetGitPathString());\r
1242 \r
1243         if(g_Git.Run(cmd,&vector))\r
1244         {\r
1245                 return FALSE;\r
1246         }\r
1247 \r
1248         CTGitPathList list;\r
1249         list.ParserFromLsFile(vector);\r
1250 \r
1251         if(list.GetCount() == 0)\r
1252                 return FALSE;\r
1253 \r
1254         TCHAR szTempName[512];  \r
1255         GetTempFileName(_T(""),_T(""),0,szTempName);\r
1256         CString temp(szTempName);\r
1257         temp=temp.Mid(1,temp.GetLength()-5);\r
1258 \r
1259         CTGitPath theirs;\r
1260         CTGitPath mine;\r
1261         CTGitPath base;\r
1262 \r
1263         CString format;\r
1264         format=g_Git.m_CurrentDir+_T("\\")+directory.GetWinPathString()+merge.GetFilename()+CString(_T(".%s."))+temp+merge.GetFileExtension();\r
1265 \r
1266         CString file;\r
1267         file.Format(format,_T("LOCAL"));\r
1268         mine.SetFromGit(file);\r
1269         file.Format(format,_T("REMOTE"));\r
1270         theirs.SetFromGit(file);\r
1271         file.Format(format,_T("BASE"));\r
1272         base.SetFromGit(file);\r
1273 \r
1274         \r
1275         format=_T("git.exe cat-file blob \":%d:%s\"");\r
1276         for(int i=0;i<list.GetCount();i++)\r
1277         {\r
1278                 CString cmd;\r
1279                 CString outfile;\r
1280                 cmd.Format(format,list[i].m_Stage,list[i].GetGitPathString());\r
1281 \r
1282                 if( list[i].m_Stage == 1)\r
1283                 {\r
1284                         outfile=base.GetWinPathString();\r
1285                 }\r
1286                 if( list[i].m_Stage == 2 )\r
1287                 {\r
1288                         outfile=mine.GetWinPathString();\r
1289                 }\r
1290                 if( list[i].m_Stage == 3 )\r
1291                 {\r
1292                         outfile=theirs.GetWinPathString();\r
1293                 }\r
1294                 g_Git.RunLogFile(cmd,outfile);\r
1295         }\r
1296 \r
1297         merge.SetFromWin(g_Git.m_CurrentDir+_T("\\")+merge.GetWinPathString());\r
1298         bRet = !!CAppUtils::StartExtMerge(base, theirs, mine, merge,_T("BASE"),_T("REMOTE"),_T("LOCAL"));\r
1299 \r
1300 #if 0\r
1301 \r
1302         CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool), \r
1303                         base, theirs, mine, merge);\r
1304 #endif\r
1305 #if 0\r
1306         if (stat.status->text_status == svn_wc_status_conflicted)\r
1307         {\r
1308                 // we have a text conflict, use our merge tool to resolve the conflict\r
1309 \r
1310                 CTSVNPath theirs(directory);\r
1311                 CTSVNPath mine(directory);\r
1312                 CTSVNPath base(directory);\r
1313                 bool bConflictData = false;\r
1314 \r
1315                 if ((stat.status->entry)&&(stat.status->entry->conflict_new))\r
1316                 {\r
1317                         theirs.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_new));\r
1318                         bConflictData = true;\r
1319                 }\r
1320                 if ((stat.status->entry)&&(stat.status->entry->conflict_old))\r
1321                 {\r
1322                         base.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_old));\r
1323                         bConflictData = true;\r
1324                 }\r
1325                 if ((stat.status->entry)&&(stat.status->entry->conflict_wrk))\r
1326                 {\r
1327                         mine.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->conflict_wrk));\r
1328                         bConflictData = true;\r
1329                 }\r
1330                 else\r
1331                 {\r
1332                         mine = merge;\r
1333                 }\r
1334                 if (bConflictData)\r
1335                         bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool), \r
1336                                                                                                 base, theirs, mine, merge);\r
1337         }\r
1338 \r
1339         if (stat.status->prop_status == svn_wc_status_conflicted)\r
1340         {\r
1341                 // we have a property conflict\r
1342                 CTSVNPath prej(directory);\r
1343                 if ((stat.status->entry)&&(stat.status->entry->prejfile))\r
1344                 {\r
1345                         prej.AppendPathString(CUnicodeUtils::GetUnicode(stat.status->entry->prejfile));\r
1346                         // there's a problem: the prej file contains a _description_ of the conflict, and\r
1347                         // that description string might be translated. That means we have no way of parsing\r
1348                         // the file to find out the conflicting values.\r
1349                         // The only thing we can do: show a dialog with the conflict description, then\r
1350                         // let the user either accept the existing property or open the property edit dialog\r
1351                         // to manually change the properties and values. And a button to mark the conflict as\r
1352                         // resolved.\r
1353                         CEditPropConflictDlg dlg;\r
1354                         dlg.SetPrejFile(prej);\r
1355                         dlg.SetConflictedItem(merge);\r
1356                         bRet = (dlg.DoModal() != IDCANCEL);\r
1357                 }\r
1358         }\r
1359 \r
1360         if (stat.status->tree_conflict)\r
1361         {\r
1362                 // we have a tree conflict\r
1363                 SVNInfo info;\r
1364                 const SVNInfoData * pInfoData = info.GetFirstFileInfo(merge, SVNRev(), SVNRev());\r
1365                 if (pInfoData)\r
1366                 {\r
1367                         if (pInfoData->treeconflict_kind == svn_wc_conflict_kind_text)\r
1368                         {\r
1369                                 CTSVNPath theirs(directory);\r
1370                                 CTSVNPath mine(directory);\r
1371                                 CTSVNPath base(directory);\r
1372                                 bool bConflictData = false;\r
1373 \r
1374                                 if (pInfoData->treeconflict_theirfile)\r
1375                                 {\r
1376                                         theirs.AppendPathString(pInfoData->treeconflict_theirfile);\r
1377                                         bConflictData = true;\r
1378                                 }\r
1379                                 if (pInfoData->treeconflict_basefile)\r
1380                                 {\r
1381                                         base.AppendPathString(pInfoData->treeconflict_basefile);\r
1382                                         bConflictData = true;\r
1383                                 }\r
1384                                 if (pInfoData->treeconflict_myfile)\r
1385                                 {\r
1386                                         mine.AppendPathString(pInfoData->treeconflict_myfile);\r
1387                                         bConflictData = true;\r
1388                                 }\r
1389                                 else\r
1390                                 {\r
1391                                         mine = merge;\r
1392                                 }\r
1393                                 if (bConflictData)\r
1394                                         bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool),\r
1395                                                                                                                 base, theirs, mine, merge);\r
1396                         }\r
1397                         else if (pInfoData->treeconflict_kind == svn_wc_conflict_kind_tree)\r
1398                         {\r
1399                                 CString sConflictAction;\r
1400                                 CString sConflictReason;\r
1401                                 CString sResolveTheirs;\r
1402                                 CString sResolveMine;\r
1403                                 CTSVNPath treeConflictPath = CTSVNPath(pInfoData->treeconflict_path);\r
1404                                 CString sItemName = treeConflictPath.GetUIFileOrDirectoryName();\r
1405                                 \r
1406                                 if (pInfoData->treeconflict_nodekind == svn_node_file)\r
1407                                 {\r
1408                                         switch (pInfoData->treeconflict_operation)\r
1409                                         {\r
1410                                         case svn_wc_operation_update:\r
1411                                                 switch (pInfoData->treeconflict_action)\r
1412                                                 {\r
1413                                                 case svn_wc_conflict_action_edit:\r
1414                                                         sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEEDIT, (LPCTSTR)sItemName);\r
1415                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);\r
1416                                                         break;\r
1417                                                 case svn_wc_conflict_action_add:\r
1418                                                         sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEADD, (LPCTSTR)sItemName);\r
1419                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);\r
1420                                                         break;\r
1421                                                 case svn_wc_conflict_action_delete:\r
1422                                                         sConflictAction.Format(IDS_TREECONFLICT_FILEUPDATEDELETE, (LPCTSTR)sItemName);\r
1423                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE);\r
1424                                                         break;\r
1425                                                 }\r
1426                                                 break;\r
1427                                         case svn_wc_operation_switch:\r
1428                                                 switch (pInfoData->treeconflict_action)\r
1429                                                 {\r
1430                                                 case svn_wc_conflict_action_edit:\r
1431                                                         sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHEDIT, (LPCTSTR)sItemName);\r
1432                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);\r
1433                                                         break;\r
1434                                                 case svn_wc_conflict_action_add:\r
1435                                                         sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHADD, (LPCTSTR)sItemName);\r
1436                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);\r
1437                                                         break;\r
1438                                                 case svn_wc_conflict_action_delete:\r
1439                                                         sConflictAction.Format(IDS_TREECONFLICT_FILESWITCHDELETE, (LPCTSTR)sItemName);\r
1440                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE);\r
1441                                                         break;\r
1442                                                 }\r
1443                                                 break;\r
1444                                         case svn_wc_operation_merge:\r
1445                                                 switch (pInfoData->treeconflict_action)\r
1446                                                 {\r
1447                                                 case svn_wc_conflict_action_edit:\r
1448                                                         sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEEDIT, (LPCTSTR)sItemName);\r
1449                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);\r
1450                                                         break;\r
1451                                                 case svn_wc_conflict_action_add:\r
1452                                                         sResolveTheirs.Format(IDS_TREECONFLICT_FILEMERGEADD, (LPCTSTR)sItemName);\r
1453                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYFILE);\r
1454                                                         break;\r
1455                                                 case svn_wc_conflict_action_delete:\r
1456                                                         sConflictAction.Format(IDS_TREECONFLICT_FILEMERGEDELETE, (LPCTSTR)sItemName);\r
1457                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEFILE);\r
1458                                                         break;\r
1459                                                 }\r
1460                                                 break;\r
1461                                         }\r
1462                                 }\r
1463                                 else if (pInfoData->treeconflict_nodekind == svn_node_dir)\r
1464                                 {\r
1465                                         switch (pInfoData->treeconflict_operation)\r
1466                                         {\r
1467                                         case svn_wc_operation_update:\r
1468                                                 switch (pInfoData->treeconflict_action)\r
1469                                                 {\r
1470                                                 case svn_wc_conflict_action_edit:\r
1471                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEEDIT, (LPCTSTR)sItemName);\r
1472                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);\r
1473                                                         break;\r
1474                                                 case svn_wc_conflict_action_add:\r
1475                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEADD, (LPCTSTR)sItemName);\r
1476                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);\r
1477                                                         break;\r
1478                                                 case svn_wc_conflict_action_delete:\r
1479                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRUPDATEDELETE, (LPCTSTR)sItemName);\r
1480                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR);\r
1481                                                         break;\r
1482                                                 }\r
1483                                                 break;\r
1484                                         case svn_wc_operation_switch:\r
1485                                                 switch (pInfoData->treeconflict_action)\r
1486                                                 {\r
1487                                                 case svn_wc_conflict_action_edit:\r
1488                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHEDIT, (LPCTSTR)sItemName);\r
1489                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);\r
1490                                                         break;\r
1491                                                 case svn_wc_conflict_action_add:\r
1492                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHADD, (LPCTSTR)sItemName);\r
1493                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);\r
1494                                                         break;\r
1495                                                 case svn_wc_conflict_action_delete:\r
1496                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRSWITCHDELETE, (LPCTSTR)sItemName);\r
1497                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR);\r
1498                                                         break;\r
1499                                                 }\r
1500                                                 break;\r
1501                                         case svn_wc_operation_merge:\r
1502                                                 switch (pInfoData->treeconflict_action)\r
1503                                                 {\r
1504                                                 case svn_wc_conflict_action_edit:\r
1505                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEEDIT, (LPCTSTR)sItemName);\r
1506                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);\r
1507                                                         break;\r
1508                                                 case svn_wc_conflict_action_add:\r
1509                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEADD, (LPCTSTR)sItemName);\r
1510                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_KEEPREPOSITORYDIR);\r
1511                                                         break;\r
1512                                                 case svn_wc_conflict_action_delete:\r
1513                                                         sConflictAction.Format(IDS_TREECONFLICT_DIRMERGEDELETE, (LPCTSTR)sItemName);\r
1514                                                         sResolveTheirs.LoadString(IDS_TREECONFLICT_RESOLVE_REMOVEDIR);\r
1515                                                         break;\r
1516                                                 }\r
1517                                                 break;\r
1518                                         }\r
1519                                 }\r
1520 \r
1521                                 UINT uReasonID = 0;\r
1522                                 switch (pInfoData->treeconflict_reason)\r
1523                                 { \r
1524                                 case svn_wc_conflict_reason_edited:\r
1525                                         uReasonID = IDS_TREECONFLICT_REASON_EDITED;\r
1526                                         sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);\r
1527                                         break;\r
1528                                 case svn_wc_conflict_reason_obstructed:\r
1529                                         uReasonID = IDS_TREECONFLICT_REASON_OBSTRUCTED;\r
1530                                         sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);\r
1531                                         break;\r
1532                                 case svn_wc_conflict_reason_deleted:\r
1533                                         uReasonID = IDS_TREECONFLICT_REASON_DELETED;\r
1534                                         sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_REMOVEDIR : IDS_TREECONFLICT_RESOLVE_REMOVEFILE);\r
1535                                         break;\r
1536                                 case svn_wc_conflict_reason_added:\r
1537                                         uReasonID = IDS_TREECONFLICT_REASON_ADDED;\r
1538                                         sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);\r
1539                                         break;\r
1540                                 case svn_wc_conflict_reason_missing:\r
1541                                         uReasonID = IDS_TREECONFLICT_REASON_MISSING;\r
1542                                         sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_REMOVEDIR : IDS_TREECONFLICT_RESOLVE_REMOVEFILE);\r
1543                                         break;\r
1544                                 case svn_wc_conflict_reason_unversioned:\r
1545                                         uReasonID = IDS_TREECONFLICT_REASON_UNVERSIONED;\r
1546                                         sResolveMine.LoadString(pInfoData->treeconflict_nodekind == svn_node_dir ? IDS_TREECONFLICT_RESOLVE_KEEPLOCALDIR : IDS_TREECONFLICT_RESOLVE_KEEPLOCALFILE);\r
1547                                         break;\r
1548                                 }\r
1549                                 sConflictReason.Format(uReasonID, (LPCTSTR)sConflictAction);\r
1550 \r
1551                                 CTreeConflictEditorDlg dlg;\r
1552                                 dlg.SetConflictInfoText(sConflictReason);\r
1553                                 dlg.SetResolveTexts(sResolveTheirs, sResolveMine);\r
1554                                 dlg.SetPath(treeConflictPath);\r
1555                                 INT_PTR dlgRet = dlg.DoModal();\r
1556                                 bRet = (dlgRet != IDCANCEL);\r
1557                         }\r
1558                 }\r
1559         }\r
1560 #endif\r
1561         return bRet;\r
1562 }\r
1563 \r
1564 /**\r
1565  * FUNCTION    :   FormatDateAndTime\r
1566  * DESCRIPTION :   Generates a displayable string from a CTime object in\r
1567  *                 system short or long format  or as a relative value\r
1568  *                                 cTime - the time\r
1569  *                                 option - DATE_SHORTDATE or DATE_LONGDATE\r
1570  *                                 bIncluedeTime - whether to show time as well as date\r
1571  *                                 bRelative - if true then relative time is shown if reasonable \r
1572  *                                 If HKCU\Software\TortoiseGit\UseSystemLocaleForDates is 0 then use fixed format\r
1573  *                                 rather than locale\r
1574  * RETURN      :   CString containing date/time\r
1575  */\r
1576 CString CAppUtils::FormatDateAndTime( const CTime& cTime, DWORD option, bool bIncludeTime /*=true*/,\r
1577         bool bRelative /*=false*/)\r
1578 {\r
1579         CString datetime;\r
1580         if ( bRelative )\r
1581         {\r
1582                 datetime = ToRelativeTimeString( cTime );\r
1583         }\r
1584         else\r
1585         {\r
1586                 // should we use the locale settings for formatting the date/time?\r
1587                 if (CRegDWORD(_T("Software\\TortoiseGit\\UseSystemLocaleForDates"), TRUE))\r
1588                 {\r
1589                         // yes\r
1590                         SYSTEMTIME sysTime;\r
1591                         cTime.GetAsSystemTime( sysTime );\r
1592                         \r
1593                         TCHAR buf[100];\r
1594                         \r
1595                         GetDateFormat(LOCALE_USER_DEFAULT, option, &sysTime, NULL, buf, \r
1596                                 sizeof(buf)/sizeof(TCHAR)-1);\r
1597                         datetime = buf;\r
1598                         if ( bIncludeTime )\r
1599                         {\r
1600                                 datetime += _T(" ");\r
1601                                 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &sysTime, NULL, buf, sizeof(buf)/sizeof(TCHAR)-1);\r
1602                                 datetime += buf;\r
1603                         }\r
1604                 }\r
1605                 else\r
1606                 {\r
1607                         // no, so fixed format\r
1608                         if ( bIncludeTime )\r
1609                         {\r
1610                                 datetime = cTime.Format(_T("%Y-%m-%d %H:%M:%S"));\r
1611                         }\r
1612                         else\r
1613                         {\r
1614                                 datetime = cTime.Format(_T("%Y-%m-%d"));\r
1615                         }\r
1616                 }\r
1617         }\r
1618         return datetime;\r
1619 }\r
1620 \r
1621 /**\r
1622  *      Converts a given time to a relative display string (relative to current time)\r
1623  *      Given time must be in local timezone\r
1624  */\r
1625 CString CAppUtils::ToRelativeTimeString(CTime time)\r
1626 {\r
1627     CString answer;\r
1628         // convert to COleDateTime\r
1629         SYSTEMTIME sysTime;\r
1630         time.GetAsSystemTime( sysTime );\r
1631         COleDateTime oleTime( sysTime );\r
1632         answer = ToRelativeTimeString(oleTime, COleDateTime::GetCurrentTime());\r
1633         return answer;\r
1634 }\r
1635 \r
1636 /**\r
1637  *      Generates a display string showing the relative time between the two given times as COleDateTimes\r
1638  */\r
1639 CString CAppUtils::ToRelativeTimeString(COleDateTime time,COleDateTime RelativeTo)\r
1640 {\r
1641     CString answer;\r
1642         COleDateTimeSpan ts = RelativeTo - time;\r
1643     //years\r
1644         if(fabs(ts.GetTotalDays()) >= 3*365)\r
1645     {\r
1646                 answer = ExpandRelativeTime( (int)ts.GetTotalDays()/365, IDS_YEAR_AGO, IDS_YEARS_AGO );\r
1647         }\r
1648         //Months\r
1649         if(fabs(ts.GetTotalDays()) >= 60)\r
1650         {\r
1651                 answer = ExpandRelativeTime( (int)ts.GetTotalDays()/30, IDS_MONTH_AGO, IDS_MONTHS_AGO );\r
1652                 return answer;\r
1653         }\r
1654         //Weeks\r
1655         if(fabs(ts.GetTotalDays()) >= 14)\r
1656         {\r
1657                 answer = ExpandRelativeTime( (int)ts.GetTotalDays()/7, IDS_WEEK_AGO, IDS_WEEKS_AGO );\r
1658                 return answer;\r
1659         }\r
1660         //Days\r
1661         if(fabs(ts.GetTotalDays()) >= 2)\r
1662         {\r
1663                 answer = ExpandRelativeTime( (int)ts.GetTotalDays(), IDS_DAY_AGO, IDS_DAYS_AGO );\r
1664                 return answer;\r
1665         }\r
1666         //hours\r
1667         if(fabs(ts.GetTotalHours()) >= 2)\r
1668         {\r
1669                 answer = ExpandRelativeTime( (int)ts.GetTotalHours(), IDS_HOUR_AGO, IDS_HOURS_AGO );\r
1670                 return answer;\r
1671         }\r
1672         //minutes\r
1673         if(fabs(ts.GetTotalMinutes()) >= 2)\r
1674         {\r
1675                 answer = ExpandRelativeTime( (int)ts.GetTotalMinutes(), IDS_MINUTE_AGO, IDS_MINUTES_AGO );\r
1676                 return answer;\r
1677         }\r
1678         //seconds\r
1679                 answer = ExpandRelativeTime( (int)ts.GetTotalSeconds(), IDS_SECOND_AGO, IDS_SECONDS_AGO );\r
1680     return answer;\r
1681 }\r
1682 \r
1683 /** \r
1684  * Passed a value and two resource string ids\r
1685  * if count is 1 then FormatString is called with format_1 and the value\r
1686  * otherwise format_2 is used\r
1687  * the formatted string is returned\r
1688 */\r
1689 CString CAppUtils::ExpandRelativeTime( int count, UINT format_1, UINT format_n )\r
1690 {\r
1691         CString answer;\r
1692         if ( count == 1 )\r
1693         {\r
1694                 answer.FormatMessage( format_1, count );\r
1695         }\r
1696         else\r
1697         {\r
1698                 answer.FormatMessage( format_n, count );\r
1699         }\r
1700         return answer;\r
1701 }\r
1702 \r