]> git.saurik.com Git - wxWidgets.git/commitdiff
added wxDir::Traverse
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 19 May 2001 00:58:05 +0000 (00:58 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 19 May 2001 00:58:05 +0000 (00:58 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@10226 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

distrib/msw/tmake/filelist.txt
docs/changes.txt
docs/latex/wx/dir.tex
include/wx/dir.h
samples/console/console.cpp
src/common/dircmn.cpp [new file with mode: 0644]
src/msw/dir.cpp
src/unix/dir.cpp

index 054fa153c4488ee8fa69fa5cb7e16d32902af23c..d4013fd5de9c409800859b6055453e7286f574aa 100644 (file)
@@ -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
index 7a975621d6e5856e8f78595cd1bfb0b394724e64..15f9740580d25de94c9e13ed81f77e8793a199b4 100644 (file)
@@ -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 <meta> tag
index 3b1e5b7e258f4abaab35b89e912d46606432a739..4c06f3bce3ff735b633e1bb78f0e4d4d33e91b7b 100644 (file)
@@ -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}
+
+<wx/dir.h>
+
+\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.
+
index f8b0b67f3cab965649516fa63134dc647edb78b6..de2563540be0218fbbc8a55f12c91d32a8830bed 100644 (file)
@@ -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;
-
-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
+    // return the number of files found
+    size_t Traverse(wxDirTraverser& sink,
+                    const wxString& filespec = wxEmptyString,
+                    int flags = wxDIR_DEFAULT) const;
+
+    // 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;
index 12d8911e08e4fcf2c0d7737b89b17d6e0c55df56..c89655a18106bc7d4347cf18dfec55036b82bdb9 100644 (file)
 // 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 <wx/dir.h>
 
+#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 (file)
index 0000000..c39290a
--- /dev/null
@@ -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 <zeitlin@dptmaths.ens-cachan.fr>
+// 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;
+}
+
index adfa2dd7e31284b383d42e536a6033e79bb1b7e3..7d505e56bc4531ca9b987010aac9bbf220f2059a 100644 (file)
@@ -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;
index 121ccda391e7eaa01dc6da2373e7047c601ee6f0..13b8d2a68a05becc2630de91a4735e7783d0913e 100644 (file)
@@ -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;