]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/iconbndl.cpp
Fix recursion problems when loading pages from a virtual file system using the WebKit...
[wxWidgets.git] / src / common / iconbndl.cpp
index 19ede4871a4845a261e7d8c79e6300e664ab3343..186d4df0cccc3ac64838e6d3e70e35e74fdee9ae 100644 (file)
@@ -8,14 +8,6 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-// ============================================================================
-// declarations
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// headers
-// ----------------------------------------------------------------------------
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 
 #ifndef WX_PRECOMP
     #include "wx/settings.h"
-    #include "wx/icon.h"
     #include "wx/log.h"
     #include "wx/intl.h"
     #include "wx/bitmap.h"
     #include "wx/image.h"
+    #include "wx/stream.h"
 #endif
 
-#include "wx/arrimpl.cpp"
+#include "wx/wfstream.h"
 
+#include "wx/arrimpl.cpp"
 WX_DEFINE_OBJARRAY(wxIconArray)
 
 IMPLEMENT_DYNAMIC_CLASS(wxIconBundle, wxGDIObject)
 
-#define M_ICONBUNDLEDATA ((wxIconBundleRefData *)m_refData)
+#define M_ICONBUNDLEDATA static_cast<wxIconBundleRefData*>(m_refData)
 
 // ----------------------------------------------------------------------------
 // wxIconBundleRefData
@@ -49,12 +42,21 @@ IMPLEMENT_DYNAMIC_CLASS(wxIconBundle, wxGDIObject)
 class WXDLLEXPORT wxIconBundleRefData : public wxGDIRefData
 {
 public:
-    // default and copy ctors and assignment operators are ok
+    wxIconBundleRefData() { }
 
-protected:
-    wxIconArray m_icons;
+    // We need the copy ctor for CloneGDIRefData() but notice that we use the
+    // base class default ctor in it and not the copy one which it doesn't have.
+    wxIconBundleRefData(const wxIconBundleRefData& other)
+        : wxGDIRefData(),
+          m_icons(other.m_icons)
+    {
+    }
+
+    // default assignment operator and dtor are ok
 
-    friend class WXDLLEXPORT wxIconBundle;
+    virtual bool IsOk() const { return !m_icons.empty(); }
+
+    wxIconArray m_icons;
 };
 
 // ============================================================================
@@ -62,61 +64,106 @@ protected:
 // ============================================================================
 
 wxIconBundle::wxIconBundle()
-            : wxGDIObject()
 {
-    m_refData = new wxIconBundleRefData;
 }
 
-wxIconBundle::wxIconBundle(const wxString& file, long type)
+#if wxUSE_STREAMS && wxUSE_IMAGE
+
+#if wxUSE_FFILE || wxUSE_FILE
+wxIconBundle::wxIconBundle(const wxString& file, wxBitmapType type)
             : wxGDIObject()
 {
-    m_refData = new wxIconBundleRefData;
     AddIcon(file, type);
 }
+#endif // wxUSE_FFILE || wxUSE_FILE
 
-wxIconBundle::wxIconBundle(const wxIconBundle& icon)
+wxIconBundle::wxIconBundle(wxInputStream& stream, wxBitmapType type)
             : wxGDIObject()
 {
-    Ref(icon);
+    AddIcon(stream, type);
 }
+#endif // wxUSE_STREAMS && wxUSE_IMAGE
 
 wxIconBundle::wxIconBundle(const wxIcon& icon)
             : wxGDIObject()
 {
-    m_refData = new wxIconBundleRefData;
     AddIcon(icon);
 }
 
-wxObjectRefData *wxIconBundle::CreateRefData() const
+wxGDIRefData *wxIconBundle::CreateGDIRefData() const
 {
     return new wxIconBundleRefData;
 }
 
-wxObjectRefData *wxIconBundle::CloneRefData(const wxObjectRefData *data) const
+wxGDIRefData *wxIconBundle::CloneGDIRefData(const wxGDIRefData *data) const
 {
-    return new wxIconBundleRefData(*wx_static_cast(const wxIconBundleRefData *, data));
+    return new wxIconBundleRefData(*static_cast<const wxIconBundleRefData *>(data));
 }
 
 void wxIconBundle::DeleteIcons()
 {
-    wxIconBundleRefData* ref = new wxIconBundleRefData();
     UnRef();
-    m_refData = ref;
 }
 
