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>
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()
119 if (m_historyIndex
< 0) {
123 int progressCount
= 0;
125 calcStepsCount(macroCount
, progressCount
);
127 m_progressIndicator
= new ProgressIndicator(i18n("Executing undo operation..."),
128 i18n("Executed undo operation."),
131 for (int i
= 0; i
< macroCount
; ++i
) {
132 const DolphinCommand command
= m_history
[m_historyIndex
];
134 if (m_historyIndex
< 0) {
135 emit
undoAvailable(false);
136 emit
undoTextChanged(i18n("Undo"));
139 emit
undoTextChanged(i18n("Undo: %1",commandText(m_history
[m_historyIndex
])));
142 if (m_historyIndex
< static_cast<int>(m_history
.count()) - 1) {
143 emit
redoAvailable(true);
144 emit
redoTextChanged(i18n("Redo: %1",commandText(command
)));
147 emit
redoAvailable(false);
148 emit
redoTextChanged(i18n("Redo"));
151 KUrl::List sourceUrls
= command
.source();
152 KUrl::List::Iterator it
= sourceUrls
.begin();
153 const KUrl::List::Iterator end
= sourceUrls
.end();
154 const QString
destUrl(command
.destination().prettyUrl(KUrl::AddTrailingSlash
));
157 switch (command
.type()) {
158 case DolphinCommand::Link
:
159 case DolphinCommand::Copy
: {
162 const KUrl
deleteUrl(destUrl
+ (*it
).fileName());
163 list
.append(deleteUrl
);
166 job
= KIO::del(list
, false, false);
170 case DolphinCommand::Move
: {
172 const KUrl
newDestUrl((*it
).directory());
174 const KUrl
newSourceUrl(destUrl
+ (*it
).fileName());
175 list
.append(newSourceUrl
);
178 job
= KIO::move(list
, newDestUrl
, false);
182 case DolphinCommand::Rename
: {
183 assert(sourceUrls
.count() == 1);
184 KIO::NetAccess::move(command
.destination(), (*it
));
188 case DolphinCommand::Trash
: {
190 // TODO: use KIO::special for accessing the trash protocol. See
191 // also Dolphin::slotJobResult() for further details.
192 const QString
originalFileName((*it
).fileName().section('-', 1));
193 KUrl
newDestUrl(destUrl
+ originalFileName
);
194 KIO::NetAccess::move(*it
, newDestUrl
);
197 m_progressIndicator
->execOperation();
202 case DolphinCommand::CreateFolder
:
203 case DolphinCommand::CreateFile
: {
204 KIO::NetAccess::del(command
.destination(), &Dolphin::mainWin());
210 // Execute the jobs in a synchronous manner and forward the progress
211 // information to the Dolphin statusbar.
212 connect(job
, SIGNAL(percent(KIO::Job
*, unsigned long)),
213 this, SLOT(slotPercent(KIO::Job
*, unsigned long)));
214 KIO::NetAccess::synchronousRun(job
, &Dolphin::mainWin());
217 m_progressIndicator
->execOperation();
220 delete m_progressIndicator
;
221 m_progressIndicator
= 0;
224 void UndoManager::redo()
230 const int maxHistoryIndex
= m_history
.count() - 1;
231 if (m_historyIndex
>= maxHistoryIndex
) {
236 int progressCount
= 0;
238 calcStepsCount(macroCount
, progressCount
);
240 m_progressIndicator
= new ProgressIndicator(i18n("Executing redo operation..."),
241 i18n("Executed redo operation."),
244 for (int i
= 0; i
< macroCount
; ++i
) {
245 const DolphinCommand command
= m_history
[m_historyIndex
];
246 if (m_historyIndex
>= maxHistoryIndex
) {
247 emit
redoAvailable(false);
248 emit
redoTextChanged(i18n("Redo"));
251 emit
redoTextChanged(i18n("Redo: %1",commandText(m_history
[m_historyIndex
+ 1])));
254 emit
undoAvailable(true);
255 emit
undoTextChanged(i18n("Undo: %1",commandText(command
)));
257 Dolphin
& dolphin
= Dolphin::mainWin();
259 KUrl::List sourceUrls
= command
.source();
260 KUrl::List::Iterator it
= sourceUrls
.begin();
261 const KUrl::List::Iterator end
= sourceUrls
.end();
264 switch (command
.type()) {
265 case DolphinCommand::Link
: {
266 job
= KIO::link(sourceUrls
, command
.destination(), false);
270 case DolphinCommand::Copy
: {
271 job
= KIO::copy(sourceUrls
, command
.destination(), false);
275 case DolphinCommand::Rename
:
276 case DolphinCommand::Move
: {
277 job
= KIO::move(sourceUrls
, command
.destination(), false);
281 case DolphinCommand::Trash
: {
282 const QString
destUrl(command
.destination().prettyUrl());
284 // TODO: use KIO::special for accessing the trash protocol. See
285 // also Dolphin::slotJobResult() for further details.
286 const QString
originalFileName((*it
).fileName().section('-', 1));
287 KUrl
originalSourceUrl(destUrl
+ "/" + originalFileName
);
288 KIO::Job
* moveToTrashJob
= KIO::trash(originalSourceUrl
);
289 KIO::NetAccess::synchronousRun(moveToTrashJob
, &dolphin
);
292 m_progressIndicator
->execOperation();
297 case DolphinCommand::CreateFolder
: {
298 KIO::NetAccess::mkdir(command
.destination(), &dolphin
);
302 case DolphinCommand::CreateFile
: {
303 m_progressIndicator
->execOperation();
304 KUrl::List::Iterator it
= sourceUrls
.begin();
305 assert(sourceUrls
.count() == 1);
306 KIO::CopyJob
* copyJob
= KIO::copyAs(*it
, command
.destination(), false);
307 copyJob
->setDefaultPermissions(true);
314 // Execute the jobs in a synchronous manner and forward the progress
315 // information to the Dolphin statusbar.
316 connect(job
, SIGNAL(percent(KIO::Job
*, unsigned long)),
317 this, SLOT(slotPercent(KIO::Job
*, unsigned long)));
318 KIO::NetAccess::synchronousRun(job
, &dolphin
);
322 m_progressIndicator
->execOperation();
327 delete m_progressIndicator
;
328 m_progressIndicator
= 0;
331 UndoManager::UndoManager() :
332 m_recordMacro(false),
335 m_progressIndicator(0)
339 UndoManager::~UndoManager()
341 delete m_progressIndicator
;
342 m_progressIndicator
= 0;
345 QString
UndoManager::commandText(const DolphinCommand
& command
) const
348 switch (command
.type()) {
349 case DolphinCommand::Copy
: text
= i18n("Copy"); break;
350 case DolphinCommand::Move
: text
= i18n("Move"); break;
351 case DolphinCommand::Link
: text
= i18n("Link"); break;
352 case DolphinCommand::Rename
: text
= i18n("Rename"); break;
353 case DolphinCommand::Trash
: text
= i18n("Move to Trash"); break;
354 case DolphinCommand::CreateFolder
: text
= i18n("Create New Folder"); break;
355 case DolphinCommand::CreateFile
: text
= i18n("Create New File"); break;
361 void UndoManager::slotPercent(KIO::Job
* /* job */, unsigned long /* percent */)
363 // It is not allowed to update the progress indicator in the context
364 // of this slot, hence do an asynchronous triggering.
365 QTimer::singleShot(0, this, SLOT(updateProgress()));
368 void UndoManager::updateProgress()
370 m_progressIndicator
->execOperation();
373 void UndoManager::calcStepsCount(int& macroCount
, int& progressCount
)
378 const int macroIndex
= m_history
[m_historyIndex
].m_macroIndex
;
379 if (macroIndex
< 0) {
380 // default use case: no macro has been recorded
382 progressCount
= m_history
[m_historyIndex
].source().count();
386 // iterate backward for undo...
387 int i
= m_historyIndex
;
388 while ((i
>= 0) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
390 progressCount
+= m_history
[i
].source().count();
394 // iterate forward for redo...
395 const int max
= m_history
.count() - 1;
396 i
= m_historyIndex
+ 1;
397 while ((i
<= max
) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
399 progressCount
+= m_history
[i
].source().count();
404 #include "undomanager.moc"