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::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
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 != 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 {
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;
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();
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;
00259
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);
00295 count=m_commands.count();
00296
00297 if(d->m_savedAt!=-42 && d->m_savedAt<-1)
00298 d->m_savedAt=-1;
00299 }
00300
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 )
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 )
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 { }
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 { }
00374
00375 #include "kcommand.moc"