]> git.saurik.com Git - wxWidgets.git/blame - src/common/list.cpp
GTK is standard in configure again
[wxWidgets.git] / src / common / list.cpp
CommitLineData
fd3f686c 1////////////////////////////////////////////////////////////////////////////////
c801d85f
KB
2// Name: list.cpp
3// Purpose: wxList implementation
4// Author: Julian Smart
fd3f686c 5// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added
c801d85f
KB
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
fd3f686c
VZ
9// Licence: wxWindows license
10////////////////////////////////////////////////////////////////////////////////
c801d85f 11
fd3f686c
VZ
12// =============================================================================
13// declarations
14// =============================================================================
15
16// -----------------------------------------------------------------------------
17// headers
18// -----------------------------------------------------------------------------
c801d85f
KB
19#ifdef __GNUG__
20#pragma implementation "list.h"
21#endif
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
fd3f686c 27 #pragma hdrstop
c801d85f
KB
28#endif
29
fd3f686c
VZ
30#include <stdarg.h>
31#include <stdlib.h>
32#include <string.h>
33
c801d85f 34#ifndef WX_PRECOMP
fd3f686c
VZ
35 #include "wx/defs.h"
36 #include "wx/list.h"
37 #include "wx/utils.h" // for copystring() (beurk...)
c801d85f
KB
38#endif
39
40// Sun CC compatibility (interference with xview/pkg.h, apparently...)
3013b6f4
JS
41// But XView is no longer supported.
42/*
43#if defined (SUN_CC) || defined(__SUNCC__) && defined(__XVIEW__)
fd3f686c
VZ
44 #undef va_start
45 #undef va_end
46 #undef va_arg
47 #undef va_list
c801d85f 48#endif
3013b6f4 49*/
c801d85f 50
fd3f686c
VZ
51// =============================================================================
52// implementation
53// =============================================================================
c801d85f 54
ff528365
VZ
55// -----------------------------------------------------------------------------
56// wxListKey
57// -----------------------------------------------------------------------------
58
59bool wxListKey::operator==(wxListKeyValue value) const
60{
61 switch ( m_keyType )
62 {
63 default:
64 wxFAIL_MSG("bad key type.");
65 // let compiler optimize the line above away in release build
66 // by not putting return here...
67
68 case wxKEY_STRING:
69 return strcmp(m_key.string, value.string) == 0;
70
71 case wxKEY_INTEGER:
72 return m_key.integer == value.integer;
73 }
77c5eefb 74}
ff528365 75
fd3f686c
VZ
76// -----------------------------------------------------------------------------
77// wxNodeBase
78// -----------------------------------------------------------------------------
c801d85f 79
fd3f686c
VZ
80wxNodeBase::wxNodeBase(wxListBase *list,
81 wxNodeBase *previous, wxNodeBase *next,
82 void *data, const wxListKey& key)
c801d85f 83{
fd3f686c
VZ
84 m_list = list;
85 m_data = data;
86 m_previous = previous;
87 m_next = next;
77c5eefb 88
fd3f686c
VZ
89 switch ( key.GetKeyType() )
90 {
91 case wxKEY_NONE:
92 break;
77c5eefb 93
fd3f686c
VZ
94 case wxKEY_INTEGER:
95 m_key.integer = key.GetNumber();
96 break;
77c5eefb 97
fd3f686c
VZ
98 case wxKEY_STRING:
99 // to be free()d later
100 m_key.string = strdup(key.GetString());
101 break;
77c5eefb 102
fd3f686c
VZ
103 default:
104 wxFAIL_MSG("invalid key type");
105 }
77c5eefb 106
fd3f686c
VZ
107 if ( previous )
108 previous->m_next = this;
77c5eefb 109
fd3f686c
VZ
110 if ( next )
111 next->m_previous = this;
112}
c801d85f 113
fd3f686c
VZ
114wxNodeBase::~wxNodeBase()
115{
116 // handle the case when we're being deleted from the list by the user (i.e.
117 // not by the list itself from DeleteNode) - we must do it for
118 // compatibility with old code
119 if ( m_list != NULL )
120 {
121 m_list->DetachNode(this);
122 }
c801d85f
KB
123}
124
77c5eefb
VZ
125int wxNodeBase::IndexOf() const
126{
127 wxCHECK_MSG( m_list, NOT_FOUND, "node doesn't belong to a list in IndexOf");
128
129 // It would be more efficient to implement IndexOf() completely inside
130 // wxListBase (only traverse the list once), but this is probably a more
131 // reusable way of doing it. Can always be optimized at a later date (since
132 // IndexOf() resides in wxListBase as well) if efficiency is a problem.
133 int i;
134 wxNodeBase *prev = m_previous;
135
136 for( i = 0; prev; i++ )
137 {
138 prev = prev->m_previous;
139 }
140
141 return i;
142}
143
fd3f686c
VZ
144// -----------------------------------------------------------------------------
145// wxListBase
146// -----------------------------------------------------------------------------
147
148void wxListBase::Init(wxKeyType keyType = wxKEY_NONE)
c801d85f 149{
fd3f686c
VZ
150 m_nodeFirst =
151 m_nodeLast = (wxNodeBase *) NULL;
152 m_count = 0;
153 m_destroy = FALSE;
154 m_keyType = keyType;
155}
c801d85f 156
fd3f686c
VZ
157wxListBase::wxListBase(size_t count, void *elements[])
158{
159 Init();
c801d85f 160
fd3f686c
VZ
161 for ( size_t n = 0; n < count; n++ )
162 {
163 Append(elements[n]);
164 }
c801d85f
KB
165}
166
fd3f686c 167void wxListBase::DoCopy(const wxListBase& list)
c801d85f 168{
fd3f686c
VZ
169 wxASSERT_MSG( !list.m_destroy,
170 "copying list which owns it's elements is a bad idea" );
c801d85f 171
fd3f686c
VZ
172 m_count = list.m_count;
173 m_destroy = list.m_destroy;
174 m_keyType = list.m_keyType;
175 m_nodeFirst =
176 m_nodeLast = (wxNodeBase *) NULL;
c801d85f 177
fd3f686c
VZ
178 for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() )
179 {
180 Append(node);
181 }
c801d85f
KB
182}
183
fd3f686c 184wxListBase::~wxListBase()
c801d85f 185{
fd3f686c
VZ
186 wxNodeBase *each = m_nodeFirst;
187 while ( each != NULL )
188 {
189 wxNodeBase *next = each->GetNext();
190 DoDeleteNode(each);
191 each = next;
192 }
c801d85f
KB
193}
194
fd3f686c 195wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node)
c801d85f 196{
fd3f686c
VZ
197 if ( !m_nodeFirst )
198 {
199 m_nodeFirst = node;
200 m_nodeLast = m_nodeFirst;
201 }
202 else
203 {
204 m_nodeLast->m_next = node;
205 m_nodeLast = node;
206 }
207
208 m_count++;
209
210 return node;
c801d85f
KB
211}
212
fd3f686c 213wxNodeBase *wxListBase::Append(void *object)
c801d85f 214{
fd3f686c
VZ
215 // all objects in a keyed list should have a key
216 wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL,
217 "need a key for the object to append" );
c801d85f 218
fd3f686c
VZ
219 wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object);
220
221 return AppendCommon(node);
c801d85f
KB
222}
223
fd3f686c 224wxNodeBase *wxListBase::Append(long key, void *object)
c801d85f 225{
fd3f686c
VZ
226 wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) ||
227 (m_keyType == wxKEY_NONE && m_count == 0),
228 (wxNodeBase *)NULL,
229 "can't append object with numeric key to this list" );
230
231 wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key);
232 return AppendCommon(node);
c801d85f
KB
233}
234
fd3f686c 235wxNodeBase *wxListBase::Append (const char *key, void *object)
c801d85f 236{
fd3f686c
VZ
237 wxCHECK_MSG( (m_keyType == wxKEY_STRING) ||
238 (m_keyType == wxKEY_NONE && m_count == 0),
239 (wxNodeBase *)NULL,
240 "can't append object with string key to this list" );
241
242 wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key);
243 return AppendCommon(node);
244}
c801d85f 245
fd3f686c
VZ
246wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object)
247{
248 // all objects in a keyed list should have a key
249 wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL,
250 "need a key for the object to insert" );
c801d85f 251
ff528365
VZ
252 wxCHECK_MSG( !position || position->m_list == this, (wxNodeBase *)NULL,
253 "can't insert before a node from another list" );
254
255 // previous and next node for the node being inserted
256 wxNodeBase *prev, *next;
fd3f686c 257 if ( position )
ff528365 258 {
fd3f686c 259 prev = position->GetPrevious();
ff528365
VZ
260 next = position;
261 }
262 else
263 {
264 // inserting in the beginning of the list
265 prev = (wxNodeBase *)NULL;
266 next = m_nodeFirst;
267 }
c801d85f 268
ff528365 269 wxNodeBase *node = CreateNode(prev, next, object);
fd3f686c 270 if ( !m_nodeFirst )
c801d85f 271 {
fd3f686c 272 m_nodeLast = node;
c801d85f 273 }
c801d85f 274
fd3f686c 275 if ( prev == NULL )
c801d85f 276 {
fd3f686c 277 m_nodeFirst = node;
c801d85f 278 }
c801d85f 279
fd3f686c
VZ
280 m_count++;
281
c801d85f
KB
282 return node;
283}
284
fd3f686c 285wxNodeBase *wxListBase::Item(size_t n) const
c801d85f 286{
fd3f686c 287 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
c801d85f 288 {
fd3f686c
VZ
289 if ( n-- == 0 )
290 {
291 return current;
292 }
c801d85f 293 }
c801d85f 294
b46e8696 295 wxFAIL_MSG( "invalid index in wxListBase::Item" );
c801d85f 296
1b4092eb 297 return (wxNodeBase *)NULL;
c801d85f
KB
298}
299
fd3f686c 300wxNodeBase *wxListBase::Find(const wxListKey& key) const
c801d85f 301{
fd3f686c
VZ
302 wxASSERT_MSG( m_keyType == key.GetKeyType(),
303 "this list is not keyed on the type of this key" );
c801d85f 304
fd3f686c
VZ
305 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
306 {
307 if ( key == current->m_key )
308 {
309 return current;
310 }
311 }
c801d85f 312
fd3f686c
VZ
313 // not found
314 return (wxNodeBase *)NULL;
c801d85f
KB
315}
316
fd3f686c 317wxNodeBase *wxListBase::Find(void *object) const
c801d85f 318{
fd3f686c 319 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
c801d85f 320 {
fd3f686c
VZ
321 if ( current->GetData() == object )
322 return current;
c801d85f 323 }
fd3f686c
VZ
324
325 // not found
326 return (wxNodeBase *)NULL;
c801d85f
KB
327}
328
77c5eefb
VZ
329int wxListBase::IndexOf(void *object) const
330{
331 wxNodeBase *node = Find( object );
332
333 return node ? node->IndexOf() : NOT_FOUND;
334}
335
fd3f686c 336void wxListBase::DoDeleteNode(wxNodeBase *node)
c801d85f 337{
fd3f686c
VZ
338 // free node's data
339 if ( m_keyType == wxKEY_STRING )
c801d85f 340 {
fd3f686c 341 free(node->m_key.string);
c801d85f 342 }
c801d85f 343
fd3f686c 344 if ( m_destroy )
c801d85f 345 {
fd3f686c 346 node->DeleteData();
c801d85f 347 }
c801d85f 348
fd3f686c 349 delete node;
c801d85f
KB
350}
351
fd3f686c 352wxNodeBase *wxListBase::DetachNode(wxNodeBase *node)
c801d85f 353{
fd3f686c
VZ
354 wxCHECK_MSG( node, NULL, "detaching NULL wxNodeBase" );
355 wxCHECK_MSG( node->m_list == this, NULL,
356 "detaching node which is not from this list" );
c801d85f 357
fd3f686c
VZ
358 // update the list
359 wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next
360 : &m_nodeFirst;
361 wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous
362 : &m_nodeLast;
c801d85f 363
fd3f686c
VZ
364 *prevNext = node->GetNext();
365 *nextPrev = node->GetPrevious();
c801d85f 366
fd3f686c 367 m_count--;
c801d85f 368
fd3f686c
VZ
369 // mark the node as not belonging to this list any more
370 node->m_list = NULL;
c801d85f 371
fd3f686c 372 return node;
c801d85f
KB
373}
374
fd3f686c 375bool wxListBase::DeleteNode(wxNodeBase *node)
c801d85f 376{
fd3f686c
VZ
377 if ( !DetachNode(node) )
378 return FALSE;
379
380 DoDeleteNode(node);
381
382 return TRUE;
c801d85f
KB
383}
384
fd3f686c 385bool wxListBase::DeleteObject(void *object)
c801d85f 386{
fd3f686c
VZ
387 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
388 {
389 if ( current->GetData() == object )
390 {
391 DeleteNode(current);
392 return TRUE;
393 }
394 }
395
396 // not found
397 return FALSE;
c801d85f
KB
398}
399
fd3f686c 400void wxListBase::Clear()
c801d85f 401{
fd3f686c
VZ
402 wxNodeBase *current = m_nodeFirst;
403 while ( current )
c801d85f 404 {
fd3f686c
VZ
405 wxNodeBase *next = current->GetNext();
406 DoDeleteNode(current);
407 current = next;
c801d85f 408 }
fd3f686c
VZ
409
410 m_nodeFirst =
411 m_nodeLast = (wxNodeBase *)NULL;
412
413 m_count = 0;
c801d85f
KB
414}
415
fd3f686c 416void wxListBase::ForEach(wxListIterateFunction F)
c801d85f 417{
fd3f686c
VZ
418 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
419 {
420 (*F)(current->GetData());
c801d85f
KB
421 }
422}
fd3f686c
VZ
423
424void *wxListBase::FirstThat(wxListIterateFunction F)
c801d85f 425{
fd3f686c
VZ
426 for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() )
427 {
428 if ( (*F)(current->GetData()) )
429 return current->GetData();
c801d85f 430 }
fd3f686c
VZ
431
432 return (wxNodeBase *)NULL;
c801d85f 433}
fd3f686c
VZ
434
435void *wxListBase::LastThat(wxListIterateFunction F)
c801d85f 436{
fd3f686c
VZ
437 for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() )
438 {
439 if ( (*F)(current->GetData()) )
440 return current->GetData();
c801d85f 441 }
fd3f686c
VZ
442
443 return (wxNodeBase *)NULL;
c801d85f
KB
444}
445
446// (stefan.hammes@urz.uni-heidelberg.de)
447//
448// function for sorting lists. the concept is borrowed from 'qsort'.
449// by giving a sort function, arbitrary lists can be sorted.
450// method:
451// - put wxObject pointers into an array
452// - sort the array with qsort
453// - put back the sorted wxObject pointers into the list
454//
455// CAVE: the sort function receives pointers to wxObject pointers (wxObject **),
456// so dereference right!
457// EXAMPLE:
458// int listcompare(const void *arg1, const void *arg2)
459// {
460// return(compare(**(wxString **)arg1,
461// **(wxString **)arg2));
462// }
463//
464// void main()
fd3f686c
VZ
465// {
466// wxListBase list;
c801d85f
KB
467//
468// list.Append(new wxString("DEF"));
469// list.Append(new wxString("GHI"));
470// list.Append(new wxString("ABC"));
471// list.Sort(listcompare);
472// }
473
fd3f686c 474void wxListBase::Sort(const wxSortCompareFunction compfunc)
c801d85f 475{
fd3f686c
VZ
476 // allocate an array for the wxObject pointers of the list
477 const size_t num = GetCount();
478 void **objArray = new void *[num];
479 void **objPtr = objArray;
480
481 // go through the list and put the pointers into the array
482 wxNodeBase *node;
483 for ( node = GetFirst(); node; node = node->Next() )
484 {
485 *objPtr++ = node->Data();
486 }
487
488 // sort the array
489 qsort((void *)objArray,num,sizeof(wxObject *),compfunc);
490
491 // put the sorted pointers back into the list
492 objPtr = objArray;
493 for ( node = GetFirst(); node; node = node->Next() )
494 {
495 node->SetData(*objPtr++);
496 }
497
498 // free the array
499 delete[] objArray;
c801d85f
KB
500}
501
fd3f686c
VZ
502// -----------------------------------------------------------------------------
503// wxList (a.k.a. wxObjectList)
504// -----------------------------------------------------------------------------
c801d85f 505
fd3f686c 506void wxObjectListNode::DeleteData()
c801d85f 507{
fd3f686c 508 delete (wxObject *)GetData();
c801d85f
KB
509}
510
fd3f686c
VZ
511// -----------------------------------------------------------------------------
512// wxStringList
513// -----------------------------------------------------------------------------
514
515// instead of WX_DEFINE_LIST(wxStringListBase) we define this function
516// ourselves
517void wxStringListNode::DeleteData()
341287bf 518{
fd3f686c 519 delete [] (char *)GetData();
341287bf
JS
520}
521
f0824a5a
VZ
522bool wxStringList::Delete(const char *s)
523{
524 wxStringListNode *current;
525
526 for ( current = GetFirst(); current; current = current->GetNext() )
527 {
528 if ( strcmp(current->GetData(), s) == 0 )
529 {
530 DeleteNode(current);
531 return TRUE;
532 }
533 }
534
535 // not found
536 return FALSE;
537}
538
db9504c5
VZ
539void wxStringList::DoCopy(const wxStringList& other)
540{
541 wxASSERT( GetCount() == 0 ); // this list must be empty before copying!
542
543 size_t count = other.GetCount();
544 for ( size_t n = 0; n < count; n++ )
545 {
77c5eefb 546 Add(other.Item(n)->GetData());
db9504c5
VZ
547 }
548}
549
c801d85f
KB
550// Variable argument list, terminated by a zero
551// Makes new storage for the strings
fd3f686c 552wxStringList::wxStringList (const char *first, ...)
c801d85f 553{
fd3f686c 554 if ( !first )
c801d85f
KB
555 return;
556
557 va_list ap;
fd3f686c 558 va_start(ap, first);
c801d85f 559
fd3f686c 560 const char *s = first;
c801d85f 561 for (;;)
fd3f686c
VZ
562 {
563 Add(s);
564
565 s = va_arg(ap, const char *);
566 // if (s == NULL)
2049ba38 567#ifdef __WXMSW__
c801d85f
KB
568 if ((int) s == 0)
569#else
570 if ((long) s == 0)
571#endif
fd3f686c
VZ
572 break;
573 }
c801d85f 574
fd3f686c 575 va_end(ap);
341287bf
JS
576}
577
fd3f686c
VZ
578// Only makes new strings if arg is TRUE
579char **wxStringList::ListToArray(bool new_copies) const
341287bf 580{
fd3f686c
VZ
581 char **string_array = new char *[GetCount()];
582 wxStringListNode *node = GetFirst();
583 for (size_t i = 0; i < GetCount(); i++)
c801d85f 584 {
fd3f686c
VZ
585 char *s = node->GetData();
586 if ( new_copies )
587 string_array[i] = copystring(s);
588 else
589 string_array[i] = s;
590 node = node->GetNext();
c801d85f 591 }
c801d85f 592
fd3f686c 593 return string_array;
c801d85f
KB
594}
595
fd3f686c
VZ
596// Checks whether s is a member of the list
597bool wxStringList::Member(const char *s) const
c801d85f 598{
fd3f686c 599 for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() )
c801d85f 600 {
fd3f686c
VZ
601 const char *s1 = node->GetData();
602 if (s == s1 || strcmp (s, s1) == 0)
603 return TRUE;
c801d85f 604 }
fd3f686c
VZ
605
606 return FALSE;
c801d85f
KB
607}
608
fd3f686c
VZ
609static int
610wx_comparestrings(const void *arg1, const void *arg2)
c801d85f
KB
611{
612 char **s1 = (char **) arg1;
613 char **s2 = (char **) arg2;
614
615 return strcmp (*s1, *s2);
616}
617
618// Sort a list of strings - deallocates old nodes, allocates new
fd3f686c 619void wxStringList::Sort()
c801d85f 620{
fd3f686c
VZ
621 size_t N = GetCount();
622 char **array = new char *[N];
c801d85f 623
fd3f686c
VZ
624 size_t i = 0;
625 for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() )
c801d85f 626 {
fd3f686c 627 array[i++] = node->GetData();
c801d85f 628 }
341287bf 629
fd3f686c 630 qsort (array, N, sizeof (char *), wx_comparestrings);
341287bf
JS
631 Clear();
632
fd3f686c
VZ
633 for (i = 0; i < N; i++)
634 Append (array[i]);
341287bf 635
fd3f686c 636 delete[]array;
341287bf
JS
637}
638