1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (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 *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
21 #include "undomanager.h"
23 #include <kio/netaccess.h>
27 #include "dolphinmainwindow.h"
28 #include "dolphinstatusbar.h"
29 #include "progressindicator.h"
31 DolphinCommand::DolphinCommand() :
35 // Implementation note: DolphinCommands are stored in a QValueList, whereas
36 // QValueList requires a default constructor of the added class.
37 // Instead of expressing this implementation detail to the interface by adding a
38 // Type::Undefined just Type::Copy is used to assure that all members have
41 // KDE4TODO: QList doesn't require a default constructor iirc - so remove this
44 DolphinCommand::DolphinCommand(Type type
,
45 const KUrl::List
& source
,
54 DolphinCommand::~DolphinCommand()
58 DolphinCommand
& DolphinCommand::operator = (const DolphinCommand
& command
)
60 m_type
= command
.m_type
;
61 m_source
= command
.m_source
;
62 m_dest
= command
.m_dest
;
66 UndoManager
& UndoManager::instance()
68 static UndoManager
* instance
= 0;
70 instance
= new UndoManager();
75 void UndoManager::addCommand(const DolphinCommand
& command
)
79 QList
<DolphinCommand
>::iterator it
= m_history
.begin();
82 DolphinCommand macroCommand
= command
;
83 macroCommand
.m_macroIndex
= m_macroCounter
;
84 m_history
.insert(it
, macroCommand
);
87 m_history
.insert(it
, command
);
90 emit
undoAvailable(true);
91 emit
undoTextChanged(i18n("Undo: %1",commandText(command
)));
93 // prevent an endless growing of the Undo history
94 if (m_historyIndex
> 10000) {
95 m_history
.erase(m_history
.begin());
100 void UndoManager::beginMacro()
102 assert(!m_recordMacro
);
103 m_recordMacro
= true;
107 void UndoManager::endMacro()
109 assert(m_recordMacro
);
110 m_recordMacro
= false;
113 // KDE4 TODO: consider switching to KCommandHistory (kdeui) for the command history, and to
114 // KonqCommandRecorder etc. from libkonq/konq_undo.*
115 void UndoManager::undo(DolphinMainWindow
* mainWindow
)
121 if (m_historyIndex
< 0) {
125 int progressCount
= 0;
127 calcStepsCount(macroCount
, progressCount
);
130 * KDE4, ### TODO Only here to avoid possible crash
132 ProgressIndicator
progressIndicator(mainWindow
, i18n("Executing undo operation..."),
133 i18n("Executed undo operation."),
136 for (int i
= 0; i
< macroCount
; ++i
) {
137 const DolphinCommand command
= m_history
[m_historyIndex
];
140 if (m_historyIndex
< 0) {
141 emit
undoAvailable(false);
142 emit
undoTextChanged(i18n("Undo"));
145 emit
undoTextChanged(i18n("Undo: %1",commandText(m_history
[m_historyIndex
])));
148 if (m_historyIndex
< static_cast<int>(m_history
.count()) - 1) {
149 emit
redoAvailable(true);
150 emit
redoTextChanged(i18n("Redo: %1",commandText(command
)));
153 emit
redoAvailable(false);
154 emit
redoTextChanged(i18n("Redo"));
157 KUrl::List sourceUrls
= command
.source();
158 KUrl::List::Iterator it
= sourceUrls
.begin();
159 const KUrl::List::Iterator end
= sourceUrls
.end();
160 const QString
destUrl(command
.destination().prettyUrl(KUrl::AddTrailingSlash
));
163 switch (command
.type()) {
164 case DolphinCommand::Link
:
165 case DolphinCommand::Copy
: {
168 const KUrl
deleteUrl(destUrl
+ (*it
).fileName());
169 list
.append(deleteUrl
);
172 job
= KIO::del(list
, false, false);
176 case DolphinCommand::Move
: {
178 const KUrl
newDestUrl((*it
).directory());
180 const KUrl
newSourceUrl(destUrl
+ (*it
).fileName());
181 list
.append(newSourceUrl
);
184 job
= KIO::move(list
, newDestUrl
, false);
188 case DolphinCommand::Rename
: {
189 assert(sourceUrls
.count() == 1);
190 KIO::NetAccess::move(command
.destination(), (*it
));
194 case DolphinCommand::Trash
: {
196 // TODO: use KIO::special for accessing the trash protocol. See
197 // also Dolphin::slotJobResult() for further details.
198 const QString
originalFileName((*it
).fileName().section('-', 1));
199 KUrl
newDestUrl(destUrl
+ originalFileName
);
200 KIO::NetAccess::move(*it
, newDestUrl
);
203 progressIndicator
.execOperation();
208 case DolphinCommand::CreateFolder
:
209 case DolphinCommand::CreateFile
: {
210 KIO::NetAccess::del(command
.destination(), mainWindow
);
216 // Execute the jobs in a synchronous manner and forward the progress
217 // information to the Dolphin statusbar.
218 connect(job
, SIGNAL(percent(KIO::Job
*, unsigned long)),
219 this, SLOT(slotPercent(KIO::Job
*, unsigned long)));
220 KIO::NetAccess::synchronousRun(job
, mainWindow
);
223 progressIndicator
.execOperation();
227 void UndoManager::redo(DolphinMainWindow
*mainWindow
)
233 const int maxHistoryIndex
= m_history
.count() - 1;
234 if (m_historyIndex
>= maxHistoryIndex
) {
239 int progressCount
= 0;
241 calcStepsCount(macroCount
, progressCount
);
243 ProgressIndicator
progressIndicator(mainWindow
, i18n("Executing redo operation..."),
244 i18n("Executed redo operation."),
247 for (int i
= 0; i
< macroCount
; ++i
) {
248 const DolphinCommand command
= m_history
[m_historyIndex
];
249 if (m_historyIndex
>= maxHistoryIndex
) {
250 emit
redoAvailable(false);
251 emit
redoTextChanged(i18n("Redo"));
254 emit
redoTextChanged(i18n("Redo: %1",commandText(m_history
[m_historyIndex
+ 1])));
257 emit
undoAvailable(true);
258 emit
undoTextChanged(i18n("Undo: %1",commandText(command
)));
260 KUrl::List sourceUrls
= command
.source();
261 KUrl::List::Iterator it
= sourceUrls
.begin();
262 const KUrl::List::Iterator end
= sourceUrls
.end();
265 switch (command
.type()) {
266 case DolphinCommand::Link
: {
267 job
= KIO::link(sourceUrls
, command
.destination(), false);
271 case DolphinCommand::Copy
: {
272 job
= KIO::copy(sourceUrls
, command
.destination(), false);
276 case DolphinCommand::Rename
:
277 case DolphinCommand::Move
: {
278 job
= KIO::move(sourceUrls
, command
.destination(), false);
282 case DolphinCommand::Trash
: {
283 const QString
destUrl(command
.destination().prettyUrl());
285 // TODO: use KIO::special for accessing the trash protocol. See
286 // also Dolphin::slotJobResult() for further details.
287 const QString
originalFileName((*it
).fileName().section('-', 1));
288 KUrl
originalSourceUrl(destUrl
+ "/" + originalFileName
);
289 KIO::Job
* moveToTrashJob
= KIO::trash(originalSourceUrl
);
290 KIO::NetAccess::synchronousRun(moveToTrashJob
, mainWindow
);
293 progressIndicator
.execOperation();
298 case DolphinCommand::CreateFolder
: {
299 KIO::NetAccess::mkdir(command
.destination(), mainWindow
);
303 case DolphinCommand::CreateFile
: {
304 progressIndicator
.execOperation();
305 KUrl::List::Iterator it
= sourceUrls
.begin();
306 assert(sourceUrls
.count() == 1);
307 KIO::CopyJob
* copyJob
= KIO::copyAs(*it
, command
.destination(), false);
308 copyJob
->setDefaultPermissions(true);
315 // Execute the jobs in a synchronous manner and forward the progress
316 // information to the Dolphin statusbar.
317 connect(job
, SIGNAL(percent(KJob
*, unsigned long)),
318 this, SLOT(slotPercent(KJob
*, unsigned long)));
319 KIO::NetAccess::synchronousRun(job
, mainWindow
);
323 progressIndicator
.execOperation();
330 UndoManager::UndoManager() :
331 m_recordMacro(false),
337 UndoManager::~UndoManager()
341 QString
UndoManager::commandText(const DolphinCommand
& command
) const
344 switch (command
.type()) {
345 case DolphinCommand::Copy
: text
= i18n("Copy"); break;
346 case DolphinCommand::Move
: text
= i18n("Move"); break;
347 case DolphinCommand::Link
: text
= i18n("Link"); break;
348 case DolphinCommand::Rename
: text
= i18n("Rename"); break;
349 case DolphinCommand::Trash
: text
= i18n("Move to Trash"); break;
350 case DolphinCommand::CreateFolder
: text
= i18n("Create New Folder"); break;
351 case DolphinCommand::CreateFile
: text
= i18n("Create New File"); break;
357 void UndoManager::slotPercent(KJob
* /* job */, unsigned long /* percent */)
359 // It is not allowed to update the progress indicator in the context
360 // of this slot, hence do an asynchronous triggering.
361 QTimer::singleShot(0, this, SLOT(updateProgress()));
364 void UndoManager::updateProgress()
367 * ### XXX, TODO, KDE4 make this work when switchting to KonqUndoManager
369 //m_progressIndicator->execOperation();
372 void UndoManager::calcStepsCount(int& macroCount
, int& progressCount
)
377 const int macroIndex
= m_history
[m_historyIndex
].m_macroIndex
;
378 if (macroIndex
< 0) {
379 // default use case: no macro has been recorded
381 progressCount
= m_history
[m_historyIndex
].source().count();
385 // iterate backward for undo...
386 int i
= m_historyIndex
;
387 while ((i
>= 0) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
389 progressCount
+= m_history
[i
].source().count();
393 // iterate forward for redo...
394 const int max
= m_history
.count() - 1;
395 i
= m_historyIndex
+ 1;
396 while ((i
<= max
) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
398 progressCount
+= m_history
[i
].source().count();
403 #include "undomanager.moc"