1 /// PanelCopy.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/MyException.h"
6
7 #include "../GUI/HashGUI.h"
8
9 #include "ExtractCallback.h"
10 #include "LangUtils.h"
11 #include "Panel.h"
12 #include "resource.h"
13 #include "UpdateCallback100.h"
14
15 using namespace NWindows;
16
17 class CPanelCopyThread: public CProgressThreadVirt
18 {
19 HRESULT ProcessVirt();
20 public:
21 const CCopyToOptions *options;
22 CMyComPtr<IFolderOperations> FolderOperations;
23 CRecordVector<UInt32> Indices;
24 CExtractCallbackImp *ExtractCallbackSpec;
25 CMyComPtr<IFolderOperationsExtractCallback> ExtractCallback;
26
27 CHashBundle Hash;
28 UString FirstFilePath;
29
30 HRESULT Result;
31
32
CPanelCopyThread()33 CPanelCopyThread(): Result(E_FAIL) {}
34 };
35
ProcessVirt()36 HRESULT CPanelCopyThread::ProcessVirt()
37 {
38 /*
39 CMyComPtr<IFolderSetReplaceAltStreamCharsMode> iReplace;
40 FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace);
41 if (iReplace)
42 {
43 RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0));
44 }
45 */
46
47 if (options->testMode)
48 {
49 CMyComPtr<IArchiveFolder> archiveFolder;
50 FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder);
51 if (!archiveFolder)
52 return E_NOTIMPL;
53 CMyComPtr<IFolderArchiveExtractCallback> extractCallback2;
54 RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2));
55 NExtract::NPathMode::EEnum pathMode =
56 NExtract::NPathMode::kCurPaths;
57 // NExtract::NPathMode::kFullPathnames;
58 Result = archiveFolder->Extract(&Indices.Front(), Indices.Size(),
59 BoolToInt(options->includeAltStreams),
60 BoolToInt(options->replaceAltStreamChars),
61 pathMode, NExtract::NOverwriteMode::kAsk,
62 options->folder, BoolToInt(true), extractCallback2);
63 }
64 else
65 Result = FolderOperations->CopyTo(
66 BoolToInt(options->moveMode),
67 &Indices.Front(), Indices.Size(),
68 BoolToInt(options->includeAltStreams),
69 BoolToInt(options->replaceAltStreamChars),
70 options->folder, ExtractCallback);
71
72 if (Result == S_OK && !ExtractCallbackSpec->ThereAreMessageErrors &&
73 (!options->hashMethods.IsEmpty() || options->testMode))
74 {
75 CProgressMessageBoxPair &pair = GetMessagePair(false); // GetMessagePair(ExtractCallbackSpec->Hash.NumErrors != 0);
76 AddHashBundleRes(pair.Message, Hash, FirstFilePath);
77 }
78
79 return Result;
80 }
81
82
83 /*
84 #ifdef EXTERNAL_CODECS
85
86 static void ThrowException_if_Error(HRESULT res)
87 {
88 if (res != S_OK)
89 throw CSystemException(res);
90 }
91
92 #endif
93 */
94
95
CopyTo(CCopyToOptions & options,const CRecordVector<UInt32> & indices,UStringVector * messages,bool & usePassword,UString & password)96 HRESULT CPanel::CopyTo(CCopyToOptions &options, const CRecordVector<UInt32> &indices,
97 UStringVector *messages,
98 bool &usePassword, UString &password)
99 {
100 if (!_folderOperations)
101 {
102 UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED);
103 if (options.showErrorMessages)
104 MessageBox_Error(errorMessage);
105 else if (messages != 0)
106 messages->Add(errorMessage);
107 return E_FAIL;
108 }
109
110 HRESULT res = S_OK;
111
112 {
113 /*
114 #ifdef EXTERNAL_CODECS
115 CExternalCodecs g_ExternalCodecs;
116 #endif
117 */
118 /* extracter.Hash uses g_ExternalCodecs
119 extracter must be declared after g_ExternalCodecs for correct destructor order !!! */
120
121 CPanelCopyThread extracter;
122
123 extracter.ExtractCallbackSpec = new CExtractCallbackImp;
124 extracter.ExtractCallback = extracter.ExtractCallbackSpec;
125
126 extracter.options = &options;
127 extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
128 extracter.ProgressDialog.CompressingMode = false;
129
130 extracter.ExtractCallbackSpec->StreamMode = options.streamMode;
131
132
133 if (indices.Size() == 1)
134 extracter.FirstFilePath = GetItemRelPath(indices[0]);
135
136 if (options.VirtFileSystem)
137 {
138 extracter.ExtractCallbackSpec->VirtFileSystem = options.VirtFileSystem;
139 extracter.ExtractCallbackSpec->VirtFileSystemSpec = options.VirtFileSystemSpec;
140 }
141 extracter.ExtractCallbackSpec->ProcessAltStreams = options.includeAltStreams;
142
143 if (!options.hashMethods.IsEmpty())
144 {
145 /* this code is used when we call CRC calculation for files in side archive
146 But new code uses global codecs so we don't need to call LoadGlobalCodecs again */
147
148 /*
149 #ifdef EXTERNAL_CODECS
150 ThrowException_if_Error(LoadGlobalCodecs());
151 #endif
152 */
153
154 extracter.Hash.SetMethods(EXTERNAL_CODECS_VARS_G options.hashMethods);
155 extracter.ExtractCallbackSpec->SetHashMethods(&extracter.Hash);
156 }
157 else if (options.testMode)
158 {
159 extracter.ExtractCallbackSpec->SetHashCalc(&extracter.Hash);
160 }
161
162 extracter.Hash.Init();
163
164 UString title;
165 {
166 UInt32 titleID = IDS_COPYING;
167 if (options.moveMode)
168 titleID = IDS_MOVING;
169 else if (!options.hashMethods.IsEmpty() && options.streamMode)
170 {
171 titleID = IDS_CHECKSUM_CALCULATING;
172 if (options.hashMethods.Size() == 1)
173 {
174 const UString &s = options.hashMethods[0];
175 if (s != L"*")
176 title = s;
177 }
178 }
179 else if (options.testMode)
180 titleID = IDS_PROGRESS_TESTING;
181
182 if (title.IsEmpty())
183 title = LangString(titleID);
184 }
185
186 UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE);
187
188 extracter.ProgressDialog.MainWindow = GetParent();
189 extracter.ProgressDialog.MainTitle = progressWindowTitle;
190 extracter.ProgressDialog.MainAddTitle = title + L' ';
191
192 extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAsk;
193 extracter.ExtractCallbackSpec->Init();
194 extracter.Indices = indices;
195 extracter.FolderOperations = _folderOperations;
196
197 extracter.ExtractCallbackSpec->PasswordIsDefined = usePassword;
198 extracter.ExtractCallbackSpec->Password = password;
199
200 RINOK(extracter.Create(title, GetParent()));
201
202 if (messages != 0)
203 *messages = extracter.ProgressDialog.Sync.Messages;
204 res = extracter.Result;
205
206 if (res == S_OK && extracter.ExtractCallbackSpec->IsOK())
207 {
208 usePassword = extracter.ExtractCallbackSpec->PasswordIsDefined;
209 password = extracter.ExtractCallbackSpec->Password;
210 }
211 }
212
213 RefreshTitleAlways();
214 return res;
215 }
216
217
218 struct CThreadUpdate
219 {
220 CMyComPtr<IFolderOperations> FolderOperations;
221 UString FolderPrefix;
222 UStringVector FileNames;
223 CRecordVector<const wchar_t *> FileNamePointers;
224 CProgressDialog ProgressDialog;
225 CMyComPtr<IFolderArchiveUpdateCallback> UpdateCallback;
226 CUpdateCallback100Imp *UpdateCallbackSpec;
227 HRESULT Result;
228 bool MoveMode;
229
ProcessCThreadUpdate230 void Process()
231 {
232 try
233 {
234 CProgressCloser closer(ProgressDialog);
235 Result = FolderOperations->CopyFrom(
236 MoveMode,
237 FolderPrefix,
238 &FileNamePointers.Front(),
239 FileNamePointers.Size(),
240 UpdateCallback);
241 }
242 catch(...) { Result = E_FAIL; }
243 }
MyThreadFunctionCThreadUpdate244 static THREAD_FUNC_DECL MyThreadFunction(void *param)
245 {
246 ((CThreadUpdate *)param)->Process();
247 return 0;
248 }
249 };
250
251
CopyFrom(bool moveMode,const UString & folderPrefix,const UStringVector & filePaths,bool showErrorMessages,UStringVector * messages)252 HRESULT CPanel::CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths,
253 bool showErrorMessages, UStringVector *messages)
254 {
255 // CDisableNotify disableNotify(*this);
256
257 HRESULT res;
258 if (!_folderOperations)
259 res = E_NOINTERFACE;
260 else
261 {
262 CThreadUpdate updater;
263 updater.MoveMode = moveMode;
264 updater.UpdateCallbackSpec = new CUpdateCallback100Imp;
265 updater.UpdateCallback = updater.UpdateCallbackSpec;
266 updater.UpdateCallbackSpec->Init();
267
268 updater.UpdateCallbackSpec->ProgressDialog = &updater.ProgressDialog;
269
270 UString title = LangString(IDS_COPYING);
271 UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE);
272
273 updater.ProgressDialog.MainWindow = GetParent();
274 updater.ProgressDialog.MainTitle = progressWindowTitle;
275 updater.ProgressDialog.MainAddTitle = title + L' ';
276
277 {
278 if (!_parentFolders.IsEmpty())
279 {
280 const CFolderLink &fl = _parentFolders.Back();
281 updater.UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword;
282 updater.UpdateCallbackSpec->Password = fl.Password;
283 }
284 }
285
286 updater.FolderOperations = _folderOperations;
287 updater.FolderPrefix = folderPrefix;
288 updater.FileNames.ClearAndReserve(filePaths.Size());
289 unsigned i;
290 for (i = 0; i < filePaths.Size(); i++)
291 updater.FileNames.AddInReserved(filePaths[i]);
292 updater.FileNamePointers.ClearAndReserve(updater.FileNames.Size());
293 for (i = 0; i < updater.FileNames.Size(); i++)
294 updater.FileNamePointers.AddInReserved(updater.FileNames[i]);
295
296 NWindows::CThread thread;
297 RINOK(thread.Create(CThreadUpdate::MyThreadFunction, &updater));
298 updater.ProgressDialog.Create(title, thread, GetParent());
299
300 if (messages != 0)
301 *messages = updater.ProgressDialog.Sync.Messages;
302
303 res = updater.Result;
304 }
305
306 if (res == E_NOINTERFACE)
307 {
308 UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED);
309 if (showErrorMessages)
310 MessageBox_Error(errorMessage);
311 else if (messages != 0)
312 messages->Add(errorMessage);
313 return E_ABORT;
314 }
315
316 RefreshTitleAlways();
317 return res;
318 }
319
CopyFromNoAsk(const UStringVector & filePaths)320 void CPanel::CopyFromNoAsk(const UStringVector &filePaths)
321 {
322 CDisableTimerProcessing disableTimerProcessing(*this);
323
324 CSelectedState srcSelState;
325 SaveSelectedState(srcSelState);
326
327 CDisableNotify disableNotify(*this);
328
329 HRESULT result = CopyFrom(false, L"", filePaths, true, 0);
330
331 if (result != S_OK)
332 {
333 disableNotify.Restore();
334 // For Password:
335 SetFocusToList();
336 if (result != E_ABORT)
337 MessageBox_Error_HRESULT(result);
338 return;
339 }
340
341 RefreshListCtrl(srcSelState);
342
343 disableNotify.Restore();
344 SetFocusToList();
345 }
346
CopyFromAsk(const UStringVector & filePaths)347 void CPanel::CopyFromAsk(const UStringVector &filePaths)
348 {
349 UString title = LangString(IDS_CONFIRM_FILE_COPY);
350 UString message = LangString(IDS_WANT_TO_COPY_FILES);
351 message += "\n\'";
352 message += _currentFolderPrefix;
353 message += "\' ?";
354 int res = ::MessageBoxW(*(this), message, title, MB_YESNOCANCEL | MB_ICONQUESTION);
355 if (res != IDYES)
356 return;
357
358 CopyFromNoAsk(filePaths);
359 }
360