]> git.saurik.com Git - wxWidgets.git/blame - src/common/cmdproc.cpp
clipboard handler must be extern C (Sun CC warning)
[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
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
70050c82
VZ
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
70050c82
VZ
56// ----------------------------------------------------------------------------
57// Command processor
58// ----------------------------------------------------------------------------
59
60wxCommandProcessor::wxCommandProcessor(int maxCommands)
61{
62 m_maxNoCommands = maxCommands;
70050c82
VZ
63#if wxUSE_MENUS
64 m_commandEditMenu = (wxMenu *) NULL;
65#endif // wxUSE_MENUS
6aa3ea88
JS
66 m_undoAccelerator = wxT("\tCtrl+Z");
67 m_redoAccelerator = wxT("\tCtrl+Y");
f260c476
VZ
68
69 m_lastSavedCommand =
70 m_currentCommand = wxList::compatibility_iterator();
70050c82
VZ
71}
72
73wxCommandProcessor::~wxCommandProcessor()
74{
75 ClearCommands();
76}
77
78bool wxCommandProcessor::DoCommand(wxCommand& cmd)
79{
80 return cmd.Do();
81}
82
83bool 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
c9d59ee7 90// storeIt is false.
70050c82
VZ
91bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt)
92{
c9d59ee7 93 wxCHECK_MSG( command, false, _T("no command in wxCommandProcessor::Submit") );
70050c82
VZ
94
95 if ( !DoCommand(*command) )
ca1b5af1
VZ
96 {
97 // the user code expects the command to be deleted anyhow
98 delete command;
99
c9d59ee7 100 return false;
ca1b5af1 101 }
70050c82
VZ
102
103 if ( storeIt )
104 Store(command);
f530fa27
VZ
105 else
106 delete command;
70050c82 107
c9d59ee7 108 return true;
70050c82
VZ
109}
110
111void wxCommandProcessor::Store(wxCommand *command)
112{
113 wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") );
114
b1d4dd7a 115 if ( (int)m_commands.GetCount() == m_maxNoCommands )
70050c82 116 {
222ed1d6 117 wxList::compatibility_iterator firstNode = m_commands.GetFirst();
b1d4dd7a 118 wxCommand *firstCommand = (wxCommand *)firstNode->GetData();
70050c82 119 delete firstCommand;
222ed1d6 120 m_commands.Erase(firstNode);
f260c476
VZ
121
122 // Make sure m_lastSavedCommand won't point to freed memory
123 if ( m_lastSavedCommand == firstNode )
124 m_lastSavedCommand = wxList::compatibility_iterator();
70050c82
VZ
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 {
222ed1d6 133 wxList::compatibility_iterator node = m_currentCommand->GetNext();
70050c82
VZ
134 while (node)
135 {
222ed1d6 136 wxList::compatibility_iterator next = node->GetNext();
b1d4dd7a 137 delete (wxCommand *)node->GetData();
222ed1d6 138 m_commands.Erase(node);
f260c476
VZ
139
140 // Make sure m_lastSavedCommand won't point to freed memory
141 if ( m_lastSavedCommand == node )
142 m_lastSavedCommand = wxList::compatibility_iterator();
143
70050c82
VZ
144 node = next;
145 }
146 }
147
148 m_commands.Append(command);
b1d4dd7a 149 m_currentCommand = m_commands.GetLast();
70050c82
VZ
150 SetMenuStrings();
151}
152
153bool wxCommandProcessor::Undo()
154{
155 wxCommand *command = GetCurrentCommand();
156 if ( command && command->CanUndo() )
157 {
158 if ( UndoCommand(*command) )
159 {
b1d4dd7a 160 m_currentCommand = m_currentCommand->GetPrevious();
70050c82 161 SetMenuStrings();
c9d59ee7 162 return true;
70050c82
VZ
163 }
164 }
165
c9d59ee7 166 return false;
70050c82
VZ
167}
168
169bool wxCommandProcessor::Redo()
170{
171 wxCommand *redoCommand = (wxCommand *) NULL;
4ed40684
VZ
172 wxList::compatibility_iterator redoNode
173#if !wxUSE_STL
174 = NULL // just to avoid warnings
175#endif // !wxUSE_STL
176 ;
17271c79
VZ
177
178 if ( m_currentCommand )
70050c82 179 {
17271c79 180 // is there anything to redo?
b1d4dd7a 181 if ( m_currentCommand->GetNext() )
17271c79 182 {
b1d4dd7a
RL
183 redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
184 redoNode = m_currentCommand->GetNext();
17271c79 185 }
70050c82 186 }
17271c79 187 else // no current command, redo the first one
70050c82 188 {
b1d4dd7a 189 if (m_commands.GetCount() > 0)
70050c82 190 {
b1d4dd7a
RL
191 redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
192 redoNode = m_commands.GetFirst();
70050c82
VZ
193 }
194 }
195
196 if (redoCommand)
197 {
198 bool success = DoCommand(*redoCommand);
199 if (success)
200 {
201 m_currentCommand = redoNode;
202 SetMenuStrings();
c9d59ee7 203 return true;
70050c82
VZ
204 }
205 }
c9d59ee7 206 return false;
70050c82
VZ
207}
208
209bool wxCommandProcessor::CanUndo() const
210{
211 wxCommand *command = GetCurrentCommand();
212
213 return command && command->CanUndo();
214}
215
216bool wxCommandProcessor::CanRedo() const
217{
222ed1d6 218 if (m_currentCommand && !m_currentCommand->GetNext())
c9d59ee7 219 return false;
70050c82 220
222ed1d6 221 if (m_currentCommand && m_currentCommand->GetNext())
c9d59ee7 222 return true;
70050c82 223
222ed1d6 224 if (!m_currentCommand && (m_commands.GetCount() > 0))
c9d59ee7 225 return true;
70050c82 226
c9d59ee7 227 return false;
70050c82
VZ
228}
229
230void wxCommandProcessor::Initialize()
231{
b1d4dd7a 232 m_currentCommand = m_commands.GetLast();
70050c82
VZ
233 SetMenuStrings();
234}
235
236void wxCommandProcessor::SetMenuStrings()
237{
238#if wxUSE_MENUS
239 if (m_commandEditMenu)
240 {
d863ed83
JS
241 wxString undoLabel = GetUndoMenuLabel();
242 wxString redoLabel = GetRedoMenuLabel();
c9d59ee7 243
d863ed83
JS
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.
254wxString wxCommandProcessor::GetUndoMenuLabel() const
255{
256 wxString buf;
257 if (m_currentCommand)
258 {
b1d4dd7a 259 wxCommand *command = (wxCommand *)m_currentCommand->GetData();
d863ed83 260 wxString commandName(command->GetName());
b494c48b 261 if (commandName.empty()) commandName = _("Unnamed command");
d863ed83
JS
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 }
c9d59ee7 272
d863ed83
JS
273 return buf;
274}
275
276// Gets the current Undo menu label.
277wxString 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.
b1d4dd7a 283 if (m_currentCommand->GetNext())
70050c82 284 {
b1d4dd7a 285 wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
d863ed83 286 wxString redoCommandName(redoCommand->GetName());
b494c48b 287 if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
d863ed83 288 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
70050c82
VZ
289 }
290 else
291 {
d863ed83 292 buf = _("&Redo") + m_redoAccelerator;
70050c82
VZ
293 }
294 }
d863ed83
JS
295 else
296 {
b1d4dd7a 297 if (m_commands.GetCount() == 0)
d863ed83
JS
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.
b1d4dd7a 305 wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
d863ed83 306 wxString redoCommandName(redoCommand->GetName());
b494c48b 307 if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
d863ed83
JS
308 buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
309 }
310 }
311 return buf;
70050c82
VZ
312}
313
314void wxCommandProcessor::ClearCommands()
315{
222ed1d6 316 wxList::compatibility_iterator node = m_commands.GetFirst();
70050c82
VZ
317 while (node)
318 {
b1d4dd7a 319 wxCommand *command = (wxCommand *)node->GetData();
70050c82 320 delete command;
222ed1d6 321 m_commands.Erase(node);
b1d4dd7a 322 node = m_commands.GetFirst();
70050c82 323 }
f260c476 324
222ed1d6 325 m_currentCommand = wxList::compatibility_iterator();
f260c476 326 m_lastSavedCommand = wxList::compatibility_iterator();
70050c82
VZ
327}
328
329