OSDN Git Service

Move a part of CMainFrame::OnToolsGeneratePatch() to DirView and MergeDoc
[winmerge-jp/winmerge-jp.git] / Src / PatchTool.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    License (GPLv2+):
3 //    This program is free software; you can redistribute it and/or modify
4 //    it under the terms of the GNU General Public License as published by
5 //    the Free Software Foundation; either version 2 of the License, or (at
6 //    your option) any later version.
7 //    
8 //    This program is distributed in the hope that it will be useful, but
9 //    WITHOUT ANY WARRANTY; without even the implied warranty of
10 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //    GNU General Public License for more details.
12 //
13 //    You should have received a copy of the GNU General Public License
14 //    along with this program; if not, write to the Free Software
15 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 /////////////////////////////////////////////////////////////////////////////
17 /** 
18  * @file  PatchTool.cpp
19  *
20  * @brief Code file routines
21  */
22
23 #include "StdAfx.h"
24 #include "PatchTool.h"
25 #include "UnicodeString.h"
26 #include "DiffWrapper.h"
27 #include "PathContext.h"
28 #include "PatchDlg.h"
29 #include "paths.h"
30 #include "Merge.h"
31
32 #ifdef _DEBUG
33 #define new DEBUG_NEW
34 #endif
35
36 /**
37  * @brief Default constructor.
38  */
39 CPatchTool::CPatchTool() : m_bOpenToEditor(false)
40 {
41 }
42
43 /**
44  * @brief Default destructor.
45  */
46 CPatchTool::~CPatchTool()
47 {
48 }
49
50 /** 
51  * @brief Adds files to list for patching.
52  * @param [in] file1 First file to add.
53  * @param [in] file2 Second file to add.
54  */
55 void CPatchTool::AddFiles(const String &file1, const String &file2)
56 {
57         PATCHFILES files;
58         files.lfile = file1;
59         files.rfile = file2;
60
61         // TODO: Read and add file's timestamps
62         m_fileList.push_back(files);
63 }
64
65 /**
66  * @brief Add files with alternative paths.
67  * This function adds files with alternative paths. Alternative path is the
68  * one that is added to the patch file. So while @p file1 and @p file2 are
69  * paths in disk (can be temp file names), @p altPath1 and @p altPath2 are
70  * "visible " paths printed to the patch file.
71  * @param [in] file1 First path in disk.
72  * @param [in] altPath1 First path as printed to the patch file.
73  * @param [in] file2 Second path in disk.
74  * @param [in] altPath2 Second path as printed to the patch file.
75  */
76 void CPatchTool::AddFiles(const String &file1, const String &altPath1,
77                 const String &file2, const String &altPath2)
78 {
79         PATCHFILES files;
80         files.lfile = file1;
81         files.rfile = file2;
82         files.pathLeft = altPath1;
83         files.pathRight = altPath2;
84
85         // TODO: Read and add file's timestamps
86         m_fileList.push_back(files);
87 }
88
89 /** 
90  * @brief Create a patch from files given.
91  * @note Files can be given using AddFiles() or selecting using
92  * CPatchDlg.
93  */
94 int CPatchTool::CreatePatch()
95 {
96         DIFFSTATUS status;
97         int retVal = 0;
98
99         CPatchDlg dlgPatch;
100
101         // If files already inserted, add them to dialog
102     for(std::vector<PATCHFILES>::iterator iter = m_fileList.begin(); iter != m_fileList.end(); ++iter)
103     {
104         dlgPatch.AddItem(*iter);
105         }
106
107         if (ShowDialog(&dlgPatch))
108         {
109                 bool bResult = true;
110
111                 if (!paths_CreateIfNeeded(paths_GetPathOnly(dlgPatch.m_fileResult)))
112                 {
113                         LangMessageBox(IDS_FOLDER_NOTEXIST, MB_OK | MB_ICONSTOP);
114                         return 0;
115                 }
116
117                 // Select patch create -mode
118                 m_diffWrapper.SetCreatePatchFile(dlgPatch.m_fileResult);
119                 m_diffWrapper.SetAppendFiles(dlgPatch.m_appendFile);
120                 m_diffWrapper.SetPrediffer(NULL);
121
122                 size_t fileCount = dlgPatch.GetItemCount();
123
124                 m_diffWrapper.WritePatchFileHeader(dlgPatch.m_outputStyle, dlgPatch.m_appendFile);
125                 m_diffWrapper.SetAppendFiles(true);
126
127                 for (size_t index = 0; index < fileCount; index++)
128                 {
129                         const PATCHFILES& files = dlgPatch.GetItemAt(index);
130                         String filename1 = files.lfile.length() == 0 ? _T("NUL") : files.lfile;
131                         String filename2 = files.rfile.length() == 0 ? _T("NUL") : files.rfile;
132                         
133                         // Set up DiffWrapper
134                         m_diffWrapper.SetPaths(PathContext(filename1, filename2), false);
135                         m_diffWrapper.SetAlternativePaths(PathContext(files.pathLeft, files.pathRight));
136                         m_diffWrapper.SetCompareFiles(PathContext(files.lfile, files.rfile));
137                         bool bDiffSuccess = m_diffWrapper.RunFileDiff();
138                         m_diffWrapper.GetDiffStatus(&status);
139
140                         if (!bDiffSuccess)
141                         {
142                                 LangMessageBox(IDS_FILEERROR, MB_ICONSTOP);
143                                 bResult = false;
144                                 break;
145                         }
146                         else if (status.bBinaries)
147                         {
148                                 LangMessageBox(IDS_CANNOT_CREATE_BINARYPATCH, MB_ICONSTOP);
149                                 bResult = false;
150                                 break;
151                         }
152                         else if (status.bPatchFileFailed)
153                         {
154                                 String errMsg = string_format_string1(_("Could not write to file %1."), dlgPatch.m_fileResult);
155                                 AfxMessageBox(errMsg.c_str(), MB_ICONSTOP);
156                                 bResult = false;
157                                 break;
158                         }
159                 }
160                 
161                 m_diffWrapper.WritePatchFileTerminator(dlgPatch.m_outputStyle);
162
163                 if (bResult && fileCount > 0)
164                 {
165                         LangMessageBox(IDS_DIFF_SUCCEEDED, MB_ICONINFORMATION|MB_DONT_DISPLAY_AGAIN,
166                                             IDS_DIFF_SUCCEEDED);
167                         
168                         m_sPatchFile = dlgPatch.m_fileResult;
169                         m_bOpenToEditor = dlgPatch.m_openToEditor;
170                         retVal = 1;
171                 }
172         }
173         dlgPatch.ClearItems();
174         if (retVal)
175         {
176                 if (m_bOpenToEditor)
177                         theApp.OpenFileToExternalEditor(m_sPatchFile);
178         }
179         return retVal;
180 }
181
182 /** 
183  * @brief Show patch options dialog and check options selected.
184  * @return TRUE if user wants to create a patch (didn't cancel dialog).
185  */
186 bool CPatchTool::ShowDialog(CPatchDlg *pDlgPatch)
187 {
188         DIFFOPTIONS diffOptions = {0};
189         PATCHOPTIONS patchOptions;
190         bool bRetVal = true;
191
192         if (pDlgPatch->DoModal() == IDOK)
193         {
194                 // There must be one filepair
195                 if (pDlgPatch->GetItemCount() < 1)
196                         bRetVal = false;
197
198                 // These two are from dropdown list - can't be wrong
199                 patchOptions.outputStyle = pDlgPatch->m_outputStyle;
200                 patchOptions.nContext = pDlgPatch->m_contextLines;
201
202                 // Checkbox - can't be wrong
203                 patchOptions.bAddCommandline = !!pDlgPatch->m_includeCmdLine;
204                 m_diffWrapper.SetPatchOptions(&patchOptions);
205
206                 // These are from checkboxes and radiobuttons - can't be wrong
207                 diffOptions.nIgnoreWhitespace = pDlgPatch->m_whitespaceCompare;
208                 diffOptions.bIgnoreBlankLines = pDlgPatch->m_ignoreBlanks;
209                 m_diffWrapper.SetAppendFiles(pDlgPatch->m_appendFile);
210
211                 // Use this because non-sensitive setting can't write
212                 // patch file EOLs correctly
213                 diffOptions.bIgnoreEol = pDlgPatch->m_ignoreEOLDifference;
214                 
215                 diffOptions.bIgnoreCase = pDlgPatch->m_caseSensitive == false;
216                 m_diffWrapper.SetOptions(&diffOptions);
217         }
218         else
219                 return false;
220
221         return bRetVal;
222 }