1/* Copyright (C) 2004-2005 ian reinhart geiser <geiseri@sourcextreme.com> */
2#include <kaboutdata.h>
3#include <kcomponentdata.h>
4#include <kcmdlineargs.h>
5#include <kconfig.h>
6#include <kmacroexpander.h>
7#include <kdebug.h>
8#include <kconfiggroup.h>
9#include <klocale.h>
10#include <QtCore/QFile>
11#include <QtCore/QFileInfo>
12#include <QtCore/QHash>
13#include <QtCore/QString>
14#include <QtCore/QStringList>
15#include <QtCore/QTextStream>
16
17static const char classHeader[] = "/**\n"
18 "* This file was autogenerated by makekdewidgets. Any changes will be lost!\n"
19 "* The generated code in this file is licensed under the same license that the\n"
20 "* input file.\n"
21 "*/\n"
22 "#include <QIcon>\n"
23 "#include <QtDesigner/QDesignerContainerExtension>\n"
24 "#include <QDesignerCustomWidgetInterface>\n"
25 "#include <qplugin.h>\n"
26 "#include <qdebug.h>\n";
27
28static const char collClassDef[] = "class %CollName : public QObject, public QDesignerCustomWidgetCollectionInterface\n"
29 "{\n"
30 " Q_OBJECT\n"
31 " Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)\n"
32 "public:\n"
33 " %CollName(QObject *parent = 0);\n"
34 " virtual ~%CollName() {}\n"
35 " QList<QDesignerCustomWidgetInterface*> customWidgets() const { return m_plugins; } \n"
36 " \n"
37 "private:\n"
38 " QList<QDesignerCustomWidgetInterface*> m_plugins;\n"
39 "};\n\n"
40 "Q_EXPORT_PLUGIN2(%CollName, %CollName)\n\n";
41
42static const char collClassImpl[] = "%CollName::%CollName(QObject *parent)\n"
43 " : QObject(parent)"
44 "{\n"
45 " (void) new KComponentData(\"makekdewidgets\");\n"
46 "%CollectionAdd\n"
47 "}\n\n";
48
49
50static const char classDef[] = "class %PluginName : public QObject, public QDesignerCustomWidgetInterface\n"
51 "{\n"
52 " Q_OBJECT\n"
53 " Q_INTERFACES(QDesignerCustomWidgetInterface)\n"
54 "public:\n"
55 " %PluginName(QObject *parent = 0) :\n\t\tQObject(parent), mInitialized(false) {}\n"
56 " virtual ~%PluginName() {}\n"
57 " \n"
58 " bool isContainer() const { return %IsContainer; }\n"
59 " bool isInitialized() const { return mInitialized; }\n"
60 " QIcon icon() const { return QIcon(QLatin1String(\"%IconName\")); }\n"
61 " QString codeTemplate() const { return QLatin1String(\"%CodeTemplate\");}\n"
62 " QString domXml() const { return %DomXml; }\n"
63 " QString group() const { return QLatin1String(\"%Group\"); }\n"
64 " QString includeFile() const { return QLatin1String(\"%IncludeFile\"); }\n"
65 " QString name() const { return QLatin1String(\"%Class\"); }\n"
66 " QString toolTip() const { return QLatin1String(\"%ToolTip\"); }\n"
67 " QString whatsThis() const { return QLatin1String(\"%WhatsThis\"); }\n\n"
68 " QWidget* createWidget( QWidget* parent ) \n\t{%CreateWidget\n\t}\n"
69 " void initialize(QDesignerFormEditorInterface *core) \n\t{%Initialize\n\t}\n"
70 "\n"
71 "private:\n"
72 " bool mInitialized;\n"
73 "};\n\n";
74
75static QString denamespace ( const QString &str );
76static QString buildCollClass( KConfig &input, const QStringList& classes );
77static QString buildWidgetClass( const QString &name, KConfig &input, const QString &group );
78static QString buildWidgetInclude( const QString &name, KConfig &input );
79static void buildFile( QTextStream &stream, const QString& group, const QString& fileName, const QString& pluginName );
80
81int main( int argc, char **argv ) {
82 new KComponentData( "makekdewidgets" );
83
84 KLocalizedString description = ki18n( "Builds Qt widget plugins from an ini style description file." );
85 const char version[] = "0.4";
86
87 KCmdLineOptions options;
88 options.add("+file", ki18n( "Input file" ) );
89 options.add("o <file>", ki18n( "Output file" ) );
90 options.add("n <plugin name>", ki18n( "Name of the plugin class to generate" ), "WidgetsPlugin" );
91 options.add("g <group>", ki18n( "Default widget group name to display in designer" ), "Custom" );
92
93
94 KAboutData about( "makekdewidgets", 0, ki18n( "makekdewidgets" ), version, description, KAboutData::License_GPL, ki18n("(C) 2004-2005 Ian Reinhart Geiser"), KLocalizedString(), 0, "geiseri@kde.org" );
95 about.addAuthor( ki18n("Ian Reinhart Geiser"), KLocalizedString(), "geiseri@kde.org" );
96 about.addAuthor( ki18n("Daniel Molkentin"), KLocalizedString(), "molkentin@kde.org" );
97 KCmdLineArgs::init( argc, argv, &about );
98 KCmdLineArgs::addCmdLineOptions( options );
99 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
100 if ( args->count() < 1 ) {
101 args->usage();
102 return ( 1 );
103 }
104
105 QFileInfo fi( args->arg( args->count() - 1 ) );
106
107 QString outputFile = args->getOption( "o" );
108 QString pluginName = args->getOption( "n" );
109 QString group = args->getOption( "g" );
110 QString fileName = fi.absoluteFilePath();
111
112 if ( args->isSet( "o" ) ) {
113 QFile output( outputFile );
114 if ( output.open( QIODevice::WriteOnly ) ) {
115 QTextStream ts( &output );
116 buildFile( ts, group, fileName , pluginName );
117 QString mocFile = output.fileName();
118 mocFile.replace(".cpp", ".moc");
119 ts << QString( "#include <%1>\n" ).arg(mocFile) << endl;
120 }
121 output.close();
122 } else {
123 QTextStream ts( stdout, QIODevice::WriteOnly );
124 buildFile( ts, group, fileName , pluginName );
125 }
126}
127
128void buildFile( QTextStream &ts, const QString& group, const QString& fileName, const QString& pluginName ) {
129 KConfig input( fileName, KConfig::NoGlobals );
130 KConfigGroup cg(&input, "Global" );
131 QHash<QString, QString> MainMap;
132 MainMap.insert( "PluginName", cg.readEntry( "PluginName", pluginName ) );
133 MainMap.insert( "PluginNameLower", cg.readEntry( "PluginName", pluginName ).toLower() );
134 MainMap.insert( "Init", cg.readEntry( "Init", "" ) );
135 MainMap.insert( "Destroy", cg.readEntry( "Destroy", "" ) );
136 ts << classHeader << endl;
137
138 QStringList includes = cg.readEntry( "Includes", QStringList() );
139 QStringList classes = input.groupList();
140 classes.removeAll( "Global" );
141
142 foreach ( const QString &myInclude, classes )
143 includes += buildWidgetInclude( myInclude, input );
144
145 foreach ( const QString &myInclude, includes)
146 ts << "#include <" << myInclude << ">" << endl;
147
148 ts << QLatin1String("\n\n");
149
150 // Autogenerate widget defs here
151 foreach ( const QString &myClass, classes )
152 ts << buildWidgetClass( myClass, input, group ) << endl;
153
154 ts << buildCollClass( input, classes );
155
156}
157
158QString denamespace ( const QString &str ) {
159 QString denamespaced = str;
160 denamespaced.remove("::");
161 return denamespaced;
162}
163
164QString buildCollClass( KConfig &_input, const QStringList& classes ) {
165 KConfigGroup input(&_input, "Global");
166 QHash<QString, QString> defMap;
167 defMap.insert( "CollName", input.readEntry( "PluginName" ) );
168 QString genCode;
169
170 foreach ( const QString &myClass, classes )
171 {
172 genCode += QString("\t\tm_plugins.append( new %1(this) );\n").arg(denamespace( myClass ) +"Plugin");
173 }
174
175 defMap.insert( "CollectionAdd", genCode );
176
177 QString str = KMacroExpander::expandMacros(collClassDef, defMap);
178 str += KMacroExpander::expandMacros(collClassImpl, defMap);
179 return str;
180}
181
182QString buildWidgetClass( const QString &name, KConfig &_input, const QString &group ) {
183 KConfigGroup input(&_input, name);
184 QHash<QString, QString> defMap;
185
186 defMap.insert( "Group", input.readEntry( "Group", group ).replace( '\"', "\\\"" ) );
187 defMap.insert( "IconSet", input.readEntry( "IconSet", QString(name.toLower() + ".png") ).replace( ':', '_' ) );
188 defMap.insert( "Pixmap", name.toLower().replace( ':', '_' ) + "_xpm" );
189 defMap.insert( "IncludeFile", input.readEntry( "IncludeFile", QString(name.toLower() + ".h") ).remove( ':' ) );
190 defMap.insert( "ToolTip", input.readEntry( "ToolTip", QString(name + " Widget") ).replace( '\"', "\\\"" ) );
191 defMap.insert( "WhatsThis", input.readEntry( "WhatsThis", QString(name + " Widget") ).replace( '\"', "\\\"" ) );
192 defMap.insert( "IsContainer", input.readEntry( "IsContainer", "false" ) );
193 defMap.insert( "IconName", input.readEntry( "IconName", QString::fromLatin1(":/pics/%1.png").arg( denamespace( name ).toLower() ) ) );
194 defMap.insert( "Class", name );
195 defMap.insert( "PluginName", denamespace( name ) + QLatin1String( "Plugin" ) );
196
197 // FIXME: ### make this more useful, i.e. outsource to separate file
198 QString domXml = input.readEntry("DomXML", QString());
199 // If domXml is empty then we shoud call base class function
200 if ( domXml.isEmpty() ) {
201 domXml = QLatin1String("QDesignerCustomWidgetInterface::domXml()");
202 }
203 else {
204 // Wrap domXml value into QLatin1String
205 domXml = QString(QLatin1String("QLatin1String(\"%1\")")).arg(domXml.replace( '\"', "\\\"" ));
206 }
207 defMap.insert( "DomXml", domXml );
208 defMap.insert( "CodeTemplate", input.readEntry( "CodeTemplate" ) );
209 defMap.insert( "CreateWidget", input.readEntry( "CreateWidget",
210 QString( "\n\t\treturn new %1%2;" )
211 .arg( input.readEntry( "ImplClass", name ) )
212 .arg( input.readEntry( "ConstructorArgs", "( parent )" ) ) ) );
213 defMap.insert( "Initialize", input.readEntry( "Initialize", "\n\t\tQ_UNUSED(core);\n\t\tif (mInitialized) return;\n\t\tmInitialized=true;" ) );
214
215 return KMacroExpander::expandMacros( classDef, defMap );
216}
217
218QString buildWidgetInclude( const QString &name, KConfig &_input ) {
219 KConfigGroup input(&_input, name);
220 return input.readEntry( "IncludeFile", QString(name.toLower() + ".h") );
221}
222