OSDN Git Service

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