]> git.saurik.com Git - wxWidgets.git/commitdiff
adding mimetype patch, closes #12072
authorStefan Csomor <csomor@advancedconcepts.ch>
Mon, 21 Jun 2010 16:36:45 +0000 (16:36 +0000)
committerStefan Csomor <csomor@advancedconcepts.ch>
Mon, 21 Jun 2010 16:36:45 +0000 (16:36 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64671 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/osx/core/mimetype.h
include/wx/osx/icon.h
src/common/mimecmn.cpp
src/osx/carbon/icon.cpp
src/osx/core/mimetype.cpp

index 4255411162db002c0e6ec56c34014df2ac8bfd58..21e1b6440f64d4437eb5a2b24aff816f719ddb67 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
 // Name:        wx/osx/core/mimetype.h
-// Purpose:     classes and functions to manage MIME types
-// Author:      Vadim Zeitlin
+// Purpose:     Mac implementation for wx mime-related classes
+// Author:      Neil Perkins
 // Modified by:
-// Created:     23.09.98
+// Created:     2010-05-15
 // RCS-ID:      $Id: mimetype.h 54448 2008-07-01 09:28:08Z RR $
-// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
-// Licence:     wxWindows licence (part of wxExtra library)
+// Copyright:   (C) 2010 Neil Perkins
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 #ifndef _MIMETYPE_IMPL_H
 #define _MIMETYPE_IMPL_H
 
-#include "wx/mimetype.h"
+#include "wx/defs.h"
 
 #if wxUSE_MIMETYPE
 
-class wxMimeTypeCommands;
+#include "wx/mimetype.h"
+#include "wx/hashmap.h"
+#include "wx/iconloc.h"
 
-WX_DEFINE_ARRAY_PTR(wxMimeTypeCommands *, wxMimeCommandsArray);
 
-// this is the real wxMimeTypesManager for Unix
+// This class implements mime type functionality for Mac OS X using UTIs and Launch Services
+// Currently only the GetFileTypeFromXXXX public functions have been implemented
 class WXDLLIMPEXP_BASE wxMimeTypesManagerImpl
 {
 public:
-    // ctor and dtor
+
     wxMimeTypesManagerImpl();
     virtual ~wxMimeTypesManagerImpl();
 
-    // load all data into memory - done when it is needed for the first time
-    void Initialize(int mailcapStyles = wxMAILCAP_ALL,
-                    const wxString& extraDir = wxEmptyString);
-
-    // and delete the data here
+    // These functions are not needed on Mac OS X and have no-op implementations
+    void Initialize(int mailcapStyles = wxMAILCAP_STANDARD, const wxString& extraDir = wxEmptyString);
     void ClearData();
 
-    // implement containing class functions
+    // Functions to look up types by ext, mime or UTI
     wxFileType *GetFileTypeFromExtension(const wxString& ext);
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
+    wxFileType *GetFileTypeFromUti(const wxString& uti);
 
+    // These functions are only stubs on Mac OS X
     size_t EnumAllFileTypes(wxArrayString& mimetypes);
+    wxFileType *Associate(const wxFileTypeInfo& ftInfo);
+    bool Unassociate(wxFileType *ft);
 
-    void AddFallback(const wxFileTypeInfo& filetype);
+private:
 
-    // add information about the given mimetype
-    void AddMimeTypeInfo(const wxString& mimetype,
-                         const wxString& extensions,
-                         const wxString& description);
-    void AddMailcapInfo(const wxString& strType,
-                        const wxString& strOpenCmd,
-                        const wxString& strPrintCmd,
-                        const wxString& strTest,
-                        const wxString& strDesc);
+    // The work of querying the OS for type data is done in these two functions
+    void LoadTypeDataForUti(const wxString& uti);
+    void LoadDisplayDataForUti(const wxString& uti);
 
-    // add a new record to the user .mailcap/.mime.types files
-    wxFileType *Associate(const wxFileTypeInfo& ftInfo);
-    // remove association
-    bool Unassociate(wxFileType *ft);
+    // These functions are pass-throughs from wxFileTypeImpl
+    bool GetExtensions(const wxString& uti, wxArrayString& extensions);
+    bool GetMimeType(const wxString& uti, wxString *mimeType);
+    bool GetMimeTypes(const wxString& uti, wxArrayString& mimeTypes);
+    bool GetIcon(const wxString& uti, wxIconLocation *iconLoc);
+    bool GetDescription(const wxString& uti, wxString *desc);
+
+    // Structure to represent file types
+    typedef struct FileTypeData
+    {
+        wxArrayString extensions;
+        wxArrayString mimeTypes;
+        wxIconLocation iconLoc;
+        wxString description;
+    }
+    FileTypeInfo;
+
+    // Map types
+    WX_DECLARE_STRING_HASH_MAP( wxString, TagMap );
+    WX_DECLARE_STRING_HASH_MAP( FileTypeData, UtiMap );
 
-    // accessors
-        // get the string containing space separated extensions for the given
-        // file type
-    wxString GetExtension(size_t index) { return m_aExtensions[index]; }
-
-protected:
-    void InitIfNeeded();
-
-    wxArrayString m_aTypes,         // MIME types
-                  m_aDescriptions,  // descriptions (just some text)
-                  m_aExtensions,    // space separated list of extensions
-                  m_aIcons;         // Icon filenames
-
-    // verb=command pairs for this file type
-    wxMimeCommandsArray m_aEntries;
-
-    // are we initialized?
-    bool m_initialized;
-
-    wxString GetCommand(const wxString &verb, size_t nIndex) const;
-
-    // Read XDG *.desktop file
-    void LoadXDGApp(const wxString& filename);
-    // Scan XDG directory
-    void LoadXDGAppsFilesFromDir(const wxString& dirname);
-
-    // Load XDG globs files
-    void LoadXDGGlobs(const wxString& filename);
-
-    // functions used to do associations
-    virtual int AddToMimeData(const wxString& strType,
-                      const wxString& strIcon,
-                      wxMimeTypeCommands *entry,
-                      const wxArrayString& strExtensions,
-                      const wxString& strDesc,
-                      bool replaceExisting = true);
-    virtual bool DoAssociation(const wxString& strType,
-                       const wxString& strIcon,
-                       wxMimeTypeCommands *entry,
-                       const wxArrayString& strExtensions,
-                       const wxString& strDesc);
-
-    // give it access to m_aXXX variables
-    friend class WXDLLIMPEXP_FWD_BASE wxFileTypeImpl;
+    // Data store
+    TagMap m_extMap;
+    TagMap m_mimeMap;
+    UtiMap m_utiMap;
+
+    friend class wxFileTypeImpl;
 };
 
+
+// This class provides the interface between wxFileType and wxMimeTypesManagerImple for Mac OS X
+// Currently only extension, mimetype, description and icon information is available
+// All other methods have no-op implementation
 class WXDLLIMPEXP_BASE wxFileTypeImpl
 {
 public:
-    // initialization functions
-    // this is used to construct a list of mimetypes which match;
-    // if built with GetFileTypeFromMimetype index 0 has the exact match and
-    // index 1 the type / * match
-    // if built with GetFileTypeFromExtension, index 0 has the mimetype for
-    // the first extension found, index 1 for the second and so on
-
-    void Init(wxMimeTypesManagerImpl *manager, size_t index)
-        { m_manager = manager; m_index.Add(index); }
-
-    // accessors
-    bool GetExtensions(wxArrayString& extensions);
-    bool GetMimeType(wxString *mimeType) const
-        { *mimeType = m_manager->m_aTypes[m_index[0]]; return true; }
-    bool GetMimeTypes(wxArrayString& mimeTypes) const;
-    bool GetIcon(wxIconLocation *iconLoc) const;
-
-    bool GetDescription(wxString *desc) const
-        { *desc = m_manager->m_aDescriptions[m_index[0]]; return true; }
-
-    bool GetOpenCommand(wxString *openCmd,
-                        const wxFileType::MessageParameters& params) const
-    {
-        *openCmd = GetExpandedCommand(wxT("open"), params);
-        return (! openCmd -> IsEmpty() );
-    }
-
-    bool GetPrintCommand(wxString *printCmd,
-                         const wxFileType::MessageParameters& params) const
-    {
-        *printCmd = GetExpandedCommand(wxT("print"), params);
-        return (! printCmd -> IsEmpty() );
-    }
 
-        // return the number of commands defined for this file type, 0 if none
-    size_t GetAllCommands(wxArrayString *verbs, wxArrayString *commands,
-                          const wxFileType::MessageParameters& params) const;
+    wxFileTypeImpl();
+    virtual ~wxFileTypeImpl();
 
+    bool GetExtensions(wxArrayString& extensions) const ;
+    bool GetMimeType(wxString *mimeType) const ;
+    bool GetMimeTypes(wxArrayString& mimeTypes) const ;
+    bool GetIcon(wxIconLocation *iconLoc) const ;
+    bool GetDescription(wxString *desc) const ;
 
-    // remove the record for this file type
-    // probably a mistake to come here, use wxMimeTypesManager.Unassociate (ft) instead
-    bool Unassociate(wxFileType *ft)
-    {
-        return m_manager->Unassociate(ft);
-    }
-
-    // set an arbitrary command, ask confirmation if it already exists and
-    // overwriteprompt is TRUE
-    bool SetCommand(const wxString& cmd, const wxString& verb, bool overwriteprompt = true);
+    // These functions are only stubs on Mac OS X
+    bool GetOpenCommand(wxString *openCmd, const wxFileType::MessageParameters& params) const;
+    bool GetPrintCommand(wxString *printCmd, const wxFileType::MessageParameters& params) const;
+    size_t GetAllCommands(wxArrayString *verbs, wxArrayString *commands, const wxFileType::MessageParameters& params) const;
+    bool SetCommand(const wxString& cmd, const wxString& verb, bool overwriteprompt = TRUE);
     bool SetDefaultIcon(const wxString& strIcon = wxEmptyString, int index = 0);
+    bool Unassociate(wxFileType *ft);
 
 private:
-    wxString
-    GetExpandedCommand(const wxString & verb,
-                       const wxFileType::MessageParameters& params) const;
 
-    wxMimeTypesManagerImpl *m_manager;
-    wxArrayInt              m_index; // in the wxMimeTypesManagerImpl arrays
+    // All that is needed to query type info - UTI and pointer to the manager
+    wxString m_uti;
+    wxMimeTypesManagerImpl* m_manager;
+
+    friend class wxMimeTypesManagerImpl;
 };
 
 #endif // wxUSE_MIMETYPE
-
-#endif // _MIMETYPE_IMPL_H
+#endif //_MIMETYPE_IMPL_H
 
 
index 76113f712130ece3d612e0fe6dce3eaac1633ce5..1728e07ec5fa2012b1c3ea21c95f4b148e873722 100644 (file)
@@ -58,6 +58,11 @@ protected:
 
 private:
     DECLARE_DYNAMIC_CLASS(wxIcon)
+
+    bool LoadIconFromSystemResource(const wxString& resourceName, int desiredWidth, int desiredHeight);
+    bool LoadIconFromBundleResource(const wxString& resourceName, int desiredWidth, int desiredHeight);
+    bool LoadIconFromFile(const wxString& filename, int desiredWidth, int desiredHeight);
+    bool LoadIconAsBitmap(const wxString& filename, wxBitmapType flags = wxICON_DEFAULT_TYPE, int desiredWidth = -1, int desiredHeight = -1);
 };
 
 class WXDLLIMPEXP_CORE wxICONResourceHandler: public wxBitmapHandler
