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