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
42 DolphinCommand::DolphinCommand(Type type
,
43 const KUrl::List
& source
,
52 DolphinCommand::~DolphinCommand()
56 DolphinCommand
& DolphinCommand::operator = (const DolphinCommand
& command
)
58 m_type
= command
.m_type
;
59 m_source
= command
.m_source
;
60 m_dest
= command
.m_dest
;
64 UndoManager
& UndoManager::instance()
66 static UndoManager
* instance
= 0;
68 instance
= new UndoManager();
73 void UndoManager::addCommand(const DolphinCommand
& command
)
78 DolphinCommand macroCommand
= command
;
79 macroCommand
.m_macroIndex
= m_macroCounter
;
80 m_history
.insert(m_history
.at(m_historyIndex
), macroCommand
);
83 m_history
.insert(m_history
.at(m_historyIndex
), command
);
86 emit
undoAvailable(true);
87 emit
undoTextChanged(i18n("Undo: %1").arg(commandText(command
)));
89 // prevent an endless growing of the Undo history
90 if (m_historyIndex
> 10000) {
91 m_history
.erase(m_history
.begin());
96 void UndoManager::beginMacro()
98 assert(!m_recordMacro
);
103 void UndoManager::endMacro()
105 assert(m_recordMacro
);
106 m_recordMacro
= false;
109 void UndoManager::undo()
115 if (m_historyIndex
< 0) {
119 int progressCount
= 0;
121 calcStepsCount(macroCount
, progressCount
);
123 m_progressIndicator
= new ProgressIndicator(i18n("Executing undo operation..."),
124 i18n("Executed undo operation."),
127 for (int i
= 0; i
< macroCount
; ++i
) {
128 const DolphinCommand command
= m_history
[m_historyIndex
];
130 if (m_historyIndex
< 0) {
131 emit
undoAvailable(false);
132 emit
undoTextChanged(i18n("Undo"));
135 emit
undoTextChanged(i18n("Undo: %1").arg(commandText(m_history
[m_historyIndex
])));
138 if (m_historyIndex
< static_cast<int>(m_history
.count()) - 1) {
139 emit
redoAvailable(true);
140 emit
redoTextChanged(i18n("Redo: %1").arg(commandText(command
)));
143 emit
redoAvailable(false);
144 emit
redoTextChanged(i18n("Redo"));
147 KUrl::List sourceURLs
= command
.source();
148 KUrl::List::Iterator it
= sourceURLs
.begin();
149 const KUrl::List::Iterator end
= sourceURLs
.end();
150 const QString
destURL(command
.destination().prettyURL(+1));
153 switch (command
.type()) {
154 case DolphinCommand::Link
:
155 case DolphinCommand::Copy
: {
158 const KUrl
deleteURL(destURL
+ (*it
).filename());
159 list
.append(deleteURL
);
162 job
= KIO::del(list
, false, false);
166 case DolphinCommand::Move
: {
168 const KUrl
newDestURL((*it
).directory());
170 const KUrl
newSourceURL(destURL
+ (*it
).filename());
171 list
.append(newSourceURL
);
174 job
= KIO::move(list
, newDestURL
, false);
178 case DolphinCommand::Rename
: {
179 assert(sourceURLs
.count() == 1);
180 KIO::NetAccess::move(command
.destination(), (*it
));
184 case DolphinCommand::Trash
: {
186 // TODO: use KIO::special for accessing the trash protocol. See
187 // also Dolphin::slotJobResult() for further details.
188 const QString
originalFileName((*it
).filename().section('-', 1));
189 KUrl
newDestURL(destURL
+ originalFileName
);
190 KIO::NetAccess::move(*it
, newDestURL
);
193 m_progressIndicator
->execOperation();
198 case DolphinCommand::CreateFolder
:
199 case DolphinCommand::CreateFile
: {
200 KIO::NetAccess::del(command
.destination(), &Dolphin::mainWin());
206 // Execute the jobs in a synchronous manner and forward the progress
207 // information to the Dolphin statusbar.
208 connect(job
, SIGNAL(percent(KIO::Job
*, unsigned long)),
209 this, SLOT(slotPercent(KIO::Job
*, unsigned long)));
210 KIO::NetAccess::synchronousRun(job
, &Dolphin::mainWin());
213 m_progressIndicator
->execOperation();
216 delete m_progressIndicator
;
217 m_progressIndicator
= 0;
220 void UndoManager::redo()
226 const int maxHistoryIndex
= m_history
.count() - 1;
227 if (m_historyIndex
>= maxHistoryIndex
) {
232 int progressCount
= 0;
234 calcStepsCount(macroCount
, progressCount
);
236 m_progressIndicator
= new ProgressIndicator(i18n("Executing redo operation..."),
237 i18n("Executed redo operation."),
240 for (int i
= 0; i
< macroCount
; ++i
) {
241 const DolphinCommand command
= m_history
[m_historyIndex
];
242 if (m_historyIndex
>= maxHistoryIndex
) {
243 emit
redoAvailable(false);
244 emit
redoTextChanged(i18n("Redo"));
247 emit
redoTextChanged(i18n("Redo: %1").arg(commandText(m_history
[m_historyIndex
+ 1])));
250 emit
undoAvailable(true);
251 emit
undoTextChanged(i18n("Undo: %1").arg(commandText(command
)));
253 Dolphin
& dolphin
= Dolphin::mainWin();
255 KUrl::List sourceURLs
= command
.source();
256 KUrl::List::Iterator it
= sourceURLs
.begin();
257 const KUrl::List::Iterator end
= sourceURLs
.end();
260 switch (command
.type()) {
261 case DolphinCommand::Link
: {
262 job
= KIO::link(sourceURLs
, command
.destination(), false);
266 case DolphinCommand::Copy
: {
267 job
= KIO::copy(sourceURLs
, command
.destination(), false);
271 case DolphinCommand::Rename
:
272 case DolphinCommand::Move
: {
273 job
= KIO::move(sourceURLs
, command
.destination(), false);
277 case DolphinCommand::Trash
: {
278 const QString
destURL(command
.destination().prettyURL());
280 // TODO: use KIO::special for accessing the trash protocol. See
281 // also Dolphin::slotJobResult() for further details.
282 const QString
originalFileName((*it
).filename().section('-', 1));
283 KUrl
originalSourceURL(destURL
+ "/" + originalFileName
);
284 KIO::Job
* moveToTrashJob
= KIO::trash(originalSourceURL
);
285 KIO::NetAccess::synchronousRun(moveToTrashJob
, &dolphin
);
288 m_progressIndicator
->execOperation();
293 case DolphinCommand::CreateFolder
: {
294 KIO::NetAccess::mkdir(command
.destination(), &dolphin
);
298 case DolphinCommand::CreateFile
: {
299 m_progressIndicator
->execOperation();
300 KUrl::List::Iterator it
= sourceURLs
.begin();
301 assert(sourceURLs
.count() == 1);
302 KIO::CopyJob
* copyJob
= KIO::copyAs(*it
, command
.destination(), false);
303 copyJob
->setDefaultPermissions(true);
310 // Execute the jobs in a synchronous manner and forward the progress
311 // information to the Dolphin statusbar.
312 connect(job
, SIGNAL(percent(KIO::Job
*, unsigned long)),
313 this, SLOT(slotPercent(KIO::Job
*, unsigned long)));
314 KIO::NetAccess::synchronousRun(job
, &dolphin
);
318 m_progressIndicator
->execOperation();
323 delete m_progressIndicator
;
324 m_progressIndicator
= 0;
327 UndoManager::UndoManager() :
328 m_recordMacro(false),
331 m_progressIndicator(0)
335 UndoManager::~UndoManager()
337 delete m_progressIndicator
;
338 m_progressIndicator
= 0;
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(KIO::Job
* /* 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()
366 m_progressIndicator
->execOperation();
369 void UndoManager::calcStepsCount(int& macroCount
, int& progressCount
)
374 const int macroIndex
= m_history
[m_historyIndex
].m_macroIndex
;
375 if (macroIndex
< 0) {
376 // default use case: no macro has been recorded
378 progressCount
= m_history
[m_historyIndex
].source().count();
382 // iterate backward for undo...
383 int i
= m_historyIndex
;
384 while ((i
>= 0) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
386 progressCount
+= m_history
[i
].source().count();
390 // iterate forward for redo...
391 const int max
= m_history
.count() - 1;
392 i
= m_historyIndex
+ 1;
393 while ((i
<= max
) && (m_history
[i
].m_macroIndex
== macroIndex
)) {
395 progressCount
+= m_history
[i
].source().count();
400 #include "undomanager.moc"