]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/dirctrlg.cpp
preserve checkbox status in SetString()
[wxWidgets.git] / src / generic / dirctrlg.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/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// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
19#if wxUSE_DIRDLG || wxUSE_FILEDLG
20
21#include "wx/generic/dirctrlg.h"
22
23#ifndef WX_PRECOMP
24 #include "wx/hash.h"
25 #include "wx/intl.h"
26 #include "wx/log.h"
27 #include "wx/utils.h"
28 #include "wx/button.h"
29 #include "wx/icon.h"
30 #include "wx/settings.h"
31 #include "wx/msgdlg.h"
32 #include "wx/choice.h"
33 #include "wx/textctrl.h"
34 #include "wx/layout.h"
35 #include "wx/sizer.h"
36 #include "wx/textdlg.h"
37 #include "wx/gdicmn.h"
38 #include "wx/image.h"
39 #include "wx/module.h"
40#endif
41
42#include "wx/filename.h"
43#include "wx/filefn.h"
44#include "wx/imaglist.h"
45#include "wx/tokenzr.h"
46#include "wx/dir.h"
47#include "wx/artprov.h"
48#include "wx/mimetype.h"
49
50#if wxUSE_STATLINE
51 #include "wx/statline.h"
52#endif
53
54#if defined(__WXMAC__)
55 #include "wx/osx/private.h" // includes mac headers
56#endif
57
58#ifdef __WINDOWS__
59#include <windows.h>
60#include "wx/msw/winundef.h"
61#include "wx/volume.h"
62
63// FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume
64// older releases don't, but it should be verified and the checks modified
65// accordingly.
66#if !defined(__GNUWIN32__) || (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
67#if !defined(__WXWINCE__)
68 #include <direct.h>
69#endif
70 #include <stdlib.h>
71 #include <ctype.h>
72#endif
73
74#endif // __WINDOWS__
75
76#if defined(__OS2__) || defined(__DOS__)
77 #ifdef __OS2__
78 #define INCL_BASE
79 #include <os2.h>
80 #ifndef __EMX__
81 #include <direct.h>
82 #endif
83 #include <stdlib.h>
84 #include <ctype.h>
85 #endif
86#endif // __OS2__
87
88#if defined(__WXMAC__)
89// #include "MoreFilesX.h"
90#endif
91
92#ifdef __BORLANDC__
93 #include "dos.h"
94#endif
95
96extern WXDLLEXPORT_DATA(const char) wxFileSelectorDefaultWildcardStr[];
97
98// If compiled under Windows, this macro can cause problems
99#ifdef GetFirstChild
100#undef GetFirstChild
101#endif
102
103bool wxIsDriveAvailable(const wxString& dirName);
104
105// ----------------------------------------------------------------------------
106// events
107// ----------------------------------------------------------------------------
108
109wxDEFINE_EVENT( wxEVT_DIRCTRL_SELECTIONCHANGED, wxTreeEvent );
110wxDEFINE_EVENT( wxEVT_DIRCTRL_FILEACTIVATED, wxTreeEvent );
111
112// ----------------------------------------------------------------------------
113// wxGetAvailableDrives, for WINDOWS, DOS, OS2, MAC, UNIX (returns "/")
114// ----------------------------------------------------------------------------
115
116size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids)
117{
118#ifdef wxHAS_FILESYSTEM_VOLUMES
119
120#ifdef __WXWINCE__
121 // No logical drives; return "\"
122 paths.Add(wxT("\\"));
123 names.Add(wxT("\\"));
124 icon_ids.Add(wxFileIconsTable::computer);
125#elif defined(__WIN32__) && wxUSE_FSVOLUME
126 // TODO: this code (using wxFSVolumeBase) should be used for all platforms
127 // but unfortunately wxFSVolumeBase is not implemented everywhere
128 const wxArrayString as = wxFSVolumeBase::GetVolumes();
129
130 for (size_t i = 0; i < as.GetCount(); i++)
131 {
132 wxString path = as[i];
133 wxFSVolume vol(path);
134 int imageId;
135 switch (vol.GetKind())
136 {
137 case wxFS_VOL_FLOPPY:
138 if ( (path == wxT("a:\\")) || (path == wxT("b:\\")) )
139 imageId = wxFileIconsTable::floppy;
140 else
141 imageId = wxFileIconsTable::removeable;
142 break;
143 case wxFS_VOL_DVDROM:
144 case wxFS_VOL_CDROM:
145 imageId = wxFileIconsTable::cdrom;
146 break;
147 case wxFS_VOL_NETWORK:
148 if (path[0] == wxT('\\'))
149 continue; // skip "\\computer\folder"
150 imageId = wxFileIconsTable::drive;
151 break;
152 case wxFS_VOL_DISK:
153 case wxFS_VOL_OTHER:
154 default:
155 imageId = wxFileIconsTable::drive;
156 break;
157 }
158 paths.Add(path);
159 names.Add(vol.GetDisplayName());
160 icon_ids.Add(imageId);
161 }
162#elif defined(__OS2__)
163 APIRET rc;
164 ULONG ulDriveNum = 0;
165 ULONG ulDriveMap = 0;
166 rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
167 if ( rc == 0)
168 {
169 size_t i = 0;
170 while (i < 26)
171 {
172 if (ulDriveMap & ( 1 << i ))
173 {
174 const wxString path = wxFileName::GetVolumeString(
175 'A' + i, wxPATH_GET_SEPARATOR);
176 const wxString name = wxFileName::GetVolumeString(
177 'A' + i, wxPATH_NO_SEPARATOR);
178
179 // Note: If _filesys is unsupported by some compilers,
180 // we can always replace it by DosQueryFSAttach
181 char filesysname[20];
182#ifdef __WATCOMC__
183 ULONG cbBuffer = sizeof(filesysname);
184 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)filesysname;
185 APIRET rc = ::DosQueryFSAttach(name.fn_str(),0,FSAIL_QUERYNAME,pfsqBuffer,&cbBuffer);
186 if (rc != NO_ERROR)
187 {
188 filesysname[0] = '\0';
189 }
190#else
191 _filesys(name.fn_str(), filesysname, sizeof(filesysname));
192#endif
193 /* FAT, LAN, HPFS, CDFS, NFS */
194 int imageId;
195 if (path == wxT("A:\\") || path == wxT("B:\\"))
196 imageId = wxFileIconsTable::floppy;
197 else if (!strcmp(filesysname, "CDFS"))
198 imageId = wxFileIconsTable::cdrom;
199 else if (!strcmp(filesysname, "LAN") ||
200 !strcmp(filesysname, "NFS"))
201 imageId = wxFileIconsTable::drive;
202 else
203 imageId = wxFileIconsTable::drive;
204 paths.Add(path);
205 names.Add(name);
206 icon_ids.Add(imageId);
207 }
208 i ++;
209 }
210 }
211#else // !__WIN32__, !__OS2__
212 /* If we can switch to the drive, it exists. */
213 for ( char drive = 'A'; drive <= 'Z'; drive++ )
214 {
215 const wxString
216 path = wxFileName::GetVolumeString(drive, wxPATH_GET_SEPARATOR);
217
218 if (wxIsDriveAvailable(path))
219 {
220 paths.Add(path);
221 names.Add(wxFileName::GetVolumeString(drive, wxPATH_NO_SEPARATOR));
222 icon_ids.Add(drive <= 2 ? wxFileIconsTable::floppy
223 : wxFileIconsTable::drive);
224 }
225 }
226#endif // __WIN32__/!__WIN32__
227
228#elif defined(__WXMAC__) && wxOSX_USE_COCOA_OR_CARBON
229
230 ItemCount volumeIndex = 1;
231 OSErr err = noErr ;
232
233 while( noErr == err )
234 {
235 HFSUniStr255 volumeName ;
236 FSRef fsRef ;
237 FSVolumeInfo volumeInfo ;
238 err = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoFlags , &volumeInfo , &volumeName, &fsRef);
239 if( noErr == err )
240 {
241 wxString path = wxMacFSRefToPath( &fsRef ) ;
242 wxString name = wxMacHFSUniStrToString( &volumeName ) ;
243
244 if ( (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) || (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
245 {
246 icon_ids.Add(wxFileIconsTable::cdrom);
247 }
248 else
249 {
250 icon_ids.Add(wxFileIconsTable::drive);
251 }
252 // todo other removable
253
254 paths.Add(path);
255 names.Add(name);
256 volumeIndex++ ;
257 }
258 }
259
260#elif defined(__UNIX__)
261 paths.Add(wxT("/"));
262 names.Add(wxT("/"));
263 icon_ids.Add(wxFileIconsTable::computer);
264#else
265 #error "Unsupported platform in wxGenericDirCtrl!"
266#endif
267 wxASSERT_MSG( (paths.GetCount() == names.GetCount()), wxT("The number of paths and their human readable names should be equal in number."));
268 wxASSERT_MSG( (paths.GetCount() == icon_ids.GetCount()), wxT("Wrong number of icons for available drives."));
269 return paths.GetCount();
270}
271
272// ----------------------------------------------------------------------------
273// wxIsDriveAvailable
274// ----------------------------------------------------------------------------
275
276#if defined(__DOS__)
277
278bool wxIsDriveAvailable(const wxString& dirName)
279{
280 // FIXME: this method leads to hang up under Watcom for some reason
281#ifdef __WATCOMC__
282 wxUnusedVar(dirName);
283#else
284 if ( dirName.length() == 3 && dirName[1u] == wxT(':') )
285 {
286 wxString dirNameLower(dirName.Lower());
287 // VS: always return true for removable media, since Win95 doesn't
288 // like it when MS-DOS app accesses empty floppy drive
289 return (dirNameLower[0u] == wxT('a') ||
290 dirNameLower[0u] == wxT('b') ||
291 wxDirExists(dirNameLower));
292 }
293 else
294#endif
295 return true;
296}
297
298#elif defined(__WINDOWS__) || defined(__OS2__)
299
300int setdrive(int WXUNUSED_IN_WINCE(drive))
301{
302#ifdef __WXWINCE__
303 return 0;
304#elif defined(__GNUWIN32__) && \
305 (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
306 return _chdrive(drive);
307#else
308 wxChar newdrive[4];
309
310 if (drive < 1 || drive > 31)
311 return -1;
312 newdrive[0] = (wxChar)(wxT('A') + drive - 1);
313 newdrive[1] = wxT(':');
314#ifdef __OS2__
315 newdrive[2] = wxT('\\');
316 newdrive[3] = wxT('\0');
317#else
318 newdrive[2] = wxT('\0');
319#endif
320#if defined(__WINDOWS__)
321 if (::SetCurrentDirectory(newdrive))
322#else
323 // VA doesn't know what LPSTR is and has its own set
324 if (!DosSetCurrentDir((PSZ)newdrive))
325#endif
326 return 0;
327 else
328 return -1;
329#endif // !GNUWIN32
330}
331
332bool wxIsDriveAvailable(const wxString& WXUNUSED_IN_WINCE(dirName))
333{
334#ifdef __WXWINCE__
335 return false;
336#else
337#ifdef __WIN32__
338 UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
339#endif
340 bool success = true;
341
342 // Check if this is a root directory and if so,
343 // whether the drive is available.
344 if (dirName.length() == 3 && dirName[(size_t)1] == wxT(':'))
345 {
346 wxString dirNameLower(dirName.Lower());
347#if defined(__GNUWIN32__) && !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
348 success = wxDirExists(dirNameLower);
349#else
350 #if defined(__OS2__)
351 // Avoid changing to drive since no media may be inserted.
352 if (dirNameLower[(size_t)0] == 'a' || dirNameLower[(size_t)0] == 'b')
353 return success;
354 #endif
355 int currentDrive = _getdrive();
356 int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ;
357 int err = setdrive( thisDrive ) ;
358 setdrive( currentDrive );
359
360 if (err == -1)
361 {
362 success = false;
363 }
364#endif
365 }
366#ifdef __WIN32__
367 (void) SetErrorMode(errorMode);
368#endif
369
370 return success;
371#endif
372}
373#endif // __WINDOWS__ || __OS2__
374
375#endif // wxUSE_DIRDLG || wxUSE_FILEDLG
376
377
378
379#if wxUSE_DIRDLG
380
381// Function which is called by quick sort. We want to override the default wxArrayString behaviour,
382// and sort regardless of case.
383static int wxCMPFUNC_CONV wxDirCtrlStringCompareFunction(const wxString& strFirst, const wxString& strSecond)
384{
385 return strFirst.CmpNoCase(strSecond);
386}
387
388//-----------------------------------------------------------------------------
389// wxDirItemData
390//-----------------------------------------------------------------------------
391
392wxDirItemData::wxDirItemData(const wxString& path, const wxString& name,
393 bool isDir)
394{
395 m_path = path;
396 m_name = name;
397 /* Insert logic to detect hidden files here
398 * In UnixLand we just check whether the first char is a dot
399 * For FileNameFromPath read LastDirNameInThisPath ;-) */
400 // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
401 m_isHidden = false;
402 m_isExpanded = false;
403 m_isDir = isDir;
404}
405
406void wxDirItemData::SetNewDirName(const wxString& path)
407{
408 m_path = path;
409 m_name = wxFileNameFromPath(path);
410}
411
412bool wxDirItemData::HasSubDirs() const
413{
414 if (m_path.empty())
415 return false;
416
417 wxDir dir;
418 {
419 wxLogNull nolog;
420 if ( !dir.Open(m_path) )
421 return false;
422 }
423
424 return dir.HasSubDirs();
425}
426
427bool wxDirItemData::HasFiles(const wxString& WXUNUSED(spec)) const
428{
429 if (m_path.empty())
430 return false;
431
432 wxDir dir;
433 {
434 wxLogNull nolog;
435 if ( !dir.Open(m_path) )
436 return false;
437 }
438
439 return dir.HasFiles();
440}
441
442//-----------------------------------------------------------------------------
443// wxGenericDirCtrl
444//-----------------------------------------------------------------------------
445
446BEGIN_EVENT_TABLE(wxGenericDirCtrl, wxControl)
447 EVT_TREE_ITEM_EXPANDING (wxID_TREECTRL, wxGenericDirCtrl::OnExpandItem)
448 EVT_TREE_ITEM_COLLAPSED (wxID_TREECTRL, wxGenericDirCtrl::OnCollapseItem)
449 EVT_TREE_BEGIN_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnBeginEditItem)
450 EVT_TREE_END_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnEndEditItem)
451 EVT_TREE_SEL_CHANGED (wxID_TREECTRL, wxGenericDirCtrl::OnTreeSelChange)
452 EVT_TREE_ITEM_ACTIVATED (wxID_TREECTRL, wxGenericDirCtrl::OnItemActivated)
453 EVT_SIZE (wxGenericDirCtrl::OnSize)
454END_EVENT_TABLE()
455
456wxGenericDirCtrl::wxGenericDirCtrl(void)
457{
458 Init();
459}
460
461void wxGenericDirCtrl::ExpandRoot()
462{
463 ExpandDir(m_rootId); // automatically expand first level
464
465 // Expand and select the default path
466 if (!m_defaultPath.empty())
467 {
468 ExpandPath(m_defaultPath);
469 }
470#ifdef __UNIX__
471 else
472 {
473 // On Unix, there's only one node under the (hidden) root node. It
474 // represents the / path, so the user would always have to expand it;
475 // let's do it ourselves
476 ExpandPath( wxT("/") );
477 }
478#endif
479}
480
481bool wxGenericDirCtrl::Create(wxWindow *parent,
482 const wxWindowID treeid,
483 const wxString& dir,
484 const wxPoint& pos,
485 const wxSize& size,
486 long style,
487 const wxString& filter,
488 int defaultFilter,
489 const wxString& name)
490{
491 if (!wxControl::Create(parent, treeid, pos, size, style, wxDefaultValidator, name))
492 return false;
493
494 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
495 SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
496
497 Init();
498
499 long treeStyle = wxTR_HAS_BUTTONS;
500
501 // On Windows CE, if you hide the root, you get a crash when
502 // attempting to access data for children of the root item.
503#ifndef __WXWINCE__
504 treeStyle |= wxTR_HIDE_ROOT;
505#endif
506
507#ifdef __WXGTK20__
508 treeStyle |= wxTR_NO_LINES;
509#endif
510
511 if (style & wxDIRCTRL_EDIT_LABELS)
512 treeStyle |= wxTR_EDIT_LABELS;
513
514 if (style & wxDIRCTRL_MULTIPLE)
515 treeStyle |= wxTR_MULTIPLE;
516
517 if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
518 treeStyle |= wxNO_BORDER;
519
520 m_treeCtrl = CreateTreeCtrl(this, wxID_TREECTRL,
521 wxPoint(0,0), GetClientSize(), treeStyle);
522
523 if (!filter.empty() && (style & wxDIRCTRL_SHOW_FILTERS))
524 m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL);
525
526 m_defaultPath = dir;
527 m_filter = filter;
528
529 if (m_filter.empty())
530 m_filter = wxFileSelectorDefaultWildcardStr;
531
532 SetFilterIndex(defaultFilter);
533
534 if (m_filterListCtrl)
535 m_filterListCtrl->FillFilterList(filter, defaultFilter);
536
537 m_treeCtrl->SetImageList(wxTheFileIconsTable->GetSmallImageList());
538
539 m_showHidden = false;
540 wxDirItemData* rootData = new wxDirItemData(wxEmptyString, wxEmptyString, true);
541
542 wxString rootName;
543
544#if defined(__WINDOWS__) || defined(__OS2__) || defined(__DOS__)
545 rootName = _("Computer");
546#else
547 rootName = _("Sections");
548#endif
549
550 m_rootId = m_treeCtrl->AddRoot( rootName, 3, -1, rootData);
551 m_treeCtrl->SetItemHasChildren(m_rootId);
552
553 ExpandRoot();
554
555 SetInitialSize(size);
556 DoResize();
557
558 return true;
559}
560
561wxGenericDirCtrl::~wxGenericDirCtrl()
562{
563}
564
565void wxGenericDirCtrl::Init()
566{
567 m_showHidden = false;
568 m_currentFilter = 0;
569 m_currentFilterStr = wxEmptyString; // Default: any file
570 m_treeCtrl = NULL;
571 m_filterListCtrl = NULL;
572}
573
574wxTreeCtrl* wxGenericDirCtrl::CreateTreeCtrl(wxWindow *parent, wxWindowID treeid, const wxPoint& pos, const wxSize& size, long treeStyle)
575{
576 return new wxTreeCtrl(parent, treeid, pos, size, treeStyle);
577}
578
579void wxGenericDirCtrl::ShowHidden( bool show )
580{
581 if ( m_showHidden == show )
582 return;
583
584 m_showHidden = show;
585
586 if ( HasFlag(wxDIRCTRL_MULTIPLE) )
587 {
588 wxArrayString paths;
589 GetPaths(paths);
590 ReCreateTree();
591 for ( unsigned n = 0; n < paths.size(); n++ )
592 {
593 ExpandPath(paths[n]);
594 }
595 }
596 else
597 {
598 wxString path = GetPath();
599 ReCreateTree();
600 SetPath(path);
601 }
602}
603
604const wxTreeItemId
605wxGenericDirCtrl::AddSection(const wxString& path, const wxString& name, int imageId)
606{
607 wxDirItemData *dir_item = new wxDirItemData(path,name,true);
608
609 wxTreeItemId treeid = AppendItem( m_rootId, name, imageId, -1, dir_item);
610
611 m_treeCtrl->SetItemHasChildren(treeid);
612
613 return treeid;
614}
615
616void wxGenericDirCtrl::SetupSections()
617{
618 wxArrayString paths, names;
619 wxArrayInt icons;
620
621 size_t n, count = wxGetAvailableDrives(paths, names, icons);
622
623#ifdef __WXGTK20__
624 wxString home = wxGetHomeDir();
625 AddSection( home, _("Home directory"), 1);
626 home += wxT("/Desktop");
627 AddSection( home, _("Desktop"), 1);
628#endif
629
630 for (n = 0; n < count; n++)
631 AddSection(paths[n], names[n], icons[n]);
632}
633
634void wxGenericDirCtrl::SetFocus()
635{
636 // we don't need focus ourselves, give it to the tree so that the user
637 // could navigate it
638 if (m_treeCtrl)
639 m_treeCtrl->SetFocus();
640}
641
642void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent &event)
643{
644 // don't rename the main entry "Sections"
645 if (event.GetItem() == m_rootId)
646 {
647 event.Veto();
648 return;
649 }
650
651 // don't rename the individual sections
652 if (m_treeCtrl->GetItemParent( event.GetItem() ) == m_rootId)
653 {
654 event.Veto();
655 return;
656 }
657}
658
659void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent &event)
660{
661 if (event.IsEditCancelled())
662 return;
663
664 if ((event.GetLabel().empty()) ||
665 (event.GetLabel() == wxT(".")) ||
666 (event.GetLabel() == wxT("..")) ||
667 (event.GetLabel().Find(wxT('/')) != wxNOT_FOUND) ||
668 (event.GetLabel().Find(wxT('\\')) != wxNOT_FOUND) ||
669 (event.GetLabel().Find(wxT('|')) != wxNOT_FOUND))
670 {
671 wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
672 dialog.ShowModal();
673 event.Veto();
674 return;
675 }
676
677 wxTreeItemId treeid = event.GetItem();
678 wxDirItemData *data = GetItemData( treeid );
679 wxASSERT( data );
680
681 wxString new_name( wxPathOnly( data->m_path ) );
682 new_name += wxString(wxFILE_SEP_PATH);
683 new_name += event.GetLabel();
684
685 wxLogNull log;
686
687 if (wxFileExists(new_name))
688 {
689 wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
690 dialog.ShowModal();
691 event.Veto();
692 }
693
694 if (wxRenameFile(data->m_path,new_name))
695 {
696 data->SetNewDirName( new_name );
697 }
698 else
699 {
700 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
701 dialog.ShowModal();
702 event.Veto();
703 }
704}
705
706void wxGenericDirCtrl::OnTreeSelChange(wxTreeEvent &event)
707{
708 wxTreeEvent changedEvent(wxEVT_DIRCTRL_SELECTIONCHANGED, GetId());
709
710 changedEvent.SetEventObject(this);
711 changedEvent.SetItem(event.GetItem());
712 changedEvent.SetClientObject(m_treeCtrl->GetItemData(event.GetItem()));
713
714 if (GetEventHandler()->SafelyProcessEvent(changedEvent) && !changedEvent.IsAllowed())
715 event.Veto();
716 else
717 event.Skip();
718}
719
720void wxGenericDirCtrl::OnItemActivated(wxTreeEvent &event)
721{
722 wxTreeItemId treeid = event.GetItem();
723 const wxDirItemData *data = GetItemData(treeid);
724
725 if (data->m_isDir)
726 {
727 // is dir
728 event.Skip();
729 }
730 else
731 {
732 // is file
733 wxTreeEvent changedEvent(wxEVT_DIRCTRL_FILEACTIVATED, GetId());
734
735 changedEvent.SetEventObject(this);
736 changedEvent.SetItem(treeid);
737 changedEvent.SetClientObject(m_treeCtrl->GetItemData(treeid));
738
739 if (GetEventHandler()->SafelyProcessEvent(changedEvent) && !changedEvent.IsAllowed())
740 event.Veto();
741 else
742 event.Skip();
743 }
744}
745
746void wxGenericDirCtrl::OnExpandItem(wxTreeEvent &event)
747{
748 wxTreeItemId parentId = event.GetItem();
749
750 // VS: this is needed because the event handler is called from wxTreeCtrl
751 // ctor when wxTR_HIDE_ROOT was specified
752
753 if (!m_rootId.IsOk())
754 m_rootId = m_treeCtrl->GetRootItem();
755
756 ExpandDir(parentId);
757}
758
759void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent &event )
760{
761 CollapseDir(event.GetItem());
762}
763
764void wxGenericDirCtrl::CollapseDir(wxTreeItemId parentId)
765{
766 wxTreeItemId child;
767
768 wxDirItemData *data = GetItemData(parentId);
769 if (!data->m_isExpanded)
770 return;
771
772 data->m_isExpanded = false;
773
774 m_treeCtrl->Freeze();
775 if (parentId != m_treeCtrl->GetRootItem())
776 m_treeCtrl->CollapseAndReset(parentId);
777 m_treeCtrl->DeleteChildren(parentId);
778 m_treeCtrl->Thaw();
779}
780
781void wxGenericDirCtrl::PopulateNode(wxTreeItemId parentId)
782{
783 wxDirItemData *data = GetItemData(parentId);
784
785 if (data->m_isExpanded)
786 return;
787
788 data->m_isExpanded = true;
789
790 if (parentId == m_treeCtrl->GetRootItem())
791 {
792 SetupSections();
793 return;
794 }
795
796 wxASSERT(data);
797
798 wxString search,path,filename;
799
800 wxString dirName(data->m_path);
801
802#if (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__DOS__) || defined(__OS2__)
803 // Check if this is a root directory and if so,
804 // whether the drive is avaiable.
805 if (!wxIsDriveAvailable(dirName))
806 {
807 data->m_isExpanded = false;
808 //wxMessageBox(wxT("Sorry, this drive is not available."));
809 return;
810 }
811#endif
812
813 // This may take a longish time. Go to busy cursor
814 wxBusyCursor busy;
815
816#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
817 if (dirName.Last() == ':')
818 dirName += wxString(wxFILE_SEP_PATH);
819#endif
820
821 wxArrayString dirs;
822 wxArrayString filenames;
823
824 wxDir d;
825 wxString eachFilename;
826
827 wxLogNull log;
828 d.Open(dirName);
829
830 if (d.IsOpened())
831 {
832 int style = wxDIR_DIRS;
833 if (m_showHidden) style |= wxDIR_HIDDEN;
834 if (d.GetFirst(& eachFilename, wxEmptyString, style))
835 {
836 do
837 {
838 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
839 {
840 dirs.Add(eachFilename);
841 }
842 }
843 while (d.GetNext(&eachFilename));
844 }
845 }
846 dirs.Sort(wxDirCtrlStringCompareFunction);
847
848 // Now do the filenames -- but only if we're allowed to
849 if (!HasFlag(wxDIRCTRL_DIR_ONLY))
850 {
851 d.Open(dirName);
852
853 if (d.IsOpened())
854 {
855 int style = wxDIR_FILES;
856 if (m_showHidden) style |= wxDIR_HIDDEN;
857 // Process each filter (ex: "JPEG Files (*.jpg;*.jpeg)|*.jpg;*.jpeg")
858 wxStringTokenizer strTok;
859 wxString curFilter;
860 strTok.SetString(m_currentFilterStr,wxT(";"));
861 while(strTok.HasMoreTokens())
862 {
863 curFilter = strTok.GetNextToken();
864 if (d.GetFirst(& eachFilename, curFilter, style))
865 {
866 do
867 {
868 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
869 {
870 filenames.Add(eachFilename);
871 }
872 }
873 while (d.GetNext(& eachFilename));
874 }
875 }
876 }
877 filenames.Sort(wxDirCtrlStringCompareFunction);
878 }
879
880 // Now we really know whether we have any children so tell the tree control
881 // about it.
882 m_treeCtrl->SetItemHasChildren(parentId, !dirs.empty() || !filenames.empty());
883
884 // Add the sorted dirs
885 size_t i;
886 for (i = 0; i < dirs.GetCount(); i++)
887 {
888 eachFilename = dirs[i];
889 path = dirName;
890 if (!wxEndsWithPathSeparator(path))
891 path += wxString(wxFILE_SEP_PATH);
892 path += eachFilename;
893
894 wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,true);
895 wxTreeItemId treeid = AppendItem( parentId, eachFilename,
896 wxFileIconsTable::folder, -1, dir_item);
897 m_treeCtrl->SetItemImage( treeid, wxFileIconsTable::folder_open,
898 wxTreeItemIcon_Expanded );
899
900 // assume that it does have children by default as it can take a long
901 // time to really check for this (think remote drives...)
902 //
903 // and if we're wrong, we'll correct the icon later if
904 // the user really tries to open this item
905 m_treeCtrl->SetItemHasChildren(treeid);
906 }
907
908 // Add the sorted filenames
909 if (!HasFlag(wxDIRCTRL_DIR_ONLY))
910 {
911 for (i = 0; i < filenames.GetCount(); i++)
912 {
913 eachFilename = filenames[i];
914 path = dirName;
915 if (!wxEndsWithPathSeparator(path))
916 path += wxString(wxFILE_SEP_PATH);
917 path += eachFilename;
918 //path = dirName + wxString(wxT("/")) + eachFilename;
919 wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,false);
920 int image_id = wxFileIconsTable::file;
921 if (eachFilename.Find(wxT('.')) != wxNOT_FOUND)
922 image_id = wxTheFileIconsTable->GetIconID(eachFilename.AfterLast(wxT('.')));
923 (void) AppendItem( parentId, eachFilename, image_id, -1, dir_item);
924 }
925 }
926}
927
928void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId)
929{
930 // ExpandDir() will not actually expand the tree node, just populate it
931 PopulateNode(parentId);
932}
933
934void wxGenericDirCtrl::ReCreateTree()
935{
936 CollapseDir(m_treeCtrl->GetRootItem());
937 ExpandRoot();
938}
939
940void wxGenericDirCtrl::CollapseTree()
941{
942 wxTreeItemIdValue cookie;
943 wxTreeItemId child = m_treeCtrl->GetFirstChild(m_rootId, cookie);
944 while (child.IsOk())
945 {
946 CollapseDir(child);
947 child = m_treeCtrl->GetNextChild(m_rootId, cookie);
948 }
949}
950
951// Find the child that matches the first part of 'path'.
952// E.g. if a child path is "/usr" and 'path' is "/usr/include"
953// then the child for /usr is returned.
954wxTreeItemId wxGenericDirCtrl::FindChild(wxTreeItemId parentId, const wxString& path, bool& done)
955{
956 wxString path2(path);
957
958 // Make sure all separators are as per the current platform
959 path2.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH));
960 path2.Replace(wxT("/"), wxString(wxFILE_SEP_PATH));
961
962 // Append a separator to foil bogus substring matching
963 path2 += wxString(wxFILE_SEP_PATH);
964
965 // In MSW or PM, case is not significant
966#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
967 path2.MakeLower();
968#endif
969
970 wxTreeItemIdValue cookie;
971 wxTreeItemId childId = m_treeCtrl->GetFirstChild(parentId, cookie);
972 while (childId.IsOk())
973 {
974 wxDirItemData* data = GetItemData(childId);
975
976 if (data && !data->m_path.empty())
977 {
978 wxString childPath(data->m_path);
979 if (!wxEndsWithPathSeparator(childPath))
980 childPath += wxString(wxFILE_SEP_PATH);
981
982 // In MSW and PM, case is not significant
983#if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
984 childPath.MakeLower();
985#endif
986
987 if (childPath.length() <= path2.length())
988 {
989 wxString path3 = path2.Mid(0, childPath.length());
990 if (childPath == path3)
991 {
992 if (path3.length() == path2.length())
993 done = true;
994 else
995 done = false;
996 return childId;
997 }
998 }
999 }
1000
1001 childId = m_treeCtrl->GetNextChild(parentId, cookie);
1002 }
1003 wxTreeItemId invalid;
1004 return invalid;
1005}
1006
1007// Try to expand as much of the given path as possible,
1008// and select the given tree item.
1009bool wxGenericDirCtrl::ExpandPath(const wxString& path)
1010{
1011 bool done = false;
1012 wxTreeItemId treeid = FindChild(m_rootId, path, done);
1013 wxTreeItemId lastId = treeid; // The last non-zero treeid
1014 while (treeid.IsOk() && !done)
1015 {
1016 ExpandDir(treeid);
1017
1018 treeid = FindChild(treeid, path, done);
1019 if (treeid.IsOk())
1020 lastId = treeid;
1021 }
1022 if (!lastId.IsOk())
1023 return false;
1024
1025 wxDirItemData *data = GetItemData(lastId);
1026 if (data->m_isDir)
1027 {
1028 m_treeCtrl->Expand(lastId);
1029 }
1030 if (HasFlag(wxDIRCTRL_SELECT_FIRST) && data->m_isDir)
1031 {
1032 // Find the first file in this directory
1033 wxTreeItemIdValue cookie;
1034 wxTreeItemId childId = m_treeCtrl->GetFirstChild(lastId, cookie);
1035 bool selectedChild = false;
1036 while (childId.IsOk())
1037 {
1038 data = GetItemData(childId);
1039
1040 if (data && data->m_path != wxEmptyString && !data->m_isDir)
1041 {
1042 m_treeCtrl->SelectItem(childId);
1043 m_treeCtrl->EnsureVisible(childId);
1044 selectedChild = true;
1045 break;
1046 }
1047 childId = m_treeCtrl->GetNextChild(lastId, cookie);
1048 }
1049 if (!selectedChild)
1050 {
1051 m_treeCtrl->SelectItem(lastId);
1052 m_treeCtrl->EnsureVisible(lastId);
1053 }
1054 }
1055 else
1056 {
1057 m_treeCtrl->SelectItem(lastId);
1058 m_treeCtrl->EnsureVisible(lastId);
1059 }
1060
1061 return true;
1062}
1063
1064
1065bool wxGenericDirCtrl::CollapsePath(const wxString& path)
1066{
1067 bool done = false;
1068 wxTreeItemId treeid = FindChild(m_rootId, path, done);
1069 wxTreeItemId lastId = treeid; // The last non-zero treeid
1070
1071 while ( treeid.IsOk() && !done )
1072 {
1073 CollapseDir(treeid);
1074
1075 treeid = FindChild(treeid, path, done);
1076
1077 if ( treeid.IsOk() )
1078 lastId = treeid;
1079 }
1080
1081 if ( !lastId.IsOk() )
1082 return false;
1083
1084 m_treeCtrl->SelectItem(lastId);
1085 m_treeCtrl->EnsureVisible(lastId);
1086
1087 return true;
1088}
1089
1090wxDirItemData* wxGenericDirCtrl::GetItemData(wxTreeItemId itemId)
1091{
1092 return static_cast<wxDirItemData*>(m_treeCtrl->GetItemData(itemId));
1093}
1094
1095wxString wxGenericDirCtrl::GetPath(wxTreeItemId itemId) const
1096{
1097 const wxDirItemData*
1098 data = static_cast<wxDirItemData*>(m_treeCtrl->GetItemData(itemId));
1099
1100 return data->m_path;
1101}
1102
1103wxString wxGenericDirCtrl::GetPath() const
1104{
1105 // Allow calling GetPath() in multiple selection from OnSelFilter
1106 if (m_treeCtrl->HasFlag(wxTR_MULTIPLE))
1107 {
1108 wxArrayTreeItemIds items;
1109 m_treeCtrl->GetSelections(items);
1110 if (items.size() > 0)
1111 {
1112 // return first string only
1113 wxTreeItemId treeid = items[0];
1114 return GetPath(treeid);
1115 }
1116
1117 return wxEmptyString;
1118 }
1119
1120 wxTreeItemId treeid = m_treeCtrl->GetSelection();
1121 if (treeid)
1122 {
1123 return GetPath(treeid);
1124 }
1125 else
1126 return wxEmptyString;
1127}
1128
1129void wxGenericDirCtrl::GetPaths(wxArrayString& paths) const
1130{
1131 paths.clear();
1132
1133 wxArrayTreeItemIds items;
1134 m_treeCtrl->GetSelections(items);
1135 for ( unsigned n = 0; n < items.size(); n++ )
1136 {
1137 wxTreeItemId treeid = items[n];
1138 paths.push_back(GetPath(treeid));
1139 }
1140}
1141
1142wxString wxGenericDirCtrl::GetFilePath() const
1143{
1144 wxTreeItemId treeid = m_treeCtrl->GetSelection();
1145 if (treeid)
1146 {
1147 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(treeid);
1148 if (data->m_isDir)
1149 return wxEmptyString;
1150 else
1151 return data->m_path;
1152 }
1153 else
1154 return wxEmptyString;
1155}
1156
1157void wxGenericDirCtrl::GetFilePaths(wxArrayString& paths) const
1158{
1159 paths.clear();
1160
1161 wxArrayTreeItemIds items;
1162 m_treeCtrl->GetSelections(items);
1163 for ( unsigned n = 0; n < items.size(); n++ )
1164 {
1165 wxTreeItemId treeid = items[n];
1166 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(treeid);
1167 if ( !data->m_isDir )
1168 paths.Add(data->m_path);
1169 }
1170}
1171
1172void wxGenericDirCtrl::SetPath(const wxString& path)
1173{
1174 m_defaultPath = path;
1175 if (m_rootId)
1176 ExpandPath(path);
1177}
1178
1179void wxGenericDirCtrl::SelectPath(const wxString& path, bool select)
1180{
1181 bool done = false;
1182 wxTreeItemId treeid = FindChild(m_rootId, path, done);
1183 wxTreeItemId lastId = treeid; // The last non-zero treeid
1184 while ( treeid.IsOk() && !done )
1185 {
1186 treeid = FindChild(treeid, path, done);
1187 if ( treeid.IsOk() )
1188 lastId = treeid;
1189 }
1190 if ( !lastId.IsOk() )
1191 return;
1192
1193 if ( done )
1194 {
1195 m_treeCtrl->SelectItem(treeid, select);
1196 }
1197}
1198
1199void wxGenericDirCtrl::SelectPaths(const wxArrayString& paths)
1200{
1201 if ( HasFlag(wxDIRCTRL_MULTIPLE) )
1202 {
1203 UnselectAll();
1204 for ( unsigned n = 0; n < paths.size(); n++ )
1205 {
1206 SelectPath(paths[n]);
1207 }
1208 }
1209}
1210
1211void wxGenericDirCtrl::UnselectAll()
1212{
1213 m_treeCtrl->UnselectAll();
1214}
1215
1216// Not used
1217#if 0
1218void wxGenericDirCtrl::FindChildFiles(wxTreeItemId treeid, int dirFlags, wxArrayString& filenames)
1219{
1220 wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(treeid);
1221
1222 // This may take a longish time. Go to busy cursor
1223 wxBusyCursor busy;
1224
1225 wxASSERT(data);
1226
1227 wxString search,path,filename;
1228
1229 wxString dirName(data->m_path);
1230
1231#if defined(__WINDOWS__) || defined(__OS2__)
1232 if (dirName.Last() == ':')
1233 dirName += wxString(wxFILE_SEP_PATH);
1234#endif
1235
1236 wxDir d;
1237 wxString eachFilename;
1238
1239 wxLogNull log;
1240 d.Open(dirName);
1241
1242 if (d.IsOpened())
1243 {
1244 if (d.GetFirst(& eachFilename, m_currentFilterStr, dirFlags))
1245 {
1246 do
1247 {
1248 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
1249 {
1250 filenames.Add(eachFilename);
1251 }
1252 }
1253 while (d.GetNext(& eachFilename)) ;
1254 }
1255 }
1256}
1257#endif
1258
1259void wxGenericDirCtrl::SetFilterIndex(int n)
1260{
1261 m_currentFilter = n;
1262
1263 wxString f, d;
1264 if (ExtractWildcard(m_filter, n, f, d))
1265 m_currentFilterStr = f;
1266 else
1267#ifdef __UNIX__
1268 m_currentFilterStr = wxT("*");
1269#else
1270 m_currentFilterStr = wxT("*.*");
1271#endif
1272}
1273
1274void wxGenericDirCtrl::SetFilter(const wxString& filter)
1275{
1276 m_filter = filter;
1277
1278 if (!filter.empty() && !m_filterListCtrl && HasFlag(wxDIRCTRL_SHOW_FILTERS))
1279 m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL);
1280 else if (filter.empty() && m_filterListCtrl)
1281 {
1282 m_filterListCtrl->Destroy();
1283 m_filterListCtrl = NULL;
1284 }
1285
1286 wxString f, d;
1287 if (ExtractWildcard(m_filter, m_currentFilter, f, d))
1288 m_currentFilterStr = f;
1289 else
1290#ifdef __UNIX__
1291 m_currentFilterStr = wxT("*");
1292#else
1293 m_currentFilterStr = wxT("*.*");
1294#endif
1295 // current filter index is meaningless after filter change, set it to zero
1296 SetFilterIndex(0);
1297 if (m_filterListCtrl)
1298 m_filterListCtrl->FillFilterList(m_filter, 0);
1299}
1300
1301// Extract description and actual filter from overall filter string
1302bool wxGenericDirCtrl::ExtractWildcard(const wxString& filterStr, int n, wxString& filter, wxString& description)
1303{
1304 wxArrayString filters, descriptions;
1305 int count = wxParseCommonDialogsFilter(filterStr, descriptions, filters);
1306 if (count > 0 && n < count)
1307 {
1308 filter = filters[n];
1309 description = descriptions[n];
1310 return true;
1311 }
1312
1313 return false;
1314}
1315
1316
1317void wxGenericDirCtrl::DoResize()
1318{
1319 wxSize sz = GetClientSize();
1320 int verticalSpacing = 3;
1321 if (m_treeCtrl)
1322 {
1323 wxSize filterSz ;
1324 if (m_filterListCtrl)
1325 {
1326 filterSz = m_filterListCtrl->GetSize();
1327 sz.y -= (filterSz.y + verticalSpacing);
1328 }
1329 m_treeCtrl->SetSize(0, 0, sz.x, sz.y);
1330 if (m_filterListCtrl)
1331 {
1332 m_filterListCtrl->SetSize(0, sz.y + verticalSpacing, sz.x, filterSz.y);
1333 // Don't know why, but this needs refreshing after a resize (wxMSW)
1334 m_filterListCtrl->Refresh();
1335 }
1336 }
1337}
1338
1339
1340void wxGenericDirCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
1341{
1342 DoResize();
1343}
1344
1345wxTreeItemId wxGenericDirCtrl::AppendItem (const wxTreeItemId & parent,
1346 const wxString & text,
1347 int image, int selectedImage,
1348 wxTreeItemData * data)
1349{
1350 wxTreeCtrl *treeCtrl = GetTreeCtrl ();
1351
1352 wxASSERT (treeCtrl);
1353
1354 if (treeCtrl)
1355 {
1356 return treeCtrl->AppendItem (parent, text, image, selectedImage, data);
1357 }
1358 else
1359 {
1360 return wxTreeItemId();
1361 }
1362}
1363
1364
1365//-----------------------------------------------------------------------------
1366// wxDirFilterListCtrl
1367//-----------------------------------------------------------------------------
1368
1369IMPLEMENT_CLASS(wxDirFilterListCtrl, wxChoice)
1370
1371BEGIN_EVENT_TABLE(wxDirFilterListCtrl, wxChoice)
1372 EVT_CHOICE(wxID_ANY, wxDirFilterListCtrl::OnSelFilter)
1373END_EVENT_TABLE()
1374
1375bool wxDirFilterListCtrl::Create(wxGenericDirCtrl* parent,
1376 const wxWindowID treeid,
1377 const wxPoint& pos,
1378 const wxSize& size,
1379 long style)
1380{
1381 m_dirCtrl = parent;
1382
1383 // by default our border style is determined by the style of our parent
1384 if ( !(style & wxBORDER_MASK) )
1385 {
1386 style |= parent->HasFlag(wxDIRCTRL_3D_INTERNAL) ? wxBORDER_SUNKEN
1387 : wxBORDER_NONE;
1388 }
1389
1390 return wxChoice::Create(parent, treeid, pos, size, 0, NULL, style);
1391}
1392
1393void wxDirFilterListCtrl::Init()
1394{
1395 m_dirCtrl = NULL;
1396}
1397
1398void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent& WXUNUSED(event))
1399{
1400 int sel = GetSelection();
1401
1402 if (m_dirCtrl->HasFlag(wxDIRCTRL_MULTIPLE))
1403 {
1404 wxArrayString paths;
1405 m_dirCtrl->GetPaths(paths);
1406
1407 m_dirCtrl->SetFilterIndex(sel);
1408
1409 // If the filter has changed, the view is out of date, so
1410 // collapse the tree.
1411 m_dirCtrl->ReCreateTree();
1412
1413 // Expand and select the previously selected paths
1414 for (unsigned int i = 0; i < paths.GetCount(); i++)
1415 {
1416 m_dirCtrl->ExpandPath(paths.Item(i));
1417 }
1418 }
1419 else
1420 {
1421 wxString currentPath = m_dirCtrl->GetPath();
1422
1423 m_dirCtrl->SetFilterIndex(sel);
1424 m_dirCtrl->ReCreateTree();
1425
1426 // Try to restore the selection, or at least the directory
1427 m_dirCtrl->ExpandPath(currentPath);
1428 }
1429}
1430
1431void wxDirFilterListCtrl::FillFilterList(const wxString& filter, int defaultFilter)
1432{
1433 Clear();
1434 wxArrayString descriptions, filters;
1435 size_t n = (size_t) wxParseCommonDialogsFilter(filter, descriptions, filters);
1436
1437 if (n > 0 && defaultFilter < (int) n)
1438 {
1439 for (size_t i = 0; i < n; i++)
1440 Append(descriptions[i]);
1441 SetSelection(defaultFilter);
1442 }
1443}
1444#endif // wxUSE_DIRDLG
1445
1446#if wxUSE_DIRDLG || wxUSE_FILEDLG
1447
1448// ----------------------------------------------------------------------------
1449// wxFileIconsTable icons
1450// ----------------------------------------------------------------------------
1451
1452#ifndef __WXGTK20__
1453/* Computer (c) Julian Smart */
1454static const char* const file_icons_tbl_computer_xpm[] = {
1455/* columns rows colors chars-per-pixel */
1456"16 16 42 1",
1457"r c #4E7FD0",
1458"$ c #7198D9",
1459"; c #DCE6F6",
1460"q c #FFFFFF",
1461"u c #4A7CCE",
1462"# c #779DDB",
1463"w c #95B2E3",
1464"y c #7FA2DD",
1465"f c #3263B4",
1466"= c #EAF0FA",
1467"< c #B1C7EB",
1468"% c #6992D7",
1469"9 c #D9E4F5",
1470"o c #9BB7E5",
1471"6 c #F7F9FD",
1472", c #BED0EE",
1473"3 c #F0F5FC",
1474"1 c #A8C0E8",
1475" c None",
1476"0 c #FDFEFF",
1477"4 c #C4D5F0",
1478"@ c #81A4DD",
1479"e c #4377CD",
1480"- c #E2EAF8",
1481"i c #9FB9E5",
1482"> c #CCDAF2",
1483"+ c #89A9DF",
1484"s c #5584D1",
1485"t c #5D89D3",
1486": c #D2DFF4",
1487"5 c #FAFCFE",
1488"2 c #F5F8FD",
1489"8 c #DFE8F7",
1490"& c #5E8AD4",
1491"X c #638ED5",
1492"a c #CEDCF2",
1493"p c #90AFE2",
1494"d c #2F5DA9",
1495"* c #5282D0",
1496"7 c #E5EDF9",
1497". c #A2BCE6",
1498"O c #8CACE0",
1499/* pixels */
1500" ",
1501" .XXXXXXXXXXX ",
1502" oXO++@#$%&*X ",
1503" oX=-;:>,<1%X ",
1504" oX23=-;:4,$X ",
1505" oX5633789:@X ",
1506" oX05623=78+X ",
1507" oXqq05623=OX ",
1508" oX,,,,,<<<$X ",
1509" wXXXXXXXXXXe ",
1510" XrtX%$$y@+O,, ",
1511" uyiiiiiiiii@< ",
1512" ouiiiiiiiiiip<a",
1513" rustX%$$y@+Ow,,",
1514" dfffffffffffffd",
1515" "
1516};
1517#endif // !GTK+ 2
1518
1519// ----------------------------------------------------------------------------
1520// wxFileIconsTable & friends
1521// ----------------------------------------------------------------------------
1522
1523// global instance of a wxFileIconsTable
1524wxFileIconsTable* wxTheFileIconsTable = NULL;
1525
1526// A module to allow icons table cleanup
1527
1528class wxFileIconsTableModule: public wxModule
1529{
1530DECLARE_DYNAMIC_CLASS(wxFileIconsTableModule)
1531public:
1532 wxFileIconsTableModule() {}
1533 bool OnInit() { wxTheFileIconsTable = new wxFileIconsTable; return true; }
1534 void OnExit()
1535 {
1536 wxDELETE(wxTheFileIconsTable);
1537 }
1538};
1539
1540IMPLEMENT_DYNAMIC_CLASS(wxFileIconsTableModule, wxModule)
1541
1542class wxFileIconEntry : public wxObject
1543{
1544public:
1545 wxFileIconEntry(int i) { iconid = i; }
1546
1547 int iconid;
1548};
1549
1550wxFileIconsTable::wxFileIconsTable()
1551{
1552 m_HashTable = NULL;
1553 m_smallImageList = NULL;
1554}
1555
1556wxFileIconsTable::~wxFileIconsTable()
1557{
1558 if (m_HashTable)
1559 {
1560 WX_CLEAR_HASH_TABLE(*m_HashTable);
1561 delete m_HashTable;
1562 }
1563 if (m_smallImageList) delete m_smallImageList;
1564}
1565
1566// delayed initialization - wait until first use (wxArtProv not created yet)
1567void wxFileIconsTable::Create()
1568{
1569 wxCHECK_RET(!m_smallImageList && !m_HashTable, wxT("creating icons twice"));
1570 m_HashTable = new wxHashTable(wxKEY_STRING);
1571 m_smallImageList = new wxImageList(16, 16);
1572
1573 // folder:
1574 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FOLDER,
1575 wxART_CMN_DIALOG,
1576 wxSize(16, 16)));
1577 // folder_open
1578 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FOLDER_OPEN,
1579 wxART_CMN_DIALOG,
1580 wxSize(16, 16)));
1581 // computer
1582#ifdef __WXGTK20__
1583 // GTK24 uses this icon in the file open dialog
1584 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK,
1585 wxART_CMN_DIALOG,
1586 wxSize(16, 16)));
1587#else
1588 m_smallImageList->Add(wxIcon(file_icons_tbl_computer_xpm));
1589#endif
1590 // drive
1591 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK,
1592 wxART_CMN_DIALOG,
1593 wxSize(16, 16)));
1594 // cdrom
1595 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_CDROM,
1596 wxART_CMN_DIALOG,
1597 wxSize(16, 16)));
1598 // floppy
1599 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FLOPPY,
1600 wxART_CMN_DIALOG,
1601 wxSize(16, 16)));
1602 // removeable
1603 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_REMOVABLE,
1604 wxART_CMN_DIALOG,
1605 wxSize(16, 16)));
1606 // file
1607 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE,
1608 wxART_CMN_DIALOG,
1609 wxSize(16, 16)));
1610 // executable
1611 if (GetIconID(wxEmptyString, wxT("application/x-executable")) == file)
1612 {
1613 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE,
1614 wxART_CMN_DIALOG,
1615 wxSize(16, 16)));
1616 delete m_HashTable->Get(wxT("exe"));
1617 m_HashTable->Delete(wxT("exe"));
1618 m_HashTable->Put(wxT("exe"), new wxFileIconEntry(executable));
1619 }
1620 /* else put into list by GetIconID
1621 (KDE defines application/x-executable for *.exe and has nice icon)
1622 */
1623}
1624
1625wxImageList *wxFileIconsTable::GetSmallImageList()
1626{
1627 if (!m_smallImageList)
1628 Create();
1629
1630 return m_smallImageList;
1631}
1632
1633#if wxUSE_MIMETYPE && wxUSE_IMAGE && (!defined(__WINDOWS__) || wxUSE_WXDIB)
1634// VS: we don't need this function w/o wxMimeTypesManager because we'll only have
1635// one icon and we won't resize it
1636
1637static wxBitmap CreateAntialiasedBitmap(const wxImage& img)
1638{
1639 const unsigned int size = 16;
1640
1641 wxImage smallimg (size, size);
1642 unsigned char *p1, *p2, *ps;
1643 unsigned char mr = img.GetMaskRed(),
1644 mg = img.GetMaskGreen(),
1645 mb = img.GetMaskBlue();
1646
1647 unsigned x, y;
1648 unsigned sr, sg, sb, smask;
1649
1650 p1 = img.GetData(), p2 = img.GetData() + 3 * size*2, ps = smallimg.GetData();
1651 smallimg.SetMaskColour(mr, mr, mr);
1652
1653 for (y = 0; y < size; y++)
1654 {
1655 for (x = 0; x < size; x++)
1656 {
1657 sr = sg = sb = smask = 0;
1658 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
1659 sr += p1[0], sg += p1[1], sb += p1[2];
1660 else smask++;
1661 p1 += 3;
1662 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
1663 sr += p1[0], sg += p1[1], sb += p1[2];
1664 else smask++;
1665 p1 += 3;
1666 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
1667 sr += p2[0], sg += p2[1], sb += p2[2];
1668 else smask++;
1669 p2 += 3;
1670 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
1671 sr += p2[0], sg += p2[1], sb += p2[2];
1672 else smask++;
1673 p2 += 3;
1674
1675 if (smask > 2)
1676 ps[0] = ps[1] = ps[2] = mr;
1677 else
1678 {
1679 ps[0] = (unsigned char)(sr >> 2);
1680 ps[1] = (unsigned char)(sg >> 2);
1681 ps[2] = (unsigned char)(sb >> 2);
1682 }
1683 ps += 3;
1684 }
1685 p1 += size*2 * 3, p2 += size*2 * 3;
1686 }
1687
1688 return wxBitmap(smallimg);
1689}
1690
1691// This function is currently not unused anymore
1692#if 0
1693// finds empty borders and return non-empty area of image:
1694static wxImage CutEmptyBorders(const wxImage& img)
1695{
1696 unsigned char mr = img.GetMaskRed(),
1697 mg = img.GetMaskGreen(),
1698 mb = img.GetMaskBlue();
1699 unsigned char *dt = img.GetData(), *dttmp;
1700 unsigned w = img.GetWidth(), h = img.GetHeight();
1701
1702 unsigned top, bottom, left, right, i;
1703 bool empt;
1704
1705#define MK_DTTMP(x,y) dttmp = dt + ((x + y * w) * 3)
1706#define NOEMPTY_PIX(empt) if (dttmp[0] != mr || dttmp[1] != mg || dttmp[2] != mb) {empt = false; break;}
1707
1708 for (empt = true, top = 0; empt && top < h; top++)
1709 {
1710 MK_DTTMP(0, top);
1711 for (i = 0; i < w; i++, dttmp+=3)
1712 NOEMPTY_PIX(empt)
1713 }
1714 for (empt = true, bottom = h-1; empt && bottom > top; bottom--)
1715 {
1716 MK_DTTMP(0, bottom);
1717 for (i = 0; i < w; i++, dttmp+=3)
1718 NOEMPTY_PIX(empt)
1719 }
1720 for (empt = true, left = 0; empt && left < w; left++)
1721 {
1722 MK_DTTMP(left, 0);
1723 for (i = 0; i < h; i++, dttmp+=3*w)
1724 NOEMPTY_PIX(empt)
1725 }
1726 for (empt = true, right = w-1; empt && right > left; right--)
1727 {
1728 MK_DTTMP(right, 0);
1729 for (i = 0; i < h; i++, dttmp+=3*w)
1730 NOEMPTY_PIX(empt)
1731 }
1732 top--, left--, bottom++, right++;
1733
1734 return img.GetSubImage(wxRect(left, top, right - left + 1, bottom - top + 1));
1735}
1736#endif // #if 0
1737
1738#endif // wxUSE_MIMETYPE
1739
1740int wxFileIconsTable::GetIconID(const wxString& extension, const wxString& mime)
1741{
1742 if (!m_smallImageList)
1743 Create();
1744
1745#if wxUSE_MIMETYPE
1746 if (!extension.empty())
1747 {
1748 wxFileIconEntry *entry = (wxFileIconEntry*) m_HashTable->Get(extension);
1749 if (entry) return (entry -> iconid);
1750 }
1751
1752 wxFileType *ft = (mime.empty()) ?
1753 wxTheMimeTypesManager -> GetFileTypeFromExtension(extension) :
1754 wxTheMimeTypesManager -> GetFileTypeFromMimeType(mime);
1755
1756 wxIconLocation iconLoc;
1757 wxIcon ic;
1758
1759 {
1760 wxLogNull logNull;
1761 if ( ft && ft->GetIcon(&iconLoc) )
1762 {
1763 ic = wxIcon( iconLoc );
1764 }
1765 }
1766
1767 delete ft;
1768
1769 if ( !ic.IsOk() )
1770 {
1771 int newid = file;
1772 m_HashTable->Put(extension, new wxFileIconEntry(newid));
1773 return newid;
1774 }
1775
1776 wxBitmap bmp;
1777 bmp.CopyFromIcon(ic);
1778
1779 if ( !bmp.IsOk() )
1780 {
1781 int newid = file;
1782 m_HashTable->Put(extension, new wxFileIconEntry(newid));
1783 return newid;
1784 }
1785
1786 const unsigned int size = 16;
1787
1788 int treeid = m_smallImageList->GetImageCount();
1789 if ((bmp.GetWidth() == (int) size) && (bmp.GetHeight() == (int) size))
1790 {
1791 m_smallImageList->Add(bmp);
1792 }
1793#if wxUSE_IMAGE && (!defined(__WINDOWS__) || wxUSE_WXDIB)
1794 else
1795 {
1796 wxImage img = bmp.ConvertToImage();
1797
1798 if ((img.GetWidth() != size*2) || (img.GetHeight() != size*2))
1799// m_smallImageList->Add(CreateAntialiasedBitmap(CutEmptyBorders(img).Rescale(size*2, size*2)));
1800 m_smallImageList->Add(CreateAntialiasedBitmap(img.Rescale(size*2, size*2)));
1801 else
1802 m_smallImageList->Add(CreateAntialiasedBitmap(img));
1803 }
1804#endif // wxUSE_IMAGE
1805
1806 m_HashTable->Put(extension, new wxFileIconEntry(treeid));
1807 return treeid;
1808
1809#else // !wxUSE_MIMETYPE
1810
1811 wxUnusedVar(mime);
1812 if (extension == wxT("exe"))
1813 return executable;
1814 else
1815 return file;
1816#endif // wxUSE_MIMETYPE/!wxUSE_MIMETYPE
1817}
1818
1819#endif // wxUSE_DIRDLG || wxUSE_FILEDLG