|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "konq_undo.h"
|
|
|
|
|
|
|
|
#undef Always
|
|
|
|
|
|
|
|
#include <kio/uiserver_stub.h>
|
|
|
|
#include "konq_operations.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <dcopclient.h>
|
|
|
|
#include <dcopref.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kdatastream.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kglobalsettings.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kipc.h>
|
|
|
|
|
|
|
|
#include <kio/job.h>
|
|
|
|
#include <kdirnotify_stub.h>
|
|
|
|
|
|
|
|
inline const char *dcopTypeName( const KonqCommand & ) { return "KonqCommand"; }
|
|
|
|
inline const char *dcopTypeName( const KonqCommand::Stack & ) { return "KonqCommand::Stack"; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* checklist:
|
|
|
|
* copy dir -> overwrite -> works
|
|
|
|
* move dir -> overwrite -> works
|
|
|
|
* copy dir -> rename -> works
|
|
|
|
* move dir -> rename -> works
|
|
|
|
*
|
|
|
|
* copy dir -> works
|
|
|
|
* move dir -> works
|
|
|
|
*
|
|
|
|
* copy files -> works
|
|
|
|
* move files -> works (TODO: optimize (change FileCopyJob to use the renamed arg for copyingDone)
|
|
|
|
*
|
|
|
|
* copy files -> overwrite -> works
|
|
|
|
* move files -> overwrite -> works
|
|
|
|
*
|
|
|
|
* copy files -> rename -> works
|
|
|
|
* move files -> rename -> works
|
|
|
|
*/
|
|
|
|
|
|
|
|
class KonqUndoJob : public KIO::Job
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
KonqUndoJob() : KIO::Job( true ) { KonqUndoManager::incRef(); };
|
|
|
|
virtual ~KonqUndoJob() { KonqUndoManager::decRef(); }
|
|
|
|
|
|
|
|
virtual void kill( bool q) { KonqUndoManager::self()->stopUndo( true ); KIO::Job::kill( q ); }
|
|
|
|
};
|
|
|
|
|
|
|
|
class KonqCommandRecorder::KonqCommandRecorderPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
KonqCommandRecorderPrivate()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
~KonqCommandRecorderPrivate()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqCommand m_cmd;
|
|
|
|
};
|
|
|
|
|
|
|
|
KonqCommandRecorder::KonqCommandRecorder( KonqCommand::Type op, const KURL::List &src, const KURL &dst, KIO::Job *job )
|
|
|
|
: TQObject( job, "konqcmdrecorder" )
|
|
|
|
{
|
|
|
|
d = new KonqCommandRecorderPrivate;
|
|
|
|
d->m_cmd.m_type = op;
|
|
|
|
d->m_cmd.m_valid = true;
|
|
|
|
d->m_cmd.m_src = src;
|
|
|
|
d->m_cmd.m_dst = dst;
|
|
|
|
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
|
|
this, TQT_SLOT( slotResult( KIO::Job * ) ) );
|
|
|
|
|
|
|
|
if ( op != KonqCommand::MKDIR ) {
|
|
|
|
connect( job, TQT_SIGNAL( copyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ),
|
|
|
|
this, TQT_SLOT( slotCopyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ) );
|
|
|
|
connect( job, TQT_SIGNAL( copyingLinkDone( KIO::Job *, const KURL &, const TQString &, const KURL & ) ),
|
|
|
|
this, TQT_SLOT( slotCopyingLinkDone( KIO::Job *, const KURL &, const TQString &, const KURL & ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqUndoManager::incRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqCommandRecorder::~KonqCommandRecorder()
|
|
|
|
{
|
|
|
|
KonqUndoManager::decRef();
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqCommandRecorder::slotResult( KIO::Job *job )
|
|
|
|
{
|
|
|
|
if ( job->error() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
KonqUndoManager::self()->addCommand( d->m_cmd );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqCommandRecorder::slotCopyingDone( KIO::Job *job, const KURL &from, const KURL &to, bool directory, bool renamed )
|
|
|
|
{
|
|
|
|
KonqBasicOperation op;
|
|
|
|
op.m_valid = true;
|
|
|
|
op.m_directory = directory;
|
|
|
|
op.m_renamed = renamed;
|
|
|
|
op.m_src = from;
|
|
|
|
op.m_dst = to;
|
|
|
|
op.m_link = false;
|
|
|
|
|
|
|
|
if ( d->m_cmd.m_type == KonqCommand::TRASH )
|
|
|
|
{
|
|
|
|
Q_ASSERT( from.isLocalFile() );
|
|
|
|
Q_ASSERT( to.protocol() == "trash" );
|
|
|
|
TQMap<TQString, TQString> metaData = job->metaData();
|
|
|
|
TQMap<TQString, TQString>::ConstIterator it = metaData.find( "trashURL-" + from.path() );
|
|
|
|
if ( it != metaData.end() ) {
|
|
|
|
// Update URL
|
|
|
|
op.m_dst = it.data();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->m_cmd.m_opStack.prepend( op );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqCommandRecorder::slotCopyingLinkDone( KIO::Job *, const KURL &from, const TQString &target, const KURL &to )
|
|
|
|
{
|
|
|
|
KonqBasicOperation op;
|
|
|
|
op.m_valid = true;
|
|
|
|
op.m_directory = false;
|
|
|
|
op.m_renamed = false;
|
|
|
|
op.m_src = from;
|
|
|
|
op.m_target = target;
|
|
|
|
op.m_dst = to;
|
|
|
|
op.m_link = true;
|
|
|
|
d->m_cmd.m_opStack.prepend( op );
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqUndoManager *KonqUndoManager::s_self = 0;
|
|
|
|
unsigned long KonqUndoManager::s_refCnt = 0;
|
|
|
|
|
|
|
|
class KonqUndoManager::KonqUndoManagerPrivate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
KonqUndoManagerPrivate()
|
|
|
|
{
|
|
|
|
m_uiserver = new UIServer_stub( "kio_uiserver", "UIServer" );
|
|
|
|
m_undoJob = 0;
|
|
|
|
}
|
|
|
|
~KonqUndoManagerPrivate()
|
|
|
|
{
|
|
|
|
delete m_uiserver;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool m_syncronized;
|
|
|
|
|
|
|
|
KonqCommand::Stack m_commands;
|
|
|
|
|
|
|
|
KonqCommand m_current;
|
|
|
|
KIO::Job *m_currentJob;
|
|
|
|
UndoState m_undoState;
|
|
|
|
TQValueStack<KURL> m_dirStack;
|
|
|
|
TQValueStack<KURL> m_dirCleanupStack;
|
|
|
|
TQValueStack<KURL> m_fileCleanupStack;
|
|
|
|
TQValueList<KURL> m_dirsToUpdate;
|
|
|
|
|
|
|
|
bool m_lock;
|
|
|
|
|
|
|
|
UIServer_stub *m_uiserver;
|
|
|
|
int m_uiserverJobId;
|
|
|
|
|
|
|
|
KonqUndoJob *m_undoJob;
|
|
|
|
};
|
|
|
|
|
|
|
|
KonqUndoManager::KonqUndoManager()
|
|
|
|
: DCOPObject( "KonqUndoManager" )
|
|
|
|
{
|
|
|
|
if ( !kapp->dcopClient()->isAttached() )
|
|
|
|
kapp->dcopClient()->attach();
|
|
|
|
|
|
|
|
d = new KonqUndoManagerPrivate;
|
|
|
|
d->m_syncronized = initializeFromKDesky();
|
|
|
|
d->m_lock = false;
|
|
|
|
d->m_currentJob = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqUndoManager::~KonqUndoManager()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::incRef()
|
|
|
|
{
|
|
|
|
s_refCnt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::decRef()
|
|
|
|
{
|
|
|
|
s_refCnt--;
|
|
|
|
if ( s_refCnt == 0 && s_self )
|
|
|
|
{
|
|
|
|
delete s_self;
|
|
|
|
s_self = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqUndoManager *KonqUndoManager::self()
|
|
|
|
{
|
|
|
|
if ( !s_self )
|
|
|
|
{
|
|
|
|
if ( s_refCnt == 0 )
|
|
|
|
s_refCnt++; // someone forgot to call incRef
|
|
|
|
s_self = new KonqUndoManager;
|
|
|
|
}
|
|
|
|
return s_self;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::addCommand( const KonqCommand &cmd )
|
|
|
|
{
|
|
|
|
broadcastPush( cmd );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqUndoManager::undoAvailable() const
|
|
|
|
{
|
|
|
|
return ( d->m_commands.count() > 0 ) && !d->m_lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KonqUndoManager::undoText() const
|
|
|
|
{
|
|
|
|
if ( d->m_commands.count() == 0 )
|
|
|
|
return i18n( "Und&o" );
|
|
|
|
|
|
|
|
KonqCommand::Type t = d->m_commands.top().m_type;
|
|
|
|
if ( t == KonqCommand::COPY )
|
|
|
|
return i18n( "Und&o: Copy" );
|
|
|
|
else if ( t == KonqCommand::LINK )
|
|
|
|
return i18n( "Und&o: Link" );
|
|
|
|
else if ( t == KonqCommand::MOVE )
|
|
|
|
return i18n( "Und&o: Move" );
|
|
|
|
else if ( t == KonqCommand::TRASH )
|
|
|
|
return i18n( "Und&o: Trash" );
|
|
|
|
else if ( t == KonqCommand::MKDIR )
|
|
|
|
return i18n( "Und&o: Create Folder" );
|
|
|
|
else
|
|
|
|
assert( false );
|
|
|
|
/* NOTREACHED */
|
|
|
|
return TQString::null;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::undo()
|
|
|
|
{
|
|
|
|
KonqCommand cmd = d->m_commands.top();
|
|
|
|
assert( cmd.m_valid );
|
|
|
|
|
|
|
|
d->m_current = cmd;
|
|
|
|
|
|
|
|
TQValueList<KonqBasicOperation>& opStack = d->m_current.m_opStack;
|
|
|
|
|
|
|
|
// Let's first ask for confirmation if we need to delete any file (#99898)
|
|
|
|
KURL::List fileCleanupStack;
|
|
|
|
TQValueList<KonqBasicOperation>::Iterator it = opStack.begin();
|
|
|
|
for ( ; it != opStack.end() ; ++it ) {
|
|
|
|
if ( !(*it).m_directory && !(*it).m_link && d->m_current.m_type == KonqCommand::COPY ) {
|
|
|
|
fileCleanupStack.append( (*it).m_dst );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !fileCleanupStack.isEmpty() ) {
|
|
|
|
// Because undo can happen with an accidental Ctrl-Z, we want to always confirm.
|
|
|
|
if ( !KonqOperations::askDeleteConfirmation( fileCleanupStack, KonqOperations::DEL,
|
|
|
|
KonqOperations::FORCE_CONFIRMATION,
|
|
|
|
0 /* TODO parent */ ) )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->m_dirCleanupStack.clear();
|
|
|
|
d->m_dirStack.clear();
|
|
|
|
d->m_dirsToUpdate.clear();
|
|
|
|
|
|
|
|
d->m_undoState = MOVINGFILES;
|
|
|
|
|
|
|
|
broadcastPop();
|
|
|
|
broadcastLock();
|
|
|
|
|
|
|
|
it = opStack.begin();
|
|
|
|
TQValueList<KonqBasicOperation>::Iterator end = opStack.end();
|
|
|
|
while ( it != end )
|
|
|
|
{
|
|
|
|
if ( (*it).m_directory && !(*it).m_renamed )
|
|
|
|
{
|
|
|
|
d->m_dirStack.push( (*it).m_src );
|
|
|
|
d->m_dirCleanupStack.prepend( (*it).m_dst );
|
|
|
|
it = d->m_current.m_opStack.remove( it );
|
|
|
|
d->m_undoState = MAKINGDIRS;
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undo MAKINGDIRS" << endl;
|
|
|
|
}
|
|
|
|
else if ( (*it).m_link )
|
|
|
|
{
|
|
|
|
if ( !d->m_fileCleanupStack.contains( (*it).m_dst ) )
|
|
|
|
d->m_fileCleanupStack.prepend( (*it).m_dst );
|
|
|
|
|
|
|
|
if ( d->m_current.m_type != KonqCommand::MOVE )
|
|
|
|
it = d->m_current.m_opStack.remove( it );
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this shouldn't be necessary at all:
|
|
|
|
* 1) the source list may contain files, we don't want to
|
|
|
|
* create those as... directories
|
|
|
|
* 2) all directories that need creation should already be in the
|
|
|
|
* directory stack
|
|
|
|
if ( d->m_undoState == MAKINGDIRS )
|
|
|
|
{
|
|
|
|
KURL::List::ConstIterator it = d->m_current.m_src.begin();
|
|
|
|
KURL::List::ConstIterator end = d->m_current.m_src.end();
|
|
|
|
for (; it != end; ++it )
|
|
|
|
if ( !d->m_dirStack.contains( *it) )
|
|
|
|
d->m_dirStack.push( *it );
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ( d->m_current.m_type != KonqCommand::MOVE )
|
|
|
|
d->m_dirStack.clear();
|
|
|
|
|
|
|
|
d->m_undoJob = new KonqUndoJob;
|
|
|
|
d->m_uiserverJobId = d->m_undoJob->progressId();
|
|
|
|
undoStep();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::stopUndo( bool step )
|
|
|
|
{
|
|
|
|
d->m_current.m_opStack.clear();
|
|
|
|
d->m_dirCleanupStack.clear();
|
|
|
|
d->m_fileCleanupStack.clear();
|
|
|
|
d->m_undoState = REMOVINGDIRS;
|
|
|
|
d->m_undoJob = 0;
|
|
|
|
|
|
|
|
if ( d->m_currentJob )
|
|
|
|
d->m_currentJob->kill( true );
|
|
|
|
|
|
|
|
d->m_currentJob = 0;
|
|
|
|
|
|
|
|
if ( step )
|
|
|
|
undoStep();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::slotResult( KIO::Job *job )
|
|
|
|
{
|
|
|
|
d->m_uiserver->jobFinished( d->m_uiserverJobId );
|
|
|
|
if ( job->error() )
|
|
|
|
{
|
|
|
|
job->showErrorDialog( 0L );
|
|
|
|
d->m_currentJob = 0;
|
|
|
|
stopUndo( false );
|
|
|
|
if ( d->m_undoJob )
|
|
|
|
{
|
|
|
|
delete d->m_undoJob;
|
|
|
|
d->m_undoJob = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
undoStep();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KonqUndoManager::addDirToUpdate( const KURL& url )
|
|
|
|
{
|
|
|
|
if ( d->m_dirsToUpdate.find( url ) == d->m_dirsToUpdate.end() )
|
|
|
|
d->m_dirsToUpdate.prepend( url );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::undoStep()
|
|
|
|
{
|
|
|
|
d->m_currentJob = 0;
|
|
|
|
|
|
|
|
if ( d->m_undoState == MAKINGDIRS )
|
|
|
|
undoMakingDirectories();
|
|
|
|
|
|
|
|
if ( d->m_undoState == MOVINGFILES )
|
|
|
|
undoMovingFiles();
|
|
|
|
|
|
|
|
if ( d->m_undoState == REMOVINGFILES )
|
|
|
|
undoRemovingFiles();
|
|
|
|
|
|
|
|
if ( d->m_undoState == REMOVINGDIRS )
|
|
|
|
undoRemovingDirectories();
|
|
|
|
|
|
|
|
if ( d->m_currentJob )
|
|
|
|
connect( d->m_currentJob, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
|
|
this, TQT_SLOT( slotResult( KIO::Job * ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::undoMakingDirectories()
|
|
|
|
{
|
|
|
|
if ( !d->m_dirStack.isEmpty() ) {
|
|
|
|
KURL dir = d->m_dirStack.pop();
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep creatingDir " << dir.prettyURL() << endl;
|
|
|
|
d->m_currentJob = KIO::mkdir( dir );
|
|
|
|
d->m_uiserver->creatingDir( d->m_uiserverJobId, dir );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
d->m_undoState = MOVINGFILES;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::undoMovingFiles()
|
|
|
|
{
|
|
|
|
if ( !d->m_current.m_opStack.isEmpty() )
|
|
|
|
{
|
|
|
|
KonqBasicOperation op = d->m_current.m_opStack.pop();
|
|
|
|
|
|
|
|
assert( op.m_valid );
|
|
|
|
if ( op.m_directory )
|
|
|
|
{
|
|
|
|
if ( op.m_renamed )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep rename " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
|
|
|
|
d->m_currentJob = KIO::rename( op.m_dst, op.m_src, false );
|
|
|
|
d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
assert( 0 ); // this should not happen!
|
|
|
|
}
|
|
|
|
else if ( op.m_link )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep symlink " << op.m_target << " " << op.m_src.prettyURL() << endl;
|
|
|
|
d->m_currentJob = KIO::symlink( op.m_target, op.m_src, true, false );
|
|
|
|
}
|
|
|
|
else if ( d->m_current.m_type == KonqCommand::COPY )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << op.m_dst.prettyURL() << endl;
|
|
|
|
d->m_currentJob = KIO::file_delete( op.m_dst );
|
|
|
|
d->m_uiserver->deleting( d->m_uiserverJobId, op.m_dst );
|
|
|
|
}
|
|
|
|
else if ( d->m_current.m_type == KonqCommand::MOVE
|
|
|
|
|| d->m_current.m_type == KonqCommand::TRASH )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep file_move " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
|
|
|
|
d->m_currentJob = KIO::file_move( op.m_dst, op.m_src, -1, true );
|
|
|
|
d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
|
|
|
|
}
|
|
|
|
|
|
|
|
// The above KIO jobs are lowlevel, they don't trigger KDirNotify notification
|
|
|
|
// So we need to do it ourselves (but schedule it to the end of the undo, to compress them)
|
|
|
|
KURL url( op.m_dst );
|
|
|
|
url.setPath( url.directory() );
|
|
|
|
addDirToUpdate( url );
|
|
|
|
|
|
|
|
url = op.m_src;
|
|
|
|
url.setPath( url.directory() );
|
|
|
|
addDirToUpdate( url );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
d->m_undoState = REMOVINGFILES;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::undoRemovingFiles()
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep REMOVINGFILES" << endl;
|
|
|
|
if ( !d->m_fileCleanupStack.isEmpty() )
|
|
|
|
{
|
|
|
|
KURL file = d->m_fileCleanupStack.pop();
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << file.prettyURL() << endl;
|
|
|
|
d->m_currentJob = KIO::file_delete( file );
|
|
|
|
d->m_uiserver->deleting( d->m_uiserverJobId, file );
|
|
|
|
|
|
|
|
KURL url( file );
|
|
|
|
url.setPath( url.directory() );
|
|
|
|
addDirToUpdate( url );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->m_undoState = REMOVINGDIRS;
|
|
|
|
|
|
|
|
if ( d->m_dirCleanupStack.isEmpty() && d->m_current.m_type == KonqCommand::MKDIR )
|
|
|
|
d->m_dirCleanupStack << d->m_current.m_dst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::undoRemovingDirectories()
|
|
|
|
{
|
|
|
|
if ( !d->m_dirCleanupStack.isEmpty() )
|
|
|
|
{
|
|
|
|
KURL dir = d->m_dirCleanupStack.pop();
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep rmdir " << dir.prettyURL() << endl;
|
|
|
|
d->m_currentJob = KIO::rmdir( dir );
|
|
|
|
d->m_uiserver->deleting( d->m_uiserverJobId, dir );
|
|
|
|
addDirToUpdate( dir );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->m_current.m_valid = false;
|
|
|
|
d->m_currentJob = 0;
|
|
|
|
if ( d->m_undoJob )
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "KonqUndoManager::undoStep deleting undojob" << endl;
|
|
|
|
d->m_uiserver->jobFinished( d->m_uiserverJobId );
|
|
|
|
delete d->m_undoJob;
|
|
|
|
d->m_undoJob = 0;
|
|
|
|
}
|
|
|
|
KDirNotify_stub allDirNotify( "*", "KDirNotify*" );
|
|
|
|
TQValueList<KURL>::ConstIterator it = d->m_dirsToUpdate.begin();
|
|
|
|
for( ; it != d->m_dirsToUpdate.end(); ++it ) {
|
|
|
|
kdDebug() << "Notifying FilesAdded for " << *it << endl;
|
|
|
|
allDirNotify.FilesAdded( *it );
|
|
|
|
}
|
|
|
|
broadcastUnlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::push( const KonqCommand &cmd )
|
|
|
|
{
|
|
|
|
d->m_commands.push( cmd );
|
|
|
|
emit undoAvailable( true );
|
|
|
|
emit undoTextChanged( undoText() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::pop()
|
|
|
|
{
|
|
|
|
d->m_commands.pop();
|
|
|
|
emit undoAvailable( undoAvailable() );
|
|
|
|
emit undoTextChanged( undoText() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::lock()
|
|
|
|
{
|
|
|
|
// assert( !d->m_lock );
|
|
|
|
d->m_lock = true;
|
|
|
|
emit undoAvailable( undoAvailable() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::unlock()
|
|
|
|
{
|
|
|
|
// assert( d->m_lock );
|
|
|
|
d->m_lock = false;
|
|
|
|
emit undoAvailable( undoAvailable() );
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqCommand::Stack KonqUndoManager::get() const
|
|
|
|
{
|
|
|
|
return d->m_commands;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::broadcastPush( const KonqCommand &cmd )
|
|
|
|
{
|
|
|
|
if ( !d->m_syncronized )
|
|
|
|
{
|
|
|
|
push( cmd );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DCOPRef( "kdesktop", "KonqUndoManager" ).send( "push", cmd );
|
|
|
|
DCOPRef( "konqueror*", "KonqUndoManager" ).send( "push", cmd );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::broadcastPop()
|
|
|
|
{
|
|
|
|
if ( !d->m_syncronized )
|
|
|
|
{
|
|
|
|
pop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DCOPRef( "kdesktop", "KonqUndoManager" ).send( "pop" );
|
|
|
|
DCOPRef( "konqueror*", "KonqUndoManager" ).send( "pop" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::broadcastLock()
|
|
|
|
{
|
|
|
|
// assert( !d->m_lock );
|
|
|
|
|
|
|
|
if ( !d->m_syncronized )
|
|
|
|
{
|
|
|
|
lock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DCOPRef( "kdesktop", "KonqUndoManager" ).send( "lock" );
|
|
|
|
DCOPRef( "konqueror*", "KonqUndoManager" ).send( "lock" );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqUndoManager::broadcastUnlock()
|
|
|
|
{
|
|
|
|
// assert( d->m_lock );
|
|
|
|
|
|
|
|
if ( !d->m_syncronized )
|
|
|
|
{
|
|
|
|
unlock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DCOPRef( "kdesktop", "KonqUndoManager" ).send( "unlock" );
|
|
|
|
DCOPRef( "konqueror*", "KonqUndoManager" ).send( "unlock" );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqUndoManager::initializeFromKDesky()
|
|
|
|
{
|
|
|
|
// ### workaround for dcop problem and upcoming 2.1 release:
|
|
|
|
// in case of huge io operations the amount of data sent over
|
|
|
|
// dcop (containing undo information broadcasted for global undo
|
|
|
|
// to all konqueror instances) can easily exceed the 64kb limit
|
|
|
|
// of dcop. In order not to run into trouble we disable global
|
|
|
|
// undo for now! (Simon)
|
|
|
|
// ### FIXME: post 2.1
|
|
|
|
return false;
|
|
|
|
|
|
|
|
DCOPClient *client = kapp->dcopClient();
|
|
|
|
|
|
|
|
if ( client->appId() == "kdesktop" ) // we are master :)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if ( !client->isApplicationRegistered( "kdesktop" ) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
d->m_commands = DCOPRef( "kdesktop", "KonqUndoManager" ).call( "get" );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDataStream &operator<<( TQDataStream &stream, const KonqBasicOperation &op )
|
|
|
|
{
|
|
|
|
stream << op.m_valid << op.m_directory << op.m_renamed << op.m_link
|
|
|
|
<< op.m_src << op.m_dst << op.m_target;
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
TQDataStream &operator>>( TQDataStream &stream, KonqBasicOperation &op )
|
|
|
|
{
|
|
|
|
stream >> op.m_valid >> op.m_directory >> op.m_renamed >> op.m_link
|
|
|
|
>> op.m_src >> op.m_dst >> op.m_target;
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDataStream &operator<<( TQDataStream &stream, const KonqCommand &cmd )
|
|
|
|
{
|
|
|
|
stream << cmd.m_valid << (Q_INT8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst;
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDataStream &operator>>( TQDataStream &stream, KonqCommand &cmd )
|
|
|
|
{
|
|
|
|
Q_INT8 type;
|
|
|
|
stream >> cmd.m_valid >> type >> cmd.m_opStack >> cmd.m_src >> cmd.m_dst;
|
|
|
|
cmd.m_type = static_cast<KonqCommand::Type>( type );
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "konq_undo.moc"
|