diff --git a/distrib/msw/tmake/filelist.txt b/distrib/msw/tmake/filelist.txt
index 054fa153c4..d4013fd5de 100644
--- a/distrib/msw/tmake/filelist.txt
+++ b/distrib/msw/tmake/filelist.txt
@@ -119,6 +119,7 @@ datstrm.cpp C B
db.cpp C 32,B
dbtable.cpp C 32,B
dcbase.cpp C
+dircmn.cpp C B
dlgcmn.cpp C
dobjcmn.cpp C
dndcmn.cpp C
diff --git a/docs/changes.txt b/docs/changes.txt
index 7a975621d6..15f9740580 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -8,14 +8,15 @@ wxBase:
- fixed problem with wxURL when using static version of the library
- wxZipFSHandler::FindFirst() and FindNext() now correctly list directories
-- wxMimeTypesManager now can create file associations too
+- wxMimeTypesManager now can create file associations too (Chris Elliott)
- wxCopyFile() respects the file permissions (Roland Scholz)
- wxFTP::GetFileSize() added (Søren Erland Vestø)
- wxDateTime::IsSameDate() bug fixed
- wxTimeSpan::Format() now behaves more as expected, see docs
-- wxLocale now provides much more convenient API for setting language and detecting
- current system language. New API is more abstracted and truly cross-platform,
- independent of underlying C runtime library.
+- wxLocale now provides much more convenient API for setting language and
+ detecting current system language. New API is more abstracted and truly
+ cross-platform, independent of underlying C runtime library.
+- wxDir::Traverse() added
All (GUI):
@@ -25,7 +26,7 @@ All (GUI):
- FindOrCreateBrush/Pen() bug fix for invalid colour values
- new wxXPMHandler for reading and writing XPM images
- added new (now recommended) API for conversion between wxImage and wxBitmap
- (wxBitmap::ConvertToImage() and wxBitmap::wxBitmap(wxImage&) instead of
+ (wxBitmap::ConvertToImage() and wxBitmap::wxBitmap(wxImage&) instead of
wxImage methods and ctor)
wxMSW:
@@ -34,7 +35,7 @@ wxMSW:
- fixed bug in MDI children flags (mis)handling
- it is possible to compile wxCHMHelpController with other compilers than VisualC++
now and hhctrl.ocx is loaded at runtime.
-
+
wxGTK:
- added support for wchar_t (wxUSE_WCHAR_T) under Unix
@@ -238,7 +239,7 @@ wxHTML:
- almost complete rewrite of wxHtmlHelpController,
including faster search, bookmarks, printing, setup dialog
- and cross-platform binary compatible .cached files for faster
+ and cross-platform binary compatible .cached files for faster
loading of large helpbooks, case insensitive search
splitted into 3 parts: wxHtmlHelpData, Frame and Controller
- added support for charsets and tag
diff --git a/docs/latex/wx/dir.tex b/docs/latex/wx/dir.tex
index 3b1e5b7e25..4c06f3bce3 100644
--- a/docs/latex/wx/dir.tex
+++ b/docs/latex/wx/dir.tex
@@ -1,8 +1,13 @@
-%
-% automatically generated by HelpGen from
-% include\wx\dir.h at 11/Dec/99 00:55:30
-%
-
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Name: dir.tex
+%% Purpose: wxDir documentation
+%% Author: Vadim Zeitlin
+%% Modified by:
+%% Created: 04.04.00
+%% RCS-ID: $Id$
+%% Copyright: (c) Vadim Zeitlin
+%% License: wxWindows license
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{\class{wxDir}}\label{wxdir}
@@ -10,6 +15,10 @@ wxDir is a portable equivalent of Unix {open/read/close}dir functions which
allow enumerating of the files in a directory. wxDir allows enumerate files as
well as directories.
+wxDir also provides a flexible way to enumerate files recursively using
+\helpref{Traverse}{wxdirtraverse} or a simpler
+\helpref{GetAllFiles}{wxdirgetallfiles} function.
+
Example of use:
\begin{verbatim}
@@ -117,3 +126,117 @@ empty) and flags, return TRUE on success.
Continue enumerating files satisfying the criteria specified by the last call
to \helpref{GetFirst}{wxdirgetfirst}.
+\membersection{wxDir::Traverse}{wxdirtraverse}
+
+\func{size\_t}{Traverse}{\param{wxDirTraverser& }{sink}, \param{const wxString& }{filespec = wxEmptyString}, \param{int }{flags = wxDIR\_DEFAULT}}
+
+Enumerate all files and directories under the given directory recursively
+calling the element of the provided \helpref{wxDirTraverser}{wxdirtraverser}
+object for each of them.
+
+More precisely, the function will really recurse into subdirectories if
+{\it flags} contains {\tt wxDIR\_DIRS} flag. It will ignore the files (but
+still possibly recurse into subdirectories) if {\tt wxDIR\_FILES} flag is
+given.
+
+For each found directory, \helpref{sink.OnDir()}{wxdirtraverserondir} is called
+and \helpref{sink.OnFile()}{wxdirtraverseronfile} is called for every file.
+Depending on the return value, the enumeration may continue or stop.
+
+The function returns the total number of files found or {\tt (size\_t)-1} on
+error.
+
+See also: \helpref{GetAllFiles}{wxdirgetallfiles}
+
+\membersection{wxDirTraverser::GetAllFiles}{wxdirtraversergetallfiles}
+
+\func{static size\_t}{GetAllFiles}{\param{const wxString& }{dirname}, \param{wxArrayString *}{files}, \param{const wxString& }{filespec = wxEmptyString}, \param{int }{flags = wxDIR\_DEFAULT}}
+
+The function appends the names of all the files under directory {\it dirname}
+to the array {\it files} (note that its old contents is preserved). Only files
+matching the {\it filespec} are taken, with empty spec matching all the files.
+
+The {\it flags} parameter should always include {\tt wxDIR\_FILES} or the array
+would be unchanged and should include {\tt wxDIR\_DIRS} flag to recurse into
+subdirectories (both flags are included in the value by default).
+
+See also: \helpref{Traverse}{wxdirtraverse}
+
+\section{\class{wxDirTraverser}}\label{wxdirtraverser}
+
+wxDirTraverser is an abstract interface which must be implemented by objects
+passed to \helpref{Traverse}{wxdirtraverse} function.
+
+Example of use (this works almost like \helpref{GetAllFiles}{wxdirgetallfiles}):
+
+\begin{verbatim}
+ class wxDirTraverserSimple : public wxDirTraverser
+ {
+ public:
+ wxDirTraverserSimple(wxArrayString& files) : m_files(files) { }
+
+ virtual wxDirTraverseResult OnFile(const wxString& filename)
+ {
+ m_files.Add(filename);
+ return wxDIR_CONTINUE;
+ }
+
+ virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname))
+ {
+ return wxDIR_CONTINUE;
+ }
+
+ private:
+ wxArrayString& m_files;
+ };
+
+ // get the names of all files in the array
+ wxArrayString files;
+ wxDirTraverserSimple traverser(files);
+
+ wxDir dir(dirname);
+ dir.Traverse(traverser);
+\end{verbatim}
+
+\wxheading{Derived from}
+
+No base class
+
+\wxheading{Constants}
+
+The elements of {\tt wxDirTraverseResult} are the possible return values of the
+callback functions:
+
+{\small
+\begin{verbatim}
+enum wxDirTraverseResult
+{
+ wxDIR_IGNORE = -1, // ignore this directory but continue with others
+ wxDIR_STOP, // stop traversing
+ wxDIR_CONTINUE // continue into this directory
+};
+\end{verbatim}
+
+\wxheading{Include files}
+
+
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+\membersection{wxDirTraverser::OnFile}{wxdirtraverseronfile}
+
+\func{virtual wxDirTraverseResult}{OnFile}{\param{const wxString& }{filename}}
+
+This function is called for each file. It may return {\tt wxDIR\_STOP} to abort
+traversing (for example, if the file being searched is found) or
+{\tt wxDIR\_CONTINUE} to proceed.
+
+\membersection{wxDirTraverser::OnDir}{wxdirtraverserondir}
+
+\func{virtual wxDirTraverseResult}{OnDir}{\param{const wxString& }{dirname}}
+
+This function is called for each directory. It may return {\tt wxSIR\_STOP}
+to abort traversing completely, {\tt wxDIR\_IGNORE} to skip this directory but
+continue with others or {\tt wxDIR\_CONTINUE} to enumerate all files and
+subdirectories in this directory.
+
diff --git a/include/wx/dir.h b/include/wx/dir.h
index f8b0b67f3c..de2563540b 100644
--- a/include/wx/dir.h
+++ b/include/wx/dir.h
@@ -37,6 +37,32 @@ enum
wxDIR_DEFAULT = wxDIR_FILES | wxDIR_DIRS | wxDIR_HIDDEN
};
+// these constants are possible return value of wxDirTraverser::OnDir()
+enum wxDirTraverseResult
+{
+ wxDIR_IGNORE = -1, // ignore this directory but continue with others
+ wxDIR_STOP, // stop traversing
+ wxDIR_CONTINUE // continue into this directory
+};
+
+// ----------------------------------------------------------------------------
+// wxDirTraverser: helper class for wxDir::Traverse()
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxDirTraverser
+{
+public:
+ // called for each file found by wxDir::Traverse()
+ //
+ // return wxDIR_STOP or wxDIR_CONTINUE from here
+ virtual wxDirTraverseResult OnFile(const wxString& filename) = 0;
+
+ // called for each directory found by wxDir::Traverse()
+ //
+ // return one of the enum elements defined above
+ virtual wxDirTraverseResult OnDir(const wxString& dirname) = 0;
+};
+
// ----------------------------------------------------------------------------
// wxDir: portable equivalent of {open/read/close}dir functions
// ----------------------------------------------------------------------------
@@ -65,6 +91,9 @@ public:
// returns TRUE if the directory was successfully opened
bool IsOpened() const;
+ // get the full name of the directory (without '/' at the end)
+ wxString GetName() const;
+
// file enumeration routines
// -------------------------
@@ -78,27 +107,19 @@ public:
// GetFirstNormal()
bool GetNext(wxString *filename) const;
- // TODO using scandir() when available later, emulating it otherwise
-#if 0
- // get all files in the directory into an array, return TRUE on success
+ // enumerate all files in this directory and its subdirectories
//
- // this function uses Select() function to select the files
- // unless the filespec is explicitly given and Compare() function to sort
- // them
- bool Read(wxArrayString& filenames,
- const wxString& filespec = wxEmptyString) const;
+ // return the number of files found
+ size_t Traverse(wxDirTraverser& sink,
+ const wxString& filespec = wxEmptyString,
+ int flags = wxDIR_DEFAULT) const;
-protected:
- // this function is called by Read() if filespec is not specified in
- // Read(): it should return TRUE if the file matches our selection
- // criteria and FALSE otherwise
- virtual bool Select(const wxChar* filename);
-
- // This function is called by Read() to sort the array: it should return
- // -1, 0 or +1 if the first file is less than, equal to or greater than
- // the second. The base class version does
- virtual int Compare(const wxChar *filename1, const wxChar *filename2);
-#endif // 0
+ // simplest version of Traverse(): get the names of all files under this
+ // directory into filenames array, return the number of files
+ static size_t GetAllFiles(const wxString& dirname,
+ wxArrayString *files,
+ const wxString& filespec = wxEmptyString,
+ int flags = wxDIR_DEFAULT);
private:
friend class WXDLLEXPORT wxDirData;
diff --git a/samples/console/console.cpp b/samples/console/console.cpp
index 12d8911e08..c89655a181 100644
--- a/samples/console/console.cpp
+++ b/samples/console/console.cpp
@@ -36,10 +36,10 @@
// what to test (in alphabetic order)?
//#define TEST_ARRAYS
-#define TEST_CHARSET
+//#define TEST_CHARSET
//#define TEST_CMDLINE
//#define TEST_DATETIME
-//#define TEST_DIR
+#define TEST_DIR
//#define TEST_DLLLOADER
//#define TEST_ENVIRON
//#define TEST_EXECUTE
@@ -206,6 +206,16 @@ static void ShowCmdLine(const wxCmdLineParser& parser)
#include
+#ifdef __UNIX__
+ static const wxChar *ROOTDIR = _T("/");
+ static const wxChar *TESTDIR = _T("/usr");
+#elif defined(__WXMSW__)
+ static const wxChar *ROOTDIR = _T("c:\\");
+ static const wxChar *TESTDIR = _T("d:\\");
+#else
+ #error "don't know where the root directory is"
+#endif
+
static void TestDirEnumHelper(wxDir& dir,
int flags = wxDIR_DEFAULT,
const wxString& filespec = wxEmptyString)
@@ -228,6 +238,8 @@ static void TestDirEnumHelper(wxDir& dir,
static void TestDirEnum()
{
+ puts("*** Testing wxDir::GetFirst/GetNext ***");
+
wxDir dir(wxGetCwd());
puts("Enumerating everything in current directory:");
@@ -248,13 +260,7 @@ static void TestDirEnum()
puts("Enumerating files including hidden in current directory:");
TestDirEnumHelper(dir, wxDIR_FILES | wxDIR_HIDDEN);
-#ifdef __UNIX__
- dir.Open("/");
-#elif defined(__WXMSW__)
- dir.Open("c:\\");
-#else
- #error "don't know where the root directory is"
-#endif
+ dir.Open(ROOTDIR);
puts("Enumerating everything in root directory:");
TestDirEnumHelper(dir, wxDIR_DEFAULT);
@@ -273,6 +279,55 @@ static void TestDirEnum()
TestDirEnumHelper(dirNo);
}
+class DirPrintTraverser : public wxDirTraverser
+{
+public:
+ virtual wxDirTraverseResult OnFile(const wxString& filename)
+ {
+ return wxDIR_CONTINUE;
+ }
+
+ virtual wxDirTraverseResult OnDir(const wxString& dirname)
+ {
+ wxString path, name, ext;
+ wxSplitPath(dirname, &path, &name, &ext);
+
+ if ( !ext.empty() )
+ name << _T('.') << ext;
+
+ wxString indent;
+ for ( const wxChar *p = path.c_str(); *p; p++ )
+ {
+ if ( wxIsPathSeparator(*p) )
+ indent += _T(" ");
+ }
+
+ printf("%s%s\n", indent.c_str(), name.c_str());
+
+ return wxDIR_CONTINUE;
+ }
+};
+
+static void TestDirTraverse()
+{
+ puts("*** Testing wxDir::Traverse() ***");
+
+ // enum all files
+ wxArrayString files;
+ size_t n = wxDir::GetAllFiles(TESTDIR, &files);
+ printf("There are %u files under '%s'\n", n, TESTDIR);
+ if ( n > 1 )
+ {
+ printf("First one is '%s'\n", files[0u]);
+ printf(" last one is '%s'\n", files[n - 1]);
+ }
+
+ // enum again with custom traverser
+ wxDir dir(TESTDIR);
+ DirPrintTraverser traverser;
+ dir.Traverse(traverser, _T(""), wxDIR_DIRS | wxDIR_HIDDEN);
+}
+
#endif // TEST_DIR
// ----------------------------------------------------------------------------
@@ -4601,7 +4656,9 @@ int main(int argc, char **argv)
#endif // TEST_ARRAYS
#ifdef TEST_DIR
- TestDirEnum();
+ if ( 0 )
+ TestDirEnum();
+ TestDirTraverse();
#endif // TEST_DIR
#ifdef TEST_DLLLOADER
diff --git a/src/common/dircmn.cpp b/src/common/dircmn.cpp
new file mode 100644
index 0000000000..c39290a58c
--- /dev/null
+++ b/src/common/dircmn.cpp
@@ -0,0 +1,162 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name: src/common/dircmn.cpp
+// Purpose: wxDir methods common to all implementations
+// Author: Vadim Zeitlin
+// Modified by:
+// Created: 19.05.01
+// RCS-ID: $Id$
+// Copyright: (c) 2001 Vadim Zeitlin
+// License: wxWindows license
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+/* this is done in platform-specific files
+#ifdef __GNUG__
+ #pragma implementation "dir.h"
+#endif
+*/
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/string.h"
+ #include "wx/log.h"
+ #include "wx/intl.h"
+#endif //WX_PRECOMP
+
+#include "wx/dir.h"
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxDir::Traverse()
+// ----------------------------------------------------------------------------
+
+size_t wxDir::Traverse(wxDirTraverser& sink,
+ const wxString& filespec,
+ int flags) const
+{
+ wxCHECK_MSG( IsOpened(), (size_t)-1,
+ _T("dir must be opened before traversing it") );
+
+ // the total number of files found
+ size_t nFiles = 0;
+
+ // the name of this dir with path delimiter at the end
+ wxString prefix = GetName();
+ prefix += wxFILE_SEP_PATH;
+
+ // first, recurse into subdirs
+ if ( flags & wxDIR_DIRS )
+ {
+ wxString dirname;
+ bool cont = GetFirst(&dirname, _T(""), wxDIR_DIRS | wxDIR_HIDDEN);
+ while ( cont )
+ {
+ wxDirTraverseResult res = sink.OnDir(prefix + dirname);
+
+ if ( res == wxDIR_STOP )
+ break;
+
+ if ( res == wxDIR_CONTINUE )
+ {
+ wxDir subdir(prefix + dirname);
+ if ( subdir.IsOpened() )
+ {
+ nFiles += subdir.Traverse(sink, filespec, flags);
+ }
+ }
+ else
+ {
+ wxASSERT_MSG( res == wxDIR_IGNORE,
+ _T("unexpected OnDir() return value") );
+ }
+
+ cont = GetNext(&dirname);
+ }
+ }
+
+ // now enum our own files
+ if ( flags & wxDIR_FILES )
+ {
+ flags &= ~wxDIR_DIRS;
+
+ wxString filename;
+ bool cont = GetFirst(&filename, filespec, flags);
+ while ( cont )
+ {
+ wxDirTraverseResult res = sink.OnFile(prefix + filename);
+ if ( res == wxDIR_STOP )
+ break;
+
+ wxASSERT_MSG( res == wxDIR_CONTINUE,
+ _T("unexpected OnFile() return value") );
+
+ nFiles++;
+
+ cont = GetNext(&filename);
+ }
+ }
+
+ return nFiles;
+}
+
+// ----------------------------------------------------------------------------
+// wxDir::GetAllFiles()
+// ----------------------------------------------------------------------------
+
+class wxDirTraverserSimple : public wxDirTraverser
+{
+public:
+ wxDirTraverserSimple(wxArrayString& files) : m_files(files) { }
+
+ virtual wxDirTraverseResult OnFile(const wxString& filename)
+ {
+ m_files.Add(filename);
+ return wxDIR_CONTINUE;
+ }
+
+ virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname))
+ {
+ return wxDIR_CONTINUE;
+ }
+
+private:
+ wxArrayString& m_files;
+};
+
+/* static */
+size_t wxDir::GetAllFiles(const wxString& dirname,
+ wxArrayString *files,
+ const wxString& filespec,
+ int flags)
+{
+ wxCHECK_MSG( files, (size_t)-1, _T("NULL pointer in wxDir::GetAllFiles") );
+
+ size_t nFiles = 0;
+
+ wxDir dir(dirname);
+ if ( dir.IsOpened() )
+ {
+ wxDirTraverserSimple traverser(*files);
+
+ nFiles += dir.Traverse(traverser, filespec, flags);
+ }
+
+ return nFiles;
+}
+
diff --git a/src/msw/dir.cpp b/src/msw/dir.cpp
index adfa2dd7e3..7d505e56bc 100644
--- a/src/msw/dir.cpp
+++ b/src/msw/dir.cpp
@@ -215,6 +215,8 @@ public:
void Rewind();
bool Read(wxString *filename);
+ const wxString& GetName() const { return m_dirname; }
+
private:
FIND_DATA m_finddata;
@@ -403,6 +405,28 @@ bool wxDir::IsOpened() const
return m_data != NULL;
}
+wxString wxDir::GetName() const
+{
+ wxString name;
+ if ( m_data )
+ {
+ name = M_DIR->GetName();
+ if ( !name.empty() )
+ {
+ // bring to canonical Windows form
+ name.Replace(_T("/"), _T("\\"));
+
+ if ( name.Last() == _T('\\') )
+ {
+ // chop off the last (back)slash
+ name.Truncate(name.length() - 1);
+ }
+ }
+ }
+
+ return name;
+}
+
wxDir::~wxDir()
{
delete M_DIR;
diff --git a/src/unix/dir.cpp b/src/unix/dir.cpp
index 121ccda391..13b8d2a68a 100644
--- a/src/unix/dir.cpp
+++ b/src/unix/dir.cpp
@@ -65,6 +65,8 @@ public:
void Rewind() { rewinddir(m_dir); }
bool Read(wxString *filename);
+ const wxString& GetName() const { return m_dirname; }
+
private:
DIR *m_dir;
@@ -228,6 +230,22 @@ bool wxDir::IsOpened() const
return m_data != NULL;
}
+wxString wxDir::GetName() const
+{
+ wxString name;
+ if ( m_data )
+ {
+ name = M_DIR->GetName();
+ if ( !name.empty() && (name.Last() == _T('/')) )
+ {
+ // chop off the last (back)slash
+ name.Truncate(name.length() - 1);
+ }
+ }
+
+ return name;
+}
+
wxDir::~wxDir()
{
delete M_DIR;