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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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
)
80 DolphinCommand macroCommand
= command
;
81 macroCommand
.m_macroIndex
= m_macroCounter
;
82 m_history
.insert(m_history
.at(m_historyIndex
), macroCommand
);
85 m_history
.insert(m_history
.at(m_historyIndex
), command
);
88 emit
undoAvailable(true);
89 emit
undoTextChanged(i18n("Undo: %1",commandText(command
)));
91 // prevent an endless growing of the Undo history
92 if (m_historyIndex
> 10000) {
93 m_history
.erase(m_history
.begin());
98 void UndoManager::beginMacro()
100 assert(!m_recordMacro
);
101 m_recordMacro
= true;
105 void UndoManager::endMacro()
107 assert(m_recordMacro
);
108 m_recordMacro
= false;
111 // KDE4 TODO: consider switching to KCommandHistory (kdeui) for the command history, and to
112 // KonqCommandRecorder etc. from libkonq/konq_undo.*
113 void UndoManager::undo(DolphinMainWindow
* mainWindow
)
119 if (m_historyIndex
< 0) {
123 int progressCount
= 0;
125 calcStepsCount(macroCount
, progressCount
);
128 * KDE4, ### TODO Only here to avoid possible crash
130 ProgressIndicator
progressIndicator(mainWindow
, i18n("Executing undo operation..."),
131 i18n("Executed undo operation."),
134 for (int i
= 0; i
< macroCount
; ++i
) {
135 const DolphinCommand command
= m_history
[m_historyIndex
];
138 if (m_historyIndex
< 0) {
139 emit
undoAvailable(false);
140 emit
undoTextChanged(i18n("Undo"));
143 emit
undoTextChanged(i18n("Undo: %1",commandText(m_history
[m_historyIndex
])));
146 if (m_historyIndex
< static_cast<int>(m_history
.count()) - 1) {
147 emit
redoAvailable(true);
148 emit
redoTextChanged(i18n("Redo: %1",commandText(command
)));
151 emit
redoAvailable(false);
152 emit
redoTextChanged(i18n("Redo"));
155 KUrl::List sourceUrls
= command
.source();
156 KUrl::List::Iterator it
= sourceUrls
.begin();
157 const KUrl::List::Iterator end
= sourceUrls
.end();
158 const QString
destUrl(command
.destination().prettyUrl(KUrl::AddTrailingSlash
));
161 switch (command
.type()) {
162 case DolphinCommand::Link
:
163 case DolphinCommand::Copy
: {
166 const KUrl
deleteUrl(destUrl
+ (*it
).fileName());
167 list
.append(deleteUrl
);
170 job
= KIO::del(list
, false, false);
174 case DolphinCommand::Move
: {
176 const KUrl
newDestUrl((*it
).directory());
178 const KUrl
newSourceUrl(destUrl
+ (*it
).fileName());
179 list
.append(newSourceUrl
);
182 job
= KIO::move(list
, newDestUrl
, false);
186 case DolphinCommand::Rename
: {
187 assert(sourceUrls
.count() == 1);
188 KIO::NetAccess::move(command
.destination(), (*it
));
192 case DolphinCommand::Trash
: {
194 // TODO: use KIO::special for accessing the trash protocol. See
195 // also Dolphin::slotJobResult() for further details.
196 const QString
originalFileName((*it
).fileName().section('-', 1));
197 KUrl
newDestUrl(destUrl
+ originalFileName
);
198 KIO::NetAccess::move(*it
, newDestUrl
);
201 progressIndicator
.execOperation();
206 case DolphinCommand::CreateFolder
:
207 case DolphinCommand::CreateFile
: {
208 KIO::NetAccess::del(command
.destination(), mainWindow
);
214 // Execute the jobs in a synchronous manner and forward the progress
215 // information to the Dolphin statusbar.
216 connect(job
, SIGNAL(percent(KIO::Job
*, unsigned long)),
217 this, SLOT(slotPercent(KIO::Job
*, unsigned long)));
218 KIO::NetAccess::synchronousRun(job
, mainWindow
);
221 progressIndicator
.execOperation();
225 void UndoManager::redo(DolphinMainWindow
*mainWindow
)
231 const int maxHistoryIndex
= m_history
.count() - 1;
232 if (m_historyIndex
>= maxHistoryIndex
) {
237 int progressCount
= 0;
239 calcStepsCount(macroCount
, progressCount
);
241 ProgressIndicator
progressIndicator(mainWindow
, i18n("Executing redo operation..."),
242 i18n("Executed redo operation."),
245 for (int i
= 0; i
< macroCount
; ++i
) {
246 const DolphinCommand command
= m_history
[m_historyIndex
];
247 if (m_historyIndex
>= maxHistoryIndex
) {
248 emit
redoAvailable(false);
249 emit
redoTextChanged(i18n("Redo"));
252 emit
redoTextChanged(i18n("Redo: %1",commandText(m_history
[m_historyIndex
+ 1])));
255 emit
undoAvailable(true);
256 emit
undoTextChanged(i18n("Undo: %1",commandText(command
)));
258 KUrl::List sourceUrls
= command
.source();
259 KUrl::List::Iterator it
= sourceUrls
.begin();
260 const KUrl::List::Iterator end
= sourceUrls
.end();
263 switch (command
.type()) {
264 case DolphinCommand::Link
: {
265 job
= KIO::link(sourceUrls
, command
.destination(), false);
269 case DolphinCommand::Copy
: {
270 job
= KIO::copy(sourceUrls
, command
.destination(), false);
274 case DolphinCommand::Rename
:
275 case DolphinCommand::Move
: {
276 job
= KIO::move(sourceUrls
, command
.destination(), false);
280 case DolphinCommand::Trash
: {
281 const QString
destUrl(command
.destination().prettyUrl());
283 // TODO: use KIO::special for accessing the trash protocol. See
284 // also Dolphin::slotJobResult() for further details.
285 const QString
originalFileName((*it
).fileName().section('-', 1));
286 KUrl
originalSourceUrl(destUrl
+ "/" + originalFileName
);
287 KIO::Job
* moveToTrashJob
= KIO::trash(originalSourceUrl
);
288 KIO::NetAccess::synchronousRun(moveToTrashJob
, mainWindow
);
291 progressIndicator
.execOperation();
296 case DolphinCommand::CreateFolder
: {
297 KIO::NetAccess::mkdir(command
.destination(), mainWindow
);
301 case DolphinCommand::CreateFile
: {
302 progressIndicator
.execOperation();
303 KUrl::List::Iterator it
= sourceUrls
.begin();
304 assert(sourceUrls
.count() == 1);
305 KIO::CopyJob
* copyJob
= KIO::copyAs(*it
, command
.destination(), false);
306 copyJob
->setDefaultPermissions(true);
313 // Execute the jobs in a synchronous manner and forward the progress
314 // information to the Dolphin statusbar.
315 connect(job
, SIGNAL(percent(KJob
*, unsigned long)),
316 this, SLOT(slotPercent(KJob
*, unsigned long)));
317 KIO::NetAccess::synchronousRun(job
, mainWindow
);
321 progressIndicator
.execOperation();
328 UndoManager::UndoManager() :
329 m_recordMacro(false),
335 UndoManager::~UndoManager()
339 QString
UndoManager::commandText(const DolphinCommand
& command
) const
342 switch (command
.type()) {
343 case DolphinCommand::Copy
: text
= i18n("Copy"); break;
344 case DolphinCommand::Move
: text
= i18n("Move"); break;
345 case DolphinCommand::Link
: text
= i18n("Link"); break;
346 case DolphinCommand::Rename
: text
= i18n("Rename"); break;
347 case DolphinCommand::Trash
: text
= i18n("Move to Trash"); break;
348 case DolphinCommand::CreateFolder
: text
= i18n("Create New Folder"); break;
349 case DolphinCommand::CreateFile
: text
= i18n("Create New File"); break;
355 void UndoManager::slotPercent(KJob
* /* job */, unsigned long /* percent */)
357 // It is not allowed to update the progress indicator in the context
358 // of this slot, hence do an asynchronous triggering.
359 QTimer::singleShot(0, this, SLOT(updateProgress()));
362 void UndoManager::updateProgress()
365 * ### XXX, TODO, KDE4 make this work when switchting to KonqUndoManager
367 //m_progressIndicator->execOperation();
370 void UndoManager::calcStepsCount(int& macroCount
, int& progressCount
)
375 const int macroIndex
= m_history
[m_historyIndex
].m_macroIndex
;
376 if (macroIndex
< 0) {
377 // default use case: no macro has been recorded
379 progressCount
= m_history
[m_historyIndex
].source().count();
383 // iterate backward for undo...
384 int i
= m_historyIndex
;
385 while ((i
>= 0) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
387 progressCount
+= m_history
[i
].source().count();
391 // iterate forward for redo...
392 const int max
= m_history
.count() - 1;
393 i
= m_historyIndex
+ 1;
394 while ((i
<= max
) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
396 progressCount
+= m_history
[i
].source().count();
401 #include "undomanager.moc"