kcommand.cpp Source File (kdeui Library)

| # kdeui Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kcommand.cpp

    00001 /* This file is part of the KDE project
    00002    Copyright (C) 2000 Werner Trobin <trobin@kde.org>
    00003    Copyright (C) 2000 David Faure <faure@kde.org>
    00004
    00005    This library is free software; you can redistribute it and/or
    00006    modify it under the terms of the GNU Library General Public
    00007    License as published by the Free Software Foundation; either
    00008    version 2 of the License, or (at your option) any later version.
    00009
    00010    This library is distributed in the hope that it will be useful,
    00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013    Library General Public License for more details.
    00014
    00015    You should have received a copy of the GNU Library General Public License
    00016    along with this library; see the file COPYING.LIB.  If not, write to
    00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018    Boston, MA 02111-1307, USA.
    00019 */
    00020
    00021 #include "kcommand.h"
    00022 #include <kaction.h>
    00023 #include <kstdaccel.h>
    00024 #include <kstdaction.h>
    00025 #include <kdebug.h>
    00026 #include <klocale.h>
    00027 #include <kpopupmenu.h>
    00028
    00029 KCommand::~KCommand()
    00030 {
    00031 }
    00032
    00033 KMacroCommand::KMacroCommand( const QString & name ) : KNamedCommand(name)
    00034 {
    00035     m_commands.setAutoDelete(true);
    00036 }
    00037
    00038 void KMacroCommand::addCommand(KCommand *command)
    00039 {
    00040     m_commands.append(command);
    00041 }
    00042
    00043 void KMacroCommand::execute()
    00044 {
    00045     QPtrListIterator<KCommand> it(m_commands);
    00046     for ( ; it.current() ; ++it )
    00047         it.current()->execute();
    00048 }
    00049
    00050 void KMacroCommand::unexecute()
    00051 {
    00052     QPtrListIterator<KCommand> it(m_commands);
    00053     it.toLast();
    00054     for ( ; it.current() ; --it )
    00055         it.current()->unexecute();
    00056 }
    00057
    00058
    00059 class KCommandHistory::KCommandHistoryPrivate {
    00060 public:
    00061     KCommandHistoryPrivate() {
    00062         m_savedAt=-1;
    00063         m_present=0;
    00064     }
    00065     ~KCommandHistoryPrivate() {}
    00066     int m_savedAt;
    00067     KCommand *m_present;
    00068 };
    00069
    00071
    00072 KCommandHistory::KCommandHistory() :
    00073     m_undo(0), m_redo(0), m_undoLimit(50), m_redoLimit(30), m_first(false)
    00074 {
    00075     d=new KCommandHistoryPrivate();
    00076     m_commands.setAutoDelete(true);
    00077     clear();
    00078 }
    00079
    00080 KCommandHistory::KCommandHistory(KActionCollection * actionCollection, bool withMenus) :
    00081     m_undoLimit(50), m_redoLimit(30), m_first(false)
    00082 {
    00083     d=new KCommandHistoryPrivate();
    00084     if (withMenus)
    00085     {
    00086         KToolBarPopupAction * undo = new KToolBarPopupAction( i18n("&Undo"), "undo",
    00087                                           KStdAccel::key(KStdAccel::Undo), this, SLOT( undo() ),
    00088                                           actionCollection, KStdAction::stdName( KStdAction::Undo ) );
    00089         connect( undo->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( slotUndoAboutToShow() ) );
    00090         connect( undo->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( slotUndoActivated( int ) ) );
    00091         m_undo = undo;
    00092         m_undoPopup = undo->popupMenu();
    00093
    00094         KToolBarPopupAction * redo = new KToolBarPopupAction( i18n("&Redo"), "redo",
    00095                                           KStdAccel::key(KStdAccel::Redo), this, SLOT( redo() ),
    00096                                           actionCollection, KStdAction::stdName( KStdAction::Redo ) );
    00097         connect( redo->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( slotRedoAboutToShow() ) );
    00098         connect( redo->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( slotRedoActivated( int ) ) );
    00099         m_redo = redo;
    00100         m_redoPopup = redo->popupMenu();
    00101     }
    00102     else
    00103     {
    00104         m_undo = KStdAction::undo( this, SLOT( undo() ), actionCollection );
    00105         m_redo = KStdAction::redo( this, SLOT( redo() ), actionCollection );
    00106         m_undoPopup = 0L;
    00107         m_redoPopup = 0L;
    00108     }
    00109     m_commands.setAutoDelete(true);
    00110     clear();
    00111 }
    00112
    00113 KCommandHistory::~KCommandHistory() {
    00114     delete d;
    00115 }
    00116
    00117 void KCommandHistory::clear() {
    00118     if (m_undo != 0) {
    00119         m_undo->setEnabled(false);
    00120         m_undo->setText(i18n("&Undo"));
    00121     }
    00122     if (m_redo != 0) {
    00123         m_redo->setEnabled(false);
    00124         m_redo->setText(i18n("&Redo"));
    00125     }
    00126     d->m_present = 0L;
    00127     d->m_savedAt=-42;
    00128 }
    00129
    00130 void KCommandHistory::addCommand(KCommand *command, bool execute) {
    00131
    00132     if(command==0L)
    00133         return;
    00134
    00135     int index;
    00136     if(d->m_present!=0L && (index=m_commands.findRef(d->m_present))!=-1) {
    00137         if (m_first)
    00138             --index;
    00139         m_commands.insert(index+1, command);
    00140         // truncate history
    00141         unsigned int count=m_commands.count();
    00142         for(unsigned int i=index+2; i<count; ++i)
    00143             m_commands.removeLast();
    00144         // check whether we still can reach savedAt
    00145         if(index<d->m_savedAt)
    00146             d->m_savedAt=-1;
    00147         d->m_present=command;
    00148         m_first=false;
    00149         if (m_undo != 0) {
    00150             m_undo->setEnabled(true);
    00151             m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
    00152         }
    00153         if((m_redo != 0) && m_redo->isEnabled()) {
    00154             m_redo->setEnabled(false);
    00155             m_redo->setText(i18n("&Redo"));
    00156         }
    00157         clipCommands();
    00158     }
    00159     else { // either this is the first time we add a Command or something has gone wrong
    00160         kdDebug(230) << "Initializing the Command History" << endl;
    00161         m_commands.clear();
    00162         m_commands.append(command);
    00163         d->m_present=command;
    00164         if (m_undo != 0) {
    00165             m_undo->setEnabled(true);
    00166             m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
    00167         }
    00168         if (m_redo != 0) {
    00169             m_redo->setEnabled(false);
    00170             m_redo->setText(i18n("&Redo"));
    00171         }
    00172         m_first=false;    // Michael B: yes, that *is* correct :-)
    00173     }
    00174     if ( execute )
    00175     {
    00176         command->execute();
    00177         emit commandExecuted();
    00178     }
    00179 }
    00180
    00181 void KCommandHistory::undo() {
    00182
    00183     if (m_first || (d->m_present == 0L))
    00184         return;
    00185
    00186     d->m_present->unexecute();
    00187     emit commandExecuted();
    00188     if (m_redo != 0) {
    00189         m_redo->setEnabled(true);
    00190         m_redo->setText(i18n("&Redo: %1").arg(d->m_present->name()));
    00191     }
    00192     int index;
    00193     if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.prev()!=0) {
    00194         d->m_present=m_commands.current();
    00195         if (m_undo != 0) {
    00196             m_undo->setEnabled(true);
    00197             m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
    00198         }
    00199         --index;
    00200         if(index==d->m_savedAt)
    00201             emit documentRestored();
    00202     }
    00203     else {
    00204         if (m_undo != 0) {
    00205             m_undo->setEnabled(false);
    00206             m_undo->setText(i18n("&Undo"));
    00207         }
    00208         if(d->m_savedAt==-42)
    00209             emit documentRestored();
    00210         m_first=true;
    00211     }
    00212     clipCommands(); // only needed here and in addCommand, NOT in redo
    00213 }
    00214
    00215 void KCommandHistory::redo() {
    00216
    00217     int index;
    00218     if(m_first) {
    00219         d->m_present->execute();
    00220         emit commandExecuted();
    00221         m_first=false;
    00222         m_commands.first();
    00223         if(d->m_savedAt==0)
    00224             emit documentRestored();
    00225     }
    00226     else if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.next()!=0) {
    00227         d->m_present=m_commands.current();
    00228         d->m_present->execute();
    00229         emit commandExecuted();
    00230         ++index;
    00231         if(index==d->m_savedAt)
    00232             emit documentRestored();
    00233     }
    00234
    00235     if (m_undo != 0) {
    00236         m_undo->setEnabled(true);
    00237         m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
    00238     }
    00239
    00240     if(m_commands.next()!=0) {
    00241         if (m_redo != 0) {
    00242             m_redo->setEnabled(true);
    00243             m_redo->setText(i18n("&Redo: %1").arg(m_commands.current()->name()));
    00244         }
    00245     }
    00246     else {
    00247         if((m_redo != 0) && m_redo->isEnabled()) {
    00248             m_redo->setEnabled(false);
    00249             m_redo->setText(i18n("&Redo"));
    00250         }
    00251     }
    00252 }
    00253
    00254 void KCommandHistory::documentSaved() {
    00255     if(d->m_present!=0 && !m_first)
    00256         d->m_savedAt=m_commands.findRef(d->m_present);
    00257     else if(d->m_present==0 && !m_first)
    00258         d->m_savedAt=-42;  // this value signals that the document has
    00259                         // been saved with an empty history.
    00260     else if(m_first)
    00261         d->m_savedAt=-42;
    00262 }
    00263
    00264 void KCommandHistory::setUndoLimit(int limit) {
    00265
    00266     if(limit>0 && limit!=m_undoLimit) {
    00267         m_undoLimit=limit;
    00268         clipCommands();
    00269     }
    00270 }
    00271
    00272 void KCommandHistory::setRedoLimit(int limit) {
    00273
    00274     if(limit>0 && limit!=m_redoLimit) {
    00275         m_redoLimit=limit;
    00276         clipCommands();
    00277     }
    00278 }
    00279
    00280 void KCommandHistory::clipCommands() {
    00281
    00282     int count=m_commands.count();
    00283     if(count<=m_undoLimit && count<=m_redoLimit)
    00284         return;
    00285
    00286     int index=m_commands.findRef(d->m_present);
    00287     if(index>=m_undoLimit) {
    00288         for(int i=0; i<=(index-m_undoLimit); ++i) {
    00289             m_commands.removeFirst();
    00290             --d->m_savedAt;
    00291             if(d->m_savedAt==-1)
    00292                 d->m_savedAt=-42;
    00293         }
    00294         index=m_commands.findRef(d->m_present); // calculate the new
    00295         count=m_commands.count();            // values (for the redo-branch :)
    00296         // make it easier for us... d->m_savedAt==-1 -> invalid
    00297         if(d->m_savedAt!=-42 && d->m_savedAt<-1)
    00298             d->m_savedAt=-1;
    00299     }
    00300     // adjust the index if it's the first command
    00301     if(m_first)
    00302         index=-1;
    00303     if((index+m_redoLimit+1)<count) {
    00304         if(d->m_savedAt>(index+m_redoLimit))
    00305             d->m_savedAt=-1;
    00306         for(int i=0; i<(count-(index+m_redoLimit+1)); ++i)
    00307             m_commands.removeLast();
    00308     }
    00309 }
    00310
    00311 void KCommandHistory::slotUndoAboutToShow()
    00312 {
    00313     m_undoPopup->clear();
    00314     int i = 0;
    00315     if (m_commands.findRef(d->m_present)!=-1)
    00316         while ( m_commands.current() && i<10 ) // TODO make number of items configurable ?
    00317         {
    00318             m_undoPopup->insertItem( i18n("Undo: %1").arg(m_commands.current()->name()), i++ );
    00319             m_commands.prev();
    00320         }
    00321 }
    00322
    00323 void KCommandHistory::slotUndoActivated( int pos )
    00324 {
    00325     kdDebug(230) << "KCommandHistory::slotUndoActivated " << pos << endl;
    00326     for ( int i = 0 ; i < pos+1; ++i )
    00327         undo();
    00328 }
    00329
    00330 void KCommandHistory::slotRedoAboutToShow()
    00331 {
    00332     m_redoPopup->clear();
    00333     int i = 0;
    00334     if (m_first)
    00335     {
    00336         d->m_present = m_commands.first();
    00337         m_redoPopup->insertItem( i18n("Redo: %1").arg(d->m_present->name()), i++ );
    00338     }
    00339     if (m_commands.findRef(d->m_present)!=-1 && m_commands.next())
    00340         while ( m_commands.current() && i<10 ) // TODO make number of items configurable ?
    00341         {
    00342             m_redoPopup->insertItem( i18n("Redo: %1").arg(m_commands.current()->name()), i++ );
    00343             m_commands.next();
    00344         }
    00345 }
    00346
    00347 void KCommandHistory::slotRedoActivated( int pos )
    00348 {
    00349     kdDebug(230) << "KCommandHistory::slotRedoActivated " << pos << endl;
    00350     for ( int i = 0 ; i < pos+1; ++i )
    00351         redo();
    00352 }
    00353
    00354 void KCommandHistory::updateActions()
    00355 {
    00356     if ( m_undo && m_redo )
    00357     {
    00358         m_undo->setEnabled( !m_first && ( d->m_present != 0L ) );
    00359         m_redo->setEnabled(m_first || (m_commands.findRef(d->m_present)!=-1 && m_commands.next()!=0));
    00360     }
    00361 }
    00362
    00363 void KCommand::virtual_hook( int, void* )
    00364 { /*BASE::virtual_hook( id, data );*/ }
    00365
    00366 void KNamedCommand::virtual_hook( int id, void* data )
    00367 { KCommand::virtual_hook( id, data ); }
    00368
    00369 void KMacroCommand::virtual_hook( int id, void* data )
    00370 { KNamedCommand::virtual_hook( id, data ); }
    00371
    00372 void KCommandHistory::virtual_hook( int, void* )
    00373 { /*BASE::virtual_hook( id, data );*/ }
    00374
    00375 #include "kcommand.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:56:23 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001