konq_undo.cc
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "konq_undo.h"
00021
00022 #undef Always
00023
00024 #include <kio/uiserver_stub.h>
00025
00026 #include <assert.h>
00027
00028 #include <dcopclient.h>
00029 #include <dcopref.h>
00030
00031 #include <kapplication.h>
00032 #include <kdatastream.h>
00033 #include <kdebug.h>
00034 #include <klocale.h>
00035 #include <kglobalsettings.h>
00036 #include <kconfig.h>
00037 #include <kipc.h>
00038
00039 #include <kio/job.h>
00040
00041 inline const char *dcopTypeName( const KonqCommand & ) { return "KonqCommand"; }
00042 inline const char *dcopTypeName( const KonqCommand::Stack & ) { return "KonqCommand::Stack"; }
00043
00064 class KonqUndoJob : public KIO::Job
00065 {
00066 public:
00067 KonqUndoJob() : KIO::Job( true ) { KonqUndoManager::incRef(); };
00068 virtual ~KonqUndoJob() { KonqUndoManager::decRef(); }
00069
00070 virtual void kill( bool q) { KonqUndoManager::self()->stopUndo( true ); KIO::Job::kill( q ); }
00071 };
00072
00073 class KonqCommandRecorder::KonqCommandRecorderPrivate
00074 {
00075 public:
00076 KonqCommandRecorderPrivate()
00077 {
00078 }
00079 ~KonqCommandRecorderPrivate()
00080 {
00081 }
00082
00083 KonqCommand m_cmd;
00084 };
00085
00086 KonqCommandRecorder::KonqCommandRecorder( KonqCommand::Type op, const KURL::List &src, const KURL &dst, KIO::Job *job )
00087 : QObject( job, "konqcmdrecorder" )
00088 {
00089 d = new KonqCommandRecorderPrivate;
00090 d->m_cmd.m_type = op;
00091 d->m_cmd.m_valid = true;
00092 d->m_cmd.m_src = src;
00093 d->m_cmd.m_dst = dst;
00094 connect( job, SIGNAL( result( KIO::Job * ) ),
00095 this, SLOT( slotResult( KIO::Job * ) ) );
00096
00097 if ( op != KonqCommand::MKDIR ) {
00098 connect( job, SIGNAL( copyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ),
00099 this, SLOT( slotCopyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ) );
00100 connect( job, SIGNAL( copyingLinkDone( KIO::Job *, const KURL &, const QString &, const KURL & ) ),
00101 this, SLOT( slotCopyingLinkDone( KIO::Job *, const KURL &, const QString &, const KURL & ) ) );
00102 }
00103
00104 KonqUndoManager::incRef();
00105 }
00106
00107 KonqCommandRecorder::~KonqCommandRecorder()
00108 {
00109 KonqUndoManager::decRef();
00110 delete d;
00111 }
00112
00113 void KonqCommandRecorder::slotResult( KIO::Job *job )
00114 {
00115 if ( job->error() )
00116 return;
00117
00118 KonqUndoManager::self()->addCommand( d->m_cmd );
00119 }
00120
00121 void KonqCommandRecorder::slotCopyingDone( KIO::Job *, const KURL &from, const KURL &to, bool directory, bool renamed )
00122 {
00123 KonqBasicOperation op;
00124 op.m_valid = true;
00125 op.m_directory = directory;
00126 op.m_renamed = renamed;
00127 op.m_src = from;
00128 op.m_dst = to;
00129 op.m_link = false;
00130 d->m_cmd.m_opStack.prepend( op );
00131 }
00132
00133 void KonqCommandRecorder::slotCopyingLinkDone( KIO::Job *, const KURL &from, const QString &target, const KURL &to )
00134 {
00135 KonqBasicOperation op;
00136 op.m_valid = true;
00137 op.m_directory = false;
00138 op.m_renamed = false;
00139 op.m_src = from;
00140 op.m_target = target;
00141 op.m_dst = to;
00142 op.m_link = true;
00143 d->m_cmd.m_opStack.prepend( op );
00144 }
00145
00146 KonqUndoManager *KonqUndoManager::s_self = 0;
00147 unsigned long KonqUndoManager::s_refCnt = 0;
00148
00149 class KonqUndoManager::KonqUndoManagerPrivate
00150 {
00151 public:
00152 KonqUndoManagerPrivate()
00153 {
00154 m_uiserver = new UIServer_stub( "kio_uiserver", "UIServer" );
00155 m_undoJob = 0;
00156 }
00157 ~KonqUndoManagerPrivate()
00158 {
00159 delete m_uiserver;
00160 }
00161
00162 bool m_syncronized;
00163
00164 KonqCommand::Stack m_commands;
00165
00166 KonqCommand m_current;
00167 KIO::Job *m_currentJob;
00168 UndoState m_undoState;
00169 QValueStack<KURL> m_dirStack;
00170 QValueStack<KURL> m_dirCleanupStack;
00171 QValueStack<KURL> m_fileCleanupStack;
00172
00173 bool m_lock;
00174
00175 UIServer_stub *m_uiserver;
00176 int m_uiserverJobId;
00177
00178 KonqUndoJob *m_undoJob;
00179 };
00180
00181 KonqUndoManager::KonqUndoManager()
00182 : DCOPObject( "KonqUndoManager" )
00183 {
00184 if ( !kapp->dcopClient()->isAttached() )
00185 kapp->dcopClient()->attach();
00186
00187 d = new KonqUndoManagerPrivate;
00188 d->m_syncronized = initializeFromKDesky();
00189 d->m_lock = false;
00190 d->m_currentJob = 0;
00191 }
00192
00193 KonqUndoManager::~KonqUndoManager()
00194 {
00195 delete d;
00196 }
00197
00198 void KonqUndoManager::incRef()
00199 {
00200 s_refCnt++;
00201 }
00202
00203 void KonqUndoManager::decRef()
00204 {
00205 s_refCnt--;
00206 if ( s_refCnt == 0 && s_self )
00207 {
00208 delete s_self;
00209 s_self = 0;
00210 }
00211 }
00212
00213 KonqUndoManager *KonqUndoManager::self()
00214 {
00215 if ( !s_self )
00216 {
00217 if ( s_refCnt == 0 )
00218 s_refCnt++;
00219 s_self = new KonqUndoManager;
00220 }
00221 return s_self;
00222 }
00223
00224 void KonqUndoManager::addCommand( const KonqCommand &cmd )
00225 {
00226 broadcastPush( cmd );
00227 }
00228
00229 bool KonqUndoManager::undoAvailable() const
00230 {
00231 return ( d->m_commands.count() > 0 ) && !d->m_lock;
00232 }
00233
00234 QString KonqUndoManager::undoText() const
00235 {
00236 if ( d->m_commands.count() == 0 )
00237 return i18n( "Und&o" );
00238
00239 KonqCommand::Type t = d->m_commands.top().m_type;
00240 if ( t == KonqCommand::COPY )
00241 return i18n( "Und&o: Copy" );
00242 else if ( t == KonqCommand::LINK )
00243 return i18n( "Und&o: Link" );
00244 else if ( t == KonqCommand::MOVE )
00245 return i18n( "Und&o: Move" );
00246 else if ( t == KonqCommand::MKDIR )
00247 return i18n( "Und&o: Create Folder" );
00248 else
00249 assert( false );
00250
00251 return QString::null;
00252 }
00253
00254 void KonqUndoManager::undo()
00255 {
00256 KonqCommand cmd = d->m_commands.top();
00257 broadcastPop();
00258 broadcastLock();
00259
00260 assert( cmd.m_valid );
00261
00262 d->m_current = cmd;
00263 d->m_dirCleanupStack.clear();
00264 d->m_dirStack.clear();
00265
00266 d->m_undoState = MOVINGFILES;
00267 kdDebug(1203) << "KonqUndoManager::undo MOVINGFILES" << endl;
00268
00269 QValueList<KonqBasicOperation>::Iterator it = d->m_current.m_opStack.begin();
00270 QValueList<KonqBasicOperation>::Iterator end = d->m_current.m_opStack.end();
00271 while ( it != end )
00272 {
00273 if ( d->m_current.m_type == KonqCommand::MOVE && (*it).m_src.path(1) == KGlobalSettings::trashPath())
00274 {
00275 kdDebug(1203) << "Update trash path" <<(*it).m_dst.path()<< endl;
00276 KConfig *globalConfig = KGlobal::config();
00277 KConfigGroupSaver cgs( globalConfig, "Paths" );
00278 globalConfig->writeEntry("Trash" , (*it).m_dst.path(), true, true );
00279 globalConfig->sync();
00280 KIPC::sendMessageAll(KIPC::SettingsChanged, KApplication::SETTINGS_PATHS);
00281 }
00282
00283 if ( (*it).m_directory && !(*it).m_renamed )
00284 {
00285 d->m_dirStack.push( (*it).m_src );
00286 d->m_dirCleanupStack.prepend( (*it).m_dst );
00287 it = d->m_current.m_opStack.remove( it );
00288 d->m_undoState = MAKINGDIRS;
00289 kdDebug(1203) << "KonqUndoManager::undo MAKINGDIRS" << endl;
00290 }
00291 else if ( (*it).m_link )
00292 {
00293 if ( !d->m_fileCleanupStack.contains( (*it).m_dst ) )
00294 d->m_fileCleanupStack.prepend( (*it).m_dst );
00295
00296 if ( d->m_current.m_type != KonqCommand::MOVE )
00297 it = d->m_current.m_opStack.remove( it );
00298 else
00299 ++it;
00300 }
00301 else
00302 ++it;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 if ( d->m_current.m_type != KonqCommand::MOVE )
00321 d->m_dirStack.clear();
00322
00323 d->m_undoJob = new KonqUndoJob;
00324 d->m_uiserverJobId = d->m_undoJob->progressId();
00325 undoStep();
00326 }
00327
00328 void KonqUndoManager::stopUndo( bool step )
00329 {
00330 d->m_current.m_opStack.clear();
00331 d->m_dirCleanupStack.clear();
00332 d->m_fileCleanupStack.clear();
00333 d->m_undoState = REMOVINGDIRS;
00334 d->m_undoJob = 0;
00335
00336 if ( d->m_currentJob )
00337 d->m_currentJob->kill( true );
00338
00339 d->m_currentJob = 0;
00340
00341 if ( step )
00342 undoStep();
00343 }
00344
00345 void KonqUndoManager::slotResult( KIO::Job *job )
00346 {
00347 d->m_uiserver->jobFinished( d->m_uiserverJobId );
00348 if ( job->error() )
00349 {
00350 job->showErrorDialog( 0L );
00351 d->m_currentJob = 0;
00352 stopUndo( false );
00353 if ( d->m_undoJob )
00354 {
00355 delete d->m_undoJob;
00356 d->m_undoJob = 0;
00357 }
00358 }
00359
00360 undoStep();
00361 }
00362
00363 void KonqUndoManager::undoStep()
00364 {
00365 d->m_currentJob = 0;
00366
00367 if ( d->m_undoState == MAKINGDIRS )
00368 undoMakingDirectories();
00369
00370 if ( d->m_undoState == MOVINGFILES )
00371 undoMovingFiles();
00372
00373 if ( d->m_undoState == REMOVINGFILES )
00374 undoRemovingFiles();
00375
00376 if ( d->m_undoState == REMOVINGDIRS )
00377 undoRemovingDirectories();
00378
00379 if ( d->m_currentJob )
00380 connect( d->m_currentJob, SIGNAL( result( KIO::Job * ) ),
00381 this, SLOT( slotResult( KIO::Job * ) ) );
00382 }
00383
00384 void KonqUndoManager::undoMakingDirectories()
00385 {
00386 if ( !d->m_dirStack.isEmpty() ) {
00387 KURL dir = d->m_dirStack.pop();
00388 kdDebug(1203) << "KonqUndoManager::undoStep creatingDir " << dir.prettyURL() << endl;
00389 d->m_currentJob = KIO::mkdir( dir );
00390 d->m_uiserver->creatingDir( d->m_uiserverJobId, dir );
00391 }
00392 else
00393 d->m_undoState = MOVINGFILES;
00394 }
00395
00396 void KonqUndoManager::undoMovingFiles()
00397 {
00398 if ( !d->m_current.m_opStack.isEmpty() )
00399 {
00400 KonqBasicOperation op = d->m_current.m_opStack.pop();
00401
00402 assert( op.m_valid );
00403 if ( op.m_directory )
00404 {
00405 if ( op.m_renamed )
00406 {
00407 kdDebug(1203) << "KonqUndoManager::undoStep rename " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
00408 d->m_currentJob = KIO::rename( op.m_dst, op.m_src, false );
00409 d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
00410 }
00411 else
00412 assert( 0 );
00413 }
00414 else if ( op.m_link )
00415 {
00416 kdDebug(1203) << "KonqUndoManager::undoStep symlink " << op.m_target << " " << op.m_src.prettyURL() << endl;
00417 d->m_currentJob = KIO::symlink( op.m_target, op.m_src, true, false );
00418 }
00419 else if ( d->m_current.m_type == KonqCommand::COPY )
00420 {
00421 kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << op.m_dst.prettyURL() << endl;
00422 d->m_currentJob = KIO::file_delete( op.m_dst );
00423 d->m_uiserver->deleting( d->m_uiserverJobId, op.m_dst );
00424 }
00425 else
00426 {
00427 kdDebug(1203) << "KonqUndoManager::undoStep file_move " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
00428 d->m_currentJob = KIO::file_move( op.m_dst, op.m_src, -1, true );
00429 d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
00430 }
00431 }
00432 else
00433 d->m_undoState = REMOVINGFILES;
00434 }
00435
00436 void KonqUndoManager::undoRemovingFiles()
00437 {
00438 kdDebug(1203) << "KonqUndoManager::undoStep REMOVINGFILES" << endl;
00439 if ( !d->m_fileCleanupStack.isEmpty() )
00440 {
00441 KURL file = d->m_fileCleanupStack.pop();
00442 kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << file.prettyURL() << endl;
00443 d->m_currentJob = KIO::file_delete( file );
00444 d->m_uiserver->deleting( d->m_uiserverJobId, file );
00445 }
00446 else
00447 {
00448 d->m_undoState = REMOVINGDIRS;
00449
00450 if ( d->m_dirCleanupStack.isEmpty() && d->m_current.m_type == KonqCommand::MKDIR )
00451 d->m_dirCleanupStack << d->m_current.m_dst;
00452 }
00453 }
00454
00455 void KonqUndoManager::undoRemovingDirectories()
00456 {
00457 if ( !d->m_dirCleanupStack.isEmpty() )
00458 {
00459 KURL dir = d->m_dirCleanupStack.pop();
00460 kdDebug(1203) << "KonqUndoManager::undoStep rmdir " << dir.prettyURL() << endl;
00461 d->m_currentJob = KIO::rmdir( dir );
00462 d->m_uiserver->deleting( d->m_uiserverJobId, dir );
00463 }
00464 else
00465 {
00466 d->m_current.m_valid = false;
00467 d->m_currentJob = 0;
00468 if ( d->m_undoJob )
00469 {
00470 kdDebug(1203) << "KonqUndoManager::undoStep deleting undojob" << endl;
00471 d->m_uiserver->jobFinished( d->m_uiserverJobId );
00472 delete d->m_undoJob;
00473 d->m_undoJob = 0;
00474 }
00475 broadcastUnlock();
00476 }
00477 }
00478
00479 void KonqUndoManager::push( const KonqCommand &cmd )
00480 {
00481 d->m_commands.push( cmd );
00482 emit undoAvailable( true );
00483 emit undoTextChanged( undoText() );
00484 }
00485
00486 void KonqUndoManager::pop()
00487 {
00488 d->m_commands.pop();
00489 emit undoAvailable( undoAvailable() );
00490 emit undoTextChanged( undoText() );
00491 }
00492
00493 void KonqUndoManager::lock()
00494 {
00495
00496 d->m_lock = true;
00497 emit undoAvailable( undoAvailable() );
00498 }
00499
00500 void KonqUndoManager::unlock()
00501 {
00502
00503 d->m_lock = false;
00504 emit undoAvailable( undoAvailable() );
00505 }
00506
00507 KonqCommand::Stack KonqUndoManager::get() const
00508 {
00509 return d->m_commands;
00510 }
00511
00512 void KonqUndoManager::broadcastPush( const KonqCommand &cmd )
00513 {
00514 if ( !d->m_syncronized )
00515 {
00516 push( cmd );
00517 return;
00518 }
00519
00520 DCOPRef( "kdesktop", "KonqUndoManager" ).send( "push", cmd );
00521 DCOPRef( "konqueror*", "KonqUndoManager" ).send( "push", cmd );
00522 }
00523
00524 void KonqUndoManager::broadcastPop()
00525 {
00526 if ( !d->m_syncronized )
00527 {
00528 pop();
00529 return;
00530 }
00531 DCOPRef( "kdesktop", "KonqUndoManager" ).send( "pop" );
00532 DCOPRef( "konqueror*", "KonqUndoManager" ).send( "pop" );
00533 }
00534
00535 void KonqUndoManager::broadcastLock()
00536 {
00537
00538
00539 if ( !d->m_syncronized )
00540 {
00541 lock();
00542 return;
00543 }
00544 DCOPRef( "kdesktop", "KonqUndoManager" ).send( "lock" );
00545 DCOPRef( "konqueror*", "KonqUndoManager" ).send( "lock" );
00546 }
00547
00548 void KonqUndoManager::broadcastUnlock()
00549 {
00550
00551
00552 if ( !d->m_syncronized )
00553 {
00554 unlock();
00555 return;
00556 }
00557 DCOPRef( "kdesktop", "KonqUndoManager" ).send( "unlock" );
00558 DCOPRef( "konqueror*", "KonqUndoManager" ).send( "unlock" );
00559 }
00560
00561 bool KonqUndoManager::initializeFromKDesky()
00562 {
00563
00564
00565
00566
00567
00568
00569
00570 return false;
00571
00572 DCOPClient *client = kapp->dcopClient();
00573
00574 if ( client->appId() == "kdesktop" )
00575 return true;
00576
00577 if ( !client->isApplicationRegistered( "kdesktop" ) )
00578 return false;
00579
00580 d->m_commands = DCOPRef( "kdesktop", "KonqUndoManager" ).call( "get" );
00581 return true;
00582 }
00583
00584 QDataStream &operator<<( QDataStream &stream, const KonqBasicOperation &op )
00585 {
00586 stream << op.m_valid << op.m_directory << op.m_renamed << op.m_link
00587 << op.m_src << op.m_dst << op.m_target;
00588 return stream;
00589 }
00590 QDataStream &operator>>( QDataStream &stream, KonqBasicOperation &op )
00591 {
00592 stream >> op.m_valid >> op.m_directory >> op.m_renamed >> op.m_link
00593 >> op.m_src >> op.m_dst >> op.m_target;
00594 return stream;
00595 }
00596
00597 QDataStream &operator<<( QDataStream &stream, const KonqCommand &cmd )
00598 {
00599 stream << cmd.m_valid << (Q_INT8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst;
00600 return stream;
00601 }
00602
00603 QDataStream &operator>>( QDataStream &stream, KonqCommand &cmd )
00604 {
00605 Q_INT8 type;
00606 stream >> cmd.m_valid >> type >> cmd.m_opStack >> cmd.m_src >> cmd.m_dst;
00607 cmd.m_type = static_cast<KonqCommand::Type>( type );
00608 return stream;
00609 }
00610
00611 #include "konq_undo.moc"
This file is part of the documentation for libkonq Library Version 3.3.0.