]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/mimecmn.cpp
don't assume there's always an active wxEventLoop instance
[wxWidgets.git] / src / common / mimecmn.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/mimecmn.cpp
3// Purpose: classes and functions to manage MIME types
4// Author: Vadim Zeitlin
5// Modified by:
6// Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32
7// Created: 23.09.98
8// RCS-ID: $Id$
9// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10// Licence: wxWindows licence (part of wxExtra library)
11/////////////////////////////////////////////////////////////////////////////
12
13// ============================================================================
14// declarations
15// ============================================================================
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
21// for compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25 #pragma hdrstop
26#endif
27
28#if wxUSE_MIMETYPE
29
30#include "wx/mimetype.h"
31
32#ifndef WX_PRECOMP
33 #include "wx/dynarray.h"
34 #include "wx/string.h"
35 #include "wx/intl.h"
36 #include "wx/log.h"
37 #include "wx/module.h"
38#endif //WX_PRECOMP
39
40#include "wx/file.h"
41#include "wx/iconloc.h"
42#include "wx/confbase.h"
43
44// other standard headers
45#include <ctype.h>
46
47// implementation classes:
48#if defined(__WXMSW__)
49 #include "wx/msw/mimetype.h"
50#elif defined(__WXMAC__)
51 #include "wx/mac/mimetype.h"
52#elif defined(__WXPM__) || defined (__EMX__)
53 #include "wx/os2/mimetype.h"
54 #undef __UNIX__
55#elif defined(__DOS__)
56 #include "wx/msdos/mimetype.h"
57#else // Unix
58 #include "wx/unix/mimetype.h"
59#endif
60
61// ============================================================================
62// common classes
63// ============================================================================
64
65// ----------------------------------------------------------------------------
66// wxMimeTypeCommands
67// ----------------------------------------------------------------------------
68
69void
70wxMimeTypeCommands::AddOrReplaceVerb(const wxString& verb, const wxString& cmd)
71{
72 int n = m_verbs.Index(verb, false /* ignore case */);
73 if ( n == wxNOT_FOUND )
74 {
75 m_verbs.Add(verb);
76 m_commands.Add(cmd);
77 }
78 else
79 {
80 m_commands[n] = cmd;
81 }
82}
83
84wxString
85wxMimeTypeCommands::GetCommandForVerb(const wxString& verb, size_t *idx) const
86{
87 wxString s;
88
89 int n = m_verbs.Index(verb);
90 if ( n != wxNOT_FOUND )
91 {
92 s = m_commands[(size_t)n];
93 if ( idx )
94 *idx = n;
95 }
96 else if ( idx )
97 {
98 // different from any valid index
99 *idx = (size_t)-1;
100 }
101
102 return s;
103}
104
105wxString wxMimeTypeCommands::GetVerbCmd(size_t n) const
106{
107 return m_verbs[n] + wxT('=') + m_commands[n];
108}
109
110// ----------------------------------------------------------------------------
111// wxFileTypeInfo
112// ----------------------------------------------------------------------------
113
114wxFileTypeInfo::wxFileTypeInfo(const wxChar *mimeType,
115 const wxChar *openCmd,
116 const wxChar *printCmd,
117 const wxChar *desc,
118 ...)
119 : m_mimeType(mimeType),
120 m_openCmd(openCmd),
121 m_printCmd(printCmd),
122 m_desc(desc)
123{
124 va_list argptr;
125 va_start(argptr, desc);
126
127 for ( ;; )
128 {
129 // icc gives this warning in its own va_arg() macro, argh
130#ifdef __INTELC__
131 #pragma warning(push)
132 #pragma warning(disable: 1684)
133#endif
134
135 const wxChar *ext = va_arg(argptr, const wxChar *);
136
137#ifdef __INTELC__
138 #pragma warning(pop)
139#endif
140 if ( !ext )
141 {
142 // NULL terminates the list
143 break;
144 }
145
146 m_exts.Add(ext);
147 }
148
149 va_end(argptr);
150}
151
152
153wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray)
154{
155 m_mimeType = sArray [0u];
156 m_openCmd = sArray [1u];
157 m_printCmd = sArray [2u];
158 m_desc = sArray [3u];
159
160 size_t count = sArray.GetCount();
161 for ( size_t i = 4; i < count; i++ )
162 {
163 m_exts.Add(sArray[i]);
164 }
165}
166
167#include "wx/arrimpl.cpp"
168WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo)
169
170// ============================================================================
171// implementation of the wrapper classes
172// ============================================================================
173
174// ----------------------------------------------------------------------------
175// wxFileType
176// ----------------------------------------------------------------------------
177
178/* static */
179wxString wxFileType::ExpandCommand(const wxString& command,
180 const wxFileType::MessageParameters& params)
181{
182 bool hasFilename = false;
183
184 wxString str;
185 for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) {
186 if ( *pc == wxT('%') ) {
187 switch ( *++pc ) {
188 case wxT('s'):
189 // '%s' expands into file name (quoted because it might
190 // contain spaces) - except if there are already quotes
191 // there because otherwise some programs may get confused
192 // by double double quotes
193#if 0
194 if ( *(pc - 2) == wxT('"') )
195 str << params.GetFileName();
196 else
197 str << wxT('"') << params.GetFileName() << wxT('"');
198#endif
199 str << params.GetFileName();
200 hasFilename = true;
201 break;
202
203 case wxT('t'):
204 // '%t' expands into MIME type (quote it too just to be
205 // consistent)
206 str << wxT('\'') << params.GetMimeType() << wxT('\'');
207 break;
208
209 case wxT('{'):
210 {
211 const wxChar *pEnd = wxStrchr(pc, wxT('}'));
212 if ( pEnd == NULL ) {
213 wxString mimetype;
214 wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
215 params.GetMimeType().c_str());
216 str << wxT("%{");
217 }
218 else {
219 wxString param(pc + 1, pEnd - pc - 1);
220 str << wxT('\'') << params.GetParamValue(param) << wxT('\'');
221 pc = pEnd;
222 }
223 }
224 break;
225
226 case wxT('n'):
227 case wxT('F'):
228 // TODO %n is the number of parts, %F is an array containing
229 // the names of temp files these parts were written to
230 // and their mime types.
231 break;
232
233 default:
234 wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
235 *pc, command.c_str());
236 str << *pc;
237 }
238 }
239 else {
240 str << *pc;
241 }
242 }
243
244 // metamail(1) man page states that if the mailcap entry doesn't have '%s'
245 // the program will accept the data on stdin so normally we should append
246 // "< %s" to the end of the command in such case, but not all commands
247 // behave like this, in particular a common test is 'test -n "$DISPLAY"'
248 // and appending "< %s" to this command makes the test fail... I don't
249 // know of the correct solution, try to guess what we have to do.
250
251 // test now carried out on reading file so test should never get here
252 if ( !hasFilename && !str.empty()
253#ifdef __UNIX__
254 && !str.StartsWith(_T("test "))
255#endif // Unix
256 ) {
257 str << wxT(" < '") << params.GetFileName() << wxT('\'');
258 }
259
260 return str;
261}
262
263wxFileType::wxFileType(const wxFileTypeInfo& info)
264{
265 m_info = &info;
266 m_impl = NULL;
267}
268
269wxFileType::wxFileType()
270{
271 m_info = NULL;
272 m_impl = new wxFileTypeImpl;
273}
274
275wxFileType::~wxFileType()
276{
277 if ( m_impl )
278 delete m_impl;
279}
280
281bool wxFileType::GetExtensions(wxArrayString& extensions)
282{
283 if ( m_info )
284 {
285 extensions = m_info->GetExtensions();
286 return true;
287 }
288
289 return m_impl->GetExtensions(extensions);
290}
291
292bool wxFileType::GetMimeType(wxString *mimeType) const
293{
294 wxCHECK_MSG( mimeType, false, _T("invalid parameter in GetMimeType") );
295
296 if ( m_info )
297 {
298 *mimeType = m_info->GetMimeType();
299
300 return true;
301 }
302
303 return m_impl->GetMimeType(mimeType);
304}
305
306bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const
307{
308 if ( m_info )
309 {
310 mimeTypes.Clear();
311 mimeTypes.Add(m_info->GetMimeType());
312
313 return true;
314 }
315
316 return m_impl->GetMimeTypes(mimeTypes);
317}
318
319bool wxFileType::GetIcon(wxIconLocation *iconLoc) const
320{
321 if ( m_info )
322 {
323 if ( iconLoc )
324 {
325 iconLoc->SetFileName(m_info->GetIconFile());
326#ifdef __WXMSW__
327 iconLoc->SetIndex(m_info->GetIconIndex());
328#endif // __WXMSW__
329 }
330
331 return true;
332 }
333
334 return m_impl->GetIcon(iconLoc);
335}
336
337bool
338wxFileType::GetIcon(wxIconLocation *iconloc,
339 const MessageParameters& params) const
340{
341 if ( !GetIcon(iconloc) )
342 {
343 return false;
344 }
345
346 // we may have "%s" in the icon location string, at least under Windows, so
347 // expand this
348 if ( iconloc )
349 {
350 iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params));
351 }
352
353 return true;
354}
355
356bool wxFileType::GetDescription(wxString *desc) const
357{
358 wxCHECK_MSG( desc, false, _T("invalid parameter in GetDescription") );
359
360 if ( m_info )
361 {
362 *desc = m_info->GetDescription();
363
364 return true;
365 }
366
367 return m_impl->GetDescription(desc);
368}
369
370bool
371wxFileType::GetOpenCommand(wxString *openCmd,
372 const wxFileType::MessageParameters& params) const
373{
374 wxCHECK_MSG( openCmd, false, _T("invalid parameter in GetOpenCommand") );
375
376 if ( m_info )
377 {
378 *openCmd = ExpandCommand(m_info->GetOpenCommand(), params);
379
380 return true;
381 }
382
383 return m_impl->GetOpenCommand(openCmd, params);
384}
385
386wxString wxFileType::GetOpenCommand(const wxString& filename) const
387{
388 wxString cmd;
389 if ( !GetOpenCommand(&cmd, filename) )
390 {
391 // return empty string to indicate an error
392 cmd.clear();
393 }
394
395 return cmd;
396}
397
398bool
399wxFileType::GetPrintCommand(wxString *printCmd,
400 const wxFileType::MessageParameters& params) const
401{
402 wxCHECK_MSG( printCmd, false, _T("invalid parameter in GetPrintCommand") );
403
404 if ( m_info )
405 {
406 *printCmd = ExpandCommand(m_info->GetPrintCommand(), params);
407
408 return true;
409 }
410
411 return m_impl->GetPrintCommand(printCmd, params);
412}
413
414
415size_t wxFileType::GetAllCommands(wxArrayString *verbs,
416 wxArrayString *commands,
417 const wxFileType::MessageParameters& params) const
418{
419 if ( verbs )
420 verbs->Clear();
421 if ( commands )
422 commands->Clear();
423
424#if defined (__WXMSW__) || defined(__UNIX__)
425 return m_impl->GetAllCommands(verbs, commands, params);
426#else // !__WXMSW__ || Unix
427 // we don't know how to retrieve all commands, so just try the 2 we know
428 // about
429 size_t count = 0;
430 wxString cmd;
431 if ( GetOpenCommand(&cmd, params) )
432 {
433 if ( verbs )
434 verbs->Add(_T("Open"));
435 if ( commands )
436 commands->Add(cmd);
437 count++;
438 }
439
440 if ( GetPrintCommand(&cmd, params) )
441 {
442 if ( verbs )
443 verbs->Add(_T("Print"));
444 if ( commands )
445 commands->Add(cmd);
446
447 count++;
448 }
449
450 return count;
451#endif // __WXMSW__/| __UNIX__
452}
453
454bool wxFileType::Unassociate()
455{
456#if defined(__WXMSW__)
457 return m_impl->Unassociate();
458#elif defined(__UNIX__)
459 return m_impl->Unassociate(this);
460#else
461 wxFAIL_MSG( _T("not implemented") ); // TODO
462 return false;
463#endif
464}
465
466bool wxFileType::SetCommand(const wxString& cmd,
467 const wxString& verb,
468 bool overwriteprompt)
469{
470#if defined (__WXMSW__) || defined(__UNIX__)
471 return m_impl->SetCommand(cmd, verb, overwriteprompt);
472#else
473 wxUnusedVar(cmd);
474 wxUnusedVar(verb);
475 wxUnusedVar(overwriteprompt);
476 wxFAIL_MSG(_T("not implemented"));
477 return false;
478#endif
479}
480
481bool wxFileType::SetDefaultIcon(const wxString& cmd, int index)
482{
483 wxString sTmp = cmd;
484#ifdef __WXMSW__
485 // VZ: should we do this?
486 // chris elliott : only makes sense in MS windows
487 if ( sTmp.empty() )
488 GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString));
489#endif
490 wxCHECK_MSG( !sTmp.empty(), false, _T("need the icon file") );
491
492#if defined (__WXMSW__) || defined(__UNIX__)
493 return m_impl->SetDefaultIcon (cmd, index);
494#else
495 wxUnusedVar(index);
496 wxFAIL_MSG(_T("not implemented"));
497 return false;
498#endif
499}
500
501// ----------------------------------------------------------------------------
502// wxMimeTypesManagerFactory
503// ----------------------------------------------------------------------------
504
505wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::m_factory = NULL;
506
507/* static */
508void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory *factory)
509{
510 delete m_factory;
511
512 m_factory = factory;
513}
514
515/* static */
516wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::Get()
517{
518 if ( !m_factory )
519 m_factory = new wxMimeTypesManagerFactory;
520
521 return m_factory;
522}
523
524wxMimeTypesManagerImpl *wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl()
525{
526 return new wxMimeTypesManagerImpl;
527}
528
529// ----------------------------------------------------------------------------
530// wxMimeTypesManager
531// ----------------------------------------------------------------------------
532
533void wxMimeTypesManager::EnsureImpl()
534{
535 if ( !m_impl )
536 m_impl = wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl();
537}
538
539bool wxMimeTypesManager::IsOfType(const wxString& mimeType,
540 const wxString& wildcard)
541{
542 wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND,
543 wxT("first MIME type can't contain wildcards") );
544
545 // all comparaisons are case insensitive (2nd arg of IsSameAs() is false)
546 if ( wildcard.BeforeFirst(wxT('/')).
547 IsSameAs(mimeType.BeforeFirst(wxT('/')), false) )
548 {
549 wxString strSubtype = wildcard.AfterFirst(wxT('/'));
550
551 if ( strSubtype == wxT("*") ||
552 strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) )
553 {
554 // matches (either exactly or it's a wildcard)
555 return true;
556 }
557 }
558
559 return false;
560}
561
562wxMimeTypesManager::wxMimeTypesManager()
563{
564 m_impl = NULL;
565}
566
567wxMimeTypesManager::~wxMimeTypesManager()
568{
569 if ( m_impl )
570 delete m_impl;
571}
572
573bool wxMimeTypesManager::Unassociate(wxFileType *ft)
574{
575 EnsureImpl();
576
577#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
578 return m_impl->Unassociate(ft);
579#else
580 return ft->Unassociate();
581#endif
582}
583
584
585wxFileType *
586wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo)
587{
588 EnsureImpl();
589
590#if defined(__WXMSW__) || defined(__UNIX__)
591 return m_impl->Associate(ftInfo);
592#else // other platforms
593 wxUnusedVar(ftInfo);
594 wxFAIL_MSG( _T("not implemented") ); // TODO
595 return NULL;
596#endif // platforms
597}
598
599wxFileType *
600wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext)
601{
602 EnsureImpl();
603 wxFileType *ft = m_impl->GetFileTypeFromExtension(ext);
604
605 if ( !ft ) {
606 // check the fallbacks
607 //
608 // TODO linear search is potentially slow, perhaps we should use a
609 // sorted array?
610 size_t count = m_fallbacks.GetCount();
611 for ( size_t n = 0; n < count; n++ ) {
612 if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) {
613 ft = new wxFileType(m_fallbacks[n]);
614
615 break;
616 }
617 }
618 }
619
620 return ft;
621}
622
623wxFileType *
624wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType)
625{
626 EnsureImpl();
627 wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType);
628
629 if ( !ft ) {
630 // check the fallbacks
631 //
632 // TODO linear search is potentially slow, perhaps we should use a
633 // sorted array?
634 size_t count = m_fallbacks.GetCount();
635 for ( size_t n = 0; n < count; n++ ) {
636 if ( wxMimeTypesManager::IsOfType(mimeType,
637 m_fallbacks[n].GetMimeType()) ) {
638 ft = new wxFileType(m_fallbacks[n]);
639
640 break;
641 }
642 }
643 }
644
645 return ft;
646}
647
648bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback)
649{
650 EnsureImpl();
651 return m_impl->ReadMailcap(filename, fallback);
652}
653
654bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename)
655{
656 EnsureImpl();
657 return m_impl->ReadMimeTypes(filename);
658}
659
660void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes)
661{
662 EnsureImpl();
663 for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) {
664 AddFallback(*ft);
665 }
666}
667
668size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes)
669{
670 EnsureImpl();
671 size_t countAll = m_impl->EnumAllFileTypes(mimetypes);
672
673 // add the fallback filetypes
674 size_t count = m_fallbacks.GetCount();
675 for ( size_t n = 0; n < count; n++ ) {
676 if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) {
677 mimetypes.Add(m_fallbacks[n].GetMimeType());
678 countAll++;
679 }
680 }
681
682 return countAll;
683}
684
685void wxMimeTypesManager::Initialize(int mcapStyle,
686 const wxString& sExtraDir)
687{
688#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
689 EnsureImpl();
690
691 m_impl->Initialize(mcapStyle, sExtraDir);
692#else
693 (void)mcapStyle;
694 (void)sExtraDir;
695#endif // Unix
696}
697
698// and this function clears all the data from the manager
699void wxMimeTypesManager::ClearData()
700{
701#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
702 EnsureImpl();
703
704 m_impl->ClearData();
705#endif // Unix
706}
707
708// ----------------------------------------------------------------------------
709// global data and wxMimeTypeCmnModule
710// ----------------------------------------------------------------------------
711
712// private object
713static wxMimeTypesManager gs_mimeTypesManager;
714
715// and public pointer
716wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager;
717
718class wxMimeTypeCmnModule: public wxModule
719{
720public:
721 wxMimeTypeCmnModule() : wxModule() { }
722
723 virtual bool OnInit() { return true; }
724 virtual void OnExit()
725 {
726 wxMimeTypesManagerFactory::Set(NULL);
727
728 if ( gs_mimeTypesManager.m_impl != NULL )
729 {
730 delete gs_mimeTypesManager.m_impl;
731 gs_mimeTypesManager.m_impl = NULL;
732 gs_mimeTypesManager.m_fallbacks.Clear();
733 }
734 }
735
736 DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule)
737};
738
739IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule)
740
741#endif // wxUSE_MIMETYPE