kcommand.cpp
/* This file is part of the KDE project
Copyright (C) 2000 Werner Trobin <trobin@kde.org>
Copyright (C) 2000 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kcommand.h"
#include <kaction.h>
#include <kstdaccel.h>
#include <kstdaction.h>
#include <kdebug.h>
#include <klocale.h>
#include <kpopupmenu.h>
KCommand::~KCommand()
{
}
KMacroCommand::KMacroCommand( const QString & name ) : KNamedCommand(name)
{
m_commands.setAutoDelete(true);
}
void KMacroCommand::addCommand(KCommand *command)
{
m_commands.append(command);
}
void KMacroCommand::execute()
{
QPtrListIterator<KCommand> it(m_commands);
for ( ; it.current() ; ++it )
it.current()->execute();
}
void KMacroCommand::unexecute()
{
QPtrListIterator<KCommand> it(m_commands);
it.toLast();
for ( ; it.current() ; --it )
it.current()->unexecute();
}
class KCommandHistory::KCommandHistoryPrivate {
public:
KCommandHistoryPrivate() {
m_savedAt=-1;
m_present=0;
}
~KCommandHistoryPrivate() {}
int m_savedAt;
KCommand *m_present;
};
KCommandHistory::KCommandHistory() :
m_undo(0), m_redo(0), m_undoLimit(50), m_redoLimit(30), m_first(false)
{
d=new KCommandHistoryPrivate();
m_commands.setAutoDelete(true);
clear();
}
KCommandHistory::KCommandHistory(KActionCollection * actionCollection, bool withMenus) :
m_undoLimit(50), m_redoLimit(30), m_first(false)
{
d=new KCommandHistoryPrivate();
if (withMenus)
{
KToolBarPopupAction * undo = new KToolBarPopupAction( i18n("&Undo"), "undo",
KStdAccel::shortcut(KStdAccel::Undo), this, SLOT( undo() ),
actionCollection, KStdAction::stdName( KStdAction::Undo ) );
connect( undo->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( slotUndoAboutToShow() ) );
connect( undo->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( slotUndoActivated( int ) ) );
m_undo = undo;
m_undoPopup = undo->popupMenu();
KToolBarPopupAction * redo = new KToolBarPopupAction( i18n("&Redo"), "redo",
KStdAccel::shortcut(KStdAccel::Redo), this, SLOT( redo() ),
actionCollection, KStdAction::stdName( KStdAction::Redo ) );
connect( redo->popupMenu(), SIGNAL( aboutToShow() ), this, SLOT( slotRedoAboutToShow() ) );
connect( redo->popupMenu(), SIGNAL( activated( int ) ), this, SLOT( slotRedoActivated( int ) ) );
m_redo = redo;
m_redoPopup = redo->popupMenu();
}
else
{
m_undo = KStdAction::undo( this, SLOT( undo() ), actionCollection );
m_redo = KStdAction::redo( this, SLOT( redo() ), actionCollection );
m_undoPopup = 0L;
m_redoPopup = 0L;
}
m_commands.setAutoDelete(true);
clear();
}
KCommandHistory::~KCommandHistory() {
delete d;
}
void KCommandHistory::clear() {
if (m_undo) {
m_undo->setEnabled(false);
m_undo->setText(i18n("&Undo"));
}
if (m_redo) {
m_redo->setEnabled(false);
m_redo->setText(i18n("&Redo"));
}
d->m_present = 0L;
d->m_savedAt=-42;
}
void KCommandHistory::addCommand(KCommand *command, bool execute) {
if(!command)
return;
int index;
if(d->m_present && (index=m_commands.findRef(d->m_present))!=-1) {
if (m_first)
--index;
m_commands.insert(index+1, command);
// truncate history
unsigned int count=m_commands.count();
for(unsigned int i=index+2; i<count; ++i)
m_commands.removeLast();
// check whether we still can reach savedAt
if(index<d->m_savedAt)
d->m_savedAt=-1;
d->m_present=command;
m_first=false;
if (m_undo) {
m_undo->setEnabled(true);
m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
}
if((m_redo) && m_redo->isEnabled()) {
m_redo->setEnabled(false);
m_redo->setText(i18n("&Redo"));
}
clipCommands();
}
else { // either this is the first time we add a Command or something has gone wrong
kdDebug(230) << "Initializing the Command History" << endl;
m_commands.clear();
m_commands.append(command);
d->m_present=command;
if (m_undo) {
m_undo->setEnabled(true);
m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
}
if (m_redo) {
m_redo->setEnabled(false);
m_redo->setText(i18n("&Redo"));
}
m_first=false; // Michael B: yes, that *is* correct :-)
}
if ( execute )
{
command->execute();
emit commandExecuted();
emit commandExecuted(command);
}
}
void KCommandHistory::undo() {
if (m_first || !d->m_present)
return;
d->m_present->unexecute();
emit commandExecuted();
emit commandExecuted(d->m_present);
if (m_redo) {
m_redo->setEnabled(true);
m_redo->setText(i18n("&Redo: %1").arg(d->m_present->name()));
}
int index;
if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.prev()) {
d->m_present=m_commands.current();
if (m_undo) {
m_undo->setEnabled(true);
m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
}
--index;
if(index==d->m_savedAt)
emit documentRestored();
}
else {
if (m_undo) {
m_undo->setEnabled(false);
m_undo->setText(i18n("&Undo"));
}
if(d->m_savedAt==-42)
emit documentRestored();
m_first=true;
}
clipCommands(); // only needed here and in addCommand, NOT in redo
}
void KCommandHistory::redo() {
int index;
if(m_first) {
d->m_present->execute();
emit commandExecuted();
emit commandExecuted(d->m_present);
m_first=false;
m_commands.first();
if(!d->m_savedAt)
emit documentRestored();
}
else if((index=m_commands.findRef(d->m_present))!=-1 && m_commands.next()) {
d->m_present=m_commands.current();
d->m_present->execute();
emit commandExecuted();
emit commandExecuted(d->m_present);
++index;
if(index==d->m_savedAt)
emit documentRestored();
}
if (m_undo) {
m_undo->setEnabled(true);
m_undo->setText(i18n("&Undo: %1").arg(d->m_present->name()));
}
if(m_commands.next()) {
if (m_redo) {
m_redo->setEnabled(true);
m_redo->setText(i18n("&Redo: %1").arg(m_commands.current()->name()));
}
}
else {
if((m_redo) && m_redo->isEnabled()) {
m_redo->setEnabled(false);
m_redo->setText(i18n("&Redo"));
}
}
}
void KCommandHistory::documentSaved() {
if(d->m_present && !m_first)
d->m_savedAt=m_commands.findRef(d->m_present);
else if(!d->m_present && !m_first)
d->m_savedAt=-42; // this value signals that the document has
// been saved with an empty history.
else if(m_first)
d->m_savedAt=-42;
}
void KCommandHistory::setUndoLimit(int limit) {
if(limit>0 && limit!=m_undoLimit) {
m_undoLimit=limit;
clipCommands();
}
}
void KCommandHistory::setRedoLimit(int limit) {
if(limit>0 && limit!=m_redoLimit) {
m_redoLimit=limit;
clipCommands();
}
}
void KCommandHistory::clipCommands() {
int count=m_commands.count();
if(count<=m_undoLimit && count<=m_redoLimit)
return;
int index=m_commands.findRef(d->m_present);
if(index>=m_undoLimit) {
for(int i=0; i<=(index-m_undoLimit); ++i) {
m_commands.removeFirst();
--d->m_savedAt;
if(d->m_savedAt==-1)
d->m_savedAt=-42;
}
index=m_commands.findRef(d->m_present); // calculate the new
count=m_commands.count(); // values (for the redo-branch :)
// make it easier for us... d->m_savedAt==-1 -> invalid
if(d->m_savedAt!=-42 && d->m_savedAt<-1)
d->m_savedAt=-1;
}
// adjust the index if it's the first command
if(m_first)
index=-1;
if((index+m_redoLimit+1)<count) {
if(d->m_savedAt>(index+m_redoLimit))
d->m_savedAt=-1;
for(int i=0; i<(count-(index+m_redoLimit+1)); ++i)
m_commands.removeLast();
}
}
void KCommandHistory::slotUndoAboutToShow()
{
m_undoPopup->clear();
int i = 0;
if (m_commands.findRef(d->m_present)!=-1)
while ( m_commands.current() && i<10 ) // TODO make number of items configurable ?
{
m_undoPopup->insertItem( i18n("Undo: %1").arg(m_commands.current()->name()), i++ );
m_commands.prev();
}
}
void KCommandHistory::slotUndoActivated( int pos )
{
kdDebug(230) << "KCommandHistory::slotUndoActivated " << pos << endl;
for ( int i = 0 ; i < pos+1; ++i )
undo();
}
void KCommandHistory::slotRedoAboutToShow()
{
m_redoPopup->clear();
int i = 0;
if (m_first)
{
d->m_present = m_commands.first();
m_redoPopup->insertItem( i18n("Redo: %1").arg(d->m_present->name()), i++ );
}
if (m_commands.findRef(d->m_present)!=-1 && m_commands.next())
while ( m_commands.current() && i<10 ) // TODO make number of items configurable ?
{
m_redoPopup->insertItem( i18n("Redo: %1").arg(m_commands.current()->name()), i++ );
m_commands.next();
}
}
void KCommandHistory::slotRedoActivated( int pos )
{
kdDebug(230) << "KCommandHistory::slotRedoActivated " << pos << endl;
for ( int i = 0 ; i < pos+1; ++i )
redo();
}
void KCommandHistory::updateActions()
{
if ( m_undo && m_redo )
{
m_undo->setEnabled( !m_first && ( d->m_present ) );
m_redo->setEnabled(m_first || (m_commands.findRef(d->m_present)!=-1 && m_commands.next()));
}
}
void KCommand::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
void KNamedCommand::virtual_hook( int id, void* data )
{ KCommand::virtual_hook( id, data ); }
void KMacroCommand::virtual_hook( int id, void* data )
{ KNamedCommand::virtual_hook( id, data ); }
void KCommandHistory::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }
#include "kcommand.moc"
KActionCollection
A managed set of KAction objects.
Definition: kactioncollection.h:78
KCommandHistory::commandExecuted
void commandExecuted()
Emitted every time a command is executed (whether by addCommand, undo or redo).
KToolBarPopupAction::popupMenu
KPopupMenu * popupMenu() const
The popup menu that is shown when clicking (some time) on the toolbar button.
Definition: kactionclasses.cpp:1968
KStdAccel::shortcut
const KShortcut & shortcut(StdAccel id)
KCommandHistory::documentRestored
void documentRestored()
Emitted every time we reach the index where you saved the document for the last time.
KStdAction::undo
KAction * undo(const QObject *recvr, const char *slot, KActionCollection *parent, const char *name)
Undo the last operation.
Definition: kstdaction.cpp:164
KCommand::execute
virtual void execute()=0
The main method: executes this command.
KMacroCommand::execute
virtual void execute()
Executes this command, i.e.
Definition: kcommand.cpp:43
kdDebug
kdbgstream kdDebug(int area=0)
KCommandHistory::redo
virtual void redo()
Redoes the last undone action.
Definition: kcommand.cpp:217
KStdAction::redo
KAction * redo(const QObject *recvr, const char *slot, KActionCollection *parent, const char *name)
Redo the last operation.
Definition: kstdaction.cpp:166
klocale.h
KCommandHistory::documentSaved
virtual void documentSaved()
Remembers when you saved the document.
Definition: kcommand.cpp:258
KMacroCommand::addCommand
void addCommand(KCommand *command)
Appends a command to this macro command.
Definition: kcommand.cpp:38
KCommandHistory::updateActions
void updateActions()
Enable or disable the undo and redo actions.
Definition: kcommand.cpp:358
KCommandHistory::undo
virtual void undo()
Undoes the last action.
Definition: kcommand.cpp:182
KMacroCommand::KMacroCommand
KMacroCommand(const QString &name)
Creates a macro command.
Definition: kcommand.cpp:33
KMacroCommand::unexecute
virtual void unexecute()
Undoes the execution of this command, i.e.
Definition: kcommand.cpp:50
KAction::setText
virtual void setText(const QString &text)
Sets the text associated with this action.
Definition: kaction.cpp:863
KCommandHistory::clear
void clear()
Erases all the undo/redo history.
Definition: kcommand.cpp:117
KCommand
The abstract base class for all Commands.
Definition: kcommand.h:37
KCommandHistory::setUndoLimit
void setUndoLimit(int limit)
Sets the maximum number of items in the undo history.
Definition: kcommand.cpp:268
KCommandHistory::~KCommandHistory
virtual ~KCommandHistory()
Destructs the command history object.
Definition: kcommand.cpp:113
KCommandHistory::KCommandHistory
KCommandHistory()
Creates a command history, to store commands.
Definition: kcommand.cpp:72
KNamedCommand
A command which stores its name.
Definition: kcommand.h:78
KStdAction::stdName
const char * stdName(StdAction act_enum)
Definition: kstdaction.h:192
KToolBarPopupAction
This action is a normal action everywhere, except in a toolbar where it also has a popupmenu (optionn...
Definition: kactionclasses.h:1086
KCommandHistory::setRedoLimit
void setRedoLimit(int limit)
Sets the maximum number of items in the redo history.
Definition: kcommand.cpp:276
endl
kndbgstream & endl(kndbgstream &s)
KAction::setEnabled
virtual void setEnabled(bool enable)
Enables or disables this action.
Definition: kaction.cpp:816
KCommandHistory::addCommand
void addCommand(KCommand *command, bool execute=true)
Adds a command to the history.
Definition: kcommand.cpp:130
KAction::isEnabled
virtual bool isEnabled() const
Returns true if this action is enabled.
Definition: kaction.cpp:586

KDE Home | KDE Accessibility Home | Description of Access Keys