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