00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kocommandhistory.h"
00022 #include <kcommand.h>
00023 #include <kaction.h>
00024 #include <kstdaccel.h>
00025 #include <kstdaction.h>
00026 #include <kdebug.h>
00027 #include <klocale.h>
00028 #include <kpopupmenu.h>
00029 #include <qlistbox.h>
00030 #include <kshortcutlist.h>
00031 #include <qlabel.h>
00032
00033 KoListBox::KoListBox( QWidget *parent , const char *name , WFlags f)
00034 : QListBox( parent, name, f)
00035 {
00036 setVScrollBarMode( AlwaysOn );
00037 }
00038
00039 void KoListBox::contentsMouseMoveEvent ( QMouseEvent * e)
00040 {
00041 QListBoxItem *item_p = itemAt( contentsToViewport(e->pos()));
00042 if ( item_p )
00043 {
00044 int itemIndex = index( item_p );
00045 for ( int i = 0; i<=itemIndex;i++)
00046 setSelected ( i, true );
00047 for ( int i = itemIndex+1; i<(int)count();i++)
00048 setSelected ( i, false );
00049 emit changeNumberOfSelectedItem( itemIndex);
00050 }
00051 }
00052
00053 class KoCommandHistory::KoCommandHistoryPrivate {
00054 public:
00055 KoCommandHistoryPrivate() {
00056 m_savedAt=-1;
00057 m_present=0;
00058 }
00059 ~KoCommandHistoryPrivate() {}
00060 int m_savedAt;
00061 KCommand *m_present;
00062 KoListBox *m_undoListBox;
00063 KoListBox *m_redoListBox;
00064 QLabel *m_undoLabel;
00065 QLabel *m_redoLabel;
00066 };
00067
00069
00070 KoCommandHistory::KoCommandHistory() :
00071 m_undo(0), m_redo(0), m_undoLimit(50), m_redoLimit(30), m_first(false)
00072 {
00073 d=new KoCommandHistoryPrivate();
00074 m_commands.setAutoDelete(true);
00075 clear();
00076 }
00077
00078 KoCommandHistory::KoCommandHistory(KActionCollection * actionCollection, bool withMenus) :
00079 m_undoLimit(50), m_redoLimit(30), m_first(false)
00080 {
00081 d=new KoCommandHistoryPrivate();
00082 if (withMenus)
00083 {
00084 KToolBarPopupAction * undo = new KToolBarPopupAction( i18n("&Undo"), "undo",
00085 KStdAccel::undo(), this, SLOT( undo() ),
00086 actionCollection, "koffice_undo" );
00087 connect( undo->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( slotUndoAboutToShow() ) );
00088 connect( undo->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( slotUndoActivated( int ) ) );
00089 m_undo = undo;
00090 m_undoPopup = undo->popupMenu();
00091 d->m_undoListBox = new KoListBox( m_undoPopup );
00092 d->m_undoListBox->resize( 200, 200);
00093 d->m_undoListBox->setSelectionMode( QListBox::Multi );
00094
00095 m_undoPopup->insertItem(d->m_undoListBox);
00096 d->m_undoLabel = new QLabel( m_undoPopup);
00097 m_undoPopup->insertItem(d->m_undoLabel);
00098
00099 connect( d->m_undoListBox, SIGNAL( selected( int ) ), this, SLOT( slotUndoActivated( int ) ) );
00100 connect( d->m_undoListBox, SIGNAL(clicked ( QListBoxItem *)), this, SLOT( slotUndoActivated( QListBoxItem * ) ) );
00101
00102 connect( d->m_undoListBox, SIGNAL( changeNumberOfSelectedItem( int )), this, SLOT( slotChangeUndoNumberOfSelectedItem( int )));
00103
00104 KToolBarPopupAction * redo = new KToolBarPopupAction( i18n("&Redo"), "redo",
00105 KStdAccel::redo(), this, SLOT( redo() ),
00106 actionCollection,
00107 "koffice_redo");
00108 connect( redo->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( slotRedoAboutToShow() ) );
00109 connect( redo->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( slotRedoActivated( int ) ) );
00110 m_redo = redo;
00111 m_redoPopup = redo->popupMenu();
00112 d->m_redoListBox = new KoListBox( m_redoPopup );
00113 d->m_redoListBox->setSelectionMode( QListBox::Multi );
00114 d->m_redoListBox->resize( 200, 200);
00115 m_redoPopup->insertItem(d->m_redoListBox);
00116
00117 d->m_redoLabel = new QLabel( m_redoPopup);
00118 m_redoPopup->insertItem(d->m_redoLabel);
00119
00120
00121 connect( d->m_redoListBox, SIGNAL( selected( int ) ), this, SLOT( slotRedoActivated( int ) ) );
00122 connect( d->m_redoListBox, SIGNAL(clicked ( QListBoxItem *)), this, SLOT( slotRedoActivated( QListBoxItem * ) ) );
00123 connect( d->m_redoListBox, SIGNAL( changeNumberOfSelectedItem( int )), this, SLOT( slotChangeRedoNumberOfSelectedItem( int )));
00124
00125 }
00126 else
00127 {
00128 m_undo = KStdAction::undo( this, SLOT( undo() ), actionCollection, "koffice_undo");
00129 m_redo = KStdAction::redo( this, SLOT( redo() ), actionCollection, "koffice_redo");
00130 m_undoPopup = 0L;
00131 m_redoPopup = 0L;
00132 d->m_redoListBox = 0L;
00133 d->m_undoListBox = 0L;
00134 d->m_redoLabel = 0L;
00135 d->m_undoLabel = 0L;
00136 }
00137 m_commands.setAutoDelete(true);
00138 clear();
00139 }
00140
00141 KoCommandHistory::~KoCommandHistory() {
00142 delete d;
00143 }
00144
00145 void KoCommandHistory::clear() {
00146 if (m_undo != 0) {
00147 m_undo->setEnabled(false);
00148 m_undo->setText(i18n("&Undo"));
00149 }
00150 if (m_redo != 0) {
00151 m_redo->setEnabled(false);
00152 m_redo->setText(i18n("&Redo"));
00153 }
00154 d->m_present = 0L;
00155 d->m_savedAt=-42;
00156 }
00157
00158 void KoCommandHistory::addCommand(KCommand *command, bool execute) {
00159
00160 if(command==0L)
00161 return;
00162
00163 int index;
00164 if(d->m_present!=0L && (index=m_commands.findRef(d->m_present))!=-1) {
00165 if (m_first)
00166 --index;
00167 m_commands.insert(index+1, command);
00168
00169 unsigned int count=m_commands.count();
00170 for(unsigned int i=index+2; i<count; ++i)
00171 m_commands.removeLast();
00172
00173 if(index<d->m_savedAt)
00174 d->m_savedAt=-1;
00175 d->m_present=command;
00176 m_first=false;
00177 if (m_undo != 0) {
00178 m_undo->setEnabled(true);
00179 m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00180 }
00181 if((m_redo != 0) && m_redo->isEnabled()) {
00182 m_redo->setEnabled(false);
00183 m_redo->setText(i18n("&Redo"));
00184 }
00185 clipCommands();
00186 }
00187 else {
00188 kdDebug(230) << "Initializing the Command History" << endl;
00189 m_commands.clear();
00190 m_commands.append(command);
00191 d->m_present=command;
00192 if (m_undo != 0) {
00193 m_undo->setEnabled(true);
00194 m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00195 }
00196 if (m_redo != 0) {
00197 m_redo->setEnabled(false);
00198 m_redo->setText(i18n("&Redo"));
00199 }
00200 m_first=false;
00201 }
00202 if ( execute )
00203 {
00204 command->execute();
00205 emit commandExecuted();
00206 }
00207 }
00208
00209 void KoCommandHistory::undo() {
00210
00211 if (m_first || (d->m_present == 0L))
00212 return;
00213
00214 d->m_present->unexecute();
00215 emit commandExecuted();
00216 if (m_redo != 0) {
00217 m_redo->setEnabled(true);
00218 m_redo->setText(i18n("&Redo: %1").arg(d->m_present->name()));
00219 }
00220 int index;
00221 if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.prev()!=0) {
00222 d->m_present=m_commands.current();
00223 if (m_undo != 0) {
00224 m_undo->setEnabled(true);
00225 m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00226 }
00227 --index;
00228 if(index==d->m_savedAt)
00229 emit documentRestored();
00230 }
00231 else {
00232 if (m_undo != 0) {
00233 m_undo->setEnabled(false);
00234 m_undo->setText(i18n("&Undo"));
00235 }
00236 if(d->m_savedAt==-42)
00237 emit documentRestored();
00238 m_first=true;
00239 }
00240 clipCommands();
00241 }
00242
00243 void KoCommandHistory::redo() {
00244
00245 int index;
00246 if(m_first) {
00247 d->m_present->execute();
00248 emit commandExecuted();
00249 m_first=false;
00250 m_commands.first();
00251 if(d->m_savedAt==0)
00252 emit documentRestored();
00253 }
00254 else if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.next()!=0) {
00255 d->m_present=m_commands.current();
00256 d->m_present->execute();
00257 emit commandExecuted();
00258 ++index;
00259 if(index==d->m_savedAt)
00260 emit documentRestored();
00261 }
00262
00263 if (m_undo != 0) {
00264 m_undo->setEnabled(true);
00265 m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
00266 }
00267
00268 if(m_commands.next()!=0) {
00269 if (m_redo != 0) {
00270 m_redo->setEnabled(true);
00271 m_redo->setText(i18n("&Redo: %1").arg(m_commands.current()->name()));
00272 }
00273 }
00274 else {
00275 if((m_redo != 0) && m_redo->isEnabled()) {
00276 m_redo->setEnabled(false);
00277 m_redo->setText(i18n("&Redo"));
00278 }
00279 }
00280 }
00281
00282 void KoCommandHistory::documentSaved() {
00283 if(d->m_present!=0 && !m_first)
00284 d->m_savedAt=m_commands.findRef(d->m_present);
00285 else if(d->m_present==0 && !m_first)
00286 d->m_savedAt=-42;
00287
00288 else if(m_first)
00289 d->m_savedAt=-42;
00290 }
00291
00292 void KoCommandHistory::setUndoLimit(int limit) {
00293
00294 if(limit>0 && limit!=m_undoLimit) {
00295 m_undoLimit=limit;
00296 clipCommands();
00297 }
00298 }
00299
00300 void KoCommandHistory::setRedoLimit(int limit) {
00301
00302 if(limit>0 && limit!=m_redoLimit) {
00303 m_redoLimit=limit;
00304 clipCommands();
00305 }
00306 }
00307
00308 void KoCommandHistory::clipCommands() {
00309
00310 int count=m_commands.count();
00311 if(count<=m_undoLimit && count<=m_redoLimit)
00312 return;
00313
00314 int index=m_commands.findRef(d->m_present);
00315 if(index>=m_undoLimit) {
00316 for(int i=0; i<=(index-m_undoLimit); ++i) {
00317 m_commands.removeFirst();
00318 --d->m_savedAt;
00319 if(d->m_savedAt==-1)
00320 d->m_savedAt=-42;
00321 }
00322 index=m_commands.findRef(d->m_present);
00323 count=m_commands.count();
00324
00325 if(d->m_savedAt!=-42 && d->m_savedAt<-1)
00326 d->m_savedAt=-1;
00327 }
00328
00329 if(m_first)
00330 index=-1;
00331 if((index+m_redoLimit+1)<count) {
00332 if(d->m_savedAt>(index+m_redoLimit))
00333 d->m_savedAt=-1;
00334 for(int i=0; i<(count-(index+m_redoLimit+1)); ++i)
00335 m_commands.removeLast();
00336 }
00337 }
00338
00339 void KoCommandHistory::slotUndoAboutToShow()
00340 {
00341 d->m_undoListBox->clear();
00342 slotChangeUndoNumberOfSelectedItem( -1 );
00343 int i = 0;
00344 QStringList lst;
00345 if (m_commands.findRef(d->m_present)!=-1)
00346 while ( m_commands.current() && i<10 )
00347 {
00348 lst.append(i18n("Undo: %1").arg(m_commands.current()->name()));
00349 m_commands.prev();
00350 }
00351 d->m_undoListBox->insertStringList( lst );
00352 }
00353
00354 void KoCommandHistory::slotUndoActivated( int pos )
00355 {
00356 kdDebug(230) << "KoCommandHistory::slotUndoActivated " << pos << endl;
00357 for ( int i = 0 ; i < pos+1; ++i )
00358 undo();
00359 m_undoPopup->hide();
00360 }
00361
00362 void KoCommandHistory::slotUndoActivated( QListBoxItem * item)
00363 {
00364 if ( item )
00365 slotUndoActivated( item->listBox()->index(item));
00366 }
00367
00368 void KoCommandHistory::slotRedoActivated( QListBoxItem * item)
00369 {
00370 if ( item )
00371 slotRedoActivated( item->listBox()->index(item));
00372 }
00373
00374 void KoCommandHistory::slotChangeUndoNumberOfSelectedItem( int pos)
00375 {
00376 d->m_undoLabel->setText( i18n("Undo %n action", "Undo %n actions", pos+1) );
00377 }
00378
00379 void KoCommandHistory::slotChangeRedoNumberOfSelectedItem( int pos)
00380 {
00381 d->m_redoLabel->setText( i18n("Redo %n action", "Redo %n actions", pos+1) );
00382 }
00383
00384
00385 void KoCommandHistory::slotRedoAboutToShow()
00386 {
00387 d->m_redoListBox->clear();
00388 slotChangeRedoNumberOfSelectedItem( -1 );
00389 QStringList lst;
00390 int i = 0;
00391 if (m_first)
00392 {
00393 d->m_present = m_commands.first();
00394 lst.append(i18n("Redo: %1").arg(d->m_present->name()));
00395 }
00396 if (m_commands.findRef(d->m_present)!=-1 && m_commands.next())
00397 while ( m_commands.current() && i<10 )
00398 {
00399 lst.append(i18n("Redo: %1").arg(m_commands.current()->name()));
00400 m_commands.next();
00401 }
00402 d->m_redoListBox->insertStringList( lst );
00403
00404 }
00405
00406 void KoCommandHistory::slotRedoActivated( int pos )
00407 {
00408 kdDebug(230) << "KoCommandHistory::slotRedoActivated " << pos << endl;
00409 for ( int i = 0 ; i < pos+1; ++i )
00410 redo();
00411 m_redoPopup->hide();
00412 }
00413
00414 void KoCommandHistory::updateActions()
00415 {
00416 if ( m_undo && m_redo )
00417 {
00418 m_undo->setEnabled( !m_first && ( d->m_present != 0L ) );
00419 m_redo->setEnabled(m_first || (m_commands.findRef(d->m_present)!=-1 && m_commands.next()!=0));
00420 }
00421 }
00422
00423 void KoCommandHistory::virtual_hook( int, void* )
00424 { }
00425
00426 #include "kocommandhistory.moc"