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