]> git.saurik.com Git - wxWidgets.git/blob - src/common/utilscmn.cpp
Avoid an endless recursion situation
[wxWidgets.git] / src / common / utilscmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/utilscmn.cpp
3 // Purpose: Miscellaneous utility functions and classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 29/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Julian Smart
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/app.h"
29 #include "wx/string.h"
30 #include "wx/utils.h"
31 #include "wx/intl.h"
32 #include "wx/log.h"
33
34 #if wxUSE_GUI
35 #include "wx/window.h"
36 #include "wx/frame.h"
37 #include "wx/menu.h"
38 #include "wx/msgdlg.h"
39 #include "wx/textdlg.h"
40 #include "wx/textctrl.h" // for wxTE_PASSWORD
41 #if wxUSE_ACCEL
42 #include "wx/menuitem.h"
43 #include "wx/accel.h"
44 #endif // wxUSE_ACCEL
45 #endif // wxUSE_GUI
46 #endif // WX_PRECOMP
47
48 #include "wx/apptrait.h"
49
50 #include "wx/process.h"
51 #include "wx/txtstrm.h"
52 #include "wx/uri.h"
53 #include "wx/mimetype.h"
54 #include "wx/config.h"
55
56 #if defined(__WXWINCE__) && wxUSE_DATETIME
57 #include "wx/datetime.h"
58 #endif
59
60 #include <ctype.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64
65 #if !wxONLY_WATCOM_EARLIER_THAN(1,4)
66 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
67 #include <errno.h>
68 #endif
69 #endif
70
71 #if wxUSE_GUI
72 #include "wx/colordlg.h"
73 #include "wx/fontdlg.h"
74 #include "wx/notebook.h"
75 #include "wx/statusbr.h"
76 #endif // wxUSE_GUI
77
78 #ifndef __WXPALMOS5__
79 #ifndef __WXWINCE__
80 #include <time.h>
81 #else
82 #include "wx/msw/wince/time.h"
83 #endif
84 #endif // ! __WXPALMOS5__
85
86 #ifdef __WXMAC__
87 #include "wx/osx/private.h"
88 #endif
89
90 #ifndef __WXPALMOS5__
91 #if !defined(__MWERKS__) && !defined(__WXWINCE__)
92 #include <sys/types.h>
93 #include <sys/stat.h>
94 #endif
95 #endif // ! __WXPALMOS5__
96
97 #if defined(__WXMSW__)
98 #include "wx/msw/private.h"
99 #include "wx/filesys.h"
100 #endif
101
102 #if wxUSE_GUI && defined(__WXGTK__)
103 #include <gtk/gtk.h> // for GTK_XXX_VERSION constants
104 #endif
105
106 #if wxUSE_BASE
107
108 // ============================================================================
109 // implementation
110 // ============================================================================
111
112 // Array used in DecToHex conversion routine.
113 static const wxChar hexArray[] = wxT("0123456789ABCDEF");
114
115 // Convert 2-digit hex number to decimal
116 int wxHexToDec(const wxString& str)
117 {
118 char buf[2];
119 buf[0] = str.GetChar(0);
120 buf[1] = str.GetChar(1);
121 return wxHexToDec((const char*) buf);
122 }
123
124 // Convert decimal integer to 2-character hex string
125 void wxDecToHex(int dec, wxChar *buf)
126 {
127 int firstDigit = (int)(dec/16.0);
128 int secondDigit = (int)(dec - (firstDigit*16.0));
129 buf[0] = hexArray[firstDigit];
130 buf[1] = hexArray[secondDigit];
131 buf[2] = 0;
132 }
133
134 // Convert decimal integer to 2 characters
135 void wxDecToHex(int dec, char* ch1, char* ch2)
136 {
137 int firstDigit = (int)(dec/16.0);
138 int secondDigit = (int)(dec - (firstDigit*16.0));
139 (*ch1) = (char) hexArray[firstDigit];
140 (*ch2) = (char) hexArray[secondDigit];
141 }
142
143 // Convert decimal integer to 2-character hex string
144 wxString wxDecToHex(int dec)
145 {
146 wxChar buf[3];
147 wxDecToHex(dec, buf);
148 return wxString(buf);
149 }
150
151 // ----------------------------------------------------------------------------
152 // misc functions
153 // ----------------------------------------------------------------------------
154
155 // Return the current date/time
156 wxString wxNow()
157 {
158 #ifdef __WXWINCE__
159 #if wxUSE_DATETIME
160 wxDateTime now = wxDateTime::Now();
161 return now.Format();
162 #else
163 return wxEmptyString;
164 #endif
165 #else
166 time_t now = time(NULL);
167 char *date = ctime(&now);
168 date[24] = '\0';
169 return wxString::FromAscii(date);
170 #endif
171 }
172
173 #if WXWIN_COMPATIBILITY_2_8
174 void wxUsleep(unsigned long milliseconds)
175 {
176 wxMilliSleep(milliseconds);
177 }
178 #endif
179
180 const wxChar *wxGetInstallPrefix()
181 {
182 wxString prefix;
183
184 if ( wxGetEnv(wxT("WXPREFIX"), &prefix) )
185 return prefix.c_str();
186
187 #ifdef wxINSTALL_PREFIX
188 return wxT(wxINSTALL_PREFIX);
189 #else
190 return wxEmptyString;
191 #endif
192 }
193
194 wxString wxGetDataDir()
195 {
196 wxString dir = wxGetInstallPrefix();
197 dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx");
198 return dir;
199 }
200
201 bool wxIsPlatformLittleEndian()
202 {
203 // Are we little or big endian? This method is from Harbison & Steele.
204 union
205 {
206 long l;
207 char c[sizeof(long)];
208 } u;
209 u.l = 1;
210
211 return u.c[0] == 1;
212 }
213
214
215 // ----------------------------------------------------------------------------
216 // wxPlatform
217 // ----------------------------------------------------------------------------
218
219 /*
220 * Class to make it easier to specify platform-dependent values
221 */
222
223 wxArrayInt* wxPlatform::sm_customPlatforms = NULL;
224
225 void wxPlatform::Copy(const wxPlatform& platform)
226 {
227 m_longValue = platform.m_longValue;
228 m_doubleValue = platform.m_doubleValue;
229 m_stringValue = platform.m_stringValue;
230 }
231
232 wxPlatform wxPlatform::If(int platform, long value)
233 {
234 if (Is(platform))
235 return wxPlatform(value);
236 else
237 return wxPlatform();
238 }
239
240 wxPlatform wxPlatform::IfNot(int platform, long value)
241 {
242 if (!Is(platform))
243 return wxPlatform(value);
244 else
245 return wxPlatform();
246 }
247
248 wxPlatform& wxPlatform::ElseIf(int platform, long value)
249 {
250 if (Is(platform))
251 m_longValue = value;
252 return *this;
253 }
254
255 wxPlatform& wxPlatform::ElseIfNot(int platform, long value)
256 {
257 if (!Is(platform))
258 m_longValue = value;
259 return *this;
260 }
261
262 wxPlatform wxPlatform::If(int platform, double value)
263 {
264 if (Is(platform))
265 return wxPlatform(value);
266 else
267 return wxPlatform();
268 }
269
270 wxPlatform wxPlatform::IfNot(int platform, double value)
271 {
272 if (!Is(platform))
273 return wxPlatform(value);
274 else
275 return wxPlatform();
276 }
277
278 wxPlatform& wxPlatform::ElseIf(int platform, double value)
279 {
280 if (Is(platform))
281 m_doubleValue = value;
282 return *this;
283 }
284
285 wxPlatform& wxPlatform::ElseIfNot(int platform, double value)
286 {
287 if (!Is(platform))
288 m_doubleValue = value;
289 return *this;
290 }
291
292 wxPlatform wxPlatform::If(int platform, const wxString& value)
293 {
294 if (Is(platform))
295 return wxPlatform(value);
296 else
297 return wxPlatform();
298 }
299
300 wxPlatform wxPlatform::IfNot(int platform, const wxString& value)
301 {
302 if (!Is(platform))
303 return wxPlatform(value);
304 else
305 return wxPlatform();
306 }
307
308 wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value)
309 {
310 if (Is(platform))
311 m_stringValue = value;
312 return *this;
313 }
314
315 wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value)
316 {
317 if (!Is(platform))
318 m_stringValue = value;
319 return *this;
320 }
321
322 wxPlatform& wxPlatform::Else(long value)
323 {
324 m_longValue = value;
325 return *this;
326 }
327
328 wxPlatform& wxPlatform::Else(double value)
329 {
330 m_doubleValue = value;
331 return *this;
332 }
333
334 wxPlatform& wxPlatform::Else(const wxString& value)
335 {
336 m_stringValue = value;
337 return *this;
338 }
339
340 void wxPlatform::AddPlatform(int platform)
341 {
342 if (!sm_customPlatforms)
343 sm_customPlatforms = new wxArrayInt;
344 sm_customPlatforms->Add(platform);
345 }
346
347 void wxPlatform::ClearPlatforms()
348 {
349 wxDELETE(sm_customPlatforms);
350 }
351
352 /// Function for testing current platform
353
354 bool wxPlatform::Is(int platform)
355 {
356 #ifdef __WXMSW__
357 if (platform == wxOS_WINDOWS)
358 return true;
359 #endif
360 #ifdef __WXWINCE__
361 if (platform == wxOS_WINDOWS_CE)
362 return true;
363 #endif
364
365 #if 0
366
367 // FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols
368
369 #if defined(__WXWINCE__) && defined(__POCKETPC__)
370 if (platform == wxWinPocketPC)
371 return true;
372 #endif
373 #if defined(__WXWINCE__) && defined(__SMARTPHONE__)
374 if (platform == wxWinSmartPhone)
375 return true;
376 #endif
377
378 #endif
379
380 #ifdef __WXGTK__
381 if (platform == wxPORT_GTK)
382 return true;
383 #endif
384 #ifdef __WXMAC__
385 if (platform == wxPORT_MAC)
386 return true;
387 #endif
388 #ifdef __WXX11__
389 if (platform == wxPORT_X11)
390 return true;
391 #endif
392 #ifdef __UNIX__
393 if (platform == wxOS_UNIX)
394 return true;
395 #endif
396 #ifdef __WXMGL__
397 if (platform == wxPORT_MGL)
398 return true;
399 #endif
400 #ifdef __OS2__
401 if (platform == wxOS_OS2)
402 return true;
403 #endif
404 #ifdef __WXPM__
405 if (platform == wxPORT_PM)
406 return true;
407 #endif
408 #ifdef __WXCOCOA__
409 if (platform == wxPORT_MAC)
410 return true;
411 #endif
412
413 if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND)
414 return true;
415
416 return false;
417 }
418
419 // ----------------------------------------------------------------------------
420 // network and user id functions
421 // ----------------------------------------------------------------------------
422
423 // Get Full RFC822 style email address
424 bool wxGetEmailAddress(wxChar *address, int maxSize)
425 {
426 wxString email = wxGetEmailAddress();
427 if ( !email )
428 return false;
429
430 wxStrlcpy(address, email.t_str(), maxSize);
431
432 return true;
433 }
434
435 wxString wxGetEmailAddress()
436 {
437 wxString email;
438
439 wxString host = wxGetFullHostName();
440 if ( !host.empty() )
441 {
442 wxString user = wxGetUserId();
443 if ( !user.empty() )
444 {
445 email << user << wxT('@') << host;
446 }
447 }
448
449 return email;
450 }
451
452 wxString wxGetUserId()
453 {
454 static const int maxLoginLen = 256; // FIXME arbitrary number
455
456 wxString buf;
457 bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen);
458
459 if ( !ok )
460 buf.Empty();
461
462 return buf;
463 }
464
465 wxString wxGetUserName()
466 {
467 static const int maxUserNameLen = 1024; // FIXME arbitrary number
468
469 wxString buf;
470 bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen);
471
472 if ( !ok )
473 buf.Empty();
474
475 return buf;
476 }
477
478 wxString wxGetHostName()
479 {
480 static const size_t hostnameSize = 257;
481
482 wxString buf;
483 bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
484
485 if ( !ok )
486 buf.Empty();
487
488 return buf;
489 }
490
491 wxString wxGetFullHostName()
492 {
493 static const size_t hostnameSize = 257;
494
495 wxString buf;
496 bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize);
497
498 if ( !ok )
499 buf.Empty();
500
501 return buf;
502 }
503
504 wxString wxGetHomeDir()
505 {
506 wxString home;
507 wxGetHomeDir(&home);
508
509 return home;
510 }
511
512 #if 0
513
514 wxString wxGetCurrentDir()
515 {
516 wxString dir;
517 size_t len = 1024;
518 bool ok;
519 do
520 {
521 ok = getcwd(dir.GetWriteBuf(len + 1), len) != NULL;
522 dir.UngetWriteBuf();
523
524 if ( !ok )
525 {
526 if ( errno != ERANGE )
527 {
528 wxLogSysError(wxT("Failed to get current directory"));
529
530 return wxEmptyString;
531 }
532 else
533 {
534 // buffer was too small, retry with a larger one
535 len *= 2;
536 }
537 }
538 //else: ok
539 } while ( !ok );
540
541 return dir;
542 }
543
544 #endif // 0
545
546 // ----------------------------------------------------------------------------
547 // wxExecute
548 // ----------------------------------------------------------------------------
549
550 // wxDoExecuteWithCapture() helper: reads an entire stream into one array
551 //
552 // returns true if ok, false if error
553 #if wxUSE_STREAMS
554 static bool ReadAll(wxInputStream *is, wxArrayString& output)
555 {
556 wxCHECK_MSG( is, false, wxT("NULL stream in wxExecute()?") );
557
558 // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state
559 is->Reset();
560
561 wxTextInputStream tis(*is);
562
563 for ( ;; )
564 {
565 wxString line = tis.ReadLine();
566
567 // check for EOF before other errors as it's not really an error
568 if ( is->Eof() )
569 {
570 // add the last, possibly incomplete, line
571 if ( !line.empty() )
572 output.Add(line);
573 break;
574 }
575
576 // any other error is fatal
577 if ( !*is )
578 return false;
579
580 output.Add(line);
581 }
582
583 return true;
584 }
585 #endif // wxUSE_STREAMS
586
587 // this is a private function because it hasn't a clean interface: the first
588 // array is passed by reference, the second by pointer - instead we have 2
589 // public versions of wxExecute() below
590 static long wxDoExecuteWithCapture(const wxString& command,
591 wxArrayString& output,
592 wxArrayString* error,
593 int flags)
594 {
595 // create a wxProcess which will capture the output
596 wxProcess *process = new wxProcess;
597 process->Redirect();
598
599 long rc = wxExecute(command, wxEXEC_SYNC | flags, process);
600
601 #if wxUSE_STREAMS
602 if ( rc != -1 )
603 {
604 if ( !ReadAll(process->GetInputStream(), output) )
605 rc = -1;
606
607 if ( error )
608 {
609 if ( !ReadAll(process->GetErrorStream(), *error) )
610 rc = -1;
611 }
612
613 }
614 #else
615 wxUnusedVar(output);
616 wxUnusedVar(error);
617 #endif // wxUSE_STREAMS/!wxUSE_STREAMS
618
619 delete process;
620
621 return rc;
622 }
623
624 long wxExecute(const wxString& command, wxArrayString& output, int flags)
625 {
626 return wxDoExecuteWithCapture(command, output, NULL, flags);
627 }
628
629 long wxExecute(const wxString& command,
630 wxArrayString& output,
631 wxArrayString& error,
632 int flags)
633 {
634 return wxDoExecuteWithCapture(command, output, &error, flags);
635 }
636
637 // ----------------------------------------------------------------------------
638 // Id functions
639 // ----------------------------------------------------------------------------
640
641 // Id generation
642 static long wxCurrentId = 100;
643
644 long wxNewId()
645 {
646 // skip the part of IDs space that contains hard-coded values:
647 if (wxCurrentId == wxID_LOWEST)
648 wxCurrentId = wxID_HIGHEST + 1;
649
650 return wxCurrentId++;
651 }
652
653 long
654 wxGetCurrentId(void) { return wxCurrentId; }
655
656 void
657 wxRegisterId (long id)
658 {
659 if (id >= wxCurrentId)
660 wxCurrentId = id + 1;
661 }
662
663 // ----------------------------------------------------------------------------
664 // wxQsort, adapted by RR to allow user_data
665 // ----------------------------------------------------------------------------
666
667 /* This file is part of the GNU C Library.
668 Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
669
670 Douglas Schmidt kindly gave permission to relicence the
671 code under the wxWindows licence:
672
673 From: "Douglas C. Schmidt" <schmidt@dre.vanderbilt.edu>
674 To: Robert Roebling <robert.roebling@uni-ulm.de>
675 Subject: Re: qsort licence
676 Date: Mon, 23 Jul 2007 03:44:25 -0500
677 Sender: schmidt@dre.vanderbilt.edu
678 Message-Id: <20070723084426.64F511000A8@tango.dre.vanderbilt.edu>
679
680 Hi Robert,
681
682 > [...] I'm asking if you'd be willing to relicence your code
683 > under the wxWindows licence. [...]
684
685 That's fine with me [...]
686
687 Thanks,
688
689 Doug */
690
691
692 /* Byte-wise swap two items of size SIZE. */
693 #define SWAP(a, b, size) \
694 do \
695 { \
696 register size_t __size = (size); \
697 register char *__a = (a), *__b = (b); \
698 do \
699 { \
700 char __tmp = *__a; \
701 *__a++ = *__b; \
702 *__b++ = __tmp; \
703 } while (--__size > 0); \
704 } while (0)
705
706 /* Discontinue quicksort algorithm when partition gets below this size.
707 This particular magic number was chosen to work best on a Sun 4/260. */
708 #define MAX_THRESH 4
709
710 /* Stack node declarations used to store unfulfilled partition obligations. */
711 typedef struct
712 {
713 char *lo;
714 char *hi;
715 } stack_node;
716
717 /* The next 4 #defines implement a very fast in-line stack abstraction. */
718 #define STACK_SIZE (8 * sizeof(unsigned long int))
719 #define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
720 #define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
721 #define STACK_NOT_EMPTY (stack < top)
722
723
724 /* Order size using quicksort. This implementation incorporates
725 four optimizations discussed in Sedgewick:
726
727 1. Non-recursive, using an explicit stack of pointer that store the
728 next array partition to sort. To save time, this maximum amount
729 of space required to store an array of MAX_INT is allocated on the
730 stack. Assuming a 32-bit integer, this needs only 32 *
731 sizeof(stack_node) == 136 bits. Pretty cheap, actually.
732
733 2. Chose the pivot element using a median-of-three decision tree.
734 This reduces the probability of selecting a bad pivot value and
735 eliminates certain extraneous comparisons.
736
737 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
738 insertion sort to order the MAX_THRESH items within each partition.
739 This is a big win, since insertion sort is faster for small, mostly
740 sorted array segments.
741
742 4. The larger of the two sub-partitions is always pushed onto the
743 stack first, with the algorithm then concentrating on the
744 smaller partition. This *guarantees* no more than log (n)
745 stack size is needed (actually O(1) in this case)! */
746
747 void wxQsort(void *const pbase, size_t total_elems,
748 size_t size, CMPFUNCDATA cmp, const void* user_data)
749 {
750 register char *base_ptr = (char *) pbase;
751 const size_t max_thresh = MAX_THRESH * size;
752
753 if (total_elems == 0)
754 /* Avoid lossage with unsigned arithmetic below. */
755 return;
756
757 if (total_elems > MAX_THRESH)
758 {
759 char *lo = base_ptr;
760 char *hi = &lo[size * (total_elems - 1)];
761 stack_node stack[STACK_SIZE];
762 stack_node *top = stack;
763
764 PUSH (NULL, NULL);
765
766 while (STACK_NOT_EMPTY)
767 {
768 char *left_ptr;
769 char *right_ptr;
770
771 /* Select median value from among LO, MID, and HI. Rearrange
772 LO and HI so the three values are sorted. This lowers the
773 probability of picking a pathological pivot value and
774 skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
775
776 char *mid = lo + size * ((hi - lo) / size >> 1);
777
778 if ((*cmp) ((void *) mid, (void *) lo, user_data) < 0)
779 SWAP (mid, lo, size);
780 if ((*cmp) ((void *) hi, (void *) mid, user_data) < 0)
781 SWAP (mid, hi, size);
782 else
783 goto jump_over;
784 if ((*cmp) ((void *) mid, (void *) lo, user_data) < 0)
785 SWAP (mid, lo, size);
786 jump_over:;
787 left_ptr = lo + size;
788 right_ptr = hi - size;
789
790 /* Here's the famous ``collapse the walls'' section of quicksort.
791 Gotta like those tight inner loops! They are the main reason
792 that this algorithm runs much faster than others. */
793 do
794 {
795 while ((*cmp) ((void *) left_ptr, (void *) mid, user_data) < 0)
796 left_ptr += size;
797
798 while ((*cmp) ((void *) mid, (void *) right_ptr, user_data) < 0)
799 right_ptr -= size;
800
801 if (left_ptr < right_ptr)
802 {
803 SWAP (left_ptr, right_ptr, size);
804 if (mid == left_ptr)
805 mid = right_ptr;
806 else if (mid == right_ptr)
807 mid = left_ptr;
808 left_ptr += size;
809 right_ptr -= size;
810 }
811 else if (left_ptr == right_ptr)
812 {
813 left_ptr += size;
814 right_ptr -= size;
815 break;
816 }
817 }
818 while (left_ptr <= right_ptr);
819
820 /* Set up pointers for next iteration. First determine whether
821 left and right partitions are below the threshold size. If so,
822 ignore one or both. Otherwise, push the larger partition's
823 bounds on the stack and continue sorting the smaller one. */
824
825 if ((size_t) (right_ptr - lo) <= max_thresh)
826 {
827 if ((size_t) (hi - left_ptr) <= max_thresh)
828 /* Ignore both small partitions. */
829 POP (lo, hi);
830 else
831 /* Ignore small left partition. */
832 lo = left_ptr;
833 }
834 else if ((size_t) (hi - left_ptr) <= max_thresh)
835 /* Ignore small right partition. */
836 hi = right_ptr;
837 else if ((right_ptr - lo) > (hi - left_ptr))
838 {
839 /* Push larger left partition indices. */
840 PUSH (lo, right_ptr);
841 lo = left_ptr;
842 }
843 else
844 {
845 /* Push larger right partition indices. */
846 PUSH (left_ptr, hi);
847 hi = right_ptr;
848 }
849 }
850 }
851
852 /* Once the BASE_PTR array is partially sorted by quicksort the rest
853 is completely sorted using insertion sort, since this is efficient
854 for partitions below MAX_THRESH size. BASE_PTR points to the beginning
855 of the array to sort, and END_PTR points at the very last element in
856 the array (*not* one beyond it!). */
857
858 {
859 char *const end_ptr = &base_ptr[size * (total_elems - 1)];
860 char *tmp_ptr = base_ptr;
861 char *thresh = base_ptr + max_thresh;
862 if ( thresh > end_ptr )
863 thresh = end_ptr;
864 register char *run_ptr;
865
866 /* Find smallest element in first threshold and place it at the
867 array's beginning. This is the smallest array element,
868 and the operation speeds up insertion sort's inner loop. */
869
870 for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
871 if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0)
872 tmp_ptr = run_ptr;
873
874 if (tmp_ptr != base_ptr)
875 SWAP (tmp_ptr, base_ptr, size);
876
877 /* Insertion sort, running from left-hand-side up to right-hand-side. */
878
879 run_ptr = base_ptr + size;
880 while ((run_ptr += size) <= end_ptr)
881 {
882 tmp_ptr = run_ptr - size;
883 while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0)
884 tmp_ptr -= size;
885
886 tmp_ptr += size;
887 if (tmp_ptr != run_ptr)
888 {
889 char *trav;
890
891 trav = run_ptr + size;
892 while (--trav >= run_ptr)
893 {
894 char c = *trav;
895 char *hi, *lo;
896
897 for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
898 *hi = *lo;
899 *hi = c;
900 }
901 }
902 }
903 }
904 }
905
906 #endif // wxUSE_BASE
907
908
909
910 // ============================================================================
911 // GUI-only functions from now on
912 // ============================================================================
913
914 #if wxUSE_GUI
915
916 // this function is only really implemented for X11-based ports, including GTK1
917 // (GTK2 sets detectable auto-repeat automatically anyhow)
918 #if !(defined(__WXX11__) || defined(__WXMOTIF__) || \
919 (defined(__WXGTK__) && !defined(__WXGTK20__)))
920 bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) )
921 {
922 return true;
923 }
924 #endif // !X11-based port
925
926 // ----------------------------------------------------------------------------
927 // Launch default browser
928 // ----------------------------------------------------------------------------
929
930 #if defined(__WXMSW__)
931
932 // implemented in a port-specific utils source file:
933 bool wxDoLaunchDefaultBrowser(const wxString& url, const wxString& scheme, int flags);
934
935 #elif defined(__WXX11__) || defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXCOCOA__) || \
936 (defined(__WXOSX__) )
937
938 // implemented in a port-specific utils source file:
939 bool wxDoLaunchDefaultBrowser(const wxString& url, int flags);
940
941 #else
942
943 // a "generic" implementation:
944 bool wxDoLaunchDefaultBrowser(const wxString& url, int flags)
945 {
946 // on other platforms try to use mime types or wxExecute...
947
948 bool ok = false;
949 wxString cmd;
950
951 #if wxUSE_MIMETYPE
952 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(wxT("html"));
953 if ( ft )
954 {
955 wxString mt;
956 ft->GetMimeType(&mt);
957
958 ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url));
959 delete ft;
960 }
961 #endif // wxUSE_MIMETYPE
962
963 if ( !ok || cmd.empty() )
964 {
965 // fallback to checking for the BROWSER environment variable
966 if ( !wxGetEnv(wxT("BROWSER"), &cmd) || cmd.empty() )
967 cmd << wxT(' ') << url;
968 }
969
970 ok = ( !cmd.empty() && wxExecute(cmd) );
971 if (ok)
972 return ok;
973
974 // no file type for HTML extension
975 wxLogError(_("No default application configured for HTML files."));
976
977 return false;
978 }
979 #endif
980
981 static bool DoLaunchDefaultBrowserHelper(const wxString& urlOrig, int flags)
982 {
983 // NOTE: we don't have to care about the wxBROWSER_NOBUSYCURSOR flag
984 // as it was already handled by wxLaunchDefaultBrowser
985
986 wxUnusedVar(flags);
987
988 wxString url(urlOrig), scheme;
989 wxURI uri(url);
990
991 // this check is useful to avoid that wxURI recognizes as scheme parts of
992 // the filename, in case urlOrig is a local filename
993 // (e.g. "C:\\test.txt" when parsed by wxURI reports a scheme == "C")
994 bool hasValidScheme = uri.HasScheme() && uri.GetScheme().length() > 1;
995
996 #if defined(__WXMSW__)
997
998 // NOTE: when testing wxMSW's wxLaunchDefaultBrowser all possible forms
999 // of the URL/flags should be tested; e.g.:
1000 //
1001 // for (int i=0; i<2; i++)
1002 // {
1003 // // test arguments without a valid URL scheme:
1004 // wxLaunchDefaultBrowser("C:\\test.txt", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1005 // wxLaunchDefaultBrowser("wxwidgets.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1006 //
1007 // // test arguments with different valid schemes:
1008 // wxLaunchDefaultBrowser("file:/C%3A/test.txt", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1009 // wxLaunchDefaultBrowser("http://wxwidgets.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1010 // wxLaunchDefaultBrowser("mailto:user@host.org", i==0 ? 0 : wxBROWSER_NEW_WINDOW);
1011 // }
1012 // (assuming you have a C:\test.txt file)
1013
1014 if ( !hasValidScheme )
1015 {
1016 if (wxFileExists(urlOrig) || wxDirExists(urlOrig))
1017 {
1018 scheme = "file";
1019 // do not prepend the file scheme to the URL as ShellExecuteEx() doesn't like it
1020 }
1021 else
1022 {
1023 url.Prepend(wxS("http://"));
1024 scheme = "http";
1025 }
1026 }
1027 else if ( hasValidScheme )
1028 {
1029 scheme = uri.GetScheme();
1030
1031 if ( uri.GetScheme() == "file" )
1032 {
1033 // TODO: extract URLToFileName() to some always compiled in
1034 // function
1035 #if wxUSE_FILESYSTEM
1036 // ShellExecuteEx() doesn't like the "file" scheme when opening local files;
1037 // remove it
1038 url = wxFileSystem::URLToFileName(url).GetFullPath();
1039 #endif // wxUSE_FILESYSTEM
1040 }
1041 }
1042
1043 if (wxDoLaunchDefaultBrowser(url, scheme, flags))
1044 return true;
1045 //else: call wxLogSysError
1046 #else
1047 if ( !hasValidScheme )
1048 {
1049 // set the scheme of url to "http" or "file" if it does not have one
1050 if (wxFileExists(urlOrig) || wxDirExists(urlOrig))
1051 url.Prepend(wxS("file://"));
1052 else
1053 url.Prepend(wxS("http://"));
1054 }
1055
1056 if (wxDoLaunchDefaultBrowser(url, flags))
1057 return true;
1058 //else: call wxLogSysError
1059 #endif
1060
1061 wxLogSysError(_("Failed to open URL \"%s\" in default browser."),
1062 url.c_str());
1063
1064 return false;
1065 }
1066
1067 bool wxLaunchDefaultBrowser(const wxString& url, int flags)
1068 {
1069 // NOTE: as documented, "url" may be both a real well-formed URL
1070 // and a local file name
1071
1072 if ( flags & wxBROWSER_NOBUSYCURSOR )
1073 return DoLaunchDefaultBrowserHelper(url, flags);
1074
1075 wxBusyCursor bc;
1076 return DoLaunchDefaultBrowserHelper(url, flags);
1077 }
1078
1079 // ----------------------------------------------------------------------------
1080 // Menu accelerators related functions
1081 // ----------------------------------------------------------------------------
1082
1083 #if WXWIN_COMPATIBILITY_2_6
1084 wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out)
1085 {
1086 #if wxUSE_MENUS
1087 wxString s = wxMenuItem::GetLabelText(in);
1088 #else
1089 wxString str(in);
1090 wxString s = wxStripMenuCodes(str);
1091 #endif // wxUSE_MENUS
1092 if ( out )
1093 {
1094 // go smash their buffer if it's not big enough - I love char * params
1095 memcpy(out, s.c_str(), s.length() * sizeof(wxChar));
1096 }
1097 else
1098 {
1099 out = new wxChar[s.length() + 1];
1100 wxStrcpy(out, s.c_str());
1101 }
1102
1103 return out;
1104 }
1105 #endif
1106
1107 wxString wxStripMenuCodes(const wxString& in, int flags)
1108 {
1109 wxASSERT_MSG( flags, wxT("this is useless to call without any flags") );
1110
1111 wxString out;
1112
1113 size_t len = in.length();
1114 out.reserve(len);
1115
1116 for ( size_t n = 0; n < len; n++ )
1117 {
1118 wxChar ch = in[n];
1119 if ( (flags & wxStrip_Mnemonics) && ch == wxT('&') )
1120 {
1121 // skip it, it is used to introduce the accel char (or to quote
1122 // itself in which case it should still be skipped): note that it
1123 // can't be the last character of the string
1124 if ( ++n == len )
1125 {
1126 wxLogDebug(wxT("Invalid menu string '%s'"), in.c_str());
1127 }
1128 else
1129 {
1130 // use the next char instead
1131 ch = in[n];
1132 }
1133 }
1134 else if ( (flags & wxStrip_Accel) && ch == wxT('\t') )
1135 {
1136 // everything after TAB is accel string, exit the loop
1137 break;
1138 }
1139
1140 out += ch;
1141 }
1142
1143 return out;
1144 }
1145
1146 // ----------------------------------------------------------------------------
1147 // Window search functions
1148 // ----------------------------------------------------------------------------
1149
1150 /*
1151 * If parent is non-NULL, look through children for a label or title
1152 * matching the specified string. If NULL, look through all top-level windows.
1153 *
1154 */
1155
1156 wxWindow *
1157 wxFindWindowByLabel (const wxString& title, wxWindow * parent)
1158 {
1159 return wxWindow::FindWindowByLabel( title, parent );
1160 }
1161
1162
1163 /*
1164 * If parent is non-NULL, look through children for a name
1165 * matching the specified string. If NULL, look through all top-level windows.
1166 *
1167 */
1168
1169 wxWindow *
1170 wxFindWindowByName (const wxString& name, wxWindow * parent)
1171 {
1172 return wxWindow::FindWindowByName( name, parent );
1173 }
1174
1175 // Returns menu item id or wxNOT_FOUND if none.
1176 int
1177 wxFindMenuItemId(wxFrame *frame,
1178 const wxString& menuString,
1179 const wxString& itemString)
1180 {
1181 #if wxUSE_MENUS
1182 wxMenuBar *menuBar = frame->GetMenuBar ();
1183 if ( menuBar )
1184 return menuBar->FindMenuItem (menuString, itemString);
1185 #else // !wxUSE_MENUS
1186 wxUnusedVar(frame);
1187 wxUnusedVar(menuString);
1188 wxUnusedVar(itemString);
1189 #endif // wxUSE_MENUS/!wxUSE_MENUS
1190
1191 return wxNOT_FOUND;
1192 }
1193
1194 // Try to find the deepest child that contains 'pt'.
1195 // We go backwards, to try to allow for controls that are spacially
1196 // within other controls, but are still siblings (e.g. buttons within
1197 // static boxes). Static boxes are likely to be created _before_ controls
1198 // that sit inside them.
1199 wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt)
1200 {
1201 if (!win->IsShown())
1202 return NULL;
1203
1204 // Hack for wxNotebook case: at least in wxGTK, all pages
1205 // claim to be shown, so we must only deal with the selected one.
1206 #if wxUSE_NOTEBOOK
1207 if (win->IsKindOf(CLASSINFO(wxNotebook)))
1208 {
1209 wxNotebook* nb = (wxNotebook*) win;
1210 int sel = nb->GetSelection();
1211 if (sel >= 0)
1212 {
1213 wxWindow* child = nb->GetPage(sel);
1214 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1215 if (foundWin)
1216 return foundWin;
1217 }
1218 }
1219 #endif
1220
1221 wxWindowList::compatibility_iterator node = win->GetChildren().GetLast();
1222 while (node)
1223 {
1224 wxWindow* child = node->GetData();
1225 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1226 if (foundWin)
1227 return foundWin;
1228 node = node->GetPrevious();
1229 }
1230
1231 wxPoint pos = win->GetPosition();
1232 wxSize sz = win->GetSize();
1233 if ( !win->IsTopLevel() && win->GetParent() )
1234 {
1235 pos = win->GetParent()->ClientToScreen(pos);
1236 }
1237
1238 wxRect rect(pos, sz);
1239 if (rect.Contains(pt))
1240 return win;
1241
1242 return NULL;
1243 }
1244
1245 wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt)
1246 {
1247 // Go backwards through the list since windows
1248 // on top are likely to have been appended most
1249 // recently.
1250 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast();
1251 while (node)
1252 {
1253 wxWindow* win = node->GetData();
1254 wxWindow* found = wxFindWindowAtPoint(win, pt);
1255 if (found)
1256 return found;
1257 node = node->GetPrevious();
1258 }
1259 return NULL;
1260 }
1261
1262 // ----------------------------------------------------------------------------
1263 // GUI helpers
1264 // ----------------------------------------------------------------------------
1265
1266 /*
1267 * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp
1268 * since otherwise the generic code may be pulled in unnecessarily.
1269 */
1270
1271 #if wxUSE_MSGDLG
1272
1273 int wxMessageBox(const wxString& message, const wxString& caption, long style,
1274 wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) )
1275 {
1276 // add the appropriate icon unless this was explicitly disabled by use of
1277 // wxICON_NONE
1278 if ( !(style & wxICON_NONE) && !(style & wxICON_MASK) )
1279 {
1280 style |= style & wxYES ? wxICON_QUESTION : wxICON_INFORMATION;
1281 }
1282
1283 wxMessageDialog dialog(parent, message, caption, style);
1284
1285 int ans = dialog.ShowModal();
1286 switch ( ans )
1287 {
1288 case wxID_OK:
1289 return wxOK;
1290 case wxID_YES:
1291 return wxYES;
1292 case wxID_NO:
1293 return wxNO;
1294 case wxID_CANCEL:
1295 return wxCANCEL;
1296 }
1297
1298 wxFAIL_MSG( wxT("unexpected return code from wxMessageDialog") );
1299
1300 return wxCANCEL;
1301 }
1302
1303 void wxInfoMessageBox(wxWindow* parent)
1304 {
1305 // don't translate these strings, they're for diagnostics purposes only
1306 wxString msg;
1307 msg.Printf(wxS("wxWidgets Library (%s port)\n")
1308 wxS("Version %d.%d.%d (Unicode: %s, debug level: %d),\n")
1309 wxS("compiled at %s %s\n\n")
1310 wxS("Runtime version of toolkit used is %d.%d.\n"),
1311 wxPlatformInfo::Get().GetPortIdName(),
1312 wxMAJOR_VERSION,
1313 wxMINOR_VERSION,
1314 wxRELEASE_NUMBER,
1315 #if wxUSE_UNICODE_UTF8
1316 "UTF-8",
1317 #elif wxUSE_UNICODE
1318 "wchar_t",
1319 #else
1320 "none",
1321 #endif
1322 wxDEBUG_LEVEL,
1323 __TDATE__,
1324 __TTIME__,
1325 wxPlatformInfo::Get().GetToolkitMajorVersion(),
1326 wxPlatformInfo::Get().GetToolkitMinorVersion()
1327 );
1328
1329 #ifdef __WXGTK__
1330 msg += wxString::Format("Compile-time GTK+ version is %d.%d.%d.\n",
1331 GTK_MAJOR_VERSION,
1332 GTK_MINOR_VERSION,
1333 GTK_MICRO_VERSION);
1334 #endif // __WXGTK__
1335
1336 msg += wxS("\nCopyright (c) 1995-2010 wxWidgets team");
1337
1338 wxMessageBox(msg, wxT("wxWidgets information"),
1339 wxICON_INFORMATION | wxOK,
1340 parent);
1341 }
1342
1343 #endif // wxUSE_MSGDLG
1344
1345 #if wxUSE_TEXTDLG
1346
1347 wxString wxGetTextFromUser(const wxString& message, const wxString& caption,
1348 const wxString& defaultValue, wxWindow *parent,
1349 wxCoord x, wxCoord y, bool centre )
1350 {
1351 wxString str;
1352 long style = wxTextEntryDialogStyle;
1353
1354 if (centre)
1355 style |= wxCENTRE;
1356 else
1357 style &= ~wxCENTRE;
1358
1359 wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y));
1360
1361 if (dialog.ShowModal() == wxID_OK)
1362 {
1363 str = dialog.GetValue();
1364 }
1365
1366 return str;
1367 }
1368
1369 wxString wxGetPasswordFromUser(const wxString& message,
1370 const wxString& caption,
1371 const wxString& defaultValue,
1372 wxWindow *parent,
1373 wxCoord x, wxCoord y, bool centre )
1374 {
1375 wxString str;
1376 long style = wxTextEntryDialogStyle;
1377
1378 if (centre)
1379 style |= wxCENTRE;
1380 else
1381 style &= ~wxCENTRE;
1382
1383 wxPasswordEntryDialog dialog(parent, message, caption, defaultValue,
1384 style, wxPoint(x, y));
1385 if ( dialog.ShowModal() == wxID_OK )
1386 {
1387 str = dialog.GetValue();
1388 }
1389
1390 return str;
1391 }
1392
1393 #endif // wxUSE_TEXTDLG
1394
1395 #if wxUSE_COLOURDLG
1396
1397 wxColour wxGetColourFromUser(wxWindow *parent,
1398 const wxColour& colInit,
1399 const wxString& caption,
1400 wxColourData *ptrData)
1401 {
1402 // contains serialized representation of wxColourData used the last time
1403 // the dialog was shown: we want to reuse it the next time in order to show
1404 // the same custom colours to the user (and we can't just have static
1405 // wxColourData itself because it's a GUI object and so should be destroyed
1406 // before GUI shutdown and doing it during static cleanup is too late)
1407 static wxString s_strColourData;
1408
1409 wxColourData data;
1410 if ( !ptrData )
1411 {
1412 ptrData = &data;
1413 if ( !s_strColourData.empty() )
1414 {
1415 if ( !data.FromString(s_strColourData) )
1416 {
1417 wxFAIL_MSG( "bug in wxColourData::FromString()?" );
1418 }
1419
1420 #ifdef __WXMSW__
1421 // we don't get back the "choose full" flag value from the native
1422 // dialog and so we can't preserve it between runs, so we decide to
1423 // always use it as it seems better than not using it (user can
1424 // just ignore the extra controls in the dialog but having to click
1425 // a button each time to show them would be very annoying
1426 data.SetChooseFull(true);
1427 #endif // __WXMSW__
1428 }
1429 }
1430
1431 if ( colInit.IsOk() )
1432 {
1433 ptrData->SetColour(colInit);
1434 }
1435
1436 wxColour colRet;
1437 wxColourDialog dialog(parent, ptrData);
1438 if (!caption.empty())
1439 dialog.SetTitle(caption);
1440 if ( dialog.ShowModal() == wxID_OK )
1441 {
1442 *ptrData = dialog.GetColourData();
1443 colRet = ptrData->GetColour();
1444 s_strColourData = ptrData->ToString();
1445 }
1446 //else: leave colRet invalid
1447
1448 return colRet;
1449 }
1450
1451 #endif // wxUSE_COLOURDLG
1452
1453 #if wxUSE_FONTDLG
1454
1455 wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption)
1456 {
1457 wxFontData data;
1458 if ( fontInit.Ok() )
1459 {
1460 data.SetInitialFont(fontInit);
1461 }
1462
1463 wxFont fontRet;
1464 wxFontDialog dialog(parent, data);
1465 if (!caption.empty())
1466 dialog.SetTitle(caption);
1467 if ( dialog.ShowModal() == wxID_OK )
1468 {
1469 fontRet = dialog.GetFontData().GetChosenFont();
1470 }
1471 //else: leave it invalid
1472
1473 return fontRet;
1474 }
1475
1476 #endif // wxUSE_FONTDLG
1477
1478 // ----------------------------------------------------------------------------
1479 // wxSafeYield and supporting functions
1480 // ----------------------------------------------------------------------------
1481
1482 void wxEnableTopLevelWindows(bool enable)
1483 {
1484 wxWindowList::compatibility_iterator node;
1485 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1486 node->GetData()->Enable(enable);
1487 }
1488
1489 wxWindowDisabler::wxWindowDisabler(bool disable)
1490 {
1491 m_disabled = disable;
1492 if ( disable )
1493 DoDisable();
1494 }
1495
1496 wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
1497 {
1498 m_disabled = true;
1499 DoDisable(winToSkip);
1500 }
1501
1502 void wxWindowDisabler::DoDisable(wxWindow *winToSkip)
1503 {
1504 // remember the top level windows which were already disabled, so that we
1505 // don't reenable them later
1506 m_winDisabled = NULL;
1507
1508 wxWindowList::compatibility_iterator node;
1509 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1510 {
1511 wxWindow *winTop = node->GetData();
1512 if ( winTop == winToSkip )
1513 continue;
1514
1515 // we don't need to disable the hidden or already disabled windows
1516 if ( winTop->IsEnabled() && winTop->IsShown() )
1517 {
1518 winTop->Disable();
1519 }
1520 else
1521 {
1522 if ( !m_winDisabled )
1523 {
1524 m_winDisabled = new wxWindowList;
1525 }
1526
1527 m_winDisabled->Append(winTop);
1528 }
1529 }
1530 }
1531
1532 wxWindowDisabler::~wxWindowDisabler()
1533 {
1534 if ( !m_disabled )
1535 return;
1536
1537 wxWindowList::compatibility_iterator node;
1538 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1539 {
1540 wxWindow *winTop = node->GetData();
1541 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
1542 {
1543 winTop->Enable();
1544 }
1545 //else: had been already disabled, don't reenable
1546 }
1547
1548 delete m_winDisabled;
1549 }
1550
1551 // Yield to other apps/messages and disable user input to all windows except
1552 // the given one
1553 bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
1554 {
1555 wxWindowDisabler wd(win);
1556
1557 bool rc;
1558 if (onlyIfNeeded)
1559 rc = wxYieldIfNeeded();
1560 else
1561 rc = wxYield();
1562
1563 return rc;
1564 }
1565
1566 // ----------------------------------------------------------------------------
1567 // wxApp::Yield() wrappers for backwards compatibility
1568 // ----------------------------------------------------------------------------
1569
1570 bool wxYield()
1571 {
1572 return wxTheApp && wxTheApp->Yield();
1573 }
1574
1575 bool wxYieldIfNeeded()
1576 {
1577 return wxTheApp && wxTheApp->Yield(true);
1578 }
1579
1580 #endif // wxUSE_GUI