index 2171a14328abaa58d59d8ebf7dbaee48ffd87f2e..f159809a84b46db8c4e4fd9b235e2db690c98177 100644 (file)
@@ -48,7 +48,7 @@
 // implementation classes:
 #if defined(__WXMSW__)
     #include "wx/msw/mimetype.h"
-#elif ( defined(__WXMAC__) && wxOSX_USE_CARBON )
+#elif ( defined(__WXMAC__) )
     #include "wx/osx/mimetype.h"
 #elif defined(__WXPM__) || defined (__EMX__)
     #include "wx/os2/mimetype.h"
index fa46e150881ddfafede5f008ec0563eb7d53cc19..e156e55a183923bd09f34bd532ecb1781bede9b4 100644 (file)
@@ -167,178 +167,248 @@ void wxIcon::SetHeight( int WXUNUSED(height) )
 {
 }
 
+// Load an icon based on resource name or filel name
+// Return true on success, false otherwise
 bool wxIcon::LoadFile(
     const wxString& filename, wxBitmapType type,
     int desiredWidth, int desiredHeight )
+{
+    if( type == wxBITMAP_TYPE_ICON_RESOURCE )
+    {
+        if( LoadIconFromSystemResource( filename, desiredWidth, desiredHeight ) )
+            return true;
+        else
+            return LoadIconFromBundleResource( filename, desiredWidth, desiredHeight );
+    }
+    else  if( type == wxBITMAP_TYPE_ICON )
+    {
+        return LoadIconFromFile( filename, desiredWidth, desiredHeight );
+    }
+    else
+    {
+        return LoadIconAsBitmap( filename, type, desiredWidth, desiredHeight );
+    }
+}
+
+// Load a well known system icon by its wxWidgets identifier
+// Returns true on success, false otherwise
+bool wxIcon::LoadIconFromSystemResource(const wxString& resourceName, int desiredWidth, int desiredHeight)
 {
     UnRef();
 
-    if ( type == wxBITMAP_TYPE_ICON_RESOURCE )
+    OSType theId = 0 ;
+
+    if ( resourceName == wxT("wxICON_INFORMATION") )
+    {
+        theId = kAlertNoteIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_QUESTION") )
+    {
+        theId = kAlertCautionIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_WARNING") )
+    {
+        theId = kAlertCautionIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_ERROR") )
     {
-        OSType theId = 0 ;
+        theId = kAlertStopIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_FOLDER") )
+    {
+        theId = kGenericFolderIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_FOLDER_OPEN") )
+    {
+        theId = kOpenFolderIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_NORMAL_FILE") )
+    {
+        theId = kGenericDocumentIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_EXECUTABLE_FILE") )
+    {
+        theId = kGenericApplicationIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_CDROM") )
+    {
+        theId = kGenericCDROMIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_FLOPPY") )
+    {
+        theId = kGenericFloppyIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_HARDDISK") )
+    {
+        theId = kGenericHardDiskIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_REMOVABLE") )
+    {
+        theId = kGenericRemovableMediaIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_DELETE") )
+    {
+        theId = kToolbarDeleteIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_GO_BACK") )
+    {
+        theId = kBackwardArrowIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_GO_FORWARD") )
+    {
+        theId = kForwardArrowIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_GO_HOME") )
+    {
+        theId = kToolbarHomeIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_HELP_SETTINGS") )
+    {
+        theId = kGenericFontIcon ;
+    }
+    else if ( resourceName == wxT("wxICON_HELP_PAGE") )
+    {
+        theId = kGenericDocumentIcon ;
+    }
 
-        if ( filename == wxT("wxICON_INFORMATION") )
-        {
-            theId = kAlertNoteIcon ;
-        }
-        else if ( filename == wxT("wxICON_QUESTION") )
-        {
-            theId = kAlertCautionIcon ;
-        }
-        else if ( filename == wxT("wxICON_WARNING") )
-        {
-            theId = kAlertCautionIcon ;
-        }
-        else if ( filename == wxT("wxICON_ERROR") )
-        {
-            theId = kAlertStopIcon ;
-        }
-        else if ( filename == wxT("wxICON_FOLDER") )
-        {
-            theId = kGenericFolderIcon ;
-        }
-        else if ( filename == wxT("wxICON_FOLDER_OPEN") )
-        {
-            theId = kOpenFolderIcon ;
-        }
-        else if ( filename == wxT("wxICON_NORMAL_FILE") )
-        {
-            theId = kGenericDocumentIcon ;
-        }
-        else if ( filename == wxT("wxICON_EXECUTABLE_FILE") )
-        {
-            theId = kGenericApplicationIcon ;
-        }
-        else if ( filename == wxT("wxICON_CDROM") )
-        {
-            theId = kGenericCDROMIcon ;
-        }
-        else if ( filename == wxT("wxICON_FLOPPY") )
-        {
-            theId = kGenericFloppyIcon ;
-        }
-        else if ( filename == wxT("wxICON_HARDDISK") )
-        {
-            theId = kGenericHardDiskIcon ;
-        }
-        else if ( filename == wxT("wxICON_REMOVABLE") )
-        {
-            theId = kGenericRemovableMediaIcon ;
-        }
-        else if ( filename == wxT("wxICON_DELETE") )
-        {
-            theId = kToolbarDeleteIcon ;
-        }
-        else if ( filename == wxT("wxICON_GO_BACK") )
-        {
-            theId = kBackwardArrowIcon ;
-        }
-        else if ( filename == wxT("wxICON_GO_FORWARD") )
-        {
-            theId = kForwardArrowIcon ;
-        }
-        else if ( filename == wxT("wxICON_GO_HOME") )
-        {
-            theId = kToolbarHomeIcon ;
-        }
-        else if ( filename == wxT("wxICON_HELP_SETTINGS") )
-        {
-            theId = kGenericFontIcon ;
-        }
-        else if ( filename == wxT("wxICON_HELP_PAGE") )
+    if ( theId != 0 )
+    {
+        IconRef iconRef = NULL ;
+        verify_noerr( GetIconRef( kOnSystemDisk, kSystemIconsCreator, theId, &iconRef ) ) ;
+        if ( iconRef )
         {
-            theId = kGenericDocumentIcon ;
+            m_refData = new wxIconRefData( (WXHICON) iconRef, desiredWidth, desiredHeight ) ;
+            return true ;
         }
-        else
-        {
-            IconRef iconRef = NULL ;
+    }
 
-            // first look in the resource fork
-            if ( iconRef == NULL )
-            {
-                Str255 theName ;
-
-                wxMacStringToPascal( filename , theName ) ;
-                Handle resHandle = GetNamedResource( 'icns' , theName ) ;
-                if ( resHandle != 0L )
-                {
-                    IconFamilyHandle iconFamily = (IconFamilyHandle) resHandle ;
-                    HLock((Handle) iconFamily);
-                    OSStatus err = GetIconRefFromIconFamilyPtr( *iconFamily, GetHandleSize((Handle) iconFamily), &iconRef );
-                    HUnlock((Handle) iconFamily);
-                    if ( err != noErr )
-                    {
-                        wxFAIL_MSG("Error when constructing icon ref");
-                    }
-
-                    ReleaseResource( resHandle ) ;
-                }
-              }
-            if ( iconRef == NULL )
-            {
-                // TODO add other attempts to load it from files etc here
-            }
-               if ( iconRef )
-               {
-                   m_refData = new wxIconRefData( (WXHICON) iconRef, desiredWidth, desiredHeight ) ;
-                return true ;
-               }
-        }
+    return false;
+}
 
-        if ( theId != 0 )
+// Load an icon of type 'icns' by resource by name
+// The resource must exist in one of the currently accessible bundles
+// (usually this means the application bundle for the current application)
+// Return true on success, false otherwise
+bool wxIcon::LoadIconFromBundleResource(const wxString& resourceName, int desiredWidth, int desiredHeight)
+{
+    UnRef();
+
+    IconRef iconRef = NULL ;
+
+    // first look in the resource fork
+    if ( iconRef == NULL )
+    {
+        Str255 theName ;
+
+        wxMacStringToPascal( resourceName , theName ) ;
+        Handle resHandle = GetNamedResource( 'icns' , theName ) ;
+        if ( resHandle != 0L )
         {
-            IconRef iconRef = NULL ;
-            verify_noerr( GetIconRef( kOnSystemDisk, kSystemIconsCreator, theId, &iconRef ) ) ;
-            if ( iconRef )
-            {
-                m_refData = new wxIconRefData( (WXHICON) iconRef, desiredWidth, desiredHeight ) ;
+            IconFamilyHandle iconFamily = (IconFamilyHandle) resHandle ;
+            OSStatus err = GetIconRefFromIconFamilyPtr( *iconFamily, GetHandleSize((Handle) iconFamily), &iconRef );
 
-                return true ;
+            if ( err != noErr )
+            {
+                wxFAIL_MSG("Error when constructing icon ref");
             }
+
+            ReleaseResource( resHandle ) ;
         }
+    }
 
-        return false ;
+    if ( iconRef )
+    {
+        m_refData = new wxIconRefData( (WXHICON) iconRef, desiredWidth, desiredHeight );
+        return true;
     }
-    else
+
+   return false;
+}
+
+// Load an icon from an icon file using the underlying OS X API
+// The icon file must be in a format understood by the OS
+// Return true for success, false otherwise
+bool wxIcon::LoadIconFromFile(const wxString& filename, int desiredWidth, int desiredHeight)
+{
+    UnRef();
+
+    OSStatus err;
+    bool result = false;
+
+    // Get a file system reference
+    FSRef fsRef;
+    err = FSPathMakeRef( (const wxUint8*)filename.utf8_str().data(), &fsRef, NULL );
+
+    if( err != noErr )
+        return false;
+
+    // Get a handle on the icon family
+    IconFamilyHandle iconFamily;
+    err = ReadIconFromFSRef( &fsRef, &iconFamily );
+
+    if( err != noErr )
+        return false;
+
+    // Get the icon reference itself
+    IconRef iconRef;
+    err = GetIconRefFromIconFamilyPtr( *iconFamily, GetHandleSize((Handle) iconFamily), &iconRef );
+
+    if( err == noErr )
     {
-        wxBitmapHandler *handler = wxBitmap::FindHandler( type );
+        // If everthing is OK, assign m_refData
+        m_refData = new wxIconRefData( (WXHICON) iconRef, desiredWidth, desiredHeight );
+        result = true;
+    }
 
-        if ( handler )
-        {
-            wxBitmap bmp ;
-            if ( handler->LoadFile( &bmp , filename, type, desiredWidth, desiredHeight ))
-            {
-                CopyFromBitmap( bmp ) ;
+    // Release the iconFamily before returning
+    ReleaseResource( (Handle) iconFamily );
+    return result;
+}
 
-                return true ;
-            }
+// Load an icon from a file using functionality from wxWidgets
+// A suitable bitmap handler (or image handler) must be available
+// Return true on success, false otherwise
+bool wxIcon::LoadIconAsBitmap(const wxString& filename, wxBitmapType type, int desiredWidth, int desiredHeight)
+{
+    UnRef();
 
-            return false ;
-        }
-        else
+    wxBitmapHandler *handler = wxBitmap::FindHandler( type );
+
+    if ( handler )
+    {
+        wxBitmap bmp ;
+        if ( handler->LoadFile( &bmp , filename, type, desiredWidth, desiredHeight ))
         {
+            CopyFromBitmap( bmp ) ;
+            return true ;
+        }
+    }
+
 #if wxUSE_IMAGE
-            wxImage loadimage( filename, type );
-            if (loadimage.Ok())
-            {
-                if ( desiredWidth == -1 )
-                    desiredWidth = loadimage.GetWidth() ;
-                if ( desiredHeight == -1 )
-                    desiredHeight = loadimage.GetHeight() ;
-                if ( desiredWidth != loadimage.GetWidth() || desiredHeight != loadimage.GetHeight() )
-                    loadimage.Rescale( desiredWidth , desiredHeight ) ;
+    else
+    {
+        wxImage loadimage( filename, type );
+        if (loadimage.Ok())
+        {
+            if ( desiredWidth == -1 )
+                desiredWidth = loadimage.GetWidth() ;
+            if ( desiredHeight == -1 )
+                desiredHeight = loadimage.GetHeight() ;
+            if ( desiredWidth != loadimage.GetWidth() || desiredHeight != loadimage.GetHeight() )
+                loadimage.Rescale( desiredWidth , desiredHeight ) ;
 
-                wxBitmap bmp( loadimage );
-                CopyFromBitmap( bmp ) ;
+            wxBitmap bmp( loadimage );
+            CopyFromBitmap( bmp ) ;
 
-                return true;
-            }
-#endif
+            return true;
         }
     }
+#endif
+
     return false;
 }
 
+
 void wxIcon::CopyFromBitmap( const wxBitmap& bmp )
 {
     UnRef() ;
index 6bfd38a8b933aadf2f4d5268945cc2e24fe4db4a..f51c8565560f584c436b1c1d88a38a9c01c9ab1f 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
 // Name:        src/osx/core/mimetype.cpp
-// Purpose:     classes and functions to manage MIME types
-// Author:      Vadim Zeitlin, Stefan Csomor
+// Purpose:     Mac OS X implementation for wx MIME-related classes
+// Author:      Neil Perkins
 // Modified by:
-// Created:     23.09.98
+// Created:     2010-05-15
 // RCS-ID:      $Id: mimetype.cpp 54734 2008-07-21 01:33:51Z VZ $
-// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
-// Licence:     wxWindows licence (part of wxExtra library)
+// Copyright:   (C) 2010 Neil Perkins
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-// for compilers that support precompilation, includes "wx.h".
+
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-    #pragma hdrstop
+#pragma hdrstop
 #endif
 
-#if wxUSE_MIMETYPE && wxUSE_FILE
-
-#include "wx/unix/mimetype.h"
-
 #ifndef WX_PRECOMP
-    #include "wx/dynarray.h"
-    #include "wx/string.h"
-    #include "wx/intl.h"
-    #include "wx/log.h"
-    #include "wx/utils.h"
+#include "wx/defs.h"
 #endif
 
-#include "wx/file.h"
-#include "wx/confbase.h"
+#if wxUSE_MIMETYPE
 
-#include "wx/ffile.h"
-#include "wx/dir.h"
-#include "wx/tokenzr.h"
-#include "wx/iconloc.h"
-#include "wx/filename.h"
-#include "wx/app.h"
-#include "wx/apptrait.h"
+#include "wx/osx/mimetype.h"
+#include "wx/osx/private.h"
 
-// other standard headers
-#include <ctype.h>
+/////////////////////////////////////////////////////////////////////////////
+// Helper functions
+/////////////////////////////////////////////////////////////////////////////
 
-// ----------------------------------------------------------------------------
-// constants
-// ----------------------------------------------------------------------------
 
-// MIME code tracing mask
-#define TRACE_MIME wxT("mime")
+// Read a string or array of strings from a CFDictionary for a given key
+// Return an empty list on error
+wxArrayString ReadStringListFromCFDict( CFDictionaryRef dictionary, CFStringRef key )
+{
+    // Create an empty list
+    wxArrayString results;
 
-// ----------------------------------------------------------------------------
-// wxFileTypeImpl (Unix)
-// ----------------------------------------------------------------------------
+    // Look up the requested key
+    CFTypeRef valueData = CFDictionaryGetValue( dictionary, key );
 
-wxString wxFileTypeImpl::GetExpandedCommand(const wxString & verb, const wxFileType::MessageParameters& params) const
-{
-    wxString sTmp;
-    size_t i = 0;
-    while ( (i < m_index.GetCount() ) && sTmp.empty() )
+    if( valueData )
     {
-        sTmp = m_manager->GetCommand( verb, m_index[i] );
-        i++;
-    }
+        // Value is an array
+        if( CFGetTypeID( valueData ) == CFArrayGetTypeID() )
+        {
+            CFArrayRef valueList = reinterpret_cast< CFArrayRef >( valueData );
 
-    return wxFileType::ExpandCommand(sTmp, params);
-}
+            CFTypeRef itemData;
+            wxCFStringRef item;
 
-bool wxFileTypeImpl::GetIcon(wxIconLocation *iconLoc) const
-{
-    wxString sTmp;
-    size_t i = 0;
-    while ( (i < m_index.GetCount() ) && sTmp.empty() )
-    {
-        sTmp = m_manager->m_aIcons[m_index[i]];
-        i++;
-    }
+            // Look at each item in the array
+            for( CFIndex i = 0, n = CFArrayGetCount( valueList ); i < n; i++ )
+            {
+                itemData = CFArrayGetValueAtIndex( valueList, i );
 
-    if ( sTmp.empty() )
-        return false;
+                // Make sure the item is a string
+                if( CFGetTypeID( itemData ) == CFStringGetTypeID() )
+                {
+                    // wxCFStringRef will automatically CFRelease, so an extra CFRetain is needed
+                    item = reinterpret_cast< CFStringRef >( itemData );
+                    wxCFRetain( item.get() );
 
-    if ( iconLoc )
-    {
-        iconLoc->SetFileName(sTmp);
+                    // Add the string to the list
+                    results.Add( item.AsString() );
+                }
+            }
+        }
+
+        // Value is a single string - return a list of one item
+        else if( CFGetTypeID( valueData ) == CFStringGetTypeID() )
+        {
+            // wxCFStringRef will automatically CFRelease, so an extra CFRetain is needed
+            wxCFStringRef value = reinterpret_cast< CFStringRef >( valueData );
+            wxCFRetain( value.get() );
+
+            // Add the string to the list
+            results.Add( value.AsString() );
+        }
     }
 
-    return true;
+    // Return the list. If the dictionary did not contain key,
+    // or contained the wrong data type, the list will be empty
+    return results;
 }
 
-bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const
+
+// Given a single CFDictionary representing document type data, check whether
+// it matches a particular file extension. Return true for a match, false otherwise
+bool CheckDocTypeMatchesExt( CFDictionaryRef docType, CFStringRef requiredExt )
 {
-    mimeTypes.Clear();
-    size_t nCount = m_index.GetCount();
-    for (size_t i = 0; i < nCount; i++)
-        mimeTypes.Add(m_manager->m_aTypes[m_index[i]]);
+    const static wxCFStringRef extKey( "CFBundleTypeExtensions" );
 
-    return true;
-}
+    CFTypeRef extData = CFDictionaryGetValue( docType, extKey );
 
-size_t wxFileTypeImpl::GetAllCommands(wxArrayString *verbs,
-                                  wxArrayString *commands,
-                                  const wxFileType::MessageParameters& params) const
-{
-    wxString vrb, cmd, sTmp;
-    size_t count = 0;
-    wxMimeTypeCommands * sPairs;
+    if( !extData )
+        return false;
 
-    // verbs and commands have been cleared already in mimecmn.cpp...
-    // if we find no entries in the exact match, try the inexact match
-    for (size_t n = 0; ((count == 0) && (n < m_index.GetCount())); n++)
+    if( CFGetTypeID( extData ) == CFArrayGetTypeID() )
     {
-        // list of verb = command pairs for this mimetype
-        sPairs = m_manager->m_aEntries [m_index[n]];
-        size_t i;
-        for ( i = 0; i < sPairs->GetCount(); i++ )
+        CFArrayRef extList = reinterpret_cast< CFArrayRef >( extData );
+        CFTypeRef extItem;
+
+        for( CFIndex i = 0, n = CFArrayGetCount( extList ); i < n; i++ )
         {
-            vrb = sPairs->GetVerb(i);
-            // some gnome entries have "." inside
-            vrb = vrb.AfterLast(wxT('.'));
-            cmd = sPairs->GetCmd(i);
-            if (! cmd.empty() )
+            extItem = CFArrayGetValueAtIndex( extList, i );
+
+            if( CFGetTypeID( extItem ) == CFStringGetTypeID() )
             {
-                 cmd = wxFileType::ExpandCommand(cmd, params);
-                 count++;
-                 if ( vrb.IsSameAs(wxT("open")))
-                 {
-                     if ( verbs )
-                        verbs->Insert(vrb, 0u);
-                     if ( commands )
-                        commands ->Insert(cmd, 0u);
-                 }
-                 else
-                 {
-                     if ( verbs )
-                        verbs->Add(vrb);
-                     if ( commands )
-                        commands->Add(cmd);
-                 }
-             }
+                CFStringRef ext = reinterpret_cast< CFStringRef >( extItem );
+
+                if( CFStringCompare( ext, requiredExt, kCFCompareCaseInsensitive ) == kCFCompareEqualTo )
+                    return true;
+            }
         }
     }
 
-    return count;
+    if( CFGetTypeID( extData ) == CFStringGetTypeID() )
+    {
+        CFStringRef ext = reinterpret_cast< CFStringRef >( extData );
+
+        if( CFStringCompare( ext, requiredExt, kCFCompareCaseInsensitive ) == kCFCompareEqualTo )
+            return true;
+    }
+
+    return false;
 }
 
-bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
+
+// Given a data structure representing document type data, or a list of such
+// structures, find the one which matches a particular file extension
+// The result will be a CFDictionary containining document type data
+// if a match is found, or null otherwise
+CFDictionaryRef GetDocTypeForExt( CFTypeRef docTypeData, CFStringRef requiredExt )
 {
-    const wxString strExtensions = m_manager->GetExtension(m_index[0]);
-    extensions.Empty();
+    CFDictionaryRef docType;
+    CFArrayRef docTypes;
+    CFTypeRef item;
+
+    if( !docTypeData )
+        return NULL;
 
-    // one extension in the space or comma-delimited list
-    wxString strExt;
-    wxString::const_iterator end = strExtensions.end();
-    for ( wxString::const_iterator p = strExtensions.begin(); /* nothing */; ++p )
+    if( CFGetTypeID( docTypeData ) == CFArrayGetTypeID() )
     {
-        if ( p == end || *p == wxT(' ') || *p == wxT(',') )
-        {
-            if ( !strExt.empty() )
-            {
-                extensions.Add(strExt);
-                strExt.Empty();
-            }
-            //else: repeated spaces
-            // (shouldn't happen, but it's not that important if it does happen)
+        docTypes = reinterpret_cast< CFArrayRef >( docTypeData );
 
-            if ( p == end )
-                break;
-        }
-        else if ( *p == wxT('.') )
+        for( CFIndex i = 0, n = CFArrayGetCount( docTypes ); i < n; i++ )
         {
-            // remove the dot from extension (but only if it's the first char)
-            if ( !strExt.empty() )
+            item = CFArrayGetValueAtIndex( docTypes, i );
+
+            if( CFGetTypeID( item ) == CFDictionaryGetTypeID() )
             {
-                strExt += wxT('.');
+                docType = reinterpret_cast< CFDictionaryRef >( item );
+
+                if( CheckDocTypeMatchesExt( docType, requiredExt ) )
+                    return docType;
             }
-            //else: no, don't append it
-        }
-        else
-        {
-            strExt += *p;
         }
     }
 
-    return true;
+    if( CFGetTypeID( docTypeData ) == CFDictionaryGetTypeID() )
+    {
+        CFDictionaryRef docType = reinterpret_cast< CFDictionaryRef >( docTypeData );
+
+        if( CheckDocTypeMatchesExt( docType, requiredExt ) )
+            return docType;
+    }
+
+    return NULL;
 }
 
-// set an arbitrary command:
-// could adjust the code to ask confirmation if it already exists and
-// overwriteprompt is true, but this is currently ignored as *Associate* has
-// no overwrite prompt
-bool
-wxFileTypeImpl::SetCommand(const wxString& cmd,
-                           const wxString& verb,
-                           bool WXUNUSED(overwriteprompt))
+
+// Given an application bundle reference and the name of an icon file
+// which is a resource in that bundle, look up the full (posix style)
+// path to that icon. Returns the path, or an empty wxString on failure
+wxString GetPathForIconFile( CFBundleRef bundle, CFStringRef iconFile )
 {
-    wxArrayString strExtensions;
-    wxString strDesc, strIcon;
+    // If either parameter is NULL there is no hope of success
+    if( !bundle || !iconFile )
+        return wxEmptyString;
 
-    wxArrayString strTypes;
-    GetMimeTypes(strTypes);
-    if ( strTypes.IsEmpty() )
-        return false;
+    // Create a range object representing the whole string
+    CFRange wholeString;
+    wholeString.location = 0;
+    wholeString.length = CFStringGetLength( iconFile );
 
-    wxMimeTypeCommands *entry = new wxMimeTypeCommands();
-    entry->Add(verb + wxT("=")  + cmd + wxT(" %s "));
+    // Index of the period in the file name for iconFile
+    UniCharCount periodIndex;
 
-    bool ok = false;
-    size_t nCount = strTypes.GetCount();
-    for ( size_t i = 0; i < nCount; i++ )
+    // In order to locate the period delimiting the extension,
+    // iconFile must be represented as UniChar[]
     {
-        if ( m_manager->DoAssociation
-                        (
-                            strTypes[i],
-                            strIcon,
-                            entry,
-                            strExtensions,
-                            strDesc
-                        ) )
-        {
-            // DoAssociation() took ownership of entry, don't delete it below
-            ok = true;
-        }
-    }
+        // Allocate a buffer and copy in the iconFile string
+        UniChar* buffer = new UniChar[ wholeString.length ];
+        CFStringGetCharacters( iconFile, wholeString, buffer );
 
-    if ( !ok )
-        delete entry;
+        // Locate the period character
+        OSStatus status = LSGetExtensionInfo( wholeString.length, buffer, &periodIndex );
 
-    return ok;
-}
+        // Deallocate the buffer
+        delete buffer;
 
-// ignore index on the grounds that we only have one icon in a Unix file
-bool wxFileTypeImpl::SetDefaultIcon(const wxString& strIcon, int WXUNUSED(index))
-{
-    if (strIcon.empty())
-        return false;
+        // If the period could not be located it will not be possible to get the URL
+        if( status != noErr || periodIndex == kLSInvalidExtensionIndex )
+            return wxEmptyString;
+    }
 
-    wxArrayString strExtensions;
-    wxString strDesc;
+    // Range representing the name part of iconFile
+    CFRange iconNameRange;
+    iconNameRange.location = 0;
+    iconNameRange.length = periodIndex - 1;
 
-    wxArrayString strTypes;
-    GetMimeTypes(strTypes);
-    if ( strTypes.IsEmpty() )
-        return false;
+    // Range representing the extension part of iconFile
+    CFRange iconExtRange;
+    iconExtRange.location = periodIndex;
+    iconExtRange.length = wholeString.length - periodIndex;
 
-    wxMimeTypeCommands *entry = new wxMimeTypeCommands();
-    bool ok = false;
-    size_t nCount = strTypes.GetCount();
-    for ( size_t i = 0; i < nCount; i++ )
-    {
-        if ( m_manager->DoAssociation
-                        (
-                            strTypes[i],
-                            strIcon,
-                            entry,
-                            strExtensions,
-                            strDesc
-                        ) )
-        {
-            // we don't need to free entry now, DoAssociation() took ownership
-            // of it
-            ok = true;
-        }
-    }
+    // Get the name and extension strings
+    wxCFStringRef iconName = CFStringCreateWithSubstring( kCFAllocatorDefault, iconFile, iconNameRange );
+    wxCFStringRef iconExt = CFStringCreateWithSubstring( kCFAllocatorDefault, iconFile, iconExtRange );
+
+    // Now it is possible to query the URL for the icon as a resource
+    wxCFRef< CFURLRef > iconUrl = wxCFRef< CFURLRef >( CFBundleCopyResourceURL( bundle, iconName, iconExt, NULL ) );
 
-    if ( !ok )
-        delete entry;
+    if( !iconUrl.get() )
+        return wxEmptyString;
 
-    return ok;
+    // All being well, return the icon path
+    return wxCFStringRef( CFURLCopyFileSystemPath( iconUrl, kCFURLPOSIXPathStyle ) ).AsString();
 }
 
-// ----------------------------------------------------------------------------
-// wxMimeTypesManagerImpl (Unix)
-// ----------------------------------------------------------------------------
 
 wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
 {
-    m_initialized = false;
 }
 
-void wxMimeTypesManagerImpl::InitIfNeeded()
+wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl()
 {
-    if ( !m_initialized )
-    {
-        // set the flag first to prevent recursion
-        m_initialized = true;
+}
 
-        wxString wm = wxTheApp->GetTraits()->GetDesktopEnvironment();
 
-        if (wm == wxT("KDE"))
-            Initialize( wxMAILCAP_KDE  );
-        else if (wm == wxT("GNOME"))
-            Initialize( wxMAILCAP_GNOME );
-        else
-            Initialize();
-    }
-}
+/////////////////////////////////////////////////////////////////////////////
+// Init / shutdown functions
+//
+// The Launch Services / UTI API provides no helpful way of getting a list
+// of all registered types. Instead the API is focused arround looking up
+// information for a particular file type once you already have some
+// identifying piece of information. In order to get a list of registered
+// types it would first be necessary to get a list of all bundles exporting
+// type information (all application bundles may be sufficient) then look at
+// the Info.plist file for those bundles and store the type information. As
+// this would require trawling the hard disk when a wxWidgets program starts
+// up it was decided instead to load the information lazily.
+//
+// If this behaviour really messes up your app, please feel free to implement
+// the trawling approach (perhaps with a configure switch?). A good place to
+// start would be CFBundleCreateBundlesFromDirectory( NULL, "/Applications", "app" )
+/////////////////////////////////////////////////////////////////////////////
 
 
+void wxMimeTypesManagerImpl::Initialize(int WXUNUSED(mailcapStyles), const wxString& WXUNUSED(extraDir))
+{
+    // NO-OP
+}
 
-// read system and user mailcaps and other files
-void wxMimeTypesManagerImpl::Initialize(int WXUNUSED(mailcapStyles),
-                                        const wxString& WXUNUSED(sExtraDir))
+void wxMimeTypesManagerImpl::ClearData()
 {
-#ifdef __VMS
-    // XDG tables are never installed on OpenVMS
-    return;
-#endif
-#if 0
-    // Read MIME type - extension associations
-    LoadXDGGlobs( "/usr/share/mime/globs" );
-    LoadXDGGlobs( "/usr/local/share/mime/globs" );
-
-    // Load desktop files for XDG, and then override them with the defaults.
-    // We will override them one desktop file at a time, rather
-    // than one mime type at a time, but it should be a reasonable
-    // heuristic.
-    {
-        wxString xdgDataHome = wxGetenv("XDG_DATA_HOME");
-        if ( xdgDataHome.empty() )
-            xdgDataHome = wxGetHomeDir() + "/.local/share";
-        wxString xdgDataDirs = wxGetenv("XDG_DATA_DIRS");
-        if ( xdgDataDirs.empty() )
-        {
-            xdgDataDirs = "/usr/local/share:/usr/share";
-            if (mailcapStyles & wxMAILCAP_GNOME)
-                xdgDataDirs += ":/usr/share/gnome:/opt/gnome/share";
-            if (mailcapStyles & wxMAILCAP_KDE)
-                xdgDataDirs += ":/usr/share/kde3:/opt/kde3/share";
-        }
-        if ( !sExtraDir.empty() )
-        {
-           xdgDataDirs += ':';
-           xdgDataDirs += sExtraDir;
-        }
+    // NO-OP
+}
 
-        wxArrayString dirs;
-        wxStringTokenizer tokenizer(xdgDataDirs, ":");
-        while ( tokenizer.HasMoreTokens() )
-        {
-            wxString p = tokenizer.GetNextToken();
-            dirs.Add(p);
-        }
-        dirs.insert(dirs.begin(), xdgDataHome);
 
-        wxString defaultsList;
-        size_t i;
-        for (i = 0; i < dirs.GetCount(); i++)
-        {
-            wxString f = dirs[i];
-            if (f.Last() != '/') f += '/';
-            f += "applications/defaults.list";
-            if (wxFileExists(f))
-            {
-                defaultsList = f;
-                break;
-            }
-        }
+/////////////////////////////////////////////////////////////////////////////
+// Lookup functions
+//
+// Apple uses a number of different systems for file type information.
+// As of Spring 2010, these include:
+//
+// OS Types / OS Creators
+// File Extensions
+// Mime Types
+// Uniform Type Identifiers (UTI)
+//
+// This implementation of the type manager for Mac supports all except OS
+// Type / OS Creator codes, which have been deprecated for some time with
+// less and less support in recent versions of OS X.
+//
+// The UTI system is the internal system used by OS X, as such it offers a
+// one-to-one mapping with file types understood by Mac OS X and is the
+// easiest way to convert between type systems. However, UTI meta-data is
+// not stored with data files (as of OS X 10.6), instead the OS looks at
+// the file extension and uses this to determine the UTI. Simillarly, most
+// applications do not yet advertise the file types they can handle by UTI.
+//
+// The result is that no one typing system is suitable for all tasks. Further,
+// as there is not a one-to-one mapping between type systems for the
+// description of any given type, it follows that ambiguity cannot be precluded,
+// whichever system is taken to be the "master".
+//
+// In the implementation below I have used UTI as the master key for looking
+// up file types. Extensions and mime types are mapped to UTIs and the data
+// for each UTI contains a list of all associated extensions and mime types.
+// This has the advantage that unknown types will still be assigned a unique
+// ID, while using any other system as the master could result in conflicts
+// if there were no mime type assigned to an extension or vice versa. However
+// there is still plenty of room for ambiguity if two or more applications
+// are fighting over ownership of a particular type or group of types.
+//
+// If this proves to be serious issue it may be helpful to add some slightly
+// more cleve logic to the code so that the key used to look up a file type is
+// always first in the list in the resulting wxFileType object. I.e, if you
+// look up .mpeg3 the list you get back could be .mpeg3, mp3, .mpg3, while
+// looking up .mp3 would give .mp3, .mpg3, .mpeg3. The simplest way to do
+// this would probably to keep two separate sets of data, one for lookup
+// by extetnsion and one for lookup by mime type.
+//
+// One other point which may require consideration is handling of unrecognised
+// types. Using UTI these will be assigned a unique ID of dyn.xxx. This will
+// result in a wxFileType object being returned, although querying properties
+// on that object will fail. If it would be more helpful to return NULL in this
+// case a suitable check can be added.
+/////////////////////////////////////////////////////////////////////////////
 
-        // Load application files and associate them to corresponding mime types.
-        size_t nDirs = dirs.GetCount();
-        for (size_t nDir = 0; nDir < nDirs; nDir++)
-        {
-            wxString dirStr = dirs[nDir];
-            if (dirStr.Last() != '/') dirStr += '/';
-            dirStr += "applications";
-            LoadXDGAppsFilesFromDir(dirStr);
-        }
+// Look up a file type by extension
+// The extensions if mapped to a UTI
+// If the requested extension is not know the OS is querried and the results saved
+wxFileType *wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
+{
+    wxString uti;
 
-        if (!defaultsList.IsEmpty())
-        {
-            wxArrayString deskTopFilesSeen;
+    const TagMap::const_iterator extItr = m_extMap.find( ext );
 
-            wxMimeTextFile textfile(defaultsList);
-            if ( textfile.Open() )
-            {
-                int nIndex = textfile.pIndexOf( wxT("[Default Applications]") );
-                if (nIndex != wxNOT_FOUND)
-                {
-                    for (i = nIndex+1; i < textfile.GetLineCount(); i++)
-                    {
-                        if (textfile.GetLine(i).Find(wxT("=")) != wxNOT_FOUND)
-                        {
-                            wxString mimeType = textfile.GetVerb(i);
-                            wxString desktopFile = textfile.GetCmd(i);
-
-                            if (deskTopFilesSeen.Index(desktopFile) == wxNOT_FOUND)
-                            {
-                                deskTopFilesSeen.Add(desktopFile);
-                                size_t j;
-                                for (j = 0; j < dirs.GetCount(); j++)
-                                {
-                                    wxString desktopPath = dirs[j];
-                                    if (desktopPath.Last() != '/') desktopPath += '/';
-                                    desktopPath += "applications/";
-                                    desktopPath += desktopFile;
-
-                                    if (wxFileExists(desktopPath))
-                                        LoadXDGApp(desktopPath);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
+    if( extItr == m_extMap.end() )
+    {
+        wxCFStringRef utiRef = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, wxCFStringRef( ext ), NULL );
+        m_extMap[ ext ] = uti = utiRef.AsString();
     }
-#endif
+    else
+        uti = extItr->second;
+
+    return GetFileTypeFromUti( uti );
 }
 
-// clear data so you can read another group of WM files
-void wxMimeTypesManagerImpl::ClearData()
+// Look up a file type by mime type
+// The mime type is mapped to a UTI
+// If the requested extension is not know the OS is querried and the results saved
+wxFileType *wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
 {
-    m_aTypes.Clear();
-    m_aIcons.Clear();
-    m_aExtensions.Clear();
-    m_aDescriptions.Clear();
+    wxString uti;
 
-    WX_CLEAR_ARRAY(m_aEntries);
-    m_aEntries.Empty();
+    const TagMap::const_iterator mimeItr = m_mimeMap.find( mimeType );
+
+    if( mimeItr == m_mimeMap.end() )
+    {
+        wxCFStringRef utiRef = UTTypeCreatePreferredIdentifierForTag( kUTTagClassFilenameExtension, wxCFStringRef( mimeType ), NULL );
+        m_mimeMap[ mimeType ] = uti = utiRef.AsString();
+    }
+    else
+        uti = mimeItr->second;
+
+    return GetFileTypeFromUti( uti );
 }
 
-wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl()
+// Look up a file type by UTI
+// If the requested extension is not know the OS is querried and the results saved
+wxFileType *wxMimeTypesManagerImpl::GetFileTypeFromUti(const wxString& uti)
 {
-    ClearData();
+    UtiMap::const_iterator utiItr = m_utiMap.find( uti );
+
+    if( utiItr == m_utiMap.end() )
+    {
+        LoadTypeDataForUti( uti );
+        LoadDisplayDataForUti( uti );
+    }
+
+    wxFileType* const ft = new wxFileType;
+    ft->m_impl->m_uti = uti;
+    ft->m_impl->m_manager = this;
+
+    return ft;
 }
 
-wxFileType * wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& ftInfo)
-{
-    InitIfNeeded();
 
-    wxString strType = ftInfo.GetMimeType();
-    wxString strDesc = ftInfo.GetDescription();
-    wxString strIcon = ftInfo.GetIconFile();
+/////////////////////////////////////////////////////////////////////////////
+// Load functions
+//
+// These functions query the OS for information on a particular file type
+/////////////////////////////////////////////////////////////////////////////
 
-    wxMimeTypeCommands *entry = new wxMimeTypeCommands();
 
-    if ( ! ftInfo.GetOpenCommand().empty())
-        entry->Add(wxT("open=")  + ftInfo.GetOpenCommand() + wxT(" %s "));
-    if ( ! ftInfo.GetPrintCommand().empty())
-        entry->Add(wxT("print=") + ftInfo.GetPrintCommand() + wxT(" %s "));
+// Look up all extensions and mime types associated with a UTI
+void wxMimeTypesManagerImpl::LoadTypeDataForUti(const wxString& uti)
+{
+    // Keys in to the UTI declaration plist
+    const static wxCFStringRef tagsKey( "UTTypeTagSpecification" );
+    const static wxCFStringRef extKey( "public.filename-extension" );
+    const static wxCFStringRef mimeKey( "public.mime-type" );
 
-    // now find where these extensions are in the data store and remove them
-    wxArrayString sA_Exts = ftInfo.GetExtensions();
-    wxString sExt, sExtStore;
-    size_t i, nIndex;
-    size_t nExtCount = sA_Exts.GetCount();
-    for (i=0; i < nExtCount; i++)
-    {
-        sExt = sA_Exts.Item(i);
+    // Get the UTI as a CFString
+    wxCFStringRef utiRef( uti );
 
-        // clean up to just a space before and after
-        sExt.Trim().Trim(false);
-        sExt = wxT(' ') + sExt + wxT(' ');
-        size_t nCount = m_aExtensions.GetCount();
-        for (nIndex = 0; nIndex < nCount; nIndex++)
-        {
-            sExtStore = m_aExtensions.Item(nIndex);
-            if (sExtStore.Replace(sExt, wxT(" ") ) > 0)
-                m_aExtensions.Item(nIndex) = sExtStore;
-        }
-    }
+    // Get a copy of the UTI declaration
+    wxCFRef< CFDictionaryRef > utiDecl;
+    utiDecl = wxCFRef< CFDictionaryRef >( UTTypeCopyDeclaration( utiRef ) );
 
-    if ( !DoAssociation(strType, strIcon, entry, sA_Exts, strDesc) )
-        return NULL;
+    if( !utiDecl )
+        return;
 
-    return GetFileTypeFromMimeType(strType);
-}
+    // Get the tags spec (the section of a UTI declaration containing mappings to other type systems)
+    CFTypeRef tagsData = CFDictionaryGetValue( utiDecl, tagsKey );
 
-bool wxMimeTypesManagerImpl::DoAssociation(const wxString& strType,
-                                           const wxString& strIcon,
-                                           wxMimeTypeCommands *entry,
-                                           const wxArrayString& strExtensions,
-                                           const wxString& strDesc)
-{
-    int nIndex = AddToMimeData(strType, strIcon, entry, strExtensions, strDesc, true);
+    if( CFGetTypeID( tagsData ) != CFDictionaryGetTypeID() )
+        return;
 
-    if ( nIndex == wxNOT_FOUND )
-        return false;
+    CFDictionaryRef tags = reinterpret_cast< CFDictionaryRef >( tagsData );
 
-    return true;
+    // Read tags for extensions and mime types
+    m_utiMap[ uti ].extensions = ReadStringListFromCFDict( tags, extKey );
+    m_utiMap[ uti ].mimeTypes = ReadStringListFromCFDict( tags, mimeKey );
 }
 
-int wxMimeTypesManagerImpl::AddToMimeData(const wxString& strType,
-                                          const wxString& strIcon,
-                                          wxMimeTypeCommands *entry,
-                                          const wxArrayString& strExtensions,
-                                          const wxString& strDesc,
-                                          bool replaceExisting)
+
+// Look up the (locale) display name and icon file associated with a UTI
+void wxMimeTypesManagerImpl::LoadDisplayDataForUti(const wxString& uti)
 {
-    InitIfNeeded();
+    // Keys in to Info.plist
+    const static wxCFStringRef docTypesKey( "CFBundleDocumentTypes" );
+    const static wxCFStringRef descKey( "CFBundleTypeName" );
+    const static wxCFStringRef iconKey( "CFBundleTypeIconFile" );
 
-    // ensure mimetype is always lower case
-    wxString mimeType = strType.Lower();
+    // The call for finding the preferred application for a UTI is LSCopyDefaultRoleHandlerForContentType
+    // This returns an empty string on OS X 10.5
+    // Instead it is necessary to get the primary extension and use LSGetApplicationForInfo
+    wxCFStringRef ext = UTTypeCopyPreferredTagWithClass( wxCFStringRef( uti ), kUTTagClassFilenameExtension );
 
-    // is this a known MIME type?
-    int nIndex = m_aTypes.Index(mimeType);
-    if ( nIndex == wxNOT_FOUND )
-    {
-        // new file type
-        m_aTypes.Add(mimeType);
-        m_aIcons.Add(strIcon);
-        m_aEntries.Add(entry ? entry : new wxMimeTypeCommands);
+    // Look up the preferred application
+    CFURLRef appUrl;
+    OSStatus status = LSGetApplicationForInfo( kLSUnknownType, kLSUnknownCreator, ext, kLSRolesAll, NULL, &appUrl );
 
-        // change nIndex so we can use it below to add the extensions
-        m_aExtensions.Add(wxEmptyString);
-        nIndex = m_aExtensions.size() - 1;
+    if( status != noErr )
+        return;
 
-        m_aDescriptions.Add(strDesc);
-    }
-    else // yes, we already have it
-    {
-        if ( replaceExisting )
-        {
-            // if new description change it
-            if ( !strDesc.empty())
-                m_aDescriptions[nIndex] = strDesc;
+    // Create a bundle object for that application
+    wxCFRef< CFBundleRef > bundle;
+    bundle = wxCFRef< CFBundleRef >( CFBundleCreate( kCFAllocatorDefault, appUrl ) );
 
-            // if new icon change it
-            if ( !strIcon.empty())
-                m_aIcons[nIndex] = strIcon;
+    if( !bundle )
+        return;
 
-            if ( entry )
-            {
-                delete m_aEntries[nIndex];
-                m_aEntries[nIndex] = entry;
-            }
-        }
-        else // add data we don't already have ...
-        {
-            // if new description add only if none
-            if ( m_aDescriptions[nIndex].empty() )
-                m_aDescriptions[nIndex] = strDesc;
+    // Get a all the document type data in this bundle
+    CFTypeRef docTypeData;
+    docTypeData = CFBundleGetValueForInfoDictionaryKey( bundle, docTypesKey );
 
-            // if new icon and no existing icon
-            if ( m_aIcons[nIndex].empty() )
-                m_aIcons[nIndex] = strIcon;
+    if( !docTypeData )
+        return;
 
-            // add any new entries...
-            if ( entry )
-            {
-                wxMimeTypeCommands *entryOld = m_aEntries[nIndex];
+    // Find the document type entry that matches ext
+    CFDictionaryRef docType;
+    docType = GetDocTypeForExt( docTypeData, ext );
 
-                size_t count = entry->GetCount();
-                for ( size_t i = 0; i < count; i++ )
-                {
-                    const wxString& verb = entry->GetVerb(i);
-                    if ( !entryOld->HasVerb(verb) )
-                    {
-                        entryOld->AddOrReplaceVerb(verb, entry->GetCmd(i));
-                    }
-                }
+    if( !docType )
+        return;
 
-                // as we don't store it anywhere, it won't be deleted later as
-                // usual -- do it immediately instead
-                delete entry;
-            }
-        }
-    }
+    // Get the display name for docType
+    wxCFStringRef description = reinterpret_cast< CFStringRef >( CFDictionaryGetValue( docType, descKey ) );
+    wxCFRetain( description.get() );
+    m_utiMap[ uti ].description = description.AsString();
 
-    // always add the extensions to this mimetype
-    wxString& exts = m_aExtensions[nIndex];
+    // Get the icon path for docType
+    CFStringRef iconFile = reinterpret_cast< CFStringRef > ( CFDictionaryGetValue( docType, iconKey ) );
+    m_utiMap[ uti ].iconLoc.SetFileName( GetPathForIconFile( bundle, iconFile ) );
+}
 
-    // add all extensions we don't have yet
-    wxString ext;
-    size_t count = strExtensions.GetCount();
-    for ( size_t i = 0; i < count; i++ )
-    {
-        ext = strExtensions[i];
-        ext += wxT(' ');
 
-        if ( exts.Find(ext) == wxNOT_FOUND )
-        {
-            exts += ext;
-        }
-    }
 
-    // check data integrity
-    wxASSERT( m_aTypes.GetCount() == m_aEntries.GetCount() &&
-              m_aTypes.GetCount() == m_aExtensions.GetCount() &&
-              m_aTypes.GetCount() == m_aIcons.GetCount() &&
-              m_aTypes.GetCount() == m_aDescriptions.GetCount() );
+/////////////////////////////////////////////////////////////////////////////
+// The remaining functionality from the public interface of
+// wxMimeTypesManagerImpl is not implemented.
+//
+// Please see the note further up this file on Initialise/Clear to explain why
+// EnumAllFileTypes is not available.
+//
+// Some thought will be needed before implementing Associate / Unassociate
+// for OS X to ensure proper integration with the many file type and
+// association mechanisms already used by the OS. Leaving these methods as
+// NO-OP on OS X and asking client apps to put suitable entries in their
+// Info.plist files when building their OS X bundle may well be the
+// correct solution.
+/////////////////////////////////////////////////////////////////////////////
 
-    return nIndex;
+
+size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& WXUNUSED(mimetypes))
+{
+    return 0;
 }
 
-wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
+wxFileType *wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo& WXUNUSED(ftInfo))
 {
-    if (ext.empty() )
-        return NULL;
+    return 0;
+}
 
-    InitIfNeeded();
+bool wxMimeTypesManagerImpl::Unassociate(wxFileType *WXUNUSED(ft))
+{
+    return false;
+}
 
-    size_t count = m_aExtensions.GetCount();
-    for ( size_t n = 0; n < count; n++ )
-    {
-        wxStringTokenizer tk(m_aExtensions[n], wxT(' '));
 
-        while ( tk.HasMoreTokens() )
-        {
-            // consider extensions as not being case-sensitive
-            if ( tk.GetNextToken().IsSameAs(ext, false /* no case */) )
-            {
-                // found
-                wxFileType *fileType = new wxFileType;
-                fileType->m_impl->Init(this, n);
+/////////////////////////////////////////////////////////////////////////////
+// Getter methods
+//
+// These methods are private and should only ever be called by wxFileTypeImpl
+// after the required information has been loaded. It should not be possible
+// to get a wxFileTypeImpl for a UTI without information for that UTI being
+// querried, however it is possible that some information may not have been
+// found.
+/////////////////////////////////////////////////////////////////////////////
 
-                return fileType;
-            }
-        }
-    }
 
-    return NULL;
-}
 
-wxFileType * wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
+bool wxMimeTypesManagerImpl::GetExtensions(const wxString& uti, wxArrayString& extensions)
 {
-    InitIfNeeded();
+    const UtiMap::const_iterator itr = m_utiMap.find( uti );
 
-    wxFileType * fileType = NULL;
-    // mime types are not case-sensitive
-    wxString mimetype(mimeType);
-    mimetype.MakeLower();
-
-    // first look for an exact match
-    int index = m_aTypes.Index(mimetype);
-
-    if ( index != wxNOT_FOUND )
+    if( itr == m_utiMap.end() || itr->second.extensions.GetCount() < 1 )
     {
-        fileType = new wxFileType;
-        fileType->m_impl->Init(this, index);
+        extensions.Clear();
+        return false;
     }
 
-    // then try to find "text/*" as match for "text/plain" (for example)
-    // NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return
-    //     the whole string - ok.
+    extensions = itr->second.extensions;
+    return true;
+}
 
-    index = wxNOT_FOUND;
-    wxString strCategory = mimetype.BeforeFirst(wxT('/'));
+bool wxMimeTypesManagerImpl::GetMimeType(const wxString& uti, wxString *mimeType)
+{
+    const UtiMap::const_iterator itr = m_utiMap.find( uti );
 
-    size_t nCount = m_aTypes.GetCount();
-    for ( size_t n = 0; n < nCount; n++ )
+    if( itr == m_utiMap.end() || itr->second.mimeTypes.GetCount() < 1 )
     {
-        if ( (m_aTypes[n].BeforeFirst(wxT('/')) == strCategory ) &&
-                m_aTypes[n].AfterFirst(wxT('/')) == wxT("*") )
-        {
-            index = n;
-            break;
-        }
+        *mimeType = wxEmptyString;
+        return false;
     }
 
-    if ( index != wxNOT_FOUND )
+    *mimeType = itr->second.mimeTypes[ 0 ];
+    return true;
+}
+
+bool wxMimeTypesManagerImpl::GetMimeTypes(const wxString& uti, wxArrayString& mimeTypes)
+{
+    const UtiMap::const_iterator itr = m_utiMap.find( uti );
+
+    if( itr == m_utiMap.end() || itr->second.mimeTypes.GetCount() < 1 )
     {
-       // don't throw away fileType that was already found
-        if (!fileType)
-            fileType = new wxFileType;
-        fileType->m_impl->Init(this, index);
+        mimeTypes.Clear();
+        return false;
     }
 
-    return fileType;
+    mimeTypes = itr->second.mimeTypes;
+    return true;
 }
 
-wxString wxMimeTypesManagerImpl::GetCommand(const wxString & verb, size_t nIndex) const
+bool wxMimeTypesManagerImpl::GetIcon(const wxString& uti, wxIconLocation *iconLoc)
 {
-    wxString command, testcmd, sV, sTmp;
-    sV = verb + wxT("=");
-
-    // list of verb = command pairs for this mimetype
-    wxMimeTypeCommands * sPairs = m_aEntries [nIndex];
+    const UtiMap::const_iterator itr = m_utiMap.find( uti );
 
-    size_t i;
-    size_t nCount = sPairs->GetCount();
-    for ( i = 0; i < nCount; i++ )
+    if( itr == m_utiMap.end() || !itr->second.iconLoc.IsOk() )
     {
-        sTmp = sPairs->GetVerbCmd (i);
-        if ( sTmp.Contains(sV) )
-            command = sTmp.AfterFirst(wxT('='));
+        *iconLoc = wxIconLocation();
+        return false;
     }
 
-    return command;
+    *iconLoc = itr->second.iconLoc;
+    return true;
 }
 
-void wxMimeTypesManagerImpl::AddFallback(const wxFileTypeInfo& filetype)
+bool wxMimeTypesManagerImpl::GetDescription(const wxString& uti, wxString *desc)
 {
-    InitIfNeeded();
+    const UtiMap::const_iterator itr = m_utiMap.find( uti );
 
-    wxString extensions;
-    const wxArrayString& exts = filetype.GetExtensions();
-    size_t nExts = exts.GetCount();
-    for ( size_t nExt = 0; nExt < nExts; nExt++ )
+    if( itr == m_utiMap.end() || itr->second.description.IsNull() )
     {
-        if ( nExt > 0 )
-            extensions += wxT(' ');
-
-        extensions += exts[nExt];
+        *desc = wxEmptyString;
+        return false;
     }
 
-    AddMimeTypeInfo(filetype.GetMimeType(),
-                    extensions,
-                    filetype.GetDescription());
+    *desc = itr->second.description;
+    return true;
 }
 
-void wxMimeTypesManagerImpl::AddMimeTypeInfo(const wxString& strMimeType,
-                                             const wxString& strExtensions,
-                                             const wxString& strDesc)
+
+/////////////////////////////////////////////////////////////////////////////
+// The remaining functionality has not yet been implemented for OS X
+/////////////////////////////////////////////////////////////////////////////
+
+wxFileTypeImpl::wxFileTypeImpl() 
 {
-    // reading mailcap may find image/* , while
-    // reading mime.types finds image/gif and no match is made
-    // this means all the get functions don't work  fix this
-    wxString strIcon;
-    wxString sTmp = strExtensions;
+}
 
-    wxArrayString sExts;
-    sTmp.Trim().Trim(false);
+wxFileTypeImpl::~wxFileTypeImpl() 
+{
+}
 
-    while (!sTmp.empty())
-    {
-        sExts.Add(sTmp.AfterLast(wxT(' ')));
-        sTmp = sTmp.BeforeLast(wxT(' '));
-    }
+// Query wxMimeTypesManagerImple to get real information for a file type
+bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions) const 
+{ 
+    return m_manager->GetExtensions( m_uti, extensions ); 
+}
 
-    AddToMimeData(strMimeType, strIcon, NULL, sExts, strDesc, true);
+bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const 
+{ 
+    return m_manager->GetMimeType( m_uti, mimeType ); 
 }
 
-size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
-{
-    InitIfNeeded();
+bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const 
+{ 
+    return m_manager->GetMimeTypes( m_uti, mimeTypes ); 
+}
 
-    mimetypes.Empty();
+bool wxFileTypeImpl::GetIcon(wxIconLocation *iconLoc) const 
+{ 
+    return m_manager->GetIcon( m_uti, iconLoc ); 
+}
 
-    size_t count = m_aTypes.GetCount();
-    for ( size_t n = 0; n < count; n++ )
-    {
-        // don't return template types from here (i.e. anything containg '*')
-        const wxString &type = m_aTypes[n];
-        if ( type.Find(wxT('*')) == wxNOT_FOUND )
-        {
-            mimetypes.Add(type);
-        }
-    }
+bool wxFileTypeImpl::GetDescription(wxString *desc) const 
+{ 
+    return m_manager->GetDescription( m_uti, desc ); 
+}
 
-    return mimetypes.GetCount();
+bool wxFileTypeImpl::GetOpenCommand(wxString *WXUNUSED(openCmd), const wxFileType::MessageParameters& WXUNUSED(params)) const
+{
+    return false;
 }
 
-// ----------------------------------------------------------------------------
-// writing to MIME type files
-// ----------------------------------------------------------------------------
+bool wxFileTypeImpl::GetPrintCommand(wxString *WXUNUSED(printCmd), const wxFileType::MessageParameters& WXUNUSED(params)) const
+{
+    return false;
+}
 
-bool wxMimeTypesManagerImpl::Unassociate(wxFileType *ft)
+size_t wxFileTypeImpl::GetAllCommands(wxArrayString *WXUNUSED(verbs), wxArrayString *WXUNUSED(commands), const wxFileType::MessageParameters& WXUNUSED(params)) const
 {
-    InitIfNeeded();
+    return false;
+}
 
-    wxArrayString sMimeTypes;
-    ft->GetMimeTypes(sMimeTypes);
+bool wxFileTypeImpl::SetCommand(const wxString& WXUNUSED(cmd), const wxString& WXUNUSED(verb), bool WXUNUSED(overwriteprompt))
+{
+    return false;
+}
 
-    size_t i;
-    size_t nCount = sMimeTypes.GetCount();
-    for (i = 0; i < nCount; i ++)
-    {
-        const wxString &sMime = sMimeTypes.Item(i);
-        int nIndex = m_aTypes.Index(sMime);
-        if ( nIndex == wxNOT_FOUND)
-        {
-            // error if we get here ??
-            return false;
-        }
-        else
-        {
-            m_aTypes.RemoveAt(nIndex);
-            m_aEntries.RemoveAt(nIndex);
-            m_aExtensions.RemoveAt(nIndex);
-            m_aDescriptions.RemoveAt(nIndex);
-            m_aIcons.RemoveAt(nIndex);
-        }
-    }
-    // check data integrity
-    wxASSERT( m_aTypes.GetCount() == m_aEntries.GetCount() &&
-            m_aTypes.GetCount() == m_aExtensions.GetCount() &&
-            m_aTypes.GetCount() == m_aIcons.GetCount() &&
-            m_aTypes.GetCount() == m_aDescriptions.GetCount() );
+bool wxFileTypeImpl::SetDefaultIcon(const wxString& WXUNUSED(strIcon), int WXUNUSED(index))
+{
+    return false;
+}
 
-    return true;
+bool wxFileTypeImpl::Unassociate(wxFileType *WXUNUSED(ft))
+{
+    return false;
 }
 
-#endif
-  // wxUSE_MIMETYPE && wxUSE_FILE
+
+#endif // wxUSE_MIMETYPE
+
+