/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
-#pragma implementation "dirctrl.h"
+#pragma implementation "dirctrlg.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/sizer.h"
#include "wx/tokenzr.h"
#include "wx/dir.h"
+#include "wx/settings.h"
#if wxUSE_STATLINE
#include "wx/statline.h"
#include "wx/generic/dirctrlg.h"
#ifdef __WXMSW__
+#include <windows.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>
#endif
+#ifdef __BORLANDC__
+#include "dos.h"
+#endif
+
// If compiled under Windows, this macro can cause problems
#ifdef GetFirstChild
#undef GetFirstChild
/* width height ncolors chars_per_pixel */
"16 16 3 1",
/* colors */
-" s None c None",
-". c #000000",
-"+ c #ffffff",
+" s None c None",
+". c #000000",
+"+ c #ffffff",
/* pixels */
" ",
" ........ ",
/* Computer */
static char * icon4_xpm[] = {
"16 16 7 1",
-" s None c None",
-". c #808080",
-"X c #c0c0c0",
-"o c Black",
-"O c Gray100",
-"+ c #008080",
-"@ c Blue",
+" s None c None",
+". c #808080",
+"X c #c0c0c0",
+"o c Black",
+"O c Gray100",
+"+ c #008080",
+"@ c Blue",
" ........... ",
" .XXXXXXXXXX.o",
" .OOOOOOOOO..o",
/* Drive */
static char * icon5_xpm[] = {
"16 16 7 1",
-" s None c None",
-". c #808080",
-"X c #c0c0c0",
-"o c Black",
-"O c Gray100",
-"+ c Green",
-"@ c #008000",
+" s None c None",
+". c #808080",
+"X c #c0c0c0",
+"o c Black",
+"O c Gray100",
+"+ c Green",
+"@ c #008000",
" ",
" ",
" ",
/* CD-ROM */
static char *icon6_xpm[] = {
"16 16 10 1",
-" s None c None",
-". c #808080",
-"X c #c0c0c0",
-"o c Yellow",
-"O c Blue",
-"+ c Black",
-"@ c Gray100",
-"# c #008080",
-"$ c Green",
-"% c #008000",
+" s None c None",
+". c #808080",
+"X c #c0c0c0",
+"o c Yellow",
+"O c Blue",
+"+ c Black",
+"@ c Gray100",
+"# c #008080",
+"$ c Green",
+"% c #008000",
" ... ",
" ..XoX.. ",
" .O.XoXXX+ ",
/* Floppy */
static char * icon7_xpm[] = {
"16 16 7 1",
-" s None c None",
-". c #808080",
-"X c Gray100",
-"o c #c0c0c0",
-"O c Black",
-"+ c Cyan",
-"@ c Red",
+" s None c None",
+". c #808080",
+"X c Gray100",
+"o c #c0c0c0",
+"O c Black",
+"+ c Cyan",
+"@ c Red",
" ......X",
" .ooooooO",
" .+++++OO",
/* Removeable */
static char * icon8_xpm[] = {
"16 16 7 1",
-" s None c None",
-". c #808080",
-"X c #c0c0c0",
-"o c Black",
-"O c Gray100",
-"+ c Red",
-"@ c #800000",
+" s None c None",
+". c #808080",
+"X c #c0c0c0",
+"o c Black",
+"O c Gray100",
+"+ c Red",
+"@ c #800000",
" ",
" ",
" ",
static const int ID_NEW = 1004;
//static const int ID_CHECK = 1005;
+#ifdef __WXMSW__
+static bool wxIsDriveAvailable(const wxString dirName)
+{
+#ifdef __WIN32__
+ UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+#endif
+ bool success = TRUE;
+
+ // Check if this is a root directory and if so,
+ // whether the drive is avaiable.
+ if (dirName.Len() == 3 && dirName[(size_t)1] == wxT(':'))
+ {
+ wxString dirNameLower(dirName.Lower());
+ int currentDrive = _getdrive();
+ int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ;
+ int err = _chdrive( thisDrive ) ;
+ _chdrive( currentDrive );
+
+ if (err == -1)
+ {
+ success = FALSE;
+ }
+ }
+#ifdef __WIN32__
+ (void) SetErrorMode(errorMode);
+#endif
+
+ return success;
+}
+#endif
+
//-----------------------------------------------------------------------------
// wxDirItemDataEx
//-----------------------------------------------------------------------------
* For FileNameFromPath read LastDirNameInThisPath ;-) */
// m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
m_isHidden = FALSE;
- m_hasSubDirs = HasSubDirs();
+ // m_hasSubDirs is no longer needed
+ m_hasSubDirs = TRUE; // HasSubDirs();
m_isExpanded = FALSE;
m_isDir = isDir;
}
m_name = wxFileNameFromPath( path );
}
+// No longer used, and takes a very long time
bool wxDirItemDataEx::HasSubDirs()
{
- wxString search = m_path + wxT("/*");
+ if (m_path.IsEmpty())
+ return TRUE;
+
+ // On WIN32, must check if this volume is mounted or
+ // we get an error dialog for e.g. drive a:
+#ifdef __WIN32__
+ if (!wxIsDriveAvailable(m_path))
+ return FALSE;
+#endif
+
+ wxString search = m_path;
+
+ if (m_path.Last() != wxFILE_SEP_PATH)
+ {
+ search += wxString(wxFILE_SEP_PATH);
+ }
+ search += wxT("*");
+
wxLogNull log;
wxString path = wxFindFirstFile( search, wxDIR );
return (bool)(!path.IsNull());
Init();
- long treeStyle = wxTR_HAS_BUTTONS;
+ long treeStyle = wxTR_HAS_BUTTONS ; // | wxTR_EDIT_LABELS;
if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
treeStyle |= wxNO_BORDER;
m_imageList->Add(wxIcon(icon7_xpm));
m_imageList->Add(wxIcon(icon8_xpm));
#elif defined(__WXMSW__)
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_CLOSED_FOLDER"), wxBITMAP_TYPE_RESOURCE));
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_OPEN_FOLDER"), wxBITMAP_TYPE_RESOURCE));
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_FILE"), wxBITMAP_TYPE_RESOURCE));
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_COMPUTER"), wxBITMAP_TYPE_RESOURCE));
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_DRIVE"), wxBITMAP_TYPE_RESOURCE));
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_CDROM"), wxBITMAP_TYPE_RESOURCE));
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_FLOPPY"), wxBITMAP_TYPE_RESOURCE));
- m_imageList->Add(wxIcon(wxT("wxICON_SMALL_REMOVEABLE"), wxBITMAP_TYPE_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_CLOSED_FOLDER"), wxBITMAP_TYPE_ICO_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_OPEN_FOLDER"), wxBITMAP_TYPE_ICO_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_FILE"), wxBITMAP_TYPE_ICO_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_COMPUTER"), wxBITMAP_TYPE_ICO_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_DRIVE"), wxBITMAP_TYPE_ICO_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_CDROM"), wxBITMAP_TYPE_ICO_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_FLOPPY"), wxBITMAP_TYPE_ICO_RESOURCE));
+ m_imageList->Add(wxIcon(wxT("wxICON_SMALL_REMOVEABLE"), wxBITMAP_TYPE_ICO_RESOURCE));
#else
#error "Sorry, we don't have icons available for this platforms."
#endif
{
m_showHidden = FALSE;
m_imageList = NULL;
- m_rootId = 0;
m_currentFilter = 0;
m_currentFilterStr = wxEmptyString; // Default: any file
m_treeCtrl = NULL;
#else
// Unix: sections are displayed as folders
wxTreeItemId id = m_treeCtrl->AppendItem( m_rootId, name, 0, -1, dir_item);
- SetItemImage( id, 1, wxTreeItemIcon_Expanded );
+ m_treeCtrl->SetItemImage( id, 1, wxTreeItemIcon_Expanded );
#endif
// TODO: other operating systems.
int drive;
int currentDrive;
- /* Save current drive. */
- currentDrive = _getdrive();
-
/* If we can switch to the drive, it exists. */
for( drive = 1; drive <= 26; drive++ )
{
path.Printf(wxT("%c:\\"), (char) (drive + 'a' - 1));
name.Printf(wxT("(%c:)"), (char) (drive + 'a' - 1));
- if( !_chdrive( drive ) )
+ if (wxIsDriveAvailable(path))
{
AddSection(path, name);
}
}
-
- /* Restore original drive.*/
- _chdrive( currentDrive );
#endif
#else
- wxString home;
- AddSection(wxT("/"), _("The Computer"), 0)
- wxGetHomeDir(&home);
- AddSection(home, _("My Home"), 0 )
- AddSection(wxT("/mnt"), _("Mounted Devices"), 0 )
- AddSection(wxT("/usr/local"), _("User Local"), 0 )
- AddSection(wxT("/usr"), _("User"), 0 )
- AddSection(wxT("/var"), _("Variables"), 0 )
- AddSection(wxT("/etc"), _("Etcetera"), 0 )
- AddSection(wxT("/tmp"), _("Temporary"), 0 )
+ AddSection(wxT("/"), _("The Computer"), 0);
+ AddSection(wxGetHomeDir(), _("My Home"), 0 );
+ AddSection(wxT("/mnt"), _("Mounted Devices"), 0 );
+ AddSection(wxT("/usr/local"), _("User Local"), 0 );
+ AddSection(wxT("/usr"), _("User"), 0 );
+ AddSection(wxT("/var"), _("Variables"), 0 );
+ AddSection(wxT("/etc"), _("Etcetera"), 0 );
+ AddSection(wxT("/tmp"), _("Temporary"), 0 );
#endif
}
wxASSERT( data );
wxString new_name( wxPathOnly( data->m_path ) );
- new_name += wxT("/");
+ new_name += wxString(wxFILE_SEP_PATH);
new_name += event.GetLabel();
wxLogNull log;
#ifdef __WXMSW__
// Check if this is a root directory and if so,
// whether the drive is avaiable.
- if (dirName.Len() == 3 && dirName[1] == wxT(':'))
+ if (!wxIsDriveAvailable(dirName))
{
- int currentDrive = _getdrive();
- int thisDrive = (int) (dirName[0] - 'a' + 1) ;
- int err = _chdrive( thisDrive ) ;
- _chdrive( currentDrive );
-
- if (err == -1)
- {
- data->m_isExpanded = FALSE;
- wxMessageBox(wxT("Sorry, this drive is not available."));
- return;
- }
+ data->m_isExpanded = FALSE;
+ wxMessageBox(wxT("Sorry, this drive is not available."));
+ return;
}
#endif
wxDir d;
wxString eachFilename;
+ wxLogNull log;
d.Open(dirName);
if (d.IsOpened())
// Now do the filenames -- but only if we're allowed to
if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0)
{
+ wxLogNull log;
+
d.Open(dirName);
if (d.IsOpened())
options = wxDIR_DIRS;
}
- wxDir dir2(path);
- wxString str;
- // Have to test for wxDIR_DIRS separately in case m_currentFilterStr is non-empty and
- // and filters out any directories
- if (dir2.GetFirst(& str, m_currentFilterStr, options) || dir2.GetFirst(& str, wxEmptyString, wxDIR_DIRS))
+ wxLogNull log;
+ wxDir dir2;
+ if (dir2.Open(path))
{
- m_treeCtrl->SetItemHasChildren(id);
- }
+ wxString str;
+ // Have to test for wxDIR_DIRS separately in case m_currentFilterStr is non-empty and
+ // and filters out any directories
+ if (dir2.GetFirst(& str, m_currentFilterStr, options) || dir2.GetFirst(& str, wxEmptyString, wxDIR_DIRS))
+ {
+ m_treeCtrl->SetItemHasChildren(id);
+ }
+ }
}
// Add the sorted filenames
path += eachFilename;
//path = dirName + wxString(wxT("/")) + eachFilename;
wxDirItemDataEx *dir_item = new wxDirItemDataEx(path,eachFilename,FALSE);
- wxTreeItemId id = m_treeCtrl->AppendItem( parentId, eachFilename, 2, -1, dir_item);
+ (void)m_treeCtrl->AppendItem( parentId, eachFilename, 2, -1, dir_item);
}
}
}
childId = m_treeCtrl->GetNextChild(childId, cookie);
}
- return 0;
+ wxTreeItemId invalid;
+ return invalid;
}
// Try to expand as much of the given path as possible,
wxDir d;
wxString eachFilename;
+ wxLogNull log;
d.Open(dirName);
if (d.IsOpened())
BEGIN_EVENT_TABLE(wxGenericDirDialog, wxDialog)
EVT_BUTTON(wxID_OK, wxGenericDirDialog::OnOK)
+ EVT_BUTTON(wxID_NEW, wxGenericDirDialog::OnNew)
+ EVT_BUTTON (wxID_NEW, wxGenericDirDialog::OnNew)
EVT_CLOSE(wxGenericDirDialog::OnCloseWindow)
+ EVT_TREE_KEY_DOWN (-1, wxGenericDirDialog::OnTreeKeyDown)
+ EVT_TREE_SEL_CHANGED (-1, wxGenericDirDialog::OnTreeSelected)
+ EVT_TEXT_ENTER (ID_TEXTCTRL, wxGenericDirDialog::OnOK)
END_EVENT_TABLE()
wxGenericDirDialog::wxGenericDirDialog(wxWindow* parent, const wxString& title,
const wxString& defaultPath, long style, const wxPoint& pos, const wxSize& sz, const wxString& name):
wxDialog(parent, ID_DIRCTRL, title, pos, sz, style, name)
{
+ m_dirCtrl = NULL;
+ m_path = defaultPath;
+
wxBusyCursor cursor;
wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
// 1) dir ctrl
m_dirCtrl = new wxGenericDirCtrl(this, ID_DIRCTRL,
defaultPath, wxPoint(5, 5),
- wxSize(300, 200), wxDIRCTRL_DIR_ONLY);
+ wxSize(300, 200), wxDIRCTRL_DIR_ONLY|wxSUNKEN_BORDER);
topsizer->Add( m_dirCtrl, 1, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 );
- // 2) TODO: text control for entering path?
+ // 2) text ctrl
+ m_input = new wxTextCtrl( this, ID_TEXTCTRL, m_path, wxDefaultPosition );
+ topsizer->Add( m_input, 0, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 );
#if wxUSE_STATLINE
// 3) Static line
wxButton* cancelButton = new wxButton(this, wxID_CANCEL, _("Cancel"));
buttonsizer->Add( cancelButton, 0, wxLEFT|wxRIGHT, 10 );
-/* TODO: new directory button
- wxButton* newButton = new wxButton( this, ID_NEW, _("New...") );
+ // I'm not convinced we need a New button, and we tend to get annoying
+ // accidental-editing with label editing enabled.
+#if 0
+ wxButton* newButton = new wxButton( this, wxID_NEW, _("New...") );
buttonsizer->Add( newButton, 0, wxLEFT|wxRIGHT, 10 );
-*/
+#endif
+
topsizer->Add( buttonsizer, 0, wxALL | wxCENTER, 10 );
okButton->SetDefault();
void wxGenericDirDialog::OnOK(wxCommandEvent& event)
{
- EndModal(wxID_OK);
+ m_path = m_input->GetValue();
+ // Does the path exist? (User may have typed anything in m_input)
+ if (wxPathExists(m_path)) {
+ // OK, path exists, we're done.
+ EndModal(wxID_OK);
+ return;
+ }
+ // Interact with user, find out if the dir is a typo or to be created
+ wxString msg( _("The directory ") );
+ msg = msg + m_path;
+ msg = msg + _("\ndoes not exist\nCreate it now?") ;
+ wxMessageDialog dialog(this, msg, _("Directory does not exist"), wxYES_NO | wxICON_WARNING );
+ if ( dialog.ShowModal() == wxID_YES ) {
+ // Okay, let's make it
+ wxLogNull log;
+ if (wxMkdir(m_path)) {
+ // The new dir was created okay.
+ EndModal(wxID_OK);
+ return;
+ }
+ else {
+ // Trouble...
+ msg = _("Failed to create directory ")+m_path+
+ _("\n(Do you have the required permissions?)");
+ wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK | wxICON_ERROR);
+ errmsg.ShowModal();
+ // We still don't have a valid dir. Back to the main dialog.
+ }
+ }
+ // User has answered NO to create dir.
}
void wxGenericDirDialog::SetPath(const wxString& path)
{
m_dirCtrl->SetPath(path);
+ m_path = path;
}
wxString wxGenericDirDialog::GetPath(void) const
{
- return m_dirCtrl->GetPath();
+ return m_path;
+}
+
+int wxGenericDirDialog::ShowModal()
+{
+ //m_input->SetValue( m_path );
+ return wxDialog::ShowModal();
+}
+
+void wxGenericDirDialog::OnTreeSelected( wxTreeEvent &event )
+{
+ if (!m_dirCtrl)
+ return;
+
+ wxDirItemDataEx *data = (wxDirItemDataEx*)m_dirCtrl->GetTreeCtrl()->GetItemData(event.GetItem());
+ if (data)
+ m_input->SetValue( data->m_path );
+};
+
+void wxGenericDirDialog::OnTreeKeyDown( wxTreeEvent &WXUNUSED(event) )
+{
+ if (!m_dirCtrl)
+ return;
+
+ wxDirItemDataEx *data = (wxDirItemDataEx*)m_dirCtrl->GetTreeCtrl()->GetItemData(m_dirCtrl->GetTreeCtrl()->GetSelection());
+ if (data)
+ m_input->SetValue( data->m_path );
+};
+
+void wxGenericDirDialog::OnNew( wxCommandEvent& WXUNUSED(event) )
+{
+ wxTreeItemId id = m_dirCtrl->GetTreeCtrl()->GetSelection();
+ if ((id == m_dirCtrl->GetTreeCtrl()->GetRootItem()) ||
+ (m_dirCtrl->GetTreeCtrl()->GetParent(id) == m_dirCtrl->GetTreeCtrl()->GetRootItem()))
+ {
+ wxMessageDialog msg(this, _("You cannot add a new directory to this section."),
+ _("Create directory"), wxOK | wxICON_INFORMATION );
+ msg.ShowModal();
+ return;
+ }
+
+ wxTreeItemId parent = id ; // m_dirCtrl->GetTreeCtrl()->GetParent( id );
+ wxDirItemDataEx *data = (wxDirItemDataEx*)m_dirCtrl->GetTreeCtrl()->GetItemData( parent );
+ wxASSERT( data );
+
+ wxString new_name( wxT("NewName") );
+ wxString path( data->m_path );
+ if (path.Last() != wxFILE_SEP_PATH)
+ path += wxFILE_SEP_PATH;
+ path += new_name;
+ if (wxFileExists(path))
+ {
+ // try NewName0, NewName1 etc.
+ int i = 0;
+ do {
+ new_name = wxT("NewName");
+ wxString num;
+ num.Printf( wxT("%d"), i );
+ new_name += num;
+
+ path = data->m_path;
+ if (path.Last() != wxFILE_SEP_PATH)
+ path += wxFILE_SEP_PATH;
+ path += new_name;
+ i++;
+ } while (wxFileExists(path));
+ }
+
+ wxLogNull log;
+ if (!wxMkdir(path))
+ {
+ wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
+ dialog.ShowModal();
+ return;
+ }
+
+ wxDirItemDataEx *new_data = new wxDirItemDataEx( path, new_name, TRUE );
+
+ // TODO: THIS CODE DOESN'T WORK YET. We need to avoid duplication of the first child
+ // of the parent.
+ wxTreeItemId new_id = m_dirCtrl->GetTreeCtrl()->AppendItem( parent, new_name, 0, 0, new_data );
+ m_dirCtrl->GetTreeCtrl()->EnsureVisible( new_id );
+ m_dirCtrl->GetTreeCtrl()->EditLabel( new_id );
}