drop repositorybrowser
[TortoiseGit.git] / src / TortoiseProc / Commands / CreatePatchCommand.cpp
blob5e9ecbf56858cc6988c8b749cfff5d60c2437065
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2007-2008 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "StdAfx.h"
20 #include "CreatePatchCommand.h"
22 #include "PathUtils.h"
23 #include "StringUtils.h"
24 #include "AppUtils.h"
25 #include "CreatePatchDlg.h"
26 #include "SVN.h"
27 #include "TempFile.h"
28 #include "ProgressDlg.h"
30 #define PATCH_TO_CLIPBOARD_PSEUDO_FILENAME _T(".TSVNPatchToClipboard")
33 bool CreatePatchCommand::Execute()
35 bool bRet = false;
36 CString savepath = CPathUtils::GetLongPathname(parser.GetVal(_T("savepath")));
37 CCreatePatch dlg;
38 dlg.m_pathList = pathList;
39 if (dlg.DoModal()==IDOK)
41 if (cmdLinePath.IsEmpty())
43 cmdLinePath = pathList.GetCommonRoot();
45 bRet = CreatePatch(cmdLinePath.GetDirectory(), dlg.m_pathList, CTSVNPath(savepath));
46 SVN svn;
47 svn.Revert(dlg.m_filesToRevert, CStringArray(), false);
49 return bRet;
52 UINT_PTR CALLBACK CreatePatchCommand::CreatePatchFileOpenHook(HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM /*lParam*/)
54 if(uiMsg == WM_COMMAND && LOWORD(wParam) == IDC_PATCH_TO_CLIPBOARD)
56 HWND hFileDialog = GetParent(hDlg);
58 CString strFilename = CTempFiles::Instance().GetTempFilePath(false).GetWinPathString() + PATCH_TO_CLIPBOARD_PSEUDO_FILENAME;
60 CommDlg_OpenSave_SetControlText(hFileDialog, edt1, (LPCTSTR)strFilename);
62 PostMessage(hFileDialog, WM_COMMAND, MAKEWPARAM(IDOK, BM_CLICK), (LPARAM)(GetDlgItem(hDlg, IDOK)));
64 return 0;
67 bool CreatePatchCommand::CreatePatch(const CTSVNPath& root, const CTSVNPathList& path, const CTSVNPath& cmdLineSavePath)
69 OPENFILENAME ofn = {0}; // common dialog box structure
70 CString temp;
71 CTSVNPath savePath;
73 if (cmdLineSavePath.IsEmpty())
75 TCHAR szFile[MAX_PATH] = {0}; // buffer for file name
76 // Initialize OPENFILENAME
77 ofn.lStructSize = sizeof(OPENFILENAME);
78 ofn.hwndOwner = hwndExplorer;
79 ofn.lpstrFile = szFile;
80 ofn.nMaxFile = _countof(szFile);
81 ofn.lpstrInitialDir = root.GetWinPath();
83 temp.LoadString(IDS_REPOBROWSE_SAVEAS);
84 CStringUtils::RemoveAccelerators(temp);
85 if (temp.IsEmpty())
86 ofn.lpstrTitle = NULL;
87 else
88 ofn.lpstrTitle = temp;
89 ofn.Flags = OFN_OVERWRITEPROMPT | OFN_ENABLETEMPLATE | OFN_EXPLORER | OFN_ENABLEHOOK;
91 ofn.hInstance = AfxGetResourceHandle();
92 ofn.lpTemplateName = MAKEINTRESOURCE(IDD_PATCH_FILE_OPEN_CUSTOM);
93 ofn.lpfnHook = CreatePatchFileOpenHook;
95 CString sFilter;
96 sFilter.LoadString(IDS_PATCHFILEFILTER);
97 TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
98 _tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
99 // Replace '|' delimiters with '\0's
100 TCHAR *ptr = pszFilters + _tcslen(pszFilters); //set ptr at the NULL
101 while (ptr != pszFilters)
103 if (*ptr == '|')
104 *ptr = '\0';
105 ptr--;
107 ofn.lpstrFilter = pszFilters;
108 ofn.nFilterIndex = 1;
109 // Display the Open dialog box.
110 if (GetSaveFileName(&ofn)==FALSE)
112 delete [] pszFilters;
113 return FALSE;
115 delete [] pszFilters;
116 savePath = CTSVNPath(ofn.lpstrFile);
117 if (ofn.nFilterIndex == 1)
119 if (savePath.GetFileExtension().IsEmpty())
120 savePath.AppendRawString(_T(".patch"));
123 else
125 savePath = cmdLineSavePath;
128 // This is horrible and I should be ashamed of myself, but basically, the
129 // the file-open dialog writes ".TSVNPatchToClipboard" to its file field if the user clicks
130 // the "Save To Clipboard" button.
131 bool bToClipboard = _tcsstr(savePath.GetWinPath(), PATCH_TO_CLIPBOARD_PSEUDO_FILENAME) != NULL;
133 CProgressDlg progDlg;
134 progDlg.SetTitle(IDS_PROC_PATCHTITLE);
135 progDlg.SetShowProgressBar(false);
136 progDlg.ShowModeless(CWnd::FromHandle(hwndExplorer));
137 progDlg.FormatNonPathLine(1, IDS_PROC_SAVEPATCHTO);
138 if(bToClipboard)
140 progDlg.FormatNonPathLine(2, IDS_CLIPBOARD_PROGRESS_DEST);
142 else
144 progDlg.SetLine(2, savePath.GetUIPathString(), true);
146 //progDlg.SetAnimation(IDR_ANIMATION);
148 CTSVNPath tempPatchFilePath;
149 if (bToClipboard)
150 tempPatchFilePath = CTempFiles::Instance().GetTempFilePath(true);
151 else
152 tempPatchFilePath = savePath;
154 ::DeleteFile(tempPatchFilePath.GetWinPath());
156 CTSVNPath sDir = root;
157 if (sDir.IsEmpty())
158 sDir = path.GetCommonRoot();
160 SVN svn;
161 for (int fileindex = 0; fileindex < path.GetCount(); ++fileindex)
163 svn_depth_t depth = path[fileindex].IsDirectory() ? svn_depth_empty : svn_depth_files;
164 if (!svn.CreatePatch(path[fileindex], SVNRev::REV_BASE, path[fileindex], SVNRev::REV_WC, sDir.GetDirectory(), depth, FALSE, FALSE, FALSE, _T(""), true, tempPatchFilePath))
166 progDlg.Stop();
167 ::MessageBox(hwndExplorer, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);
168 return FALSE;
172 if(bToClipboard)
174 // The user actually asked for the patch to be written to the clipboard
175 CStringA sClipdata;
176 FILE * inFile;
177 _tfopen_s(&inFile, tempPatchFilePath.GetWinPath(), _T("rb"));
178 if(inFile)
180 char chunkBuffer[16384];
181 while(!feof(inFile))
183 size_t readLength = fread(chunkBuffer, 1, sizeof(chunkBuffer), inFile);
184 sClipdata.Append(chunkBuffer, (int)readLength);
186 fclose(inFile);
188 CStringUtils::WriteDiffToClipboard(sClipdata);
191 else
192 CAppUtils::StartUnifiedDiffViewer(tempPatchFilePath, tempPatchFilePath.GetFilename());
194 progDlg.Stop();
195 return TRUE;