Separation of wxUSE_FILEDLG and wxUSE_DIRDLG in generic implementations.
[wxWidgets.git] / src / generic / dirctrlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dirctrlg.cpp
3 // Purpose: wxGenericDirCtrl
4 // Author: Harm van der Heijden, Robert Roebling, Julian Smart
5 // Modified by:
6 // Created: 12/12/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Harm van der Heijden, Robert Roebling and Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "dirctrlg.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #if wxUSE_DIRDLG || wxUSE_FILEDLG
24
25 #include "wx/generic/dirctrlg.h"
26 #include "wx/module.h"
27 #include "wx/utils.h"
28 #include "wx/button.h"
29 #include "wx/layout.h"
30 #include "wx/msgdlg.h"
31 #include "wx/textctrl.h"
32 #include "wx/textdlg.h"
33 #include "wx/filefn.h"
34 #include "wx/cmndata.h"
35 #include "wx/gdicmn.h"
36 #include "wx/intl.h"
37 #include "wx/imaglist.h"
38 #include "wx/icon.h"
39 #include "wx/log.h"
40 #include "wx/sizer.h"
41 #include "wx/tokenzr.h"
42 #include "wx/dir.h"
43 #include "wx/settings.h"
44 #include "wx/artprov.h"
45 #include "wx/hash.h"
46 #include "wx/mimetype.h"
47 #include "wx/image.h"
48 #include "wx/choice.h"
49
50 #if wxUSE_STATLINE
51 #include "wx/statline.h"
52 #endif
53
54 #if defined(__WXMAC__)
55 #include "wx/mac/private.h" // includes mac headers
56 #endif
57
58 #ifdef __WXMSW__
59 #include <windows.h>
60
61 // FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume
62 // older releases don't, but it should be verified and the checks modified
63 // accordingly.
64 #if !defined(__GNUWIN32__) || (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
65 #if !defined(__WXWINCE__)
66 #include <direct.h>
67 #endif
68 #include <stdlib.h>
69 #include <ctype.h>
70 #endif
71
72 #endif
73
74 #if defined(__OS2__) || defined(__DOS__)
75 #ifdef __OS2__
76 #define INCL_BASE
77 #include <os2.h>
78 #ifndef __EMX__
79 #include <direct.h>
80 #endif
81 #include <stdlib.h>
82 #include <ctype.h>
83 #endif
84 extern bool wxIsDriveAvailable(const wxString& dirName);
85 #endif // __OS2__
86
87 #if defined(__WXMAC__)
88 # ifdef __DARWIN__
89 # include "MoreFilesX.h"
90 # else
91 # include "MoreFilesExtras.h"
92 # endif
93 #endif
94
95 #ifdef __BORLANDC__
96 #include "dos.h"
97 #endif
98
99 // If compiled under Windows, this macro can cause problems
100 #ifdef GetFirstChild
101 #undef GetFirstChild
102 #endif
103
104 // ----------------------------------------------------------------------------
105 // wxGetAvailableDrives, for WINDOWS, DOS, OS2, MAC, UNIX (returns "/")
106 // ----------------------------------------------------------------------------
107
108 size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids)
109 {
110 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
111
112 #ifdef __WXWINCE__
113 // No logical drives; return "\"
114 paths.Add(wxT("\\"));
115 names.Add(wxT("\\"));
116 return 1;
117 #elif defined(__WIN32__)
118 wxChar driveBuffer[256];
119 size_t n = (size_t) GetLogicalDriveStrings(255, driveBuffer);
120 size_t i = 0;
121 while (i < n)
122 {
123 wxString path, name;
124 path.Printf(wxT("%c:\\"), driveBuffer[i]);
125 name.Printf(wxT("%c:"), driveBuffer[i]);
126
127 int imageId;
128 int driveType = ::GetDriveType(path);
129 switch (driveType)
130 {
131 case DRIVE_REMOVABLE:
132 if (path == wxT("a:\\") || path == wxT("b:\\"))
133 imageId = wxFileIconsTable::floppy;
134 else
135 imageId = wxFileIconsTable::removeable;
136 break;
137 case DRIVE_CDROM:
138 imageId = wxFileIconsTable::cdrom;
139 break;
140 case DRIVE_REMOTE:
141 case DRIVE_FIXED:
142 default:
143 imageId = wxFileIconsTable::drive;
144 break;
145 }
146
147 paths.Add(path);
148 names.Add(name);
149 icon_ids.Add(imageId);
150
151 while (driveBuffer[i] != wxT('\0'))
152 i ++;
153 i ++;
154 if (driveBuffer[i] == wxT('\0'))
155 break;
156 }
157 #elif defined(__OS2__)
158 APIRET rc;
159 ULONG ulDriveNum = 0;
160 ULONG ulDriveMap = 0;
161 rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
162 if ( rc == 0)
163 {
164 size_t i = 0;
165 while (i < 26)
166 {
167 if (ulDriveMap & ( 1 << i ))
168 {
169 wxString path, name;
170 path.Printf(wxT("%c:\\"), 'A' + i);
171 name.Printf(wxT("%c:"), 'A' + i);
172
173 int imageId;
174 if (path == wxT("A:\\") || path == wxT("B:\\"))
175 imageId = wxFileIconsTable::floppy;
176 else
177 imageId = wxFileIconsTable::drive;
178 paths.Add(path);
179 names.Add(name);
180 icon_ids.Add(imageId);
181 }
182 i ++;
183 }
184 }
185 #else // !__WIN32__, !__OS2__
186 int drive;
187
188 /* If we can switch to the drive, it exists. */
189 for( drive = 1; drive <= 26; drive++ )
190 {
191 wxString path, name;
192 path.Printf(wxT("%c:\\"), (char) (drive + 'a' - 1));
193 name.Printf(wxT("%c:"), (char) (drive + 'A' - 1));
194
195 if (wxIsDriveAvailable(path))
196 {
197 paths.Add(path);
198 names.Add(name);
199 icon_ids.Add((drive <= 2) ? wxFileIconsTable::floppy : wxFileIconsTable::drive);
200 }
201 }
202 #endif // __WIN32__/!__WIN32__
203
204 #elif defined(__WXMAC__)
205 #ifdef __DARWIN__
206 FSRef **theVolRefs;
207 ItemCount theVolCount;
208 char thePath[FILENAME_MAX];
209
210 if (FSGetMountedVolumes(&theVolRefs, &theVolCount) == noErr) {
211 ItemCount index;
212 ::HLock( (Handle)theVolRefs ) ;
213 for (index = 0; index < theVolCount; ++index) {
214 // get the POSIX path associated with the FSRef
215 if ( FSRefMakePath(&((*theVolRefs)[index]),
216 (UInt8 *)thePath, sizeof(thePath)) != noErr ) {
217 continue;
218 }
219 // add path separator at end if necessary
220 wxString path( thePath , wxConvLocal) ;
221 if (path.Last() != wxFILE_SEP_PATH) {
222 path += wxFILE_SEP_PATH;
223 }
224 // get Mac volume name for display
225 FSVolumeRefNum vRefNum ;
226 HFSUniStr255 volumeName ;
227
228 if ( FSGetVRefNum(&((*theVolRefs)[index]), &vRefNum) != noErr ) {
229 continue;
230 }
231 if ( FSGetVInfo(vRefNum, &volumeName, NULL, NULL) != noErr ) {
232 continue;
233 }
234 // get C string from Unicode HFS name
235 // see: http://developer.apple.com/carbon/tipsandtricks.html
236 CFStringRef cfstr = CFStringCreateWithCharacters( kCFAllocatorDefault,
237 volumeName.unicode,
238 volumeName.length );
239 // Do something with str
240 char *cstr = NewPtr(CFStringGetLength(cfstr) + 1);
241 if (( cstr == NULL ) ||
242 !CFStringGetCString(cfstr, cstr, CFStringGetLength(cfstr) + 1,
243 kCFStringEncodingMacRoman))
244 {
245 CFRelease( cstr );
246 continue;
247 }
248 wxString name( cstr , wxConvLocal );
249 DisposePtr( cstr );
250 CFRelease( cfstr );
251
252 GetVolParmsInfoBuffer volParmsInfo;
253 UInt32 actualSize;
254 if ( FSGetVolParms(vRefNum, sizeof(volParmsInfo), &volParmsInfo, &actualSize) != noErr ) {
255 continue;
256 }
257
258 paths.Add(path);
259 names.Add(name);
260
261 if ( VolIsEjectable(&volParmsInfo) )
262 icon_ids.Add(wxFileIconsTable::cdrom);
263 else
264 icon_ids.Add(wxFileIconsTable::drive);
265 }
266 ::HUnlock( (Handle)theVolRefs );
267 ::DisposeHandle( (Handle)theVolRefs );
268 }
269 #else // !__DARWIN__
270 FSSpec volume;
271 short index = 1;
272 while(1)
273 {
274 short actualCount = 0 ;
275 if (OnLine(&volume, 1, &actualCount, &index ) != noErr || actualCount==0)
276 {
277 break;
278 }
279
280 wxString name = wxMacFSSpec2MacFilename( &volume );
281 paths.Add(name + wxFILE_SEP_PATH);
282 names.Add(name);
283 icon_ids.Add(wxFileIconsTable::drive);
284 }
285 #endif // __DARWIN__
286
287 #elif defined(__UNIX__)
288 paths.Add(wxT("/"));
289 names.Add(wxT("/"));
290 icon_ids.Add(wxFileIconsTable::computer);
291 #else
292 #error "Unsupported platform in wxGenericDirCtrl!"
293 #endif
294 return paths.GetCount();
295 }
296
297 // ----------------------------------------------------------------------------
298 // wxIsDriveAvailable
299 // ----------------------------------------------------------------------------
300
301 #if defined(__DOS__)
302
303 bool wxIsDriveAvailable(const wxString& dirName)
304 {
305 // FIXME_MGL - this method leads to hang up under Watcom for some reason
306 #ifndef __WATCOMC__
307 if ( dirName.Len() == 3 && dirName[1u] == wxT(':') )
308 {
309 wxString dirNameLower(dirName.Lower());
310 // VS: always return true for removable media, since Win95 doesn't
311 // like it when MS-DOS app accesses empty floppy drive
312 return (dirNameLower[0u] == wxT('a') ||
313 dirNameLower[0u] == wxT('b') ||
314 wxPathExists(dirNameLower));
315 }
316 else
317 #endif
318 return true;
319 }
320
321 #elif defined(__WINDOWS__) || defined(__OS2__)
322
323 int setdrive(int drive)
324 {
325 #ifdef __WXWINCE__
326 return 0;
327 #elif defined(__GNUWIN32__) && \
328 (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
329 return _chdrive(drive);
330 #else
331 wxChar newdrive[4];
332
333 if (drive < 1 || drive > 31)
334 return -1;
335 newdrive[0] = (wxChar)(wxT('A') + drive - 1);
336 newdrive[1] = wxT(':');
337 #ifdef __OS2__
338 newdrive[2] = wxT('\\');
339 newdrive[3] = wxT('\0');
340 #else
341 newdrive[2] = wxT('\0');
342 #endif
343 #if defined(__WXMSW__)
344 if (::SetCurrentDirectory(newdrive))
345 #else
346 // VA doesn't know what LPSTR is and has its own set
347 if (!DosSetCurrentDir((PSZ)newdrive))
348 #endif
349 return 0;
350 else
351 return -1;
352 #endif // !GNUWIN32
353 }
354
355 bool wxIsDriveAvailable(const wxString& dirName)
356 {
357 #ifdef __WXWINCE__
358 return false;
359 #else
360 #ifdef __WIN32__
361 UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
362 #endif
363 bool success = true;
364
365 // Check if this is a root directory and if so,
366 // whether the drive is available.
367 if (dirName.Len() == 3 && dirName[(size_t)1] == wxT(':'))
368 {
369 wxString dirNameLower(dirName.Lower());
370 #if defined(__GNUWIN32__) && !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
371 success = wxPathExists(dirNameLower);
372 #else
373 #if defined(__OS2__)
374 // Avoid changing to drive since no media may be inserted.
375 if (dirNameLower[(size_t)0] == 'a' || dirNameLower[(size_t)0] == 'b')
376 return success;
377 #endif
378 int currentDrive = _getdrive();
379 int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ;
380 int err = setdrive( thisDrive ) ;
381 setdrive( currentDrive );
382
383 if (err == -1)
384 {
385 success = false;
386 }
387 #endif
388 }
389 #ifdef __WIN32__
390 (void) SetErrorMode(errorMode);
391 #endif
392
393 return success;
394 #endif
395 }
396 #endif // __WINDOWS__ || __OS2__
397
398 #endif // wxUSE_DIRDLG || wxUSE_FILEDLG
399
400
401
402 #if wxUSE_DIRDLG
403
404 // Function which is called by quick sort. We want to override the default wxArrayString behaviour,
405 // and sort regardless of case.
406 static int wxCMPFUNC_CONV wxDirCtrlStringCompareFunction(wxString* strFirst, wxString* strSecond)
407 {
408 return strFirst->CmpNoCase(*strSecond);
409 }
410
411 //-----------------------------------------------------------------------------
412 // wxDirItemData
413 //-----------------------------------------------------------------------------
414
415 wxDirItemData::wxDirItemData(const wxString& path, const wxString& name,
416 bool isDir)
417 {
418 m_path = path;
419 m_name = name;
420 /* Insert logic to detect hidden files here
421 * In UnixLand we just check whether the first char is a dot
422 * For FileNameFromPath read LastDirNameInThisPath ;-) */
423 // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
424 m_isHidden = false;
425 m_isExpanded = false;
426 m_isDir = isDir;
427 }
428
429 wxDirItemData::~wxDirItemData()
430 {
431 }
432
433 void wxDirItemData::SetNewDirName(const wxString& path)
434 {
435 m_path = path;
436 m_name = wxFileNameFromPath(path);
437 }
438
439 bool wxDirItemData::HasSubDirs() const
440 {
441 if (m_path.IsEmpty())
442 return false;
443
444 wxDir dir;
445 {
446 wxLogNull nolog;
447 if ( !dir.Open(m_path) )
448 return false;
449 }
450
451 return dir.HasSubDirs();
452 }
453
454 bool wxDirItemData::HasFiles(const wxString& WXUNUSED(spec)) const
455 {
456 if (m_path.IsEmpty())
457 return false;
458
459 wxDir dir;
460 {
461 wxLogNull nolog;
462 if ( !dir.Open(m_path) )
463 return false;
464 }
465
466 return dir.HasFiles();
467 }
468
469 //-----------------------------------------------------------------------------
470 // wxGenericDirCtrl
471 //-----------------------------------------------------------------------------
472
473
474 #if wxUSE_EXTENDED_RTTI
475 WX_DEFINE_FLAGS( wxGenericDirCtrlStyle )
476
477 wxBEGIN_FLAGS( wxGenericDirCtrlStyle )
478 // new style border flags, we put them first to
479 // use them for streaming out
480 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
481 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
482 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
483 wxFLAGS_MEMBER(wxBORDER_RAISED)
484 wxFLAGS_MEMBER(wxBORDER_STATIC)
485 wxFLAGS_MEMBER(wxBORDER_NONE)
486
487 // old style border flags
488 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
489 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
490 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
491 wxFLAGS_MEMBER(wxRAISED_BORDER)
492 wxFLAGS_MEMBER(wxSTATIC_BORDER)
493 wxFLAGS_MEMBER(wxBORDER)
494
495 // standard window styles
496 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
497 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
498 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
499 wxFLAGS_MEMBER(wxWANTS_CHARS)
500 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
501 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
502 wxFLAGS_MEMBER(wxVSCROLL)
503 wxFLAGS_MEMBER(wxHSCROLL)
504
505 wxFLAGS_MEMBER(wxDIRCTRL_DIR_ONLY)
506 wxFLAGS_MEMBER(wxDIRCTRL_3D_INTERNAL)
507 wxFLAGS_MEMBER(wxDIRCTRL_SELECT_FIRST)
508 wxFLAGS_MEMBER(wxDIRCTRL_SHOW_FILTERS)
509
510 wxEND_FLAGS( wxGenericDirCtrlStyle )
511
512 IMPLEMENT_DYNAMIC_CLASS_XTI(wxGenericDirCtrl, wxControl,"wx/dirctrl.h")
513
514 wxBEGIN_PROPERTIES_TABLE(wxGenericDirCtrl)
515 wxHIDE_PROPERTY( Children )
516 wxPROPERTY( DefaultPath , wxString , SetDefaultPath , GetDefaultPath , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
517 wxPROPERTY( Filter , wxString , SetFilter , GetFilter , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
518 wxPROPERTY( DefaultFilter , int , SetFilterIndex, GetFilterIndex, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
519 wxPROPERTY_FLAGS( WindowStyle, wxGenericDirCtrlStyle, long, SetWindowStyleFlag, GetWindowStyleFlag, EMPTY_MACROVALUE , 0, wxT("Helpstring"), wxT("group") )
520 wxEND_PROPERTIES_TABLE()
521
522 wxBEGIN_HANDLERS_TABLE(wxGenericDirCtrl)
523 wxEND_HANDLERS_TABLE()
524
525 wxCONSTRUCTOR_8( wxGenericDirCtrl , wxWindow* , Parent , wxWindowID , Id , wxString , DefaultPath ,
526 wxPoint , Position , wxSize , Size , long , WindowStyle , wxString , Filter , int , DefaultFilter )
527 #else
528 IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl, wxControl)
529 #endif
530
531 BEGIN_EVENT_TABLE(wxGenericDirCtrl, wxControl)
532 EVT_TREE_ITEM_EXPANDING (wxID_TREECTRL, wxGenericDirCtrl::OnExpandItem)
533 EVT_TREE_ITEM_COLLAPSED (wxID_TREECTRL, wxGenericDirCtrl::OnCollapseItem)
534 EVT_TREE_BEGIN_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnBeginEditItem)
535 EVT_TREE_END_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnEndEditItem)
536 EVT_SIZE (wxGenericDirCtrl::OnSize)
537 END_EVENT_TABLE()
538
539 wxGenericDirCtrl::wxGenericDirCtrl(void)
540 {
541 Init();
542 }
543
544 bool wxGenericDirCtrl::Create(wxWindow *parent,
545 const wxWindowID id,
546 const wxString& dir,
547 const wxPoint& pos,
548 const wxSize& size,
549 long style,
550 const wxString& filter,
551 int defaultFilter,
552 const wxString& name)
553 {
554 if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name))
555 return false;
556
557 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
558
559 Init();
560
561 long treeStyle = wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT;
562
563 if (style & wxDIRCTRL_EDIT_LABELS)
564 treeStyle |= wxTR_EDIT_LABELS;
565
566 if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
567 treeStyle |= wxNO_BORDER;
568 else
569 treeStyle |= wxBORDER_SUNKEN;
570
571 long filterStyle = 0;
572 if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
573 filterStyle |= wxNO_BORDER;
574 else
575 filterStyle |= wxBORDER_SUNKEN;
576
577 m_treeCtrl = new wxTreeCtrl(this, wxID_TREECTRL, pos, size, treeStyle);
578
579 if (!filter.IsEmpty() && (style & wxDIRCTRL_SHOW_FILTERS))
580 m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL, wxDefaultPosition, wxDefaultSize, filterStyle);
581
582 m_defaultPath = dir;
583 m_filter = filter;
584
585 SetFilterIndex(defaultFilter);
586
587 if (m_filterListCtrl)
588 m_filterListCtrl->FillFilterList(filter, defaultFilter);
589
590 m_treeCtrl->SetImageList(wxTheFileIconsTable->GetSmallImageList());
591
592 m_showHidden = false;
593 wxDirItemData* rootData = new wxDirItemData(wxEmptyString, wxEmptyString, true);
594
595 wxString rootName;
596
597 #if defined(__WINDOWS__) || defined(__OS2__) || defined(__DOS__)
598 rootName = _("Computer");
599 #else
600 rootName = _("Sections");
601 #endif
602
603 m_rootId = m_treeCtrl->AddRoot( rootName, 3, -1, rootData);
604 m_treeCtrl->SetItemHasChildren(m_rootId);
605 ExpandDir(m_rootId); // automatically expand first level
606
607 // Expand and select the default path
608 if (!m_defaultPath.IsEmpty())
609 ExpandPath(m_defaultPath);
610
611 SetBestSize(size);
612 DoResize();
613
614 return true;
615 }
616
617 wxGenericDirCtrl::~wxGenericDirCtrl()
618 {
619 }
620
621 void wxGenericDirCtrl::Init()
622 {
623 m_showHidden = false;
624 m_currentFilter = 0;
625 m_currentFilterStr = wxEmptyString; // Default: any file
626 m_treeCtrl = NULL;
627 m_filterListCtrl = NULL;
628 }
629
630 void wxGenericDirCtrl::ShowHidden( bool show )
631 {
632 m_showHidden = show;
633
634 wxString path = GetPath();
635 ReCreateTree();
636 SetPath(path);
637 }
638
639 const wxTreeItemId
640 wxGenericDirCtrl::AddSection(const wxString& path, const wxString& name, int imageId)
641 {
642 wxDirItemData *dir_item = new wxDirItemData(path,name,true);
643
644 wxTreeItemId id = AppendItem( m_rootId, name, imageId, -1, dir_item);
645
646 m_treeCtrl->SetItemHasChildren(id);
647
648 return id;
649 }
650
651 void wxGenericDirCtrl::SetupSections()
652 {
653 wxArrayString paths, names;
654 wxArrayInt icons;
655
656 size_t n, count = wxGetAvailableDrives(paths, names, icons);
657
658 for (n = 0; n < count; n++)
659 {
660 AddSection(paths[n], names[n], icons[n]);
661 }
662 }
663
664 void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent &event)
665 {
666 // don't rename the main entry "Sections"
667 if (event.GetItem() == m_rootId)
668 {
669 event.Veto();
670 return;
671 }
672
673 // don't rename the individual sections
674 if (m_treeCtrl->GetItemParent( event.GetItem() ) == m_rootId)
675 {
676 event.Veto();
677 return;
678 }
679 }
680
681 void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent &event)
682 {
683 if ((event.GetLabel().IsEmpty()) ||
684 (event.GetLabel() == _(".")) ||
685 (event.GetLabel() == _("..")) ||
686 (event.GetLabel().Find(wxT('/')) != wxNOT_FOUND) ||
687 (event.GetLabel().Find(wxT('\\')) != wxNOT_FOUND) ||
688 (event.GetLabel().Find(wxT('|')) != wxNOT_FOUND))
689 {
690 wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
691 dialog.ShowModal();
692 event.Veto();
693 return;
694 }
695
696 wxTreeItemId id = event.GetItem();
697 wxDirItemData *data = (wxDirItemData*)m_treeCtrl->GetItemData( id );
698 wxASSERT( data );
699
700 wxString new_name( wxPathOnly( data->m_path ) );
701 new_name += wxString(wxFILE_SEP_PATH);
702 new_name += event.GetLabel();
703
704 wxLogNull log;
705
706 if (wxFileExists(new_name))
707 {
708 wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
709 dialog.ShowModal();
710 event.Veto();
711 }
712
713 if (wxRenameFile(data->m_path,new_name))
714 {
715 data->SetNewDirName( new_name );
716 }
717 else
718 {
719 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
720 dialog.ShowModal();
721 event.Veto();
722 }
723 }
724
725 void wxGenericDirCtrl::OnExpandItem(wxTreeEvent &event)
726 {
727 wxTreeItemId parentId = event.GetItem();
728
729 // VS: this is needed because the event handler is called from wxTreeCtrl
730 // ctor when wxTR_HIDE_ROOT was specified
731
732 if (!m_rootId.IsOk())
733
734 m_rootId = m_treeCtrl->GetRootItem();
735
736 ExpandDir(parentId);
737 }
738
739 void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent &event )
740 {
741 CollapseDir(event.GetItem());
742 }
743
744 void wxGenericDirCtrl::CollapseDir(wxTreeItemId parentId)
745 {
746 wxTreeItemId child;
747
748 wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId);
749 if (!data->m_isExpanded)
750 return;
751
752 data->m_isExpanded = false;
753 wxTreeItemIdValue cookie;
754 /* Workaround because DeleteChildren has disapeared (why?) and
755 * CollapseAndReset doesn't work as advertised (deletes parent too) */
756 child = m_treeCtrl->GetFirstChild(parentId, cookie);
757 while (child.IsOk())
758 {
759 m_treeCtrl->Delete(child);
760 /* Not GetNextChild below, because the cookie mechanism can't
761 * handle disappearing children! */
762 child = m_treeCtrl->GetFirstChild(parentId, cookie);
763 }
764 }
765
766 void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId)
767 {
768 wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId);
769
770 if (data->m_isExpanded)
771 return;
772
773 data->m_isExpanded = true;
774
775 if (parentId == m_treeCtrl->GetRootItem())
776 {
777 SetupSections();
778 return;
779 }
780
781 wxASSERT(data);
782
783 wxString search,path,filename;
784
785 wxString dirName(data->m_path);
786
787 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
788 // Check if this is a root directory and if so,
789 // whether the drive is avaiable.
790 if (!wxIsDriveAvailable(dirName))
791 {
792 data->m_isExpanded = false;
793 //wxMessageBox(wxT("Sorry, this drive is not available."));
794 return;
795 }
796 #endif
797
798 // This may take a longish time. Go to busy cursor
799 wxBusyCursor busy;
800
801 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
802 if (dirName.Last() == ':')
803 dirName += wxString(wxFILE_SEP_PATH);
804 #endif
805
806 wxArrayString dirs;
807 wxArrayString filenames;
808
809 wxDir d;
810 wxString eachFilename;
811
812 wxLogNull log;
813 d.Open(dirName);
814
815 if (d.IsOpened())
816 {
817 int style = wxDIR_DIRS;
818 if (m_showHidden) style |= wxDIR_HIDDEN;
819 if (d.GetFirst(& eachFilename, wxEmptyString, style))
820 {
821 do
822 {
823 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
824 {
825 dirs.Add(eachFilename);
826 }
827 }
828 while (d.GetNext(&eachFilename));
829 }
830 }
831 dirs.Sort(wxDirCtrlStringCompareFunction);
832
833 // Now do the filenames -- but only if we're allowed to
834 if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0)
835 {
836 wxLogNull log;
837
838 d.Open(dirName);
839
840 if (d.IsOpened())
841 {
842 int style = wxDIR_FILES;
843 if (m_showHidden) style |= wxDIR_HIDDEN;
844 // Process each filter (ex: "JPEG Files (*.jpg;*.jpeg)|*.jpg;*.jpeg")
845 wxStringTokenizer strTok;
846 wxString curFilter;
847 strTok.SetString(m_currentFilterStr,wxT(";"));
848 while(strTok.HasMoreTokens())
849 {
850 curFilter = strTok.GetNextToken();
851 if (d.GetFirst(& eachFilename, m_currentFilterStr, style))
852 {
853 do
854 {
855 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
856 {
857 filenames.Add(eachFilename);
858 }
859 }
860 while (d.GetNext(& eachFilename));
861 }
862 }
863 }
864 filenames.Sort(wxDirCtrlStringCompareFunction);
865 }
866
867 // Add the sorted dirs
868 size_t i;
869 for (i = 0; i < dirs.Count(); i++)
870 {
871 wxString eachFilename(dirs[i]);
872 path = dirName;
873 if (!wxEndsWithPathSeparator(path))
874 path += wxString(wxFILE_SEP_PATH);
875 path += eachFilename;
876
877 wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,true);
878 wxTreeItemId id = AppendItem( parentId, eachFilename,
879 wxFileIconsTable::folder, -1, dir_item);
880 m_treeCtrl->SetItemImage( id, wxFileIconsTable::folder_open,
881 wxTreeItemIcon_Expanded );
882
883 // Has this got any children? If so, make it expandable.
884 // (There are two situations when a dir has children: either it
885 // has subdirectories or it contains files that weren't filtered
886 // out. The latter only applies to dirctrl with files.)
887 if ( dir_item->HasSubDirs() ||
888 (((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) &&
889 dir_item->HasFiles(m_currentFilterStr)) )
890 {
891 m_treeCtrl->SetItemHasChildren(id);
892 }
893 }
894
895 // Add the sorted filenames
896 if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0)
897 {
898 for (i = 0; i < filenames.Count(); i++)
899 {
900 wxString eachFilename(filenames[i]);
901 path = dirName;
902 if (!wxEndsWithPathSeparator(path))
903 path += wxString(wxFILE_SEP_PATH);
904 path += eachFilename;
905 //path = dirName + wxString(wxT("/")) + eachFilename;
906 wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,false);
907 int image_id = wxFileIconsTable::file;
908 if (eachFilename.Find(wxT('.')) != wxNOT_FOUND)
909 image_id = wxTheFileIconsTable->GetIconID(eachFilename.AfterLast(wxT('.')));
910 (void) AppendItem( parentId, eachFilename, image_id, -1, dir_item);
911 }
912 }
913 }
914
915 void wxGenericDirCtrl::ReCreateTree()
916 {
917 CollapseDir(m_treeCtrl->GetRootItem());
918 ExpandDir(m_treeCtrl->GetRootItem());
919 }
920
921 // Find the child that matches the first part of 'path'.
922 // E.g. if a child path is "/usr" and 'path' is "/usr/include"
923 // then the child for /usr is returned.
924 wxTreeItemId wxGenericDirCtrl::FindChild(wxTreeItemId parentId, const wxString& path, bool& done)
925 {
926 wxString path2(path);
927
928 // Make sure all separators are as per the current platform
929 path2.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH));
930 path2.Replace(wxT("/"), wxString(wxFILE_SEP_PATH));
931
932 // Append a separator to foil bogus substring matching
933 path2 += wxString(wxFILE_SEP_PATH);
934
935 // In MSW or PM, case is not significant
936 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
937 path2.MakeLower();
938 #endif
939
940 wxTreeItemIdValue cookie;
941 wxTreeItemId childId = m_treeCtrl->GetFirstChild(parentId, cookie);
942 while (childId.IsOk())
943 {
944 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(childId);
945
946 if (data && !data->m_path.IsEmpty())
947 {
948 wxString childPath(data->m_path);
949 if (!wxEndsWithPathSeparator(childPath))
950 childPath += wxString(wxFILE_SEP_PATH);
951
952 // In MSW and PM, case is not significant
953 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
954 childPath.MakeLower();
955 #endif
956
957 if (childPath.Len() <= path2.Len())
958 {
959 wxString path3 = path2.Mid(0, childPath.Len());
960 if (childPath == path3)
961 {
962 if (path3.Len() == path2.Len())
963 done = true;
964 else
965 done = false;
966 return childId;
967 }
968 }
969 }
970
971 childId = m_treeCtrl->GetNextChild(parentId, cookie);
972 }
973 wxTreeItemId invalid;
974 return invalid;
975 }
976
977 // Try to expand as much of the given path as possible,
978 // and select the given tree item.
979 bool wxGenericDirCtrl::ExpandPath(const wxString& path)
980 {
981 bool done = false;
982 wxTreeItemId id = FindChild(m_rootId, path, done);
983 wxTreeItemId lastId = id; // The last non-zero id
984 while (id.IsOk() && !done)
985 {
986 ExpandDir(id);
987
988 id = FindChild(id, path, done);
989 if (id.IsOk())
990 lastId = id;
991 }
992 if (lastId.IsOk())
993 {
994 wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(lastId);
995 if (data->m_isDir)
996 {
997 m_treeCtrl->Expand(lastId);
998 }
999 if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST) && data->m_isDir)
1000 {
1001 // Find the first file in this directory
1002 wxTreeItemIdValue cookie;
1003 wxTreeItemId childId = m_treeCtrl->GetFirstChild(lastId, cookie);
1004 bool selectedChild = false;
1005 while (childId.IsOk())
1006 {
1007 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(childId);
1008
1009 if (data && data->m_path != wxEmptyString && !data->m_isDir)
1010 {
1011 m_treeCtrl->SelectItem(childId);
1012 m_treeCtrl->EnsureVisible(childId);
1013 selectedChild = true;
1014 break;
1015 }
1016 childId = m_treeCtrl->GetNextChild(lastId, cookie);
1017 }
1018 if (!selectedChild)
1019 {
1020 m_treeCtrl->SelectItem(lastId);
1021 m_treeCtrl->EnsureVisible(lastId);
1022 }
1023 }
1024 else
1025 {
1026 m_treeCtrl->SelectItem(lastId);
1027 m_treeCtrl->EnsureVisible(lastId);
1028 }
1029
1030 return true;
1031 }
1032 else
1033 return false;
1034 }
1035
1036 wxString wxGenericDirCtrl::GetPath() const
1037 {
1038 wxTreeItemId id = m_treeCtrl->GetSelection();
1039 if (id)
1040 {
1041 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id);
1042 return data->m_path;
1043 }
1044 else
1045 return wxEmptyString;
1046 }
1047
1048 wxString wxGenericDirCtrl::GetFilePath() const
1049 {
1050 wxTreeItemId id = m_treeCtrl->GetSelection();
1051 if (id)
1052 {
1053 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id);
1054 if (data->m_isDir)
1055 return wxEmptyString;
1056 else
1057 return data->m_path;
1058 }
1059 else
1060 return wxEmptyString;
1061 }
1062
1063 void wxGenericDirCtrl::SetPath(const wxString& path)
1064 {
1065 m_defaultPath = path;
1066 if (m_rootId)
1067 ExpandPath(path);
1068 }
1069
1070 // Not used
1071 #if 0
1072 void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id, int dirFlags, wxArrayString& filenames)
1073 {
1074 wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(id);
1075
1076 // This may take a longish time. Go to busy cursor
1077 wxBusyCursor busy;
1078
1079 wxASSERT(data);
1080
1081 wxString search,path,filename;
1082
1083 wxString dirName(data->m_path);
1084
1085 #if defined(__WXMSW__) || defined(__OS2__)
1086 if (dirName.Last() == ':')
1087 dirName += wxString(wxFILE_SEP_PATH);
1088 #endif
1089
1090 wxDir d;
1091 wxString eachFilename;
1092
1093 wxLogNull log;
1094 d.Open(dirName);
1095
1096 if (d.IsOpened())
1097 {
1098 if (d.GetFirst(& eachFilename, m_currentFilterStr, dirFlags))
1099 {
1100 do
1101 {
1102 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
1103 {
1104 filenames.Add(eachFilename);
1105 }
1106 }
1107 while (d.GetNext(& eachFilename)) ;
1108 }
1109 }
1110 }
1111 #endif
1112
1113 void wxGenericDirCtrl::SetFilterIndex(int n)
1114 {
1115 m_currentFilter = n;
1116
1117 wxString f, d;
1118 if (ExtractWildcard(m_filter, n, f, d))
1119 m_currentFilterStr = f;
1120 else
1121 m_currentFilterStr = wxT("*.*");
1122 }
1123
1124 void wxGenericDirCtrl::SetFilter(const wxString& filter)
1125 {
1126 m_filter = filter;
1127
1128 wxString f, d;
1129 if (ExtractWildcard(m_filter, m_currentFilter, f, d))
1130 m_currentFilterStr = f;
1131 else
1132 m_currentFilterStr = wxT("*.*");
1133 }
1134
1135 // Extract description and actual filter from overall filter string
1136 bool wxGenericDirCtrl::ExtractWildcard(const wxString& filterStr, int n, wxString& filter, wxString& description)
1137 {
1138 wxArrayString filters, descriptions;
1139 int count = wxParseWildcard(filterStr, filters, descriptions);
1140 if (count > 0 && n < count)
1141 {
1142 filter = filters[n];
1143 description = descriptions[n];
1144 return true;
1145 }
1146
1147 return false;
1148 }
1149
1150 #if WXWIN_COMPATIBILITY_2_4
1151 // Parses the global filter, returning the number of filters.
1152 // Returns 0 if none or if there's a problem.
1153 // filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg"
1154 int wxGenericDirCtrl::ParseFilter(const wxString& filterStr, wxArrayString& filters, wxArrayString& descriptions)
1155 {
1156 return wxParseWildcard(filterStr, descriptions, filters );
1157 }
1158 #endif // WXWIN_COMPATIBILITY_2_4
1159
1160 void wxGenericDirCtrl::DoResize()
1161 {
1162 wxSize sz = GetClientSize();
1163 int verticalSpacing = 3;
1164 if (m_treeCtrl)
1165 {
1166 wxSize filterSz ;
1167 if (m_filterListCtrl)
1168 {
1169 #ifdef __WXMSW__
1170 // For some reason, this is required in order for the
1171 // correct control height to always be returned, rather
1172 // than the drop-down list height which is sometimes returned.
1173 wxSize oldSize = m_filterListCtrl->GetSize();
1174 m_filterListCtrl->SetSize(wxDefaultPosition.x,
1175 wxDefaultPosition.y,
1176 oldSize.x+10,
1177 wxDefaultSize.y,
1178 wxSIZE_USE_EXISTING);
1179 m_filterListCtrl->SetSize(wxDefaultPosition.x,
1180 wxDefaultPosition.y,
1181 oldSize.x,
1182 wxDefaultSize.y,
1183 wxSIZE_USE_EXISTING);
1184 #endif
1185 filterSz = m_filterListCtrl->GetSize();
1186 sz.y -= (filterSz.y + verticalSpacing);
1187 }
1188 m_treeCtrl->SetSize(0, 0, sz.x, sz.y);
1189 if (m_filterListCtrl)
1190 {
1191 m_filterListCtrl->SetSize(0, sz.y + verticalSpacing, sz.x, filterSz.y);
1192 // Don't know why, but this needs refreshing after a resize (wxMSW)
1193 m_filterListCtrl->Refresh();
1194 }
1195 }
1196 }
1197
1198
1199 void wxGenericDirCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
1200 {
1201 DoResize();
1202 }
1203
1204 wxTreeItemId wxGenericDirCtrl::AppendItem (const wxTreeItemId & parent,
1205 const wxString & text,
1206 int image, int selectedImage,
1207 wxTreeItemData * data)
1208 {
1209 wxTreeCtrl *treeCtrl = GetTreeCtrl ();
1210
1211 wxASSERT (treeCtrl);
1212
1213 if (treeCtrl)
1214 {
1215 return treeCtrl->AppendItem (parent, text, image, selectedImage, data);
1216 }
1217 else
1218 {
1219 return wxTreeItemId();
1220 }
1221 }
1222
1223
1224 //-----------------------------------------------------------------------------
1225 // wxDirFilterListCtrl
1226 //-----------------------------------------------------------------------------
1227
1228 IMPLEMENT_CLASS(wxDirFilterListCtrl, wxChoice)
1229
1230 BEGIN_EVENT_TABLE(wxDirFilterListCtrl, wxChoice)
1231 EVT_CHOICE(wxID_ANY, wxDirFilterListCtrl::OnSelFilter)
1232 END_EVENT_TABLE()
1233
1234 bool wxDirFilterListCtrl::Create(wxGenericDirCtrl* parent, const wxWindowID id,
1235 const wxPoint& pos,
1236 const wxSize& size,
1237 long style)
1238 {
1239 m_dirCtrl = parent;
1240 return wxChoice::Create(parent, id, pos, size, 0, NULL, style);
1241 }
1242
1243 void wxDirFilterListCtrl::Init()
1244 {
1245 m_dirCtrl = NULL;
1246 }
1247
1248 void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent& WXUNUSED(event))
1249 {
1250 int sel = GetSelection();
1251
1252 wxString currentPath = m_dirCtrl->GetPath();
1253
1254 m_dirCtrl->SetFilterIndex(sel);
1255
1256 // If the filter has changed, the view is out of date, so
1257 // collapse the tree.
1258 m_dirCtrl->ReCreateTree();
1259
1260 // Try to restore the selection, or at least the directory
1261 m_dirCtrl->ExpandPath(currentPath);
1262 }
1263
1264 void wxDirFilterListCtrl::FillFilterList(const wxString& filter, int defaultFilter)
1265 {
1266 Clear();
1267 wxArrayString descriptions, filters;
1268 size_t n = (size_t) wxParseWildcard(filter, filters, descriptions);
1269
1270 if (n > 0 && defaultFilter < (int) n)
1271 {
1272 for (size_t i = 0; i < n; i++)
1273 Append(descriptions[i]);
1274 SetSelection(defaultFilter);
1275 }
1276 }
1277 #endif // wxUSE_DIRDLG
1278
1279 #if wxUSE_DIRDLG || wxUSE_FILEDLG
1280
1281 // ----------------------------------------------------------------------------
1282 // wxFileIconsTable icons
1283 // ----------------------------------------------------------------------------
1284
1285 /* Open folder */
1286 static const char * file_icons_tbl_folder_open_xpm[] = {
1287 /* width height ncolors chars_per_pixel */
1288 "16 16 6 1",
1289 /* colors */
1290 " s None c None",
1291 ". c #000000",
1292 "+ c #c0c0c0",
1293 "@ c #808080",
1294 "# c #ffff00",
1295 "$ c #ffffff",
1296 /* pixels */
1297 " ",
1298 " @@@@@ ",
1299 " @$$$$$@ ",
1300 " @$#+#+#$@@@@@@ ",
1301 " @$+#+#+$$$$$$@.",
1302 " @$#+#+#+#+#+#@.",
1303 "@@@@@@@@@@@@@#@.",
1304 "@$$$$$$$$$$@@+@.",
1305 "@$#+#+#+#+##.@@.",
1306 " @$#+#+#+#+#+.@.",
1307 " @$+#+#+#+#+#.@.",
1308 " @$+#+#+#+##@..",
1309 " @@@@@@@@@@@@@.",
1310 " .............",
1311 " ",
1312 " "};
1313
1314 /* Computer */
1315 static const char * file_icons_tbl_computer_xpm[] = {
1316 "16 16 7 1",
1317 " s None c None",
1318 ". c #808080",
1319 "X c #c0c0c0",
1320 "o c Black",
1321 "O c Gray100",
1322 "+ c #008080",
1323 "@ c Blue",
1324 " ........... ",
1325 " .XXXXXXXXXX.o",
1326 " .OOOOOOOOO..o",
1327 " .OoooooooX..o",
1328 " .Oo+...@+X..o",
1329 " .Oo+XXX.+X..o",
1330 " .Oo+....+X..o",
1331 " .Oo++++++X..o",
1332 " .OXXXXXXXX.oo",
1333 " ..........o.o",
1334 " ...........Xo",
1335 " .XXXXXXXXXX.o",
1336 " .o.o.o.o.o...o",
1337 " .oXoXoXoXoXo.o ",
1338 ".XOXXXXXXXXX.o ",
1339 "............o "};
1340
1341 /* Drive */
1342 static const char * file_icons_tbl_drive_xpm[] = {
1343 "16 16 7 1",
1344 " s None c None",
1345 ". c #808080",
1346 "X c #c0c0c0",
1347 "o c Black",
1348 "O c Gray100",
1349 "+ c Green",
1350 "@ c #008000",
1351 " ",
1352 " ",
1353 " ",
1354 " ",
1355 " ............. ",
1356 " .XXXXXXXXXXXX.o",
1357 ".OOOOOOOOOOOO..o",
1358 ".XXXXXXXXX+@X..o",
1359 ".XXXXXXXXXXXX..o",
1360 ".X..........X..o",
1361 ".XOOOOOOOOOOX..o",
1362 "..............o ",
1363 " ooooooooooooo ",
1364 " ",
1365 " ",
1366 " "};
1367
1368 /* CD-ROM */
1369 static const char *file_icons_tbl_cdrom_xpm[] = {
1370 "16 16 10 1",
1371 " s None c None",
1372 ". c #808080",
1373 "X c #c0c0c0",
1374 "o c Yellow",
1375 "O c Blue",
1376 "+ c Black",
1377 "@ c Gray100",
1378 "# c #008080",
1379 "$ c Green",
1380 "% c #008000",
1381 " ... ",
1382 " ..XoX.. ",
1383 " .O.XoXXX+ ",
1384 " ...O.oXXXX+ ",
1385 " .O..X.XXXX+ ",
1386 " ....X.+..XXX+",
1387 " .XXX.+@+.XXX+",
1388 " .X@XX.+.X@@X+",
1389 " .....X...#XX@+ ",
1390 ".@@@...XXo.O@X+ ",
1391 ".@XXX..XXoXOO+ ",
1392 ".@++++..XoX+++ ",
1393 ".@$%@@XX+++X.+ ",
1394 ".............+ ",
1395 " ++++++++++++ ",
1396 " "};
1397
1398 /* Floppy */
1399 static const char * file_icons_tbl_floppy_xpm[] = {
1400 "16 16 7 1",
1401 " s None c None",
1402 ". c #808080",
1403 "X c Gray100",
1404 "o c #c0c0c0",
1405 "O c Black",
1406 "+ c Cyan",
1407 "@ c Red",
1408 " ......X",
1409 " .ooooooO",
1410 " .+++++OO",
1411 " .++++++O",
1412 " .++++++O",
1413 " .ooooooO",
1414 " .......o....oO",
1415 " .oooooo.o.O.XoO",
1416 ".XXXXXXXXOOOOOO ",
1417 ".ooooooooo@o..O ",
1418 ".ooo....oooo..O ",
1419 ".o..OOOO...o..O ",
1420 ".oooXXXXoooo..O ",
1421 ".............O ",
1422 " OOOOOOOOOOOO ",
1423 " "};
1424
1425 /* Removeable */
1426 static const char * file_icons_tbl_removeable_xpm[] = {
1427 "16 16 7 1",
1428 " s None c None",
1429 ". c #808080",
1430 "X c #c0c0c0",
1431 "o c Black",
1432 "O c Gray100",
1433 "+ c Red",
1434 "@ c #800000",
1435 " ",
1436 " ",
1437 " ",
1438 " ............. ",
1439 " .XXXXXXXXXXXX.o",
1440 ".OOOOOOOOOOOO..o",
1441 ".OXXXXXXXXXXX..o",
1442 ".O+@.oooooo.X..o",
1443 ".OXXOooooooOX..o",
1444 ".OXXXOOOOOOXX..o",
1445 ".OXXXXXXXXXXX..o",
1446 ".O............o ",
1447 " ooooooooooooo ",
1448 " ",
1449 " ",
1450 " "};
1451
1452 // ----------------------------------------------------------------------------
1453 // wxFileIconsTable & friends
1454 // ----------------------------------------------------------------------------
1455
1456 // global instance of a wxFileIconsTable
1457 wxFileIconsTable* wxTheFileIconsTable = (wxFileIconsTable *)NULL;
1458
1459 // A module to allow icons table cleanup
1460
1461 class wxFileIconsTableModule: public wxModule
1462 {
1463 DECLARE_DYNAMIC_CLASS(wxFileIconsTableModule)
1464 public:
1465 wxFileIconsTableModule() {}
1466 bool OnInit() { wxTheFileIconsTable = new wxFileIconsTable; return true; }
1467 void OnExit()
1468 {
1469 if (wxTheFileIconsTable)
1470 {
1471 delete wxTheFileIconsTable;
1472 wxTheFileIconsTable = NULL;
1473 }
1474 }
1475 };
1476
1477 IMPLEMENT_DYNAMIC_CLASS(wxFileIconsTableModule, wxModule)
1478
1479 class wxFileIconEntry : public wxObject
1480 {
1481 public:
1482 wxFileIconEntry(int i) { id = i; }
1483
1484 int id;
1485 };
1486
1487 wxFileIconsTable::wxFileIconsTable()
1488 {
1489 m_HashTable = NULL;
1490 m_smallImageList = NULL;
1491 }
1492
1493 wxFileIconsTable::~wxFileIconsTable()
1494 {
1495 if (m_HashTable)
1496 {
1497 WX_CLEAR_HASH_TABLE(*m_HashTable);
1498 delete m_HashTable;
1499 }
1500 if (m_smallImageList) delete m_smallImageList;
1501 }
1502
1503 // delayed initialization - wait until first use (wxArtProv not created yet)
1504 void wxFileIconsTable::Create()
1505 {
1506 wxCHECK_RET(!m_smallImageList && !m_HashTable, wxT("creating icons twice"));
1507 m_HashTable = new wxHashTable(wxKEY_STRING);
1508 m_smallImageList = new wxImageList(16, 16);
1509
1510 // folder:
1511 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FOLDER, wxART_CMN_DIALOG));
1512 // folder_open
1513 m_smallImageList->Add(wxIcon(file_icons_tbl_folder_open_xpm));
1514 // computer
1515 m_smallImageList->Add(wxIcon(file_icons_tbl_computer_xpm));
1516 // drive
1517 m_smallImageList->Add(wxIcon(file_icons_tbl_drive_xpm));
1518 // cdrom
1519 m_smallImageList->Add(wxIcon(file_icons_tbl_cdrom_xpm));
1520 // floppy
1521 m_smallImageList->Add(wxIcon(file_icons_tbl_floppy_xpm));
1522 // removeable
1523 m_smallImageList->Add(wxIcon(file_icons_tbl_removeable_xpm));
1524 // file
1525 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE, wxART_CMN_DIALOG));
1526 // executable
1527 if (GetIconID(wxEmptyString, _T("application/x-executable")) == file)
1528 {
1529 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE, wxART_CMN_DIALOG));
1530 delete m_HashTable->Get(_T("exe"));
1531 m_HashTable->Delete(_T("exe"));
1532 m_HashTable->Put(_T("exe"), new wxFileIconEntry(executable));
1533 }
1534 /* else put into list by GetIconID
1535 (KDE defines application/x-executable for *.exe and has nice icon)
1536 */
1537 }
1538
1539 wxImageList *wxFileIconsTable::GetSmallImageList()
1540 {
1541 if (!m_smallImageList)
1542 Create();
1543
1544 return m_smallImageList;
1545 }
1546
1547 #if wxUSE_MIMETYPE && wxUSE_IMAGE
1548 // VS: we don't need this function w/o wxMimeTypesManager because we'll only have
1549 // one icon and we won't resize it
1550
1551 static wxBitmap CreateAntialiasedBitmap(const wxImage& img)
1552 {
1553 const unsigned int size = 16;
1554
1555 wxImage smallimg (size, size);
1556 unsigned char *p1, *p2, *ps;
1557 unsigned char mr = img.GetMaskRed(),
1558 mg = img.GetMaskGreen(),
1559 mb = img.GetMaskBlue();
1560
1561 unsigned x, y;
1562 unsigned sr, sg, sb, smask;
1563
1564 p1 = img.GetData(), p2 = img.GetData() + 3 * size*2, ps = smallimg.GetData();
1565 smallimg.SetMaskColour(mr, mr, mr);
1566
1567 for (y = 0; y < size; y++)
1568 {
1569 for (x = 0; x < size; x++)
1570 {
1571 sr = sg = sb = smask = 0;
1572 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
1573 sr += p1[0], sg += p1[1], sb += p1[2];
1574 else smask++;
1575 p1 += 3;
1576 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
1577 sr += p1[0], sg += p1[1], sb += p1[2];
1578 else smask++;
1579 p1 += 3;
1580 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
1581 sr += p2[0], sg += p2[1], sb += p2[2];
1582 else smask++;
1583 p2 += 3;
1584 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
1585 sr += p2[0], sg += p2[1], sb += p2[2];
1586 else smask++;
1587 p2 += 3;
1588
1589 if (smask > 2)
1590 ps[0] = ps[1] = ps[2] = mr;
1591 else
1592 ps[0] = sr >> 2, ps[1] = sg >> 2, ps[2] = sb >> 2;
1593 ps += 3;
1594 }
1595 p1 += size*2 * 3, p2 += size*2 * 3;
1596 }
1597
1598 return wxBitmap(smallimg);
1599 }
1600
1601 // This function is currently not unused anymore
1602 #if 0
1603 // finds empty borders and return non-empty area of image:
1604 static wxImage CutEmptyBorders(const wxImage& img)
1605 {
1606 unsigned char mr = img.GetMaskRed(),
1607 mg = img.GetMaskGreen(),
1608 mb = img.GetMaskBlue();
1609 unsigned char *dt = img.GetData(), *dttmp;
1610 unsigned w = img.GetWidth(), h = img.GetHeight();
1611
1612 unsigned top, bottom, left, right, i;
1613 bool empt;
1614
1615 #define MK_DTTMP(x,y) dttmp = dt + ((x + y * w) * 3)
1616 #define NOEMPTY_PIX(empt) if (dttmp[0] != mr || dttmp[1] != mg || dttmp[2] != mb) {empt = false; break;}
1617
1618 for (empt = true, top = 0; empt && top < h; top++)
1619 {
1620 MK_DTTMP(0, top);
1621 for (i = 0; i < w; i++, dttmp+=3)
1622 NOEMPTY_PIX(empt)
1623 }
1624 for (empt = true, bottom = h-1; empt && bottom > top; bottom--)
1625 {
1626 MK_DTTMP(0, bottom);
1627 for (i = 0; i < w; i++, dttmp+=3)
1628 NOEMPTY_PIX(empt)
1629 }
1630 for (empt = true, left = 0; empt && left < w; left++)
1631 {
1632 MK_DTTMP(left, 0);
1633 for (i = 0; i < h; i++, dttmp+=3*w)
1634 NOEMPTY_PIX(empt)
1635 }
1636 for (empt = true, right = w-1; empt && right > left; right--)
1637 {
1638 MK_DTTMP(right, 0);
1639 for (i = 0; i < h; i++, dttmp+=3*w)
1640 NOEMPTY_PIX(empt)
1641 }
1642 top--, left--, bottom++, right++;
1643
1644 return img.GetSubImage(wxRect(left, top, right - left + 1, bottom - top + 1));
1645 }
1646 #endif // #if 0
1647
1648 #endif // wxUSE_MIMETYPE
1649
1650 int wxFileIconsTable::GetIconID(const wxString& extension, const wxString& mime)
1651 {
1652 if (!m_smallImageList)
1653 Create();
1654
1655 #if wxUSE_MIMETYPE
1656 if (!extension.IsEmpty())
1657 {
1658 wxFileIconEntry *entry = (wxFileIconEntry*) m_HashTable->Get(extension);
1659 if (entry) return (entry -> id);
1660 }
1661
1662 wxFileType *ft = (mime.IsEmpty()) ?
1663 wxTheMimeTypesManager -> GetFileTypeFromExtension(extension) :
1664 wxTheMimeTypesManager -> GetFileTypeFromMimeType(mime);
1665
1666 wxIconLocation iconLoc;
1667 wxIcon ic;
1668
1669 {
1670 wxLogNull logNull;
1671 if ( ft && ft->GetIcon(&iconLoc) )
1672 {
1673 ic = wxIcon( iconLoc.GetFileName() );
1674 }
1675 }
1676
1677 delete ft;
1678
1679 if ( !ic.Ok() )
1680 {
1681 int newid = file;
1682 m_HashTable->Put(extension, new wxFileIconEntry(newid));
1683 return newid;
1684 }
1685
1686 wxBitmap bmp;
1687 bmp.CopyFromIcon(ic);
1688
1689 if ( !bmp.Ok() )
1690 {
1691 int newid = file;
1692 m_HashTable->Put(extension, new wxFileIconEntry(newid));
1693 return newid;
1694 }
1695
1696 const unsigned int size = 16;
1697
1698 int id = m_smallImageList->GetImageCount();
1699 if ((bmp.GetWidth() == (int) size) && (bmp.GetHeight() == (int) size))
1700 {
1701 m_smallImageList->Add(bmp);
1702 }
1703 #if wxUSE_IMAGE
1704 else
1705 {
1706 wxImage img = bmp.ConvertToImage();
1707
1708 if ((img.GetWidth() != size*2) || (img.GetHeight() != size*2))
1709 // m_smallImageList->Add(CreateAntialiasedBitmap(CutEmptyBorders(img).Rescale(size*2, size*2)));
1710 m_smallImageList->Add(CreateAntialiasedBitmap(img.Rescale(size*2, size*2)));
1711 else
1712 m_smallImageList->Add(CreateAntialiasedBitmap(img));
1713 }
1714 #endif // wxUSE_IMAGE
1715
1716 m_HashTable->Put(extension, new wxFileIconEntry(id));
1717 return id;
1718
1719 #else // !wxUSE_MIMETYPE
1720
1721 if (extension == wxT("exe"))
1722 return executable;
1723 else
1724 return file;
1725 #endif // wxUSE_MIMETYPE/!wxUSE_MIMETYPE
1726 }
1727
1728 #endif // wxUSE_DIRDLG || wxUSE_FILEDLG