]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdproc.cpp
fix wxString::Replace when new strings are longer than old string
[wxWidgets.git] / src / common / cmdproc.cpp
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) wxWidgets team
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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
43 IMPLEMENT_CLASS(wxCommand, wxObject)
44 IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject)
45
46 // ----------------------------------------------------------------------------
47 // wxCommand
48 // ----------------------------------------------------------------------------
49
50 wxCommand::wxCommand(bool canUndoIt, const wxString& name)
51 {
52 m_canUndo = canUndoIt;
53 m_commandName = name;
54 }
55
56 // ----------------------------------------------------------------------------
57 // Command processor
58 // ----------------------------------------------------------------------------
59
60 wxCommandProcessor::wxCommandProcessor(int maxCommands)
61 {
62 m_maxNoCommands = maxCommands;
63 #if wxUSE_MENUS
64 m_commandEditMenu = (wxMenu *) NULL;
65 #endif // wxUSE_MENUS
66 m_undoAccelerator = wxT("\tCtrl+Z");
67 m_redoAccelerator = wxT("\tCtrl+Y");
68
69 m_lastSavedCommand =
70 m_currentCommand = wxList::compatibility_iterator();
71 }
72
73 wxCommandProcessor::~wxCommandProcessor()
74 {
75 ClearCommands();
76 }
77
78 bool wxCommandProcessor::DoCommand(wxCommand& cmd)
79 {
80 return cmd.Do();
81 }
82
83 bool wxCommandProcessor::UndoCommand(wxCommand& cmd)
84 {
85 return cmd.Undo();
86 }
87
88 // Pass a command to the processor. The processor calls Do();
89 // if successful, is appended to the command history unless
90 // storeIt is false.
91 bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt)
92 {
93 wxCHECK_MSG( command, false, _T("no command in wxCommandProcessor::Submit") );
94
95 if ( !DoCommand(*command) )
96 {
97 // the user code expects the command to be deleted anyhow
98 delete command;
99
100 return false;
101 }
102
103 if ( storeIt )
104 Store(command);
105 else
106 delete command;
107
108 return true;
109 }
110
111 void wxCommandProcessor::Store(wxCommand *command)
112 {
113 wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") );
114
115 if ( (int)m_commands.GetCount() == m_maxNoCommands )
116 {
117 wxList::compatibility_iterator firstNode = m_commands.GetFirst();
118 wxCommand *firstCommand = (wxCommand *)firstNode->GetData();
119 delete firstCommand;
120 m_commands.Erase(firstNode);
121
122 // Make sure m_lastSavedCommand won't point to freed memory
123 if ( m_lastSavedCommand == firstNode )
124 m_lastSavedCommand = wxList::compatibility_iterator();
125 }
126
127 // Correct a bug: we must chop off the current 'branch'
128 // so that we're at the end of the command list.
129 if (!m_currentCommand)
130 ClearCommands();
131 else
132 {
133 wxList::compatibility_iterator node = m_currentCommand->GetNext();
134 while (node)
135 {
136 wxList::compatibility_iterator next = node->GetNext();
137 delete (wxCommand *)node->GetData();
138 m_commands.Erase(node);
139
140 // Make sure m_lastSavedCommand won't point to freed memory
141 if ( m_lastSavedCommand == node )
142 m_lastSavedCommand = wxList::compatibility_iterator();
143
144 node = next;
145 }
146 }
147
148 m_commands.Append(command);
149 m_currentCommand = m_commands.GetLast();
150 SetMenuStrings();
151 }
152
153 bool wxCommandProcessor::Undo()
154 {
155 wxCommand *command = GetCurrentCommand();
156 if ( command && command->CanUndo() )
157 {
158 if ( UndoCommand(*command) )
159 {
160 m_currentCommand = m_currentCommand->GetPrevious();
161 SetMenuStrings();
162 return true;
163 }
164 }
165
166 return false;
167 }
168
169 bool wxCommandProcessor::Redo()
170 {
171 wxCommand *redoCommand = (wxCommand *) NULL;
172 wxList::compatibility_iterator redoNode
173 #if !wxUSE_STL
174 = NULL // just to avoid warnings
175 #endif // !wxUSE_STL
176 ;
177
178 if ( m_currentCommand )
179 {
180 // is there anything to redo?
181 if ( m_currentCommand->GetNext() )
182 {
183 redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
184 redoNode = m_currentCommand->GetNext();
185 }
186 }
187 else // no current command, redo the first one
188 {
189 if (m_commands.GetCount() > 0)
190 {
191 redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
192 redoNode = m_commands.GetFirst();
193 }
194 }
195
196 if (redoCommand)
197 {
198 bool success = DoCommand(*redoCommand);
199 if (success)
200 {
201 m_currentCommand = redoNode;
202 SetMenuStrings();
203 return true;
204 }
205 }
206 return false;
207 }
208
209 bool wxCommandProcessor::CanUndo() const
210 {
211 wxCommand *command = GetCurrentCommand();
212
213 return command && command->CanUndo();
214 }
215
216 bool wxCommandProcessor::CanRedo() const
217 {
218 if (m_currentCommand && !m_currentCommand->GetNext())
219 return false;
220
221 if (m_currentCommand && m_currentCommand->GetNext())
222 return true;
223
224 if (!m_currentCommand && (m_commands.GetCount() > 0))
225 return true;
226
227 return false;
228 }
229
230 void wxCommandProcessor::Initialize()
231 {
232 m_currentCommand = m_commands.GetLast();
233 SetMenuStrings();
234 }
235
236 void wxCommandProcessor::SetMenuStrings()
237 {
238 #if wxUSE_MENUS
239 if (m_commandEditMenu)
240 {
241 wxString undoLabel = GetUndoMenuLabel();
242 wxString redoLabel = GetRedoMenuLabel();
243
244 m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel);
245 m_commandEditMenu->Enable(wxID_UNDO, CanUndo());
246
247 m_commandEditMenu->SetLabel(wxID_REDO, redoLabel);
248 m_commandEditMenu->Enable(wxID_REDO, CanRedo());
249 }
250 #endif // wxUSE_MENUS
251 }
252
253 // Gets the current Undo menu label.
254 wxString wxCommandProcessor::GetUndoMenuLabel() const
255 {
256 wxString buf;
257 if (m_currentCommand)
258 {
259 wxCommand *command = (wxCommand *)m_currentCommand->GetData();
260 wxString commandName(command->GetName());
261 if (commandName.empty()) commandName = _("Unnamed command");
262 bool canUndo = command->CanUndo();
263 if (canUndo)
264 buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator;
265 else
266 buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator;
267 }
268 else
269 {
270 buf = _("&Undo") + m_undoAccelerator;
271 }
272
273 return buf;
274 }
275
276 // Gets the current Undo menu label.
277 wxString wxCommandProcessor::GetRedoMenuLabel() const
278 {
279 wxString buf;
280 if (m_currentCommand)
281 {
282 // We can redo, if we're not at the end of the history.
283 if (m_currentCommand->GetNext())
284 {
285 wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
286 wxString redoCommandName(redoCommand->GetName());
287 if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
288 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
289 }
290 else
291 {
292 buf = _("&Redo") + m_redoAccelerator;
293 }
294 }
295 else
296 {
297 if (m_commands.GetCount() == 0)
298 {
299 buf = _("&Redo") + m_redoAccelerator;
300 }
301 else
302 {
303 // currentCommand is NULL but there are commands: this means that
304 // we've undone to the start of the list, but can redo the first.
305 wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
306 wxString redoCommandName(redoCommand->GetName());
307 if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
308 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
309 }
310 }
311 return buf;
312 }
313
314 void wxCommandProcessor::ClearCommands()
315 {
316 wxList::compatibility_iterator node = m_commands.GetFirst();
317 while (node)
318 {
319 wxCommand *command = (wxCommand *)node->GetData();
320 delete command;
321 m_commands.Erase(node);
322 node = m_commands.GetFirst();
323 }
324
325 m_currentCommand = wxList::compatibility_iterator();
326 m_lastSavedCommand = wxList::compatibility_iterator();
327 }
328
329