OSDN Git Service

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