]> git.saurik.com Git - wxWidgets.git/blob - src/common/utilscmn.cpp
add wxUSE_DATAVIEWCTRL check to fix a hundred compilation errors
[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 (err == noErr)
1059 {
1060 ConstStr255Param hint = 0;
1061 startSel = 0;
1062 endSel = url.length();
1063 err = ICLaunchURL(inst, hint, url.fn_str(), endSel, &startSel, &endSel);
1064 if (err != noErr)
1065 wxLogDebug(wxT("ICLaunchURL error %d"), (int) err);
1066 }
1067 ICStop(inst);
1068 return true;
1069 }
1070 else
1071 {
1072 wxLogDebug(wxT("ICStart error %d"), (int) err);
1073 return false;
1074 }
1075 #else
1076 // (non-Mac, non-MSW)
1077
1078 #ifdef __UNIX__
1079
1080 wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment();
1081
1082 // GNOME and KDE desktops have some applications which should be always installed
1083 // together with their main parts, which give us the
1084 if (desktop == wxT("GNOME"))
1085 {
1086 wxArrayString errors;
1087 wxArrayString output;
1088
1089 // gconf will tell us the path of the application to use as browser
1090 long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"),
1091 output, errors, wxEXEC_NODISABLE );
1092 if (res >= 0 && errors.GetCount() == 0)
1093 {
1094 wxString cmd = output[0];
1095 cmd << _T(' ') << url;
1096 if (wxExecute(cmd))
1097 return true;
1098 }
1099 }
1100 else if (desktop == wxT("KDE"))
1101 {
1102 // kfmclient directly opens the given URL
1103 if (wxExecute(wxT("kfmclient openURL ") + url))
1104 return true;
1105 }
1106 #endif
1107
1108 bool ok = false;
1109 wxString cmd;
1110
1111 #if wxUSE_MIMETYPE
1112 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html"));
1113 if ( ft )
1114 {
1115 wxString mt;
1116 ft->GetMimeType(&mt);
1117
1118 ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url));
1119 delete ft;
1120 }
1121 #endif // wxUSE_MIMETYPE
1122
1123 if ( !ok || cmd.empty() )
1124 {
1125 // fallback to checking for the BROWSER environment variable
1126 cmd = wxGetenv(wxT("BROWSER"));
1127 if ( !cmd.empty() )
1128 cmd << _T(' ') << url;
1129 }
1130
1131 ok = ( !cmd.empty() && wxExecute(cmd) );
1132 if (ok)
1133 return ok;
1134
1135 // no file type for HTML extension
1136 wxLogError(_T("No default application configured for HTML files."));
1137
1138 #endif // !wxUSE_MIMETYPE && !__WXMSW__
1139
1140 wxLogSysError(_T("Failed to open URL \"%s\" in default browser."),
1141 url.c_str());
1142
1143 return false;
1144 }
1145
1146 // ----------------------------------------------------------------------------
1147 // Menu accelerators related functions
1148 // ----------------------------------------------------------------------------
1149
1150 wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out)
1151 {
1152 #if wxUSE_MENUS
1153 wxString s = wxMenuItem::GetLabelText(in);
1154 #else
1155 wxString str(in);
1156 wxString s = wxStripMenuCodes(str);
1157 #endif // wxUSE_MENUS
1158 if ( out )
1159 {
1160 // go smash their buffer if it's not big enough - I love char * params
1161 memcpy(out, s.c_str(), s.length() * sizeof(wxChar));
1162 }
1163 else
1164 {
1165 out = new wxChar[s.length() + 1];
1166 wxStrcpy(out, s.c_str());
1167 }
1168
1169 return out;
1170 }
1171
1172 wxString wxStripMenuCodes(const wxString& in, int flags)
1173 {
1174 wxASSERT_MSG( flags, _T("this is useless to call without any flags") );
1175
1176 wxString out;
1177
1178 size_t len = in.length();
1179 out.reserve(len);
1180
1181 for ( size_t n = 0; n < len; n++ )
1182 {
1183 wxChar ch = in[n];
1184 if ( (flags & wxStrip_Mnemonics) && ch == _T('&') )
1185 {
1186 // skip it, it is used to introduce the accel char (or to quote
1187 // itself in which case it should still be skipped): note that it
1188 // can't be the last character of the string
1189 if ( ++n == len )
1190 {
1191 wxLogDebug(_T("Invalid menu string '%s'"), in.c_str());
1192 }
1193 else
1194 {
1195 // use the next char instead
1196 ch = in[n];
1197 }
1198 }
1199 else if ( (flags & wxStrip_Accel) && ch == _T('\t') )
1200 {
1201 // everything after TAB is accel string, exit the loop
1202 break;
1203 }
1204
1205 out += ch;
1206 }
1207
1208 return out;
1209 }
1210
1211 // ----------------------------------------------------------------------------
1212 // Window search functions
1213 // ----------------------------------------------------------------------------
1214
1215 /*
1216 * If parent is non-NULL, look through children for a label or title
1217 * matching the specified string. If NULL, look through all top-level windows.
1218 *
1219 */
1220
1221 wxWindow *
1222 wxFindWindowByLabel (const wxString& title, wxWindow * parent)
1223 {
1224 return wxWindow::FindWindowByLabel( title, parent );
1225 }
1226
1227
1228 /*
1229 * If parent is non-NULL, look through children for a name
1230 * matching the specified string. If NULL, look through all top-level windows.
1231 *
1232 */
1233
1234 wxWindow *
1235 wxFindWindowByName (const wxString& name, wxWindow * parent)
1236 {
1237 return wxWindow::FindWindowByName( name, parent );
1238 }
1239
1240 // Returns menu item id or wxNOT_FOUND if none.
1241 int
1242 wxFindMenuItemId(wxFrame *frame,
1243 const wxString& menuString,
1244 const wxString& itemString)
1245 {
1246 #if wxUSE_MENUS
1247 wxMenuBar *menuBar = frame->GetMenuBar ();
1248 if ( menuBar )
1249 return menuBar->FindMenuItem (menuString, itemString);
1250 #else // !wxUSE_MENUS
1251 wxUnusedVar(frame);
1252 wxUnusedVar(menuString);
1253 wxUnusedVar(itemString);
1254 #endif // wxUSE_MENUS/!wxUSE_MENUS
1255
1256 return wxNOT_FOUND;
1257 }
1258
1259 // Try to find the deepest child that contains 'pt'.
1260 // We go backwards, to try to allow for controls that are spacially
1261 // within other controls, but are still siblings (e.g. buttons within
1262 // static boxes). Static boxes are likely to be created _before_ controls
1263 // that sit inside them.
1264 wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt)
1265 {
1266 if (!win->IsShown())
1267 return NULL;
1268
1269 // Hack for wxNotebook case: at least in wxGTK, all pages
1270 // claim to be shown, so we must only deal with the selected one.
1271 #if wxUSE_NOTEBOOK
1272 if (win->IsKindOf(CLASSINFO(wxNotebook)))
1273 {
1274 wxNotebook* nb = (wxNotebook*) win;
1275 int sel = nb->GetSelection();
1276 if (sel >= 0)
1277 {
1278 wxWindow* child = nb->GetPage(sel);
1279 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1280 if (foundWin)
1281 return foundWin;
1282 }
1283 }
1284 #endif
1285
1286 wxWindowList::compatibility_iterator node = win->GetChildren().GetLast();
1287 while (node)
1288 {
1289 wxWindow* child = node->GetData();
1290 wxWindow* foundWin = wxFindWindowAtPoint(child, pt);
1291 if (foundWin)
1292 return foundWin;
1293 node = node->GetPrevious();
1294 }
1295
1296 wxPoint pos = win->GetPosition();
1297 wxSize sz = win->GetSize();
1298 if ( !win->IsTopLevel() && win->GetParent() )
1299 {
1300 pos = win->GetParent()->ClientToScreen(pos);
1301 }
1302
1303 wxRect rect(pos, sz);
1304 if (rect.Contains(pt))
1305 return win;
1306
1307 return NULL;
1308 }
1309
1310 wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt)
1311 {
1312 // Go backwards through the list since windows
1313 // on top are likely to have been appended most
1314 // recently.
1315 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast();
1316 while (node)
1317 {
1318 wxWindow* win = node->GetData();
1319 wxWindow* found = wxFindWindowAtPoint(win, pt);
1320 if (found)
1321 return found;
1322 node = node->GetPrevious();
1323 }
1324 return NULL;
1325 }
1326
1327 // ----------------------------------------------------------------------------
1328 // GUI helpers
1329 // ----------------------------------------------------------------------------
1330
1331 /*
1332 * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp
1333 * since otherwise the generic code may be pulled in unnecessarily.
1334 */
1335
1336 #if wxUSE_MSGDLG
1337
1338 int wxMessageBox(const wxString& message, const wxString& caption, long style,
1339 wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) )
1340 {
1341 long decorated_style = style;
1342
1343 if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 )
1344 {
1345 decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ;
1346 }
1347
1348 wxMessageDialog dialog(parent, message, caption, decorated_style);
1349
1350 int ans = dialog.ShowModal();
1351 switch ( ans )
1352 {
1353 case wxID_OK:
1354 return wxOK;
1355 case wxID_YES:
1356 return wxYES;
1357 case wxID_NO:
1358 return wxNO;
1359 case wxID_CANCEL:
1360 return wxCANCEL;
1361 }
1362
1363 wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") );
1364
1365 return wxCANCEL;
1366 }
1367
1368 #endif // wxUSE_MSGDLG
1369
1370 #if wxUSE_TEXTDLG
1371
1372 wxString wxGetTextFromUser(const wxString& message, const wxString& caption,
1373 const wxString& defaultValue, wxWindow *parent,
1374 wxCoord x, wxCoord y, bool centre )
1375 {
1376 wxString str;
1377 long style = wxTextEntryDialogStyle;
1378
1379 if (centre)
1380 style |= wxCENTRE;
1381 else
1382 style &= ~wxCENTRE;
1383
1384 wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y));
1385
1386 if (dialog.ShowModal() == wxID_OK)
1387 {
1388 str = dialog.GetValue();
1389 }
1390
1391 return str;
1392 }
1393
1394 wxString wxGetPasswordFromUser(const wxString& message,
1395 const wxString& caption,
1396 const wxString& defaultValue,
1397 wxWindow *parent,
1398 wxCoord x, wxCoord y, bool centre )
1399 {
1400 wxString str;
1401 long style = wxTextEntryDialogStyle;
1402
1403 if (centre)
1404 style |= wxCENTRE;
1405 else
1406 style &= ~wxCENTRE;
1407
1408 wxPasswordEntryDialog dialog(parent, message, caption, defaultValue,
1409 style, wxPoint(x, y));
1410 if ( dialog.ShowModal() == wxID_OK )
1411 {
1412 str = dialog.GetValue();
1413 }
1414
1415 return str;
1416 }
1417
1418 #endif // wxUSE_TEXTDLG
1419
1420 #if wxUSE_COLOURDLG
1421
1422 wxColour wxGetColourFromUser(wxWindow *parent, const wxColour& colInit, const wxString& caption)
1423 {
1424 wxColourData data;
1425 data.SetChooseFull(true);
1426 if ( colInit.Ok() )
1427 {
1428 data.SetColour((wxColour &)colInit); // const_cast
1429 }
1430
1431 wxColour colRet;
1432 wxColourDialog dialog(parent, &data);
1433 if (!caption.empty())
1434 dialog.SetTitle(caption);
1435 if ( dialog.ShowModal() == wxID_OK )
1436 {
1437 colRet = dialog.GetColourData().GetColour();
1438 }
1439 //else: leave it invalid
1440
1441 return colRet;
1442 }
1443
1444 #endif // wxUSE_COLOURDLG
1445
1446 #if wxUSE_FONTDLG
1447
1448 wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption)
1449 {
1450 wxFontData data;
1451 if ( fontInit.Ok() )
1452 {
1453 data.SetInitialFont(fontInit);
1454 }
1455
1456 wxFont fontRet;
1457 wxFontDialog dialog(parent, data);
1458 if (!caption.empty())
1459 dialog.SetTitle(caption);
1460 if ( dialog.ShowModal() == wxID_OK )
1461 {
1462 fontRet = dialog.GetFontData().GetChosenFont();
1463 }
1464 //else: leave it invalid
1465
1466 return fontRet;
1467 }
1468
1469 #endif // wxUSE_FONTDLG
1470
1471 // ----------------------------------------------------------------------------
1472 // wxSafeYield and supporting functions
1473 // ----------------------------------------------------------------------------
1474
1475 void wxEnableTopLevelWindows(bool enable)
1476 {
1477 wxWindowList::compatibility_iterator node;
1478 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1479 node->GetData()->Enable(enable);
1480 }
1481
1482 wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
1483 {
1484 // remember the top level windows which were already disabled, so that we
1485 // don't reenable them later
1486 m_winDisabled = NULL;
1487
1488 wxWindowList::compatibility_iterator node;
1489 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1490 {
1491 wxWindow *winTop = node->GetData();
1492 if ( winTop == winToSkip )
1493 continue;
1494
1495 // we don't need to disable the hidden or already disabled windows
1496 if ( winTop->IsEnabled() && winTop->IsShown() )
1497 {
1498 winTop->Disable();
1499 }
1500 else
1501 {
1502 if ( !m_winDisabled )
1503 {
1504 m_winDisabled = new wxWindowList;
1505 }
1506
1507 m_winDisabled->Append(winTop);
1508 }
1509 }
1510 }
1511
1512 wxWindowDisabler::~wxWindowDisabler()
1513 {
1514 wxWindowList::compatibility_iterator node;
1515 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
1516 {
1517 wxWindow *winTop = node->GetData();
1518 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
1519 {
1520 winTop->Enable();
1521 }
1522 //else: had been already disabled, don't reenable
1523 }
1524
1525 delete m_winDisabled;
1526 }
1527
1528 // Yield to other apps/messages and disable user input to all windows except
1529 // the given one
1530 bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
1531 {
1532 wxWindowDisabler wd(win);
1533
1534 bool rc;
1535 if (onlyIfNeeded)
1536 rc = wxYieldIfNeeded();
1537 else
1538 rc = wxYield();
1539
1540 return rc;
1541 }
1542
1543 // Don't synthesize KeyUp events holding down a key and producing KeyDown
1544 // events with autorepeat. On by default and always on in wxMSW. wxGTK version
1545 // in utilsgtk.cpp.
1546 #ifndef __WXGTK__
1547 bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) )
1548 {
1549 return true; // detectable auto-repeat is the only mode MSW supports
1550 }
1551 #endif // !wxGTK
1552
1553 #endif // wxUSE_GUI