kdeui Library API Documentation

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::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 != 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"
KDE Logo
This file is part of the documentation for kdeui Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:48:43 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003