1 | /* |
2 | * ark -- archiver for the KDE project |
3 | * |
4 | * Copyright (C) 2008 Harald Hvaal <haraldhv@stud.ntnu.no> |
5 | * Copyright (C) 2009-2010 Raphael Kubo da Costa <rakuco@FreeBSD.org> |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include "batchextract.h" |
30 | |
31 | #include "kerfuffle/archive.h" |
32 | #include "kerfuffle/extractiondialog.h" |
33 | #include "kerfuffle/jobs.h" |
34 | #include "kerfuffle/queries.h" |
35 | |
36 | #include <KDebug> |
37 | #include <KGlobal> |
38 | #include <KLocale> |
39 | #include <KMessageBox> |
40 | #include <KRun> |
41 | #include <KIO/RenameDialog> |
42 | #include <kwidgetjobtracker.h> |
43 | |
44 | #include <QDir> |
45 | #include <QFileInfo> |
46 | #include <QTimer> |
47 | #include <QWeakPointer> |
48 | |
49 | BatchExtract::() |
50 | : KCompositeJob(0), |
51 | m_autoSubfolder(false), |
52 | m_preservePaths(true), |
53 | m_openDestinationAfterExtraction(false) |
54 | { |
55 | setCapabilities(KJob::Killable); |
56 | |
57 | connect(this, SIGNAL(result(KJob*)), SLOT(showFailedFiles())); |
58 | } |
59 | |
60 | BatchExtract::() |
61 | { |
62 | if (!m_inputs.isEmpty()) { |
63 | KIO::getJobTracker()->unregisterJob(this); |
64 | } |
65 | } |
66 | |
67 | void BatchExtract::(Kerfuffle::Archive* archive) |
68 | { |
69 | QString destination = destinationFolder(); |
70 | |
71 | if ((autoSubfolder()) && (!archive->isSingleFolderArchive())) { |
72 | const QDir d(destination); |
73 | QString subfolderName = archive->subfolderName(); |
74 | |
75 | if (d.exists(subfolderName)) { |
76 | subfolderName = KIO::RenameDialog::suggestName(destination, subfolderName); |
77 | } |
78 | |
79 | d.mkdir(subfolderName); |
80 | |
81 | destination += QLatin1Char( '/' ) + subfolderName; |
82 | } |
83 | |
84 | Kerfuffle::ExtractionOptions options; |
85 | options[QLatin1String( "PreservePaths" )] = preservePaths(); |
86 | |
87 | Kerfuffle::ExtractJob *job = archive->copyFiles(QVariantList(), destination, options); |
88 | |
89 | kDebug() << QString(QLatin1String( "Registering job from archive %1, to %2, preservePaths %3" )).arg(archive->fileName()).arg(destination).arg(preservePaths()); |
90 | |
91 | addSubjob(job); |
92 | |
93 | m_fileNames[job] = qMakePair(archive->fileName(), destination); |
94 | |
95 | connect(job, SIGNAL(percent(KJob*,ulong)), |
96 | this, SLOT(forwardProgress(KJob*,ulong))); |
97 | connect(job, SIGNAL(userQuery(Kerfuffle::Query*)), |
98 | this, SLOT(slotUserQuery(Kerfuffle::Query*))); |
99 | } |
100 | |
101 | void BatchExtract::(Kerfuffle::Query *query) |
102 | { |
103 | query->execute(); |
104 | } |
105 | |
106 | bool BatchExtract::() const |
107 | { |
108 | return m_autoSubfolder; |
109 | } |
110 | |
111 | void BatchExtract::(bool value) |
112 | { |
113 | m_autoSubfolder = value; |
114 | } |
115 | |
116 | void BatchExtract::() |
117 | { |
118 | QTimer::singleShot(0, this, SLOT(slotStartJob())); |
119 | } |
120 | |
121 | void BatchExtract::() |
122 | { |
123 | // If none of the archives could be loaded, there is no subjob to run |
124 | if (m_inputs.isEmpty()) { |
125 | emitResult(); |
126 | return; |
127 | } |
128 | |
129 | foreach(Kerfuffle::Archive *archive, m_inputs) { |
130 | addExtraction(archive); |
131 | } |
132 | |
133 | KIO::getJobTracker()->registerJob(this); |
134 | |
135 | emit description(this, |
136 | i18n("Extracting file..." ), |
137 | qMakePair(i18n("Source archive" ), m_fileNames.value(subjobs().at(0)).first), |
138 | qMakePair(i18n("Destination" ), m_fileNames.value(subjobs().at(0)).second) |
139 | ); |
140 | |
141 | m_initialJobCount = subjobs().size(); |
142 | |
143 | kDebug() << "Starting first job" ; |
144 | |
145 | subjobs().at(0)->start(); |
146 | } |
147 | |
148 | void BatchExtract::() |
149 | { |
150 | if (!m_failedFiles.isEmpty()) { |
151 | KMessageBox::informationList(0, i18n("The following files could not be extracted:" ), m_failedFiles); |
152 | } |
153 | } |
154 | |
155 | void BatchExtract::(KJob *job) |
156 | { |
157 | kDebug(); |
158 | |
159 | // TODO: The user must be informed about which file caused the error, and that the other files |
160 | // in the queue will not be extracted. |
161 | if (job->error()) { |
162 | kDebug() << "There was en error, " << job->errorText(); |
163 | |
164 | setErrorText(job->errorText()); |
165 | setError(job->error()); |
166 | |
167 | removeSubjob(job); |
168 | |
169 | KMessageBox::error(NULL, job->errorText().isEmpty() ? |
170 | i18n("There was an error during extraction." ) : job->errorText() |
171 | ); |
172 | |
173 | emitResult(); |
174 | |
175 | return; |
176 | } else { |
177 | removeSubjob(job); |
178 | } |
179 | |
180 | if (!hasSubjobs()) { |
181 | if (openDestinationAfterExtraction()) { |
182 | KUrl destination(destinationFolder()); |
183 | destination.cleanPath(); |
184 | KRun::runUrl(destination, QLatin1String( "inode/directory" ), 0); |
185 | } |
186 | |
187 | kDebug() << "Finished, emitting the result" ; |
188 | emitResult(); |
189 | } else { |
190 | kDebug() << "Starting the next job" ; |
191 | emit description(this, |
192 | i18n("Extracting file..." ), |
193 | qMakePair(i18n("Source archive" ), m_fileNames.value(subjobs().at(0)).first), |
194 | qMakePair(i18n("Destination" ), m_fileNames.value(subjobs().at(0)).second) |
195 | ); |
196 | subjobs().at(0)->start(); |
197 | } |
198 | } |
199 | |
200 | void BatchExtract::(KJob *job, unsigned long percent) |
201 | { |
202 | Q_UNUSED(job) |
203 | int jobPart = 100 / m_initialJobCount; |
204 | setPercent(jobPart *(m_initialJobCount - subjobs().size()) + percent / m_initialJobCount); |
205 | } |
206 | |
207 | bool BatchExtract::(const KUrl& url) |
208 | { |
209 | Kerfuffle::Archive *archive = Kerfuffle::Archive::create(url.pathOrUrl(), this); |
210 | |
211 | if ((archive == NULL) || (!QFileInfo(url.pathOrUrl()).exists())) { |
212 | m_failedFiles.append(url.fileName()); |
213 | return false; |
214 | } |
215 | |
216 | m_inputs.append(archive); |
217 | |
218 | return true; |
219 | } |
220 | |
221 | bool BatchExtract::() const |
222 | { |
223 | return m_openDestinationAfterExtraction; |
224 | } |
225 | |
226 | bool BatchExtract::() const |
227 | { |
228 | return m_preservePaths; |
229 | } |
230 | |
231 | QString BatchExtract::() const |
232 | { |
233 | if (m_destinationFolder.isEmpty()) { |
234 | return QDir::currentPath(); |
235 | } else { |
236 | return m_destinationFolder; |
237 | } |
238 | } |
239 | |
240 | void BatchExtract::(const QString& folder) |
241 | { |
242 | if (QFileInfo(folder).isDir()) { |
243 | m_destinationFolder = folder; |
244 | } |
245 | } |
246 | |
247 | void BatchExtract::(bool value) |
248 | { |
249 | m_openDestinationAfterExtraction = value; |
250 | } |
251 | |
252 | void BatchExtract::(bool value) |
253 | { |
254 | m_preservePaths = value; |
255 | } |
256 | |
257 | bool BatchExtract::() |
258 | { |
259 | QWeakPointer<Kerfuffle::ExtractionDialog> dialog = |
260 | new Kerfuffle::ExtractionDialog; |
261 | |
262 | if (m_inputs.size() > 1) { |
263 | dialog.data()->batchModeOption(); |
264 | } |
265 | |
266 | dialog.data()->setAutoSubfolder(autoSubfolder()); |
267 | dialog.data()->setCurrentUrl(destinationFolder()); |
268 | dialog.data()->setPreservePaths(preservePaths()); |
269 | |
270 | if (m_inputs.size() == 1) { |
271 | if (m_inputs.at(0)->isSingleFolderArchive()) { |
272 | dialog.data()->setSingleFolderArchive(true); |
273 | } |
274 | dialog.data()->setSubfolder(m_inputs.at(0)->subfolderName()); |
275 | } |
276 | |
277 | if (!dialog.data()->exec()) { |
278 | delete dialog.data(); |
279 | return false; |
280 | } |
281 | |
282 | setAutoSubfolder(dialog.data()->autoSubfolders()); |
283 | setDestinationFolder(dialog.data()->destinationDirectory().pathOrUrl()); |
284 | setOpenDestinationAfterExtraction(dialog.data()->openDestinationAfterExtraction()); |
285 | setPreservePaths(dialog.data()->preservePaths()); |
286 | |
287 | delete dialog.data(); |
288 | |
289 | return true; |
290 | } |
291 | |
292 | #include <batchextract.moc> |
293 | |