]> git.saurik.com Git - wxWidgets.git/blob - src/generic/selstore.cpp
Fix crash in wxDC::GetMultiLineTextExtent() after last commit.
[wxWidgets.git] / src / generic / selstore.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/selstore.cpp
3 // Purpose: wxSelectionStore implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 08.06.03 (extracted from src/generic/listctrl.cpp)
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000-2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #include "wx/selstore.h"
27
28 // ============================================================================
29 // wxSelectionStore
30 // ============================================================================
31
32 // ----------------------------------------------------------------------------
33 // tests
34 // ----------------------------------------------------------------------------
35
36 bool wxSelectionStore::IsSelected(unsigned item) const
37 {
38 bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND;
39
40 // if the default state is to be selected, being in m_itemsSel means that
41 // the item is not selected, so we have to inverse the logic
42 return m_defaultState ? !isSel : isSel;
43 }
44
45 // ----------------------------------------------------------------------------
46 // Select*()
47 // ----------------------------------------------------------------------------
48
49 bool wxSelectionStore::SelectItem(unsigned item, bool select)
50 {
51 // search for the item ourselves as like this we get the index where to
52 // insert it later if needed, so we do only one search in the array instead
53 // of two (adding item to a sorted array requires a search)
54 size_t index = m_itemsSel.IndexForInsert(item);
55 bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item;
56
57 if ( select != m_defaultState )
58 {
59 if ( !isSel )
60 {
61 m_itemsSel.AddAt(item, index);
62
63 return true;
64 }
65 }
66 else // reset to default state
67 {
68 if ( isSel )
69 {
70 m_itemsSel.RemoveAt(index);
71 return true;
72 }
73 }
74
75 return false;
76 }
77
78 bool wxSelectionStore::SelectRange(unsigned itemFrom, unsigned itemTo,
79 bool select,
80 wxArrayInt *itemsChanged)
81 {
82 // 100 is hardcoded but it shouldn't matter much: the important thing is
83 // that we don't refresh everything when really few (e.g. 1 or 2) items
84 // change state
85 static const unsigned MANY_ITEMS = 100;
86
87 wxASSERT_MSG( itemFrom <= itemTo, wxT("should be in order") );
88
89 // are we going to have more [un]selected items than the other ones?
90 if ( itemTo - itemFrom > m_count/2 )
91 {
92 if ( select != m_defaultState )
93 {
94 // the default state now becomes the same as 'select'
95 m_defaultState = select;
96
97 // so all the old selections (which had state select) shouldn't be
98 // selected any more, but all the other ones should
99 wxSelectedIndices selOld = m_itemsSel;
100 m_itemsSel.Empty();
101
102 // TODO: it should be possible to optimize the searches a bit
103 // knowing the possible range
104
105 unsigned item;
106 for ( item = 0; item < itemFrom; item++ )
107 {
108 if ( selOld.Index(item) == wxNOT_FOUND )
109 m_itemsSel.Add(item);
110 }
111
112 for ( item = itemTo + 1; item < m_count; item++ )
113 {
114 if ( selOld.Index(item) == wxNOT_FOUND )
115 m_itemsSel.Add(item);
116 }
117
118 // many items (> half) changed state
119 itemsChanged = NULL;
120 }
121 else // select == m_defaultState
122 {
123 // get the inclusive range of items between itemFrom and itemTo
124 size_t count = m_itemsSel.GetCount(),
125 start = m_itemsSel.IndexForInsert(itemFrom),
126 end = m_itemsSel.IndexForInsert(itemTo);
127
128 if ( start == count || m_itemsSel[start] < itemFrom )
129 {
130 start++;
131 }
132
133 if ( end == count || m_itemsSel[end] > itemTo )
134 {
135 end--;
136 }
137
138 if ( start <= end )
139 {
140 // delete all of them (from end to avoid changing indices)
141 for ( int i = end; i >= (int)start; i-- )
142 {
143 if ( itemsChanged )
144 {
145 if ( itemsChanged->GetCount() > MANY_ITEMS )
146 {
147 // stop counting (see comment below)
148 itemsChanged = NULL;
149 }
150 else
151 {
152 itemsChanged->Add(m_itemsSel[i]);
153 }
154 }
155
156 m_itemsSel.RemoveAt(i);
157 }
158 }
159 }
160 }
161 else // "few" items change state
162 {
163 if ( itemsChanged )
164 {
165 itemsChanged->Empty();
166 }
167
168 // just add the items to the selection
169 for ( unsigned item = itemFrom; item <= itemTo; item++ )
170 {
171 if ( SelectItem(item, select) && itemsChanged )
172 {
173 itemsChanged->Add(item);
174
175 if ( itemsChanged->GetCount() > MANY_ITEMS )
176 {
177 // stop counting them, we'll just eat gobs of memory
178 // for nothing at all - faster to refresh everything in
179 // this case
180 itemsChanged = NULL;
181 }
182 }
183 }
184 }
185
186 // we set it to NULL if there are many items changing state
187 return itemsChanged != NULL;
188 }
189
190 // ----------------------------------------------------------------------------
191 // callbacks
192 // ----------------------------------------------------------------------------
193
194 void wxSelectionStore::OnItemDelete(unsigned item)
195 {
196 size_t count = m_itemsSel.GetCount(),
197 i = m_itemsSel.IndexForInsert(item);
198
199 if ( i < count && m_itemsSel[i] == item )
200 {
201 // this item itself was in m_itemsSel, remove it from there
202 m_itemsSel.RemoveAt(i);
203
204 count--;
205 }
206
207 // and adjust the index of all which follow it
208 while ( i < count )
209 {
210 // all following elements must be greater than the one we deleted
211 wxASSERT_MSG( m_itemsSel[i] > item, wxT("logic error") );
212
213 m_itemsSel[i++]--;
214 }
215 }
216
217 void wxSelectionStore::SetItemCount(unsigned count)
218 {
219 // forget about all items whose indices are now invalid if the size
220 // decreased
221 if ( count < m_count )
222 {
223 for ( size_t i = m_itemsSel.GetCount(); i > 0; i-- )
224 {
225 if ( m_itemsSel[i - 1] >= count )
226 m_itemsSel.RemoveAt(i - 1);
227 }
228 }
229
230 // remember the new number of items
231 m_count = count;
232 }