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