]>
Commit | Line | Data |
---|---|---|
d7463f75 JS |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: utils.cpp | |
3 | // Purpose: Utility functions and classes | |
4 | // Author: Julian Smart | |
5 | // Modified by: | |
6 | // Created: 2002-09-04 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Julian Smart | |
4fe30bce | 9 | // Licence: |
d7463f75 JS |
10 | ///////////////////////////////////////////////////////////////////////////// |
11 | ||
12 | #ifdef __GNUG__ | |
13 | // #pragma implementation | |
14 | #endif | |
15 | ||
d9ab621e WS |
16 | // For compilers that support precompilation, includes "wx/wx.h". |
17 | #include "wx/wxprec.h" | |
18 | ||
19 | #ifdef __BORLANDC__ | |
20 | #pragma hdrstop | |
21 | #endif | |
22 | ||
23 | #include <math.h> | |
24 | ||
25 | #ifndef WX_PRECOMP | |
26 | ||
d7463f75 | 27 | #include "wx/splitter.h" |
d7463f75 JS |
28 | #include "wx/datstrm.h" |
29 | #include "wx/file.h" | |
30 | #include "wx/listctrl.h" | |
d7463f75 | 31 | #include "wx/process.h" |
d7463f75 | 32 | #include "wx/variant.h" |
d7463f75 | 33 | #include "wx/cmdline.h" |
60c474a0 MB |
34 | #include "wx/msgdlg.h" |
35 | #include "wx/log.h" | |
d21f1d8f MB |
36 | #include "wx/sizer.h" |
37 | #include "wx/icon.h" | |
d7463f75 | 38 | |
d7463f75 JS |
39 | #endif |
40 | ||
d9ab621e WS |
41 | #include "wx/wfstream.h" |
42 | #include "wx/cshelp.h" | |
43 | #include "wx/image.h" | |
44 | #include "wx/imaglist.h" | |
45 | #include "wx/tokenzr.h" | |
46 | #include "wx/notebook.h" | |
47 | #include "wx/mimetype.h" | |
d7463f75 JS |
48 | #include "utils.h" |
49 | ||
50 | // Returns the image type, or -1, determined from the extension. | |
51 | int apDetermineImageType(const wxString& filename) | |
52 | { | |
53 | wxString path, name, ext; | |
54 | ||
55 | wxSplitPath(filename, & path, & name, & ext); | |
56 | ||
57 | ext.MakeLower(); | |
69da0d99 | 58 | if (ext == _T("jpg") || ext == _T("jpeg")) |
d7463f75 | 59 | return wxBITMAP_TYPE_JPEG; |
69da0d99 | 60 | else if (ext == _T("gif")) |
d7463f75 | 61 | return wxBITMAP_TYPE_GIF; |
69da0d99 | 62 | else if (ext == _T("bmp")) |
d7463f75 | 63 | return wxBITMAP_TYPE_BMP; |
69da0d99 | 64 | else if (ext == _T("png")) |
d7463f75 | 65 | return wxBITMAP_TYPE_PNG; |
69da0d99 | 66 | else if (ext == _T("pcx")) |
d7463f75 | 67 | return wxBITMAP_TYPE_PCX; |
69da0d99 | 68 | else if (ext == _T("tif") || ext == _T("tiff")) |
d7463f75 JS |
69 | return wxBITMAP_TYPE_TIF; |
70 | else | |
71 | return -1; | |
72 | } | |
73 | ||
74 | // Convert a colour to a 6-digit hex string | |
75 | wxString apColourToHexString(const wxColour& col) | |
76 | { | |
77 | wxString hex; | |
78 | ||
79 | hex += wxDecToHex(col.Red()); | |
80 | hex += wxDecToHex(col.Green()); | |
81 | hex += wxDecToHex(col.Blue()); | |
82 | ||
83 | return hex; | |
84 | } | |
85 | ||
86 | // Convert 6-digit hex string to a colour | |
87 | wxColour apHexStringToColour(const wxString& hex) | |
88 | { | |
254a2129 WS |
89 | unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2)); |
90 | unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2)); | |
91 | unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2)); | |
d7463f75 JS |
92 | |
93 | return wxColour(r, g, b); | |
94 | } | |
95 | ||
96 | // Convert a wxFont to a string | |
97 | wxString apFontToString(const wxFont& font) | |
98 | { | |
99 | wxString str; | |
100 | str.Printf(wxT("%d,%d,%d,%d,%d,%s"), (int) font.GetPointSize(), | |
101 | (int) font.GetFamily(), (int) font.GetStyle(), (int) font.GetWeight(), | |
102 | (int) font.GetUnderlined(), font.GetFaceName().c_str()); | |
103 | ||
104 | return str; | |
105 | } | |
106 | ||
3ac35b57 MB |
107 | static inline int StringToInt(const wxString& s) |
108 | { | |
109 | long tmp; | |
110 | s.ToLong(&tmp); | |
111 | ||
112 | return int(tmp); | |
113 | } | |
114 | ||
d7463f75 JS |
115 | // Convert a string to a wxFont |
116 | wxFont apStringToFont(const wxString& str) | |
117 | { | |
118 | int pointSize = 12; | |
119 | int family = wxSWISS; | |
120 | int style = wxNORMAL; | |
121 | int weight = wxNORMAL; | |
122 | int underlined = 0; | |
123 | wxString facename(wxT("")); | |
124 | ||
125 | wxStringTokenizer tkz(str, wxT(",")); | |
126 | int i = 0; | |
127 | while (tkz.HasMoreTokens()) | |
128 | { | |
129 | wxString token = tkz.GetNextToken(); | |
130 | ||
131 | if (i == 0) | |
132 | { | |
3ac35b57 | 133 | pointSize = StringToInt(token); |
d7463f75 JS |
134 | #if defined(__WXGTK__) || defined(__WXMAC__) |
135 | if (pointSize < 8) | |
136 | pointSize = 8; | |
137 | if (pointSize == 9) | |
138 | pointSize = 10; | |
254a2129 | 139 | #endif |
d7463f75 JS |
140 | } |
141 | else if (i == 1) | |
3ac35b57 | 142 | family = StringToInt(token); |
d7463f75 | 143 | else if (i == 2) |
3ac35b57 | 144 | style = StringToInt(token); |
d7463f75 | 145 | else if (i == 3) |
3ac35b57 | 146 | weight = StringToInt(token); |
d7463f75 | 147 | else if (i == 4) |
3ac35b57 | 148 | underlined = StringToInt(token); |
d7463f75 JS |
149 | else if (i == 5) |
150 | { | |
151 | facename = token; | |
152 | #if defined(__WXGTK__) | |
153 | if (facename == wxT("Arial")) | |
154 | facename = wxT("helvetica"); | |
155 | #endif | |
156 | } | |
157 | i ++; | |
158 | ||
159 | } | |
160 | return wxFont(pointSize, family, style, weight, (underlined != 0), facename); | |
161 | } | |
162 | ||
163 | ||
164 | // Get the index of the given named wxNotebook page | |
165 | int apFindNotebookPage(wxNotebook* notebook, const wxString& name) | |
166 | { | |
167 | int i; | |
69da0d99 | 168 | for (i = 0; i < (int)notebook->GetPageCount(); i++) |
d7463f75 JS |
169 | if (name == notebook->GetPageText(i)) |
170 | return i; | |
171 | return -1; | |
172 | } | |
173 | ||
174 | /* | |
175 | * View an HTML file | |
176 | */ | |
177 | ||
178 | void apViewHTMLFile(const wxString& url) | |
179 | { | |
180 | #ifdef __WXMSW__ | |
181 | HKEY hKey; | |
182 | TCHAR szCmdName[1024]; | |
183 | DWORD dwType, dw = sizeof(szCmdName); | |
184 | LONG lRes; | |
69da0d99 | 185 | lRes = RegOpenKey(HKEY_CLASSES_ROOT, _T("htmlfile\\shell\\open\\command"), &hKey); |
d7463f75 JS |
186 | if(lRes == ERROR_SUCCESS && RegQueryValueEx(hKey,(LPTSTR)NULL, NULL, |
187 | &dwType, (LPBYTE)szCmdName, &dw) == ERROR_SUCCESS) | |
188 | { | |
69da0d99 | 189 | wxStrcat(szCmdName, (const wxChar*) url); |
d7463f75 JS |
190 | PROCESS_INFORMATION piProcInfo; |
191 | STARTUPINFO siStartInfo; | |
192 | memset(&siStartInfo, 0, sizeof(STARTUPINFO)); | |
193 | siStartInfo.cb = sizeof(STARTUPINFO); | |
4fe30bce | 194 | CreateProcess(NULL, szCmdName, NULL, NULL, false, 0, NULL, |
d7463f75 JS |
195 | NULL, &siStartInfo, &piProcInfo ); |
196 | } | |
197 | if(lRes == ERROR_SUCCESS) | |
198 | RegCloseKey(hKey); | |
199 | #else | |
200 | wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(wxT("html")); | |
201 | if ( !ft ) | |
202 | { | |
203 | wxLogError(_T("Impossible to determine the file type for extension html. Please edit your MIME types.")); | |
204 | return ; | |
205 | } | |
206 | ||
207 | wxString cmd; | |
208 | bool ok = ft->GetOpenCommand(&cmd, | |
209 | wxFileType::MessageParameters(url, _T(""))); | |
210 | delete ft; | |
211 | ||
212 | if (!ok) | |
213 | { | |
214 | // TODO: some kind of configuration dialog here. | |
215 | wxMessageBox(_("Could not determine the command for running the browser."), | |
4fe30bce | 216 | wxT("Browsing problem"), wxOK|wxICON_EXCLAMATION); |
d7463f75 JS |
217 | return ; |
218 | } | |
219 | ||
4fe30bce | 220 | ok = (wxExecute(cmd, false) != 0); |
d7463f75 JS |
221 | #endif |
222 | } | |
223 | ||
224 | wxString wxGetTempDir() | |
225 | { | |
226 | wxString dir; | |
227 | #if defined(__WXMAC__) && !defined(__DARWIN__) | |
228 | dir = wxMacFindFolder( (short) kOnSystemDisk, kTemporaryFolderType, kCreateFolder ) ; | |
229 | #else // !Mac | |
d9ab621e WS |
230 | wxString dirEnv(wxGetenv(_T("TMP"))); |
231 | dir = dirEnv; | |
d7463f75 JS |
232 | if ( dir.empty() ) |
233 | { | |
d9ab621e WS |
234 | wxString envVar(wxGetenv(_T("TEMP"))); |
235 | dir = envVar; | |
d7463f75 | 236 | } |
254a2129 | 237 | |
d7463f75 JS |
238 | if ( dir.empty() ) |
239 | { | |
240 | // default | |
241 | #ifdef __DOS__ | |
242 | dir = _T("."); | |
243 | #else | |
244 | dir = _T("/tmp"); | |
245 | #endif | |
246 | } | |
247 | #endif // Mac/!Mac | |
248 | return dir; | |
249 | } | |
250 | ||
251 | // Invoke app for file type | |
252 | // Eventually we should allow the user to select an app. | |
253 | bool apInvokeAppForFile(const wxString& filename) | |
254 | { | |
255 | wxString path, file, ext; | |
256 | wxSplitPath(filename, & path, & file, & ext); | |
257 | ||
258 | wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); | |
259 | if ( !ft ) | |
260 | { | |
261 | wxString msg; | |
262 | msg.Printf(wxT("Sorry, could not determine what application to invoke for extension %s\nYou may need to edit your MIME types."), | |
263 | ext.c_str()); | |
264 | wxMessageBox(msg, wxT("Application Invocation"), wxICON_EXCLAMATION|wxOK); | |
4fe30bce | 265 | return false; |
d7463f75 JS |
266 | } |
267 | ||
268 | wxString cmd; | |
79830320 | 269 | ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(filename, _T(""))); |
d7463f75 JS |
270 | delete ft; |
271 | ||
4fe30bce | 272 | return (wxExecute(cmd, false) != 0); |
d7463f75 JS |
273 | } |
274 | ||
275 | // Find the absolute path where this application has been run from. | |
276 | // argv0 is wxTheApp->argv[0] | |
277 | // cwd is the current working directory (at startup) | |
278 | // appVariableName is the name of a variable containing the directory for this app, e.g. | |
279 | // MYAPPDIR. This is checked first. | |
280 | ||
281 | wxString apFindAppPath(const wxString& argv0, const wxString& cwd, const wxString& appVariableName) | |
282 | { | |
d7463f75 JS |
283 | // Try appVariableName |
284 | if (!appVariableName.IsEmpty()) | |
285 | { | |
d9ab621e WS |
286 | wxString strVar(wxGetenv(appVariableName.c_str())); |
287 | if (!strVar.IsEmpty()) | |
288 | return strVar; | |
d7463f75 JS |
289 | } |
290 | ||
291 | if (wxIsAbsolutePath(argv0)) | |
292 | return wxPathOnly(argv0); | |
293 | else | |
294 | { | |
295 | // Is it a relative path? | |
296 | wxString currentDir(cwd); | |
297 | if (currentDir.Last() != wxFILE_SEP_PATH) | |
298 | currentDir += wxFILE_SEP_PATH; | |
299 | ||
d9ab621e WS |
300 | currentDir += argv0; |
301 | if (wxFileExists(currentDir)) | |
302 | return wxPathOnly(currentDir); | |
d7463f75 JS |
303 | } |
304 | ||
305 | // OK, it's neither an absolute path nor a relative path. | |
306 | // Search PATH. | |
307 | ||
308 | wxPathList pathList; | |
309 | pathList.AddEnvList(wxT("PATH")); | |
d9ab621e WS |
310 | wxString strPath = pathList.FindAbsoluteValidPath(argv0); |
311 | if (!strPath.IsEmpty()) | |
312 | return wxPathOnly(strPath); | |
d7463f75 JS |
313 | |
314 | // Failed | |
315 | return wxEmptyString; | |
316 | } | |
317 | ||
318 | // Adds a context-sensitive help button, for non-Windows platforms | |
254a2129 | 319 | void apAddContextHelpButton(wxWindow* |
69da0d99 JS |
320 | #if defined(__WXGTK__) || defined(__WXMAC__) |
321 | parent | |
322 | #else | |
323 | WXUNUSED(parent) | |
324 | #endif | |
254a2129 | 325 | , wxSizer* |
69da0d99 JS |
326 | #if defined(__WXGTK__) || defined(__WXMAC__) |
327 | sizer | |
328 | #else | |
329 | WXUNUSED(sizer) | |
330 | #endif | |
254a2129 | 331 | , int |
69da0d99 JS |
332 | #if defined(__WXGTK__) || defined(__WXMAC__) |
333 | sizerFlags | |
334 | #else | |
335 | WXUNUSED(sizerFlags) | |
336 | #endif | |
254a2129 | 337 | , int |
69da0d99 JS |
338 | #if defined(__WXGTK__) || defined(__WXMAC__) |
339 | sizerBorder | |
340 | #else | |
341 | WXUNUSED(sizerBorder) | |
342 | #endif | |
343 | ) | |
d7463f75 JS |
344 | { |
345 | #if defined(__WXGTK__) || defined(__WXMAC__) | |
346 | #ifdef __WXMAC__ | |
347 | wxSize buttonSize(20, 20); | |
348 | #else | |
4fe30bce | 349 | wxSize buttonSize = wxDefaultSize; |
d7463f75 JS |
350 | #endif |
351 | wxButton *contextButton = new wxContextHelpButton( parent, wxID_CONTEXT_HELP, | |
352 | wxDefaultPosition, buttonSize); | |
353 | sizer->Add( contextButton, 0, sizerFlags, sizerBorder ); | |
354 | ||
355 | // Add a bit of space on the right, to allow for the dialog resizing | |
356 | // handle | |
357 | #ifdef __WXMAC__ | |
358 | sizer->Add(0, 0, 0, wxRIGHT, 10); | |
359 | #endif | |
360 | ||
361 | contextButton->SetHelpText(_("Invokes context-sensitive help for the clicked-on window.")); | |
02ae000a | 362 | #if 0 |
d7463f75 JS |
363 | if (wxGetApp().UsingTooltips()) |
364 | { | |
365 | contextButton->SetToolTip(_("Invokes context-sensitive help for the clicked-on window.")); | |
366 | } | |
367 | #endif | |
02ae000a | 368 | #endif |
d7463f75 JS |
369 | } |
370 | ||
371 | // Get selected wxNotebook page | |
372 | wxWindow* apNotebookGetSelectedPage(wxNotebook* notebook) | |
373 | { | |
374 | int sel = notebook->GetSelection(); | |
375 | if (sel > -1) | |
376 | { | |
377 | return notebook->GetPage(sel); | |
378 | } | |
379 | return NULL; | |
380 | } | |
381 | ||
382 | /* | |
383 | * wxIconInfo | |
384 | */ | |
385 | ||
386 | wxIconInfo::wxIconInfo(const wxString& name) | |
387 | { | |
388 | m_maxStates = 0; | |
389 | m_name = name; | |
390 | int i; | |
391 | for (i = 0; i < wxMAX_ICON_STATES; i++) | |
392 | m_states[i] = 0; | |
393 | } | |
394 | ||
395 | int wxIconInfo::GetIconId(int state, bool enabled) const | |
396 | { | |
397 | wxASSERT ( state < (wxMAX_ICON_STATES * 2) ); | |
398 | wxASSERT ( state < m_maxStates ); | |
254a2129 | 399 | |
d7463f75 JS |
400 | return m_states[state * 2 + (enabled ? 0 : 1)]; |
401 | } | |
402 | ||
403 | void wxIconInfo::SetIconId(int state, bool enabled, int iconId) | |
404 | { | |
405 | wxASSERT ( state < (wxMAX_ICON_STATES * 2) ); | |
406 | if (state+1 > m_maxStates) | |
407 | m_maxStates = state+1; | |
254a2129 | 408 | |
d7463f75 JS |
409 | m_states[state * 2 + (enabled ? 0 : 1)] = iconId; |
410 | } | |
411 | ||
412 | /* | |
413 | * wxIconTable | |
414 | * Contains a list of wxIconInfos | |
415 | */ | |
416 | ||
417 | wxIconTable::wxIconTable(wxImageList* imageList) | |
418 | { | |
419 | m_imageList = imageList; | |
d9ab621e | 420 | WX_CLEAR_LIST(wxIconTable,*this); |
d7463f75 JS |
421 | } |
422 | ||
423 | void wxIconTable::AppendInfo(wxIconInfo* info) | |
424 | { | |
425 | Append(info); | |
426 | } | |
427 | ||
428 | // Easy way of initialising both the image list and the | |
429 | // table. It will generate image ids itself while appending the icon. | |
430 | bool wxIconTable::AddInfo(const wxString& name, const wxIcon& icon, int state, bool enabled) | |
431 | { | |
432 | wxASSERT (m_imageList != NULL); | |
254a2129 | 433 | |
d7463f75 JS |
434 | wxIconInfo* info = FindInfo(name); |
435 | if (!info) | |
436 | { | |
437 | info = new wxIconInfo(name); | |
438 | Append(info); | |
439 | } | |
440 | info->SetIconId(state, enabled, m_imageList->Add(icon)); | |
4fe30bce | 441 | return true; |
d7463f75 JS |
442 | } |
443 | ||
444 | wxIconInfo* wxIconTable::FindInfo(const wxString& name) const | |
445 | { | |
d9ab621e | 446 | wxObjectList::compatibility_iterator node = GetFirst(); |
d7463f75 JS |
447 | while (node) |
448 | { | |
f8105809 | 449 | wxIconInfo* info = (wxIconInfo*) node->GetData(); |
d7463f75 JS |
450 | if (info->GetName() == name) |
451 | return info; | |
f8105809 | 452 | node = node->GetNext(); |
d7463f75 JS |
453 | } |
454 | return NULL; | |
455 | } | |
456 | ||
457 | int wxIconTable::GetIconId(const wxString& name, int state, bool enabled) const | |
458 | { | |
459 | wxIconInfo* info = FindInfo(name); | |
460 | if (!info) | |
461 | return -1; | |
462 | return info->GetIconId(state, enabled); | |
463 | } | |
464 | ||
465 | bool wxIconTable::SetIconId(const wxString& name, int state, bool enabled, int iconId) | |
466 | { | |
467 | wxIconInfo* info = FindInfo(name); | |
468 | if (!info) | |
4fe30bce | 469 | return false; |
d7463f75 | 470 | info->SetIconId(state, enabled, iconId); |
4fe30bce | 471 | return true; |
d7463f75 JS |
472 | } |
473 | ||
474 | // Output stream operators | |
475 | ||
476 | wxOutputStream& operator <<(wxOutputStream& stream, const wxString& s) | |
477 | { | |
478 | stream.Write(s, s.Length()); | |
479 | return stream; | |
480 | } | |
481 | ||
482 | wxOutputStream& operator <<(wxOutputStream& stream, long l) | |
483 | { | |
484 | wxString str; | |
485 | str.Printf(_T("%ld"), l); | |
486 | return stream << str; | |
487 | } | |
488 | ||
69da0d99 | 489 | wxOutputStream& operator <<(wxOutputStream& stream, const wxChar c) |
d7463f75 JS |
490 | { |
491 | wxString str; | |
492 | str.Printf(_T("%c"), c); | |
493 | return stream << str; | |
494 | } | |
495 | ||
496 | // Convert characters to HTML equivalents | |
497 | wxString ctEscapeHTMLCharacters(const wxString& str) | |
498 | { | |
499 | wxString s; | |
500 | size_t len = str.Length(); | |
501 | size_t i; | |
502 | for (i = 0; i < len; i++) | |
503 | { | |
504 | wxChar c = str.GetChar(i); | |
505 | if (c == _T('<')) | |
506 | s += _T("<"); | |
507 | else if (c == _T('>')) | |
508 | s += _T(">"); | |
509 | else if (c == _T('&')) | |
510 | s += _T("&"); | |
511 | else | |
512 | s += c; | |
513 | } | |
514 | return s; | |
f8105809 | 515 | } |
e7767867 JS |
516 | |
517 | // Match 'matchText' against 'matchAgainst', optionally constraining to | |
518 | // whole-word only. | |
519 | bool ctMatchString(const wxString& matchAgainst, const wxString& matchText, bool wholeWordOnly) | |
520 | { | |
521 | // Fast operation if not matching against whole words only | |
522 | if (!wholeWordOnly) | |
4fe30bce | 523 | return (matchAgainst.Find(matchText) != wxNOT_FOUND); |
e7767867 JS |
524 | |
525 | wxString left(matchAgainst); | |
4fe30bce | 526 | bool success = false; |
e7767867 JS |
527 | int matchTextLen = (int) matchText.Length(); |
528 | while (!success && !matchAgainst.IsEmpty()) | |
529 | { | |
79830320 | 530 | int pos = left.Find(matchText); |
4fe30bce WS |
531 | if (pos == wxNOT_FOUND) |
532 | return false; | |
e7767867 | 533 | |
4fe30bce WS |
534 | bool firstCharOK = false; |
535 | bool lastCharOK = false; | |
e7767867 | 536 | if (pos == 0 || !wxIsalnum(left[(size_t) (pos-1)])) |
4fe30bce | 537 | firstCharOK = true; |
e7767867 JS |
538 | |
539 | if (((pos + matchTextLen) == (int) left.Length()) || !wxIsalnum(left[(size_t) (pos + matchTextLen)])) | |
4fe30bce | 540 | lastCharOK = true; |
e7767867 JS |
541 | |
542 | if (firstCharOK && lastCharOK) | |
4fe30bce | 543 | success = true; |
e7767867 JS |
544 | |
545 | left = left.Mid(pos+1); | |
546 | } | |
547 | return success; | |
548 | } |