1/* $Id: xml.ccg,v 1.14 2006/01/20 14:55:53 murrayc Exp $ */
2
3/* Copyright (C) 2002 The libglademm Development Team
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include <glade/glade-xml.h>
21#include <gtkmm/button.h>
22#include <gtkmm/menuitem.h>
23#include <gtkmm/toolbutton.h>
24
25namespace Gnome
26{
27
28namespace Glade
29{
30
31XmlError::XmlError(const Glib::ustring& message)
32:
33  message_ (message)
34{}
35
36XmlError::~XmlError() throw()
37{}
38
39XmlError::XmlError(const XmlError& other)
40:
41  Glib::Exception (other),
42  message_        (other.message_)
43{}
44
45XmlError& XmlError::operator=(const XmlError& other)
46{
47  message_ = other.message_;
48  return *this;
49}
50
51Glib::ustring XmlError::what() const
52{
53  return message_;
54}
55
56
57#ifdef GLIBMM_EXCEPTIONS_ENABLED
58Xml::Xml(const std::string& filename, const Glib::ustring& root, const Glib::ustring& domain)
59#else
60Xml::Xml(const std::string& filename, const Glib::ustring& root, const Glib::ustring& domain, std::auto_ptr<XmlError>& error)
61#endif
62:
63  _CONSTRUCT()
64{
65  if(!glade_xml_construct(gobj(), filename.c_str(), root.empty()   ? 0 : root.c_str(),
66                                                    domain.empty() ? 0 : domain.c_str()))
67  {
68#ifdef GLIBMM_EXCEPTIONS_ENABLED
69    throw XmlError("Failed to load glade file `" + Glib::filename_to_utf8(filename) + '\'');
70#else
71    std::auto_ptr<Glib::Error> dummy_error;
72    error.reset(new XmlError("Failed to load glade file `" + Glib::filename_to_utf8(filename, dummy_error) + '\''));
73#endif // GLIBMM_EXCEPTIONS_ENABLED
74  }
75}
76
77#ifdef GLIBMM_EXCEPTIONS_ENABLED
78Xml::Xml(const char* buffer, int size, const Glib::ustring& root, const Glib::ustring& domain)
79#else
80Xml::Xml(const char* buffer, int size, const Glib::ustring& root, const Glib::ustring& domain, std::auto_ptr<XmlError>& error)
81#endif
82:
83  Glib::ObjectBase(0), //Mark this class as gtkmmproc-generated, rather than a custom class, to allow vfunc optimisations.
84  Glib::Object(Glib::ConstructParams(xml_class_.init(), (char*) 0))
85{
86 if(!glade_xml_construct_from_buffer(gobj(), buffer, size, root.empty()   ? 0
87: root.c_str(), domain.empty() ? 0 : domain.c_str()))
88  {
89#ifdef GLIBMM_EXCEPTIONS_ENABLED
90    throw XmlError("Failed to read glade input buffer");
91#else
92    error.reset(new XmlError("Failed to read glade input buffer"));
93#endif
94  }
95}
96
97// static
98#ifdef GLIBMM_EXCEPTIONS_ENABLED
99Glib::RefPtr<Xml> Xml::create(const std::string& filename,
100                              const Glib::ustring& root, const Glib::ustring& domain)
101#else
102Glib::RefPtr<Xml> Xml::create(const std::string& filename,
103                              const Glib::ustring& root, const Glib::ustring& domain,
104                              std::auto_ptr<XmlError>& error)
105#endif
106{
107#ifdef GLIBMM_EXCEPTIONS_ENABLED
108  return Glib::RefPtr<Xml>(new Xml(filename, root, domain));
109#else
110  // Return an empty pointer if an error occurred, the resulting Xml object
111  // would not be of use anyway becasue the underlaying gobject_ is NULL.
112  Glib::RefPtr<Xml> xml(new Xml(filename, root, domain, error));
113  if(error.get()) return Glib::RefPtr<Xml>();
114  return xml;
115#endif
116}
117
118// static
119#ifdef GLIBMM_EXCEPTIONS_ENABLED
120Glib::RefPtr<Xml> Xml::create_from_buffer(const char* buffer, int size,
121                                          const Glib::ustring& root, const Glib::ustring& domain)
122#else
123Glib::RefPtr<Xml> Xml::create_from_buffer(const char* buffer, int size,
124                                          const Glib::ustring& root, const Glib::ustring& domain,
125                                          std::auto_ptr<XmlError>& error)
126#endif
127{
128#ifdef GLIBMM_EXCEPTIONS_ENABLED
129  return Glib::RefPtr<Xml>(new Xml(buffer, size, root, domain));
130#else
131  // Return an empty pointer if an error occurred, the resulting Xml object
132  // would not be of use anyway becasue the underlaying gobject_ is NULL.
133  Glib::RefPtr<Xml> xml(new Xml(buffer, size, root, domain, error));
134  if(error.get()) return Glib::RefPtr<Xml>();
135  return xml;
136#endif
137}
138
139void Xml::reparent_widget(const Glib::ustring& name, Gtk::Container& container)
140{
141  Gtk::Widget* pWidget = 0;
142  get_widget(name, pWidget);
143
144  g_return_if_fail(pWidget != 0);
145
146  pWidget->reparent(container);
147}
148
149Gtk::Widget* Xml::get_widget_checked(const Glib::ustring& name, GType type)
150{
151  // Get the widget from the glade file.
152  Gtk::Widget *const pWidget = get_widget(name);
153
154  if(!pWidget)
155  {
156    g_critical("widget `%s' not found in glade file `%s'", name.c_str(), gobj()->filename);
157    return 0;
158  }
159
160  // Check if it has the correct type.
161  if(!g_type_is_a(G_OBJECT_TYPE(pWidget->gobj()), type))
162  {
163    g_critical("widget `%s' (in glade file `%s') is of type `%s' but `%s' was expected",
164               name.c_str(), gobj()->filename, G_OBJECT_TYPE_NAME(pWidget->gobj()), g_type_name(type));
165    return 0;
166  }
167
168  return pWidget;
169}
170
171GtkWidget* Xml::get_cwidget(const Glib::ustring& name)
172{
173  GtkWidget* pCWidget = glade_xml_get_widget(gobj(), name.c_str());
174  if(!pCWidget)
175  {
176    g_critical("Glade::Xml::get_cwidget(): glade_xml_get_widget() failed for widget name=%s", name.c_str());
177  }
178
179  return pCWidget;
180}
181
182#ifdef GLIBMM_VFUNCS_ENABLED
183// Custom coded so that we can custom-code the vfunc in the Xml class.
184// This is marginally better than modifying gtkmmproc to allow this.
185//
186GType Xml_Class::lookup_type_vfunc_callback(GladeXML* self, const char* classname)
187{
188  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
189      Glib::ObjectBase::_get_current_wrapper((GObject*) self));
190
191  if(obj)
192  {
193    #ifdef GLIBMM_EXCEPTIONS_ENABLED
194    try
195    {
196    #endif //GLIBMM_EXCEPTIONS_ENABLED
197      return obj->lookup_type_vfunc(Glib::convert_const_gchar_ptr_to_ustring(classname));
198    #ifdef GLIBMM_EXCEPTIONS_ENABLED
199    }
200    catch(...)
201    {
202      Glib::exception_handlers_invoke();
203    }
204    #endif //GLIBMM_EXCEPTIONS_ENABLED
205  }
206  else
207  {
208    BaseClassType *const base = static_cast<BaseClassType*>(
209        g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class.
210    );
211
212    if(base && base->lookup_type)
213      return (*base->lookup_type)(self, classname);
214  }
215
216  return 0;
217}
218#endif // GLIBMM_VFUNCS_ENABLED
219
220GType Xml::lookup_type_vfunc(const Glib::ustring& classname)
221{
222  // See if there is a gtkmm version of the gclass:
223  Glib::ustring classname_prefixed ("gtkmm__"); // gtkmm uses a prefix
224  classname_prefixed += classname;
225
226  GType gtype = g_type_from_name(classname_prefixed.c_str());
227
228  if(gtype == G_TYPE_INVALID) // if it's not a registered typename
229  {
230    // There's no gtkmm derived type, so just use the normal one.
231    gtype = g_type_from_name(classname.c_str());
232  }
233
234  return gtype;
235}
236
237void Xml::connect_clicked(const Glib::ustring& widget_name, const sigc::slot<void>& slot_ )
238{
239  Gtk::Widget* pWidget = 0;
240  get_widget(widget_name, pWidget);
241
242  Gtk::Button* pButton = dynamic_cast<Gtk::Button*>(pWidget);
243  Gtk::MenuItem* pMenuItem = dynamic_cast<Gtk::MenuItem*>(pWidget);
244  Gtk::ToolButton* pToolButton = dynamic_cast<Gtk::ToolButton*>(pWidget);
245
246  if(pButton)
247    pButton->signal_clicked().connect( slot_);
248
249  if(pMenuItem)
250    pMenuItem->signal_activate().connect( slot_ );
251
252  if(pToolButton)
253    pToolButton->signal_clicked().connect( slot_ );
254}
255
256} // namespace Glade
257} // namespace Gnome
258
259