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