]> git.saurik.com Git - wxWidgets.git/blame - src/common/cmdproc.cpp
In the object destructor, Disassociate the object from its Cocoa counterpart
[wxWidgets.git] / src / common / cmdproc.cpp
CommitLineData
70050c82
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/common/cmdproc.cpp
3// Purpose: wxCommand and wxCommandProcessor classes
4// Author: Julian Smart (extracted from docview.h by VZ)
5// Modified by:
6// Created: 05.11.00
7// RCS-ID: $Id$
8// Copyright: (c) wxWindows team
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "cmdproc.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
32 #include "wx/intl.h"
33 #include "wx/string.h"
34 #include "wx/menu.h"
35#endif //WX_PRECOMP
36
37#include "wx/cmdproc.h"
38
39// ============================================================================
40// implementation
41// ============================================================================
42
43IMPLEMENT_CLASS(wxCommand, wxObject)
44IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject)
45
46// ----------------------------------------------------------------------------
47// wxCommand
48// ----------------------------------------------------------------------------
49
50wxCommand::wxCommand(bool canUndoIt, const wxString& name)
51{
52 m_canUndo = canUndoIt;
53 m_commandName = name;
54}
55
56wxCommand::~wxCommand()
57{
58}
59
60// ----------------------------------------------------------------------------
61// Command processor
62// ----------------------------------------------------------------------------
63
64wxCommandProcessor::wxCommandProcessor(int maxCommands)
65{
66 m_maxNoCommands = maxCommands;
70050c82
VZ
67#if wxUSE_MENUS
68 m_commandEditMenu = (wxMenu *) NULL;
69#endif // wxUSE_MENUS
6aa3ea88
JS
70 m_undoAccelerator = wxT("\tCtrl+Z");
71 m_redoAccelerator = wxT("\tCtrl+Y");
70050c82
VZ
72}
73
74wxCommandProcessor::~wxCommandProcessor()
75{
76 ClearCommands();
77}
78
79bool wxCommandProcessor::DoCommand(wxCommand& cmd)
80{
81 return cmd.Do();
82}
83
84bool wxCommandProcessor::UndoCommand(wxCommand& cmd)
85{
86 return cmd.Undo();
87}
88
89// Pass a command to the processor. The processor calls Do();
90// if successful, is appended to the command history unless
91// storeIt is FALSE.
92bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt)
93{
94 wxCHECK_MSG( command, FALSE, _T("no command in wxCommandProcessor::Submit") );
95
96 if ( !DoCommand(*command) )
ca1b5af1
VZ
97 {
98 // the user code expects the command to be deleted anyhow
99 delete command;
100
70050c82 101 return FALSE;
ca1b5af1 102 }
70050c82
VZ
103
104 if ( storeIt )
105 Store(command);
106
107 return TRUE;
108}
109
110void wxCommandProcessor::Store(wxCommand *command)
111{
112 wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") );
113
b1d4dd7a 114 if ( (int)m_commands.GetCount() == m_maxNoCommands )
70050c82 115 {
222ed1d6 116 wxList::compatibility_iterator firstNode = m_commands.GetFirst();
b1d4dd7a 117 wxCommand *firstCommand = (wxCommand *)firstNode->GetData();
70050c82 118 delete firstCommand;
222ed1d6 119 m_commands.Erase(firstNode);
70050c82
VZ
120 }
121
122 // Correct a bug: we must chop off the current 'branch'
123 // so that we're at the end of the command list.
124 if (!m_currentCommand)
125 ClearCommands();
126 else
127 {
222ed1d6 128 wxList::compatibility_iterator node = m_currentCommand->GetNext();
70050c82
VZ
129 while (node)
130 {
222ed1d6 131 wxList::compatibility_iterator next = node->GetNext();
b1d4dd7a 132 delete (wxCommand *)node->GetData();
222ed1d6 133 m_commands.Erase(node);
70050c82
VZ
134 node = next;
135 }
136 }
137
138 m_commands.Append(command);
b1d4dd7a 139 m_currentCommand = m_commands.GetLast();
70050c82
VZ
140 SetMenuStrings();
141}
142
143bool wxCommandProcessor::Undo()
144{
145 wxCommand *command = GetCurrentCommand();
146 if ( command && command->CanUndo() )
147 {
148 if ( UndoCommand(*command) )
149 {
b1d4dd7a 150 m_currentCommand = m_currentCommand->GetPrevious();
70050c82
VZ
151 SetMenuStrings();
152 return TRUE;
153 }
154 }
155
156 return FALSE;
157}
158
159bool wxCommandProcessor::Redo()
160{
161 wxCommand *redoCommand = (wxCommand *) NULL;
dfa4a244 162 wxList::compatibility_iterator redoNode = 0;
17271c79
VZ
163
164 if ( m_currentCommand )
70050c82 165 {
17271c79 166 // is there anything to redo?
b1d4dd7a 167 if ( m_currentCommand->GetNext() )
17271c79 168 {
b1d4dd7a
RL
169 redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
170 redoNode = m_currentCommand->GetNext();
17271c79 171 }
70050c82 172 }
17271c79 173 else // no current command, redo the first one
70050c82 174 {
b1d4dd7a 175 if (m_commands.GetCount() > 0)
70050c82 176 {
b1d4dd7a
RL
177 redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
178 redoNode = m_commands.GetFirst();
70050c82
VZ
179 }
180 }
181
182 if (redoCommand)
183 {
184 bool success = DoCommand(*redoCommand);
185 if (success)
186 {
187 m_currentCommand = redoNode;
188 SetMenuStrings();
189 return TRUE;
190 }
191 }
192 return FALSE;
193}
194
195bool wxCommandProcessor::CanUndo() const
196{
197 wxCommand *command = GetCurrentCommand();
198
199 return command && command->CanUndo();
200}
201
202bool wxCommandProcessor::CanRedo() const
203{
222ed1d6 204 if (m_currentCommand && !m_currentCommand->GetNext())
70050c82
VZ
205 return FALSE;
206
222ed1d6 207 if (m_currentCommand && m_currentCommand->GetNext())
70050c82
VZ
208 return TRUE;
209
222ed1d6 210 if (!m_currentCommand && (m_commands.GetCount() > 0))
70050c82
VZ
211 return TRUE;
212
213 return FALSE;
214}
215
216void wxCommandProcessor::Initialize()
217{
b1d4dd7a 218 m_currentCommand = m_commands.GetLast();
70050c82
VZ
219 SetMenuStrings();
220}
221
222void wxCommandProcessor::SetMenuStrings()
223{
224#if wxUSE_MENUS
225 if (m_commandEditMenu)
226 {
d863ed83
JS
227 wxString undoLabel = GetUndoMenuLabel();
228 wxString redoLabel = GetRedoMenuLabel();
229
230 m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel);
231 m_commandEditMenu->Enable(wxID_UNDO, CanUndo());
232
233 m_commandEditMenu->SetLabel(wxID_REDO, redoLabel);
234 m_commandEditMenu->Enable(wxID_REDO, CanRedo());
235 }
236#endif // wxUSE_MENUS
237}
238
239// Gets the current Undo menu label.
240wxString wxCommandProcessor::GetUndoMenuLabel() const
241{
242 wxString buf;
243 if (m_currentCommand)
244 {
b1d4dd7a 245 wxCommand *command = (wxCommand *)m_currentCommand->GetData();
d863ed83
JS
246 wxString commandName(command->GetName());
247 if (commandName == wxT("")) commandName = _("Unnamed command");
248 bool canUndo = command->CanUndo();
249 if (canUndo)
250 buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator;
251 else
252 buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator;
253 }
254 else
255 {
256 buf = _("&Undo") + m_undoAccelerator;
257 }
258
259 return buf;
260}
261
262// Gets the current Undo menu label.
263wxString wxCommandProcessor::GetRedoMenuLabel() const
264{
265 wxString buf;
266 if (m_currentCommand)
267 {
268 // We can redo, if we're not at the end of the history.
b1d4dd7a 269 if (m_currentCommand->GetNext())
70050c82 270 {
b1d4dd7a 271 wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
d863ed83
JS
272 wxString redoCommandName(redoCommand->GetName());
273 if (redoCommandName == wxT("")) redoCommandName = _("Unnamed command");
274 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
70050c82
VZ
275 }
276 else
277 {
d863ed83 278 buf = _("&Redo") + m_redoAccelerator;
70050c82
VZ
279 }
280 }
d863ed83
JS
281 else
282 {
b1d4dd7a 283 if (m_commands.GetCount() == 0)
d863ed83
JS
284 {
285 buf = _("&Redo") + m_redoAccelerator;
286 }
287 else
288 {
289 // currentCommand is NULL but there are commands: this means that
290 // we've undone to the start of the list, but can redo the first.
b1d4dd7a 291 wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
d863ed83
JS
292 wxString redoCommandName(redoCommand->GetName());
293 if (redoCommandName == wxT("")) redoCommandName = _("Unnamed command");
294 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
295 }
296 }
297 return buf;
70050c82
VZ
298}
299
300void wxCommandProcessor::ClearCommands()
301{
222ed1d6 302 wxList::compatibility_iterator node = m_commands.GetFirst();
70050c82
VZ
303 while (node)
304 {
b1d4dd7a 305 wxCommand *command = (wxCommand *)node->GetData();
70050c82 306 delete command;
222ed1d6 307 m_commands.Erase(node);
b1d4dd7a 308 node = m_commands.GetFirst();
70050c82 309 }
222ed1d6 310 m_currentCommand = wxList::compatibility_iterator();
70050c82
VZ
311}
312
313