Remove all lines containing cvs/svn "$Id$" keyword.
[wxWidgets.git] / src / common / rearrangectrl.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/rearrangectrl.cpp
3 // Purpose: implementation of classes in wx/rearrangectrl.h
4 // Author: Vadim Zeitlin
5 // Created: 2008-12-15
6 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #if wxUSE_REARRANGECTRL
26
27 #ifndef WX_PRECOMP
28 #include "wx/button.h"
29 #include "wx/stattext.h"
30 #include "wx/sizer.h"
31 #endif // WX_PRECOMP
32
33 #include "wx/rearrangectrl.h"
34
35 // ============================================================================
36 // wxRearrangeList implementation
37 // ============================================================================
38
39 extern
40 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeListNameStr[] = "wxRearrangeList";
41
42 BEGIN_EVENT_TABLE(wxRearrangeList, wxCheckListBox)
43 EVT_CHECKLISTBOX(wxID_ANY, wxRearrangeList::OnCheck)
44 END_EVENT_TABLE()
45
46 bool wxRearrangeList::Create(wxWindow *parent,
47 wxWindowID id,
48 const wxPoint& pos,
49 const wxSize& size,
50 const wxArrayInt& order,
51 const wxArrayString& items,
52 long style,
53 const wxValidator& validator,
54 const wxString& name)
55 {
56 // construct the array of items in the order in which they should appear in
57 // the control
58 const size_t count = items.size();
59 wxCHECK_MSG( order.size() == count, false, "arrays not in sync" );
60
61 wxArrayString itemsInOrder;
62 itemsInOrder.reserve(count);
63 size_t n;
64 for ( n = 0; n < count; n++ )
65 {
66 int idx = order[n];
67 if ( idx < 0 )
68 idx = -idx - 1;
69 itemsInOrder.push_back(items[idx]);
70 }
71
72 // do create the real control
73 if ( !wxCheckListBox::Create(parent, id, pos, size, itemsInOrder,
74 style, validator, name) )
75 return false;
76
77 // and now check all the items which should be initially checked
78 for ( n = 0; n < count; n++ )
79 {
80 if ( order[n] >= 0 )
81 Check(n);
82 }
83
84 m_order = order;
85
86 return true;
87 }
88
89 bool wxRearrangeList::CanMoveCurrentUp() const
90 {
91 const int sel = GetSelection();
92 return sel != wxNOT_FOUND && sel != 0;
93 }
94
95 bool wxRearrangeList::CanMoveCurrentDown() const
96 {
97 const int sel = GetSelection();
98 return sel != wxNOT_FOUND && static_cast<unsigned>(sel) != GetCount() - 1;
99 }
100
101 bool wxRearrangeList::MoveCurrentUp()
102 {
103 const int sel = GetSelection();
104 if ( sel == wxNOT_FOUND || sel == 0 )
105 return false;
106
107 Swap(sel, sel - 1);
108 SetSelection(sel - 1);
109
110 return true;
111 }
112
113 bool wxRearrangeList::MoveCurrentDown()
114 {
115 const int sel = GetSelection();
116 if ( sel == wxNOT_FOUND || static_cast<unsigned>(sel) == GetCount() - 1 )
117 return false;
118
119 Swap(sel, sel + 1);
120 SetSelection(sel + 1);
121
122 return true;
123 }
124
125 void wxRearrangeList::Swap(int pos1, int pos2)
126 {
127 // update the internally stored order
128 wxSwap(m_order[pos1], m_order[pos2]);
129
130
131 // and now also swap all the attributes of the items
132
133 // first the label
134 const wxString stringTmp = GetString(pos1);
135 SetString(pos1, GetString(pos2));
136 SetString(pos2, stringTmp);
137
138 // then the checked state
139 const bool checkedTmp = IsChecked(pos1);
140 Check(pos1, IsChecked(pos2));
141 Check(pos2, checkedTmp);
142
143 // and finally the client data, if necessary
144 switch ( GetClientDataType() )
145 {
146 case wxClientData_None:
147 // nothing to do
148 break;
149
150 case wxClientData_Object:
151 {
152 wxClientData * const dataTmp = DetachClientObject(pos1);
153 SetClientObject(pos1, DetachClientObject(pos2));
154 SetClientObject(pos2, dataTmp);
155 }
156 break;
157
158 case wxClientData_Void:
159 {
160 void * const dataTmp = GetClientData(pos1);
161 SetClientData(pos1, GetClientData(pos2));
162 SetClientData(pos2, dataTmp);
163 }
164 break;
165 }
166 }
167
168 void wxRearrangeList::OnCheck(wxCommandEvent& event)
169 {
170 // update the internal state to match the new item state
171 const int n = event.GetInt();
172
173 m_order[n] = ~m_order[n];
174
175 wxASSERT_MSG( (m_order[n] >= 0) == IsChecked(n),
176 "discrepancy between internal state and GUI" );
177 }
178
179 // ============================================================================
180 // wxRearrangeCtrl implementation
181 // ============================================================================
182
183 BEGIN_EVENT_TABLE(wxRearrangeCtrl, wxPanel)
184 EVT_UPDATE_UI(wxID_UP, wxRearrangeCtrl::OnUpdateButtonUI)
185 EVT_UPDATE_UI(wxID_DOWN, wxRearrangeCtrl::OnUpdateButtonUI)
186
187 EVT_BUTTON(wxID_UP, wxRearrangeCtrl::OnButton)
188 EVT_BUTTON(wxID_DOWN, wxRearrangeCtrl::OnButton)
189 END_EVENT_TABLE()
190
191 void wxRearrangeCtrl::Init()
192 {
193 m_list = NULL;
194 }
195
196 bool
197 wxRearrangeCtrl::Create(wxWindow *parent,
198 wxWindowID id,
199 const wxPoint& pos,
200 const wxSize& size,
201 const wxArrayInt& order,
202 const wxArrayString& items,
203 long style,
204 const wxValidator& validator,
205 const wxString& name)
206 {
207 // create all the windows
208 if ( !wxPanel::Create(parent, id, pos, size, wxTAB_TRAVERSAL, name) )
209 return false;
210
211 m_list = new wxRearrangeList(this, wxID_ANY,
212 wxDefaultPosition, wxDefaultSize,
213 order, items,
214 style, validator);
215 wxButton * const btnUp = new wxButton(this, wxID_UP);
216 wxButton * const btnDown = new wxButton(this, wxID_DOWN);
217
218 // arrange them in a sizer
219 wxSizer * const sizerBtns = new wxBoxSizer(wxVERTICAL);
220 sizerBtns->Add(btnUp, wxSizerFlags().Centre().Border(wxBOTTOM));
221 sizerBtns->Add(btnDown, wxSizerFlags().Centre().Border(wxTOP));
222
223 wxSizer * const sizerTop = new wxBoxSizer(wxHORIZONTAL);
224 sizerTop->Add(m_list, wxSizerFlags(1).Expand().Border(wxRIGHT));
225 sizerTop->Add(sizerBtns, wxSizerFlags(0).Centre().Border(wxLEFT));
226 SetSizer(sizerTop);
227
228 m_list->SetFocus();
229
230 return true;
231 }
232
233 void wxRearrangeCtrl::OnUpdateButtonUI(wxUpdateUIEvent& event)
234 {
235 event.Enable( event.GetId() == wxID_UP ? m_list->CanMoveCurrentUp()
236 : m_list->CanMoveCurrentDown() );
237 }
238
239 void wxRearrangeCtrl::OnButton(wxCommandEvent& event)
240 {
241 if ( event.GetId() == wxID_UP )
242 m_list->MoveCurrentUp();
243 else
244 m_list->MoveCurrentDown();
245 }
246
247 // ============================================================================
248 // wxRearrangeDialog implementation
249 // ============================================================================
250
251 extern
252 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeDialogNameStr[] = "wxRearrangeDlg";
253
254 namespace
255 {
256
257 enum wxRearrangeDialogSizerPositions
258 {
259 Pos_Label,
260 Pos_Ctrl,
261 Pos_Buttons,
262 Pos_Max
263 };
264
265 } // anonymous namespace
266
267 bool wxRearrangeDialog::Create(wxWindow *parent,
268 const wxString& message,
269 const wxString& title,
270 const wxArrayInt& order,
271 const wxArrayString& items,
272 const wxPoint& pos,
273 const wxString& name)
274 {
275 if ( !wxDialog::Create(parent, wxID_ANY, title,
276 pos, wxDefaultSize,
277 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER,
278 name) )
279 return false;
280
281 m_ctrl = new wxRearrangeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
282 order, items);
283
284 // notice that the items in this sizer should be inserted accordingly to
285 // wxRearrangeDialogSizerPositions order
286 wxSizer * const sizerTop = new wxBoxSizer(wxVERTICAL);
287
288 if ( !message.empty() )
289 {
290 sizerTop->Add(new wxStaticText(this, wxID_ANY, message),
291 wxSizerFlags().Border());
292 }
293 else
294 {
295 // for convenience of other wxRearrangeDialog code that depends on
296 // positions of sizer items, insert a dummy zero-sized item
297 sizerTop->AddSpacer(0);
298 }
299
300 sizerTop->Add(m_ctrl,
301 wxSizerFlags(1).Expand().Border());
302 sizerTop->Add(CreateSeparatedButtonSizer(wxOK | wxCANCEL),
303 wxSizerFlags().Expand().Border());
304 SetSizerAndFit(sizerTop);
305
306 return true;
307 }
308
309 void wxRearrangeDialog::AddExtraControls(wxWindow *win)
310 {
311 wxSizer * const sizer = GetSizer();
312 wxCHECK_RET( sizer, "the dialog must be created first" );
313
314 wxASSERT_MSG( sizer->GetChildren().GetCount() == Pos_Max,
315 "calling AddExtraControls() twice?" );
316
317 sizer->Insert(Pos_Buttons, win, wxSizerFlags().Expand().Border());
318
319 win->MoveAfterInTabOrder(m_ctrl);
320
321 // we need to update the initial/minimal window size
322 sizer->SetSizeHints(this);
323 }
324
325 wxRearrangeList *wxRearrangeDialog::GetList() const
326 {
327 wxCHECK_MSG( m_ctrl, NULL, "the dialog must be created first" );
328
329 return m_ctrl->GetList();
330 }
331
332 wxArrayInt wxRearrangeDialog::GetOrder() const
333 {
334 wxCHECK_MSG( m_ctrl, wxArrayInt(), "the dialog must be created first" );
335
336 return m_ctrl->GetList()->GetCurrentOrder();
337 }
338
339 #endif // wxUSE_REARRANGECTRL