1 // $Id: WriterBase.cc,v 1.75 2004/06/14 10:38:30 christof Exp $
2 /*  glade--: C++ frontend for glade (Gtk+ User Interface Builder)
3  *  Copyright (C) 1999-2000  Adolf Petig GmbH & Co. KG, written by Christof Petig
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program 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
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #include "WriterBase.hh"
21 #include "window.hh"
22 
23 safemap<std::string,const WriterBase *> Writer;
24 
GHInclude(const Widget & w,CxxFile & f) const25 void WriterBase::GHInclude(const Widget &w, CxxFile &f) const
26 {  // if we see CXX_SEPERATE_CLASS _we_ need it for inheritance
27    if (w.getProperty("cxx_visibility","private")=="private" && CanBeManaged(w)
28 	&& !w.getBoolProperty(CXX_SEPERATE_CLASS))
29       return; // only a local ctor variable needed
30    Pkg_Version help=Configuration.gtkmm_version;
31    bool need_special=TwoFourDifferent(w);
32    if (f.ElementAlreadyThere(CxxFile::element_t(
33    			CxxFile::v_IncludeBracket,IncludeName(w))))
34    {  if (!GTKMM24 || !need_special) return;
35       Configuration.gtkmm_version=Pkg_Version(2,2,0);
36       bool ret=f.ElementAlreadyThere(CxxFile::element_t(
37    			CxxFile::v_IncludeBracket,IncludeName(w)));
38       Configuration.gtkmm_version=help;
39       if (ret) return;
40    }
41    if (need_special)
42    {  If24(f);
43       f.Include(IncludeName(w));
44       f.CppElse();
45       Configuration.gtkmm_version=Pkg_Version(2,2,0);
46    }
47    f.Include(IncludeName(w));
48    if (need_special)
49    {  Configuration.gtkmm_version=help;
50       f.EndIf();
51    }
52 }
53 
GCInclude(const Widget & w,CxxFile & f) const54 void WriterBase::GCInclude(const Widget &w, CxxFile &f) const
55 {  if (w.getProperty("cxx_visibility","private")!="private" || !CanBeManaged(w)
56 	|| w.getBoolProperty(CXX_SEPERATE_CLASS))
57       return; // only a local ctor variable needed
58    Pkg_Version help=Configuration.gtkmm_version;
59    bool need_special=TwoFourDifferent(w);
60    if (f.ElementAlreadyThere(CxxFile::element_t(
61    			CxxFile::v_IncludeBracket,IncludeName(w))))
62    {  if (!GTKMM24 || !need_special) return;
63       Configuration.gtkmm_version=Pkg_Version(2,2,0);
64       bool ret=f.ElementAlreadyThere(CxxFile::element_t(
65    			CxxFile::v_IncludeBracket,IncludeName(w)));
66       Configuration.gtkmm_version=help;
67       if (ret) return;
68    }
69    if (need_special)
70    {  If24(f);
71       f.Include(IncludeName(w));
72       f.CppElse();
73       Configuration.gtkmm_version=Pkg_Version(2,2,0);
74    }
75    f.Include(IncludeName(w));
76    if (need_special)
77    {  Configuration.gtkmm_version=help;
78       f.EndIf();
79    }
80 }
81 
Visibility(CxxFile & f,const std::string & visibility)82 void /*WriterBase::*/Visibility(CxxFile &f, const std::string &visibility)
83 {
84    if (visibility=="private") f.Private();
85    else if (visibility=="protected") f.Protected();
86    else if (visibility=="public") f.Public();
87 }
88 
MemberVariable(CxxFile & f,const std::string & visibility,const std::string & type,const std::string & name)89 void WriterBase::MemberVariable(CxxFile &f, const std::string &visibility,
90                 const std::string &type, const std::string &name)
91 {
92    Visibility(f,visibility);
93    f.Declaration() << type << ' ' << name;
94    f.EndLine();
95 }
96 
GHDeclaration(const Widget & w,CxxFile & f) const97 void WriterBase::GHDeclaration(const Widget &w, CxxFile &f) const
98 {  const std::string visibility(w.getProperty("cxx_visibility","private"));
99    if (visibility=="private" && CanBeManaged(w))
100       return; // only a local ctor variable needed
101    bool need_special=TwoFourDifferent(w);
102    Pkg_Version help=Configuration.gtkmm_version;
103    if (need_special)
104    {  Visibility(f,visibility);
105       If24(f);
106       MemberVariable(f,visibility,"class "+TypeName(w)+" *",Configuration.InstanceName(w.Name()));
107       f.CppElse();
108       Configuration.gtkmm_version=Pkg_Version(2,2,0);
109    }
110    MemberVariable(f,visibility,"class "+TypeName(w)+" *",Configuration.InstanceName(w.Name()));
111    if (need_special)
112    {  Configuration.gtkmm_version=help;
113       f.EndIf();
114    }
115 }
116 
Configure(Widget const &,CxxFile &,const std::string & instance) const117 void WriterBase::Configure(Widget const &, CxxFile &, const std::string &instance) const
118 {
119 //#warning WriterBase::Configure
120 }
121 
ConstructionArgs(Widget const & w,CxxFile & f) const122 void WriterBase::ConstructionArgs(Widget const &w, CxxFile &f) const
123 {  f.FunctionArg();
124 }
125 
LookupWriter(const std::string & type,bool seperate_entity)126 const WriterBase &LookupWriter(const std::string &type,bool seperate_entity)
127 {  safemap<std::string,const WriterBase *>::iterator i;
128    if (seperate_entity) i=Writer.find("Class");
129    else i=Writer.find(type);
130    if (i!=Writer.end()) return *(i->second);
131    const WriterBase *deflt=Writer[""];
132    if (!deflt)
133    {  std::cerr << "Writer map crazy\n";
134       for (i=Writer.begin();i!=Writer.end();++i)
135         std::cerr << i->first << ':';
136       std::cerr << '\n';
137       abort();
138    }
139    std::cerr << "glade--: unknown Widget type "<<type << '\n';
140    Writer[type]=deflt;
141    return *deflt;
142 }
143 
LookupWriter(const Widget & w,bool containing)144 const WriterBase &LookupWriter(const Widget &w,bool containing)
145 {  return LookupWriter(Configuration.use_libglade?"LibGlademm":w.Class(),
146 		containing && w.getBoolProperty(CXX_SEPERATE_CLASS));
147 }
148 
Derivation(const Widget & w,CxxFile & f) const149 void WriterBase::Derivation(const Widget &w, CxxFile &f) const
150 {  f.Derivation() << "public " << TypeName(w);
151 }
152 
CreatePointer_base(const Widget & w,CxxFile & f) const153 void WriterBase::CreatePointer_base(const Widget &w, CxxFile &f) const
154 {  if (w.getProperty("cxx_visibility","private")=="private" && CanBeManaged(w))
155      f.Declaration() << TypeName(w) << " *";
156    else
157      f.Statement();
158    f << Configuration.InstanceName(w.Name());
159    f.Assignment();
160    if (CanBeManaged(w))
161    {  f.FunctionName(GTKMM1?"manage":"Gtk::manage").FunctionArg();
162       w.markManaged();
163    }
164    f << "new class ";
165    f.FunctionName() << TypeName(w);
166    ConstructionArgs(w,f);
167    f.EndLine();
168    CreatePointer_Toplevel(w,f);
169 }
170 
CreatePointer(const Widget & w,CxxFile & f) const171 void WriterBase::CreatePointer(const Widget &w, CxxFile &f) const
172 {  Pkg_Version help=Configuration.gtkmm_version;
173    bool need_special=TwoFourDifferent(w);
174    if (need_special)
175    {  If24(f);
176       CreatePointer_base(w,f);
177       f.CppElse();
178       Configuration.gtkmm_version=Pkg_Version(2,2,0);
179    }
180    CreatePointer_base(w,f);
181    if (need_special)
182    {  Configuration.gtkmm_version=help;
183       f.EndIf();
184    }
185 }
186 
DestroyPointer(const Widget & w,CxxFile & f) const187 void WriterBase::DestroyPointer(const Widget &w, CxxFile &f) const
188 {  DestroyPointer_Toplevel(w,f);
189    if (!w.getBoolProperty(CXX_IS_MANAGED))
190    {  f.Statement() << "delete " << Configuration.InstanceName(w.Name());
191       f.EndLine();
192    }
193 }
194 
ParentConstruction(Widget const & w,CxxFile & f) const195 void WriterBase::ParentConstruction(Widget const &w, CxxFile &f) const
196 {  f.Constructor() << TypeName(w);
197    ConstructionArgs(w,f);
198 }
199 
MemberConstruction(Widget const & w,CxxFile & f) const200 void WriterBase::MemberConstruction(Widget const &w, CxxFile &f) const
201 {  f.Constructor() << Configuration.InstanceName(w.Name());
202    ConstructionArgs(w,f);
203 }
204 
Destructor(Widget const & w,CxxFile & f) const205 void WriterBase::Destructor(Widget const &w, CxxFile &f) const
206 {
207 }
208 
ApplyPreferences(Tag & t) const209 void WriterBase::ApplyPreferences(Tag &t) const
210 {  Widget w(t);
211    bool seperate_file=w.getBoolProperty(CXX_SEPERATE_FILE),
212    	seperate_class=w.getBoolProperty(CXX_SEPERATE_CLASS);
213 
214    // apply preferences
215    if (Configuration.lookup_table_compat)
216    {  w.setProperty("cxx_visibility","public");
217    }
218 
219    if (Configuration.libglade_support && dynamic_cast<const Gtk_Window*>(this))
220    {  w.setProperty("cxx_visibility","public");
221    }
222 
223    if (Configuration.only_private_widgets
224    	&& w.getProperty("cxx_visibility","private")!="private")
225       Configuration.only_private_widgets=false;
226 
227    // separate files need separate classes
228    if (seperate_file && !seperate_class)
229    {  std::cerr << w.Name() << ": widgets in a separate file need their own class, marked\n";
230       w.setProperty(CXX_SEPERATE_CLASS,"true");
231       seperate_class=true;
232    }
233 
234    // append a node for marking whether it is managed
235    w.setProperty(CXX_IS_MANAGED,"false");
236 }
237 
Instance(const Widget & parent,const Widget & w2,Subwidget sw) const238 const std::string WriterBase::Instance(const Widget &parent,const Widget &w2, Subwidget sw) const
239 {  // std::cerr << "Instance " << parent.Name() << ':' << w2.Name() << ',' << sw << '\n';
240    if (sw==SW_Unknown) sw=IsSubwidget(parent,w2);
241    if (sw==is_Subwidget_only || sw==is_Subwidget_all || sw==is_Subwidget)
242    {  std::string ii(InternalInstance(parent,w2));
243       // std::cerr << "II("<<TypeName(parent) <<") = "<< ii <<'\n';
244       if (!ii.empty())
245          return Instance(parent,parent,not_Subwidget)+ii;
246       else return "";
247    }
248    std::string ret(Configuration.InstanceName(w2.Name()));
249    ret+="->";
250    return ret;
251 }
252 
GtkName(const Widget & w) const253 const std::string WriterBase::GtkName(const Widget &w) const
254 {  const std::string prefix(GtkPrefix());
255    const std::string Typename(TypeName(w));
256    unsigned pre_len(prefix.size());
257    if (Typename.substr(0,pre_len)==prefix)
258    {  return "Gtk"+Typename.substr(pre_len);
259    }
260    else
261    {  std::cerr << "don't know how to convert " << Typename << " to a corresponding gtk+ type\n";
262       return "GtkWidget";
263    }
264 }
265 
GtkCast(const Widget & w) const266 const std::string WriterBase::GtkCast(const Widget &w) const
267 {  const std::string gtktype(GtkName(w));
268    std::string ret;
269    for (std::string::const_iterator i(gtktype.begin());i!=gtktype.end();++i)
270    {  if (isupper(*i))
271       {  if (!ret.empty()) ret=ret+'_'+*i;
272          else ret+=*i;
273       }
274       else ret+=toupper(*i);
275    }
276    return ret;
277 }
278 
ClassConstructor(const Widget & w,CxxFile & f) const279 void WriterBase::ClassConstructor(const Widget &w, CxxFile &f) const
280 {  if (w.getProperty("cxx_visibility","private")=="private" && CanBeManaged(w))
281      f.Declaration() << TypeName(w) << " *";
282    else
283      f.Statement();
284    f << Configuration.InstanceName(w.Name());
285    f.Assignment() << "this";
286 }
287 
AdditionalMemberVars(const Widget & w,CxxFile & f,bool container) const288 void WriterBase::AdditionalMemberVars(const Widget &w, CxxFile &f,bool container) const
289 {  if (container) GHDeclaration(w,f);
290 }
291 
Reference(const std::string & instance)292 const std::string WriterBase::Reference(const std::string &instance)
293 {  // this is not bullet proof but should work well enough for internal widgets
294    assert (instance.size()>2 && *(instance.end()-1)=='>' && *(instance.end()-2)=='-');
295    return "*"+std::string(instance.begin(),instance.end()-2);
296 }
297 
298 // returns true if matching
isInternalMethod(const Widget & w,std::string & method,const std::string & args,std::string & scope,bool & is_signal) const299 bool WriterBase::isInternalMethod(const Widget &w,std::string &method,const std::string &args,std::string &scope,bool &is_signal) const
300 {  std::string rettype("void");
301    std::string scope2; // =scope;
302    const std::string sargs(SignalHandlerArgs(w,method,rettype,scope2));
303    if (!scope2.empty())
304    {  is_signal=true;
305       scope=scope2;
306       return true;
307    }
308    return false;
309 }
310 
311 // by default I prefer the old style: set_title() over property_title().set_value
312 
WriteTranslatableProperty(const Widget & w,CxxFile & f,const std::string & instance,const std::string & property,bool only_new)313 void WriterBase::WriteTranslatableProperty(const Widget &w, CxxFile &f, const std::string &instance, const std::string &property, bool only_new)
314 {  if (w.hasProperty(property))
315    {  f.Statement() << instance;
316       if (only_new && GTKMM2)
317       	 f << "property_" << property << "().set_value("
318       	 	<< Configuration.Translatable(w.getProperty(property)) << ')';
319       else
320          f << "set_" << property << '('
321          	<< Configuration.Translatable(w.getProperty(property)) << ')';
322    }
323 }
324 
WriteEnumPropertyNS(const Widget & w,CxxFile & f,const std::string & instance,const std::string & property,bool only_new)325 void WriterBase::WriteEnumPropertyNS(const Widget &w, CxxFile &f, const std::string &instance, const std::string &property, bool only_new)
326 {  if (w.hasProperty(property))
327    {  f.Statement() << instance;
328       std::string val=Gtkmm2Namespace(w.getProperty(property));
329       if (only_new && GTKMM2)
330       	 f << "property_" << property << "().set_value("
331       	 	<< val << ')';
332       else
333          f << "set_" << property << '('
334          	<< val << ')';
335    }
336 }
337 
WriteBoolProperty(const Widget & w,CxxFile & f,const std::string & instance,const std::string & property,bool only_new,std::string functname)338 void WriterBase::WriteBoolProperty(const Widget &w, CxxFile &f, const std::string &instance, const std::string &property,
339 	bool only_new, std::string functname)
340 {  if (functname.empty()) functname=property;
341    if (w.hasProperty(property))
342    {  f.Statement() << instance;
343       if (only_new && GTKMM2)
344       	 f << "property_" << property << "().set_value("
345       	 	<< PRINT_BOOL(w.getBoolProperty(property)) << ')';
346       else
347          f << "set_" << functname << '('
348          	<< PRINT_BOOL(w.getBoolProperty(property)) << ')';
349    }
350 }
351 
WriteBoolProp_2Fun(const Widget & w,CxxFile & f,const std::string & instance,const std::string & property,const std::string & off,const std::string & on)352 void WriterBase::WriteBoolProp_2Fun(const Widget &w, CxxFile &f,
353 	const std::string &instance, const std::string &property,
354 	const std::string &off, const std::string &on)
355 {  if (w.hasProperty(property))
356    {  f.Statement() << instance;
357       if (w.getBoolProperty(property))
358          f << on;
359       else
360          f << off;
361    }
362 }
363 
WriteIntProperty(const Widget & w,CxxFile & f,const std::string & instance,const std::string & property,bool only_new,std::string functname)364 void WriterBase::WriteIntProperty(const Widget &w, CxxFile &f,
365 	const std::string &instance, const std::string &property,
366 	bool only_new, std::string functname)
367 {  if (functname.empty()) functname=property;
368    if (w.hasProperty(property))
369    {  f.Statement() << instance;
370       if (only_new && GTKMM2)
371       	 f << "property_" << property << "().set_value("
372       	 	<< w.getIntProperty(property) << ')';
373       else
374          f << "set_" << functname << '('
375          	<< w.getIntProperty(property) << ')';
376    }
377 }
378 
WriteIntIntProperty(const Widget & w,CxxFile & f,const std::string & instance,const std::string & prop1,const std::string & prop2,const std::string & property,bool only_new,int def)379 void WriterBase::WriteIntIntProperty(const Widget &w, CxxFile &f, const std::string &instance,
380 	const std::string &prop1, const std::string &prop2,
381 	const std::string &property, bool only_new, int def)
382 {  if (only_new && GTKMM2)
383    {  WriteIntProperty(w,f,instance, prop1, true);
384       WriteIntProperty(w,f,instance, prop2, true);
385    }
386    else if (w.hasProperty(prop1) || w.hasProperty(prop2))
387    {  f.Statement() << instance << "set_" << property << '('
388          << w.getIntProperty(prop1,def) << ','
389          << w.getIntProperty(prop2,def) << ')';
390    }
391 }
392 
WriteFloatFloatProperty(const Widget & w,CxxFile & f,const std::string & instance,const std::string & prop1,const std::string & prop2,const std::string & property,bool only_new,float def)393 void WriterBase::WriteFloatFloatProperty(const Widget &w, CxxFile &f, const std::string &instance,
394 	const std::string &prop1, const std::string &prop2,
395 	const std::string &property, bool only_new, float def)
396 {  if (only_new && GTKMM2)
397    {  WriteFloatProperty(w,f,instance, prop1, true);
398       WriteFloatProperty(w,f,instance, prop2, true);
399    }
400    else if (w.hasProperty(prop1) || w.hasProperty(prop2))
401    {  f.Statement() << instance << "set_" << property << '('
402          << w.getFloatProperty(prop1,def) << ','
403          << w.getFloatProperty(prop2,def) << ')';
404    }
405 }
406 
WriteFloatProperty(const Widget & w,CxxFile & f,const std::string & instance,const std::string & property,bool only_new)407 void WriterBase::WriteFloatProperty(const Widget &w, CxxFile &f, const std::string &instance, const std::string &property, bool only_new)
408 {  if (w.hasProperty(property))
409    {  f.Statement() << instance;
410       if (only_new && GTKMM2)
411       	 f << "property_" << property << "().set_value("
412       	 	<< w.getFloatProperty(property) << ')';
413       else
414          f << "set_" << property << '('
415          	<< w.getFloatProperty(property) << ')';
416    }
417 }
418 
419 // Remove some unwanted text from strings. *** Is there a standard
420 // function/method that will erase all occurences of a substring?
replace_all(std::string & s,const std::string & from,const std::string & to)421 void WriterBase::replace_all(std::string &s,const std::string &from, const std::string &to)
422 {  std::string::size_type rm,from_sz=from.size();
423    for(rm=s.find(from); rm!=std::string::npos; rm=s.find(from))
424 	    s.replace(rm, from_sz, to);
425 }
426 
erase_all(std::string & s,const std::string & from)427 void WriterBase::erase_all(std::string &s,const std::string &from)
428 {  std::string::size_type rm,from_sz=from.size();
429    for(rm=s.find(from); rm!=std::string::npos; rm=s.find(from))
430 	    s.erase(rm, from_sz);
431 }
432 
Gtkmm2Namespace(const std::string & s)433 std::string WriterBase::Gtkmm2Namespace(const std::string &s)
434 {  if (GTKMM1) return s;
435 
436    std::string res=s;
437    replace_all(res,"GTK_","Gtk::");
438    replace_all(res,"GDK_","Gdk::");
439    return res;
440 }
441 
createWidgetTag(const std::string & cls,const std::string & name)442 Tag WriterBase::createWidgetTag(const std::string &cls, const std::string &name)
443 {  Tag res("widget");
444    if (Configuration.glade2)
445    {  res.setAttr("class",cls);
446       res.setAttr("id",name);
447    }
448    else
449    {  res.push_back(Tag("class",cls));
450       res.push_back(Tag("name",name));
451    }
452    return res;
453 }
454 
455 #if 0
456 void WriterBase::setTagProperty(Tag &t, const std::string &name, const std::string &value)
457 {  Tag &p=t.push_back(Tag("property"));
458    p.setAttr("name",name);
459    p.Value(value);
460 }
461 #endif
462 
463 
GtkPrefix()464 const std::string WriterBase::GtkPrefix()
465 {
466 	   if (Configuration.gtkmm_version>=Pkg_Version(1,1,5))
467 	      return "Gtk::";
468 	   return "Gtk_";
469 }
GnomePrefix()470 const std::string WriterBase::GnomePrefix()
471 {  if (GNOME2)
472 	      return "Gnome::";
473 	   // FIXME: Surely we should test gnomemm, not gtkmm, here.
474 	   // I don't know which gnomemm version corresponds to gtkmm 1.1.5
475 	   // but does anybody still care about that old versions
476 	   if (Configuration.gtkmm_version>=Pkg_Version(1,1,5))
477 	      return "Gnome::";
478 	   return "Gnome_";
479 }
GnomeUIPrefix()480 const std::string WriterBase::GnomeUIPrefix()
481 {
482 	   if (GNOME2)
483 	      return "Gnome::UI::";
484 	   return GnomePrefix();
485 }
BonoboPrefix()486 const std::string WriterBase::BonoboPrefix()
487 {
488 	   if (GNOME2)
489 	      return "Gnome::Bonobo::";
490 	   return "Bonobo::";
491 }
BonoboUIPrefix()492 const std::string WriterBase::BonoboUIPrefix()
493 {
494 	   if (GNOME2)
495 	      return "Gnome::Bonobo::";
496 	   return "Bonobo::";
497 }
498 
499 	// strange things ... do we really need these any longer ?
instance(const Widget & w)500 const std::string WriterBase::instance(const Widget &w)
501 {  // if (w.getBoolProperty(CXX_SEPERATE_CLASS)) return ""; /* this->"; */
502 	   return Configuration.InstanceName(w.Name())+"->";
503 }
instance_pointer(const Widget & w)504 const std::string WriterBase::instance_pointer(const Widget &w)
505 {  // if (w.getBoolProperty(CXX_SEPERATE_CLASS)) return "this";
506 	   return Pointer(w);
507 }
instance_reference(const Widget & w)508 const std::string WriterBase::instance_reference(const Widget &w)
509 {  // if (w.getBoolProperty(CXX_SEPERATE_CLASS)) return "(*this)";
510 	   return Reference(w);
511 }
gtk_object_pointer()512 const std::string WriterBase::gtk_object_pointer()
513 {
514 	   if (Configuration.gtkmm_version >= Pkg_Version(1,3,0))
515 	      return "gobj()";
516 	   return "gtkobj()";
517 }
gtk_wrapper()518 const std::string WriterBase::gtk_wrapper()
519 {
520 	   if (Configuration.gtkmm_version >= Pkg_Version(1,3,0))
521 	      return "Glib::wrap";
522 	   return "Gtk::wrap";
523 }
524 
GTKMM_22_24(const std::string & a,const std::string & b)525 const std::string WriterBase::GTKMM_22_24(const std::string &a,const std::string &b)
526 {  if (Configuration.gtkmm_version >= Pkg_Version(2,4,0))
527       return "GMM_GTKMM_22_24("+a+","+b+")";
528    else
529       return a;
530 }
531 
If24(CxxFile & f)532 CxxFile &WriterBase::If24(CxxFile &f)
533 {  f.CppIf() << "GTKMM_MAJOR_VERSION==2 && GTKMM_MINOR_VERSION>2";
534    return f;
535 }
536