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