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

kdeui

kcommand.cpp

Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, 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::shortcut(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::shortcut(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) {
00119         m_undo->setEnabled(false);
00120         m_undo->setText(i18n("&Undo"));
00121     }
00122     if (m_redo) {
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)
00133         return;
00134 
00135     int index;
00136     if(d->m_present && (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) {
00150             m_undo->setEnabled(true);
00151             m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00152         }
00153         if((m_redo) && 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) {
00165             m_undo->setEnabled(true);
00166             m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00167         }
00168         if (m_redo) {
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         emit commandExecuted(command);
00179     }
00180 }
00181 
00182 void KCommandHistory::undo() {
00183 
00184     if (m_first || !d->m_present)
00185         return;
00186 
00187     d->m_present->unexecute();
00188     emit commandExecuted();
00189     emit commandExecuted(d->m_present);
00190     if (m_redo) {
00191         m_redo->setEnabled(true);
00192         m_redo->setText(i18n("&Redo: %1").arg(d->m_present->name()));
00193     }
00194     int index;
00195     if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.prev()) {
00196         d->m_present=m_commands.current();
00197         if (m_undo) {
00198             m_undo->setEnabled(true);
00199             m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00200         }
00201         --index;
00202         if(index==d->m_savedAt)
00203             emit documentRestored();
00204     }
00205     else {
00206         if (m_undo) {
00207             m_undo->setEnabled(false);
00208             m_undo->setText(i18n("&Undo"));
00209         }
00210         if(d->m_savedAt==-42)
00211             emit documentRestored();
00212         m_first=true;
00213     }
00214     clipCommands(); // only needed here and in addCommand, NOT in redo
00215 }
00216 
00217 void KCommandHistory::redo() {
00218 
00219     int index;
00220     if(m_first) {
00221         d->m_present->execute();
00222         emit commandExecuted();
00223         emit commandExecuted(d->m_present);
00224         m_first=false;
00225         m_commands.first();
00226         if(!d->m_savedAt)
00227             emit documentRestored();
00228     }
00229     else if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.next()) {
00230         d->m_present=m_commands.current();
00231         d->m_present->execute();
00232         emit commandExecuted();
00233         emit commandExecuted(d->m_present);
00234         ++index;
00235         if(index==d->m_savedAt)
00236             emit documentRestored();
00237     }
00238 
00239     if (m_undo) {
00240         m_undo->setEnabled(true);
00241         m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00242     }
00243 
00244     if(m_commands.next()) {
00245         if (m_redo) {
00246             m_redo->setEnabled(true);
00247             m_redo->setText(i18n("&Redo: %1").arg(m_commands.current()->name()));
00248         }
00249     }
00250     else {
00251         if((m_redo) && m_redo->isEnabled()) {
00252             m_redo->setEnabled(false);
00253             m_redo->setText(i18n("&Redo"));
00254         }
00255     }
00256 }
00257 
00258 void KCommandHistory::documentSaved() {
00259     if(d->m_present && !m_first)
00260         d->m_savedAt=m_commands.findRef(d->m_present);
00261     else if(!d->m_present && !m_first)
00262         d->m_savedAt=-42;  // this value signals that the document has
00263                         // been saved with an empty history.
00264     else if(m_first)
00265         d->m_savedAt=-42;
00266 }
00267 
00268 void KCommandHistory::setUndoLimit(int limit) {
00269 
00270     if(limit>0 && limit!=m_undoLimit) {
00271         m_undoLimit=limit;
00272         clipCommands();
00273     }
00274 }
00275 
00276 void KCommandHistory::setRedoLimit(int limit) {
00277 
00278     if(limit>0 && limit!=m_redoLimit) {
00279         m_redoLimit=limit;
00280         clipCommands();
00281     }
00282 }
00283 
00284 void KCommandHistory::clipCommands() {
00285 
00286     int count=m_commands.count();
00287     if(count<=m_undoLimit && count<=m_redoLimit)
00288         return;
00289 
00290     int index=m_commands.findRef(d->m_present);
00291     if(index>=m_undoLimit) {
00292         for(int i=0; i<=(index-m_undoLimit); ++i) {
00293             m_commands.removeFirst();
00294             --d->m_savedAt;
00295             if(d->m_savedAt==-1)
00296                 d->m_savedAt=-42;
00297         }
00298         index=m_commands.findRef(d->m_present); // calculate the new
00299         count=m_commands.count();            // values (for the redo-branch :)
00300         // make it easier for us... d->m_savedAt==-1 -> invalid
00301         if(d->m_savedAt!=-42 && d->m_savedAt<-1)
00302             d->m_savedAt=-1;
00303     }
00304     // adjust the index if it's the first command
00305     if(m_first)
00306         index=-1;
00307     if((index+m_redoLimit+1)<count) {
00308         if(d->m_savedAt>(index+m_redoLimit))
00309             d->m_savedAt=-1;
00310         for(int i=0; i<(count-(index+m_redoLimit+1)); ++i)
00311             m_commands.removeLast();
00312     }
00313 }
00314 
00315 void KCommandHistory::slotUndoAboutToShow()
00316 {
00317     m_undoPopup->clear();
00318     int i = 0;
00319     if (m_commands.findRef(d->m_present)!=-1)
00320         while ( m_commands.current() && i<10 ) // TODO make number of items configurable ?
00321         {
00322             m_undoPopup->insertItem( i18n("Undo: %1").arg(m_commands.current()->name()), i++ );
00323             m_commands.prev();
00324         }
00325 }
00326 
00327 void KCommandHistory::slotUndoActivated( int pos )
00328 {
00329     kdDebug(230) << "KCommandHistory::slotUndoActivated " << pos << endl;
00330     for ( int i = 0 ; i < pos+1; ++i )
00331         undo();
00332 }
00333 
00334 void KCommandHistory::slotRedoAboutToShow()
00335 {
00336     m_redoPopup->clear();
00337     int i = 0;
00338     if (m_first)
00339     {
00340         d->m_present = m_commands.first();
00341         m_redoPopup->insertItem( i18n("Redo: %1").arg(d->m_present->name()), i++ );
00342     }
00343     if (m_commands.findRef(d->m_present)!=-1 && m_commands.next())
00344         while ( m_commands.current() && i<10 ) // TODO make number of items configurable ?
00345         {
00346             m_redoPopup->insertItem( i18n("Redo: %1").arg(m_commands.current()->name()), i++ );
00347             m_commands.next();
00348         }
00349 }
00350 
00351 void KCommandHistory::slotRedoActivated( int pos )
00352 {
00353     kdDebug(230) << "KCommandHistory::slotRedoActivated " << pos << endl;
00354     for ( int i = 0 ; i < pos+1; ++i )
00355         redo();
00356 }
00357 
00358 void KCommandHistory::updateActions()
00359 {
00360     if ( m_undo && m_redo )
00361     {
00362         m_undo->setEnabled( !m_first && ( d->m_present ) );
00363         m_redo->setEnabled(m_first || (m_commands.findRef(d->m_present)!=-1 && m_commands.next()));
00364     }
00365 }
00366 
00367 void KCommand::virtual_hook( int, void* )
00368 { /*BASE::virtual_hook( id, data );*/ }
00369 
00370 void KNamedCommand::virtual_hook( int id, void* data )
00371 { KCommand::virtual_hook( id, data ); }
00372 
00373 void KMacroCommand::virtual_hook( int id, void* data )
00374 { KNamedCommand::virtual_hook( id, data ); }
00375 
00376 void KCommandHistory::virtual_hook( int, void* )
00377 { /*BASE::virtual_hook( id, data );*/ }
00378 
00379 #include "kcommand.moc"

kdeui

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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