]> git.saurik.com Git - wxWidgets.git/blob - src/common/cmdproc.cpp
Fixed keyboard navigation in generic tree control.
[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
126             // Make sure m_lastSavedCommand won't point to freed memory
127             if ( m_lastSavedCommand && m_lastSavedCommand == node )
128                 m_lastSavedCommand = wxList::compatibility_iterator();
129
130             delete (wxCommand *)node->GetData();
131             m_commands.Erase(node);
132
133             node = next;
134         }
135     }
136
137     if ( (int)m_commands.GetCount() == m_maxNoCommands )
138     {
139         wxList::compatibility_iterator firstNode = m_commands.GetFirst();
140
141         // Make sure m_lastSavedCommand won't point to freed memory
142         if ( m_lastSavedCommand && m_lastSavedCommand == firstNode )
143             m_lastSavedCommand = wxList::compatibility_iterator();
144
145         wxCommand *firstCommand = (wxCommand *)firstNode->GetData();
146         delete firstCommand;
147         m_commands.Erase(firstNode);
148     }
149
150     m_commands.Append(command);
151     m_currentCommand = m_commands.GetLast();
152     SetMenuStrings();
153 }
154
155 bool wxCommandProcessor::Undo()
156 {
157     wxCommand *command = GetCurrentCommand();
158     if ( command && command->CanUndo() )
159     {
160         if ( UndoCommand(*command) )
161         {
162             m_currentCommand = m_currentCommand->GetPrevious();
163             SetMenuStrings();
164             return true;
165         }
166     }
167
168     return false;
169 }
170
171 bool wxCommandProcessor::Redo()
172 {
173     wxCommand *redoCommand = NULL;
174     wxList::compatibility_iterator redoNode
175 #if !wxUSE_STD_CONTAINERS
176         = NULL          // just to avoid warnings
177 #endif // !wxUSE_STD_CONTAINERS
178         ;
179
180     if ( m_currentCommand )
181     {
182         // is there anything to redo?
183         if ( m_currentCommand->GetNext() )
184         {
185             redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
186             redoNode = m_currentCommand->GetNext();
187         }
188     }
189     else // no current command, redo the first one
190     {
191         if (m_commands.GetCount() > 0)
192         {
193             redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
194             redoNode = m_commands.GetFirst();
195         }
196     }
197
198     if (redoCommand)
199     {
200         bool success = DoCommand(*redoCommand);
201         if (success)
202         {
203             m_currentCommand = redoNode;
204             SetMenuStrings();
205             return true;
206         }
207     }
208     return false;
209 }
210
211 bool wxCommandProcessor::CanUndo() const
212 {
213     wxCommand *command = GetCurrentCommand();
214
215     return command && command->CanUndo();
216 }
217
218 bool wxCommandProcessor::CanRedo() const
219 {
220     if (m_currentCommand && !m_currentCommand->GetNext())
221         return false;
222
223     if (m_currentCommand && m_currentCommand->GetNext())
224         return true;
225
226     if (!m_currentCommand && (m_commands.GetCount() > 0))
227         return true;
228
229     return false;
230 }
231
232 void wxCommandProcessor::Initialize()
233 {
234     m_currentCommand = m_commands.GetLast();
235     SetMenuStrings();
236 }
237
238 void wxCommandProcessor::SetMenuStrings()
239 {
240 #if wxUSE_MENUS
241     if (m_commandEditMenu)
242     {
243         wxString undoLabel = GetUndoMenuLabel();
244         wxString redoLabel = GetRedoMenuLabel();
245
246         m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel);
247         m_commandEditMenu->Enable(wxID_UNDO, CanUndo());
248
249         m_commandEditMenu->SetLabel(wxID_REDO, redoLabel);
250         m_commandEditMenu->Enable(wxID_REDO, CanRedo());
251     }
252 #endif // wxUSE_MENUS
253 }
254
255 // Gets the current Undo menu label.
256 wxString wxCommandProcessor::GetUndoMenuLabel() const
257 {
258     wxString buf;
259     if (m_currentCommand)
260     {
261         wxCommand *command = (wxCommand *)m_currentCommand->GetData();
262         wxString commandName(command->GetName());
263         if (commandName.empty()) commandName = _("Unnamed command");
264         bool canUndo = command->CanUndo();
265         if (canUndo)
266             buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator;
267         else
268             buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator;
269     }
270     else
271     {
272         buf = _("&Undo") + m_undoAccelerator;
273     }
274
275     return buf;
276 }
277
278 // Gets the current Undo menu label.
279 wxString wxCommandProcessor::GetRedoMenuLabel() const
280 {
281     wxString buf;
282     if (m_currentCommand)
283     {
284         // We can redo, if we're not at the end of the history.
285         if (m_currentCommand->GetNext())
286         {
287             wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData();
288             wxString redoCommandName(redoCommand->GetName());
289             if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
290             buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
291         }
292         else
293         {
294             buf = _("&Redo") + m_redoAccelerator;
295         }
296     }
297     else
298     {
299         if (m_commands.GetCount() == 0)
300         {
301             buf = _("&Redo") + m_redoAccelerator;
302         }
303         else
304         {
305             // currentCommand is NULL but there are commands: this means that
306             // we've undone to the start of the list, but can redo the first.
307             wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData();
308             wxString redoCommandName(redoCommand->GetName());
309             if (redoCommandName.empty()) redoCommandName = _("Unnamed command");
310             buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator;
311         }
312     }
313     return buf;
314 }
315
316 void wxCommandProcessor::ClearCommands()
317 {
318     wxList::compatibility_iterator node = m_commands.GetFirst();
319     while (node)
320     {
321         wxCommand *command = (wxCommand *)node->GetData();
322         delete command;
323         m_commands.Erase(node);
324         node = m_commands.GetFirst();
325     }
326
327     m_currentCommand = wxList::compatibility_iterator();
328     m_lastSavedCommand = wxList::compatibility_iterator();
329 }
330
331