Return after activating already opened document in wxDocManager.
[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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/intl.h"
29 #include "wx/string.h"
30 #include "wx/menu.h"
31 #include "wx/accel.h"
32 #endif //WX_PRECOMP
33
34 #include "wx/cmdproc.h"
35
36 // ============================================================================
37 // implementation
38 // ============================================================================
39
40 IMPLEMENT_CLASS(wxCommand, wxObject)
41 IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject)
42
43 // ----------------------------------------------------------------------------
44 // wxCommand
45 // ----------------------------------------------------------------------------
46
47 wxCommand::wxCommand(bool canUndoIt, const wxString& name)
48 {
49 m_canUndo = canUndoIt;
50 m_commandName = name;
51 }
52
53 // ----------------------------------------------------------------------------
54 // Command processor
55 // ----------------------------------------------------------------------------
56
57 wxCommandProcessor::wxCommandProcessor(int maxCommands)
58 {
59 m_maxNoCommands = maxCommands;
60 #if wxUSE_MENUS
61 m_commandEditMenu = NULL;
62 #endif // wxUSE_MENUS
63
64 #if wxUSE_ACCEL
65 m_undoAccelerator = '\t' + wxAcceleratorEntry(wxACCEL_CTRL, 'Z').ToString();
66 m_redoAccelerator = '\t' + wxAcceleratorEntry(wxACCEL_CTRL, 'Y').ToString();
67 #endif // wxUSE_ACCEL
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, wxT("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, wxT("no command in wxCommandProcessor::Store") );
114
115 // Correct a bug: we must chop off the current 'branch'
116 // so that we're at the end of the command list.
117 if (!m_currentCommand)
118 ClearCommands();
119 else
120 {
121 wxList::compatibility_iterator node = m_currentCommand->GetNext();
122 while (node)
123 {
124 wxList::compatibility_iterator next = node->GetNext();
125 delete (wxCommand *)node->GetData();
126 m_commands.Erase(node);
127
128 // Make sure m_lastSavedCommand won't point to freed memory
129 if ( m_lastSavedCommand == node )
130 m_lastSavedCommand = wxList::compatibility_iterator();
131
132 node = next;
133 }
134 }
135
136 if ( (int)m_commands.GetCount() == m_maxNoCommands )
137 {
138 wxList::compatibility_iterator firstNode = m_commands.GetFirst();
139 wxCommand *firstCommand = (wxCommand *)firstNode->GetData();
140 delete firstCommand;
141 m_commands.Erase(firstNode);
142
143 // Make sure m_lastSavedCommand won't point to freed memory
144 if ( m_lastSavedCommand == firstNode )
145 m_lastSavedCommand = wxList::compatibility_iterator();
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 = 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