• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • @topname@
  • Sitemap
  • Contact Us
 

libkonq

konq_undo.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2000 Simon Hausmann <hausmann@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "konq_undo.h"
00021 
00022 #undef Always
00023 
00024 #include <kio/uiserver_stub.h>
00025 #include "konq_operations.h"
00026 
00027 #include <assert.h>
00028 
00029 #include <dcopclient.h>
00030 #include <dcopref.h>
00031 
00032 #include <kapplication.h>
00033 #include <kdatastream.h>
00034 #include <kdebug.h>
00035 #include <klocale.h>
00036 #include <kglobalsettings.h>
00037 #include <kconfig.h>
00038 #include <kipc.h>
00039 
00040 #include <kio/job.h>
00041 #include <kdirnotify_stub.h>
00042 
00043 inline const char *dcopTypeName( const KonqCommand & ) { return "KonqCommand"; }
00044 inline const char *dcopTypeName( const KonqCommand::Stack & ) { return "KonqCommand::Stack"; }
00045 
00066 class KonqUndoJob : public KIO::Job
00067 {
00068 public:
00069     KonqUndoJob() : KIO::Job( true ) { KonqUndoManager::incRef(); };
00070     virtual ~KonqUndoJob() { KonqUndoManager::decRef(); }
00071 
00072     virtual void kill( bool q) { KonqUndoManager::self()->stopUndo( true ); KIO::Job::kill( q ); }
00073 };
00074 
00075 class KonqCommandRecorder::KonqCommandRecorderPrivate
00076 {
00077 public:
00078   KonqCommandRecorderPrivate()
00079   {
00080   }
00081   ~KonqCommandRecorderPrivate()
00082   {
00083   }
00084 
00085   KonqCommand m_cmd;
00086 };
00087 
00088 KonqCommandRecorder::KonqCommandRecorder( KonqCommand::Type op, const KURL::List &src, const KURL &dst, KIO::Job *job )
00089   : QObject( job, "konqcmdrecorder" )
00090 {
00091   d = new KonqCommandRecorderPrivate;
00092   d->m_cmd.m_type = op;
00093   d->m_cmd.m_valid = true;
00094   d->m_cmd.m_src = src;
00095   d->m_cmd.m_dst = dst;
00096   connect( job, SIGNAL( result( KIO::Job * ) ),
00097            this, SLOT( slotResult( KIO::Job * ) ) );
00098 
00099   if ( op != KonqCommand::MKDIR ) {
00100       connect( job, SIGNAL( copyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ),
00101                this, SLOT( slotCopyingDone( KIO::Job *, const KURL &, const KURL &, bool, bool ) ) );
00102       connect( job, SIGNAL( copyingLinkDone( KIO::Job *, const KURL &, const QString &, const KURL & ) ),
00103                this, SLOT( slotCopyingLinkDone( KIO::Job *, const KURL &, const QString &, const KURL & ) ) );
00104   }
00105 
00106   KonqUndoManager::incRef();
00107 }
00108 
00109 KonqCommandRecorder::~KonqCommandRecorder()
00110 {
00111   KonqUndoManager::decRef();
00112   delete d;
00113 }
00114 
00115 void KonqCommandRecorder::slotResult( KIO::Job *job )
00116 {
00117   if ( job->error() )
00118     return;
00119 
00120   KonqUndoManager::self()->addCommand( d->m_cmd );
00121 }
00122 
00123 void KonqCommandRecorder::slotCopyingDone( KIO::Job *job, const KURL &from, const KURL &to, bool directory, bool renamed )
00124 {
00125   KonqBasicOperation op;
00126   op.m_valid = true;
00127   op.m_directory = directory;
00128   op.m_renamed = renamed;
00129   op.m_src = from;
00130   op.m_dst = to;
00131   op.m_link = false;
00132 
00133   if ( d->m_cmd.m_type == KonqCommand::TRASH )
00134   {
00135       Q_ASSERT( from.isLocalFile() );
00136       Q_ASSERT( to.protocol() == "trash" );
00137       QMap<QString, QString> metaData = job->metaData();
00138       QMap<QString, QString>::ConstIterator it = metaData.find( "trashURL-" + from.path() );
00139       if ( it != metaData.end() ) {
00140           // Update URL
00141           op.m_dst = it.data();
00142       }
00143   }
00144 
00145   d->m_cmd.m_opStack.prepend( op );
00146 }
00147 
00148 void KonqCommandRecorder::slotCopyingLinkDone( KIO::Job *, const KURL &from, const QString &target, const KURL &to )
00149 {
00150   KonqBasicOperation op;
00151   op.m_valid = true;
00152   op.m_directory = false;
00153   op.m_renamed = false;
00154   op.m_src = from;
00155   op.m_target = target;
00156   op.m_dst = to;
00157   op.m_link = true;
00158   d->m_cmd.m_opStack.prepend( op );
00159 }
00160 
00161 KonqUndoManager *KonqUndoManager::s_self = 0;
00162 unsigned long KonqUndoManager::s_refCnt = 0;
00163 
00164 class KonqUndoManager::KonqUndoManagerPrivate
00165 {
00166 public:
00167   KonqUndoManagerPrivate()
00168   {
00169       m_uiserver = new UIServer_stub( "kio_uiserver", "UIServer" );
00170       m_undoJob = 0;
00171   }
00172   ~KonqUndoManagerPrivate()
00173   {
00174       delete m_uiserver;
00175   }
00176 
00177   bool m_syncronized;
00178 
00179   KonqCommand::Stack m_commands;
00180 
00181   KonqCommand m_current;
00182   KIO::Job *m_currentJob;
00183   UndoState m_undoState;
00184   QValueStack<KURL> m_dirStack;
00185   QValueStack<KURL> m_dirCleanupStack;
00186   QValueStack<KURL> m_fileCleanupStack;
00187   QValueList<KURL> m_dirsToUpdate;
00188 
00189   bool m_lock;
00190 
00191   UIServer_stub *m_uiserver;
00192   int m_uiserverJobId;
00193 
00194   KonqUndoJob *m_undoJob;
00195 };
00196 
00197 KonqUndoManager::KonqUndoManager()
00198 : DCOPObject( "KonqUndoManager" )
00199 {
00200   if ( !kapp->dcopClient()->isAttached() )
00201       kapp->dcopClient()->attach();
00202 
00203   d = new KonqUndoManagerPrivate;
00204   d->m_syncronized = initializeFromKDesky();
00205   d->m_lock = false;
00206   d->m_currentJob = 0;
00207 }
00208 
00209 KonqUndoManager::~KonqUndoManager()
00210 {
00211   delete d;
00212 }
00213 
00214 void KonqUndoManager::incRef()
00215 {
00216   s_refCnt++;
00217 }
00218 
00219 void KonqUndoManager::decRef()
00220 {
00221   s_refCnt--;
00222   if ( s_refCnt == 0 && s_self )
00223   {
00224     delete s_self;
00225     s_self = 0;
00226   }
00227 }
00228 
00229 KonqUndoManager *KonqUndoManager::self()
00230 {
00231   if ( !s_self )
00232   {
00233     if ( s_refCnt == 0 )
00234       s_refCnt++; // someone forgot to call incRef
00235     s_self = new KonqUndoManager;
00236   }
00237   return s_self;
00238 }
00239 
00240 void KonqUndoManager::addCommand( const KonqCommand &cmd )
00241 {
00242   broadcastPush( cmd );
00243 }
00244 
00245 bool KonqUndoManager::undoAvailable() const
00246 {
00247   return ( d->m_commands.count() > 0 ) && !d->m_lock;
00248 }
00249 
00250 QString KonqUndoManager::undoText() const
00251 {
00252   if ( d->m_commands.count() == 0 )
00253     return i18n( "Und&o" );
00254 
00255   KonqCommand::Type t = d->m_commands.top().m_type;
00256   if ( t == KonqCommand::COPY )
00257     return i18n( "Und&o: Copy" );
00258   else if ( t == KonqCommand::LINK )
00259     return i18n( "Und&o: Link" );
00260   else if ( t == KonqCommand::MOVE )
00261     return i18n( "Und&o: Move" );
00262   else if ( t == KonqCommand::TRASH )
00263     return i18n( "Und&o: Trash" );
00264   else if ( t == KonqCommand::MKDIR )
00265     return i18n( "Und&o: Create Folder" );
00266   else
00267     assert( false );
00268   /* NOTREACHED */
00269   return QString::null;
00270 }
00271 
00272 void KonqUndoManager::undo()
00273 {
00274   KonqCommand cmd = d->m_commands.top();
00275   assert( cmd.m_valid );
00276 
00277   d->m_current = cmd;
00278 
00279   QValueList<KonqBasicOperation>& opStack = d->m_current.m_opStack;
00280 
00281   // Let's first ask for confirmation if we need to delete any file (#99898)
00282   KURL::List fileCleanupStack;
00283   QValueList<KonqBasicOperation>::Iterator it = opStack.begin();
00284   for ( ; it != opStack.end() ; ++it ) {
00285       if ( !(*it).m_directory && !(*it).m_link && d->m_current.m_type == KonqCommand::COPY ) {
00286           fileCleanupStack.append( (*it).m_dst );
00287       }
00288   }
00289   if ( !fileCleanupStack.isEmpty() ) {
00290       // Because undo can happen with an accidental Ctrl-Z, we want to always confirm.
00291       if ( !KonqOperations::askDeleteConfirmation( fileCleanupStack, KonqOperations::DEL,
00292                                                    KonqOperations::FORCE_CONFIRMATION,
00293                                                    0 /* TODO parent */ ) )
00294           return;
00295   }
00296 
00297   d->m_dirCleanupStack.clear();
00298   d->m_dirStack.clear();
00299   d->m_dirsToUpdate.clear();
00300 
00301   d->m_undoState = MOVINGFILES;
00302 
00303   broadcastPop();
00304   broadcastLock();
00305 
00306   it = opStack.begin();
00307   QValueList<KonqBasicOperation>::Iterator end = opStack.end();
00308   while ( it != end )
00309   {
00310     if ( (*it).m_directory && !(*it).m_renamed )
00311     {
00312       d->m_dirStack.push( (*it).m_src );
00313       d->m_dirCleanupStack.prepend( (*it).m_dst );
00314       it = d->m_current.m_opStack.remove( it );
00315       d->m_undoState = MAKINGDIRS;
00316       kdDebug(1203) << "KonqUndoManager::undo MAKINGDIRS" << endl;
00317     }
00318     else if ( (*it).m_link )
00319     {
00320       if ( !d->m_fileCleanupStack.contains( (*it).m_dst ) )
00321         d->m_fileCleanupStack.prepend( (*it).m_dst );
00322 
00323       if ( d->m_current.m_type != KonqCommand::MOVE )
00324         it = d->m_current.m_opStack.remove( it );
00325       else
00326         ++it;
00327     }
00328     else
00329       ++it;
00330   }
00331 
00332   /* this shouldn't be necessary at all:
00333    * 1) the source list may contain files, we don't want to
00334    *    create those as... directories
00335    * 2) all directories that need creation should already be in the
00336    *    directory stack
00337   if ( d->m_undoState == MAKINGDIRS )
00338   {
00339     KURL::List::ConstIterator it = d->m_current.m_src.begin();
00340     KURL::List::ConstIterator end = d->m_current.m_src.end();
00341     for (; it != end; ++it )
00342       if ( !d->m_dirStack.contains( *it) )
00343         d->m_dirStack.push( *it );
00344   }
00345   */
00346 
00347   if ( d->m_current.m_type != KonqCommand::MOVE )
00348     d->m_dirStack.clear();
00349 
00350   d->m_undoJob = new KonqUndoJob;
00351   d->m_uiserverJobId = d->m_undoJob->progressId();
00352   undoStep();
00353 }
00354 
00355 void KonqUndoManager::stopUndo( bool step )
00356 {
00357     d->m_current.m_opStack.clear();
00358     d->m_dirCleanupStack.clear();
00359     d->m_fileCleanupStack.clear();
00360     d->m_undoState = REMOVINGDIRS;
00361     d->m_undoJob = 0;
00362 
00363     if ( d->m_currentJob )
00364         d->m_currentJob->kill( true );
00365 
00366     d->m_currentJob = 0;
00367 
00368     if ( step )
00369         undoStep();
00370 }
00371 
00372 void KonqUndoManager::slotResult( KIO::Job *job )
00373 {
00374   d->m_uiserver->jobFinished( d->m_uiserverJobId );
00375   if ( job->error() )
00376   {
00377     job->showErrorDialog( 0L );
00378     d->m_currentJob = 0;
00379     stopUndo( false );
00380     if ( d->m_undoJob )
00381     {
00382         delete d->m_undoJob;
00383         d->m_undoJob = 0;
00384     }
00385   }
00386 
00387   undoStep();
00388 }
00389 
00390 
00391 void KonqUndoManager::addDirToUpdate( const KURL& url )
00392 {
00393   if ( d->m_dirsToUpdate.find( url ) == d->m_dirsToUpdate.end() )
00394     d->m_dirsToUpdate.prepend( url );
00395 }
00396 
00397 void KonqUndoManager::undoStep()
00398 {
00399   d->m_currentJob = 0;
00400 
00401   if ( d->m_undoState == MAKINGDIRS )
00402       undoMakingDirectories();
00403 
00404   if ( d->m_undoState == MOVINGFILES )
00405       undoMovingFiles();
00406 
00407   if ( d->m_undoState == REMOVINGFILES )
00408       undoRemovingFiles();
00409 
00410   if ( d->m_undoState == REMOVINGDIRS )
00411       undoRemovingDirectories();
00412 
00413   if ( d->m_currentJob )
00414     connect( d->m_currentJob, SIGNAL( result( KIO::Job * ) ),
00415              this, SLOT( slotResult( KIO::Job * ) ) );
00416 }
00417 
00418 void KonqUndoManager::undoMakingDirectories()
00419 {
00420     if ( !d->m_dirStack.isEmpty() ) {
00421       KURL dir = d->m_dirStack.pop();
00422       kdDebug(1203) << "KonqUndoManager::undoStep creatingDir " << dir.prettyURL() << endl;
00423       d->m_currentJob = KIO::mkdir( dir );
00424       d->m_uiserver->creatingDir( d->m_uiserverJobId, dir );
00425     }
00426     else
00427       d->m_undoState = MOVINGFILES;
00428 }
00429 
00430 void KonqUndoManager::undoMovingFiles()
00431 {
00432     if ( !d->m_current.m_opStack.isEmpty() )
00433     {
00434       KonqBasicOperation op = d->m_current.m_opStack.pop();
00435 
00436       assert( op.m_valid );
00437       if ( op.m_directory )
00438       {
00439         if ( op.m_renamed )
00440         {
00441           kdDebug(1203) << "KonqUndoManager::undoStep rename " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
00442           d->m_currentJob = KIO::rename( op.m_dst, op.m_src, false );
00443           d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
00444         }
00445         else
00446           assert( 0 ); // this should not happen!
00447       }
00448       else if ( op.m_link )
00449       {
00450         kdDebug(1203) << "KonqUndoManager::undoStep symlink " << op.m_target << " " << op.m_src.prettyURL() << endl;
00451         d->m_currentJob = KIO::symlink( op.m_target, op.m_src, true, false );
00452       }
00453       else if ( d->m_current.m_type == KonqCommand::COPY )
00454       {
00455         kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << op.m_dst.prettyURL() << endl;
00456         d->m_currentJob = KIO::file_delete( op.m_dst );
00457         d->m_uiserver->deleting( d->m_uiserverJobId, op.m_dst );
00458       }
00459       else if ( d->m_current.m_type == KonqCommand::MOVE
00460                 || d->m_current.m_type == KonqCommand::TRASH )
00461       {
00462         kdDebug(1203) << "KonqUndoManager::undoStep file_move " << op.m_dst.prettyURL() << " " << op.m_src.prettyURL() << endl;
00463         d->m_currentJob = KIO::file_move( op.m_dst, op.m_src, -1, true );
00464         d->m_uiserver->moving( d->m_uiserverJobId, op.m_dst, op.m_src );
00465       }
00466 
00467       // The above KIO jobs are lowlevel, they don't trigger KDirNotify notification
00468       // So we need to do it ourselves (but schedule it to the end of the undo, to compress them)
00469       KURL url( op.m_dst );
00470       url.setPath( url.directory() );
00471       addDirToUpdate( url );
00472 
00473       url = op.m_src;
00474       url.setPath( url.directory() );
00475       addDirToUpdate( url );
00476     }
00477     else
00478       d->m_undoState = REMOVINGFILES;
00479 }
00480 
00481 void KonqUndoManager::undoRemovingFiles()
00482 {
00483     kdDebug(1203) << "KonqUndoManager::undoStep REMOVINGFILES" << endl;
00484     if ( !d->m_fileCleanupStack.isEmpty() )
00485     {
00486       KURL file = d->m_fileCleanupStack.pop();
00487       kdDebug(1203) << "KonqUndoManager::undoStep file_delete " << file.prettyURL() << endl;
00488       d->m_currentJob = KIO::file_delete( file );
00489       d->m_uiserver->deleting( d->m_uiserverJobId, file );
00490 
00491       KURL url( file );
00492       url.setPath( url.directory() );
00493       addDirToUpdate( url );
00494     }
00495     else
00496     {
00497       d->m_undoState = REMOVINGDIRS;
00498 
00499       if ( d->m_dirCleanupStack.isEmpty() && d->m_current.m_type == KonqCommand::MKDIR )
00500         d->m_dirCleanupStack << d->m_current.m_dst;
00501     }
00502 }
00503 
00504 void KonqUndoManager::undoRemovingDirectories()
00505 {
00506     if ( !d->m_dirCleanupStack.isEmpty() )
00507     {
00508       KURL dir = d->m_dirCleanupStack.pop();
00509       kdDebug(1203) << "KonqUndoManager::undoStep rmdir " << dir.prettyURL() << endl;
00510       d->m_currentJob = KIO::rmdir( dir );
00511       d->m_uiserver->deleting( d->m_uiserverJobId, dir );
00512       addDirToUpdate( dir );
00513     }
00514     else
00515     {
00516       d->m_current.m_valid = false;
00517       d->m_currentJob = 0;
00518       if ( d->m_undoJob )
00519       {
00520           kdDebug(1203) << "KonqUndoManager::undoStep deleting undojob" << endl;
00521           d->m_uiserver->jobFinished( d->m_uiserverJobId );
00522           delete d->m_undoJob;
00523           d->m_undoJob = 0;
00524       }
00525       KDirNotify_stub allDirNotify( "*", "KDirNotify*" );
00526       QValueList<KURL>::ConstIterator it = d->m_dirsToUpdate.begin();
00527       for( ; it != d->m_dirsToUpdate.end(); ++it ) {
00528           kdDebug() << "Notifying FilesAdded for " << *it << endl;
00529           allDirNotify.FilesAdded( *it );
00530       }
00531       broadcastUnlock();
00532     }
00533 }
00534 
00535 void KonqUndoManager::push( const KonqCommand &cmd )
00536 {
00537   d->m_commands.push( cmd );
00538   emit undoAvailable( true );
00539   emit undoTextChanged( undoText() );
00540 }
00541 
00542 void KonqUndoManager::pop()
00543 {
00544   d->m_commands.pop();
00545   emit undoAvailable( undoAvailable() );
00546   emit undoTextChanged( undoText() );
00547 }
00548 
00549 void KonqUndoManager::lock()
00550 {
00551 //  assert( !d->m_lock );
00552   d->m_lock = true;
00553   emit undoAvailable( undoAvailable() );
00554 }
00555 
00556 void KonqUndoManager::unlock()
00557 {
00558 //  assert( d->m_lock );
00559   d->m_lock = false;
00560   emit undoAvailable( undoAvailable() );
00561 }
00562 
00563 KonqCommand::Stack KonqUndoManager::get() const
00564 {
00565   return d->m_commands;
00566 }
00567 
00568 void KonqUndoManager::broadcastPush( const KonqCommand &cmd )
00569 {
00570   if ( !d->m_syncronized )
00571   {
00572     push( cmd );
00573     return;
00574   }
00575 
00576   DCOPRef( "kdesktop", "KonqUndoManager" ).send( "push", cmd );
00577   DCOPRef( "konqueror*", "KonqUndoManager" ).send( "push", cmd );
00578 }
00579 
00580 void KonqUndoManager::broadcastPop()
00581 {
00582   if ( !d->m_syncronized )
00583   {
00584     pop();
00585     return;
00586   }
00587   DCOPRef( "kdesktop", "KonqUndoManager" ).send( "pop" );
00588   DCOPRef( "konqueror*", "KonqUndoManager" ).send( "pop" );
00589 }
00590 
00591 void KonqUndoManager::broadcastLock()
00592 {
00593 //  assert( !d->m_lock );
00594 
00595   if ( !d->m_syncronized )
00596   {
00597     lock();
00598     return;
00599   }
00600   DCOPRef( "kdesktop", "KonqUndoManager" ).send( "lock" );
00601   DCOPRef( "konqueror*", "KonqUndoManager" ).send( "lock" );
00602 }
00603 
00604 void KonqUndoManager::broadcastUnlock()
00605 {
00606 //  assert( d->m_lock );
00607 
00608   if ( !d->m_syncronized )
00609   {
00610     unlock();
00611     return;
00612   }
00613   DCOPRef( "kdesktop", "KonqUndoManager" ).send( "unlock" );
00614   DCOPRef( "konqueror*", "KonqUndoManager" ).send( "unlock" );
00615 }
00616 
00617 bool KonqUndoManager::initializeFromKDesky()
00618 {
00619   // ### workaround for dcop problem and upcoming 2.1 release:
00620   // in case of huge io operations the amount of data sent over
00621   // dcop (containing undo information broadcasted for global undo
00622   // to all konqueror instances) can easily exceed the 64kb limit
00623   // of dcop. In order not to run into trouble we disable global
00624   // undo for now! (Simon)
00625   // ### FIXME: post 2.1
00626   return false;
00627 
00628   DCOPClient *client = kapp->dcopClient();
00629 
00630   if ( client->appId() == "kdesktop" ) // we are master :)
00631     return true;
00632 
00633   if ( !client->isApplicationRegistered( "kdesktop" ) )
00634     return false;
00635 
00636   d->m_commands = DCOPRef( "kdesktop", "KonqUndoManager" ).call( "get" );
00637   return true;
00638 }
00639 
00640 QDataStream &operator<<( QDataStream &stream, const KonqBasicOperation &op )
00641 {
00642     stream << op.m_valid << op.m_directory << op.m_renamed << op.m_link
00643            << op.m_src << op.m_dst << op.m_target;
00644   return stream;
00645 }
00646 QDataStream &operator>>( QDataStream &stream, KonqBasicOperation &op )
00647 {
00648   stream >> op.m_valid >> op.m_directory >> op.m_renamed >> op.m_link
00649          >> op.m_src >> op.m_dst >> op.m_target;
00650   return stream;
00651 }
00652 
00653 QDataStream &operator<<( QDataStream &stream, const KonqCommand &cmd )
00654 {
00655   stream << cmd.m_valid << (Q_INT8)cmd.m_type << cmd.m_opStack << cmd.m_src << cmd.m_dst;
00656   return stream;
00657 }
00658 
00659 QDataStream &operator>>( QDataStream &stream, KonqCommand &cmd )
00660 {
00661   Q_INT8 type;
00662   stream >> cmd.m_valid >> type >> cmd.m_opStack >> cmd.m_src >> cmd.m_dst;
00663   cmd.m_type = static_cast<KonqCommand::Type>( type );
00664   return stream;
00665 }
00666 
00667 #include "konq_undo.moc"

libkonq

Skip menu "libkonq"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

@topname@

Skip menu "@topname@"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for @topname@ by doxygen 1.5.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal