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() :
36 // Implementation note: DolphinCommands are stored in a QValueList, whereas
37 // QValueList requires a default constructor of the added class.
38 // Instead of expressing this implementation detail to the interface by adding a
39 // Type::Undefined just Type::Copy is used to assure that all members have
42 // KDE4TODO: QList doesn't require a default constructor iirc - so remove this
45 DolphinCommand::DolphinCommand(Type type
,
46 const KUrl::List
& source
,
48 DolphinMainWindow
* mainWindow
) :
53 m_mainWindow(mainWindow
)
57 DolphinCommand::~DolphinCommand()
61 DolphinCommand
& DolphinCommand::operator = (const DolphinCommand
& command
)
63 m_type
= command
.m_type
;
64 m_source
= command
.m_source
;
65 m_dest
= command
.m_dest
;
66 m_mainWindow
= command
.m_mainWindow
;
70 UndoManager
& UndoManager::instance()
72 static UndoManager
* instance
= 0;
74 instance
= new UndoManager();
79 void UndoManager::addCommand(const DolphinCommand
& command
)
84 DolphinCommand macroCommand
= command
;
85 macroCommand
.m_macroIndex
= m_macroCounter
;
86 m_history
.insert(m_history
.at(m_historyIndex
), macroCommand
);
89 m_history
.insert(m_history
.at(m_historyIndex
), command
);
92 emit
undoAvailable(true);
93 emit
undoTextChanged(i18n("Undo: %1",commandText(command
)));
95 // prevent an endless growing of the Undo history
96 if (m_historyIndex
> 10000) {
97 m_history
.erase(m_history
.begin());
102 void UndoManager::beginMacro()
104 assert(!m_recordMacro
);
105 m_recordMacro
= true;
109 void UndoManager::endMacro()
111 assert(m_recordMacro
);
112 m_recordMacro
= false;
115 // KDE4 TODO: consider switching to KCommandHistory (kdeui) for the command history, and to
116 // KonqCommandRecorder etc. from libkonq/konq_undo.*
117 void UndoManager::undo()
123 if (m_historyIndex
< 0) {
127 int progressCount
= 0;
129 calcStepsCount(macroCount
, progressCount
);
132 for (int i
= 0; i
< macroCount
; ++i
) {
133 const DolphinCommand command
= m_history
[m_historyIndex
];
136 * KDE4, ### TODO Only here to avoid possible crash
138 ProgressIndicator
progressIndicator(command
.mainWindow(), i18n("Executing undo operation..."),
139 i18n("Executed undo operation."),
142 if (m_historyIndex
< 0) {
143 emit
undoAvailable(false);
144 emit
undoTextChanged(i18n("Undo"));
147 emit
undoTextChanged(i18n("Undo: %1",commandText(m_history
[m_historyIndex
])));
150 if (m_historyIndex
< static_cast<int>(m_history
.count()) - 1) {
151 emit
redoAvailable(true);
152 emit
redoTextChanged(i18n("Redo: %1",commandText(command
)));
155 emit
redoAvailable(false);
156 emit
redoTextChanged(i18n("Redo"));
159 KUrl::List sourceUrls
= command
.source();
160 KUrl::List::Iterator it
= sourceUrls
.begin();
161 const KUrl::List::Iterator end
= sourceUrls
.end();
162 const QString
destUrl(command
.destination().prettyUrl(KUrl::AddTrailingSlash
));
165 switch (command
.type()) {
166 case DolphinCommand::Link
:
167 case DolphinCommand::Copy
: {
170 const KUrl
deleteUrl(destUrl
+ (*it
).fileName());
171 list
.append(deleteUrl
);
174 job
= KIO::del(list
, false, false);
178 case DolphinCommand::Move
: {
180 const KUrl
newDestUrl((*it
).directory());
182 const KUrl
newSourceUrl(destUrl
+ (*it
).fileName());
183 list
.append(newSourceUrl
);
186 job
= KIO::move(list
, newDestUrl
, false);
190 case DolphinCommand::Rename
: {
191 assert(sourceUrls
.count() == 1);
192 KIO::NetAccess::move(command
.destination(), (*it
));
196 case DolphinCommand::Trash
: {
198 // TODO: use KIO::special for accessing the trash protocol. See
199 // also Dolphin::slotJobResult() for further details.
200 const QString
originalFileName((*it
).fileName().section('-', 1));
201 KUrl
newDestUrl(destUrl
+ originalFileName
);
202 KIO::NetAccess::move(*it
, newDestUrl
);
205 progressIndicator
.execOperation();
210 case DolphinCommand::CreateFolder
:
211 case DolphinCommand::CreateFile
: {
212 KIO::NetAccess::del(command
.destination(), command
.mainWindow() );
218 // Execute the jobs in a synchronous manner and forward the progress
219 // information to the Dolphin statusbar.
220 connect(job
, SIGNAL(percent(KIO::Job
*, unsigned long)),
221 this, SLOT(slotPercent(KIO::Job
*, unsigned long)));
222 KIO::NetAccess::synchronousRun(job
, command
.mainWindow() );
225 progressIndicator
.execOperation();
229 void UndoManager::redo()
235 const int maxHistoryIndex
= m_history
.count() - 1;
236 if (m_historyIndex
>= maxHistoryIndex
) {
241 int progressCount
= 0;
243 calcStepsCount(macroCount
, progressCount
);
246 for (int i
= 0; i
< macroCount
; ++i
) {
247 const DolphinCommand command
= m_history
[m_historyIndex
];
249 ProgressIndicator
progressIndicator(0, i18n("Executing redo operation..."),
250 i18n("Executed redo operation."),
252 if (m_historyIndex
>= maxHistoryIndex
) {
253 emit
redoAvailable(false);
254 emit
redoTextChanged(i18n("Redo"));
257 emit
redoTextChanged(i18n("Redo: %1",commandText(m_history
[m_historyIndex
+ 1])));
260 emit
undoAvailable(true);
261 emit
undoTextChanged(i18n("Undo: %1",commandText(command
)));
263 KUrl::List sourceUrls
= command
.source();
264 KUrl::List::Iterator it
= sourceUrls
.begin();
265 const KUrl::List::Iterator end
= sourceUrls
.end();
268 switch (command
.type()) {
269 case DolphinCommand::Link
: {
270 job
= KIO::link(sourceUrls
, command
.destination(), false);
274 case DolphinCommand::Copy
: {
275 job
= KIO::copy(sourceUrls
, command
.destination(), false);
279 case DolphinCommand::Rename
:
280 case DolphinCommand::Move
: {
281 job
= KIO::move(sourceUrls
, command
.destination(), false);
285 case DolphinCommand::Trash
: {
286 const QString
destUrl(command
.destination().prettyUrl());
288 // TODO: use KIO::special for accessing the trash protocol. See
289 // also Dolphin::slotJobResult() for further details.
290 const QString
originalFileName((*it
).fileName().section('-', 1));
291 KUrl
originalSourceUrl(destUrl
+ "/" + originalFileName
);
292 KIO::Job
* moveToTrashJob
= KIO::trash(originalSourceUrl
);
293 KIO::NetAccess::synchronousRun(moveToTrashJob
, command
.mainWindow() );
296 progressIndicator
.execOperation();
301 case DolphinCommand::CreateFolder
: {
302 KIO::NetAccess::mkdir(command
.destination(), command
.mainWindow());
306 case DolphinCommand::CreateFile
: {
307 progressIndicator
.execOperation();
308 KUrl::List::Iterator it
= sourceUrls
.begin();
309 assert(sourceUrls
.count() == 1);
310 KIO::CopyJob
* copyJob
= KIO::copyAs(*it
, command
.destination(), false);
311 copyJob
->setDefaultPermissions(true);
318 // Execute the jobs in a synchronous manner and forward the progress
319 // information to the Dolphin statusbar.
320 connect(job
, SIGNAL(percent(KJob
*, unsigned long)),
321 this, SLOT(slotPercent(KJob
*, unsigned long)));
322 KIO::NetAccess::synchronousRun(job
, command
.mainWindow());
326 progressIndicator
.execOperation();
333 UndoManager::UndoManager() :
334 m_recordMacro(false),
340 UndoManager::~UndoManager()
344 QString
UndoManager::commandText(const DolphinCommand
& command
) const
347 switch (command
.type()) {
348 case DolphinCommand::Copy
: text
= i18n("Copy"); break;
349 case DolphinCommand::Move
: text
= i18n("Move"); break;
350 case DolphinCommand::Link
: text
= i18n("Link"); break;
351 case DolphinCommand::Rename
: text
= i18n("Rename"); break;
352 case DolphinCommand::Trash
: text
= i18n("Move to Trash"); break;
353 case DolphinCommand::CreateFolder
: text
= i18n("Create New Folder"); break;
354 case DolphinCommand::CreateFile
: text
= i18n("Create New File"); break;
360 void UndoManager::slotPercent(KJob
* /* job */, unsigned long /* percent */)
362 // It is not allowed to update the progress indicator in the context
363 // of this slot, hence do an asynchronous triggering.
364 QTimer::singleShot(0, this, SLOT(updateProgress()));
367 void UndoManager::updateProgress()
370 * ### XXX, TODO, KDE4 make this work when switchting to KonqUndoManager
372 //m_progressIndicator->execOperation();
375 void UndoManager::calcStepsCount(int& macroCount
, int& progressCount
)
380 const int macroIndex
= m_history
[m_historyIndex
].m_macroIndex
;
381 if (macroIndex
< 0) {
382 // default use case: no macro has been recorded
384 progressCount
= m_history
[m_historyIndex
].source().count();
388 // iterate backward for undo...
389 int i
= m_historyIndex
;
390 while ((i
>= 0) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
392 progressCount
+= m_history
[i
].source().count();
396 // iterate forward for redo...
397 const int max
= m_history
.count() - 1;
398 i
= m_historyIndex
+ 1;
399 while ((i
<= max
) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
401 progressCount
+= m_history
[i
].source().count();
406 #include "undomanager.moc"