-bool wxIconBundle::IsOk() const
+#if wxUSE_STREAMS && wxUSE_IMAGE
+
+namespace
+{
+
+// Adds icon from 'input' to the bundle. Shows 'errorMessage' on failure
+// (it must contain "%d", because it is used to report # of image in the file
+// that failed to load):
+void DoAddIcon(wxIconBundle& bundle,
+               wxInputStream& input,
+               wxBitmapType type,
+               const wxString& errorMessage)
 {
-    return M_ICONBUNDLEDATA && !M_ICONBUNDLEDATA->m_icons.IsEmpty();
+    wxImage image;
+
+    const wxFileOffset posOrig = input.TellI();
+
+    const size_t count = wxImage::GetImageCount(input, type);
+    for ( size_t i = 0; i < count; ++i )
+    {
+        if ( i )
+        {
+            // the call to LoadFile() for the first sub-image updated the
+            // stream position but we need to start reading the subsequent
+            // sub-image at the image beginning too
+            input.SeekI(posOrig);
+        }
+
+        if ( !image.LoadFile(input, type, i) )
+        {
+            wxLogError(errorMessage, i);
+            continue;
+        }
+
+        if ( type == wxBITMAP_TYPE_ANY )
+        {
+            // store the type so that we don't need to try all handlers again
+            // for the subsequent images, they should all be of the same type
+            type = image.GetType();
+        }
+
+        wxIcon tmp;
+        tmp.CopyFromBitmap(wxBitmap(image));
+        bundle.AddIcon(tmp);
+    }
 }
 
-void wxIconBundle::AddIcon(const wxString& file, long type)
+} // anonymous namespace
+
+#if wxUSE_FFILE || wxUSE_FILE
+
+void wxIconBundle::AddIcon(const wxString& file, wxBitmapType type)
 {
 #ifdef __WXMAC__
     // Deal with standard icons
     if ( type == wxBITMAP_TYPE_ICON_RESOURCE )
     {
         wxIcon tmp(file, type);
-        if (tmp.Ok())
+        if (tmp.IsOk())
         {
             AddIcon(tmp);
             return;
@@ -124,36 +171,31 @@ void wxIconBundle::AddIcon(const wxString& file, long type)
     }
 #endif // __WXMAC__
 
-#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB)
-    wxImage image;
+#if wxUSE_FFILE
+    wxFFileInputStream stream(file);
+#elif wxUSE_FILE
+    wxFileInputStream stream(file);
+#endif
+    DoAddIcon
+    (
+        *this,
+        stream, type,
+        wxString::Format(_("Failed to load image %%d from file '%s'."), file)
+    );
+}
 
-    const size_t count = wxImage::GetImageCount( file, type );
-    for ( size_t i = 0; i < count; ++i )
-    {
-        if ( !image.LoadFile( file, type, i ) )
-        {
-            wxLogError( _("Failed to load image %d from file '%s'."),
-                        i, file.c_str() );
-            continue;
-        }
+#endif // wxUSE_FFILE || wxUSE_FILE
 
-        wxIcon tmp;
-        tmp.CopyFromBitmap(wxBitmap(image));
-        AddIcon(tmp);
-    }
-#else // !wxUSE_IMAGE
-    wxUnusedVar(file);
-    wxUnusedVar(type);
-#endif // wxUSE_IMAGE/!wxUSE_IMAGE
+void wxIconBundle::AddIcon(wxInputStream& stream, wxBitmapType type)
+{
+    DoAddIcon(*this, stream, type, _("Failed to load image %d from stream."));
 }
 
+#endif // wxUSE_STREAMS && wxUSE_IMAGE
+
 wxIcon wxIconBundle::GetIcon(const wxSize& size) const
 {
-    wxCHECK_MSG( IsOk(), wxNullIcon, _T("invalid icon bundle") );
-
-    const wxIconArray& iconArray = M_ICONBUNDLEDATA->m_icons;
-
-    const size_t count = iconArray.size();
+    const size_t count = GetIconCount();
 
     // optimize for the common case of icon bundles containing one icon only
     wxIcon iconBest;
@@ -164,7 +206,7 @@ wxIcon wxIconBundle::GetIcon(const wxSize& size) const
             break;
 
         case 1:
-            iconBest = iconArray[0];
+            iconBest = M_ICONBUNDLEDATA->m_icons[0];
             break;
 
         default:
@@ -172,6 +214,7 @@ wxIcon wxIconBundle::GetIcon(const wxSize& size) const
             wxCoord sysX = wxSystemSettings::GetMetric( wxSYS_ICON_X ),
                     sysY = wxSystemSettings::GetMetric( wxSYS_ICON_Y );
 
+            const wxIconArray& iconArray = M_ICONBUNDLEDATA->m_icons;
             for ( size_t i = 0; i < count; i++ )
             {
                 const wxIcon& icon = iconArray[i];
@@ -187,21 +230,33 @@ wxIcon wxIconBundle::GetIcon(const wxSize& size) const
 
                 // the best icon is by default (arbitrarily) the first one but
                 // if we find a system-sized icon, take it instead
-                if ( sx == sysX && sy == sysY || !iconBest.IsOk() )
+                if ((sx == sysX && sy == sysY) || !iconBest.IsOk())
                     iconBest = icon;
             }
     }
 
-#ifdef __WXMAC__
+#if defined( __WXMAC__ ) && wxOSX_USE_CARBON
     return wxIcon(iconBest.GetHICON(), size);
 #else
     return iconBest;
 #endif
 }
 
+wxIcon wxIconBundle::GetIconOfExactSize(const wxSize& size) const
+{
+    wxIcon icon = GetIcon(size);
+    if ( icon.IsOk() &&
+            (icon.GetWidth() != size.x || icon.GetHeight() != size.y) )
+    {
+        icon = wxNullIcon;
+    }
+
+    return icon;
+}
+
 void wxIconBundle::AddIcon(const wxIcon& icon)
 {
-    wxCHECK_RET( icon.IsOk(), _T("invalid icon") );
+    wxCHECK_RET( icon.IsOk(), wxT("invalid icon") );
 
     AllocExclusive();
 
@@ -212,7 +267,7 @@ void wxIconBundle::AddIcon(const wxIcon& icon)
     for ( size_t i = 0; i < count; ++i )
     {
         wxIcon& tmp = iconArray[i];
-        if ( tmp.Ok() &&
+        if ( tmp.IsOk() &&
                 tmp.GetWidth() == icon.GetWidth() &&
                 tmp.GetHeight() == icon.GetHeight() )
         {
@@ -227,11 +282,12 @@ void wxIconBundle::AddIcon(const wxIcon& icon)
 
 size_t wxIconBundle::GetIconCount() const
 {
-    return M_ICONBUNDLEDATA->m_icons.size();
+    return IsOk() ? M_ICONBUNDLEDATA->m_icons.size() : 0;
 }
 
 wxIcon wxIconBundle::GetIconByIndex(size_t n) const
 {
+    wxCHECK_MSG( n < GetIconCount(), wxNullIcon, wxT("invalid index") );
+
     return M_ICONBUNDLEDATA->m_icons[n];
 }
-