OSDN Git Service

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