/////////////////////////////////////////////////////////////////////////////
// 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
{
}
+// 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() ;
/////////////////////////////////////////////////////////////////////////////
// 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
+
+