]> git.saurik.com Git - wxWidgets.git/blame - src/common/cmdproc.cpp
wxMessageBox off the main thread lost result code.
[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
77ffb593 7// Copyright: (c) wxWidgets team
65571936 8// Licence: wxWindows licence
70050c82
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
70050c82
VZ
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#ifndef WX_PRECOMP
27 #include "wx/intl.h"
28 #include "wx/string.h"
29 #include "wx/menu.h"
62b50655 30 #include "wx/accel.h"
70050c82
VZ
31#endif //WX_PRECOMP
32
33#include "wx/cmdproc.h"
34
35// ============================================================================
36// implementation
37// ============================================================================
38
39IMPLEMENT_CLASS(wxCommand, wxObject)
40IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject)
41
42// ----------------------------------------------------------------------------
43// wxCommand
44// ----------------------------------------------------------------------------
45
46wxCommand::wxCommand(bool canUndoIt, const wxString& name)
47{
48 m_canUndo = canUndoIt;
49 m_commandName = name;
50}
51
70050c82
VZ
52// ----------------------------------------------------------------------------
53// Command processor
54// ----------------------------------------------------------------------------
55
56wxCommandProcessor::wxCommandProcessor(int maxCommands)
57{
58 m_maxNoCommands = maxCommands;
70050c82 59#if wxUSE_MENUS
d3b9f782 60 m_commandEditMenu = NULL;
70050c82 61#endif // wxUSE_MENUS
d98c269b
VZ
62
63#if wxUSE_ACCEL
675ec665
SC
64 m_undoAccelerator = '\t' + wxAcceleratorEntry(wxACCEL_CTRL, 'Z').ToString();
65 m_redoAccelerator = '\t' + wxAcceleratorEntry(wxACCEL_CTRL, 'Y').ToString();
d98c269b 66#endif // wxUSE_ACCEL
f260c476
VZ
67
68 m_lastSavedCommand =
69 m_currentCommand = wxList::compatibility_iterator();
70050c82
VZ
70}
71
72wxCommandProcessor::~wxCommandProcessor()
73{
74 ClearCommands();
75}
76
77bool wxCommandProcessor::DoCommand(wxCommand& cmd)
78{
79 return cmd.Do();
80}
81
82bool wxCommandProcessor::UndoCommand(wxCommand& cmd)
83{
84 return cmd.Undo();
85}
86
87// Pass a command to the processor. The processor calls Do();
88// if successful, is appended to the command history unless
c9d59ee7 89// storeIt is false.
70050c82
VZ
90bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt)
91{
9a83f860 92 wxCHECK_MSG( command, false, wxT("no command in wxCommandProcessor::Submit") );
70050c82
VZ
93
94 if ( !DoCommand(*command) )
ca1b5af1
VZ
95 {
96 // the user code expects the command to be deleted anyhow
97 delete command;
98
c9d59ee7 99 return false;
ca1b5af1 100 }
70050c82
VZ
101
102 if ( storeIt )
103 Store(command);
f530fa27
VZ
104 else
105 delete command;
70050c82 106
c9d59ee7 107 return true;
70050c82
VZ
108}
109
110void wxCommandProcessor::Store(wxCommand *command)
111{
9a83f860 112 wxCHECK_RET( command, wxT("no command in wxCommandProcessor::Store") );
70050c82 113
70050c82
VZ
114 // Correct a bug: we must chop off the current 'branch'
115 // so that we're at the end of the command list.
116 if (!m_currentCommand)
117 ClearCommands();
118 else
119 {
222ed1d6 120 wxList::compatibility_iterator node = m_currentCommand->GetNext();
70050c82
VZ
121 while (node)
122 {
222ed1d6 123 wxList::compatibility_iterator next = node->GetNext();
f260c476
VZ
124
125 // Make sure m_lastSavedCommand won't point to freed memory
7e0b0eb3 126 if ( m_lastSavedCommand && m_lastSavedCommand == node )
f260c476
VZ
127 m_lastSavedCommand = wxList::compatibility_iterator();
128
7e0b0eb3
VZ
129 delete (wxCommand *)node->GetData();
130 m_commands.Erase(node);
131
70050c82
VZ
132 node = next;
133 }
134 }
135
1544ba0e
VZ
136 if ( (int)m_commands.GetCount() == m_maxNoCommands )
137 {
138 wxList::compatibility_iterator firstNode = m_commands.GetFirst();
1544ba0e
VZ
139
140 // Make sure m_lastSavedCommand won't point to freed memory
7e0b0eb3 141 if ( m_lastSavedCommand && m_lastSavedCommand == firstNode )
1544ba0e 142 m_lastSavedCommand = wxList::compatibility_iterator();
7e0b0eb3
VZ
143
144 wxCommand *firstCommand = (wxCommand *)firstNode->GetData();
145 delete firstCommand;
146 m_commands.Erase(firstNode);
1544ba0e
VZ
147 }
148
70050c82 149 m_commands.Append(command);
b1d4dd7a 150 m_currentCommand = m_commands.GetLast();
70050c82
VZ
151 SetMenuStrings();
152}
153
154bool wxCommandProcessor::Undo()
155{
156 wxCommand *command = GetCurrentCommand();
157 if ( command && command->CanUndo() )
158 {
159 if ( UndoCommand(*command) )
160 {
b1d4dd7a 161 m_currentCommand = m_currentCommand->GetPrevious();
70050c82 162 SetMenuStrings();
c9d59ee7 163 return true;
70050c82
VZ
164 }
165 }
166
c9d59ee7 167 return false;
70050c82
VZ
168}
169
170bool wxCommandProcessor::Redo()
171{
d3b9f782 172 wxCommand *redoCommand = NULL;
4ed40684 173 wxList::compatibility_iterator redoNode
01871bf6 174#if !wxUSE_STD_CONTAINERS
4ed40684 175 = NULL // just to avoid warnings
01871bf6 176#endif // !wxUSE_STD_CONTAINERS
4ed40684 177 ;
17271c79
VZ
178
179 if ( m_currentCommand )
70050c82 180 {
17271c79 181 // is there anything to redo?
b1d4dd7a 182 if ( m_currentCommand->GetNext() )
17271c79 183 {
b1d4dd7a
RL
184 redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
185 redoNode = m_currentCommand->GetNext();
17271c79 186 }
70050c82 187 }
17271c79 188 else // no current command, redo the first one
70050c82 189 {
b1d4dd7a 190 if (m_commands.GetCount() > 0)
70050c82 191 {
b1d4dd7a
RL
192 redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
193 redoNode = m_commands.GetFirst();
70050c82
VZ
194 }
195 }
196
197 if (redoCommand)
198 {
199 bool success = DoCommand(*redoCommand);
200 if (success)
201 {
202 m_currentCommand = redoNode;
203 SetMenuStrings();
c9d59ee7 204 return true;
70050c82
VZ
205 }
206 }
c9d59ee7 207 return false;
70050c82
VZ
208}
209
210bool wxCommandProcessor::CanUndo() const
211{
212 wxCommand *command = GetCurrentCommand();
213
214 return command && command->CanUndo();
215}
216
217bool wxCommandProcessor::CanRedo() const
218{
222ed1d6 219 if (m_currentCommand && !m_currentCommand->GetNext())
c9d59ee7 220 return false;
70050c82 221
222ed1d6 222 if (m_currentCommand && m_currentCommand->GetNext())
c9d59ee7 223 return true;
70050c82 224
222ed1d6 225 if (!m_currentCommand && (m_commands.GetCount() > 0))
c9d59ee7 226 return true;
70050c82 227
c9d59ee7 228 return false;
70050c82
VZ
229}
230
231void wxCommandProcessor::Initialize()
232{
b1d4dd7a 233 m_currentCommand = m_commands.GetLast();
70050c82
VZ
234 SetMenuStrings();
235}
236
237void wxCommandProcessor::SetMenuStrings()
238{
239#if wxUSE_MENUS
240 if (m_commandEditMenu)
241 {
d863ed83
JS
242 wxString undoLabel = GetUndoMenuLabel();
243 wxString redoLabel = GetRedoMenuLabel();
c9d59ee7 244
d863ed83
JS
245 m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel);
246 m_commandEditMenu->Enable(wxID_UNDO, CanUndo());
247
248 m_commandEditMenu->SetLabel(wxID_REDO, redoLabel);
249 m_commandEditMenu->Enable(wxID_REDO, CanRedo());
250 }
251#endif // wxUSE_MENUS
252}
253
254// Gets the current Undo menu label.
255wxString wxCommandProcessor::GetUndoMenuLabel() const
256{
257 wxString buf;
258 if (m_currentCommand)
259 {
b1d4dd7a 260 wxCommand *command = (wxCommand *)m_currentCommand->GetData();
d863ed83 261 wxString commandName(command->GetName());
b494c48b 262 if (commandName.empty()) commandName = _("Unnamed command");
d863ed83
JS
263 bool canUndo = command->CanUndo();
264 if (canUndo)
265 buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator;
266 else
267 buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator;
268 }
269 else
270 {
271 buf = _("&Undo") + m_undoAccelerator;
272 }
c9d59ee7 273
d863ed83
JS
274 return buf;
275}
276
277// Gets the current Undo menu label.
278wxString wxCommandProcessor::GetRedoMenuLabel() const
279{
280 wxString buf;
281 if (m_currentCommand)
282 {
283 // We can redo, if we're not at the end of the history.
b1d4dd7a 284 if (m_currentCommand->GetNext())
70050c82 285 {
b1d4dd7a 286 wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
d863ed83 287 wxString redoCommandName(redoCommand->GetName());
b494c48b 288 if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
d863ed83 289 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
70050c82
VZ
290 }
291 else
292 {
d863ed83 293 buf = _("&Redo") + m_redoAccelerator;
70050c82
VZ
294 }
295 }
d863ed83
JS
296 else
297 {
b1d4dd7a 298 if (m_commands.GetCount() == 0)
d863ed83
JS
299 {
300 buf = _("&Redo") + m_redoAccelerator;
301 }
302 else
303 {
304 // currentCommand is NULL but there are commands: this means that
305 // we've undone to the start of the list, but can redo the first.
b1d4dd7a 306 wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
d863ed83 307 wxString redoCommandName(redoCommand->GetName());
b494c48b 308 if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
d863ed83
JS
309 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
310 }
311 }
312 return buf;
70050c82
VZ
313}
314
315void wxCommandProcessor::ClearCommands()
316{
222ed1d6 317 wxList::compatibility_iterator node = m_commands.GetFirst();
70050c82
VZ
318 while (node)
319 {
b1d4dd7a 320 wxCommand *command = (wxCommand *)node->GetData();
70050c82 321 delete command;
222ed1d6 322 m_commands.Erase(node);
b1d4dd7a 323 node = m_commands.GetFirst();
70050c82 324 }
f260c476 325
222ed1d6 326 m_currentCommand = wxList::compatibility_iterator();
f260c476 327 m_lastSavedCommand = wxList::compatibility_iterator();
70050c82
VZ
328}
329
ef20428e
VZ
330bool wxCommandProcessor::IsDirty() const
331{
812a2148
VZ
332 if ( m_commands.empty() )
333 {
334 // If we have never been modified, we can't be dirty.
ef20428e 335 return false;
812a2148 336 }
ef20428e
VZ
337
338 if ( !m_lastSavedCommand )
812a2148
VZ
339 {
340 // If we have been modified but have never been saved, we're dirty.
341 return true;
342 }
343
344 if ( !m_currentCommand )
345 {
346 // This only happens if all commands were undone after saving the
347 // document: we're dirty then.
ef20428e 348 return true;
812a2148 349 }
ef20428e 350
812a2148
VZ
351 // Finally if both iterators are valid, we may just compare them.
352 return m_currentCommand != m_lastSavedCommand;
ef20428e 353}
70050c82 354