lib Library API Documentation

kocommandhistory.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2000 Werner Trobin <trobin@kde.org>
00003    Copyright (C) 2000 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
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, /*KStdAction::stdName( KStdAction::Undo )*/"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);//todo fix me
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, /*KStdAction::stdName( KStdAction::Redo )*/
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);//todo fix me
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         // truncate history
00169         unsigned int count=m_commands.count();
00170         for(unsigned int i=index+2; i<count; ++i)
00171             m_commands.removeLast();
00172         // check whether we still can reach savedAt
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 { // either this is the first time we add a Command or something has gone wrong
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;    // Michael B: yes, that *is* correct :-)
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(); // only needed here and in addCommand, NOT in redo
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;  // this value signals that the document has
00287                         // been saved with an empty history.
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); // calculate the new
00323         count=m_commands.count();            // values (for the redo-branch :)
00324         // make it easier for us... d->m_savedAt==-1 -> invalid
00325         if(d->m_savedAt!=-42 && d->m_savedAt<-1)
00326             d->m_savedAt=-1;
00327     }
00328     // adjust the index if it's the first command
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 ) // TODO make number of items configurable ?
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 ) // TODO make number of items configurable ?
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 { /*BASE::virtual_hook( id, data );*/ }
00425 
00426 #include "kocommandhistory.moc"
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Mar 11 11:47:40 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003