diff --git a/src/common/cmdproc.cpp b/src/common/cmdproc.cpp new file mode 100644 index 0000000000..c2d44c895b --- /dev/null +++ b/src/common/cmdproc.cpp @@ -0,0 +1,286 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/cmdproc.cpp +// Purpose: wxCommand and wxCommandProcessor classes +// Author: Julian Smart (extracted from docview.h by VZ) +// Modified by: +// Created: 05.11.00 +// RCS-ID: $Id$ +// Copyright: (c) wxWindows team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "cmdproc.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/string.h" + #include "wx/menu.h" +#endif //WX_PRECOMP + +#include "wx/cmdproc.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_CLASS(wxCommand, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject) + +// ---------------------------------------------------------------------------- +// wxCommand +// ---------------------------------------------------------------------------- + +wxCommand::wxCommand(bool canUndoIt, const wxString& name) +{ + m_canUndo = canUndoIt; + m_commandName = name; +} + +wxCommand::~wxCommand() +{ +} + +// ---------------------------------------------------------------------------- +// Command processor +// ---------------------------------------------------------------------------- + +wxCommandProcessor::wxCommandProcessor(int maxCommands) +{ + m_maxNoCommands = maxCommands; + m_currentCommand = (wxNode *) NULL; +#if wxUSE_MENUS + m_commandEditMenu = (wxMenu *) NULL; +#endif // wxUSE_MENUS +} + +wxCommandProcessor::~wxCommandProcessor() +{ + ClearCommands(); +} + +bool wxCommandProcessor::DoCommand(wxCommand& cmd) +{ + return cmd.Do(); +} + +bool wxCommandProcessor::UndoCommand(wxCommand& cmd) +{ + return cmd.Undo(); +} + +// Pass a command to the processor. The processor calls Do(); +// if successful, is appended to the command history unless +// storeIt is FALSE. +bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt) +{ + wxCHECK_MSG( command, FALSE, _T("no command in wxCommandProcessor::Submit") ); + + if ( !DoCommand(*command) ) + return FALSE; + + if ( storeIt ) + Store(command); + + return TRUE; +} + +void wxCommandProcessor::Store(wxCommand *command) +{ + wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") ); + + if (m_commands.Number() == m_maxNoCommands) + { + wxNode *firstNode = m_commands.First(); + wxCommand *firstCommand = (wxCommand *)firstNode->Data(); + delete firstCommand; + delete firstNode; + } + + // Correct a bug: we must chop off the current 'branch' + // so that we're at the end of the command list. + if (!m_currentCommand) + ClearCommands(); + else + { + wxNode *node = m_currentCommand->Next(); + while (node) + { + wxNode *next = node->Next(); + delete (wxCommand *)node->Data(); + delete node; + node = next; + } + } + + m_commands.Append(command); + m_currentCommand = m_commands.Last(); + SetMenuStrings(); +} + +bool wxCommandProcessor::Undo() +{ + wxCommand *command = GetCurrentCommand(); + if ( command && command->CanUndo() ) + { + if ( UndoCommand(*command) ) + { + m_currentCommand = m_currentCommand->Previous(); + SetMenuStrings(); + return TRUE; + } + } + + return FALSE; +} + +bool wxCommandProcessor::Redo() +{ + wxCommand *redoCommand = (wxCommand *) NULL; + wxNode *redoNode = (wxNode *) NULL; + if (m_currentCommand && m_currentCommand->Next()) + { + redoCommand = (wxCommand *)m_currentCommand->Next()->Data(); + redoNode = m_currentCommand->Next(); + } + else + { + if (m_commands.Number() > 0) + { + redoCommand = (wxCommand *)m_commands.First()->Data(); + redoNode = m_commands.First(); + } + } + + if (redoCommand) + { + bool success = DoCommand(*redoCommand); + if (success) + { + m_currentCommand = redoNode; + SetMenuStrings(); + return TRUE; + } + } + return FALSE; +} + +bool wxCommandProcessor::CanUndo() const +{ + wxCommand *command = GetCurrentCommand(); + + return command && command->CanUndo(); +} + +bool wxCommandProcessor::CanRedo() const +{ + if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() == (wxNode*) NULL)) + return FALSE; + + if ((m_currentCommand != (wxNode*) NULL) && (m_currentCommand->Next() != (wxNode*) NULL)) + return TRUE; + + if ((m_currentCommand == (wxNode*) NULL) && (m_commands.Number() > 0)) + return TRUE; + + return FALSE; +} + +void wxCommandProcessor::Initialize() +{ + m_currentCommand = m_commands.Last(); + SetMenuStrings(); +} + +void wxCommandProcessor::SetMenuStrings() +{ +#if wxUSE_MENUS + if (m_commandEditMenu) + { + wxString buf; + if (m_currentCommand) + { + wxCommand *command = (wxCommand *)m_currentCommand->Data(); + wxString commandName(command->GetName()); + if (commandName == wxT("")) commandName = _("Unnamed command"); + bool canUndo = command->CanUndo(); + if (canUndo) + buf = wxString(_("&Undo ")) + commandName; + else + buf = wxString(_("Can't &Undo ")) + commandName; + + m_commandEditMenu->SetLabel(wxID_UNDO, buf); + m_commandEditMenu->Enable(wxID_UNDO, canUndo); + + // We can redo, if we're not at the end of the history. + if (m_currentCommand->Next()) + { + wxCommand *redoCommand = (wxCommand *)m_currentCommand->Next()->Data(); + wxString redoCommandName(redoCommand->GetName()); + if (redoCommandName == wxT("")) redoCommandName = _("Unnamed command"); + buf = wxString(_("&Redo ")) + redoCommandName; + m_commandEditMenu->SetLabel(wxID_REDO, buf); + m_commandEditMenu->Enable(wxID_REDO, TRUE); + } + else + { + m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo")); + m_commandEditMenu->Enable(wxID_REDO, FALSE); + } + } + else + { + m_commandEditMenu->SetLabel(wxID_UNDO, _("&Undo")); + m_commandEditMenu->Enable(wxID_UNDO, FALSE); + + if (m_commands.Number() == 0) + { + m_commandEditMenu->SetLabel(wxID_REDO, _("&Redo")); + m_commandEditMenu->Enable(wxID_REDO, FALSE); + } + else + { + // currentCommand is NULL but there are commands: this means that + // we've undone to the start of the list, but can redo the first. + wxCommand *redoCommand = (wxCommand *)m_commands.First()->Data(); + wxString redoCommandName(redoCommand->GetName()); + if (redoCommandName == wxT("")) redoCommandName = _("Unnamed command"); + buf = wxString(_("&Redo ")) + redoCommandName; + m_commandEditMenu->SetLabel(wxID_REDO, buf); + m_commandEditMenu->Enable(wxID_REDO, TRUE); + } + } + } +#endif // wxUSE_MENUS +} + +void wxCommandProcessor::ClearCommands() +{ + wxNode *node = m_commands.First(); + while (node) + { + wxCommand *command = (wxCommand *)node->Data(); + delete command; + delete node; + node = m_commands.First(); + } + m_currentCommand = (wxNode *) NULL; +} + +