00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00141 unsigned int count=m_commands.count();
00142 for(unsigned int i=index+2; i<count; ++i)
00143 m_commands.removeLast();
00144
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 {
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;
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();
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;
00263
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);
00299 count=m_commands.count();
00300
00301 if(d->m_savedAt!=-42 && d->m_savedAt<-1)
00302 d->m_savedAt=-1;
00303 }
00304
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 )
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 )
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 { }
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 { }
00378
00379 #include "kcommand.moc"