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