OSDN Git Service

Add WinMergePluginBase.h (2)
[winmerge-jp/winmerge-jp.git] / Src / FileActionScript.cpp
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /**
3  * @file  FileActionScript.cpp
4  *
5  * @brief Implementation of FileActionScript and related classes
6  */
7
8 #include "stdafx.h"
9 #include "FileActionScript.h"
10 #include <vector>
11 #include "UnicodeString.h"
12 #include "Merge.h"
13 #include "OptionsDef.h"
14 #include "OptionsMgr.h"
15 #include "ShellFileOperations.h"
16 #include "paths.h"
17
18 using std::vector;
19
20 /**
21  * @brief Standard constructor.
22  */
23 FileActionScript::FileActionScript()
24 : m_bUseRecycleBin(true)
25 , m_bHasCopyOperations(false)
26 , m_bHasMoveOperations(false)
27 , m_bHasRenameOperations(false)
28 , m_bHasDelOperations(false)
29 , m_hParentWindow(nullptr)
30 , m_pCopyOperations(new ShellFileOperations())
31 , m_pMoveOperations(new ShellFileOperations())
32 , m_pRenameOperations(new ShellFileOperations())
33 , m_pDelOperations(new ShellFileOperations())
34 , m_bCanceled(false)
35 {
36 }
37
38 /**
39  * @brief Standard destructor.
40  */
41 FileActionScript::~FileActionScript()
42 {
43 }
44
45 /**
46  * @brief Remove last action item from the list.
47  * @return Item removed from the list.
48  */
49 FileActionItem FileActionScript::RemoveTailActionItem()
50 {
51         FileActionItem item = m_actions.back();
52         m_actions.pop_back();
53         return item;
54 }
55
56 /**
57  * @brief Create ShellFileOperations operation lists from our scripts.
58  *
59  * We use ShellFileOperations internally to do actual file operations.
60  * ShellFileOperations can do only one type of operation (copy, move, delete)
61  * with one instance at a time, so we use own instance for every
62  * type of action.
63  * @return One of CreateScriptReturn values.
64  */
65 int FileActionScript::CreateOperationsScripts()
66 {
67         UINT operation = 0;
68         FILEOP_FLAGS operFlags = 0;
69         bool bContinue = true;
70
71         // Copy operations first
72         operation = FO_COPY;
73         operFlags |= FOF_NOCONFIRMMKDIR | FOF_MULTIDESTFILES | FOF_NOCONFIRMATION;
74         if (m_bUseRecycleBin)
75                 operFlags |= FOF_ALLOWUNDO;
76
77         vector<FileActionItem>::const_iterator iter = m_actions.begin();
78         while (iter != m_actions.end() && bContinue)
79         {
80                 bool bSkip = false;
81                 if ((*iter).atype == FileAction::ACT_COPY && !(*iter).dirflag)
82                 {
83                         if (bContinue)
84                         {
85                                 if (!theApp.CreateBackup(true, (*iter).dest))
86                                 {
87                                         String strErr = _("Error backing up file");
88                                         AfxMessageBox(strErr.c_str(), MB_OK | MB_ICONERROR);
89                                         bContinue = false;
90                                 }
91                         }
92                 }
93
94                 if ((*iter).atype == FileAction::ACT_COPY &&
95                         !bSkip && bContinue)
96                 {
97                         m_pCopyOperations->AddSourceAndDestination((*iter).src, (*iter).dest);
98                         m_bHasCopyOperations = true;
99                 }
100                 ++iter;
101         }
102         if (!bContinue)
103         {
104                 m_bHasCopyOperations = false;
105                 m_pCopyOperations->Reset();
106                 return SCRIPT_USERCANCEL;
107         }
108         
109         if (m_bHasCopyOperations)
110                 m_pCopyOperations->SetOperation(operation, operFlags, m_hParentWindow);
111
112         // Move operations next
113         operation = FO_MOVE;
114         operFlags = FOF_MULTIDESTFILES;
115         if (m_bUseRecycleBin)
116                 operFlags |= FOF_ALLOWUNDO;
117
118         iter = m_actions.begin();
119         while (iter != m_actions.end())
120         {
121                 if ((*iter).atype == FileAction::ACT_MOVE)
122                 {
123                         m_pMoveOperations->AddSourceAndDestination((*iter).src, (*iter).dest);
124                         m_bHasMoveOperations = true;
125                 }
126                 ++iter;
127         }
128         if (m_bHasMoveOperations)
129                 m_pMoveOperations->SetOperation(operation, operFlags,  m_hParentWindow);
130
131         // Rename operations nextbbbb
132         operation = FO_RENAME;
133         operFlags = FOF_MULTIDESTFILES;
134         if (m_bUseRecycleBin)
135                 operFlags |= FOF_ALLOWUNDO;
136
137         iter = m_actions.begin();
138         while (iter != m_actions.end())
139         {
140                 if ((*iter).atype == FileAction::ACT_RENAME)
141                 {
142                         m_pRenameOperations->AddSourceAndDestination((*iter).src, (*iter).dest);
143                         m_bHasRenameOperations = true;
144                 }
145                 ++iter;
146         }
147         if (m_bHasRenameOperations)
148                 m_pRenameOperations->SetOperation(operation, operFlags, m_hParentWindow);
149
150         // Delete operations last
151         operation = FO_DELETE;
152         operFlags = 0;
153         if (m_bUseRecycleBin)
154                 operFlags |= FOF_ALLOWUNDO;
155
156         iter = m_actions.begin();
157         while (iter != m_actions.end())
158         {
159                 if ((*iter).atype == FileAction::ACT_DEL)
160                 {
161                         m_pDelOperations->AddSource((*iter).src);
162                         if (!(*iter).dest.empty())
163                                 m_pDelOperations->AddSource((*iter).dest);
164                         m_bHasDelOperations = true;
165                 }
166                 ++iter;
167         }
168         if (m_bHasDelOperations)
169                 m_pDelOperations->SetOperation(operation, operFlags, m_hParentWindow);
170         return SCRIPT_SUCCESS;
171 }
172
173 /**
174  * @brief Run one operation set.
175  * @param [in] oplist List of operations to run.
176  * @param [out] userCancelled Did user cancel the operation?
177  * @return true if the operation succeeded and finished.
178  */
179 bool FileActionScript::RunOp(ShellFileOperations *oplist, bool & userCancelled)
180 {
181         bool fileOpSucceed = false;
182         __try
183         {
184                 fileOpSucceed = oplist->Run();
185                 userCancelled = oplist->IsCanceled();
186         }
187         __except (EXCEPTION_EXECUTE_HANDLER)
188         {
189                 fileOpSucceed = false;
190         }
191         return fileOpSucceed;
192 }
193
194 /**
195  * @brief Execute fileoperations.
196  * @return `true` if all actions were done successfully, `false` otherwise.
197  */
198 bool FileActionScript::Run()
199 {
200         // Now process files/directories that got added to list
201         bool bFileOpSucceed = true;
202         bool bUserCancelled = false;
203         bool bRetVal = true;
204
205         CreateOperationsScripts();
206
207         if (m_bHasCopyOperations)
208         {
209                 vector<FileActionItem>::const_iterator iter = m_actions.begin();
210                 while (iter != m_actions.end())
211                 {
212                         if ((*iter).dirflag)
213                                 paths::CreateIfNeeded((*iter).dest);
214                         ++iter;
215                 }
216                 bFileOpSucceed = RunOp(m_pCopyOperations.get(), bUserCancelled);
217         }
218
219         if (m_bHasMoveOperations)
220         {
221                 if (bFileOpSucceed && !bUserCancelled)
222                 {
223                         bFileOpSucceed = RunOp(m_pMoveOperations.get(), bUserCancelled);
224                 }
225                 else
226                         bRetVal = false;
227         }
228
229         if (m_bHasRenameOperations)
230         {
231                 if (bFileOpSucceed && !bUserCancelled)
232                 {
233                         bFileOpSucceed = RunOp(m_pRenameOperations.get(), bUserCancelled);
234                 }
235                 else
236                         bRetVal = false;
237         }
238
239         if (m_bHasDelOperations)
240         {
241                 if (bFileOpSucceed && !bUserCancelled)
242                 {
243                         bFileOpSucceed = RunOp(m_pDelOperations.get(), bUserCancelled);
244                 }
245                 else
246                         bRetVal = false;
247         }
248
249         if (!bFileOpSucceed || bUserCancelled)
250                 bRetVal = false;
251
252         m_bCanceled = bUserCancelled;
253
254         return bRetVal;
255 }