// $Id: Cxx_Fileset.cc,v 1.92 2004/05/07 07:04:47 christof Exp $ /* glade--: C++ frontend for glade (Gtk+ User Interface Builder) * Copyright (C) 1998 Christof Petig * Copyright (C) 1999-2000 Adolf Petig GmbH & Co. KG, written by Christof Petig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "Cxx.hh" #include "Configuration.hh" #include "writers/WriterBase.hh" #include "WidgetMap.hh" Cxx_Fileset::Cxx_Fileset(const Tag &t, Cxx &_toplevel) : top(t), toplevel(_toplevel) { } void Cxx_Fileset::WriteFiles(bool _toplevel) { const Widget w(top); ReregisterLocal(w); gh.open(&w,File_FOO_GLADE_HH); WriteHeader(gh,File_FOO_GLADE_HH); gc.open(&w,File_FOO_GLADE_CC); WriteHeader(gc,File_FOO_GLADE_CC); if (!Configuration.bare_bones) { h.open(&w,File_FOO_HH); WriteHeader(h,File_FOO_HH); c.open(&w,File_FOO_CC); WriteHeader(c,File_FOO_CC); if (Configuration.baseclass) { bc.open(&w,File_BASECLASSES_HH); WriteHeader(bc,File_BASECLASSES_HH); } if (_toplevel) {toplevel.main.Include(h.FileName(),true); Remember os=Remember(toplevel.main); os.Declaration(); os << Configuration.TypeName(w.Name()) << " *"; os << Configuration.InstanceName(w.Name()); os.Assignment() << "new class " << Configuration.TypeName(w.Name()) << "()"; os.EndLine(); Remember os2=Remember(toplevel.main,1); os2.Statement(); os2 << "delete " << Configuration.InstanceName(w.Name()); os2.EndLine(); } if (!Configuration.no_autoconf) { toplevel.makefile_am.Dependancy(gc.FileName(File_NODIR)) .Dependancy(c.FileName(File_NODIR)); Remember(toplevel.makefile_am).Dependancy(gh.FileName(File_NODIR)) .Dependancy(h.FileName(File_NODIR)); if (Configuration.gettext_support) { toplevel.potfiles << gc.FileName(0) << '\n' << c.FileName(0) << '\n'; } } else { toplevel.makefile.Dependancy(gc.FileName(File_NODIR|File_OBJECT)) .Dependancy(c.FileName(File_NODIR|File_OBJECT)); } } if (!Configuration.bare_bones) { c.Include(h.FileName(),true); // gc.Include(h.FileName(),true); } if (Configuration.non_virtual_callbacks || Configuration.need_notebook_hack) gc.Include(h.FileName(),true); else gc.Include(gh.FileName(),true); WriteClasses(w); if (!Configuration.bare_bones) { WriteFooter(c,File_FOO_CC); c.close(); WriteFooter(h,File_FOO_HH); h.close(); } WriteFooter(gc,File_FOO_GLADE_CC); gc.close(); WriteFooter(gh,File_FOO_GLADE_HH); gh.close(); if (Configuration.baseclass) { WriteFooter(bc,File_BASECLASSES_HH); bc.close(); } } void Cxx_Fileset::DoIncludes(const Widget &w) { { const WriterBase &wr(LookupWriter(w,false)); wr.GHInclude(w,gh); } for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.GHInclude(w2,gh); // std::cout << (*i).getTagPtr() << '=' << (*i).Class() << '\n'; } } void Cxx_Fileset::WriteClasses(const Widget &w) { //if (Configuration.use_libglade) //{ WriteClasses_libglade(w); // return; //} // Include own type and type of all included widgets // std::cerr << "WriteClasses(" << w.Name() << ") {\n"; DoIncludes(w); if (Configuration.baseclass) { gh.Include("./"+Configuration.FileName("",File_BASECLASSES_HH,File_NODIR),true); } // start class generation /******* GH: class Xyz_Glade ******/ if (Configuration.debug) std::cout << "======== GH declaration ============\n"; const WriterBase &top_wr(LookupWriter(w)); gh.Definition().Class(Configuration.TypeName(w.Name(),true)); top_wr.Derivation(w,gh); if (Configuration.baseclass) gh.Derive("public "+Configuration.TypeName(w.Name())+"_base"); gh.StartBlock(); top_wr.AdditionalMemberVars(w,gh,true); for (Widget::const_contained_iterator i=w.begin_contained(); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.GHDeclaration(w2,gh); wr.AdditionalMemberVars(w2,gh); } /****** GH: ctor, dtor *********/ gh.Protected().Declaration() .FunctionName(Configuration.TypeName(w.Name(),true)); if (Configuration.has_accelerators && top_wr.needDataArg(w)) { gh.FunctionArg("GlademmData *gmm_data"); } #ifdef NEED_CONSTRUCT_ARGS top_wr.ConstructArgs(w,gh); for (Widget::const_contained_iterator i=w.begin_contained(InternalBoth); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.ConstructArgs(w2,gh); } #endif gh.EndLine(); gh.Declaration() .FunctionName("~"+Configuration.TypeName(w.Name(),true)).EndLine(); // virtual signal handlers if (!Configuration.non_virtual_callbacks) { for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); DeclareSignalHandler(wr,w2,w,false,true); } DeclareSignalHandler(top_wr,w,w,true,true); } gh.EndBlock(); /******* GH: defines (glademm_get) ***********/ if (Configuration.lookup_table) { if (w.getProperty("cxx_visibility","private")=="public") // we can't use top_wr since we need the component type, not the widget type GenerateMapDefine(LookupWriter(w,true),w); for (Widget::const_contained_iterator i=w.begin_contained(); i!=w.end_contained();++i) { Widget w2(*i); if (w2.getProperty("cxx_visibility","private")=="public" && !w2.getBoolProperty(CXX_SEPERATE_CLASS)) GenerateMapDefine(LookupWriter(w2,true),w2); } } /******* H: class Xyz ******/ if (Configuration.baseclass) { bc.Definition().Class(Configuration.TypeName(w.Name())+"_base"); bc.StartBlock(); bc.EndBlock(); } if (Configuration.debug) std::cout << "======== H declaration ============\n"; h.Definition().Class(Configuration.TypeName(w.Name())); h.Derive("public "+Configuration.TypeName(w.Name(),true)); h.StartBlock(); if (Configuration.non_virtual_callbacks || Configuration.need_notebook_hack) { h.Declaration() << "friend class " << Configuration.TypeName(w.Name(),true); h.EndLine(); } if (Configuration.has_accelerators && top_wr.needDataArg(w)) { h.Public().Definition().FunctionName(Configuration.TypeName(w.Name())) .FunctionArg("GlademmData *gmm_data") .Construct(Configuration.TypeName(w.Name(),true),"gmm_data") .StartBlock().EndBlock(); } for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); DeclareSignalHandler(wr,w2,w); } DeclareSignalHandler(top_wr,w,w,true); h.EndBlock(); /****** GC: include, definitions **************/ if (Configuration.debug) std::cout << "======== GC include ============\n"; top_wr.GCInclude(w,gc); top_wr.GCDefinition(w,gc); for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.GCInclude(w2,gc); wr.GCDefinition(w2,gc); } /****** GC: ctor **************/ if (Configuration.debug) std::cout << "======== GC ctor ============\n"; ClearRadioGroups(); gc.Definition().FunctionName() << Configuration.TypeName(w.Name(),true) << "::" << Configuration.TypeName(w.Name(),true); if (Configuration.has_accelerators && top_wr.needDataArg(w)) { gc.FunctionArg("GlademmData *gmm_data"); } #ifdef NEED_CONSTRUCT_ARGS top_wr.ConstructArgs(w,gc); for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.ConstructArgs(w2,gc); } #else if (!Configuration.has_accelerators|| !top_wr.needDataArg(w)) gc.FunctionArg(); #endif // member constructors gc.NewLine(false); // XXX: because of SourceWriter limitation if (top_wr.NeedExplicitCtor(w)) top_wr.ParentConstruction(w,gc); // function body gc.StartBlock(); // ctor head initialization if (top_wr.CantMemberConstruct(w)) { std::cerr << "ERROR: " << w.Name() << ": Can't form a class of its own (yet).\n"; } // is this order intended? T.L. suggested to change it because of menubar.cc top_wr.CreatePointer_Toplevel(w,gc); top_wr.ClassConstructor(w,gc); if (Configuration.debug) std::cout << "======== creating the widgets ============\n"; // create widgets for (Widget::const_contained_iterator i=w.begin_contained(NoInternal,Configuration.debug); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.CreatePointer(w2,gc); } top_wr.CreatePointer_depending(w,gc); for (Widget::const_contained_iterator i=w.begin_contained(NoInternal,Configuration.debug); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.CreatePointer_depending(w2,gc); } if (Configuration.debug) std::cout << "======== configuring the widgets ============\n"; // configure widgets for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both,Configuration.debug); i!=w.end_contained();++i) { const Widget w2=*i; if (!w2.getBoolProperty(CXX_SEPERATE_CLASS)) { const Widget WriterWidget=*i.getWriterTag(); const WriterBase &ww_wr=LookupWriter(WriterWidget); std::string instance=ww_wr.Instance(WriterWidget,w2,i.getSWType()); if (instance.empty()) { if (Configuration.verbose>1) std::cerr << "Warning: can't change properties of " << WriterWidget.Name() << ':' << w2.Name() << "\n"; continue; // can't modify this widget } const WriterBase &wr2=LookupWriter(w2,true); wr2.Configure(w2,gc,instance); // since we go down one step: // determine whether w2's children might be subwidgets of // i's parent if (i.getSWType()!=is_Subwidget && i.getSWType()!=is_Subwidget_all) // note that is_Subwidget_only is ok { wr2.AddChildren(w2,gc,instance,wr2,w2); } else { wr2.AddChildren(w2,gc,instance,ww_wr,WriterWidget); } // wr2.Constructor(w2,gc,instance); } } const std::string inst=top_wr.Instance(w,w,not_Subwidget); top_wr.Configure(w,gc,inst); top_wr.AddChildren(w,gc,inst,top_wr,w); // top_wr.Constructor(w,gc,inst); if (Configuration.debug) std::cout << "======== showing the widgets ============\n"; // show widgets (no need to show internal ones) for (Widget::const_contained_iterator i=w.begin_contained(); i!=w.end_contained();++i) { Widget w2(*i); if (!w2.getBoolProperty(CXX_SEPERATE_CLASS)) { const Widget WriterWidget(*i.getWriterTag()); const WriterBase &ww_wr(LookupWriter(WriterWidget)); std::string instance(ww_wr.Instance(WriterWidget,w2,i.getSWType())); if (instance.empty()) { std::cerr << "Configure_show has problems with " << WriterWidget.Name() << ':' << w2.Name() << '\n'; continue; } // assert(!instance.empty()); // we should not see internal widgets! const WriterBase &wr(LookupWriter(w2,true)); wr.Configure_show(w2,gc,instance); } } top_wr.Configure_show(w,gc,inst); if (Configuration.debug) std::cout << "======== connecting callbacks ============\n"; // Connect callbacks for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); if (!w2.getBoolProperty(CXX_SEPERATE_CLASS)) { const Widget WriterWidget(*(i.getWriterTag())); const WriterBase &ww_wr(LookupWriter(WriterWidget)); std::string instance(ww_wr.Instance(WriterWidget,w2,i.getSWType())); if (instance.empty()) { continue; // can't connect this widget } const WriterBase &wr2(LookupWriter(w2,true)); ConnectSignalHandler(wr2,w2,w,instance); } } ConnectSignalHandler(top_wr,w,w,inst); // Write out grab_default(), if any for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); if (w2.getBoolProperty("has_default") ) { const Widget WriterWidget(*(i.getWriterTag())); const WriterBase &ww_wr(LookupWriter(WriterWidget)); std::string instance(ww_wr.Instance(WriterWidget,w2,i.getSWType())); if (instance.empty()) continue; // can't connect this widget gc.Statement() << instance << "grab_default()"; break; } } // add them to the map if (Configuration.lookup_table) { if (w.getProperty("cxx_visibility","private")=="public") // we can't use top_wr since we need the component type, not the widget type AddToMap(w,"this"); for (Widget::const_contained_iterator i=w.begin_contained(); i!=w.end_contained();++i) { Widget w2(*i); if (w2.getProperty("cxx_visibility","private")=="public" && !w2.getBoolProperty(CXX_SEPERATE_CLASS)) AddToMap(w2,WriterBase::Pointer(w2)); } } gc.EndBlock(); /************ GC: dtor *************/ if (Configuration.debug) std::cout << "======== GC dtor ============\n"; gc.Definition().FunctionName() << Configuration.TypeName(w.Name(),true) << "::~" << Configuration.TypeName(w.Name(),true); gc.StartBlock(); // destroy widgets for (Widget::const_contained_iterator i=w.begin_contained(); i!=w.end_contained();++i) { Widget w2(*i); const WriterBase &wr(LookupWriter(w2,true)); wr.Destructor(w2,gc); wr.DestroyPointer(w2,gc); } top_wr.ClassDestructor(w,gc); top_wr.DestroyPointer_Toplevel(w,gc); gc.EndBlock(); /****** C: signal handler stubs *******/ if (Configuration.debug) std::cout << "======== C signal stubs ============\n"; for (Widget::const_contained_iterator i=w.begin_contained(Internal_Both); i!=w.end_contained();++i) { Widget w2(*i); if (w2.getBoolProperty(CXX_SEPERATE_CLASS)) continue; const WriterBase &wr(LookupWriter(w2,true)); DefineSignalHandler(wr,w2,w); } DefineSignalHandler(top_wr,w,w); /****** other classes/files ********/ // recurse if (Configuration.debug) std::cout << "======== separate-file widgets ============\n"; for (Widget::const_contained_iterator i=w.begin_contained(); i!=w.end_contained();++i) { Widget w2(*i); if (w2.getBoolProperty(CXX_SEPERATE_FILE)) { Cxx_Fileset sub_fs(*(w2.getTagPtr()),toplevel); sub_fs.WriteFiles(); } else if (w2.getBoolProperty(CXX_SEPERATE_CLASS)) WriteClasses(w2); } // std::cerr << "}\n"; } void Cxx_Fileset::WriteHeader(WidgetFile &f,File_type tp) { switch(tp) { case File_FOO_HH: Cxx::WriteCreation(f,tp); f << "//\n// newer (non customized) versions of this file go to "; f << Configuration.FileName(f.widgetName(),f.type(),File_GLADE|File_NODIR) << "\n" "\n" "// you might replace\n" "// class " << Configuration.TypeName("foo",false) << " : public "; f << Configuration.TypeName("foo",true) << " { ... };\n" "// by\n" "// typedef " << Configuration.TypeName("foo",true)<< ' ' << Configuration.TypeName("foo",false) << ";\n" "// if you didn't make any modifications to the widget\n" "\n"; f << "#ifndef "<\n" "# undef _\n" "# define _(String) dgettext (GETTEXT_PACKAGE, String)\n" "# ifdef gettext_noop\n" "# define N_(String) gettext_noop (String)\n" "# else\n" "# define N_(String) (String)\n" "# endif\n" "#else\n" "# define textdomain(String) (String)\n" "# define gettext(String) (String)\n" "# define dgettext(Domain,Message) (Message)\n" "# define dcgettext(Domain,Message,Type) (Message)\n" "# define bindtextdomain(Domain,Directory) (Domain)\n" "# define _(String) (String)\n" "# define N_(String) (String)\n" "#endif\n"; } } if (Configuration.gtkmm_version>=Pkg_Version(2,3,0) && !Configuration.drop_gtkmm22_support) { f.Include("gtkmmconfig.h"); f.CppIf() << "GTKMM_MAJOR_VERSION==2 && GTKMM_MINOR_VERSION>2"; f.Include("sigc++/compatibility.h"); f.DefineName("GMM_GTKMM_22_24(a,b)"); f.DefineBody("b"); f.CppElse() << "gtkmm 2.2"; f.DefineName("GMM_GTKMM_22_24(a,b)"); f.DefineBody("a"); f.EndIf(); } break; case File_FOO_CC: Cxx::WriteCreation(f,tp); f << "//\n// newer (non customized) versions of this file go to "; f << Configuration.FileName(f.widgetName(),f.type(),File_GLADE|File_NODIR) << "\n" "\n" "// This file is for your program, I won't touch it again!\n\n"; f.Include("config.h",true); // always a good idea !!! if (Configuration.sample_code) { f.Include("iostream",false); f << '\n'; } break; case File_BASECLASSES_HH: Cxx::WriteCreation(f,tp); f << "//\n// newer (non customized) versions of this file go to "; f << Configuration.FileName("",tp,File_GLADE|File_NODIR) << "\n" "\n" "// This file is for your program, I won't touch it again!\n\n"; f.CppIf("!defined("+Configuration.FileDefine("",tp)+")"); f.DefineName(Configuration.FileDefine("",tp)).DefineBody().EndLine(); break; default: assert(0); } } void Cxx_Fileset::WriteFooter(WidgetFile &f,File_type tp) { switch(tp) { case File_FOO_HH: f << "#endif\n"; break; case File_FOO_GLADE_HH: f << "#endif\n"; break; case File_BASECLASSES_HH: f.EndIf(); break; default: break; } } void Cxx_Fileset::GenerateMapDefine(const WriterBase &wr, const Widget &w) { gh.DefineName("GMM_"+ Configuration.DefineName(w.Name())); gh.DefineBody() << "(glademm_get<" << wr.TypeName(w) <<" >(\"" << w.Name() << "\"))"; gh.EndLine(); } void Cxx_Fileset::AddToMap(const Widget &w, const std::string &pointer) { gc.Statement() << "glademm_set_Widget(\"" << w.Name() << "\", " << pointer << ')'; gc.EndLine(); } // this is a hack to give local names preference (only interesting with // duplicate names). Perhaps we should test for duplicates and turn // this function off if not needed. void Cxx_Fileset::ReregisterLocal(const Widget &w) const { for (Widget::const_contained_iterator i(w.begin_contained()); i!=w.end_contained();++i) { WidgetMap[(*i).Name()]=(*i).getTagPtr(); } } // this is not really a hack but an attempt to resolve this problem // while not needing to pass Cxx_Fileset to WriterBase::Configure // so we need it static - sorry Cxx_Fileset::RadioGroupList_t Cxx_Fileset::RadioGroupList; bool Cxx_Fileset::NeedToDeclareRadioGroup(const std::string &Name) { bool res(find(RadioGroupList.begin(),RadioGroupList.end(),Name)==RadioGroupList.end()); if (res) RadioGroupList.push_back(Name); return res; } void Cxx_Fileset::ClearRadioGroups() { RadioGroupList.clear(); }