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