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 }
00179 }
00180
00181 void KCommandHistory::undo() {
00182
00183
if (m_first || !d->m_present)
00184
return;
00185
00186 d->m_present->unexecute();
00187 emit
commandExecuted();
00188
if (m_redo) {
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()) {
00194 d->m_present=m_commands.
current();
00195
if (m_undo) {
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) {
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)
00224 emit
documentRestored();
00225 }
00226
else if((index=m_commands.
findRef(d->m_present))!=-1 && m_commands.
next()) {
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) {
00236 m_undo->
setEnabled(
true);
00237 m_undo->
setText(i18n(
"&Undo: %1").arg(d->m_present->name()));
00238 }
00239
00240
if(m_commands.
next()) {
00241
if (m_redo) {
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) && 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 && !m_first)
00256 d->m_savedAt=m_commands.
findRef(d->m_present);
00257
else if(!d->m_present && !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 ) );
00359 m_redo->
setEnabled(m_first || (m_commands.
findRef(d->m_present)!=-1 && m_commands.
next()));
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"