OSDN Git Service

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