20 #include "konq_undo.h"
24 #include <tdeio/uiserver_stub.h>
25 #include "konq_operations.h"
29 #include <dcopclient.h>
32 #include <tdeapplication.h>
33 #include <kdatastream.h>
35 #include <tdelocale.h>
36 #include <tdeglobalsettings.h>
37 #include <tdeconfig.h>
40 #include <tdeio/job.h>
41 #include <kdirnotify_stub.h>
43 inline const char *dcopTypeName(
const KonqCommand & ) {
return "KonqCommand"; }
44 inline const char *dcopTypeName(
const KonqCommand::Stack & ) {
return "KonqCommand::Stack"; }
66 class KonqUndoJob :
public TDEIO::Job
69 KonqUndoJob() : TDEIO::Job( true ) { KonqUndoManager::incRef(); };
70 virtual ~KonqUndoJob() { KonqUndoManager::decRef(); }
72 virtual void kill(
bool q) { KonqUndoManager::self()->stopUndo(
true ); TDEIO::Job::kill( q ); }
75 class KonqCommandRecorder::KonqCommandRecorderPrivate
78 KonqCommandRecorderPrivate()
81 ~KonqCommandRecorderPrivate()
88 KonqCommandRecorder::KonqCommandRecorder( KonqCommand::Type op,
const KURL::List &src,
const KURL &dst, TDEIO::Job *job )
89 : TQObject( job,
"konqcmdrecorder" )
91 d =
new KonqCommandRecorderPrivate;
93 d->m_cmd.m_valid =
true;
96 connect( job, TQ_SIGNAL( result( TDEIO::Job * ) ),
97 this, TQ_SLOT( slotResult( TDEIO::Job * ) ) );
99 if ( op != KonqCommand::MKDIR ) {
100 connect( job, TQ_SIGNAL( copyingDone( TDEIO::Job *,
const KURL &,
const KURL &,
bool,
bool ) ),
101 this, TQ_SLOT( slotCopyingDone( TDEIO::Job *,
const KURL &,
const KURL &,
bool,
bool ) ) );
102 connect( job, TQ_SIGNAL( copyingLinkDone( TDEIO::Job *,
const KURL &,
const TQString &,
const KURL & ) ),
103 this, TQ_SLOT( slotCopyingLinkDone( TDEIO::Job *,
const KURL &,
const TQString &,
const KURL & ) ) );
106 KonqUndoManager::incRef();
109 KonqCommandRecorder::~KonqCommandRecorder()
111 KonqUndoManager::decRef();
115 void KonqCommandRecorder::slotResult( TDEIO::Job *job )
120 KonqUndoManager::self()->addCommand( d->m_cmd );
123 void KonqCommandRecorder::slotCopyingDone( TDEIO::Job *job,
const KURL &from,
const KURL &to,
bool directory,
bool renamed )
125 KonqBasicOperation op;
127 op.m_directory = directory;
128 op.m_renamed = renamed;
133 if ( d->m_cmd.m_type == KonqCommand::TRASH )
135 Q_ASSERT( from.isLocalFile() );
136 Q_ASSERT( to.protocol() ==
"trash" );
137 TQMap<TQString, TQString> metaData = job->metaData();
138 TQMap<TQString, TQString>::ConstIterator it = metaData.find(
"trashURL-" + from.path() );
139 if ( it != metaData.end() ) {
141 op.m_dst = it.data();
145 d->m_cmd.m_opStack.prepend( op );
148 void KonqCommandRecorder::slotCopyingLinkDone( TDEIO::Job *,
const KURL &from,
const TQString &target,
const KURL &to )
150 KonqBasicOperation op;
152 op.m_directory =
false;
153 op.m_renamed =
false;
155 op.m_target = target;
158 d->m_cmd.m_opStack.prepend( op );
161 KonqUndoManager *KonqUndoManager::s_self = 0;
162 unsigned long KonqUndoManager::s_refCnt = 0;
164 class KonqUndoManager::KonqUndoManagerPrivate
167 KonqUndoManagerPrivate()
169 m_uiserver =
new UIServer_stub(
"tdeio_uiserver",
"UIServer" );
172 ~KonqUndoManagerPrivate()
179 KonqCommand::Stack m_commands;
181 KonqCommand m_current;
182 TDEIO::Job *m_currentJob;
183 UndoState m_undoState;
184 TQValueStack<KURL> m_dirStack;
185 TQValueStack<KURL> m_dirCleanupStack;
186 TQValueStack<KURL> m_fileCleanupStack;
187 TQValueList<KURL> m_dirsToUpdate;
191 UIServer_stub *m_uiserver;
194 KonqUndoJob *m_undoJob;
197 KonqUndoManager::KonqUndoManager()
198 : DCOPObject(
"KonqUndoManager" )
200 if ( !kapp->dcopClient()->isAttached() )
201 kapp->dcopClient()->attach();
203 d =
new KonqUndoManagerPrivate;
204 d->m_syncronized = initializeFromKDesky();
209 KonqUndoManager::~KonqUndoManager()
214 void KonqUndoManager::incRef()
219 void KonqUndoManager::decRef()
222 if ( s_refCnt == 0 && s_self )
229 KonqUndoManager *KonqUndoManager::self()
235 s_self =
new KonqUndoManager;
240 void KonqUndoManager::addCommand(
const KonqCommand &cmd )
242 broadcastPush( cmd );
245 bool KonqUndoManager::undoAvailable()
const
247 return ( d->m_commands.count() > 0 ) && !d->m_lock;
250 TQString KonqUndoManager::undoText()
const
252 if ( d->m_commands.count() == 0 )
253 return i18n(
"Und&o" );
255 KonqCommand::Type t = d->m_commands.top().m_type;
256 if ( t == KonqCommand::COPY )
257 return i18n(
"Und&o: Copy" );
258 else if ( t == KonqCommand::LINK )
259 return i18n(
"Und&o: Link" );
260 else if ( t == KonqCommand::MOVE )
261 return i18n(
"Und&o: Move" );
262 else if ( t == KonqCommand::TRASH )
263 return i18n(
"Und&o: Trash" );
264 else if ( t == KonqCommand::MKDIR )
265 return i18n(
"Und&o: Create Folder" );
269 return TQString::null;
272 void KonqUndoManager::undo()
274 KonqCommand cmd = d->m_commands.top();
275 assert( cmd.m_valid );
279 TQValueList<KonqBasicOperation>& opStack = d->m_current.m_opStack;
282 KURL::List fileCleanupStack;
283 TQValueList<KonqBasicOperation>::Iterator it = opStack.begin();
284 for ( ; it != opStack.end() ; ++it ) {
285 if ( !(*it).m_directory && !(*it).m_link && d->m_current.m_type == KonqCommand::COPY ) {
286 fileCleanupStack.append( (*it).m_dst );
289 if ( !fileCleanupStack.isEmpty() ) {
292 KonqOperations::FORCE_CONFIRMATION,
297 d->m_dirCleanupStack.clear();
298 d->m_dirStack.clear();
299 d->m_dirsToUpdate.clear();
301 d->m_undoState = MOVINGFILES;
306 it = opStack.begin();
307 TQValueList<KonqBasicOperation>::Iterator end = opStack.end();
310 if ( (*it).m_directory && !(*it).m_renamed )
312 d->m_dirStack.push( (*it).m_src );
313 d->m_dirCleanupStack.prepend( (*it).m_dst );
314 it = d->m_current.m_opStack.remove( it );
315 d->m_undoState = MAKINGDIRS;
316 kdDebug(1203) <<
"KonqUndoManager::undo MAKINGDIRS" << endl;
318 else if ( (*it).m_link )
320 if ( !d->m_fileCleanupStack.contains( (*it).m_dst ) )
321 d->m_fileCleanupStack.prepend( (*it).m_dst );
323 if ( d->m_current.m_type != KonqCommand::MOVE )
324 it = d->m_current.m_opStack.remove( it );
347 if ( d->m_current.m_type != KonqCommand::MOVE )
348 d->m_dirStack.clear();
350 d->m_undoJob =
new KonqUndoJob;
351 d->m_uiserverJobId = d->m_undoJob->progressId();
355 void KonqUndoManager::stopUndo(
bool step )
357 d->m_current.m_opStack.clear();
358 d->m_dirCleanupStack.clear();
359 d->m_fileCleanupStack.clear();
360 d->m_undoState = REMOVINGDIRS;
363 if ( d->m_currentJob )
364 d->m_currentJob->kill(
true );
372 void KonqUndoManager::slotResult( TDEIO::Job *job )
374 d->m_uiserver->jobFinished( d->m_uiserverJobId );
377 job->showErrorDialog( 0L );
391 void KonqUndoManager::addDirToUpdate(
const KURL& url )
393 if ( d->m_dirsToUpdate.find( url ) == d->m_dirsToUpdate.end() )
394 d->m_dirsToUpdate.prepend( url );
397 void KonqUndoManager::undoStep()
401 if ( d->m_undoState == MAKINGDIRS )
402 undoMakingDirectories();
404 if ( d->m_undoState == MOVINGFILES )
407 if ( d->m_undoState == REMOVINGFILES )
410 if ( d->m_undoState == REMOVINGDIRS )
411 undoRemovingDirectories();
413 if ( d->m_currentJob )
414 connect( d->m_currentJob, TQ_SIGNAL( result( TDEIO::Job * ) ),
415 this, TQ_SLOT( slotResult( TDEIO::Job * ) ) );
418 void KonqUndoManager::undoMakingDirectories()
420 if ( !d->m_dirStack.isEmpty() ) {
421 KURL dir = d->m_dirStack.pop();
422 kdDebug(1203) <<
"KonqUndoManager::undoStep creatingDir " << dir.prettyURL() << endl;
423 d->m_currentJob = TDEIO::mkdir( dir );
424 d->m_uiserver->creatingDir( d->m_uiserverJobId, dir );
427 d->m_undoState = MOVINGFILES;
430 void KonqUndoManager::undoMovingFiles()
432 if ( !d->m_current.m_opStack.isEmpty() )
434 KonqBasicOperation op = d->m_current.m_opStack.pop();
436 assert( op.m_valid );
437 if ( op.m_directory )
441 kdDebug(1203) <<
"KonqUndoManager::undoStep rename " << op.m_dst.prettyURL() <<
" " << op.m_src.prettyURL() << endl;
442 d->m_currentJob = TDEIO::rename( op.m_dst, op.m_src,
false );
443 d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
448 else if ( op.m_link )
450 kdDebug(1203) <<
"KonqUndoManager::undoStep symlink " << op.m_target <<
" " << op.m_src.prettyURL() << endl;
451 d->m_currentJob = TDEIO::symlink( op.m_target, op.m_src,
true,
false );
453 else if ( d->m_current.m_type == KonqCommand::COPY )
455 kdDebug(1203) <<
"KonqUndoManager::undoStep file_delete " << op.m_dst.prettyURL() << endl;
456 d->m_currentJob = TDEIO::file_delete( op.m_dst );
457 d->m_uiserver->deleting( d->m_uiserverJobId, op.m_dst );
459 else if ( d->m_current.m_type == KonqCommand::MOVE
460 || d->m_current.m_type == KonqCommand::TRASH )
462 kdDebug(1203) <<
"KonqUndoManager::undoStep file_move " << op.m_dst.prettyURL() <<
" " << op.m_src.prettyURL() << endl;
463 d->m_currentJob = TDEIO::file_move( op.m_dst, op.m_src, -1,
true );
464 d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
469 KURL url( op.m_dst );
470 url.setPath( url.directory() );
471 addDirToUpdate( url );
474 url.setPath( url.directory() );
475 addDirToUpdate( url );
478 d->m_undoState = REMOVINGFILES;
481 void KonqUndoManager::undoRemovingFiles()
483 kdDebug(1203) <<
"KonqUndoManager::undoStep REMOVINGFILES" << endl;
484 if ( !d->m_fileCleanupStack.isEmpty() )
486 KURL file = d->m_fileCleanupStack.pop();
487 kdDebug(1203) <<
"KonqUndoManager::undoStep file_delete " << file.prettyURL() << endl;
488 d->m_currentJob = TDEIO::file_delete( file );
489 d->m_uiserver->deleting( d->m_uiserverJobId, file );
492 url.setPath( url.directory() );
493 addDirToUpdate( url );
497 d->m_undoState = REMOVINGDIRS;
499 if ( d->m_dirCleanupStack.isEmpty() && d->m_current.m_type == KonqCommand::MKDIR )
500 d->m_dirCleanupStack << d->m_current.m_dst;
504 void KonqUndoManager::undoRemovingDirectories()
506 if ( !d->m_dirCleanupStack.isEmpty() )
508 KURL dir = d->m_dirCleanupStack.pop();
509 kdDebug(1203) <<
"KonqUndoManager::undoStep rmdir " << dir.prettyURL() << endl;
510 d->m_currentJob = TDEIO::rmdir( dir );
511 d->m_uiserver->deleting( d->m_uiserverJobId, dir );
512 addDirToUpdate( dir );
516 d->m_current.m_valid =
false;
520 kdDebug(1203) <<
"KonqUndoManager::undoStep deleting undojob" << endl;
521 d->m_uiserver->jobFinished( d->m_uiserverJobId );
525 KDirNotify_stub allDirNotify(
"*",
"KDirNotify*" );
526 TQValueList<KURL>::ConstIterator it = d->m_dirsToUpdate.begin();
527 for( ; it != d->m_dirsToUpdate.end(); ++it ) {
528 kdDebug() <<
"Notifying FilesAdded for " << *it << endl;
529 allDirNotify.FilesAdded( *it );
535 void KonqUndoManager::push(
const KonqCommand &cmd )
537 d->m_commands.push( cmd );
538 emit undoAvailable(
true );
539 emit undoTextChanged( undoText() );
542 void KonqUndoManager::pop()
545 emit undoAvailable( undoAvailable() );
546 emit undoTextChanged( undoText() );
549 void KonqUndoManager::lock()
553 emit undoAvailable( undoAvailable() );
556 void KonqUndoManager::unlock()
560 emit undoAvailable( undoAvailable() );
563 KonqCommand::Stack KonqUndoManager::get()
const
565 return d->m_commands;
568 void KonqUndoManager::broadcastPush(
const KonqCommand &cmd )
570 if ( !d->m_syncronized )
576 DCOPRef(
"kdesktop",
"KonqUndoManager" ).send(
"push", cmd );
577 DCOPRef(
"konqueror*",
"KonqUndoManager" ).send(
"push", cmd );
580 void KonqUndoManager::broadcastPop()
582 if ( !d->m_syncronized )
587 DCOPRef(
"kdesktop",
"KonqUndoManager" ).send(
"pop" );
588 DCOPRef(
"konqueror*",
"KonqUndoManager" ).send(
"pop" );
591 void KonqUndoManager::broadcastLock()
595 if ( !d->m_syncronized )
600 DCOPRef(
"kdesktop",
"KonqUndoManager" ).send(
"lock" );
601 DCOPRef(
"konqueror*",
"KonqUndoManager" ).send(
"lock" );
604 void KonqUndoManager::broadcastUnlock()
608 if ( !d->m_syncronized )
613 DCOPRef(
"kdesktop",
"KonqUndoManager" ).send(
"unlock" );
614 DCOPRef(
"konqueror*",
"KonqUndoManager" ).send(
"unlock" );
617 bool KonqUndoManager::initializeFromKDesky()
628 DCOPClient *client = kapp->dcopClient();
630 if ( client->appId() ==
"kdesktop" )
633 if ( !client->isApplicationRegistered(
"kdesktop" ) )
636 d->m_commands = DCOPRef(
"kdesktop",
"KonqUndoManager" ).call(
"get" );
640 TQDataStream &operator<<( TQDataStream &stream,
const KonqBasicOperation &op )
642 stream << op.m_valid << op.m_directory << op.m_renamed << op.m_link
643 << op.m_src << op.m_dst << op.m_target;
646 TQDataStream &operator>>( TQDataStream &stream, KonqBasicOperation &op )
648 stream >> op.m_valid >> op.m_directory >> op.m_renamed >> op.m_link
649 >> op.m_src >> op.m_dst >> op.m_target;
653 TQDataStream &operator<<( TQDataStream &stream,
const KonqCommand &cmd )
655 stream << cmd.m_valid << (TQ_INT8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst;
659 TQDataStream &operator>>( TQDataStream &stream, KonqCommand &cmd )
662 stream >> cmd.m_valid >> type >> cmd.m_opStack >> cmd.m_src >> cmd.m_dst;
663 cmd.m_type =
static_cast<KonqCommand::Type
>( type );
667 #include "konq_undo.moc"
static bool askDeleteConfirmation(const KURL::List &selectedURLs, int method, ConfirmationType confirmation, TQWidget *widget)
Ask for confirmation before deleting/trashing selectedURLs.