1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/mimetype.cpp
3 // Purpose: classes and functions to manage MIME types
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence: wxWindows licence (part of wxExtra library)
9 /////////////////////////////////////////////////////////////////////////////
11 // for compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_MIMETYPE && wxUSE_FILE
20 #include "wx/unix/mimetype.h"
23 #include "wx/dynarray.h"
24 #include "wx/string.h"
31 #include "wx/confbase.h"
35 #include "wx/tokenzr.h"
36 #include "wx/iconloc.h"
37 #include "wx/filename.h"
39 #include "wx/apptrait.h"
41 // other standard headers
51 wxMimeTextFile(const wxString
& fname
)
58 wxFFile
file( m_fname
);
62 size_t size
= file
.Length();
63 wxCharBuffer
buffer( size
);
64 file
.Read( (void*) (const char*) buffer
, size
);
66 // Check for valid UTF-8 here?
67 wxString all
= wxString::FromUTF8( buffer
, size
);
69 wxStringTokenizer
tok( all
, "\n" );
70 while (tok
.HasMoreTokens())
72 wxString t
= tok
.GetNextToken();
74 if ((!!t
) && (t
.Find( "comment" ) != 0) && (t
.Find( "#" ) != 0) && (t
.Find( "generic" ) != 0))
80 unsigned int GetLineCount() const { return m_text
.GetCount(); }
81 wxString
&GetLine( unsigned int line
) { return m_text
[line
]; }
83 int pIndexOf(const wxString
& sSearch
,
84 bool bIncludeComments
= false,
87 wxString sTest
= sSearch
;
89 for(size_t i
= iStart
; i
< GetLineCount(); i
++)
91 wxString sLine
= GetLine(i
);
92 if(bIncludeComments
|| ! sLine
.StartsWith(wxT("#")))
94 if(sLine
.StartsWith(sTest
))
101 wxString
GetVerb(size_t i
)
103 if (i
> GetLineCount() )
104 return wxEmptyString
;
106 wxString sTmp
= GetLine(i
).BeforeFirst(wxT('='));
110 wxString
GetCmd(size_t i
)
112 if (i
> GetLineCount() )
113 return wxEmptyString
;
115 wxString sTmp
= GetLine(i
).AfterFirst(wxT('='));
120 wxArrayString m_text
;
124 // ----------------------------------------------------------------------------
126 // ----------------------------------------------------------------------------
128 // MIME code tracing mask
129 #define TRACE_MIME wxT("mime")
132 // Read a XDG *.desktop file of type 'Application'
133 void wxMimeTypesManagerImpl::LoadXDGApp(const wxString
& filename
)
135 wxLogTrace(TRACE_MIME
, wxT("loading XDG file %s"), filename
.c_str());
137 wxMimeTextFile
file(filename
);
141 // Here, only type 'Application' should be considered.
142 int nIndex
= file
.pIndexOf( "Type=" );
143 if (nIndex
!= wxNOT_FOUND
&& file
.GetCmd(nIndex
) != "application")
146 // The hidden entry specifies a file to be ignored.
147 nIndex
= file
.pIndexOf( "Hidden=" );
148 if (nIndex
!= wxNOT_FOUND
&& file
.GetCmd(nIndex
) == "true")
151 // Semicolon separated list of mime types handled by the application.
152 nIndex
= file
.pIndexOf( wxT("MimeType=") );
153 if (nIndex
== wxNOT_FOUND
)
155 wxString mimetypes
= file
.GetCmd (nIndex
);
157 // Name of the application
159 nIndex
= wxNOT_FOUND
;
160 #if wxUSE_INTL // try "Name[locale name]" first
161 wxLocale
*locale
= wxGetLocale();
163 nIndex
= file
.pIndexOf(wxT("Name[")+locale
->GetName()+wxT("]="));
165 if(nIndex
== wxNOT_FOUND
)
166 nIndex
= file
.pIndexOf( wxT("Name=") );
167 if(nIndex
!= wxNOT_FOUND
)
168 nameapp
= file
.GetCmd(nIndex
);
170 // Icon of the application.
171 wxString nameicon
, namemini
;
172 nIndex
= wxNOT_FOUND
;
173 #if wxUSE_INTL // try "Icon[locale name]" first
175 nIndex
= file
.pIndexOf(wxT("Icon[")+locale
->GetName()+wxT("]="));
177 if(nIndex
== wxNOT_FOUND
)
178 nIndex
= file
.pIndexOf( wxT("Icon=") );
179 if(nIndex
!= wxNOT_FOUND
) {
180 nameicon
= wxString(wxT("--icon ")) + file
.GetCmd(nIndex
);
181 namemini
= wxString(wxT("--miniicon ")) + file
.GetCmd(nIndex
);
184 // Replace some of the field code in the 'Exec' entry.
185 // TODO: deal with %d, %D, %n, %N, %k and %v (but last one is deprecated)
186 nIndex
= file
.pIndexOf( wxT("Exec=") );
187 if (nIndex
== wxNOT_FOUND
)
189 wxString sCmd
= file
.GetCmd(nIndex
);
190 // we expect %f; others including %F and %U and %u are possible
191 sCmd
.Replace(wxT("%F"), wxT("%f"));
192 sCmd
.Replace(wxT("%U"), wxT("%f"));
193 sCmd
.Replace(wxT("%u"), wxT("%f"));
194 if (0 == sCmd
.Replace ( wxT("%f"), wxT("%s") ))
195 sCmd
= sCmd
+ wxT(" %s");
196 sCmd
.Replace(wxT("%c"), nameapp
);
197 sCmd
.Replace(wxT("%i"), nameicon
);
198 sCmd
.Replace(wxT("%m"), namemini
);
200 wxStringTokenizer
tokenizer(mimetypes
, wxT(";"));
201 while(tokenizer
.HasMoreTokens()) {
202 wxString mimetype
= tokenizer
.GetNextToken().Lower();
203 nIndex
= m_aTypes
.Index(mimetype
);
204 if(nIndex
!= wxNOT_FOUND
) { // is this a known MIME type?
205 wxMimeTypeCommands
* entry
= m_aEntries
[nIndex
];
206 entry
->AddOrReplaceVerb(wxT("open"), sCmd
);
211 void wxMimeTypesManagerImpl::LoadXDGAppsFilesFromDir(const wxString
& dirname
)
213 // Don't complain if we don't have permissions to read - it confuses users
216 if(! wxDir::Exists(dirname
))
219 if ( !dir
.IsOpened() )
223 // Look into .desktop files
224 bool cont
= dir
.GetFirst(&filename
, wxT("*.desktop"), wxDIR_FILES
);
227 wxFileName
p(dirname
, filename
);
228 LoadXDGApp( p
.GetFullPath() );
229 cont
= dir
.GetNext(&filename
);
233 // RR: I'm not sure this makes any sense. On my system we'll just
234 // scan the YAST2 and other useless directories
236 // Look recursively into subdirs
237 cont
= dir
.GetFirst(&filename
, wxEmptyString
, wxDIR_DIRS
);
240 wxFileName
p(dirname
, wxEmptyString
);
241 p
.AppendDir(filename
);
242 LoadXDGAppsFilesFromDir( p
.GetPath() );
243 cont
= dir
.GetNext(&filename
);
249 void wxMimeTypesManagerImpl::LoadXDGGlobs(const wxString
& filename
)
251 if ( !wxFileName::FileExists(filename
) )
254 wxLogTrace(TRACE_MIME
, wxT("loading XDG globs file from %s"), filename
.c_str());
256 wxMimeTextFile
file(filename
);
261 for (i
= 0; i
< file
.GetLineCount(); i
++)
263 wxStringTokenizer
tok( file
.GetLine(i
), ":" );
264 wxString mime
= tok
.GetNextToken();
265 wxString ext
= tok
.GetNextToken();
270 AddToMimeData(mime
, wxEmptyString
, NULL
, exts
, wxEmptyString
, true );
274 // ----------------------------------------------------------------------------
275 // wxFileTypeImpl (Unix)
276 // ----------------------------------------------------------------------------
278 wxString
wxFileTypeImpl::GetExpandedCommand(const wxString
& verb
, const wxFileType::MessageParameters
& params
) const
282 while ( (i
< m_index
.GetCount() ) && sTmp
.empty() )
284 sTmp
= m_manager
->GetCommand( verb
, m_index
[i
] );
288 return wxFileType::ExpandCommand(sTmp
, params
);
291 bool wxFileTypeImpl::GetIcon(wxIconLocation
*iconLoc
) const
295 while ( (i
< m_index
.GetCount() ) && sTmp
.empty() )
297 sTmp
= m_manager
->m_aIcons
[m_index
[i
]];
306 iconLoc
->SetFileName(sTmp
);
312 bool wxFileTypeImpl::GetMimeTypes(wxArrayString
& mimeTypes
) const
315 size_t nCount
= m_index
.GetCount();
316 for (size_t i
= 0; i
< nCount
; i
++)
317 mimeTypes
.Add(m_manager
->m_aTypes
[m_index
[i
]]);
322 size_t wxFileTypeImpl::GetAllCommands(wxArrayString
*verbs
,
323 wxArrayString
*commands
,
324 const wxFileType::MessageParameters
& params
) const
326 wxString vrb
, cmd
, sTmp
;
328 wxMimeTypeCommands
* sPairs
;
330 // verbs and commands have been cleared already in mimecmn.cpp...
331 // if we find no entries in the exact match, try the inexact match
332 for (size_t n
= 0; ((count
== 0) && (n
< m_index
.GetCount())); n
++)
334 // list of verb = command pairs for this mimetype
335 sPairs
= m_manager
->m_aEntries
[m_index
[n
]];
337 for ( i
= 0; i
< sPairs
->GetCount(); i
++ )
339 vrb
= sPairs
->GetVerb(i
);
340 // some gnome entries have "." inside
341 vrb
= vrb
.AfterLast(wxT('.'));
342 cmd
= sPairs
->GetCmd(i
);
345 cmd
= wxFileType::ExpandCommand(cmd
, params
);
347 if ( vrb
.IsSameAs(wxT("open")))
350 verbs
->Insert(vrb
, 0u);
352 commands
->Insert(cmd
, 0u);
368 bool wxFileTypeImpl::GetExtensions(wxArrayString
& extensions
)
370 const wxString strExtensions
= m_manager
->GetExtension(m_index
[0]);
373 // one extension in the space or comma-delimited list
375 wxString::const_iterator end
= strExtensions
.end();
376 for ( wxString::const_iterator p
= strExtensions
.begin(); /* nothing */; ++p
)
378 if ( p
== end
|| *p
== wxT(' ') || *p
== wxT(',') )
380 if ( !strExt
.empty() )
382 extensions
.Add(strExt
);
385 //else: repeated spaces
386 // (shouldn't happen, but it's not that important if it does happen)
391 else if ( *p
== wxT('.') )
393 // remove the dot from extension (but only if it's the first char)
394 if ( !strExt
.empty() )
398 //else: no, don't append it
409 // set an arbitrary command:
410 // could adjust the code to ask confirmation if it already exists and
411 // overwriteprompt is true, but this is currently ignored as *Associate* has
412 // no overwrite prompt
414 wxFileTypeImpl::SetCommand(const wxString
& cmd
,
415 const wxString
& verb
,
416 bool WXUNUSED(overwriteprompt
))
418 wxArrayString strExtensions
;
419 wxString strDesc
, strIcon
;
421 wxArrayString strTypes
;
422 GetMimeTypes(strTypes
);
423 if ( strTypes
.IsEmpty() )
426 wxMimeTypeCommands
*entry
= new wxMimeTypeCommands();
427 entry
->Add(verb
+ wxT("=") + cmd
+ wxT(" %s "));
430 size_t nCount
= strTypes
.GetCount();
431 for ( size_t i
= 0; i
< nCount
; i
++ )
433 if ( m_manager
->DoAssociation
442 // DoAssociation() took ownership of entry, don't delete it below
453 // ignore index on the grounds that we only have one icon in a Unix file
454 bool wxFileTypeImpl::SetDefaultIcon(const wxString
& strIcon
, int WXUNUSED(index
))
459 wxArrayString strExtensions
;
462 wxArrayString strTypes
;
463 GetMimeTypes(strTypes
);
464 if ( strTypes
.IsEmpty() )
467 wxMimeTypeCommands
*entry
= new wxMimeTypeCommands();
469 size_t nCount
= strTypes
.GetCount();
470 for ( size_t i
= 0; i
< nCount
; i
++ )
472 if ( m_manager
->DoAssociation
481 // we don't need to free entry now, DoAssociation() took ownership
493 // ----------------------------------------------------------------------------
494 // wxMimeTypesManagerImpl (Unix)
495 // ----------------------------------------------------------------------------
497 wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
499 m_initialized
= false;
502 void wxMimeTypesManagerImpl::InitIfNeeded()
504 if ( !m_initialized
)
506 // set the flag first to prevent recursion
507 m_initialized
= true;
509 int mailcapStyles
= wxMAILCAP_ALL
;
510 if ( wxAppTraits
* const traits
= wxApp::GetTraitsIfExists() )
512 wxString wm
= traits
->GetDesktopEnvironment();
515 mailcapStyles
= wxMAILCAP_KDE
;
516 else if ( wm
== "GNOME" )
517 mailcapStyles
= wxMAILCAP_GNOME
;
518 //else: unknown, use the default
521 Initialize(mailcapStyles
);
527 // read system and user mailcaps and other files
528 void wxMimeTypesManagerImpl::Initialize(int mailcapStyles
,
529 const wxString
& sExtraDir
)
532 // XDG tables are never installed on OpenVMS
536 // Read MIME type - extension associations
537 LoadXDGGlobs( "/usr/share/mime/globs" );
538 LoadXDGGlobs( "/usr/local/share/mime/globs" );
540 // Load desktop files for XDG, and then override them with the defaults.
541 // We will override them one desktop file at a time, rather
542 // than one mime type at a time, but it should be a reasonable
545 wxString xdgDataHome
= wxGetenv("XDG_DATA_HOME");
546 if ( xdgDataHome
.empty() )
547 xdgDataHome
= wxGetHomeDir() + "/.local/share";
548 wxString xdgDataDirs
= wxGetenv("XDG_DATA_DIRS");
549 if ( xdgDataDirs
.empty() )
551 xdgDataDirs
= "/usr/local/share:/usr/share";
552 if (mailcapStyles
& wxMAILCAP_GNOME
)
553 xdgDataDirs
+= ":/usr/share/gnome:/opt/gnome/share";
554 if (mailcapStyles
& wxMAILCAP_KDE
)
555 xdgDataDirs
+= ":/usr/share/kde3:/opt/kde3/share";
557 if ( !sExtraDir
.empty() )
560 xdgDataDirs
+= sExtraDir
;
564 wxStringTokenizer
tokenizer(xdgDataDirs
, ":");
565 while ( tokenizer
.HasMoreTokens() )
567 wxString p
= tokenizer
.GetNextToken();
570 dirs
.insert(dirs
.begin(), xdgDataHome
);
572 wxString defaultsList
;
574 for (i
= 0; i
< dirs
.GetCount(); i
++)
576 wxString f
= dirs
[i
];
577 if (f
.Last() != '/') f
+= '/';
578 f
+= "applications/defaults.list";
586 // Load application files and associate them to corresponding mime types.
587 size_t nDirs
= dirs
.GetCount();
588 for (size_t nDir
= 0; nDir
< nDirs
; nDir
++)
590 wxString dirStr
= dirs
[nDir
];
591 if (dirStr
.Last() != '/') dirStr
+= '/';
592 dirStr
+= "applications";
593 LoadXDGAppsFilesFromDir(dirStr
);
596 if (!defaultsList
.IsEmpty())
598 wxArrayString deskTopFilesSeen
;
600 wxMimeTextFile
textfile(defaultsList
);
601 if ( textfile
.Open() )
603 int nIndex
= textfile
.pIndexOf( wxT("[Default Applications]") );
604 if (nIndex
!= wxNOT_FOUND
)
606 for (i
= nIndex
+1; i
< textfile
.GetLineCount(); i
++)
608 if (textfile
.GetLine(i
).Find(wxT("=")) != wxNOT_FOUND
)
610 wxString desktopFile
= textfile
.GetCmd(i
);
612 if (deskTopFilesSeen
.Index(desktopFile
) == wxNOT_FOUND
)
614 deskTopFilesSeen
.Add(desktopFile
);
616 for (j
= 0; j
< dirs
.GetCount(); j
++)
618 wxString desktopPath
= dirs
[j
];
619 if (desktopPath
.Last() != '/') desktopPath
+= '/';
620 desktopPath
+= "applications/";
621 desktopPath
+= desktopFile
;
623 if (wxFileExists(desktopPath
))
624 LoadXDGApp(desktopPath
);
636 // clear data so you can read another group of WM files
637 void wxMimeTypesManagerImpl::ClearData()
641 m_aExtensions
.Clear();
642 m_aDescriptions
.Clear();
644 WX_CLEAR_ARRAY(m_aEntries
);
648 wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl()
653 wxFileType
* wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo
& ftInfo
)
657 wxString strType
= ftInfo
.GetMimeType();
658 wxString strDesc
= ftInfo
.GetDescription();
659 wxString strIcon
= ftInfo
.GetIconFile();
661 wxMimeTypeCommands
*entry
= new wxMimeTypeCommands();
663 if ( ! ftInfo
.GetOpenCommand().empty())
664 entry
->Add(wxT("open=") + ftInfo
.GetOpenCommand() + wxT(" %s "));
665 if ( ! ftInfo
.GetPrintCommand().empty())
666 entry
->Add(wxT("print=") + ftInfo
.GetPrintCommand() + wxT(" %s "));
668 // now find where these extensions are in the data store and remove them
669 wxArrayString sA_Exts
= ftInfo
.GetExtensions();
670 wxString sExt
, sExtStore
;
672 size_t nExtCount
= sA_Exts
.GetCount();
673 for (i
=0; i
< nExtCount
; i
++)
675 sExt
= sA_Exts
.Item(i
);
677 // clean up to just a space before and after
678 sExt
.Trim().Trim(false);
679 sExt
= wxT(' ') + sExt
+ wxT(' ');
680 size_t nCount
= m_aExtensions
.GetCount();
681 for (nIndex
= 0; nIndex
< nCount
; nIndex
++)
683 sExtStore
= m_aExtensions
.Item(nIndex
);
684 if (sExtStore
.Replace(sExt
, wxT(" ") ) > 0)
685 m_aExtensions
.Item(nIndex
) = sExtStore
;
689 if ( !DoAssociation(strType
, strIcon
, entry
, sA_Exts
, strDesc
) )
692 return GetFileTypeFromMimeType(strType
);
695 bool wxMimeTypesManagerImpl::DoAssociation(const wxString
& strType
,
696 const wxString
& strIcon
,
697 wxMimeTypeCommands
*entry
,
698 const wxArrayString
& strExtensions
,
699 const wxString
& strDesc
)
701 int nIndex
= AddToMimeData(strType
, strIcon
, entry
, strExtensions
, strDesc
, true);
703 if ( nIndex
== wxNOT_FOUND
)
709 int wxMimeTypesManagerImpl::AddToMimeData(const wxString
& strType
,
710 const wxString
& strIcon
,
711 wxMimeTypeCommands
*entry
,
712 const wxArrayString
& strExtensions
,
713 const wxString
& strDesc
,
714 bool replaceExisting
)
718 // ensure mimetype is always lower case
719 wxString mimeType
= strType
.Lower();
721 // is this a known MIME type?
722 int nIndex
= m_aTypes
.Index(mimeType
);
723 if ( nIndex
== wxNOT_FOUND
)
725 // We put MIME types containing "application" at the end, so that
726 // if the MIME type for the extension "htm" is searched for, it will
727 // rather find "text/html" than "application/x-mozilla-bookmarks".
728 if (mimeType
.Find( "application" ) == 0)
731 m_aTypes
.Add(mimeType
);
732 m_aIcons
.Add(strIcon
);
733 m_aEntries
.Add(entry
? entry
: new wxMimeTypeCommands
);
735 // change nIndex so we can use it below to add the extensions
736 m_aExtensions
.Add(wxEmptyString
);
737 nIndex
= m_aExtensions
.size() - 1;
739 m_aDescriptions
.Add(strDesc
);
744 m_aTypes
.Insert(mimeType
,0);
745 m_aIcons
.Insert(strIcon
,0);
746 m_aEntries
.Insert(entry
? entry
: new wxMimeTypeCommands
,0);
748 // change nIndex so we can use it below to add the extensions
749 m_aExtensions
.Insert(wxEmptyString
,0);
752 m_aDescriptions
.Insert(strDesc
,0);
755 else // yes, we already have it
757 if ( replaceExisting
)
759 // if new description change it
760 if ( !strDesc
.empty())
761 m_aDescriptions
[nIndex
] = strDesc
;
763 // if new icon change it
764 if ( !strIcon
.empty())
765 m_aIcons
[nIndex
] = strIcon
;
769 delete m_aEntries
[nIndex
];
770 m_aEntries
[nIndex
] = entry
;
773 else // add data we don't already have ...
775 // if new description add only if none
776 if ( m_aDescriptions
[nIndex
].empty() )
777 m_aDescriptions
[nIndex
] = strDesc
;
779 // if new icon and no existing icon
780 if ( m_aIcons
[nIndex
].empty() )
781 m_aIcons
[nIndex
] = strIcon
;
783 // add any new entries...
786 wxMimeTypeCommands
*entryOld
= m_aEntries
[nIndex
];
788 size_t count
= entry
->GetCount();
789 for ( size_t i
= 0; i
< count
; i
++ )
791 const wxString
& verb
= entry
->GetVerb(i
);
792 if ( !entryOld
->HasVerb(verb
) )
794 entryOld
->AddOrReplaceVerb(verb
, entry
->GetCmd(i
));
798 // as we don't store it anywhere, it won't be deleted later as
799 // usual -- do it immediately instead
805 // always add the extensions to this mimetype
806 wxString
& exts
= m_aExtensions
[nIndex
];
808 // add all extensions we don't have yet
810 size_t count
= strExtensions
.GetCount();
811 for ( size_t i
= 0; i
< count
; i
++ )
813 ext
= strExtensions
[i
];
816 if ( exts
.Find(ext
) == wxNOT_FOUND
)
822 // check data integrity
823 wxASSERT( m_aTypes
.GetCount() == m_aEntries
.GetCount() &&
824 m_aTypes
.GetCount() == m_aExtensions
.GetCount() &&
825 m_aTypes
.GetCount() == m_aIcons
.GetCount() &&
826 m_aTypes
.GetCount() == m_aDescriptions
.GetCount() );
831 wxFileType
* wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString
& ext
)
838 size_t count
= m_aExtensions
.GetCount();
839 for ( size_t n
= 0; n
< count
; n
++ )
841 wxStringTokenizer
tk(m_aExtensions
[n
], wxT(' '));
843 while ( tk
.HasMoreTokens() )
845 // consider extensions as not being case-sensitive
846 if ( tk
.GetNextToken().IsSameAs(ext
, false /* no case */) )
849 wxFileType
*fileType
= new wxFileType
;
850 fileType
->m_impl
->Init(this, n
);
860 wxFileType
* wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString
& mimeType
)
864 wxFileType
* fileType
= NULL
;
865 // mime types are not case-sensitive
866 wxString
mimetype(mimeType
);
867 mimetype
.MakeLower();
869 // first look for an exact match
870 int index
= m_aTypes
.Index(mimetype
);
872 if ( index
!= wxNOT_FOUND
)
874 fileType
= new wxFileType
;
875 fileType
->m_impl
->Init(this, index
);
878 // then try to find "text/*" as match for "text/plain" (for example)
879 // NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return
880 // the whole string - ok.
883 wxString strCategory
= mimetype
.BeforeFirst(wxT('/'));
885 size_t nCount
= m_aTypes
.GetCount();
886 for ( size_t n
= 0; n
< nCount
; n
++ )
888 if ( (m_aTypes
[n
].BeforeFirst(wxT('/')) == strCategory
) &&
889 m_aTypes
[n
].AfterFirst(wxT('/')) == wxT("*") )
896 if ( index
!= wxNOT_FOUND
)
898 // don't throw away fileType that was already found
900 fileType
= new wxFileType
;
901 fileType
->m_impl
->Init(this, index
);
907 wxString
wxMimeTypesManagerImpl::GetCommand(const wxString
& verb
, size_t nIndex
) const
909 wxString command
, testcmd
, sV
, sTmp
;
910 sV
= verb
+ wxT("=");
912 // list of verb = command pairs for this mimetype
913 wxMimeTypeCommands
* sPairs
= m_aEntries
[nIndex
];
916 size_t nCount
= sPairs
->GetCount();
917 for ( i
= 0; i
< nCount
; i
++ )
919 sTmp
= sPairs
->GetVerbCmd (i
);
920 if ( sTmp
.Contains(sV
) )
921 command
= sTmp
.AfterFirst(wxT('='));
927 void wxMimeTypesManagerImpl::AddFallback(const wxFileTypeInfo
& filetype
)
932 const wxArrayString
& exts
= filetype
.GetExtensions();
933 size_t nExts
= exts
.GetCount();
934 for ( size_t nExt
= 0; nExt
< nExts
; nExt
++ )
937 extensions
+= wxT(' ');
939 extensions
+= exts
[nExt
];
942 AddMimeTypeInfo(filetype
.GetMimeType(),
944 filetype
.GetDescription());
947 void wxMimeTypesManagerImpl::AddMimeTypeInfo(const wxString
& strMimeType
,
948 const wxString
& strExtensions
,
949 const wxString
& strDesc
)
951 // reading mailcap may find image/* , while
952 // reading mime.types finds image/gif and no match is made
953 // this means all the get functions don't work fix this
955 wxString sTmp
= strExtensions
;
958 sTmp
.Trim().Trim(false);
960 while (!sTmp
.empty())
962 sExts
.Add(sTmp
.AfterLast(wxT(' ')));
963 sTmp
= sTmp
.BeforeLast(wxT(' '));
966 AddToMimeData(strMimeType
, strIcon
, NULL
, sExts
, strDesc
, true);
969 size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString
& mimetypes
)
975 size_t count
= m_aTypes
.GetCount();
976 for ( size_t n
= 0; n
< count
; n
++ )
978 // don't return template types from here (i.e. anything containg '*')
979 const wxString
&type
= m_aTypes
[n
];
980 if ( type
.Find(wxT('*')) == wxNOT_FOUND
)
986 return mimetypes
.GetCount();
989 // ----------------------------------------------------------------------------
990 // writing to MIME type files
991 // ----------------------------------------------------------------------------
993 bool wxMimeTypesManagerImpl::Unassociate(wxFileType
*ft
)
997 wxArrayString sMimeTypes
;
998 ft
->GetMimeTypes(sMimeTypes
);
1001 size_t nCount
= sMimeTypes
.GetCount();
1002 for (i
= 0; i
< nCount
; i
++)
1004 const wxString
&sMime
= sMimeTypes
.Item(i
);
1005 int nIndex
= m_aTypes
.Index(sMime
);
1006 if ( nIndex
== wxNOT_FOUND
)
1008 // error if we get here ??
1013 m_aTypes
.RemoveAt(nIndex
);
1014 m_aEntries
.RemoveAt(nIndex
);
1015 m_aExtensions
.RemoveAt(nIndex
);
1016 m_aDescriptions
.RemoveAt(nIndex
);
1017 m_aIcons
.RemoveAt(nIndex
);
1020 // check data integrity
1021 wxASSERT( m_aTypes
.GetCount() == m_aEntries
.GetCount() &&
1022 m_aTypes
.GetCount() == m_aExtensions
.GetCount() &&
1023 m_aTypes
.GetCount() == m_aIcons
.GetCount() &&
1024 m_aTypes
.GetCount() == m_aDescriptions
.GetCount() );
1030 // wxUSE_MIMETYPE && wxUSE_FILE