always remember to test IsOk() after using wxFileInputStream
[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 // RCS-ID: $Id$
7 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
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/button.h"
28 #include "wx/stattext.h"
29 #include "wx/sizer.h"
30 #endif // WX_PRECOMP
31
32 #include "wx/rearrangectrl.h"
33
34 // ============================================================================
35 // wxRearrangeList implementation
36 // ============================================================================
37
38 extern
39 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeListNameStr[] = "wxRearrangeList";
40
41 BEGIN_EVENT_TABLE(wxRearrangeList, wxCheckListBox)
42 EVT_CHECKLISTBOX(wxID_ANY, wxRearrangeList::OnCheck)
43 END_EVENT_TABLE()
44
45 bool wxRearrangeList::Create(wxWindow *parent,
46 wxWindowID id,
47 const wxPoint& pos,
48 const wxSize& size,
49 const wxArrayInt& order,
50 const wxArrayString& items,
51 long style,
52 const wxValidator& validator,
53 const wxString& name)
54 {
55 // construct the array of items in the order in which they should appear in
56 // the control
57 const size_t count = items.size();
58 wxCHECK_MSG( order.size() == count, false, "arrays not in sync" );
59
60 wxArrayString itemsInOrder;
61 itemsInOrder.reserve(count);
62 size_t n;
63 for ( n = 0; n < count; n++ )
64 {
65 int idx = order[n];
66 if ( idx < 0 )
67 idx = -idx - 1;
68 itemsInOrder.push_back(items[idx]);
69 }
70
71 // do create the real control
72 if ( !wxCheckListBox::Create(parent, id, pos, size, itemsInOrder,
73 style, validator, name) )
74 return false;
75
76 // and now check all the items which should be initially checked
77 for ( n = 0; n < count; n++ )
78 {
79 if ( order[n] >= 0 )
80 Check(n);
81 }
82
83 m_order = order;
84
85 return true;
86 }
87
88 bool wxRearrangeList::CanMoveCurrentUp() const
89 {
90 const int sel = GetSelection();
91 return sel != wxNOT_FOUND && sel != 0;
92 }
93
94 bool wxRearrangeList::CanMoveCurrentDown() const
95 {
96 const int sel = GetSelection();
97 return sel != wxNOT_FOUND && static_cast<unsigned>(sel) != GetCount() - 1;
98 }
99
100 bool wxRearrangeList::MoveCurrentUp()
101 {
102 const int sel = GetSelection();
103 if ( sel == wxNOT_FOUND || sel == 0 )
104 return false;
105
106 Swap(sel, sel - 1);
107 SetSelection(sel - 1);
108
109 return true;
110 }
111
112 bool wxRearrangeList::MoveCurrentDown()
113 {
114 const int sel = GetSelection();
115 if ( sel == wxNOT_FOUND || static_cast<unsigned>(sel) == GetCount() - 1 )
116 return false;
117
118 Swap(sel, sel + 1);
119 SetSelection(sel + 1);
120
121 return true;
122 }
123
124 void wxRearrangeList::Swap(int pos1, int pos2)
125 {
126 wxSwap(m_order[pos1], m_order[pos2]);
127
128 const wxString stringTmp = GetString(pos1);
129 const bool checkedTmp = IsChecked(pos1);
130
131 SetString(pos1, GetString(pos2));
132 Check(pos1, IsChecked(pos2));
133
134 SetString(pos2, stringTmp);
135 Check(pos2, checkedTmp);
136 }
137
138 void wxRearrangeList::OnCheck(wxCommandEvent& event)
139 {
140 // update the internal state to match the new item state
141 const int n = event.GetInt();
142
143 m_order[n] = ~m_order[n];
144
145 wxASSERT_MSG( (m_order[n] >= 0) == IsChecked(n),
146 "discrepancy between internal state and GUI" );
147 }
148
149 // ============================================================================
150 // wxRearrangeCtrl implementation
151 // ============================================================================
152
153 BEGIN_EVENT_TABLE(wxRearrangeCtrl, wxPanel)
154 EVT_UPDATE_UI(wxID_UP, wxRearrangeCtrl::OnUpdateButtonUI)
155 EVT_UPDATE_UI(wxID_DOWN, wxRearrangeCtrl::OnUpdateButtonUI)
156
157 EVT_BUTTON(wxID_UP, wxRearrangeCtrl::OnButton)
158 EVT_BUTTON(wxID_DOWN, wxRearrangeCtrl::OnButton)
159 END_EVENT_TABLE()
160
161 void wxRearrangeCtrl::Init()
162 {
163 m_list = NULL;
164 }
165
166 bool
167 wxRearrangeCtrl::Create(wxWindow *parent,
168 wxWindowID id,
169 const wxPoint& pos,
170 const wxSize& size,
171 const wxArrayInt& order,
172 const wxArrayString& items,
173 long style,
174 const wxValidator& validator,
175 const wxString& name)
176 {
177 // create all the windows
178 if ( !wxPanel::Create(parent, id, pos, size, wxTAB_TRAVERSAL, name) )
179 return false;
180
181 m_list = new wxRearrangeList(this, wxID_ANY,
182 wxDefaultPosition, wxDefaultSize,
183 order, items,
184 style, validator);
185 wxButton * const btnUp = new wxButton(this, wxID_UP);
186 wxButton * const btnDown = new wxButton(this, wxID_DOWN);
187
188 // arrange them in a sizer
189 wxSizer * const sizerBtns = new wxBoxSizer(wxVERTICAL);
190 sizerBtns->Add(btnUp, wxSizerFlags().Centre().Border(wxBOTTOM));
191 sizerBtns->Add(btnDown, wxSizerFlags().Centre().Border(wxTOP));
192
193 wxSizer * const sizerTop = new wxBoxSizer(wxHORIZONTAL);
194 sizerTop->Add(m_list, wxSizerFlags(1).Expand().Border(wxRIGHT));
195 sizerTop->Add(sizerBtns, wxSizerFlags(0).Centre().Border(wxLEFT));
196 SetSizer(sizerTop);
197
198 m_list->SetFocus();
199
200 return true;
201 }
202
203 void wxRearrangeCtrl::OnUpdateButtonUI(wxUpdateUIEvent& event)
204 {
205 event.Enable( event.GetId() == wxID_UP ? m_list->CanMoveCurrentUp()
206 : m_list->CanMoveCurrentDown() );
207 }
208
209 void wxRearrangeCtrl::OnButton(wxCommandEvent& event)
210 {
211 if ( event.GetId() == wxID_UP )
212 m_list->MoveCurrentUp();
213 else
214 m_list->MoveCurrentDown();
215 }
216
217 // ============================================================================
218 // wxRearrangeDialog implementation
219 // ============================================================================
220
221 extern
222 WXDLLIMPEXP_DATA_CORE(const char) wxRearrangeDialogNameStr[] = "wxRearrangeDlg";
223
224 namespace
225 {
226
227 enum wxRearrangeDialogSizerPositions
228 {
229 Pos_Label,
230 Pos_Ctrl,
231 Pos_Buttons,
232 Pos_Max
233 };
234
235 } // anonymous namespace
236
237 bool wxRearrangeDialog::Create(wxWindow *parent,
238 const wxString& message,
239 const wxString& title,
240 const wxArrayInt& order,
241 const wxArrayString& items,
242 const wxPoint& pos,
243 const wxString& name)
244 {
245 if ( !wxDialog::Create(parent, wxID_ANY, title,
246 pos, wxDefaultSize,
247 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER,
248 name) )
249 return false;
250
251 m_ctrl = new wxRearrangeCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
252 order, items);
253
254 // notice that the items in this sizer should be inserted accordingly to
255 // wxRearrangeDialogSizerPositions order
256 wxSizer * const sizerTop = new wxBoxSizer(wxVERTICAL);
257 sizerTop->Add(new wxStaticText(this, wxID_ANY, message),
258 wxSizerFlags().Border());
259 sizerTop->Add(m_ctrl,
260 wxSizerFlags(1).Expand().Border());
261 sizerTop->Add(CreateSeparatedButtonSizer(wxOK | wxCANCEL),
262 wxSizerFlags().Expand().Border());
263 SetSizerAndFit(sizerTop);
264
265 return true;
266 }
267
268 void wxRearrangeDialog::AddExtraControls(wxWindow *win)
269 {
270 wxSizer * const sizer = GetSizer();
271 wxCHECK_RET( sizer, "the dialog must be created first" );
272
273 wxASSERT_MSG( sizer->GetChildren().GetCount() == Pos_Max,
274 "calling AddExtraControls() twice?" );
275
276 sizer->Insert(Pos_Buttons, win, wxSizerFlags().Expand().Border());
277
278 win->MoveAfterInTabOrder(m_ctrl);
279
280 // we need to update the initial/minimal window size
281 sizer->SetSizeHints(this);
282 }
283
284 wxRearrangeList *wxRearrangeDialog::GetList() const
285 {
286 wxCHECK_MSG( m_ctrl, NULL, "the dialog must be created first" );
287
288 return m_ctrl->GetList();
289 }
290
291 wxArrayInt wxRearrangeDialog::GetOrder() const
292 {
293 wxCHECK_MSG( m_ctrl, wxArrayInt(), "the dialog must be created first" );
294
295 return m_ctrl->GetList()->GetCurrentOrder();
296 }