OSDN Git Service

Add blame command at TortoiseProc
[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 \r
44 CAppUtils::CAppUtils(void)\r
45 {\r
46 }\r
47 \r
48 CAppUtils::~CAppUtils(void)\r
49 {\r
50 }\r
51 \r
52 bool CAppUtils::GetMimeType(const CTGitPath& file, CString& mimetype)\r
53 {\r
54 #if 0\r
55         GitProperties props(file, GitRev::REV_WC, false);\r
56         for (int i = 0; i < props.GetCount(); ++i)\r
57         {\r
58                 if (props.GetItemName(i).compare(_T("svn:mime-type"))==0)\r
59                 {\r
60                         mimetype = props.GetItemValue(i).c_str();\r
61                         return true;\r
62                 }\r
63         }\r
64 #endif\r
65         return false;\r
66 }\r
67 \r
68 BOOL CAppUtils::StartExtMerge(\r
69         const CTGitPath& basefile, const CTGitPath& theirfile, const CTGitPath& yourfile, const CTGitPath& mergedfile,\r
70         const CString& basename, const CString& theirname, const CString& yourname, const CString& mergedname, bool bReadOnly)\r
71 {\r
72 \r
73         CRegString regCom = CRegString(_T("Software\\TortoiseGit\\Merge"));\r
74         CString ext = mergedfile.GetFileExtension();\r
75         CString com = regCom;\r
76         bool bInternal = false;\r
77 \r
78         CString mimetype;\r
79         if (ext != "")\r
80         {\r
81                 // is there an extension specific merge tool?\r
82                 CRegString mergetool(_T("Software\\TortoiseGit\\MergeTools\\") + ext.MakeLower());\r
83                 if (CString(mergetool) != "")\r
84                 {\r
85                         com = mergetool;\r
86                 }\r
87         }\r
88         if (GetMimeType(yourfile, mimetype) || GetMimeType(theirfile, mimetype) || GetMimeType(basefile, mimetype))\r
89         {\r
90                 // is there a mime type specific merge tool?\r
91                 CRegString mergetool(_T("Software\\TortoiseGit\\MergeTools\\") + mimetype);\r
92                 if (CString(mergetool) != "")\r
93                 {\r
94                         com = mergetool;\r
95                 }\r
96         }\r
97         \r
98         if (com.IsEmpty()||(com.Left(1).Compare(_T("#"))==0))\r
99         {\r
100                 // use TortoiseMerge\r
101                 bInternal = true;\r
102                 CRegString tortoiseMergePath(_T("Software\\TortoiseGit\\TMergePath"), _T(""), false, HKEY_LOCAL_MACHINE);\r
103                 com = tortoiseMergePath;\r
104                 if (com.IsEmpty())\r
105                 {\r
106                         com = CPathUtils::GetAppDirectory();\r
107                         com += _T("TortoiseMerge.exe");\r
108                 }\r
109                 com = _T("\"") + com + _T("\"");\r
110                 com = com + _T(" /base:%base /theirs:%theirs /mine:%mine /merged:%merged");\r
111                 com = com + _T(" /basename:%bname /theirsname:%tname /minename:%yname /mergedname:%mname");\r
112         }\r
113         // check if the params are set. If not, just add the files to the command line\r
114         if ((com.Find(_T("%merged"))<0)&&(com.Find(_T("%base"))<0)&&(com.Find(_T("%theirs"))<0)&&(com.Find(_T("%mine"))<0))\r
115         {\r
116                 com += _T(" \"")+basefile.GetWinPathString()+_T("\"");\r
117                 com += _T(" \"")+theirfile.GetWinPathString()+_T("\"");\r
118                 com += _T(" \"")+yourfile.GetWinPathString()+_T("\"");\r
119                 com += _T(" \"")+mergedfile.GetWinPathString()+_T("\"");\r
120         }\r
121         if (basefile.IsEmpty())\r
122         {\r
123                 com.Replace(_T("/base:%base"), _T(""));\r
124                 com.Replace(_T("%base"), _T(""));               \r
125         }\r
126         else\r
127                 com.Replace(_T("%base"), _T("\"") + basefile.GetWinPathString() + _T("\""));\r
128         if (theirfile.IsEmpty())\r
129         {\r
130                 com.Replace(_T("/theirs:%theirs"), _T(""));\r
131                 com.Replace(_T("%theirs"), _T(""));\r
132         }\r
133         else\r
134                 com.Replace(_T("%theirs"), _T("\"") + theirfile.GetWinPathString() + _T("\""));\r
135         if (yourfile.IsEmpty())\r
136         {\r
137                 com.Replace(_T("/mine:%mine"), _T(""));\r
138                 com.Replace(_T("%mine"), _T(""));\r
139         }\r
140         else\r
141                 com.Replace(_T("%mine"), _T("\"") + yourfile.GetWinPathString() + _T("\""));\r
142         if (mergedfile.IsEmpty())\r
143         {\r
144                 com.Replace(_T("/merged:%merged"), _T(""));\r
145                 com.Replace(_T("%merged"), _T(""));\r
146         }\r
147         else\r
148                 com.Replace(_T("%merged"), _T("\"") + mergedfile.GetWinPathString() + _T("\""));\r
149         if (basename.IsEmpty())\r
150         {\r
151                 if (basefile.IsEmpty())\r
152                 {\r
153                         com.Replace(_T("/basename:%bname"), _T(""));\r
154                         com.Replace(_T("%bname"), _T(""));\r
155                 }\r
156                 else\r
157                 {\r
158                         com.Replace(_T("%bname"), _T("\"") + basefile.GetUIFileOrDirectoryName() + _T("\""));\r
159                 }\r
160         }\r
161         else\r
162                 com.Replace(_T("%bname"), _T("\"") + basename + _T("\""));\r
163         if (theirname.IsEmpty())\r
164         {\r
165                 if (theirfile.IsEmpty())\r
166                 {\r
167                         com.Replace(_T("/theirsname:%tname"), _T(""));\r
168                         com.Replace(_T("%tname"), _T(""));\r
169                 }\r
170                 else\r
171                 {\r
172                         com.Replace(_T("%tname"), _T("\"") + theirfile.GetUIFileOrDirectoryName() + _T("\""));\r
173                 }\r
174         }\r
175         else\r
176                 com.Replace(_T("%tname"), _T("\"") + theirname + _T("\""));\r
177         if (yourname.IsEmpty())\r
178         {\r
179                 if (yourfile.IsEmpty())\r
180                 {\r
181                         com.Replace(_T("/minename:%yname"), _T(""));\r
182                         com.Replace(_T("%yname"), _T(""));\r
183                 }\r
184                 else\r
185                 {\r
186                         com.Replace(_T("%yname"), _T("\"") + yourfile.GetUIFileOrDirectoryName() + _T("\""));\r
187                 }\r
188         }\r
189         else\r
190                 com.Replace(_T("%yname"), _T("\"") + yourname + _T("\""));\r
191         if (mergedname.IsEmpty())\r
192         {\r
193                 if (mergedfile.IsEmpty())\r
194                 {\r
195                         com.Replace(_T("/mergedname:%mname"), _T(""));\r
196                         com.Replace(_T("%mname"), _T(""));\r
197                 }\r
198                 else\r
199                 {\r
200                         com.Replace(_T("%mname"), _T("\"") + mergedfile.GetUIFileOrDirectoryName() + _T("\""));\r
201                 }\r
202         }\r
203         else\r
204                 com.Replace(_T("%mname"), _T("\"") + mergedname + _T("\""));\r
205 \r
206         if ((bReadOnly)&&(bInternal))\r
207                 com += _T(" /readonly");\r
208 \r
209         if(!LaunchApplication(com, IDS_ERR_EXTMERGESTART, false))\r
210         {\r
211                 return FALSE;\r
212         }\r
213 \r
214         return TRUE;\r
215 }\r
216 \r
217 BOOL CAppUtils::StartExtPatch(const CTGitPath& patchfile, const CTGitPath& dir, const CString& sOriginalDescription, const CString& sPatchedDescription, BOOL bReversed, BOOL bWait)\r
218 {\r
219         CString viewer;\r
220         // use TortoiseMerge\r
221         viewer = CPathUtils::GetAppDirectory();\r
222         viewer += _T("TortoiseMerge.exe");\r
223 \r
224         viewer = _T("\"") + viewer + _T("\"");\r
225         viewer = viewer + _T(" /diff:\"") + patchfile.GetWinPathString() + _T("\"");\r
226         viewer = viewer + _T(" /patchpath:\"") + dir.GetWinPathString() + _T("\"");\r
227         if (bReversed)\r
228                 viewer += _T(" /reversedpatch");\r
229         if (!sOriginalDescription.IsEmpty())\r
230                 viewer = viewer + _T(" /patchoriginal:\"") + sOriginalDescription + _T("\"");\r
231         if (!sPatchedDescription.IsEmpty())\r
232                 viewer = viewer + _T(" /patchpatched:\"") + sPatchedDescription + _T("\"");\r
233         if(!LaunchApplication(viewer, IDS_ERR_DIFFVIEWSTART, !!bWait))\r
234         {\r
235                 return FALSE;\r
236         }\r
237         return TRUE;\r
238 }\r
239 \r
240 CString CAppUtils::PickDiffTool(const CTGitPath& file1, const CTGitPath& file2)\r
241 {\r
242         // Is there a mime type specific diff tool?\r
243         CString mimetype;\r
244         if (GetMimeType(file1, mimetype) ||  GetMimeType(file2, mimetype))\r
245         {\r
246                 CString difftool = CRegString(_T("Software\\TortoiseGit\\DiffTools\\") + mimetype);\r
247                 if (!difftool.IsEmpty())\r
248                         return difftool;\r
249         }\r
250         \r
251         // Is there an extension specific diff tool?\r
252         CString ext = file2.GetFileExtension().MakeLower();\r
253         if (!ext.IsEmpty())\r
254         {\r
255                 CString difftool = CRegString(_T("Software\\TortoiseGit\\DiffTools\\") + ext);\r
256                 if (!difftool.IsEmpty())\r
257                         return difftool;\r
258                 // Maybe we should use TortoiseIDiff?\r
259                 if ((ext == _T(".jpg")) || (ext == _T(".jpeg")) ||\r
260                         (ext == _T(".bmp")) || (ext == _T(".gif"))  ||\r
261                         (ext == _T(".png")) || (ext == _T(".ico"))  ||\r
262                         (ext == _T(".dib")) || (ext == _T(".emf")))\r
263                 {\r
264                         return\r
265                                 _T("\"") + CPathUtils::GetAppDirectory() + _T("TortoiseIDiff.exe") + _T("\"") +\r
266                                 _T(" /left:%base /right:%mine /lefttitle:%bname /righttitle:%yname");\r
267                 }\r
268         }\r
269         \r
270         // Finally, pick a generic external diff tool\r
271         CString difftool = CRegString(_T("Software\\TortoiseGit\\Diff"));\r
272         return difftool;\r
273 }\r
274 \r
275 bool CAppUtils::StartExtDiff(\r
276         const CString& file1,  const CString& file2,\r
277         const CString& sName1, const CString& sName2, \r
278         const DiffFlags& flags)\r
279 {\r
280         CString viewer;\r
281 \r
282         CRegDWORD blamediff(_T("Software\\TortoiseGit\\DiffBlamesWithTortoiseMerge"), FALSE);\r
283         if (!flags.bBlame || !(DWORD)blamediff)\r
284         {\r
285                 viewer = PickDiffTool(file1, file2);\r
286                 // If registry entry for a diff program is commented out, use TortoiseMerge.\r
287                 bool bCommentedOut = viewer.Left(1) == _T("#");\r
288                 if (flags.bAlternativeTool)\r
289                 {\r
290                         // Invert external vs. internal diff tool selection.\r
291                         if (bCommentedOut)\r
292                                 viewer.Delete(0); // uncomment\r
293                         else\r
294                                 viewer = "";\r
295                 }\r
296                 else if (bCommentedOut)\r
297                         viewer = "";\r
298         }\r
299 \r
300         bool bInternal = viewer.IsEmpty();\r
301         if (bInternal)\r
302         {\r
303                 viewer =\r
304                         _T("\"") + CPathUtils::GetAppDirectory() + _T("TortoiseMerge.exe") + _T("\"") +\r
305                         _T(" /base:%base /mine:%mine /basename:%bname /minename:%yname");\r
306                 if (flags.bBlame)\r
307                         viewer += _T(" /blame");\r
308         }\r
309         // check if the params are set. If not, just add the files to the command line\r
310         if ((viewer.Find(_T("%base"))<0)&&(viewer.Find(_T("%mine"))<0))\r
311         {\r
312                 viewer += _T(" \"")+file1+_T("\"");\r
313                 viewer += _T(" \"")+file2+_T("\"");\r
314         }\r
315         if (viewer.Find(_T("%base")) >= 0)\r
316         {\r
317                 viewer.Replace(_T("%base"),  _T("\"")+file1+_T("\""));\r
318         }\r
319         if (viewer.Find(_T("%mine")) >= 0)\r
320         {\r
321                 viewer.Replace(_T("%mine"),  _T("\"")+file2+_T("\""));\r
322         }\r
323 \r
324         if (sName1.IsEmpty())\r
325                 viewer.Replace(_T("%bname"), _T("\"") + file1 + _T("\""));\r
326         else\r
327                 viewer.Replace(_T("%bname"), _T("\"") + sName1 + _T("\""));\r
328 \r
329         if (sName2.IsEmpty())\r
330                 viewer.Replace(_T("%yname"), _T("\"") + file2 + _T("\""));\r
331         else\r
332                 viewer.Replace(_T("%yname"), _T("\"") + sName2 + _T("\""));\r
333 \r
334         if (flags.bReadOnly && bInternal)\r
335                 viewer += _T(" /readonly");\r
336 \r
337         return LaunchApplication(viewer, IDS_ERR_EXTDIFFSTART, flags.bWait);\r
338 }\r
339 \r
340 BOOL CAppUtils::StartExtDiffProps(const CTGitPath& file1, const CTGitPath& file2, const CString& sName1, const CString& sName2, BOOL bWait, BOOL bReadOnly)\r
341 {\r
342         CRegString diffpropsexe(_T("Software\\TortoiseGit\\DiffProps"));\r
343         CString viewer = diffpropsexe;\r
344         bool bInternal = false;\r
345         if (viewer.IsEmpty()||(viewer.Left(1).Compare(_T("#"))==0))\r
346         {\r
347                 //no registry entry (or commented out) for a diff program\r
348                 //use TortoiseMerge\r
349                 bInternal = true;\r
350                 viewer = CPathUtils::GetAppDirectory();\r
351                 viewer += _T("TortoiseMerge.exe");\r
352                 viewer = _T("\"") + viewer + _T("\"");\r
353                 viewer = viewer + _T(" /base:%base /mine:%mine /basename:%bname /minename:%yname");\r
354         }\r
355         // check if the params are set. If not, just add the files to the command line\r
356         if ((viewer.Find(_T("%base"))<0)&&(viewer.Find(_T("%mine"))<0))\r
357         {\r
358                 viewer += _T(" \"")+file1.GetWinPathString()+_T("\"");\r
359                 viewer += _T(" \"")+file2.GetWinPathString()+_T("\"");\r
360         }\r
361         if (viewer.Find(_T("%base")) >= 0)\r
362         {\r
363                 viewer.Replace(_T("%base"),  _T("\"")+file1.GetWinPathString()+_T("\""));\r
364         }\r
365         if (viewer.Find(_T("%mine")) >= 0)\r
366         {\r
367                 viewer.Replace(_T("%mine"),  _T("\"")+file2.GetWinPathString()+_T("\""));\r
368         }\r
369 \r
370         if (sName1.IsEmpty())\r
371                 viewer.Replace(_T("%bname"), _T("\"") + file1.GetUIFileOrDirectoryName() + _T("\""));\r
372         else\r
373                 viewer.Replace(_T("%bname"), _T("\"") + sName1 + _T("\""));\r
374 \r
375         if (sName2.IsEmpty())\r
376                 viewer.Replace(_T("%yname"), _T("\"") + file2.GetUIFileOrDirectoryName() + _T("\""));\r
377         else\r
378                 viewer.Replace(_T("%yname"), _T("\"") + sName2 + _T("\""));\r
379 \r
380         if ((bReadOnly)&&(bInternal))\r
381                 viewer += _T(" /readonly");\r
382 \r
383         if(!LaunchApplication(viewer, IDS_ERR_EXTDIFFSTART, !!bWait))\r
384         {\r
385                 return FALSE;\r
386         }\r
387         return TRUE;\r
388 }\r
389 \r
390 BOOL CAppUtils::StartUnifiedDiffViewer(const CString& patchfile, const CString& title, BOOL bWait)\r
391 {\r
392         CString viewer;\r
393         CRegString v = CRegString(_T("Software\\TortoiseGit\\DiffViewer"));\r
394         viewer = v;\r
395         if (viewer.IsEmpty() || (viewer.Left(1).Compare(_T("#"))==0))\r
396         {\r
397                 // use TortoiseUDiff\r
398                 viewer = CPathUtils::GetAppDirectory();\r
399                 viewer += _T("TortoiseUDiff.exe");\r
400                 // enquote the path to TortoiseUDiff\r
401                 viewer = _T("\"") + viewer + _T("\"");\r
402                 // add the params\r
403                 viewer = viewer + _T(" /patchfile:%1 /title:\"%title\"");\r
404 \r
405         }\r
406         if (viewer.Find(_T("%1"))>=0)\r
407         {\r
408                 if (viewer.Find(_T("\"%1\"")) >= 0)\r
409                         viewer.Replace(_T("%1"), patchfile);\r
410                 else\r
411                         viewer.Replace(_T("%1"), _T("\"") + patchfile + _T("\""));\r
412         }\r
413         else\r
414                 viewer += _T(" \"") + patchfile + _T("\"");\r
415         if (viewer.Find(_T("%title")) >= 0)\r
416         {\r
417                 viewer.Replace(_T("%title"), title);\r
418         }\r
419 \r
420         if(!LaunchApplication(viewer, IDS_ERR_DIFFVIEWSTART, !!bWait))\r
421         {\r
422                 return FALSE;\r
423         }\r
424         return TRUE;\r
425 }\r
426 \r
427 BOOL CAppUtils::StartTextViewer(CString file)\r
428 {\r
429         CString viewer;\r
430         CRegString txt = CRegString(_T(".txt\\"), _T(""), FALSE, HKEY_CLASSES_ROOT);\r
431         viewer = txt;\r
432         viewer = viewer + _T("\\Shell\\Open\\Command\\");\r
433         CRegString txtexe = CRegString(viewer, _T(""), FALSE, HKEY_CLASSES_ROOT);\r
434         viewer = txtexe;\r
435 \r
436         DWORD len = ExpandEnvironmentStrings(viewer, NULL, 0);\r
437         TCHAR * buf = new TCHAR[len+1];\r
438         ExpandEnvironmentStrings(viewer, buf, len);\r
439         viewer = buf;\r
440         delete [] buf;\r
441         len = ExpandEnvironmentStrings(file, NULL, 0);\r
442         buf = new TCHAR[len+1];\r
443         ExpandEnvironmentStrings(file, buf, len);\r
444         file = buf;\r
445         delete [] buf;\r
446         file = _T("\"")+file+_T("\"");\r
447         if (viewer.IsEmpty())\r
448         {\r
449                 OPENFILENAME ofn = {0};                         // common dialog box structure\r
450                 TCHAR szFile[MAX_PATH] = {0};           // buffer for file name. Explorer can't handle paths longer than MAX_PATH.\r
451                 // Initialize OPENFILENAME\r
452                 ofn.lStructSize = sizeof(OPENFILENAME);\r
453                 ofn.hwndOwner = NULL;\r
454                 ofn.lpstrFile = szFile;\r
455                 ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);\r
456                 CString sFilter;\r
457                 sFilter.LoadString(IDS_PROGRAMSFILEFILTER);\r
458                 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];\r
459                 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);\r
460                 // Replace '|' delimiters with '\0's\r
461                 TCHAR *ptr = pszFilters + _tcslen(pszFilters);  //set ptr at the NULL\r
462                 while (ptr != pszFilters)\r
463                 {\r
464                         if (*ptr == '|')\r
465                                 *ptr = '\0';\r
466                         ptr--;\r
467                 }\r
468                 ofn.lpstrFilter = pszFilters;\r
469                 ofn.nFilterIndex = 1;\r
470                 ofn.lpstrFileTitle = NULL;\r
471                 ofn.nMaxFileTitle = 0;\r
472                 ofn.lpstrInitialDir = NULL;\r
473                 CString temp;\r
474                 temp.LoadString(IDS_UTILS_SELECTTEXTVIEWER);\r
475                 CStringUtils::RemoveAccelerators(temp);\r
476                 ofn.lpstrTitle = temp;\r
477                 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;\r
478 \r
479                 // Display the Open dialog box. \r
480 \r
481                 if (GetOpenFileName(&ofn)==TRUE)\r
482                 {\r
483                         delete [] pszFilters;\r
484                         viewer = CString(ofn.lpstrFile);\r
485                 }\r
486                 else\r
487                 {\r
488                         delete [] pszFilters;\r
489                         return FALSE;\r
490                 }\r
491         }\r
492         if (viewer.Find(_T("\"%1\"")) >= 0)\r
493         {\r
494                 viewer.Replace(_T("\"%1\""), file);\r
495         }\r
496         else if (viewer.Find(_T("%1")) >= 0)\r
497         {\r
498                 viewer.Replace(_T("%1"),  file);\r
499         }\r
500         else\r
501         {\r
502                 viewer += _T(" ");\r
503                 viewer += file;\r
504         }\r
505 \r
506         if(!LaunchApplication(viewer, IDS_ERR_TEXTVIEWSTART, false))\r
507         {\r
508                 return FALSE;\r
509         }\r
510         return TRUE;\r
511 }\r
512 \r
513 BOOL CAppUtils::CheckForEmptyDiff(const CTGitPath& sDiffPath)\r
514 {\r
515         DWORD length = 0;\r
516         HANDLE hFile = ::CreateFile(sDiffPath.GetWinPath(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);\r
517         if (hFile == INVALID_HANDLE_VALUE)\r
518                 return TRUE;\r
519         length = ::GetFileSize(hFile, NULL);\r
520         ::CloseHandle(hFile);\r
521         if (length < 4)\r
522                 return TRUE;\r
523         return FALSE;\r
524 \r
525 }\r
526 \r
527 void CAppUtils::CreateFontForLogs(CFont& fontToCreate)\r
528 {\r
529         LOGFONT logFont;\r
530         HDC hScreenDC = ::GetDC(NULL);\r
531         logFont.lfHeight         = -MulDiv((DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8), GetDeviceCaps(hScreenDC, LOGPIXELSY), 72);\r
532         ::ReleaseDC(NULL, hScreenDC);\r
533         logFont.lfWidth          = 0;\r
534         logFont.lfEscapement     = 0;\r
535         logFont.lfOrientation    = 0;\r
536         logFont.lfWeight         = FW_NORMAL;\r
537         logFont.lfItalic         = 0;\r
538         logFont.lfUnderline      = 0;\r
539         logFont.lfStrikeOut      = 0;\r
540         logFont.lfCharSet        = DEFAULT_CHARSET;\r
541         logFont.lfOutPrecision   = OUT_DEFAULT_PRECIS;\r
542         logFont.lfClipPrecision  = CLIP_DEFAULT_PRECIS;\r
543         logFont.lfQuality        = DRAFT_QUALITY;\r
544         logFont.lfPitchAndFamily = FF_DONTCARE | FIXED_PITCH;\r
545         _tcscpy_s(logFont.lfFaceName, 32, (LPCTSTR)(CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")));\r
546         VERIFY(fontToCreate.CreateFontIndirect(&logFont));\r
547 }\r
548 \r
549 bool CAppUtils::LaunchApplication(const CString& sCommandLine, UINT idErrMessageFormat, bool bWaitForStartup)\r
550 {\r
551         STARTUPINFO startup;\r
552         PROCESS_INFORMATION process;\r
553         memset(&startup, 0, sizeof(startup));\r
554         startup.cb = sizeof(startup);\r
555         memset(&process, 0, sizeof(process));\r
556 \r
557         CString cleanCommandLine(sCommandLine);\r
558 \r
559         if (CreateProcess(NULL, const_cast<TCHAR*>((LPCTSTR)cleanCommandLine), NULL, NULL, FALSE, 0, 0, sOrigCWD, &startup, &process)==0)\r
560         {\r
561                 if(idErrMessageFormat != 0)\r
562                 {\r
563                         LPVOID lpMsgBuf;\r
564                         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
565                                 FORMAT_MESSAGE_FROM_SYSTEM | \r
566                                 FORMAT_MESSAGE_IGNORE_INSERTS,\r
567                                 NULL,\r
568                                 GetLastError(),\r
569                                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
570                                 (LPTSTR) &lpMsgBuf,\r
571                                 0,\r
572                                 NULL \r
573                                 );\r
574                         CString temp;\r
575                         temp.Format(idErrMessageFormat, lpMsgBuf);\r
576                         CMessageBox::Show(NULL, temp, _T("TortoiseGit"), MB_OK | MB_ICONINFORMATION);\r
577                         LocalFree( lpMsgBuf );\r
578                 }\r
579                 return false;\r
580         }\r
581 \r
582         if (bWaitForStartup)\r
583         {\r
584                 WaitForInputIdle(process.hProcess, 10000);\r
585         }\r
586 \r
587         CloseHandle(process.hThread);\r
588         CloseHandle(process.hProcess);\r
589         return true;\r
590 }\r
591 \r
592 /**\r
593 * Launch the external blame viewer\r
594 */\r
595 bool CAppUtils::LaunchTortoiseBlame(const CString& sBlameFile,CString Rev,const CString& sParams)\r
596 {\r
597         CString viewer = CPathUtils::GetAppDirectory();\r
598         viewer += _T("TortoiseGitBlame.exe");\r
599         viewer += _T(" \"") + sBlameFile + _T("\"");\r
600         //viewer += _T(" \"") + sLogFile + _T("\"");\r
601         //viewer += _T(" \"") + sOriginalFile + _T("\"");\r
602         if(!Rev.IsEmpty())\r
603                 viewer += CString(_T(" /rev:"))+Rev;\r
604         viewer += _T(" ")+sParams;\r
605         \r
606         return LaunchApplication(viewer, IDS_ERR_EXTDIFFSTART, false);\r
607 }\r
608 \r
609 void CAppUtils::ResizeAllListCtrlCols(CListCtrl * pListCtrl)\r
610 {\r
611         int maxcol = ((CHeaderCtrl*)(pListCtrl->GetDlgItem(0)))->GetItemCount()-1;\r
612         int nItemCount = pListCtrl->GetItemCount();\r
613         TCHAR textbuf[MAX_PATH];\r
614         CHeaderCtrl * pHdrCtrl = (CHeaderCtrl*)(pListCtrl->GetDlgItem(0));\r
615         if (pHdrCtrl)\r
616         {\r
617                 for (int col = 0; col <= maxcol; col++)\r
618                 {\r
619                         HDITEM hdi = {0};\r
620                         hdi.mask = HDI_TEXT;\r
621                         hdi.pszText = textbuf;\r
622                         hdi.cchTextMax = sizeof(textbuf);\r
623                         pHdrCtrl->GetItem(col, &hdi);\r
624                         int cx = pListCtrl->GetStringWidth(hdi.pszText)+20; // 20 pixels for col separator and margin\r
625                         for (int index = 0; index<nItemCount; ++index)\r
626                         {\r
627                                 // get the width of the string and add 14 pixels for the column separator and margins\r
628                                 int linewidth = pListCtrl->GetStringWidth(pListCtrl->GetItemText(index, col)) + 14;\r
629                                 if (index == 0)\r
630                                 {\r
631                                         // add the image size\r
632                                         CImageList * pImgList = pListCtrl->GetImageList(LVSIL_SMALL);\r
633                                         if ((pImgList)&&(pImgList->GetImageCount()))\r
634                                         {\r
635                                                 IMAGEINFO imginfo;\r
636                                                 pImgList->GetImageInfo(0, &imginfo);\r
637                                                 linewidth += (imginfo.rcImage.right - imginfo.rcImage.left);\r
638                                                 linewidth += 3; // 3 pixels between icon and text\r
639                                         }\r
640                                 }\r
641                                 if (cx < linewidth)\r
642                                         cx = linewidth;\r
643                         }\r
644                         pListCtrl->SetColumnWidth(col, cx);\r
645 \r
646                 }\r
647         }\r
648 }\r
649 \r
650 bool CAppUtils::FormatTextInRichEditControl(CWnd * pWnd)\r
651 {\r
652         CString sText;\r
653         if (pWnd == NULL)\r
654                 return false;\r
655         bool bStyled = false;\r
656         pWnd->GetWindowText(sText);\r
657         // the rich edit control doesn't count the CR char!\r
658         // to be exact: CRLF is treated as one char.\r
659         sText.Replace(_T("\r"), _T(""));\r
660 \r
661         // style each line separately\r
662         int offset = 0;\r
663         int nNewlinePos;\r
664         do \r
665         {\r
666                 nNewlinePos = sText.Find('\n', offset);\r
667                 CString sLine = sText.Mid(offset);\r
668                 if (nNewlinePos>=0)\r
669                         sLine = sLine.Left(nNewlinePos-offset);\r
670                 int start = 0;\r
671                 int end = 0;\r
672                 while (FindStyleChars(sLine, '*', start, end))\r
673                 {\r
674                         CHARRANGE range = {(LONG)start+offset, (LONG)end+offset};\r
675                         pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);\r
676                         CHARFORMAT2 format;\r
677                         SecureZeroMemory(&format, sizeof(CHARFORMAT2));\r
678                         format.cbSize = sizeof(CHARFORMAT2);\r
679                         format.dwMask = CFM_BOLD;\r
680                         format.dwEffects = CFE_BOLD;\r
681                         pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);\r
682                         bStyled = true;\r
683                         start = end;\r
684                 }\r
685                 start = 0;\r
686                 end = 0;\r
687                 while (FindStyleChars(sLine, '^', start, end))\r
688                 {\r
689                         CHARRANGE range = {(LONG)start+offset, (LONG)end+offset};\r
690                         pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);\r
691                         CHARFORMAT2 format;\r
692                         SecureZeroMemory(&format, sizeof(CHARFORMAT2));\r
693                         format.cbSize = sizeof(CHARFORMAT2);\r
694                         format.dwMask = CFM_ITALIC;\r
695                         format.dwEffects = CFE_ITALIC;\r
696                         pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);\r
697                         bStyled = true;\r
698                         start = end;\r
699                 }\r
700                 start = 0;\r
701                 end = 0;\r
702                 while (FindStyleChars(sLine, '_', start, end))\r
703                 {\r
704                         CHARRANGE range = {(LONG)start+offset, (LONG)end+offset};\r
705                         pWnd->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);\r
706                         CHARFORMAT2 format;\r
707                         SecureZeroMemory(&format, sizeof(CHARFORMAT2));\r
708                         format.cbSize = sizeof(CHARFORMAT2);\r
709                         format.dwMask = CFM_UNDERLINE;\r
710                         format.dwEffects = CFE_UNDERLINE;\r
711                         pWnd->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);\r
712                         bStyled = true;\r
713                         start = end;\r
714                 }\r
715                 offset = nNewlinePos+1;\r
716         } while(nNewlinePos>=0);\r
717         return bStyled; \r
718 }\r
719 \r
720 bool CAppUtils::FindStyleChars(const CString& sText, TCHAR stylechar, int& start, int& end)\r
721 {\r
722         int i=start;\r
723         bool bFoundMarker = false;\r
724         // find a starting marker\r
725         while (sText[i] != 0)\r
726         {\r
727                 if (sText[i] == stylechar)\r
728                 {\r
729                         if (((i+1)<sText.GetLength())&&(IsCharAlphaNumeric(sText[i+1])) &&\r
730                                 (((i>0)&&(!IsCharAlphaNumeric(sText[i-1])))||(i==0)))\r
731                         {\r
732                                 start = i+1;\r
733                                 i++;\r
734                                 bFoundMarker = true;\r
735                                 break;\r
736                         }\r
737                 }\r
738                 i++;\r
739         }\r
740         if (!bFoundMarker)\r
741                 return false;\r
742         // find ending marker\r
743         bFoundMarker = false;\r
744         while (sText[i] != 0)\r
745         {\r
746                 if (sText[i] == stylechar)\r
747                 {\r
748                         if ((IsCharAlphaNumeric(sText[i-1])) &&\r
749                                 ((((i+1)<sText.GetLength())&&(!IsCharAlphaNumeric(sText[i+1])))||(i+1)==sText.GetLength()))\r
750                         {\r
751                                 end = i;\r
752                                 i++;\r
753                                 bFoundMarker = true;\r
754                                 break;\r
755                         }\r
756                 }\r
757                 i++;\r
758         }\r
759         return bFoundMarker;\r
760 }\r
761 \r
762 bool CAppUtils::BrowseRepository(CHistoryCombo& combo, CWnd * pParent, GitRev& rev)\r
763 {\r
764 #if 0\r
765         CString strUrl;\r
766         combo.GetWindowText(strUrl);\r
767         strUrl.Replace('\\', '/');\r
768         strUrl.Replace(_T("%"), _T("%25"));\r
769         strUrl = CUnicodeUtils::GetUnicode(CPathUtils::PathEscape(CUnicodeUtils::GetUTF8(strUrl)));\r
770         if (strUrl.Left(7) == _T("file://"))\r
771         {\r
772                 CString strFile(strUrl);\r
773                 Git::UrlToPath(strFile);\r
774 \r
775                 Git svn;\r
776                 if (svn.IsRepository(CTGitPath(strFile)))\r
777                 {\r
778                         // browse repository - show repository browser\r
779                         Git::preparePath(strUrl);\r
780                         CRepositoryBrowser browser(strUrl, rev, pParent);\r
781                         if (browser.DoModal() == IDOK)\r
782                         {\r
783                                 combo.SetCurSel(-1);\r
784                                 combo.SetWindowText(browser.GetPath());\r
785                                 rev = browser.GetRevision();\r
786                                 return true;\r
787                         }\r
788                 }\r
789                 else\r
790                 {\r
791                         // browse local directories\r
792                         CBrowseFolder folderBrowser;\r
793                         folderBrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;\r
794                         // remove the 'file:///' so the shell can recognize the local path\r
795                         Git::UrlToPath(strUrl);\r
796                         if (folderBrowser.Show(pParent->GetSafeHwnd(), strUrl) == CBrowseFolder::OK)\r
797                         {\r
798                                 Git::PathToUrl(strUrl);\r
799 \r
800                                 combo.SetCurSel(-1);\r
801                                 combo.SetWindowText(strUrl);\r
802                                 return true;\r
803                         }\r
804                 }\r
805         }\r
806         else if ((strUrl.Left(7) == _T("http://")\r
807                 ||(strUrl.Left(8) == _T("https://"))\r
808                 ||(strUrl.Left(6) == _T("svn://"))\r
809                 ||(strUrl.Left(4) == _T("svn+"))) && strUrl.GetLength() > 6)\r
810         {\r
811                 // browse repository - show repository browser\r
812                 CRepositoryBrowser browser(strUrl, rev, pParent);\r
813                 if (browser.DoModal() == IDOK)\r
814                 {\r
815                         combo.SetCurSel(-1);\r
816                         combo.SetWindowText(browser.GetPath());\r
817                         rev = browser.GetRevision();\r
818                         return true;\r
819                 }\r
820         }\r
821         else\r
822         {\r
823                 // browse local directories\r
824                 CBrowseFolder folderBrowser;\r
825                 folderBrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;\r
826                 if (folderBrowser.Show(pParent->GetSafeHwnd(), strUrl) == CBrowseFolder::OK)\r
827                 {\r
828                         Git::PathToUrl(strUrl);\r
829 \r
830                         combo.SetCurSel(-1);\r
831                         combo.SetWindowText(strUrl);\r
832                         return true;\r
833                 }\r
834         }\r
835 #endif\r
836         return false;\r
837 }\r
838 \r
839 bool CAppUtils::FileOpenSave(CString& path, int * filterindex, UINT title, UINT filter, bool bOpen, HWND hwndOwner)\r
840 {\r
841         OPENFILENAME ofn = {0};                         // common dialog box structure\r
842         TCHAR szFile[MAX_PATH] = {0};           // buffer for file name. Explorer can't handle paths longer than MAX_PATH.\r
843         ofn.lStructSize = sizeof(OPENFILENAME);\r
844         ofn.hwndOwner = hwndOwner;\r
845         _tcscpy_s(szFile, MAX_PATH, (LPCTSTR)path);\r
846         ofn.lpstrFile = szFile;\r
847         ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);\r
848         CString sFilter;\r
849         TCHAR * pszFilters = NULL;\r
850         if (filter)\r
851         {\r
852                 sFilter.LoadString(filter);\r
853                 pszFilters = new TCHAR[sFilter.GetLength()+4];\r
854                 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);\r
855                 // Replace '|' delimiters with '\0's\r
856                 TCHAR *ptr = pszFilters + _tcslen(pszFilters);  //set ptr at the NULL\r
857                 while (ptr != pszFilters)\r
858                 {\r
859                         if (*ptr == '|')\r
860                                 *ptr = '\0';\r
861                         ptr--;\r
862                 }\r
863                 ofn.lpstrFilter = pszFilters;\r
864         }\r
865         ofn.nFilterIndex = 1;\r
866         ofn.lpstrFileTitle = NULL;\r
867         ofn.nMaxFileTitle = 0;\r
868         ofn.lpstrInitialDir = NULL;\r
869         CString temp;\r
870         if (title)\r
871         {\r
872                 temp.LoadString(title);\r
873                 CStringUtils::RemoveAccelerators(temp);\r
874         }\r
875         ofn.lpstrTitle = temp;\r
876         if (bOpen)\r
877                 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER;\r
878         else\r
879                 ofn.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER;\r
880 \r
881 \r
882         // Display the Open dialog box. \r
883         bool bRet = false;\r
884         if (bOpen)\r
885         {\r
886                 bRet = !!GetOpenFileName(&ofn);\r
887         }\r
888         else\r
889         {\r
890                 bRet = !!GetSaveFileName(&ofn);\r
891         }\r
892         if (bRet)\r
893         {\r
894                 if (pszFilters)\r
895                         delete [] pszFilters;\r
896                 path = CString(ofn.lpstrFile);\r
897                 if (filterindex)\r
898                         *filterindex = ofn.nFilterIndex;\r
899                 return true;\r
900         }\r
901         if (pszFilters)\r
902                 delete [] pszFilters;\r
903         return false;\r
904 }\r
905 \r
906 bool CAppUtils::SetListCtrlBackgroundImage(HWND hListCtrl, UINT nID, int width /* = 128 */, int height /* = 128 */)\r
907 {\r
908         ListView_SetTextBkColor(hListCtrl, CLR_NONE);\r
909         COLORREF bkColor = ListView_GetBkColor(hListCtrl);\r
910         // create a bitmap from the icon\r
911         HICON hIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(nID), IMAGE_ICON, width, height, LR_DEFAULTCOLOR);\r
912         if (!hIcon)\r
913                 return false;\r
914 \r
915         RECT rect = {0};\r
916         rect.right = width;\r
917         rect.bottom = height;\r
918         HBITMAP bmp = NULL;\r
919 \r
920         HWND desktop = ::GetDesktopWindow();\r
921         if (desktop)\r
922         {\r
923                 HDC screen_dev = ::GetDC(desktop);\r
924                 if (screen_dev)\r
925                 {\r
926                         // Create a compatible DC\r
927                         HDC dst_hdc = ::CreateCompatibleDC(screen_dev);\r
928                         if (dst_hdc)\r
929                         {\r
930                                 // Create a new bitmap of icon size\r
931                                 bmp = ::CreateCompatibleBitmap(screen_dev, rect.right, rect.bottom);\r
932                                 if (bmp)\r
933                                 {\r
934                                         // Select it into the compatible DC\r
935                                         HBITMAP old_dst_bmp = (HBITMAP)::SelectObject(dst_hdc, bmp);\r
936                                         // Fill the background of the compatible DC with the given color\r
937                                         ::SetBkColor(dst_hdc, bkColor);\r
938                                         ::ExtTextOut(dst_hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);\r
939 \r
940                                         // Draw the icon into the compatible DC\r
941                                         ::DrawIconEx(dst_hdc, 0, 0, hIcon, rect.right, rect.bottom, 0, NULL, DI_NORMAL);\r
942                                         ::SelectObject(dst_hdc, old_dst_bmp);\r
943                                 }\r
944                                 ::DeleteDC(dst_hdc);\r
945                         }\r
946                 }\r
947                 ::ReleaseDC(desktop, screen_dev); \r
948         }\r
949 \r
950         // Restore settings\r
951         DestroyIcon(hIcon);\r
952 \r
953         if (bmp == NULL)\r
954                 return false;\r
955 \r
956         LVBKIMAGE lv;\r
957         lv.ulFlags = LVBKIF_TYPE_WATERMARK;\r
958         lv.hbm = bmp;\r
959         lv.xOffsetPercent = 100;\r
960         lv.yOffsetPercent = 100;\r
961         ListView_SetBkImage(hListCtrl, &lv);\r
962         return true;\r
963 }\r
964 \r
965 CString CAppUtils::GetProjectNameFromURL(CString url)\r
966 {\r
967         CString name;\r
968         while (name.IsEmpty() || (name.CompareNoCase(_T("branches"))==0) ||\r
969                 (name.CompareNoCase(_T("tags"))==0) ||\r
970                 (name.CompareNoCase(_T("trunk"))==0))\r
971         {\r
972                 name = url.Mid(url.ReverseFind('/')+1);\r
973                 url = url.Left(url.ReverseFind('/'));\r
974         }\r
975         if ((name.Compare(_T("svn")) == 0)||(name.Compare(_T("svnroot")) == 0))\r
976         {\r
977                 // a name of svn or svnroot indicates that it's not really the project name. In that\r
978                 // case, we try the first part of the URL\r
979                 // of course, this won't work in all cases (but it works for Google project hosting)\r
980                 url.Replace(_T("http://"), _T(""));\r
981                 url.Replace(_T("https://"), _T(""));\r
982                 url.Replace(_T("svn://"), _T(""));\r
983                 url.Replace(_T("svn+ssh://"), _T(""));\r
984                 url.TrimLeft(_T("/"));\r
985                 name = url.Left(url.Find('.'));\r
986         }\r
987         return name;\r
988 }\r
989 \r
990 bool CAppUtils::StartShowUnifiedDiff(HWND hWnd, const CTGitPath& url1, const git_revnum_t& rev1, \r
991                                                                                                 const CTGitPath& url2, const git_revnum_t& rev2, \r
992                                                                          //const GitRev& peg /* = GitRev */, const GitRev& headpeg /* = GitRev */,  \r
993                                                                                                 bool bAlternateDiff /* = false */, bool bIgnoreAncestry /* = false */, bool /* blame = false */)\r
994 {\r
995 \r
996         CString tempfile=GetTempFile();\r
997         CString cmd;\r
998         if(rev1 == GitRev::GetWorkingCopy())\r
999         {\r
1000                 cmd.Format(_T("git.exe diff --stat -p %s"),rev2);\r
1001         }else\r
1002         {       \r
1003                 cmd.Format(_T("git.exe diff-tree -r -p --stat %s %s"),rev1,rev2);\r
1004         }\r
1005         g_Git.RunLogFile(cmd,tempfile);\r
1006         CAppUtils::StartUnifiedDiffViewer(tempfile,rev1.Left(6)+_T(":")+rev2.Left(6));\r
1007 \r
1008 \r
1009 #if 0\r
1010         CString sCmd;\r
1011         sCmd.Format(_T("%s /command:showcompare /unified"),\r
1012                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")));\r
1013         sCmd += _T(" /url1:\"") + url1.GetGitPathString() + _T("\"");\r
1014         if (rev1.IsValid())\r
1015                 sCmd += _T(" /revision1:") + rev1.ToString();\r
1016         sCmd += _T(" /url2:\"") + url2.GetGitPathString() + _T("\"");\r
1017         if (rev2.IsValid())\r
1018                 sCmd += _T(" /revision2:") + rev2.ToString();\r
1019         if (peg.IsValid())\r
1020                 sCmd += _T(" /pegrevision:") + peg.ToString();\r
1021         if (headpeg.IsValid())\r
1022                 sCmd += _T(" /headpegrevision:") + headpeg.ToString();\r
1023 \r
1024         if (bAlternateDiff)\r
1025                 sCmd += _T(" /alternatediff");\r
1026 \r
1027         if (bIgnoreAncestry)\r
1028                 sCmd += _T(" /ignoreancestry");\r
1029 \r
1030         if (hWnd)\r
1031         {\r
1032                 sCmd += _T(" /hwnd:");\r
1033                 TCHAR buf[30];\r
1034                 _stprintf_s(buf, 30, _T("%d"), hWnd);\r
1035                 sCmd += buf;\r
1036         }\r
1037 \r
1038         return CAppUtils::LaunchApplication(sCmd, NULL, false);\r
1039 #endif\r
1040         return TRUE;\r
1041 }\r
1042 \r
1043 bool CAppUtils::StartShowCompare(HWND hWnd, const CTGitPath& url1, const GitRev& rev1, \r
1044                                                                  const CTGitPath& url2, const GitRev& rev2, \r
1045                                                                  const GitRev& peg /* = GitRev */, const GitRev& headpeg /* = GitRev */, \r
1046                                                                  bool bAlternateDiff /* = false */, bool bIgnoreAncestry /* = false */, bool blame /* = false */)\r
1047 {\r
1048 #if 0\r
1049         CString sCmd;\r
1050         sCmd.Format(_T("%s /command:showcompare"),\r
1051                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")));\r
1052         sCmd += _T(" /url1:\"") + url1.GetGitPathString() + _T("\"");\r
1053         if (rev1.IsValid())\r
1054                 sCmd += _T(" /revision1:") + rev1.ToString();\r
1055         sCmd += _T(" /url2:\"") + url2.GetGitPathString() + _T("\"");\r
1056         if (rev2.IsValid())\r
1057                 sCmd += _T(" /revision2:") + rev2.ToString();\r
1058         if (peg.IsValid())\r
1059                 sCmd += _T(" /pegrevision:") + peg.ToString();\r
1060         if (headpeg.IsValid())\r
1061                 sCmd += _T(" /headpegrevision:") + headpeg.ToString();\r
1062         if (bAlternateDiff)\r
1063                 sCmd += _T(" /alternatediff");\r
1064         if (bIgnoreAncestry)\r
1065                 sCmd += _T(" /ignoreancestry");\r
1066         if (blame)\r
1067                 sCmd += _T(" /blame");\r
1068 \r
1069         if (hWnd)\r
1070         {\r
1071                 sCmd += _T(" /hwnd:");\r
1072                 TCHAR buf[30];\r
1073                 _stprintf_s(buf, 30, _T("%d"), hWnd);\r
1074                 sCmd += buf;\r
1075         }\r
1076 \r
1077         return CAppUtils::LaunchApplication(sCmd, NULL, false);\r
1078 #endif\r
1079         return true;\r
1080 }\r
1081 \r
1082 bool CAppUtils::Export(CString *BashHash)\r
1083 {\r
1084         bool bRet = false;\r
1085 \r
1086                 // ask from where the export has to be done\r
1087         CExportDlg dlg;\r
1088         if(BashHash)\r
1089                 dlg.m_Revision=*BashHash;\r
1090 \r
1091         if (dlg.DoModal() == IDOK)\r
1092         {\r
1093                 CString cmd;\r
1094                 cmd.Format(_T("git.exe archive --format=zip --verbose %s"),\r
1095                                         dlg.m_VersionName);\r
1096 \r
1097                 //g_Git.RunLogFile(cmd,dlg.m_strExportDirectory);\r
1098                 CProgressDlg pro;\r
1099                 pro.m_GitCmd=cmd;\r
1100                 pro.m_LogFile=dlg.m_strExportDirectory;\r
1101                 pro.DoModal();\r
1102                 return TRUE;\r
1103         }\r
1104         return bRet;\r
1105 }\r
1106 \r
1107 bool CAppUtils::CreateBranchTag(bool IsTag,CString *CommitHash)\r
1108 {\r
1109         CCreateBranchTagDlg dlg;\r
1110         dlg.m_bIsTag=IsTag;\r
1111         if(CommitHash)\r
1112                 dlg.m_Base = *CommitHash;\r
1113 \r
1114         if(dlg.DoModal()==IDOK)\r
1115         {\r
1116                 CString cmd;\r
1117                 CString force;\r
1118                 CString track;\r
1119                 if(dlg.m_bTrack)\r
1120                         track=_T("--track");\r
1121 \r
1122                 if(dlg.m_bForce)\r
1123                         force=_T("-f");\r
1124 \r
1125                 if(IsTag)\r
1126                 {\r
1127                         cmd.Format(_T("git.exe tag %s %s %s %s"),\r
1128                                 track,\r
1129                                 force,\r
1130                                 dlg.m_BranchTagName,\r
1131                                 dlg.m_VersionName\r
1132                                 );\r
1133 \r
1134         \r
1135                 }else\r
1136                 {\r
1137                         cmd.Format(_T("git.exe branch %s %s %s %s"),\r
1138                                 track,\r
1139                                 force,\r
1140                                 dlg.m_BranchTagName,\r
1141                                 dlg.m_VersionName\r
1142                                 );\r
1143                 }\r
1144                 CString out;\r
1145                 if(g_Git.Run(cmd,&out))\r
1146                 {\r
1147                         CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);\r
1148                 }\r
1149                 return TRUE;\r
1150                 \r
1151         }\r
1152         return FALSE;\r
1153 }\r
1154 \r
1155 bool CAppUtils::Switch(CString *CommitHash)\r
1156 {\r
1157         CGitSwitchDlg dlg;\r
1158         if(CommitHash)\r
1159                 dlg.m_Base=*CommitHash;\r
1160         \r
1161         if (dlg.DoModal() == IDOK)\r
1162         {\r
1163                 CString cmd;\r
1164                 CString track;\r
1165                 CString base;\r
1166                 CString force;\r
1167                 CString branch;\r
1168 \r
1169                 if(dlg.m_bBranch)\r
1170                         branch.Format(_T("-b %s"),dlg.m_NewBranch);\r
1171                 if(dlg.m_bForce)\r
1172                         force=_T("-f");\r
1173                 if(dlg.m_bTrack)\r
1174                         track=_T("--track");\r
1175 \r
1176                 cmd.Format(_T("git.exe checkout %s %s %s %s"),\r
1177                          force,\r
1178                          track,\r
1179                          branch,\r
1180                          dlg.m_VersionName);\r
1181 \r
1182                 CProgressDlg progress;\r
1183                 progress.m_GitCmd=cmd;\r
1184                 if(progress.DoModal()==IDOK)\r
1185                         return TRUE;\r
1186 \r
1187         }\r
1188         return FALSE;\r
1189 }\r
1190 \r
1191 bool CAppUtils::IgnoreFile(CTGitPath &path,bool IsMask)\r
1192 {\r
1193         CString ignorefile;\r
1194         ignorefile=g_Git.m_CurrentDir;\r
1195         ignorefile+=path.GetDirectory().GetWinPathString()+_T("\\.gitignore");\r
1196 \r
1197         CStdioFile file;\r
1198         if(!file.Open(ignorefile,CFile::modeCreate|CFile::modeWrite))\r
1199         {\r
1200                 CMessageBox::Show(NULL,ignorefile+_T(" Open Failure"),_T("TortoiseGit"),MB_OK);\r
1201                 return FALSE;\r
1202         }\r
1203 \r
1204         CString ignorelist;\r
1205         file.ReadString(ignorelist);\r
1206 \r
1207         if(IsMask)\r
1208         {\r
1209                 ignorelist+=_T("\n*.")+path.GetFileExtension();\r
1210         }else\r
1211         {\r
1212                 ignorelist+=_T("\n")+path.GetBaseFilename();\r
1213         }\r
1214         file.WriteString(ignorelist);\r
1215 \r
1216         file.Close();\r
1217         return TRUE;\r
1218 }