* Add require 'khtml' statements
[kdebindings.git] / kalyptus / kalyptusCxxToKimono.pm
blob7fddd2c52b97213224936bd6fdd4e3bc33846b8a
1 #***************************************************************************
2 # kalyptusCxxToKimono.pm - Generates *.cs files for a Custom RealProxy
3 # based smoke adaptor
4 # -------------------
5 # begin : Thurs Feb 19 12:00:00 2004
6 # copyright : (C) 2004, Richard Dale. All Rights Reserved.
7 # email : Richard_Dale@tipitina.demon.co.uk
8 # author : Richard Dale, based on the SMOKE generation code
9 #***************************************************************************/
11 #/***************************************************************************
12 # * *
13 # * This program is free software; you can redistribute it and/or modify *
14 # * it under the terms of the GNU General Public License as published by *
15 # * the Free Software Foundation; either version 2 of the License, or *
16 # * (at your option) any later version. *
17 # * *
18 #***************************************************************************/
20 package kalyptusCxxToKimono;
22 use File::Path;
23 use File::Basename;
25 use Carp;
26 use Ast;
27 use kdocAstUtil;
28 use kdocUtil;
29 use Iter;
30 use kalyptusDataDict;
32 use strict;
33 no strict "subs";
35 use vars qw/
36 $libname $rootnode $outputdir $opt $debug
37 $methodNumber
38 %builtins %typeunion %allMethods %allTypes %enumValueToType %typedeflist %maptypeslist %arraytypeslist %mungedTypeMap %csharpImports
39 %skippedClasses %excludeClasses %partial_classes %operatorNames %new_classidx %interfacemap %iterator_interfacemap *CLASS /;
41 BEGIN
44 # Types supported by the StackItem union
45 # Key: C++ type Value: Union field of that type
46 %typeunion = (
47 'void*' => 's_voidp',
48 'bool' => 's_bool',
49 'char' => 's_char',
50 'uchar' => 's_uchar',
51 'short' => 's_short',
52 'ushort' => 's_ushort',
53 'int' => 's_int',
54 'uint' => 's_uint',
55 'long' => 's_long',
56 'ulong' => 's_ulong',
57 'float' => 's_float',
58 'double' => 's_double',
59 'enum' => 's_enum',
60 'class' => 's_class'
63 # Mapping for iterproto, when making up the munged method names
64 %mungedTypeMap = (
65 'QString' => '$',
66 'QString*' => '$',
67 'QString&' => '$',
68 'QCString' => '$',
69 'QCString*' => '$',
70 'QCString&' => '$',
71 'QDBusObjectPath' => '$',
72 'QDBusObjectPath*' => '$',
73 'QDBusObjectPath&' => '$',
74 'QDBusSignature' => '$',
75 'QDBusSignature*' => '$',
76 'QDBusSignature&' => '$',
77 'char*' => '$',
78 'QCOORD*' => '?',
79 'QRgb*' => '?',
80 'Q_UINT64' => '$',
81 'Q_INT64' => '$',
82 'Q_LLONG' => '$',
83 'quint64' => '$',
84 'qint64' => '$',
85 'long long' => '$',
86 'qulonglong' => '$',
87 'WId' => '$',
88 'Q_PID' => '$',
89 'KMimeType::Ptr' => '#',
90 'KMimeType::Ptr&' => '#',
91 'KServiceGroup::Ptr' => '#',
92 'KServiceGroup::Ptr&' => '#',
93 'KService::Ptr' => '#',
94 'KService::Ptr&' => '#',
95 'KServiceType::Ptr' => '#',
96 'KServiceType::Ptr&' => '#',
97 'KSharedConfig::Ptr' => '#',
98 'KSharedConfig::Ptr&' => '#',
99 'KSharedConfigPtr' => '#',
100 'KSharedConfigPtr&' => '#',
101 'KSharedPtr<KConfigBackend>' => '#',
102 'KSharedPtr<KConfigBackend>&' => '#',
103 'KSycocaEntry::Ptr' => '#',
104 'KSycocaEntry::Ptr&' => '#',
105 'Plasma::PackageStructure::Ptr' => '#',
106 'Plasma::PackageStructure::Ptr&' => '#',
109 # Yes some of this is in kalyptusDataDict's ctypemap
110 # but that one would need to be separated (builtins vs normal classes)
111 %typedeflist =
113 'GLenum' => 'int',
114 'GLint' => 'int',
115 'GLuint' => 'uint',
116 'ksocklen_t' => 'uint',
117 'mode_t' => 'long',
118 'MSG*' => 'void*',
119 'pid_t' => 'int',
120 'QCOORD' => 'int',
121 'QImageReader::ImageReaderError' => 'int',
122 'qint16' => 'short',
123 'Q_INT16' => 'short',
124 'qint32' => 'int',
125 'qint32&' => 'int',
126 'Q_INT32' => 'int',
127 'qint8' => 'char',
128 'Q_INT8' => 'char',
129 'Q_LONG' => 'long',
130 'qreal' => 'double',
131 'QRgb' => 'uint',
132 'Qt::HANDLE' => 'uint',
133 'QTSMFI' => 'int',
134 'Qt::WFlags' => 'uint',
135 'Qt::WState' => 'int',
136 'quint16' => 'ushort',
137 'Q_UINT16' => 'ushort',
138 'quint32' => 'uint',
139 'Q_UINT32' => 'uint',
140 'quint8' => 'ushort',
141 'Q_UINT8' => 'ushort',
142 'Q_ULONG' => 'long',
143 'short int' => 'short',
144 'signed char' => 'char',
145 'signed' => 'int',
146 'signed int' => 'int',
147 'signed long int' => 'long',
148 'signed long' => 'long',
149 'signed short' => 'short',
150 'size_t' => 'int',
151 'size_type' => 'int', # QSqlRecordInfo
152 'time_t' => 'int',
153 'unsigned char' => 'ushort',
154 'unsigned int' => 'uint',
155 'unsigned long int' => 'ulong',
156 'unsigned long' => 'ulong',
157 'unsigned short int' => 'ushort',
158 'unsigned short' => 'ushort',
159 'unsigned' => 'uint',
160 'void(* )()' => 'void*',
161 'void (*)(void* )' => 'void*',
162 'WState' => 'int',
163 'Plasma::PackageStructure::Ptr' => 'Plasma.PackageStructure',
164 'KService::Ptr' => 'KService',
165 'KSharedConfig::Ptr' => 'KSharedConfig',
166 'KSharedConfigPtr' => 'KSharedConfig',
167 'AnimId' => 'int',
168 'Plasma::Phase::AnimId' => 'int',
169 'KIO::filesize_t' => 'long'
172 # Some classes need extra info in addition to the autogenerated code.
173 # So they are split into two sources FooBar.cs and FooBarExtras.cs
174 # with the 'partial' modifier in the class definition
175 %partial_classes =
177 'KConfigGroup' => '1',
178 'KCmdLineArgs' => '1',
179 'QAbstractItemModel' => '1',
180 'QApplication' => '1',
181 'QBrush' => '1',
182 'QByteArray' => '1',
183 'QColor' => '1',
184 'QCoreApplication' => '1',
185 'QCursor' => '1',
186 'QDBusConnectionInterface' => '1',
187 'QIcon' => '1',
188 'QKeySequence' => '1',
189 'QLineF' => '1',
190 'QModelIndex' => '1',
191 'QObject' => '1',
192 'QPen' => '1',
193 'QPointF' => '1',
194 'QPolygon' => '1',
195 'QPolygonF' => '1',
196 'QRectF' => '1',
197 'QRegion' => '1',
198 'QSizeF' => '1',
199 'QSqlQueryModel' => '1',
200 'QStringListModel' => '1',
201 'QTransform' => '1',
202 'Qt' => '1',
203 'QUrl' => '1',
204 'QVariant' => '1',
207 %operatorNames =
209 'operator^' => 'op_xor',
210 'operator^=' => 'op_xor_assign',
211 'operator<' => 'op_lt',
212 'operator<<' => 'Write',
213 'operator<=' => 'op_lte',
214 'operator=' => 'op_assign',
215 'operator==' => 'op_equals',
216 'operator>' => 'op_gt',
217 'operator>=' => 'op_gte',
218 'operator>>' => 'Read',
219 'operator|' => 'op_or',
220 'operator|=' => 'op_or_assign',
221 'operator-' => 'op_minus',
222 'operator-=' => 'op_minus_assign',
223 'operator--' => 'op_decr',
224 'operator!' => 'op_not',
225 'operator!=' => 'op_not_equals',
226 'operator/' => 'op_div',
227 'operator/=' => 'op_div_assign',
228 'operator()' => 'op_expr',
229 'operator[]' => 'op_at',
230 'operator*' => 'op_mult',
231 'operator*=' => 'op_mult_assign',
232 'operator&' => 'op_and',
233 'operator&=' => 'op_and_assign',
234 'operator+' => 'op_plus',
235 'operator+=' => 'op_plus_assign',
236 'operator++' => 'op_incr',
239 %maptypeslist =
241 'QMap<int, QVariant>' => 'Dictionary<int, QVariant>',
242 'QMap<int, QVariant>&' => 'Dictionary<int, QVariant>',
243 'QMap<QDate, QTextCharFormat>' => 'Dictionary<QDate, QTextCharFormat>',
244 'QMap<QDate, QTextCharFormat>&' => 'Dictionary<QDate, QTextCharFormat>',
245 'QMap<QString, QString>' => 'Dictionary<string, string>',
246 'QMap<QString, QString>&' => 'Dictionary<string, string>',
247 'QMap<QString, QVariant>' => 'Dictionary<string, QVariant>',
248 'QMap<QString, QVariant>&' => 'Dictionary<string, QVariant>',
249 'QMap<QString, int>&' => 'Dictionary<string, int>',
250 'QVariantMap&' => 'Dictionary<string, QVariant>',
251 'QMap<QString, QVariant::Type>' => 'Dictionary<string, QVariant.TypeOf>',
252 'Plasma::DataEngine::Data' => 'Dictionary<string, QVariant>',
253 'Plasma::DataEngine::Data&' => 'Dictionary<string, QVariant>',
254 'QHash<QString, DataContainer*>' => 'Dictionary<string, Plasma.DataContainer>',
255 'QHash<QUrl, Nepomuk::Variant>' => 'Dictionary<QUrl, Nepomuk.Variant>',
256 'Plasma::DataEngine::SourceDict' => 'Dictionary<string, Plasma.DataContainer>',
259 %arraytypeslist =
261 'Akonadi::AgentInstance::List' => 'List<Akonadi.AgentInstance>',
262 'Akonadi::AgentType::List' => 'List<Akonadi.AgentType>',
263 'Akonadi::Attribute::List' => 'List<Akonadi.Attribute>',
264 'Akonadi::Collection::List' => 'List<Akonadi.Collection>',
265 'Akonadi::Collection::List&' => 'List<Akonadi.Collection>',
266 'Akonadi::Item::List' => 'List<Akonadi.Item>',
267 'Akonadi::Item::List&' => 'List<Akonadi.Item>',
268 'Akonadi::Job::List' => 'List<Akonadi.Job>',
269 'Akonadi::Job::List&' => 'List<Akonadi.Job>',
270 'KCompletionMatches' => 'List<string>',
271 'KCompletionMatches*' => 'List<string>',
272 'KCompletionMatchesList' => 'List<List<string>>',
273 'KCompletionMatchesList&' => 'List<List<string>>',
274 'KCompletionMatchesList*' => 'List<List<string>>',
275 'KFileItemList' => 'List<KFileItem>',
276 'KFileItemList*' => 'List<KFileItem>',
277 'KFileItemList&' => 'List<KFileItem>',
278 'KNS::Entry::List' => 'List<KNS.Entry>',
279 'KPluginInfo::List' => 'List<KPluginInfo>',
280 'KService::List' => 'List<KService>',
281 'KServiceOfferList' => 'List<KServiceOffer>',
282 'KUrl::List' => 'List<KUrl>',
283 'KUrl::List*' => 'List<KUrl>',
284 'KUrl::List&' => 'List<KUrl>',
285 'KUrlList' => 'List<KUrl>',
286 'KUrlList&' => 'List<KUrl>',
287 'QFileInfoList' => 'List<QFileInfo>',
288 'QFileInfoList&' => 'List<QFileInfo>',
289 'QList<const char*>' => 'List<string>',
290 'QList<const char*>&' => 'List<string>',
291 'QList<double>' => 'List<double>',
292 'QList<double>&' => 'List<double>',
293 'QList<int>' => 'List<int>',
294 'QList<int>&' => 'List<int>',
295 'QList<uint>' => 'List<uint>',
296 'QList<uint>&' => 'List<uint>',
297 'QList<KAboutPerson>' => 'List<KAboutPerson>',
298 'QList<KAboutTranslator>' => 'List<KAboutTranslator>',
299 'QList<KActionCollection*>&' => 'List<KActionCollection>',
300 'QList<KAction*>' => 'List<KAction>',
301 'QList<KConfigDialogManager*>&' => 'List<KConfigDialogManager>',
302 'QList<KConfigSkeleton::ItemEnum::Choice>' => 'List<KConfigSkeleton.ItemEnum.Choice>',
303 'QList<KConfigSkeleton::ItemEnum::Choice>&' => 'List<KConfigSkeleton.ItemEnum.Choice>',
304 'QList<Choice>' => 'List<KConfigSkeleton.ItemEnum.Choice>',
305 'QList<Choice>&' => 'List<KConfigSkeleton.ItemEnum.Choice>',
306 'QList<KDataToolInfo>' => 'List<KDataToolInfo>',
307 'QList<KDataToolInfo>&' => 'List<KDataToolInfo>',
308 'QList<KConfigDialogManager*>' => 'List<KConfigDialogManager>',
309 'QList<KFileItem>' => 'List<KFileItem>',
310 'QList<KFileItem>&' => 'List<KFileItem>',
311 # 'QList<KIO::CopyInfo>&' => 'List<KIO.CopyInfo>',
312 'QList<KJob*>&' => 'List<KJob>',
313 'QList<KMainWindow*>' => 'List<KMainWindow>',
314 'QList<KMainWindow*>&' => 'List<KMainWindow>',
315 'QList<KMultiTabBarButton*>' => 'List<KMultiTabBarButton>',
316 'QList<KMultiTabBarTab*>' => 'List<KMultiTabBarTab>',
317 'QList<KParts::Part*>' => 'List<KParts.Part>',
318 'QList<KParts::Plugin*>' => 'List<KParts.Plugin>',
319 # 'QList<KParts::Plugin::PluginInfo>' => 'List<QXmlStreamNotationDeclaration>',
320 # 'QList<KParts::Plugin::PluginInfo>&' => 'List<QXmlStreamNotationDeclaration>',
321 'QList<KParts::ReadOnlyPart*>' => 'List<KParts.ReadOnlyPart>',
322 'QList<KPluginInfo>' => 'List<KPluginInfo>',
323 'QList<KPluginInfo>&' => 'List<KPluginInfo>',
324 'QList<KServiceOffer>&' => 'List<KServiceOffer>',
325 'QList<KSSLCertificate*>&' => 'List<KSSLCertificate>',
326 'QList<KToolBar*>' => 'List<KToolBar>',
327 'QList<KUrl>' => 'List<KUrl>',
328 'QList<KUrl>&' => 'List<KUrl>',
329 'QList<KUserGroup>' => 'List<KUserGroup>',
330 'QList<KUser>' => 'List<KUser>',
331 'QList<KUser>&' => 'List<KUser>',
332 'QList<KXMLGUIClient*>' => 'List<KXMLGUIClient>',
333 'QList<KXMLGUIClient*>&' => 'List<KXMLGUIClient>',
334 'QList<Plasma::Containment*>' => 'List<Plasma.Containment>',
335 'QList<Plasma::Containment*>&' => 'List<Plasma.Containment>',
336 'QList<Plasma::PlotColor>' => 'List<Plasma.PlotColor>',
337 'QList<Plasma::PlotColor>&' => 'List<Plasma.PlotColor>',
338 'QList<Plasma::SearchMatch*>' => 'List<Plasma.SearchMatch>',
339 'QList<Plasma::SearchMatch*>&' => 'List<Plasma.SearchMatch>',
340 'QList<Plasma::QueryMatch>' => 'List<Plasma.QueryMatch>',
341 'QList<Plasma::QueryMatch>&' => 'List<Plasma.QueryMatch>',
342 'Plasma::Applet::List' => 'List<Plasma.Applet>',
343 'Plasma::AbstractRunner::List' => 'List<Plasma.AbstractRunner>',
344 'QList<QAbstractButton*>' => 'List<QAbstractButton>',
345 'QList<QActionGroup*>' => 'List<QAction>',
346 'QList<QAction*>' => 'List<QAction>',
347 'QList<QAction*>&' => 'List<QAction>',
348 'QList<QByteArray>' => 'List<QByteArray>',
349 'QList<QByteArray>*' => 'List<QByteArray>',
350 'QList<QByteArray>&' => 'List<QByteArray>',
351 'QList<QGraphicsItem*>' => 'List<QGraphicsItem>',
352 'QList<QGraphicsItem*>&' => 'List<QGraphicsItem>',
353 'QList<QGraphicsView*>' => 'List<QGraphicsView>',
354 'QList <QGraphicsView*>' => 'List<QGraphicsView>',
355 'QList<QHostAddress>' => 'List<QHostAddress>',
356 'QList<QHostAddress>&' => 'List<QHostAddress>',
357 # 'QList<QImageTextKeyLang>' => 'List<QImageTextKeyLang>',
358 'QList<QKeySequence>' => 'List<QKeySequence>',
359 'QList<QKeySequence>&' => 'List<QKeySequence>',
360 'QList<QListWidgetItem*>' => 'List<QListWidgetItem>',
361 'QList<QListWidgetItem*>&' => 'List<QListWidgetItem>',
362 'QList<QLocale::Country>' => 'List<QLocale.Country>',
363 'QList<QMdiSubWindow*>' => 'List<QMdiSubWindow>',
364 'QList<QModelIndex>' => 'List<QModelIndex>',
365 'QList<QModelIndex>&' => 'List<QModelIndex>',
366 'QList<QNetworkAddressEntry>' => 'List<QNetworkAddressEntry>',
367 'QList<QNetworkCookie>' => 'List<QNetworkCookie>',
368 'QList<QNetworkCookie>&' => 'List<QNetworkCookie>',
369 'QList<QNetworkInterface>' => 'List<QNetworkInterface>',
370 # These List types with doubles don't compile:
371 # 'QList<QPair<qreal, QPointF> >' => 'List<double, QPointF>',
372 'QList<QPair<qreal, QPointF> >' => 'List<QPair<double, QPointF>>',
373 'QList<QPair<qreal, qreal> >' => 'List<QPair<double, double>>',
374 # 'QList<QPair<qreal, qreal> >' => 'List<QPair<double, double>>',
375 'QList<QPair<QString, QString> >' => 'List<QPair<string, string>>',
376 'QList<QPair<QString, QString> >&' => 'List<QPair<string, string>>',
377 'QList<QPixmap>' => 'List<QPixmap>',
378 'QList<QPolygonF>' => 'List<QPolygonF>',
379 'QList<QPrinterInfo>' => 'List<QPrinterInfo>',
380 'QList<qreal>' => 'List<double>',
381 'QList<QRectF>' => 'List<QRectF>',
382 'QList<QRectF>&' => 'List<QRectF>',
383 'QList<QSslCertificate>' => 'List<QSslCertificate>',
384 'QList<QSslCertificate>&' => 'List<QSslCertificate>',
385 'QList<QSslCipher>' => 'List<QSslCipher>',
386 'QList<QSslCipher>&' => 'List<QSslCipher>',
387 'QList<QSslError>' => 'List<QSslError>',
388 'QList<QSslError>&' => 'List<QSslError>',
389 'QList<QStandardItem*>' => 'List<QStandardItem>',
390 'QList<QStandardItem*>&' => 'List<QStandardItem>',
391 'QList<QStringList>' => 'List<List<string>>',
392 'QList<QTableWidgetItem*>' => 'List<QTableWidgetItem>',
393 'QList<QTableWidgetItem*>&' => 'List<QTableWidgetItem>',
394 'QList<QTableWidgetSelectionRange>' => 'List<QTableWidgetSelectionRange>',
395 'QList<QTextBlock>' => 'List<QTextBlock>',
396 'QList<QTextFrame*>' => 'List<QTextFrame>',
397 # 'QList<QTextLayout::FormatRange>' => 'List<QTextLayout.FormatRange>',
398 # 'QList<QTextLayout::FormatRange>&' => 'List<QTextLayout.FormatRange>',
399 'QList<QTreeWidgetItem*>' => 'List<QTreeWidgetItem>',
400 'QList<QTreeWidgetItem*>&' => 'List<QTreeWidgetItem>',
401 'QList<QTreeWidget*>' => 'List<QTreeWidget>',
402 'QList<QTreeWidget*>&' => 'List<QTreeWidget>',
403 'QList<QUndoStack*>' => 'List<QUndoStack>',
404 'QList<QUndoStack*>&' => 'List<QUndoStack>',
405 'QList<QUrl>' => 'List<QUrl>',
406 'QList<QUrl>&' => 'List<QUrl>',
407 'QList<QVariant>' => 'List<QVariant>',
408 'QList<QVariant>&' => 'List<QVariant>',
409 'QList<QWidget*>' => 'List<QWidget>',
410 'QList<QWidget*>&' => 'List<QWidget>',
411 'QList<QWebFrame*>' => 'List<QWebFrame>',
412 'QList<QWebHistoryItem>' => 'List<QWebHistoryItem>',
413 'QList<QWizard::WizardButton>&' => 'List<QWizard.WizardButton>',
414 'QModelIndexList' => 'List<QModelIndex>',
415 'QModelIndexList&' => 'List<QModelIndex>',
416 'QObjectList' => 'List<QObject>',
417 'QObjectList&' => 'List<QObject>',
418 'QStringList' => 'List<string>',
419 'QStringList*' => 'List<string>',
420 'QStringList&' => 'List<string>',
421 'QVariantList' => 'List<QVariant>',
422 'QVariantList*' => 'List<QVariant>',
423 'QVariantList&' => 'List<QVariant>',
424 'QVector<QAbstractTextDocumentLayout::Selection>' => 'List<QAbstractTextDocumentLayout.Selection>',
425 'QVector<Selection>' => 'List<QAbstractTextDocumentLayout.Selection>',
426 'QVector<QColor>' => 'List<QColor>',
427 'QVector<QColor>&' => 'List<QColor>',
428 'QVector<QLineF>' => 'List<QLineF>',
429 'QVector<QLineF>&' => 'List<QLineF>',
430 'QVector<QLine>' => 'List<QLine>',
431 'QVector<QLine>&' => 'List<QLine>',
432 'QVector<QPointF>' => 'List<QPointF>',
433 'QVector<QPointF>&' => 'List<QPointF>',
434 'QVector<QPoint>' => 'List<QPoint>',
435 'QVector<QPoint>&' => 'List<QPoint>',
436 'QVector<qreal>' => 'List<double>',
437 'QVector<qreal>&' => 'List<double>',
438 'QVector<QRectF>' => 'List<QRectF>',
439 'QVector<QRectF>&' => 'List<QRectF>',
440 'QVector<QRect>' => 'List<QRect>',
441 'QVector<QRect>&' => 'List<QRect>',
442 'QVector<QRgb>' => 'List<uint>',
443 'QVector<QRgb>&' => 'List<uint>',
444 'QVector<QTextFormat>' => 'List<QTextFormat>',
445 'QVector<QTextFormat>&' => 'List<QTextFormat>',
446 'QVector<QTextLength>' => 'List<QTextLength>',
447 'QVector<QTextLength>&' => 'List<QTextLength>',
448 'QVector<QVariant>' => 'List<QVariant>',
449 'QVector<QVariant>&' => 'List<QVariant>',
450 'QWidgetList' => 'List<QWidget>',
451 'QWidgetList&' => 'List<QWidget>',
452 'QXmlStreamEntityDeclarations' => 'List<QXmlStreamEntityDeclaration>',
453 'QXmlStreamNamespaceDeclarations' => 'List<QXmlStreamNamespaceDeclaration>',
454 'QXmlStreamNotationDeclarations' => 'List<QXmlStreamNotationDeclaration>',
457 %interfacemap = (
458 'KBookmarkActionInterface' => 'IKBookmarkAction',
459 'KCompletionBase' => 'IKCompletionBase',
460 'KDevCore' => 'IKDevCore',
461 'KDirNotify' => 'IKDirNotify',
462 'KFileView' => 'IKFileView',
463 'KIO.SlaveBase' => 'KIO.ISlaveBase',
464 'KMessageHandler' => 'IKMessageHandler',
465 'KParts.PartBase' => 'KParts.IPartBase',
466 'KXMLGUIBuilder' => 'IKXMLGUIBuilder',
467 'KXMLGUIClient' => 'IKXMLGUIClient',
468 'PartBase' => 'IPartBase',
469 'QGraphicsItem' => 'IQGraphicsItem',
470 'QGraphicsLayoutItem' => 'IQGraphicsLayoutItem',
471 'QLayoutItem' => 'IQLayoutItem',
472 'QMimeSource' => 'IQMimeSource',
473 'QPaintDevice' => 'IQPaintDevice',
474 'QwAbsSpriteFieldView' => 'IQwAbsSpriteFieldView',
475 'QwtAbstractScale' => 'IQwtAbstractScale',
476 'QwtDoubleRange' => 'IQwtDoubleRange',
477 'QwtEventPattern' => 'IQwtEventPattern',
478 'QwtPlotDict' => 'IQwtPlotDict',
479 'QXmlContentHandler' => 'IQXmlContentHandler',
480 'QXmlDeclHandler' => 'IQXmlDeclHandler',
481 'QXmlDTDHandler' => 'IQXmlDTDHandler',
482 'QXmlEntityResolver' => 'IQXmlEntityResolver',
483 'QXmlErrorHandler' => 'IQXmlErrorHandler',
484 'SlaveBase' => 'ISlaveBase',
485 'Soprano.Error.ErrorCache' => 'Soprano.Error.IErrorCache',
486 'ErrorCache' => 'IErrorCache',
489 # Mono 1.2.4 doesn't seem to compile IEnumerable classes, so comment these
490 # out for now
491 %iterator_interfacemap = (
492 # 'Soprano::QueryResultIterator' => 'IEnumerable<Soprano.BindingSet>',
493 # 'Soprano::StatementIterator' => 'IEnumerable<Soprano.Statement>',
494 # 'Soprano::NodeIterator' => 'IEnumerable<Soprano.Node>',
495 # 'Soprano::DBusQueryResultIterator' => 'IEnumerable<Soprano.BindingSet>',
496 # 'Soprano::DBusStatementIterator' => 'IEnumerable<Soprano.Statement>',
497 # 'Soprano::DBusNodeIterator' => 'IEnumerable<Soprano.Node>',
502 sub csharpImport($)
504 my ( $classname ) = @_;
505 my $classname_ptr = $classname . "*";
506 if ( cplusplusToCSharp($classname_ptr) eq "" or $classname eq $main::globalSpaceClassName ) {
507 return "";
508 } elsif ( cplusplusToCSharp($classname_ptr) eq "ArrayList" ) {
509 return "System.Collections";
510 } elsif ( cplusplusToCSharp($classname_ptr) =~ /^List</ ) {
511 return "System.Collections.Generic";
512 } elsif ( cplusplusToCSharp($classname_ptr) eq "StringBuilder" ) {
513 return "";
514 } elsif ( cplusplusToCSharp($classname_ptr) eq "string" ) {
515 return "";
516 } elsif ( cplusplusToCSharp($classname_ptr) eq "string[][]" ) {
517 return "";
518 # } elsif ( cplusplusToCSharp($classname_ptr) eq "string[]" ) {
519 # return "";
520 } elsif ( cplusplusToCSharp($classname_ptr) =~ /^[a-z]/ ) {
521 return "";
523 return "";
526 sub cplusplusToCSharp
528 my ( $cplusplusType ) = @_;
529 my $isConst = ($cplusplusType =~ /const / or $cplusplusType !~ /[*&]/ ? 1 : 0);
530 $cplusplusType =~ s/const //;
531 $cplusplusType =~ s/^signed//;
532 my $className = $cplusplusType;
533 $className =~ s/[*&]//;
535 if ( $cplusplusType =~ /void\*|KDateTime::Spec&?$|K3Icon|KHTMLPart::PageSecurity|EditMode|QNetworkProtocolFactoryBase|QDomNodePrivate|QSqlDriverCreatorBase|QSqlFieldInfoList|QObjectUserData|QUObject|QTextParag|QWidgetMapper|QMemArray<int>|QLayoutIterator|QAuBucket|QUnknownInterface|QConnectionList/ ) {
536 return ""; # Unsupported type
537 } elsif ( $cplusplusType =~ /bool/ && kalyptusDataDict::ctypemap($cplusplusType) eq "int" ) {
538 return "bool";
539 } elsif ( $cplusplusType =~ /bool\s*[*&]/ ) {
540 # return "bool";
541 return "ref bool";
542 } elsif ( $cplusplusType =~ /^long$|^qint64$/) {
543 return "long";
544 } elsif ( $cplusplusType =~ /^ulong$|^quint64$/) {
545 return "ulong";
546 } elsif ( $cplusplusType eq 'qlonglong') {
547 return "long";
548 } elsif ( $cplusplusType eq 'qulonglong') {
549 return "ulong";
550 } elsif ( $cplusplusType =~ /^QPair<(.*), (.*)>/) {
551 my $generic1 = cplusplusToCSharp($1);
552 my $generic2 = cplusplusToCSharp($2);
553 return '' if ($generic1 eq '' || $generic2 eq '');
554 return "QPair<$generic2, $generic1>";
555 } elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^void\s*\*/ ) {
556 return "int";
557 } elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^qt_QIntValueList\*/ )
559 return "int[]";
560 } elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^\s*(unsigned )?int\s*\*/
561 || $cplusplusType =~ /^int[*&]$/ )
563 # return "int";
564 return "ref int";
565 } elsif ( $cplusplusType =~ /qreal[*&]$/ )
567 # return "double";
568 return "ref double";
569 } elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^\s*double\s*\*/ ) {
570 # return "double";
571 return "ref double";
572 } elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /^\s*(unsigned )?short\s*\*/ ) {
573 # return "short";
574 return "ref short";
575 } elsif ( $maptypeslist{$cplusplusType} ) {
576 return $maptypeslist{$cplusplusType};
577 } elsif ( $arraytypeslist{$cplusplusType} ) {
578 return $arraytypeslist{$cplusplusType};
579 } elsif ( $typedeflist{$cplusplusType} ) {
580 return $typedeflist{$cplusplusType};
581 } elsif ( $cplusplusType =~ /^QList<(.*)>/ ) {
582 my $generic = cplusplusToCSharp($1);
583 return '' if ($generic eq '');
584 return "List<$generic>";
585 } elsif ( $cplusplusType =~ /^QVector<(.*)>/ ) {
586 my $generic = cplusplusToCSharp($1);
587 return '' if ($generic eq '');
588 return "List<$generic>";
589 } elsif ( $cplusplusType =~ /uchar\s*\*/ ) {
590 return "char[]";
591 } elsif ( $cplusplusType =~ /uchar/ ) {
592 return "ushort";
593 } elsif ( $cplusplusType =~ /QC?String/ and !$isConst ) {
594 return "StringBuilder"
595 } elsif ( $cplusplusType =~ /^[^<]*QString/
596 || $cplusplusType =~ /QCString/
597 || $cplusplusType =~ /^(const )?char\s*\*$/
598 || kalyptusDataDict::ctypemap($cplusplusType) =~ /^(const )?char\s*\*/ ) {
599 return "string"
600 # } elsif ( $cplusplusType =~ /QChar\s*[&\*]?/ || $cplusplusType =~ /^char$/ ) {
601 # return "char"
602 } elsif ( $cplusplusType =~ /QDBusObjectPath/ ) {
603 return "QDBusObjectPath"
604 } elsif ( $cplusplusType =~ /QDBusSignature/ ) {
605 return "QDBusSignature"
606 } elsif ( $cplusplusType =~ /QDBusVariant/ ) {
607 return "QDBusVariant"
608 } elsif ( $cplusplusType =~ /QPaintDevice/ ) {
609 return "IQPaintDevice"
610 } elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /unsigned char/ ) {
611 return "ushort";
612 } elsif ( $typedeflist{$cplusplusType} =~ /ulong/ || $cplusplusType eq 'ulong' ) {
613 return "ulong";
614 } elsif ( $typedeflist{$cplusplusType} =~ /long/ || $cplusplusType eq 'long' ) {
615 return "long";
616 } elsif ( $typedeflist{$cplusplusType} =~ /uint/ || $cplusplusType eq 'uint' ) {
617 return "uint";
618 } elsif ( $typedeflist{$cplusplusType} =~ /int/ || $cplusplusType eq 'int' ) {
619 return "int";
620 } elsif ( $typedeflist{$cplusplusType} =~ /ushort/ || $cplusplusType eq 'ushort' ) {
621 return "ushort";
622 } elsif ( $typedeflist{$cplusplusType} =~ /short/ || $cplusplusType eq 'short') {
623 return "short";
624 } elsif ( $typedeflist{$cplusplusType} =~ /float/ || $cplusplusType eq 'float' ) {
625 return "float";
626 } elsif ( $typedeflist{$cplusplusType} =~ /double/ || $cplusplusType eq 'double') {
627 return "double";
628 } elsif ( kalyptusDataDict::ctypemap($cplusplusType) =~ /(unsigned )(.*)/ ) {
629 return "u" . $2;
630 } else {
631 my $node;
632 my $item;
633 if ($className =~ /^(\w+)::(\w+)::(\w+)::(\w+)$/) {
634 $node = kdocAstUtil::findRef( $rootnode, $1 );
635 if (defined $node) {
636 $node = kdocAstUtil::findRef( $node, $2 );
637 if (defined $node) {
638 $node = kdocAstUtil::findRef( $node, $3 );
639 $item = kdocAstUtil::findRef( $node, $4 ) if defined $node;
640 if (defined $item && $item->{NodeType} eq 'enum') {
641 if ($4 eq 'Type') {
642 return "$1.$2.$3.TypeOf";
643 } else {
644 return "$1.$2.$3.$4";
646 } elsif (defined $item && ($item->{NodeType} eq 'class' || $item->{NodeType} eq 'struct')) {
647 return $skippedClasses{$className} ? "" : "$1.$2.$3.$4";
651 } elsif ($className =~ /^(\w+)::(\w+)::(\w+)$/) {
652 $node = kdocAstUtil::findRef( $rootnode, $1 );
653 if (defined $node) {
654 $node = kdocAstUtil::findRef( $node, $2 );
655 $item = kdocAstUtil::findRef( $node, $3 ) if defined $node;
656 if (defined $item && $item->{NodeType} eq 'enum') {
657 if ($3 eq 'Type') {
658 return "$1.$2.TypeOf";
659 } else {
660 return "$1.$2.$3";
662 } elsif (defined $item && ($item->{NodeType} eq 'class' || $item->{NodeType} eq 'struct')) {
663 return $skippedClasses{$className} ? "" : "$1.$2.$3";
666 } elsif ($className =~ /^(\w+)::(\w+)$/) {
667 $node = kdocAstUtil::findRef( $rootnode, $1 );
668 $item = kdocAstUtil::findRef( $node, $2 ) if defined $node;
669 if (defined $item && $item->{NodeType} eq 'enum') {
670 if ($2 eq 'Type') {
671 return "$1.TypeOf";
672 } else {
673 return "$1.$2";
675 } elsif (defined $item && ($item->{NodeType} eq 'class' || $item->{NodeType} eq 'struct')) {
676 return $skippedClasses{$className} ? "" : "$1.$2";
680 if ($className =~ /^\w+$/) {
681 $item = kdocAstUtil::findRef( $rootnode, $className );
682 if (defined $item && ($item->{NodeType} eq 'class' || $item->{NodeType} eq 'struct')) {
683 return $skippedClasses{$className} ? "" : $className;
686 return kalyptusDataDict::ctypemap($cplusplusType);;
691 sub writeDoc
693 ( $libname, $rootnode, $outputdir, $opt ) = @_;
695 print STDERR "Starting writeDoc for $libname...\n";
697 # if no classlist is given, process all classes
698 if ($main::classlist) {
699 my %includeClasses;
700 open DAT, "$main::classlist";
701 foreach my $class (<DAT>) {
702 chop($class);
703 $includeClasses{$class} = 1;
705 close DAT;
707 Iter::LocalCompounds( $rootnode, sub {
708 my $classNode = shift;
709 my $className = join( '::', kdocAstUtil::heritage($classNode) );
710 $excludeClasses{$className} = 1 unless defined $includeClasses{$className};
714 $debug = $main::debuggen;
716 if (!$main::smokeInvocation) {
717 $main::smokeInvocation = "SmokeInvocation"
720 mkpath( $outputdir ) unless -f $outputdir;
722 print STDERR "Preparsing...\n";
724 # Preparse flags
725 Iter::LocalCompounds( $rootnode, sub { preParseFlags( shift ); } );
727 # Preparse everything, to prepare some additional data in the classes and methods
728 Iter::LocalCompounds( $rootnode, sub { preParseClass( shift ); } );
730 # Have a look at each class again, to propagate CanBeCopied
731 Iter::LocalCompounds( $rootnode, sub { propagateCanBeCopied( shift ); } );
733 # Write out smokedata.cpp
734 writeSmokeDataFile($rootnode);
736 print STDERR "Writing *.cs...\n";
738 my @classlist;
739 push @classlist, ""; # Prepend empty item for "no class"
740 my %enumclasslist;
741 Iter::LocalCompounds( $rootnode, sub {
742 my $classNode = $_[0];
743 my $className = join( "::", kdocAstUtil::heritage($classNode) );
745 return if $classNode->{NodeType} eq 'namespace';
747 push @classlist, $className;
748 $enumclasslist{$className}++ if keys %{$classNode->{enumerations}};
749 $classNode->{ClassIndex} = $#classlist;
750 # addImportForClass( $classNode, \%allImports, undef );
751 } );
753 %new_classidx = do { my $i = 0; map { $_ => $i++ } @classlist };
755 # Generate *cs file for each class
756 Iter::LocalCompounds( $rootnode, sub {
757 my $classNode = $_[0];
758 my $className = join( "::", kdocAstUtil::heritage($classNode) );
759 return if defined($excludeClasses{$className});
760 writeClassDoc( shift );
761 } );
763 print STDERR "Done.\n";
766 =head2 preParseFlags
767 Called for each class, looks for Q_DECLARE_FLAGS, and maps them to uints
768 =cut
769 sub preParseFlags
771 my( $classNode ) = @_;
772 my $className = join( "::", kdocAstUtil::heritage($classNode) );
774 Iter::MembersByType ( $classNode, undef,
775 sub {
776 my( $classNode, $m ) = @_;
778 if ( $m->{NodeType} eq 'flags' ) {
779 my $fullFlagsName = $className."::".$m->{astNodeName};
781 if (exists $typedeflist{$fullFlagsName}) {
782 print("typemap for $fullFlagsName exists\n");
785 $typedeflist{$fullFlagsName} = 'uint';
786 registerType( $fullFlagsName );
788 }, undef );
792 =head2 preParseClass
793 Called for each class
794 =cut
795 sub preParseClass
797 my( $classNode ) = @_;
798 my $className = join( "::", kdocAstUtil::heritage($classNode) );
800 if ( $classNode->{Deprecated}
801 || $classNode->{NodeType} eq 'union'
802 || $#{$classNode->{Kids}} < 0
803 || $classNode->{Access} eq "private"
804 || $classNode->{Access} eq "protected" # e.g. QPixmap::QPixmapData
805 || $className =~ /.*Private$/ # Ignore any classes which aren't for public consumption
806 || $className =~ /.*Impl$/
807 || $className =~ /.*Internal.*/
808 || exists $classNode->{Tmpl}
809 || $className eq 'KAccelGen'
810 || $className eq 'KDateTime::Spec'
811 || $className eq 'KDEDModule'
812 || $className eq 'KDialogButtonBox'
813 || $className eq 'KDirOperator'
814 || $className eq 'KDirSelectDialog'
815 || $className eq 'KEditListBox::CustomEditor'
816 || $className eq 'KFileFilterCombo'
817 || $className eq 'KFileMetaInfo'
818 || $className eq 'KFileMetaInfoGroup'
819 || $className eq 'KFileTreeBranch'
820 || $className eq 'KFileView'
821 || $className eq 'KFileViewSignaler'
822 || $className eq 'KGlobalSettings::KMouseSettings'
823 || $className eq 'khtml'
824 || $className eq 'khtml::DrawContentsEvent'
825 || $className eq 'khtml::MouseDoubleClickEvent'
826 || $className eq 'khtml::MouseEvent'
827 || $className eq 'khtml::MouseMoveEvent'
828 || $className eq 'khtml::MousePressEvent'
829 || $className eq 'khtml::MouseReleaseEvent'
830 || $className eq 'KIconTheme'
831 || $className eq 'KIO::NetRC'
832 || $className eq 'KMimeTypeChooserDialog'
833 || $className eq 'KParts::ComponentFactory'
834 || $className eq 'KParts::Plugin::PluginInfo'
835 || $className eq 'KProtocolInfo::ExtraField'
836 || $className eq 'KServiceTypeProfile'
837 || $className eq 'KSettings::PluginPage'
838 || $className eq 'KTimeZone::Transition'
839 || $className eq 'KTipDatabase'
840 || $className eq 'KTzfileTimeZoneData'
841 || $className eq 'KUrl::List'
842 || $className eq 'KXMLGUIClient::StateChange'
843 || $className eq 'Soprano::Backend'
844 || $className eq 'Soprano::QueryResultIteratorBackend'
845 || $className eq 'Soprano::BackendSetting'
846 || $className eq 'QAbstractTextDocumentLayout::PaintContext'
847 || $className eq 'QAbstractTextDocumentLayout::Selection'
848 || $className eq 'QAbstractUndoItem'
849 || $className eq 'QAccessibleBridgePlugin'
850 || $className eq 'QBrushData'
851 || $className eq 'QDBusObjectPath'
852 || $className eq 'QDBusSignature'
853 || $className eq 'QDBusVariant'
854 || $className eq 'QDebug'
855 || $className eq 'QImageTextKeyLang'
856 || $className eq 'QInputMethodEvent::Attribute'
857 || $className eq 'QIPv6Address'
858 || $className eq 'QLatin1String'
859 || $className eq 'QMap::const_iterator'
860 || $className eq 'QMapData'
861 || $className eq 'QMapData::Node'
862 || $className eq 'QMap::iterator'
863 || $className eq 'QMutex'
864 || $className eq 'QMutexLocker'
865 || $className eq 'QObjectData'
866 || $className eq 'QPainterPath::Element'
867 || $className eq 'QProxyModel'
868 || $className eq 'QReadLocker'
869 || $className eq 'QReadWriteLock'
870 || $className eq 'QSemaphore'
871 || $className eq 'QSharedData'
872 || $className eq 'QString'
873 || $className eq 'QStringList'
874 || $className eq 'QStyleOptionQ3DockWindow'
875 || $className eq 'QStyleOptionQ3ListView'
876 || $className eq 'QStyleOptionQ3ListViewItem'
877 || $className eq 'QSysInfo'
878 || $className eq 'QTextCodec::ConverterState'
879 || $className eq 'QTextLayout::FormatRange'
880 || $className eq 'QTextStreamManipulator'
881 || $className eq 'QThread'
882 || $className eq 'QThreadStorageData'
883 || $className eq 'QUpdateLaterEvent'
884 || $className eq 'QVariant::Handler'
885 || $className eq 'QVariant::PrivateShared'
886 || $className eq 'QVariantComparisonHelper'
887 || $className eq 'QVectorData'
888 || $className eq 'QWaitCondition'
889 || $className eq 'QWidgetData'
890 || $className eq 'QWriteLocker'
891 || $className eq 'QX11Info' )
893 print STDERR "Skipping $className\n" if ($debug);
894 print STDERR "Skipping union $className\n" if ( $classNode->{NodeType} eq 'union');
895 $skippedClasses{$className} = 1;
896 delete $classNode->{Compound}; # Cheat, to get it excluded from Iter::LocalCompounds
897 return;
900 my $signalCount = 0;
901 my $eventHandlerCount = 0;
902 my $defaultConstructor = 'none'; # none, public, protected or private. 'none' will become 'public'.
903 my $constructorCount = 0; # total count of _all_ ctors
904 # If there are ctors, we need at least one public/protected one to instanciate the class
905 my $hasPublicProtectedConstructor = 0;
906 # We need a public dtor to destroy the object --- ### aren't protected dtors ok too ??
907 my $hasPublicDestructor = 1; # by default all classes have a public dtor!
908 #my $hasVirtualDestructor = 0;
909 my $hasDestructor = 0;
910 my $hasPrivatePureVirtual = 0;
911 my $hasCopyConstructor = 0;
912 my $hasPrivateCopyConstructor = 0;
913 # Note: no need for hasPureVirtuals. $classNode{Pure} has that.
915 if (defined $iterator_interfacemap{$className}) {
916 $partial_classes{$classNode->{astNodeName}} = 1;
919 my $doPrivate = $main::doPrivate;
920 $main::doPrivate = 1;
921 # Look at each class member (looking for methods and enums in particular)
922 Iter::MembersByType ( $classNode, undef,
923 sub {
925 my( $classNode, $m ) = @_;
926 my $name = $m->{astNodeName};
928 if( $m->{NodeType} eq "method" ) {
929 if ( $m->{ReturnType} eq 'typedef' # QFile's EncoderFn/DecoderFn callback, very badly parsed
931 $m->{NodeType} = 'deleted';
932 next;
935 print STDERR "preParseClass: looking at $className\::$name $m->{Params}\n" if ($debug);
937 if ( $name eq $classNode->{astNodeName} ) {
938 if ( $m->{ReturnType} =~ /~/ ) {
939 # A destructor
940 $hasPublicDestructor = 0 if $m->{Access} ne 'public';
941 #$hasVirtualDestructor = 1 if ( $m->{Flags} =~ "v" && $m->{Access} ne 'private' );
942 $hasDestructor = 1;
943 } else {
944 # A constructor
945 $constructorCount++;
946 $defaultConstructor = $m->{Access} if ( $m->{Params} eq '' );
947 $hasPublicProtectedConstructor = 1 if ( $m->{Access} ne 'private' );
949 # Copy constructor?
950 if ( $#{$m->{ParamList}} == 0 ) {
951 my $theArgType = @{$m->{ParamList}}[0]->{ArgType};
952 if ($theArgType =~ /$className\s*\&/) {
953 $hasCopyConstructor = 1;
954 $hasPrivateCopyConstructor = 1 if ( $m->{Access} eq 'private' );
957 # Hack the return type for constructors, since constructors return an object pointer
958 $m->{ReturnType} = $className."*";
962 if ( $name =~ /~$classNode->{astNodeName}/ && $m->{Access} ne "private" ) { # not used
963 $hasPublicDestructor = 0 if $m->{Access} ne 'public';
964 #$hasVirtualDestructor = 1 if ( $m->{Flags} =~ "v" );
965 $hasDestructor = 1;
968 if ( $m->{Flags} =~ "p" && $m->{Access} =~ /private/ ) {
969 $hasPrivatePureVirtual = 1; # ouch, can't inherit from that one
972 # All we want from private methods is to check for virtuals, nothing else
973 next if ( $m->{Access} =~ /private/ );
975 # Don't generate code for deprecated methods,
976 # or where the code won't compile/link for obscure reasons. Or even obvious reasons..
977 if ( $m->{Deprecated}
978 # Assume only Qt classes have tr() and trUtf8() in their Q_OBJECT macro
979 || ($classNode->{astNodeName} !~ /^Q/ and $name eq 'tr')
980 || ($classNode->{astNodeName} !~ /^Q/ and $name eq 'trUtf8')
981 || $m->{ReturnType} =~ /template/
982 || $m->{ReturnType} =~ /QT3_SUPPORT/
983 || $name eq 'qt_metacast'
984 || $name eq 'virtual_hook'
985 || $name eq 'handle'
986 || ($name eq 'qt_metacall')
987 || ($name eq 'metaObject')
988 || $name eq 'qWarning'
989 || $name eq 'qCritical'
990 || $name eq 'qDebug'
991 || $name eq 'finalize'
992 || ($m->{ReturnType} =~ /iterator/)
993 || ($classNode->{astNodeName} eq 'QApplication' and $name eq 'QApplication')
994 || ($classNode->{astNodeName} eq 'QCoreApplication' and $name eq 'QCoreApplication')
995 || ($classNode->{astNodeName} eq 'QBoxLayout' and $name eq 'spacing')
996 || ($classNode->{astNodeName} eq 'QBoxLayout' and $name eq 'setSpacing')
997 || ($classNode->{astNodeName} eq 'QGraphicsWidget' and $name eq 'children')
998 || ($classNode->{astNodeName} eq 'QGridLayout' and $name eq 'setSpacing')
999 || ($classNode->{astNodeName} eq 'QGridLayout' and $name eq 'spacing')
1000 || ($classNode->{astNodeName} eq 'QMessageBox' and $name eq 'setWindowTitle')
1001 || ($classNode->{astNodeName} eq 'TextEvent' and $name eq 'data')
1002 || ($classNode->{astNodeName} eq 'KCmdLineArgs' and $name eq 'init' and $m->{ParamList}[0]->{ArgType} =~ /int/)
1003 || ($classNode->{astNodeName} eq 'KConfigGroup' and $name eq 'groupImpl')
1004 || ($classNode->{astNodeName} eq 'KConfigGroup' and $name eq 'setReadDefaults')
1005 || ($classNode->{astNodeName} eq 'KConfigGroup' and $name eq 'KConfigGroup' && $#{$m->{ParamList}} == 1 && $m->{ParamList}[0]->{ArgType} =~ /const KConfigBase/)
1006 || ($name eq 'operator<<' and $m->{ParamList}[0]->{ArgType} =~ /QDebug/ )
1007 || ($name eq 'operator<<' and $m->{ParamList}[0]->{ArgType} =~ /QDataStream/ and $m->{ParamList}[1]->{ArgType} =~ /KDateTime::Spec/ )
1008 || ($name eq 'operator>>' and $m->{ParamList}[0]->{ArgType} =~ /QDataStream/ and $m->{ParamList}[1]->{ArgType} =~ /KDateTime::Spec/ )
1009 || ($name eq 'operator<<' and $m->{ParamList}[0]->{ArgType} =~ /QDataStream/ and $m->{ParamList}[1]->{ArgType} =~ /const KDateTime/ )
1010 || ($name eq 'operator>>' and $m->{ParamList}[0]->{ArgType} =~ /QDataStream/ and $m->{ParamList}[1]->{ArgType} =~ /KDateTime/ )
1011 || ($classNode->{astNodeName} eq 'KInputDialog' and $name eq 'getDouble')
1012 || ($classNode->{astNodeName} eq 'KInputDialog' and $name eq 'getInteger')
1013 || ($classNode->{astNodeName} eq 'KIO' and $name eq 'buildHTMLErrorString')
1014 || ($classNode->{astNodeName} eq 'KJob' and $name eq 'description')
1015 || ($classNode->{astNodeName} eq 'KJob' and $name eq 'KJob')
1016 || ($classNode->{astNodeName} eq 'KShortcutsEditor' and $name eq 'checkGlobalShortcutsConflict')
1017 || ($classNode->{astNodeName} eq 'KShortcutsEditor' and $name eq 'checkStandardShortcutsConflict')
1018 || ($classNode->{astNodeName} eq 'KStandardShortcut' and $name eq 'insert')
1019 || ($classNode->{astNodeName} eq 'KTzfileTimeZoneSource' and $name eq 'location')
1020 || ($classNode->{astNodeName} eq 'Wallet' and $name eq 'Wallet')
1021 || ($classNode->{astNodeName} eq 'KMD5' and $name eq 'transform') )
1023 $m->{NodeType} = 'deleted';
1024 next;
1027 my $argId = 0;
1028 my $firstDefaultParam;
1029 foreach my $arg ( @{$m->{ParamList}} ) {
1030 # Look for first param with a default value
1031 if ( defined $arg->{DefaultValue} && !defined $firstDefaultParam ) {
1032 $firstDefaultParam = $argId;
1035 if ( $arg->{ArgType} eq '...' # refuse a method with variable arguments
1036 || $arg->{ArgType} eq 'const QTextItem&' # ref to a private class
1037 || $arg->{ArgType} eq 'DecoderFn' # QFile's callback
1038 || $arg->{ArgType} eq 'EncoderFn' # QFile's callback
1039 || $arg->{ArgType} eq 'FILE*' ) # won't be able to handle that I think
1041 $m->{NodeType} = 'deleted';
1043 else
1045 # Resolve type in full, e.g. for QSessionManager::RestartHint
1046 # (QSessionManagerJBridge doesn't inherit QSessionManager)
1047 $arg->{ArgType} = kalyptusDataDict::resolveType($arg->{ArgType}, $classNode, $rootnode);
1048 registerType( $arg->{ArgType} );
1049 $argId++;
1052 $m->AddProp( "FirstDefaultParam", $firstDefaultParam );
1053 $m->{ReturnType} = kalyptusDataDict::resolveType($m->{ReturnType}, $classNode, $rootnode) if ($m->{ReturnType});
1054 registerType( $m->{ReturnType} );
1056 elsif( $m->{NodeType} eq "enum" ) {
1057 if ( ! $m->{astNodeName} ) {
1058 $m->{Access} = 'protected';
1060 my $fullEnumName = $className."::".$m->{astNodeName};
1061 if ( ($fullEnumName eq 'KMimeType::Format' and $name eq 'compression')
1062 || $fullEnumName eq 'QDataStream::ByteOrder'
1063 || $m->{Deprecated} ) {
1064 $m->{NodeType} = 'deleted';
1065 next;
1068 $classNode->{enumerations}{$m->{astNodeName}} = $fullEnumName;
1069 # if $m->{astNodeName} and $m->{Access} ne 'private';
1070 # if $m->{astNodeName} ;
1072 # Define a type for this enum
1073 registerType( $fullEnumName );
1075 # Remember that it's an enum
1076 findTypeEntry( $fullEnumName )->{isEnum} = 1;
1077 } elsif( $m->{NodeType} eq 'property' ) {
1078 if ( ($classNode->{astNodeName} eq 'QWidget' and $name eq 'Q_PROPERTY_height')
1079 || ($classNode->{astNodeName} eq 'QWidget' and $name eq 'Q_PROPERTY_minimumSizeHint')
1080 || ($classNode->{astNodeName} eq 'QWidget' and $name eq 'Q_PROPERTY_sizeHint')
1081 || ($classNode->{astNodeName} eq 'QWidget' and $name eq 'Q_PROPERTY_visible')
1082 || ($classNode->{astNodeName} eq 'QWidget' and $name eq 'Q_PROPERTY_width')
1083 || ($classNode->{astNodeName} eq 'QStackedLayout' and $name eq 'Q_PROPERTY_count') )
1085 $m->{NodeType} = 'deleted';
1086 next;
1088 # Don't generate C# code for the property's read and write methods
1089 my $method;
1090 if ( defined $m->{READ} && $m->{READ} ne '') {
1091 $method = kdocAstUtil::findRef( $classNode, $m->{READ} );
1092 if ( defined $method
1093 && $#{$method->{ParamList}} == -1
1094 && $method->{Flags} !~ 'v'
1095 && $method->{Access} !~ /slots|signals/ )
1097 $method->{NodeType} = 'deleted';
1101 if ( defined $m->{WRITE} && $m->{WRITE} ne '') {
1102 $method = kdocAstUtil::findRef( $classNode, $m->{WRITE} );
1103 if ( defined $method
1104 && $#{$method->{ParamList}} == 0
1105 && $method->{Flags} !~ 'v'
1106 && $method->{Access} !~ /slots|signals/ )
1108 $method->{NodeType} = 'deleted';
1111 } elsif( $m->{NodeType} eq 'var' ) {
1112 if ($name eq 'staticMetaObject') {
1113 $m->{NodeType} = 'deleted';
1114 next;
1116 my $varType = $m->{Type};
1117 # We are interested in public static vars, like QColor::blue
1118 if ( $varType =~ s/static\s+// && $m->{Access} ne 'private'
1119 && $className."::".$m->{astNodeName} ne "KSpell::modalListText" )
1121 $varType =~ s/const\s+(.*)\s*&/$1/;
1122 $varType =~ s/\s*$//;
1123 print STDERR "var: $m->{astNodeName} '$varType'\n" if ($debug);
1125 # Register the type
1126 registerType( $varType );
1128 } else {
1129 # To avoid duplicating the above test, we just get rid of any other var
1130 $m->{NodeType} = 'deleted';
1134 undef
1136 $main::doPrivate = $doPrivate;
1138 print STDERR "$className: ctor count: $constructorCount, hasPublicProtectedConstructor: $hasPublicProtectedConstructor, hasCopyConstructor: $hasCopyConstructor:, defaultConstructor: $defaultConstructor, hasPublicDestructor: $hasPublicDestructor, hasPrivatePureVirtual:$hasPrivatePureVirtual\n" if ($debug);
1140 # Note that if the class has _no_ constructor, the default ctor applies. Let's even generate it.
1141 if ( !$constructorCount && $defaultConstructor eq 'none' && !$hasPrivatePureVirtual ) {
1142 # Create a method node for the constructor
1143 my $methodNode = Ast::New( $classNode->{astNodeName} );
1144 $methodNode->AddProp( "NodeType", "method" );
1145 $methodNode->AddProp( "Flags", "" );
1146 $methodNode->AddProp( "Params", "" );
1147 $methodNode->AddProp( "ParamList", [] );
1148 kdocAstUtil::attachChild( $classNode, $methodNode );
1150 # Hack the return type for constructors, since constructors return an object pointer
1151 $methodNode->AddProp( "ReturnType", $className."*" );
1152 registerType( $className."*" );
1153 $methodNode->AddProp( "Access", "public" ); # after attachChild
1154 $defaultConstructor = 'public';
1155 $hasPublicProtectedConstructor = 1;
1158 # Also, if the class has no explicit destructor, generate a default one.
1159 if ( !$hasDestructor && !$hasPrivatePureVirtual ) {
1160 my $methodNode = Ast::New( "$classNode->{astNodeName}" );
1161 $methodNode->AddProp( "NodeType", "method" );
1162 $methodNode->AddProp( "Flags", "" );
1163 $methodNode->AddProp( "Params", "" );
1164 $methodNode->AddProp( "ParamList", [] );
1165 kdocAstUtil::attachChild( $classNode, $methodNode );
1167 $methodNode->AddProp( "ReturnType", "~" );
1168 $methodNode->AddProp( "Access", "public" );
1171 # If we have a private pure virtual, then the class can't be instanciated (e.g. QCanvasItem)
1172 # Same if the class has only private constructors (e.g. QInputDialog)
1173 $classNode->AddProp( "CanBeInstanciated", $hasPublicProtectedConstructor
1174 # && !$hasPrivatePureVirtual
1175 && (!$classNode->{Pure} or $classNode->{astNodeName} eq 'QValidator')
1176 && !($classNode->{NodeType} eq 'namespace')
1177 && ($classNode->{astNodeName} !~ /^DrawContentsEvent$|^MouseEvent$|^MouseDoubleClickEvent$|^MouseMoveEvent$|^MouseReleaseEvent$|^MousePressEvent$/)
1178 && ($classNode->{astNodeName} !~ /QMetaObject|QDragObject|Slave|CopyJob|KMdiChildFrm|KNamedCommand/) );
1180 # We will derive from the class only if it has public or protected constructors.
1181 # (_Even_ if it has pure virtuals. But in that case the *.cpp class can't be instantiated either.)
1182 $classNode->AddProp( "BindingDerives", $hasPublicProtectedConstructor );
1184 # We need a public dtor to destroy the object --- ### aren't protected dtors ok too ??
1185 $classNode->AddProp( "HasPublicDestructor", $hasPublicDestructor );
1187 # Hack for QAsyncIO. We don't implement the "if a class has no explicit copy ctor,
1188 # then all of its member variables must be copiable, otherwise the class isn't copiable".
1189 $hasPrivateCopyConstructor = 1 if ( $className eq 'QAsyncIO' );
1191 # Remember if this class can't be copied - it means all its descendants can't either
1192 $classNode->AddProp( "CanBeCopied", !$hasPrivateCopyConstructor );
1193 $classNode->AddProp( "HasCopyConstructor", $hasCopyConstructor );
1194 if ($classNode->{astNodeName} =~ /Abstract/
1195 || $classNode->{astNodeName} eq 'QAccessibleInterface'
1196 || $classNode->{astNodeName} eq 'QAccessibleApplication'
1197 || $classNode->{astNodeName} eq 'QAccessibleObjectEx'
1198 || $classNode->{astNodeName} eq 'QAccessibleWidgetEx'
1199 || $classNode->{astNodeName} eq 'QAccessibleObject' )
1201 $classNode->AddProp( "Pure", 1 );
1205 sub propagateCanBeCopied($)
1207 my $classNode = shift;
1208 my $className = join( "::", kdocAstUtil::heritage($classNode) );
1209 my @super = superclass_list($classNode);
1210 # A class can only be copied if none of its ancestors have a private copy ctor.
1211 for my $s (@super) {
1212 if (!$s->{CanBeCopied}) {
1213 $classNode->{CanBeCopied} = 0;
1214 print STDERR "$classNode->{astNodeName} cannot be copied\n" if ($debug);
1215 last;
1219 # Prepare the {case} dict for the class
1220 prepareCaseDict( $classNode );
1223 sub generateClass($$$$$)
1225 my( $node, $packagename, $namespace, $indent, $addImport ) = @_;
1226 my $className = join( "::", kdocAstUtil::heritage($node) );
1227 my $csharpClassName = $node->{astNodeName};
1228 my $classCode = "";
1229 my %csharpMethods = ();
1230 # my %addImport = ();
1232 my @ancestors = ();
1233 my @ancestor_nodes = ();
1234 Iter::Ancestors( $node, $rootnode, undef, undef, sub {
1235 my ( $ances, $name, $type, $template ) = @_;
1236 if ( $name ne "khtml::KHTMLWidget"
1237 and $name !~ /QList</ and $name ne 'QList' and $name !~ /QVector/
1238 and $name !~ /QMap/ and $name !~ /QHash/
1239 and $name ne 'KShared' and $name ne 'QSharedData' and $name ne '' ) {
1240 if (defined $ances) {
1241 push @ancestor_nodes, $ances;
1242 my $ancestorName = join( ".", kdocAstUtil::heritage($ances) );
1243 push @ancestors, $ancestorName;
1247 undef
1250 my ($methodCode, $staticMethodCode, $interfaceCode, $proxyInterfaceCode, $signalCode, $extraCode, $enumCode, $notConverted) = generateAllMethods( $node, $#ancestors + 1,
1251 \%csharpMethods,
1252 $node,
1254 $addImport );
1256 my $tempMethodNumber = $methodNumber;
1258 # Add method calls for the interfaces implemented by the class
1259 foreach my $ancestor_node ( @ancestor_nodes ) {
1260 if ( defined $interfacemap{$ancestor_node->{astNodeName}} && ($#ancestors > 0) ) {
1261 my ($meth, $static, $interf, $proxyInterf, $sig, $extra, $enum, $notconv) = generateAllMethods( $ancestor_node, 0, \%csharpMethods, $node, 0, $addImport );
1262 $methodCode .= $meth;
1263 $staticMethodCode .= $static;
1264 $extraCode .= $extra;
1265 $enumCode .= $enum;
1266 $interfaceCode .= $interf;
1267 $proxyInterfaceCode .= $proxyInterf;
1268 $notConverted .= $notconv;
1272 my $globalSpace = kdocAstUtil::findRef( $rootnode, $main::globalSpaceClassName );
1273 my ($meth, $static, $interf, $proxyInterf, $sig, $extra, $enum, $notconv) = generateAllMethods( $globalSpace, 0, \%csharpMethods, $node, 0, $addImport );
1274 $methodCode .= $meth;
1275 $staticMethodCode .= $static;
1276 $extraCode .= $extra;
1277 $enumCode .= $enum;
1278 $interfaceCode .= $interf;
1279 $proxyInterfaceCode .= $proxyInterf;
1280 $notConverted .= $notconv;
1281 $methodNumber = $tempMethodNumber;
1283 if ( $className eq 'Qt' ) {
1285 } else {
1286 if ( $className eq 'QListViewItem'
1287 || $className eq 'QAbstractTextDocumentLayout'
1288 || $className eq 'QUriDrag'
1289 || $className eq 'KDE' ) {
1290 # Special case these two classes as they have methods that use ArrayList added as 'extras'
1291 $classCode .= "$indent\tusing System.Collections.Generic;\n";
1294 if ( $className eq 'QObject' ) {
1295 $classCode .= "$indent\tusing System.Reflection;\n";
1299 if ( $enumCode ne '' ) {
1300 $classCode .= "$enumCode" if ($node->{NodeType} eq 'namespace'
1301 && $csharpClassName ne 'Qt'
1302 && $csharpClassName ne 'KDE');
1305 if ( defined $interfacemap{$csharpClassName} ) {
1306 $classCode .= "\n$indent\tpublic interface " . $interfacemap{$csharpClassName} . " {\n";
1307 $classCode .= $interfaceCode;
1308 $classCode .= "$indent\t}\n";
1311 my $classdec = "";
1312 my $parentClassName = "";
1314 if ($node->{NodeType} eq 'namespace') {
1315 $classdec .= "\t[SmokeClass(\"$className\")]\n";
1316 # $classdec .= "\tnamespace $className {\n";
1318 $csharpClassName = 'Global' unless ($csharpClassName eq 'Qt' || $csharpClassName eq 'KDE');
1320 if ( $partial_classes{$csharpClassName} ) {
1321 $classdec .= "\tpublic partial class $csharpClassName {\n";
1322 } else {
1323 $classdec .= "\tpublic class $csharpClassName {\n";
1326 if ( $csharpClassName eq 'Qt' ) {
1327 $classdec .= "\t\tprotected SmokeInvocation interceptor = null;\n";
1329 } elsif ( $#ancestors < 0 ) {
1330 $classdec .= "\t[SmokeClass(\"$className\")]\n";
1332 if ( $csharpClassName eq 'QObject' ) {
1333 $classdec .= "\tpublic partial class QObject : Qt, IDisposable {\n";
1334 $classdec .= "\t\tprivate IntPtr smokeObject;\n";
1335 $classdec .= "\t\tprotected Object Q_EMIT = null;\n";
1336 $classdec .= "\t\tprotected $csharpClassName(Type dummy) {\n";
1337 $classdec .= "\t\t\ttry {\n";
1338 $classdec .= "\t\t\t\tType proxyInterface = Qyoto.GetSignalsInterface(GetType());\n";
1339 $classdec .= "\t\t\t\tSignalInvocation realProxy = new SignalInvocation(proxyInterface, this);\n";
1340 $classdec .= "\t\t\t\tQ_EMIT = realProxy.GetTransparentProxy();\n";
1341 $classdec .= "\t\t\t}\n";
1342 $classdec .= "\t\t\tcatch {\n";
1343 $classdec .= "\t\t\t\tConsole.WriteLine(\"Could not retrieve signal interface\");\n";
1344 $classdec .= "\t\t\t}\n";
1345 $classdec .= "\t\t}\n";
1346 $classdec .= "\t\t[SmokeMethod(\"metaObject()\")]\n";
1347 $classdec .= "\t\tpublic virtual QMetaObject MetaObject() {\n";
1348 $classdec .= "\t\t\tif (SmokeMarshallers.IsSmokeClass(GetType())) {\n";
1349 $classdec .= "\t\t\t\treturn (QMetaObject) interceptor.Invoke(\"metaObject\", \"metaObject()\", typeof(QMetaObject));\n";
1350 $classdec .= "\t\t\t} else {\n";
1351 $classdec .= "\t\t\t\treturn Qyoto.GetMetaObject(this);\n";
1352 $classdec .= "\t\t\t}\n";
1353 $classdec .= "\t\t}\n";
1354 } else {
1355 if ( $node->{Pure} ) {
1356 $classdec .= "\tpublic abstract ";
1357 } else {
1358 $classdec .= "\tpublic ";
1361 if ( $partial_classes{$csharpClassName} ) {
1362 $classdec .= "partial class $csharpClassName : Object";
1363 } else {
1364 $classdec .= "class $csharpClassName : Object";
1366 if ( defined $interfacemap{$csharpClassName} ) {
1367 $classdec .= ", " . $interfacemap{$csharpClassName};
1370 if ($node->{CanBeInstanciated} and $node->{HasPublicDestructor} and !$node->{Pure}) {
1371 $classdec .= ", IDisposable";
1374 if (defined $iterator_interfacemap{$className}) {
1375 $classdec .= ", $iterator_interfacemap{$className}";
1378 $classdec .= " {\n\t\tprotected SmokeInvocation interceptor = null;\n";
1379 $classdec .= "\t\tprivate IntPtr smokeObject;\n";
1380 $classdec .= "\t\tprotected $csharpClassName(Type dummy) {}\n";
1382 } else {
1383 $classdec .= "\t[SmokeClass(\"$className\")]\n";
1384 if ( $partial_classes{$csharpClassName} ) {
1385 if ( $node->{Pure}
1386 || $csharpClassName eq 'QAccessibleInterface'
1387 || $csharpClassName eq 'QAccessibleApplication'
1388 || $csharpClassName eq 'QAccessibleObjectEx'
1389 || $csharpClassName eq 'QAccessibleWidgetEx'
1390 || $csharpClassName eq 'QAccessibleObject' )
1392 $classdec .= "\tpublic abstract partial class $csharpClassName : ";
1393 } else {
1394 $classdec .= "\tpublic partial class $csharpClassName : ";
1396 } else {
1397 if ( $node->{Pure} ) {
1398 $classdec .= "\tpublic abstract class $csharpClassName : ";
1399 } else {
1400 $classdec .= "\tpublic class $csharpClassName : ";
1403 my $ancestor;
1404 foreach $ancestor ( @ancestors ) {
1405 if ( !defined $interfacemap{$ancestor} or $ancestor eq @ancestors[$#ancestors] ) {
1406 $parentClassName .= "$ancestor";
1407 $classdec .= "$ancestor";
1408 last;
1412 my @implements = ();
1413 if ( $#ancestors >= 1 ) {
1414 foreach $ancestor ( @ancestors ) {
1415 if ( defined $interfacemap{$ancestor} ) {
1416 push(@implements, $interfacemap{$ancestor});
1421 if ($#implements >= 0) {
1422 $classdec .= ", ";
1423 $classdec .= join(", ", @implements);
1426 if ($node->{CanBeInstanciated} and $node->{HasPublicDestructor} and !$node->{Pure}) {
1427 $classdec .= ", IDisposable";
1430 if (defined $iterator_interfacemap{$className}) {
1431 $classdec .= ", $iterator_interfacemap{$className}";
1434 $classdec .= " {\n";
1435 $classdec .= " \t\tprotected $csharpClassName(Type dummy) : base((Type) null) {}\n";
1438 if ( $csharpClassName !~ /^Q/ or $signalCode ne '' ) {
1439 my $signalLink = '';
1440 if ( $signalCode ne '' ) {
1441 $signalLink = " See <see cref=\"I$csharpClassName" . "Signals\"></see> for signals emitted by $csharpClassName\n";
1443 my $docnode = $node->{DocNode};
1444 if ( defined $docnode ) {
1445 my $comment = printCSharpdocComment( $docnode, "", "$indent\t/// ", $signalLink );
1446 $classCode .= $comment;
1447 } else {
1448 $classCode .= "$indent\t///$signalLink";
1452 $classCode .= indentText($indent, $classdec);
1454 # only generate nested classes
1455 if ($node->{NodeType} ne 'namespace') {
1456 Iter::MembersByType ( $node, undef,
1457 sub { my ($node, $subclassNode ) = @_;
1458 if ( $subclassNode->{NodeType} =~ /class|struct/ && !defined $subclassNode->{Compound} ) {
1459 $classCode .= generateClass($subclassNode, $packagename, $namespace, $indent . "\t", $addImport);
1461 }, undef );
1463 Iter::MembersByType ( $node, undef,
1464 sub { my ($node, $subclassNode ) = @_;
1465 if ( $subclassNode->{NodeType} =~ /class|struct/ && $subclassNode->{Compound} ) {
1466 $classCode .= generateClass($subclassNode, $packagename, $namespace, $indent . "\t", $addImport);
1468 }, undef );
1471 if ($methodCode ne '') {
1472 if ( $#ancestors < 0 ) {
1473 $classCode .= "$indent\t\tprotected void CreateProxy() {\n";
1474 } else {
1475 $classCode .= "$indent\t\tprotected new void CreateProxy() {\n";
1477 $classCode .= "$indent\t\t\tinterceptor = new $main::smokeInvocation(typeof($csharpClassName), this);\n$indent\t\t}\n";
1480 if ($proxyInterfaceCode ne '') {
1481 $classCode .= "$indent\t\tprivate static SmokeInvocation staticInterceptor = null;\n";
1482 $classCode .= "$indent\t\tstatic $csharpClassName() {\n";
1483 $classCode .= "$indent\t\t\tstaticInterceptor = new $main::smokeInvocation(typeof($csharpClassName), null);\n";
1484 $classCode .= "$indent\t\t}\n";
1487 if ( $enumCode ne '' ) {
1488 $classCode .= indentText("$indent\t", "$enumCode") unless ($node->{NodeType} eq 'namespace'
1489 && $csharpClassName ne 'Qt'
1490 && $csharpClassName ne 'KDE');
1492 $classCode .= indentText($indent, $extraCode);
1493 $classCode .= indentText($indent, $notConverted);
1494 $classCode .= indentText($indent, $methodCode);
1495 $classCode .= indentText($indent, $staticMethodCode);
1497 if ( is_kindof($node, "QObject") ) {
1498 if ( $csharpClassName eq 'QObject' ) {
1499 $classCode .= "$indent\t\tprotected I" . $csharpClassName . "Signals Emit {\n";
1500 } else {
1501 $classCode .= "$indent\t\tprotected new I" . $csharpClassName . "Signals Emit {\n";
1504 $classCode .= "$indent\t\t\tget { return (I" . $csharpClassName . "Signals) Q_EMIT; }\n";
1505 $classCode .= "$indent\t\t}\n";
1506 $classCode .= "$indent\t}\n";
1508 $classCode .= "\n$indent\tpublic interface I$csharpClassName" . "Signals";
1509 if ($parentClassName =~ /(.*)[.](.*)/) {
1510 $classCode .= " : $1.I" . $2 . "Signals" unless $csharpClassName eq "QObject";
1511 } else {
1512 $classCode .= " : I" . $parentClassName . "Signals" unless $csharpClassName eq "QObject";
1514 $classCode .= " {\n";
1515 $classCode .= $signalCode;
1516 $classCode .= "$indent\t}\n";
1517 } else {
1518 $classCode .= "$indent\t}\n";
1521 return $classCode;
1524 =head2 writeClassDoc
1526 Called by writeDoc for each class to be written out
1528 =cut
1530 sub writeClassDoc
1532 my( $node ) = @_;
1534 my $className = join( "::", kdocAstUtil::heritage($node) );
1535 my $csharpClassName = $node->{astNodeName};
1536 # Makefile doesn't like '::' in filenames, so use __
1537 my $fileName = $className;
1538 $fileName =~ s/::/_/g;
1539 # my $fileName = join( "__", kdocAstUtil::heritage($node) );
1540 print "Enter: $className\n" if $debug;
1542 my $packagename;
1543 if ($className =~ /^Qsci/) {
1544 $packagename = "QScintilla";
1545 } elsif ($className =~ /^Qwt/) {
1546 $packagename = "Qwt";
1547 } elsif ($className =~ /^Q/) {
1548 $packagename = "Qyoto";
1549 } elsif ($className =~ /^Plasma/) {
1550 $packagename = "Plasma";
1551 } elsif ($className =~ /^Soprano/) {
1552 $packagename = "Soprano";
1553 } else {
1554 $packagename = "Kimono";
1557 my $namespace, my @parentClasses;
1558 my $first = 1;
1560 foreach my $n (kdocAstUtil::refHeritage($node)) {
1561 if ($n->{NodeType} eq 'namespace') {
1562 $namespace .= "." if !$first;
1563 $namespace .= "$n->{astNodeName}"
1564 } else {
1565 push @parentClasses, $n->{astNodeName} if $n != $node;
1567 $first = 0;
1570 # nested classes go into the same source file as the containing class
1571 return if (scalar(@parentClasses) > 0);
1573 my %addImport = ();
1575 # Write out the *.csharp file
1576 my $classFile = "$outputdir/$fileName.cs";
1577 open( CLASS, ">$classFile" ) || die "Couldn't create $classFile\n";
1578 print STDERR "Writing $fileName.csharp\n" if ($debug);
1580 print CLASS "//Auto-generated by kalyptus. DO NOT EDIT.\n";
1581 # print CLASS "//Auto-generated by $0. DO NOT EDIT.\n";
1583 $namespace = undef if ($namespace eq 'KDE' or $namespace eq 'Qt');
1584 # only the core classes go into the Kimono namespace, others have there own one.
1585 if (defined $namespace) {
1586 print CLASS "namespace $namespace {\n";
1587 print CLASS "\tusing $packagename;\n";
1588 } else {
1589 print CLASS "namespace $packagename {\n";
1592 print CLASS "\tusing System;\n";
1594 my $classCode = generateClass($node, $packagename, $namespace, "", \%addImport);
1596 foreach my $imp (keys %addImport) {
1597 die if $imp eq '';
1598 # Ignore any imports for classes in the same package as the current class
1599 if ($imp !~ /$packagename/) {
1600 print CLASS "\tusing $imp;\n";
1604 print CLASS $classCode;
1606 print CLASS "}\n";
1608 close CLASS;
1612 # Generate the prototypes for a method (one per arg with a default value)
1613 # Helper for makeprotos
1614 sub iterproto($$$$$) {
1615 my $classidx = shift; # to check if a class exists
1616 my $method = shift;
1617 my $proto = shift;
1618 my $idx = shift;
1619 my $protolist = shift;
1621 my $argcnt = scalar @{ $method->{ParamList} } - 1;
1622 if($idx > $argcnt) {
1623 push @$protolist, $proto;
1624 return;
1626 if(defined $method->{FirstDefaultParam} and $method->{FirstDefaultParam} <= $idx) {
1627 push @$protolist, $proto;
1630 my $arg = $method->{ParamList}[$idx]->{ArgType};
1632 my $typeEntry = findTypeEntry( $arg );
1633 my $realType = $typeEntry->{realType};
1635 # A scalar ?
1636 $arg =~ s/\bconst\b//g;
1637 $arg =~ s/\s+//g;
1638 if($typeEntry->{isEnum} || $allTypes{$realType}{isEnum} || exists $typeunion{$realType} || exists $mungedTypeMap{$arg})
1640 my $id = '$'; # a 'scalar
1641 $id = '?' if $arg =~ /[*&]{2}/;
1642 $id = $mungedTypeMap{$arg} if exists $mungedTypeMap{$arg};
1643 iterproto($classidx, $method, $proto . $id, $idx + 1, $protolist);
1644 return;
1647 # A class ?
1648 if(exists $classidx->{$realType}) {
1649 iterproto($classidx, $method, $proto . '#', $idx + 1, $protolist);
1650 return;
1653 # A non-scalar (reference to array or hash, undef)
1654 iterproto($classidx, $method, $proto . '?', $idx + 1, $protolist);
1655 return;
1658 # Generate the prototypes for a method (one per arg with a default value)
1659 sub makeprotos($$$) {
1660 my $classidx = shift;
1661 my $method = shift;
1662 my $protolist = shift;
1663 iterproto($classidx, $method, $method->{astNodeName}, 0, $protolist);
1666 # Return the string containing the signature for this method (without return type).
1667 # If the 2nd arg is not the size of $m->{ParamList}, this method returns a
1668 # partial signature (this is used to handle default values).
1669 sub argsSignature($$) {
1670 my $method = shift;
1671 my $last = shift;
1672 # my $sig = $method->{astNodeName};
1673 my $sig = "";
1674 my @argTypeList;
1675 my $argId = 0;
1676 foreach my $arg ( @{$method->{ParamList}} ) {
1677 last if $argId > $last;
1678 push @argTypeList, $arg->{ArgType};
1679 $argId++;
1681 $sig .= "(". join(", ",@argTypeList) .")";
1682 $sig .= " const" if $method->{Flags} =~ "c";
1683 return $sig;
1686 # Return the string containing the signature for this method (without return type).
1687 # If the 2nd arg is not the size of $m->{ParamList}, this method returns a
1688 # partial signature (this is used to handle default values).
1689 sub methodSignature($$) {
1690 my $method = shift;
1691 my $last = shift;
1692 my $sig = $method->{astNodeName};
1693 my @argTypeList;
1694 my $argId = 0;
1695 foreach my $arg ( @{$method->{ParamList}} ) {
1696 last if $argId > $last;
1697 push @argTypeList, $arg->{ArgType};
1698 $argId++;
1700 $sig .= "(". join(", ",@argTypeList) .")";
1701 $sig .= " const" if $method->{Flags} =~ "c";
1702 return $sig;
1705 # Return the string containing the signature for this method (without return type).
1706 # If the 2nd arg is not the size of $m->{ParamList}, this method returns a
1707 # partial signature (this is used to handle default values).
1708 sub mungedSignature($$) {
1709 my $method = shift;
1710 my $last = shift;
1711 # my $sig = $method->{astNodeName};
1712 my $sig = "";
1713 my $argId = 0;
1714 foreach my $arg ( @{$method->{ParamList}} ) {
1715 last if $argId > $last;
1716 $sig .= mungedArgType($method, $arg->{ArgType});
1717 $argId++;
1719 return $sig;
1722 # Return the string containing the csharp signature for this method (without return type).
1723 # If the 2nd arg is not the size of $m->{ParamList}, this method returns a
1724 # partial signature (this is used to handle default values).
1725 sub csharpMethodSignature($$) {
1726 my $method = shift;
1727 my $last = shift;
1728 my $sig = $method->{astNodeName};
1729 my @argTypeList;
1730 my $argId = 0;
1731 foreach my $arg ( @{$method->{ParamList}} ) {
1732 $argId++;
1733 last if $argId > $last;
1734 push @argTypeList, cplusplusToCSharp( $arg->{ArgType} );
1736 $sig .= "(". join(", ",@argTypeList) .")";
1737 return $sig;
1740 sub smokeInvocation($$$$$$) {
1741 my ( $target, $argtypes, $returnType, $mungedMethod, $signature, $addImport ) = @_;
1743 my $methodCode = "\t\t\t";
1744 if ($returnType ne 'void') {
1745 $methodCode .= "return ($returnType) ";
1748 $methodCode .= "$target.Invoke(\"$mungedMethod\", \"$signature\", typeof($returnType)";
1750 my $arglist = "";
1751 foreach my $arg ( @{$argtypes} ) {
1752 $arg =~ /^(ref )?(.*)\s(.*)$/;
1753 if ($1 ne '') {
1754 return smokeRefInvocation($target, $argtypes, $returnType, $mungedMethod, $signature, $addImport);
1756 $arglist .= ", typeof($2), $3";
1759 return $methodCode . $arglist . ");\n";
1762 sub smokeRefInvocation($$$$$$) {
1763 my ( $target, $argtypes, $returnType, $mungedMethod, $signature, $addImport ) = @_;
1765 my $preMethodCode = "";
1766 my $methodCode = "";
1767 my $postMethodCode = "";
1769 $preMethodCode = "\t\t\tStackItem[] stack = new StackItem[" . (scalar(@{$argtypes}) + 1) . "];\n";
1770 $methodCode .= "\t\t\t$target.Invoke(\"$mungedMethod\", \"$signature\", stack);\n";
1772 my $arglist = "";
1773 my $argNo = 1;
1774 foreach my $arg ( @{$argtypes} ) {
1775 $arg =~ /^(ref )?(.*)\s(.*)$/;
1776 my $argtype = $2;
1777 my $argname = $3;
1779 if ($1 ne '') {
1780 $preMethodCode .= "\t\t\tstack[$argNo].s_$argtype = $argname;\n";
1781 $postMethodCode .= "\t\t\t$argname = stack[$argNo].s_$argtype;\n";
1782 } elsif ($argtype =~ /^int$|^uint$|^bool$|^double$|^float$|^long$|^ulong$|^short$|^ushort$/ ) {
1783 $preMethodCode .= "\t\t\tstack[$argNo].s_$argtype = $argname;\n";
1784 } elsif ($argtype =~ /\./ ) {
1785 $preMethodCode .= "\t\t\tstack[$argNo].s_int = (int) $argname;\n";
1786 } else {
1787 $addImport->{"System.Runtime.InteropServices"} = 1;
1788 $preMethodCode .= "#if DEBUG\n";
1789 $preMethodCode .= "\t\t\tstack[$argNo].s_class = (IntPtr) DebugGCHandle.Alloc($argname);\n";
1790 $preMethodCode .= "#else\n";
1791 $preMethodCode .= "\t\t\tstack[$argNo].s_class = (IntPtr) GCHandle.Alloc($argname);\n";
1792 $preMethodCode .= "#endif\n";
1794 $postMethodCode .= "#if DEBUG\n";
1795 $postMethodCode .= "\t\t\tDebugGCHandle.Free((GCHandle) stack[$argNo].s_class);\n";
1796 $postMethodCode .= "#else\n";
1797 $postMethodCode .= "\t\t\t((GCHandle) stack[$argNo].s_class).Free();\n";
1798 $postMethodCode .= "#endif\n";
1801 $argNo++;
1802 # $arglist .= ", typeof($2), $3";
1805 if ($returnType eq 'void' ) {
1806 $postMethodCode .= "\t\t\treturn;\n";
1807 } elsif ($returnType =~ /^int$|^uint$|^bool$|^double$|^float$|^long$|^ulong$|^short$|^ushort$/ ) {
1808 $postMethodCode .= "\t\t\treturn stack[0].s_$returnType;\n";
1809 } elsif ($returnType =~ /\./ ) {
1810 $postMethodCode .= "\t\t\treturn ($returnType) Enum.ToObject(typeof($returnType), stack[0].s_int);\n";
1811 } else {
1812 $addImport->{"System.Runtime.InteropServices"} = 1;
1813 $postMethodCode .= "\t\t\tobject returnValue = ((GCHandle) stack[0].s_class).Target;\n";
1815 $postMethodCode .= "#if DEBUG\n";
1816 $postMethodCode .= "\t\t\tDebugGCHandle.Free((GCHandle) stack[0].s_class);\n";
1817 $postMethodCode .= "#else\n";
1818 $postMethodCode .= "\t\t\t((GCHandle) stack[0].s_class).Free();\n";
1819 $postMethodCode .= "#endif\n";
1821 $postMethodCode .= "\t\t\treturn ($returnType) returnValue;\n";
1824 return $preMethodCode . $methodCode . $postMethodCode;
1827 sub smokeInvocationArgList($) {
1828 my $argtypes = shift;
1830 my $arglist = "";
1831 foreach my $arg ( @{$argtypes} ) {
1832 if ( $arg =~ /^(ref )?(.*)\s(.*)$/ ) {
1833 $arglist .= ", typeof($2), $3";
1836 return $arglist;
1839 sub coerce_type($$$$) {
1840 #my $m = shift;
1841 my $union = shift;
1842 my $var = shift;
1843 my $type = shift;
1844 my $new = shift; # 1 if this is a return value, 0 for a normal param
1846 my $typeEntry = findTypeEntry( $type );
1847 my $realType = $typeEntry->{realType};
1849 my $unionfield = $typeEntry->{typeId};
1850 # die "$type" unless defined( $unionfield );
1851 if ( ! defined( $unionfield ) ) {
1852 print STDERR "type field not defined: $type\n";
1853 return "";
1856 $unionfield =~ s/t_/s_/;
1858 $type =~ s/\s+const$//; # for 'char* const'
1859 $type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
1861 my $code = "$union.$unionfield = ";
1862 if($type =~ /&$/) {
1863 $code .= "(void*)&$var;\n";
1864 } elsif($type =~ /\*$/) {
1865 $code .= "(void*)$var;\n";
1866 } else {
1867 if ( $unionfield eq 's_class'
1868 or ( $unionfield eq 's_voidp' and $type ne 'void*' )
1869 or $type eq 'QString' ) { # hack
1870 $type =~ s/^const\s+//;
1871 if($new) {
1872 $code .= "(void*)new $type($var);\n";
1873 } else {
1874 $code .= "(void*)&$var;\n";
1876 } else {
1877 $code .= "$var;\n";
1881 return $code;
1884 # Generate the list of args casted to their real type, e.g.
1885 # (QObject*)x[1].s_class,(QEvent*)x[2].s_class,x[3].s_int
1886 sub makeCastedArgList
1888 my @castedList;
1889 my $i = 1; # The args start at x[1]. x[0] is the return value
1890 my $arg;
1891 foreach $arg (@_) {
1892 my $type = $arg;
1893 my $cast;
1895 my $typeEntry = findTypeEntry( $type );
1896 my $unionfield = $typeEntry->{typeId};
1897 # die "$type" unless defined( $unionfield );
1898 if ( ! defined( $unionfield ) ) {
1899 print STDERR "type field not defined: $type\n";
1900 return "";
1902 $unionfield =~ s/t_/s_/;
1904 $type =~ s/\s+const$//; # for 'char* const'
1905 $type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
1907 my $v .= " arg$i";
1908 if($type =~ /&$/) {
1909 $cast = "*($type *)";
1910 } elsif($type =~ /\*$/) {
1911 $cast = "($type)";
1912 } elsif($type =~ /\(\*\)\s*\(/) { # function pointer ... (*)(...)
1913 $cast = "($type)";
1914 } else {
1915 if ( $unionfield eq 's_class'
1916 or ( $unionfield eq 's_voidp' and $type ne 'void*' )
1917 or $type eq 'QString' ) { # hack
1918 $cast = "*($type *)";
1919 } else {
1920 $cast = "($type)";
1923 push @castedList, "$type$v";
1924 $i++;
1926 return @castedList;
1930 # Adds the import for node $1 to be imported in $2 if not already there
1931 # Prints out debug stuff if $3
1932 sub addImportForClass($$$)
1934 my ( $node, $addImport, $debugMe ) = @_;
1935 my $importname = csharpImport( $node->{astNodeName} );
1936 # print " Importing $importname for node name: " . $node->{astNodeName} . "\n";
1937 # No import needed, so return
1938 return if ( $importname eq '' );
1939 unless ( defined $addImport->{$importname} ) {
1940 print " Importing $importname\n" if ($debugMe);
1941 $addImport->{$importname} = 1;
1943 else { print " $importname already imported.\n" if ($debugMe); }
1946 sub checkImportsForObject($$$)
1948 my $type = shift;
1949 my $addImport = shift;
1950 my $classNode;
1951 if ($type eq '') {
1952 return;
1955 $type = kalyptusDataDict::resolveType($type, $classNode, $rootnode);
1956 my $csharptype = cplusplusToCSharp($type);
1957 if ( $csharptype eq 'ArrayList' ) {
1958 $addImport->{"System.Collections"} = 1;
1959 } elsif ( $csharptype =~ /^List</ ) {
1960 $addImport->{"System.Collections.Generic"} = 1;
1961 } elsif ( $csharptype =~ /^Dictionary</ ) {
1962 $addImport->{"System.Collections.Generic"} = 1;
1963 } elsif ( $csharptype =~ /StringBuilder/ ) {
1964 $addImport->{"System.Text"} = 1;
1968 sub mungedArgType($$) {
1969 my $method = shift;
1970 my $arg = shift;
1972 # my $arg = $method->{ParamList}[$idx]->{ArgType};
1974 my $typeEntry = findTypeEntry( $arg );
1975 my $realType = $typeEntry->{realType};
1977 # A scalar ?
1978 $arg =~ s/\bconst\b//g;
1979 $arg =~ s/\s+//g;
1980 #print($method->{astNodeName} . " realType: " . $realType . " arg: $arg\n");
1982 if($typeEntry->{isEnum} || $allTypes{$realType}{isEnum} || exists $typeunion{$realType} || exists $mungedTypeMap{$arg})
1984 my $id = '$'; # a 'scalar
1985 $id = '?' if $arg =~ /[*&]{2}/;
1986 $id = $mungedTypeMap{$arg} if exists $mungedTypeMap{$arg};
1987 return $id;
1990 # A class ?
1991 if(exists $new_classidx{$realType}) {
1992 return '#';
1995 # A non-scalar (reference to array or hash, undef)
1996 return '?';
1999 sub generateMethod($$$$$$$$$)
2001 my( $virtualMethods, $overridenMethods, $classNode, $m, $addImport, $ancestorCount, $csharpMethods, $mainClassNode, $generateConstructors ) = @_; # input
2002 my $methodCode = ''; # output
2003 my $staticMethodCode = ''; # output
2004 my $interfaceCode = ''; # output
2005 my $proxyInterfaceCode = ''; # output
2006 my $signalCode = ''; # output
2007 my $notConverted = ''; # output
2009 my $name = $m->{astNodeName}; # method name
2011 my @heritage = kdocAstUtil::heritage($classNode);
2012 my $className = join( "::", @heritage );
2014 @heritage = kdocAstUtil::heritage($mainClassNode);
2015 my $mainClassName = join( "::", @heritage );
2017 # The csharpClassName might be 'QWidget', while currentClassName is 'QRangeControl'
2018 # and the QRangeControl methods are being copied into QWidget.
2019 my $csharpClassName = $mainClassNode->{astNodeName};
2020 my $currentClassName = $classNode->{astNodeName};
2022 my $firstUnknownArgType = 99;
2023 my $returnType = $m->{ReturnType};
2025 # Don't use $className here, it's never the fully qualified (A::B) name for a ctor.
2026 my $isConstructor = ($name eq $classNode->{astNodeName} );
2027 my $isDestructor = ($returnType eq '~');
2029 my $isStatic = $m->{Flags} =~ "s" || $classNode->{NodeType} eq 'namespace';
2030 my $isPure = $m->{Flags} =~ "p";
2031 my $fullSignature = methodSignature( $m, $#{$m->{ParamList}} );
2033 # Don't generate anything for destructors, or constructors for namespaces
2034 return if $isDestructor
2035 or ($classNode->{NodeType} eq 'namespace' and $isConstructor)
2036 # or (!$mainClassNode->{CanBeInstanciated} and $m->{Access} =~ /protected/)
2037 or $name =~ /^operator\s*(=|(\[\])|([|&^+-]=)|(!=))\s*$/
2038 or (!$isStatic and $name =~ /^operator\s*((\+\+)|(--))$/ and $#{$m->{ParamList}} == 0)
2039 or ($name =~ /^operator\s*\*$/ and $#{$m->{ParamList}} == -1);
2041 my $item = kdocAstUtil::findRef( $classNode, "Q_PROPERTY_" . $name );
2042 if ( defined $item
2043 && $item->{NodeType} eq 'property'
2044 && ! $isStatic
2045 && $#{$m->{ParamList}} == -1
2046 && $m->{Flags} !~ 'v'
2047 && $m->{Access} !~ /slots|signals/) {
2048 # If there is a property with the same name, don't bother
2049 return;
2051 my $propertyName = $name;
2052 if ( @{$m->{ParamList}} == 1 && $propertyName =~ /^set(.)(.*)/ ) {
2053 $propertyName = "Q_PROPERTY_" . lc($1) . $2;
2054 $item = kdocAstUtil::findRef( $classNode, $propertyName );
2055 if ( defined $item
2056 && $item->{NodeType} eq 'property'
2057 && ! $isStatic
2058 && $m->{Flags} !~ 'v'
2059 && $m->{Access} !~ /slots|signals/ )
2061 # If there is a property with the same name, don't bother
2062 return;
2066 if ($classNode->{astNodeName} eq $main::globalSpaceClassName) {
2067 my $sourcename = $m->{Source}->{astNodeName};
2068 # Only put Global methods which came from sources beginning with q into class Qt
2069 if ($csharpClassName eq 'Qt' and ( $sourcename !~ /\/q[^\/]*$/ or $sourcename =~ /string.h$/ or $sourcename =~ /qwt/ )) {
2070 return;
2072 # ..and any other global methods into KDE
2073 if ($csharpClassName eq 'KDE' and $m->{Source}->{astNodeName} =~ /\/q[^\/]*$/) {
2074 return;
2077 if ( $sourcename !~ s!.*(kio/|kparts/|dom/|kabc/|ksettings/|kjs/|ktexteditor/|kdeprint/|kdesu/)(.*)!$1$2!m ) {
2078 $sourcename =~ s!.*/(.*)!$1!m;
2080 if ( $sourcename eq '' ) {
2081 return;
2085 if ($returnType eq 'void') {
2086 $returnType = undef;
2087 } else {
2088 # Detect objects returned by value
2089 checkImportsForObject( $returnType, $addImport, $classNode );
2092 my $hasDuplicateSignature = 0;
2094 return if ( $m->{SkipFromSwitch} && $m->{Flags} !~ "p" );
2096 my $argId = 0;
2098 my @argTypeList=();
2099 my @csharpArgTypeList=();
2100 my @csharpArgTypeOnlyList = ();
2102 foreach my $arg ( @{$m->{ParamList}} ) {
2103 $argId++;
2105 if ( $arg->{ArgName} =~ /^ref$|^super$|^int$|^params$|^env$|^cls$|^obj$|^byte$|^event$|^base$|^object$|^in$|^out$|^checked$|^delegate$|^string$|^interface$|^override$|^lock$/ ) {
2106 $arg->{ArgName} = "";
2109 if ( $arg->{ArgName} =~ /^short$|^long$/ ) {
2110 # Oops looks like a parser error
2111 $arg->{ArgType} = $arg->{ArgName};
2112 $arg->{ArgName} = "";
2115 print STDERR " Param ".$arg->{astNodeName}." type: ".$arg->{ArgType}." name:".$arg->{ArgName}." default: ".$arg->{DefaultValue}." csharp: ".cplusplusToCSharp($arg->{ArgType})."\n" if ($debug);
2117 my $argType = $arg->{ArgType};
2118 my $csharpArgType;
2119 my $csharpArg;
2120 my $argName;
2122 if ( cplusplusToCSharp($argType) eq "" && $firstUnknownArgType > $argId ) {
2123 $firstUnknownArgType = $argId;
2126 $csharpArg = ($arg->{ArgName} eq "" ? "arg" . $argId : $arg->{ArgName});
2127 $csharpArgType = cplusplusToCSharp($argType);
2129 # if ( $csharpArgType =~ /StringBuilder/ && $classNode->{astNodeName} ne $main::globalSpaceClassName) {
2130 # $addImport->{"System.Text"} = 1;
2132 if ( $classNode->{astNodeName} eq 'Qt' or $classNode->{astNodeName} eq 'KDE' ) {
2133 $addImport->{"System.Collections.Generic"} = 1;
2136 push @argTypeList, $argType;
2137 push @csharpArgTypeOnlyList, $csharpArgType;
2138 push @csharpArgTypeList, $csharpArgType . " " . $csharpArg;
2140 # Detect objects passed by value
2141 if ($classNode->{astNodeName} ne $main::globalSpaceClassName) {
2142 checkImportsForObject( $argType, $addImport, $classNode );
2146 if ( $name eq 'QApplication' or ($csharpClassName eq 'KCmdLineArgs' and $name eq 'init' and scalar(@csharpArgTypeList) > 1) ) {
2147 # Junk the 'int argc' parameter
2148 shift @csharpArgTypeList;
2149 shift @csharpArgTypeOnlyList;
2152 my @castedArgList = makeCastedArgList( @argTypeList );
2154 # We iterate as many times as we have default params
2155 my $firstDefaultParam = $m->{FirstDefaultParam};
2156 $firstDefaultParam = scalar(@argTypeList) unless defined $firstDefaultParam;
2157 my $iterationCount = scalar(@argTypeList) - $firstDefaultParam;
2159 my $csharpReturnType = cplusplusToCSharp($m->{ReturnType});
2160 $csharpReturnType =~ s/^(out) |(ref) //;
2161 $csharpReturnType =~ s/StringBuilder/string/;
2163 if ($m->{ReturnType} =~ /^int\&/) {
2164 $csharpReturnType = 'int';
2167 if ($csharpReturnType eq "") {
2168 $firstUnknownArgType = 0;
2171 print STDERR " ". ($iterationCount+1). " iterations for $name\n" if ($debug);
2173 my $csharpSignature = csharpMethodSignature( $m, @argTypeList );
2175 if ( defined $csharpMethods->{$csharpSignature} ) {
2176 $hasDuplicateSignature = 1;
2179 my $docnode = $m->{DocNode};
2180 if ( $firstUnknownArgType >= 0 && $m->{Access} !~ /signals/ && ! $hasDuplicateSignature
2181 && $classNode->{astNodeName} ne $main::globalSpaceClassName
2182 && defined $docnode && ($generateConstructors || !$isConstructor) )
2184 my $csharpdocComment = printCSharpdocComment( $docnode, "", "\t\t/// ", "" );
2185 if ($isStatic) {
2186 $staticMethodCode .= $csharpdocComment unless $csharpdocComment =~ /^\s*$/;
2187 } else {
2188 $methodCode .= $csharpdocComment unless $csharpdocComment =~ /^\s*$/;
2192 while($iterationCount >= 0) {
2194 $csharpMethods->{$csharpSignature} = 1;
2196 local($") = ",";
2197 my $argsSignature = argsSignature( $m, $#argTypeList );
2198 my $signature = methodSignature( $m, $#argTypeList );
2199 my $mungedSignature = mungedSignature( $m, $#argTypeList );
2200 my $mungedMethod = $m->{astNodeName} . $mungedSignature;
2201 my $csharpparams = join( ", ", @csharpArgTypeList );
2203 # Ignore any methods in QGlobalSpace except those that are operator methods
2204 # with at least one arg that is the type of the current class
2205 if ( $classNode->{astNodeName} eq $main::globalSpaceClassName
2206 && $csharpClassName ne 'Qt'
2207 && $csharpClassName ne 'KDE'
2208 && !( $name =~ /^operator.*/
2209 && $name ne 'operator<<'
2210 && $name ne 'operator>>'
2211 && $csharpparams =~ /$csharpClassName / ) )
2214 } elsif ($firstUnknownArgType <= scalar(@argTypeList) || $hasDuplicateSignature || ($name =~ /^qObject$/) || $m->{Access} =~ /dcop/ || $name =~ ?[|&*/+^-]=? ) {
2215 if ( $firstUnknownArgType <= scalar(@argTypeList) || $m->{Access} =~ /dcop/ || $name =~ ?[|&*/+^-]=? ) {
2216 my $failedConversion = "\t\t// " . $m->{ReturnType} . " $name(@castedArgList[0..$#argTypeList]); >>>> NOT CONVERTED\n";
2217 if ( $m->{Access} =~ /signals/ ) {
2218 $signalCode .= $failedConversion;
2219 } else {
2220 $notConverted .= $failedConversion;
2223 } else {
2225 if ( $csharpReturnType =~ s/string\[\]/ArrayList/ ) {
2226 $addImport->{"System.Collections"} = 1;
2229 if ( $csharpReturnType =~ s/string\[\]/List<string>/ ) {
2230 $addImport->{"System.Collections.Generic"} = 1;
2233 my $cplusplusparams;
2234 my $i = 0;
2235 for my $arg (@argTypeList) {
2236 $cplusplusparams .= "," if $i++;
2237 $cplusplusparams .= "arg" . $i;
2240 my $access = $m->{Access};
2241 $access =~ s/_slots//;
2243 if ($isConstructor) {
2244 if ( $generateConstructors ) {
2245 # $proxyInterfaceCode .= "\t\t\tvoid new$csharpClassName($csharpparams);\n";
2246 $methodCode .= "\t\tpublic $csharpClassName($csharpparams) : this((Type) null) {\n";
2247 $methodCode .= "\t\t\tCreateProxy();\n";
2248 $methodCode .= smokeInvocation("interceptor", \@csharpArgTypeList, "void", $mungedMethod, $signature, $addImport);
2249 $methodCode .= "\t\t}\n";
2251 } elsif ( $mainClassNode->{Pure} && $isPure ) {
2252 if ( $#argTypeList == $#{$m->{ParamList}} ) {
2253 if ($name =~ /^sizeHint$/) {
2254 # This method is public in some places, but protected in others,
2255 # so make them all public.
2256 $access = "public";
2259 if ($name =~ /^([a-z])(.*)/) {
2260 $name = uc($1) . $2;
2263 if ($access eq 'public' && ! $isStatic) {
2264 $interfaceCode .= "\t\t$csharpReturnType $name($csharpparams);\n";
2267 # Only change the method name to start with an upper case letter
2268 # if it doesn't clash with an enum with the same name
2269 my $item = kdocAstUtil::findRef( $classNode, $name );
2270 if ( defined $item && $item->{NodeType} eq 'enum' && $name =~ /^([A-Z])(.*)/) {
2271 $name = lc($1) . $2;
2274 $methodCode .= "\t\t\[SmokeMethod(\"$signature\")]\n";
2276 if ( defined $virtualMethods->{$fullSignature}{method}
2277 || defined $overridenMethods->{$signature}{method}
2278 || (defined $overridenMethods->{$name}{method}) )
2280 if ($csharpClassName eq 'QLayout' && $name eq 'SetGeometry') {
2281 $methodCode .= "\t\t" . $access . " abstract ";
2282 } else {
2283 $methodCode .= "\t\t" . $access . " new abstract ";
2285 } else {
2286 $methodCode .= "\t\t" . $access . " abstract ";
2289 $methodCode .= $csharpReturnType;
2290 $methodCode .= " $name($csharpparams);\n";
2292 } elsif ( $name =~ /^operator.*/ && $name ne 'operator<<' && $name ne 'operator>>') {
2293 $name =~ s/ //;
2294 $name =~ s!([|&*/+^-])=!$1!;
2295 if ( $csharpSignature =~ s!([|&*/+^-])=!$1! ) {
2296 if ( $csharpMethods->{$csharpSignature} ) {
2297 print("dup method found: $csharpSignature\n");
2299 $csharpMethods->{$csharpSignature} = 1;
2301 if (!$isStatic) {
2302 # In C# operator methods must be static, so if the C++ version isn't
2303 # static, then add another arg 'lhs', the value of 'this'.
2304 $csharpparams = "$csharpClassName lhs" . ($csharpparams eq "" ? "" : ", ") . $csharpparams;
2305 unshift @csharpArgTypeList, "$csharpClassName lhs";
2306 unshift @csharpArgTypeOnlyList, $csharpClassName;
2307 $csharpSignature =~ s/\(/($csharpClassName, /;
2308 $csharpSignature =~ s/, \)/)/;
2309 if ( $csharpMethods->{$csharpSignature} ) {
2310 print("dup method found: $csharpSignature\n");
2312 $csharpMethods->{$csharpSignature} = 1;
2315 if ( $classNode->{astNodeName} ne $main::globalSpaceClassName
2316 || (@csharpArgTypeOnlyList[0] eq $csharpClassName || @csharpArgTypeOnlyList[1] eq $csharpClassName) )
2318 $proxyInterfaceCode .= "\t\t\t$csharpReturnType $operatorNames{$name}($csharpparams);\n";
2320 $staticMethodCode .= "\t\t" . $access . " static ";
2321 $staticMethodCode .= $csharpReturnType;
2323 $staticMethodCode .= " $name($csharpparams) \{\n";
2324 $staticMethodCode .= smokeInvocation("staticInterceptor", \@csharpArgTypeList, $csharpReturnType, $mungedMethod, $signature, $addImport);
2325 $staticMethodCode .= "\t\t}\n";
2328 if ( $name =~ /operator==/
2329 && ( @csharpArgTypeOnlyList[0] eq $csharpClassName || @csharpArgTypeOnlyList[1] eq $csharpClassName )
2330 && $csharpClassName ne 'Qt'
2331 && $csharpClassName ne 'KDE' )
2333 # Add a 'operator!=' method defined in terms of 'operator=='
2334 $staticMethodCode .= "\t\t" . $access . " static bool";
2335 $staticMethodCode .= " operator!=($csharpparams) \{\n";
2337 $staticMethodCode .= "\t\t\treturn ";
2338 $staticMethodCode .= "!(bool) staticInterceptor.Invoke(\"$mungedMethod\", \"$signature\", typeof($csharpReturnType)". smokeInvocationArgList(\@csharpArgTypeList) . ");\n";
2339 $staticMethodCode .= "\t\t}\n";
2341 if (!defined $mainClassNode->{HasEquals}) {
2342 $methodCode .= "\t\tpublic override bool Equals(object o) \{\n";
2343 $methodCode .= "\t\t\tif (!(o is $csharpClassName)) { return false; }\n";
2345 $methodCode .= "\t\t\treturn this == ($csharpClassName) o;\n";
2346 $methodCode .= "\t\t}\n";
2348 $methodCode .= "\t\tpublic override int GetHashCode() \{\n";
2349 $methodCode .= "\t\t\treturn interceptor.GetHashCode();\n";
2350 $methodCode .= "\t\t}\n";
2351 $mainClassNode->{HasEquals} = 1;
2355 if ( $name =~ /^operator\s*<$/
2356 && $classNode->{astNodeName} ne $main::globalSpaceClassName )
2358 my $item = kdocAstUtil::findRef( $classNode, "operator>" );
2359 if (! defined $item || $item->{Parent}->{astNodeName} eq 'Global') {
2360 $staticMethodCode .= "\t\t" . $access . " static bool";
2361 $staticMethodCode .= " operator>($csharpparams) \{\n";
2363 $staticMethodCode .= "\t\t\treturn ";
2364 $staticMethodCode .= "!(bool) staticInterceptor.Invoke(\"$mungedMethod\", \"$signature\", typeof($csharpReturnType)". smokeInvocationArgList(\@csharpArgTypeList) . ")\n";
2365 $staticMethodCode .= "\t\t\t\t\t\t&& !(bool) staticInterceptor.Invoke(\"operator==$mungedSignature\", \"operator==$argsSignature\", typeof($csharpReturnType)". smokeInvocationArgList(\@csharpArgTypeList) . ");\n";
2366 $staticMethodCode .= "\t\t}\n";
2369 } else {
2370 if ( $access eq 'public' or $access eq 'protected' ) {
2371 if ( ($csharpClassName eq 'QHeaderView' && $name =~ /^scrollTo$|^indexAt$|^visualRect$/)
2372 || ($csharpClassName eq 'QSvgGenerator' && $name =~ /^paintEngine$/)
2373 || ($csharpClassName eq 'QGridLayout' && $name =~ /^addItem$/)
2374 || ($csharpClassName eq 'QGraphicsWidget' && $name =~ /^updateGeometry$/)
2375 || $name =~ /^sizeHint$/ )
2377 # These methods are public in some places, but protected in others,
2378 # so make them all public.
2379 $access = "public";
2382 if ($name eq 'operator<<' || $name eq 'operator>>') {
2383 # 'operator<<' and 'operator>>' can only have int types as the second
2384 # arg in C#, so convert them to op_read() and op_write() calls
2385 $name = $operatorNames{$name}
2386 } elsif ($name =~ /^([a-z])(.*)/) {
2387 if ($name ne 'type') {
2388 $name = uc($1) . $2;
2391 # Only constructors can have the same name as the class
2392 if ( $name eq $csharpClassName || $name eq 'Transition' ) {
2393 $name = lc($1) . $2;
2396 # Only change the method name to start with an upper case letter
2397 # if it doesn't clash with an enum with the same name
2398 my $item = kdocAstUtil::findRef( $classNode, $name );
2399 if ( defined $item && $item->{NodeType} eq 'enum' && $name =~ /^([A-Z])(.*)/) {
2400 $name = lc($1) . $2;
2403 $item = kdocAstUtil::findRef( $classNode, "Q_PROPERTY_" . $m->{astNodeName} );
2404 if ( defined $item && $item->{NodeType} eq 'property' ) {
2405 # If there is a property with the same name, start with lower case
2406 $name = lc($1) . $2;
2409 if ($classNode->{astNodeName} eq 'QIODevice' and $name eq 'State') {
2410 $name = 'state';
2414 if ($access eq 'public' && ! $isStatic) {
2415 $interfaceCode .= "\t\t$csharpReturnType $name($csharpparams);\n";
2418 if (($isStatic or $classNode->{NodeType} eq 'namespace')) {
2419 $proxyInterfaceCode .= "\t\t\t$csharpReturnType $name($csharpparams);\n";
2422 if ( $m->{Access} =~ /_slots/ && !$isStatic ) {
2423 $methodCode .= "\t\t[Q_SLOT(\"". $m->{ReturnType} . " $signature" . "\")]\n";
2426 my $overridenVirtualMethod = $virtualMethods->{$signature}{method};
2427 $virtualMethods->{$signature}{method} = undef;
2428 my $overridenMethod = $overridenMethods->{$signature}{method};
2430 if (defined $overridenVirtualMethod || $m->{Flags} =~ "v") {
2431 $methodCode .= "\t\t\[SmokeMethod(\"$signature\")]\n";
2434 if ($isStatic or $classNode->{NodeType} eq 'namespace') {
2435 $staticMethodCode .= "\t\t$access static ";
2436 } else {
2437 $methodCode .= "\t\t$access ";
2440 if ( ($name eq 'ToString' && $csharpparams eq '')
2441 || ( ($csharpClassName =~ /^QGraphicsSvgItem$|^QGraphicsTextItem$/)
2442 && ($name eq 'Children' || $name eq 'InputMethodQuery') ) )
2444 # Tricky. QGraphicsSvgItem and QGraphicsTextItem inherit a 'children()' method from both
2445 # of their parents, and so is it resolved on the return type in C++?
2446 $methodCode .= "new ";
2447 } elsif ( defined $overridenVirtualMethod ) {
2448 # Only change the method name to start with an upper case letter
2449 # if it doesn't clash with an enum with the same name
2450 my $overrideClass = $virtualMethods->{$fullSignature}{class};
2452 # Special case looking for QStyle name clashes with methods/enums
2453 if ($csharpClassName =~ /Style/) {
2454 $overrideClass = kdocAstUtil::findRef( $rootnode, "QStyle" );
2457 my $item = kdocAstUtil::findRef( $overrideClass, $name );
2458 if ( defined $item && $item->{NodeType} eq 'enum' && $name =~ /^([A-Z])(.*)/) {
2459 $name = lc($1) . $2;
2462 $item = kdocAstUtil::findRef( $overrideClass, "Q_PROPERTY_" . $m->{astNodeName} );
2463 if ( defined $item && $item->{NodeType} eq 'property' ) {
2464 # If there is a property with the same name, start with lower case
2465 $name = lc($1) . $2;
2468 if ( $overridenVirtualMethod->{Flags} !~ "p"
2469 && ( ($overridenVirtualMethod->{Access} =~ /public/ && $m->{Access} =~ /protected/)
2470 || ($overridenVirtualMethod->{Access} =~ /protected/ && $m->{Access} =~ /public/) ) )
2472 $methodCode .= "new virtual ";
2473 } elsif ( !defined $overridenVirtualMethod->{FirstDefaultParam}
2474 && $#argTypeList < $#{$overridenVirtualMethod->{ParamList}} )
2477 } elsif ( defined $overridenVirtualMethod->{FirstDefaultParam}
2478 && $overridenVirtualMethod->{Flags} =~ "p"
2479 && $#argTypeList < $#{$overridenVirtualMethod->{ParamList}} )
2481 $methodCode .= "virtual ";
2482 } elsif ( $csharpClassName eq 'QAbstractListModel' && $name eq 'Index' && $#argTypeList == 0) {
2484 } elsif ( $ancestorCount == 0
2485 || ( $ancestorCount > 1
2486 && defined $interfacemap{$overridenVirtualMethod->{Parent}->{astNodeName}} ) )
2488 $methodCode .= "virtual ";
2489 } elsif ($overridenVirtualMethod->{Flags} =~ "p") {
2490 $methodCode .= "override ";
2491 } else {
2492 $methodCode .= "override ";
2494 } elsif ($m->{Flags} =~ "v") {
2495 if (defined $overridenMethods->{$name}{method}) {
2496 $methodCode .= "new virtual ";
2497 } else {
2498 $methodCode .= "virtual ";
2500 } elsif ( defined $overridenMethod ) {
2501 if ( $isStatic ) {
2502 $staticMethodCode .= "new ";
2503 } elsif ( $ancestorCount == 1
2504 || !defined $interfacemap{$overridenMethod->{Parent}->{astNodeName}} )
2506 $methodCode .= "new ";
2508 } elsif ( defined $overridenMethods->{$name}{method} ) {
2509 $methodCode .= "new ";
2512 if ( $name eq 'Exec'
2513 && ($csharpClassName eq 'QApplication' || $csharpClassName eq 'QCoreApplication') )
2515 $staticMethodCode .= $csharpReturnType;
2516 $staticMethodCode .= " $name($csharpparams) \{\n";
2517 $staticMethodCode .= "\t\t\tint result = (int) staticInterceptor.Invoke(\"exec\", \"exec()\", typeof(int));\n";
2518 $staticMethodCode .= "\t\t\tQyoto.SetApplicationTerminated();\n";
2519 $staticMethodCode .= "\t\t\treturn result;\n";
2520 $staticMethodCode .= "\t\t}\n";
2521 } elsif ($isStatic or $classNode->{NodeType} eq 'namespace') {
2522 $staticMethodCode .= $csharpReturnType;
2523 $staticMethodCode .= " $name($csharpparams) \{\n";
2524 $staticMethodCode .= smokeInvocation("staticInterceptor", \@csharpArgTypeList, $csharpReturnType, $mungedMethod, $signature, $addImport);
2525 $staticMethodCode .= "\t\t}\n";
2526 } else {
2527 $methodCode .= $csharpReturnType;
2528 $methodCode .= " $name($csharpparams) \{\n";
2529 $methodCode .= smokeInvocation("interceptor", \@csharpArgTypeList, $csharpReturnType, $mungedMethod, $signature, $addImport);
2530 $methodCode .= "\t\t}\n";
2532 } else {
2533 if ( $access =~ /signals/ ) {
2534 if ($name =~ /^([a-z])(.*)/) {
2535 $name = uc($1) . $2;
2537 my $docnode = $m->{DocNode};
2538 if ( defined $docnode ) {
2539 my $csharpdocComment = printCSharpdocComment( $docnode, "", "\t\t/// ", "" );
2540 $signalCode .= $csharpdocComment unless $csharpdocComment =~ /^\s*$/;
2542 $signalCode .= "\t\t[Q_SIGNAL(\"" . $m->{ReturnType} . " $signature" . "\")]\n";
2543 $signalCode .= "\t\tvoid $name($csharpparams);\n";
2549 pop @argTypeList;
2550 pop @csharpArgTypeList;
2551 pop @csharpArgTypeOnlyList;
2553 $csharpSignature = csharpMethodSignature( $m, @argTypeList );
2554 $hasDuplicateSignature = (defined $csharpMethods->{$csharpSignature} ? 1 : 0);
2556 $methodNumber++;
2557 $iterationCount--;
2558 } # Iteration loop
2560 return ( $methodCode, $staticMethodCode, $interfaceCode, $proxyInterfaceCode, $signalCode, $notConverted );
2563 sub resolveEnumValue($$)
2565 my ( $enumClass, $enumValue ) = @_;
2567 my $classNode = kdocAstUtil::findRef( $rootnode, $enumClass );
2568 my $enumType;
2570 Iter::MembersByType ( $classNode, undef,
2571 sub { my ($classNode, $enumNode ) = @_;
2573 if ( $enumNode->{NodeType} eq 'enum' ) {
2574 my @enums = split(",", $enumNode->{Params});
2575 foreach my $enum ( @enums ) {
2576 if ($enum =~ /^\s*(\w+)/) {
2577 if ($1 eq $enumValue) {
2578 $enumType = $enumNode->{astNodeName};
2583 }, undef );
2585 if (defined $enumType) {
2586 $enumType =~ s/^Type$/TypeOf/;
2587 return "$enumClass.$enumType.$enumValue";
2588 } else {
2589 return "$enumClass.$enumValue";
2593 sub generateEnum($$$)
2595 my( $classNode, $m, $generateAnonymous ) = @_; # input
2596 my $methodCode = ''; # output
2598 my @heritage = kdocAstUtil::heritage($classNode);
2599 my $className = join( "::", @heritage );
2600 my $csharpClassName = $classNode->{astNodeName};
2602 if ( ($generateAnonymous and $m->{astNodeName} ) or (! $generateAnonymous and ! $m->{astNodeName}) ) {
2603 return;
2606 if ( defined $m->{DocNode} ) {
2607 my $csharpdocComment = printCSharpdocComment( $m->{DocNode}, "", "\t/// ", "" );
2608 $methodCode .= $csharpdocComment unless $csharpdocComment =~ /^\s*$/;
2611 # In C# enums must have names, so anonymous C++ enums become constants
2612 if (! $m->{astNodeName}) {
2613 return generateConst($classNode, $m, $generateAnonymous);
2616 $m->{astNodeName} =~ /(.)(.*)/;
2618 # my $item = kdocAstUtil::findRef( $classNode, lc($1) . $2 );
2619 if ( $m->{astNodeName} eq 'Type') {
2620 # Enums and capitalized method names share the same namespace in C#, so add
2621 # 'E_' to the front to avoid a clash.
2622 $methodCode .= "\tpublic enum TypeOf {\n";
2623 } elsif ( $m->{astNodeName} eq 'ConversionFlag'
2624 || ($classNode->{astNodeName} eq 'QTextOption' and $m->{astNodeName} eq 'Flag')
2625 || ($classNode->{astNodeName} eq 'Qt' and $m->{astNodeName} eq 'Modifier')
2626 || ($classNode->{astNodeName} eq 'QGraphicsItem' and $m->{astNodeName} eq 'Extension')
2627 || ($classNode->{astNodeName} eq 'QAccessible' and $m->{astNodeName} eq 'StateFlag')
2628 || ($classNode->{astNodeName} eq 'Qt' and $m->{astNodeName} eq 'KeyboardModifier') )
2630 $methodCode .= "\tpublic enum " . $m->{astNodeName} . " : long {\n";
2631 } else {
2632 $methodCode .= "\tpublic enum " . $m->{astNodeName} . " {\n";
2635 my @enums = split(",", $m->{Params});
2636 my $enumCount = 0;
2637 foreach my $enum ( @enums ) {
2639 if ($enum =~ /.*\s(\w*)::(\w*)/) {
2640 my $result = resolveEnumValue($1, $2);
2641 $enum =~ /(.*\s)(\w*)::(\w*)(.*)/;
2642 if ( $className eq 'KProtocolInfo::ExtraField' && $m->{astNodeName} eq 'Type' ) {
2643 $enum = $1 . "(int) " . $result . $4;
2644 } else {
2645 $enum = $1 . $result . $4;
2650 if ($m->{astNodeName} ne 'KeyboardModifier') {
2651 $enum =~ s/KeyboardModifierMask/KeyboardModifier.KeyboardModifierMask/;
2654 if ($m->{astNodeName} ne 'PolicyFlag') {
2655 $enum =~ s/GrowFlag/PolicyFlag.GrowFlag/;
2656 $enum =~ s/ExpandFlag/PolicyFlag.ExpandFlag/;
2657 $enum =~ s/ShrinkFlag/PolicyFlag.ShrinkFlag/;
2658 $enum =~ s/IgnoreFlag/PolicyFlag.IgnoreFlag/;
2661 $enum =~ s/\s//g;
2662 $enum =~ s/::/./g;
2663 $enum =~ s/::([a-z])/./g;
2664 $enum =~ s/\.\././g;
2665 $enum =~ s/\(mode_t\)//;
2666 $enum =~ s/internal/_internal/;
2667 $enum =~ s/fixed/_fixed/;
2668 $enum =~ s/sizeof\(void\*\)/4/;
2669 if ( $enum =~ /(.*)=([-0-9]+)$/ ) {
2670 $methodCode .= "\t\t$1 = $2,\n";
2671 $enumCount = $2;
2672 $enumCount++;
2673 } elsif ( $enum =~ /(.*)=(.*)/ ) {
2674 my $name = $1;
2675 my $value = $2;
2676 $value =~ s/^MAX_INT$/2147483647/;
2677 $value =~ s/^SO_/QStyleOption.OptionType.SO_/;
2678 if ($classNode->{astNodeName} eq 'QStyleHintReturn' || $classNode->{astNodeName} eq 'QStyleHintReturnMask') {
2679 $value =~ s/^SH_/QStyleHintReturn.HintReturnType.SH_/;
2680 } elsif ($classNode->{astNodeName} eq 'QStyle') {
2681 $value =~ s/^SH_/QStyle.StyleHint.SH_/;
2684 $methodCode .= "\t\t$name = $value,\n";
2685 if ($value =~ /(0xf0000000)|(0xffffffff)|(0xF0000000)|(0xFFFFFFFF)/) {
2686 $methodCode =~ s/enum ((E_)?[^\s]*)/enum $1 : uint/;
2688 } else {
2689 $methodCode .= "\t\t$enum = $enumCount,\n";
2690 $enumCount++;
2694 $methodCode .= "\t}\n";
2695 $methodNumber++;
2697 return ( $methodCode );
2700 sub generateConst($$$)
2702 my( $classNode, $m, $generateAnonymous ) = @_; # input
2703 my $methodCode = ''; # output
2705 my @heritage = kdocAstUtil::heritage($classNode);
2706 my $className = join( "::", @heritage );
2707 my $csharpClassName = $classNode->{astNodeName};
2709 my @enums = split(",", $m->{Params});
2710 my $enumCount = 0;
2711 foreach my $enum ( @enums ) {
2712 $enum =~ s/\s//g;
2713 $enum =~ s/::/./g;
2714 $enum =~ s/\(mode_t\)//;
2715 $enum =~ s/internal/_internal/;
2716 $enum =~ s/fixed/_fixed/;
2717 $enum =~ s/IsActive/_IsActive/;
2719 if ($enum =~ /(.*)=(0[xX][fF][0-9a-fA-F]{7})$/) {
2720 $methodCode .= "\t\tpublic const long $1 = $2;\n";
2721 } elsif ( $enum =~ /(.*)=([-0-9]+)$/ ) {
2722 if ( $1 eq 'Type'
2723 && $classNode->{astNodeName} ne 'QGraphicsItem'
2724 && $classNode->{astNodeName} ne 'QGraphicsTextItem'
2725 && $classNode->{astNodeName} ne 'QGraphicsSvgItem' )
2727 $methodCode .= "\t\tpublic new const int $1 = $2;\n";
2728 } else {
2729 $methodCode .= "\t\tpublic const int $1 = $2;\n";
2731 $enumCount = $2;
2732 $enumCount++;
2733 } elsif ( $enum =~ /(.*)=.*static_cast<.*>\((.*)\)/ ) {
2734 $methodCode .= "\t\tpublic const int $1 = $2;\n";
2735 } elsif ( $enum =~ /(.*)=(.*)/ ) {
2736 my $name = $1;
2737 my $value = $2;
2738 if ($value =~ /\s*(\w*)\.(\w*)/) {
2739 $value = "(int) " . resolveEnumValue($1, $2);
2742 $value =~ s/^MAX_INT$/2147483647/;
2743 $methodCode .= "\t\tpublic const int $name = $value;\n";
2744 } else {
2745 $methodCode .= "\t\tpublic const int $enum = $enumCount;\n";
2746 $enumCount++;
2750 $methodNumber++;
2752 return ( $methodCode );
2755 sub generateVar($$$)
2757 my( $classNode, $m, $addImport ) = @_; # input
2758 my $methodCode = ''; # output
2759 my $interfaceCode = ''; # output
2760 my $proxyInterfaceCode = ''; # output
2762 my @heritage = kdocAstUtil::heritage($classNode);
2763 my $className = join( "::", @heritage );
2764 my $csharpClassName = $classNode->{astNodeName};
2766 my $name = $m->{astNodeName};
2767 my $varType = $m->{Type};
2768 $varType =~ s/static\s//;
2769 $varType =~ s/const\s+(.*)\s*&/$1/;
2770 $varType =~ s/\s*$//;
2771 my $fullName = "$className\::$name";
2772 $varType = cplusplusToCSharp($varType);
2773 if (!defined $varType) {
2774 return ( $methodCode, $interfaceCode, $proxyInterfaceCode );
2777 checkImportsForObject( $varType, $addImport, $classNode );
2779 my $propertyName = $name;
2780 if ( $propertyName =~ /^([a-z])(.*)/) {
2781 $propertyName = uc($1) . $2;
2784 if ( $m->{Flags} =~ "s" ) {
2785 $methodCode .= "\t\tpublic static $varType $propertyName() {\n";
2786 $methodCode .= "\t\t\treturn ($varType) staticInterceptor.Invoke(\"$name\", \"$name()\", typeof($varType));\n";
2787 $methodCode .= "\t\t}\n";
2788 $proxyInterfaceCode .= "\t\t\t$varType $name();\n";
2789 } else {
2790 # $methodCode .= "\t\tprivate $varType $name() {\n";
2791 # $methodCode .= "\t\t\treturn ($varType) interceptor.Invoke(\"$name\", \"$name()\", typeof($varType));\n";
2792 # $methodCode .= "\t\t}\n";
2793 $methodCode .= "\t\tpublic $varType $propertyName {\n";
2794 $methodCode .= "\t\t\tget { return ($varType) interceptor.Invoke(\"$name\", \"$name()\", typeof($varType)); }\n";
2795 $methodCode .= "\t\t}\n";
2796 $interfaceCode .= "\t\t". cplusplusToCSharp($varType) . " $name();\n";
2799 $methodNumber++;
2800 return ( $methodCode, $interfaceCode, $proxyInterfaceCode );
2803 sub generateProperty($$$$)
2805 my( $overridenMethods, $classNode, $m, $addImport ) = @_; # input
2806 my $methodCode = ''; # output
2808 my @heritage = kdocAstUtil::heritage($classNode);
2809 my $className = join( "::", @heritage );
2810 my $csharpClassName = $classNode->{astNodeName};
2812 my $name = $m->{astNodeName};
2814 my $resolvedType = kalyptusDataDict::resolveType($m->{Type}, $classNode, $rootnode);
2815 my $propertyType = cplusplusToCSharp( $resolvedType );
2816 if ( ! defined $propertyType ) {
2817 return ( $methodCode );
2820 checkImportsForObject( $m->{Type}, $addImport, $classNode );
2822 $name =~ s/Q_PROPERTY_//;
2823 my $propertyName = $name;
2824 if ( $propertyName =~ /^([a-z])(.*)/ && $propertyName ne 'icon') {
2825 $propertyName = uc($1) . $2;
2828 # Only change the method name to start with an upper case letter
2829 # if it doesn't clash with an enum with the same name
2830 my $uppercaseItem = kdocAstUtil::findRef( $classNode, $propertyName );
2831 if (defined $uppercaseItem && $uppercaseItem->{NodeType} eq 'enum' && $propertyName =~ /^([A-Z])(.*)/) {
2832 $propertyName = lc($1) . $2;
2835 $methodCode .= "\t\t[Q_PROPERTY(\"$resolvedType\", \"$name\")]\n";
2837 if ( defined $overridenMethods->{$propertyName}{method} ) {
2838 $methodCode .= "\t\tpublic new $propertyType $propertyName {\n";
2839 } else {
2840 $methodCode .= "\t\tpublic $propertyType $propertyName {\n";
2843 if ( defined $m->{READ} ) {
2844 $methodCode .= "\t\t\tget { return ($propertyType) interceptor.Invoke(\"$m->{READ}\", \"$m->{READ}()\", typeof($propertyType)); }\n";
2847 if ( defined $m->{WRITE} ) {
2848 $methodCode .= "\t\t\tset { interceptor.Invoke(\"$m->{WRITE}" . mungedArgType($m, $resolvedType) . "\", \"$m->{WRITE}($resolvedType)\", typeof(void), typeof($propertyType), value); }\n";
2851 $methodCode .= "\t\t}\n";
2853 return ( $methodCode );
2856 ## Called by writeClassDoc
2857 sub generateAllMethods($$$$$$)
2859 my ($classNode, $ancestorCount, $csharpMethods, $mainClassNode, $generateConstructors, $addImport) = @_;
2860 my $methodCode = '';
2861 my $staticMethodCode = '';
2862 my $interfaceCode = '';
2863 my $proxyInterfaceCode = '';
2864 my $signalCode = '';
2865 my $notConverted = '';
2866 my $extraCode = '';
2867 my $enumCode = '';
2868 $methodNumber = 0;
2869 my $className = join( "::", kdocAstUtil::heritage($classNode) );
2870 my $csharpClassName = $mainClassNode->{astNodeName};
2871 # If the C++ class had multiple inheritance, then the code for all but one of the
2872 # parents must be copied into the code for csharpClassName. Hence, for QWidget current
2873 # classname might be QPaintDevice, as its methods are needed in QWidget.
2874 my $currentClassName = join( ".", kdocAstUtil::heritage($classNode) );
2876 my $sourcename = $classNode->{Source}->{astNodeName};
2878 if ( $sourcename !~ s!.*(kio/|kparts/|dom/|kabc/|ksettings/|kjs/|ktexteditor/|kdeprint/|kdesu/)(.*)!$1$2!m ) {
2879 $sourcename =~ s!.*/(.*)!$1!m;
2881 die "Empty source name for $classNode->{astNodeName}" if ( $sourcename eq '' );
2883 $addImport->{"Qyoto"} = 1;
2884 if ($className =~ /^Plasma::/) {
2885 $addImport->{"Kimono"} = 1;
2888 my %virtualMethods;
2889 allVirtualMethods( $classNode, \%virtualMethods, $classNode );
2891 my %overridenMethods;
2892 allOverridenMethods( $classNode, \%overridenMethods, $classNode );
2894 for my $sig (keys %overridenMethods) {
2895 # print("$currentClassName sig: $overridenMethods{$sig}{class}->{astNodeName}::$sig\n");
2898 Iter::MembersByType ( $classNode, undef,
2899 sub { my ($classNode, $methodNode ) = @_;
2901 if ( $methodNode->{NodeType} eq 'enum' and $classNode->{astNodeName} eq $mainClassNode->{astNodeName} ) {
2902 my ($code) = generateEnum( $classNode, $methodNode, 0 );
2903 $enumCode .= $code;
2905 }, undef );
2907 # Do all enums first, anonymous ones and then named enums
2908 Iter::MembersByType ( $classNode, undef,
2909 sub { my ($classNode, $methodNode ) = @_;
2911 if ( $methodNode->{NodeType} eq 'enum' and $classNode->{astNodeName} eq $mainClassNode->{astNodeName} ) {
2912 my ($code) = generateEnum( $classNode, $methodNode, 1 );
2913 $extraCode .= $code;
2915 }, undef );
2917 # Then all static vars
2918 Iter::MembersByType ( $classNode, undef,
2919 sub { my ($classNode, $methodNode ) = @_;
2921 if ( $methodNode->{NodeType} eq 'var' and $classNode->{astNodeName} eq $mainClassNode->{astNodeName} ) {
2922 my ($code, $interface, $proxyInterface) = generateVar( $classNode, $methodNode, $addImport );
2923 $extraCode .= $code;
2924 $interfaceCode .= $interface;
2925 $proxyInterfaceCode .= $proxyInterface;
2927 }, undef );
2929 # Then all properties
2930 Iter::MembersByType ( $classNode, undef,
2931 sub { my ($classNode, $methodNode ) = @_;
2933 if ( $methodNode->{NodeType} eq 'property' and $classNode->{astNodeName} eq $mainClassNode->{astNodeName} ) {
2934 my ($code, $interface) = generateProperty( \%overridenMethods, $classNode, $methodNode, $addImport );
2935 $extraCode .= $code;
2937 }, undef );
2939 # Then all methods
2940 Iter::MembersByType ( $classNode, undef,
2941 sub { my ($classNode, $methodNode ) = @_;
2943 if ( $methodNode->{NodeType} eq 'method' ) {
2944 my ($meth, $static, $interface, $proxyInterface, $signals, $notconv) = generateMethod( \%virtualMethods, \%overridenMethods, $classNode, $methodNode, $addImport, $ancestorCount, $csharpMethods, $mainClassNode, $generateConstructors );
2945 $methodCode .= $meth;
2946 $staticMethodCode .= $static;
2947 $interfaceCode .= $interface;
2948 $proxyInterfaceCode .= $proxyInterface;
2949 $signalCode .= $signals;
2950 $notConverted .= $notconv;
2952 }, undef );
2954 for my $sig (keys %virtualMethods) {
2955 if ( $virtualMethods{$sig}{method}->{Flags} =~ /[p]/
2956 && $classNode->{astNodeName} ne $virtualMethods{$sig}{class}->{astNodeName}
2957 && ! exists $classNode->{Pure} )
2959 # If a pure virtual method in the superclass hasn't been overriden, then C++ will
2960 # assume it is still ok to instantiate instances of the class as long as it hasn't got
2961 # its own pure virtual methods. However, in C# this isn't allowed, and so we need
2962 # to add 'dummy' method calls here to cover the non-overriden pure virtual methods,
2963 # and avoid needing to make the class abstract.
2964 my $docNode = $virtualMethods{$sig}{method}->{DocNode};
2965 $virtualMethods{$sig}{method}->{DocNode} = undef;
2966 my ($meth, $static, $interface, $proxyInterface, $signals, $notconv) = generateMethod( \%virtualMethods, \%overridenMethods, $classNode, $virtualMethods{$sig}{method}, $addImport, $ancestorCount, $csharpMethods, $mainClassNode, $generateConstructors );
2967 $virtualMethods{$sig}{method}->{DocNode} = $docNode;
2968 if ( $meth =~ /override/ ) {
2969 $methodCode .= "\t\t// WARNING: Unimplemented C++ pure virtual - DO NOT CALL\n";
2970 $methodCode .= $meth;
2971 $staticMethodCode .= $static;
2972 $interfaceCode .= $interface;
2973 $proxyInterfaceCode .= $proxyInterface;
2974 $signalCode .= $signals;
2975 $notConverted .= $notconv;
2980 if ( $classNode->{astNodeName} eq $csharpClassName
2981 && $classNode->{HasPublicDestructor}
2982 && $classNode->{CanBeInstanciated}
2983 && !$classNode->{Pure} )
2985 if ( $generateConstructors && $csharpClassName ne 'Qt' ) {
2986 $methodCode .= "\t\t~$csharpClassName() {\n";
2987 if ($csharpClassName eq 'QModelIndex') {
2988 $methodCode .= "\t\t\tQAbstractItemModel.DerefIndexHandle(InternalPointer());\n";
2990 $methodCode .= "\t\t\tinterceptor.Invoke(\"~$classNode->{astNodeName}\", \"~$classNode->{astNodeName}()\", typeof(void));\n\t\t}\n";
2992 my $overridenMethod = $overridenMethods{~$classNode->{astNodeName}}{method};
2993 if ( defined $overridenMethod
2994 && $classNode->{astNodeName} ne 'QObject'
2995 && ( $ancestorCount == 1
2996 || !defined $interfacemap{$overridenMethod->{Parent}->{astNodeName}} ) )
2998 $methodCode .= "\t\tpublic new ";
2999 } else {
3000 $methodCode .= "\t\tpublic ";
3002 $methodCode .= "void Dispose() {\n";
3003 if ($csharpClassName eq 'QModelIndex') {
3004 $methodCode .= "\t\t\tQAbstractItemModel.DerefIndexHandle(InternalPointer());\n";
3006 $methodCode .= "\t\t\tinterceptor.Invoke(\"~$classNode->{astNodeName}\", \"~$classNode->{astNodeName}()\", typeof(void));\n\t\t}\n";
3008 $methodNumber++;
3011 return ( $methodCode, $staticMethodCode, $interfaceCode, $proxyInterfaceCode, $signalCode, $extraCode, $enumCode, $notConverted );
3014 # Return 0 if the class has no virtual dtor, 1 if it has, 2 if it's private
3015 sub hasVirtualDestructor($$)
3017 my ( $classNode, $startNode ) = @_;
3018 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3019 return if ( $skippedClasses{$className} || defined $interfacemap{$className} );
3021 my $parentHasIt;
3022 # Look at ancestors, and (recursively) call hasVirtualDestructor for each
3023 # It's enough to have one parent with a prot/public virtual dtor
3024 Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
3025 my $vd = hasVirtualDestructor( $_[0], $_[1] );
3026 $parentHasIt = $vd unless $parentHasIt > $vd;
3027 } );
3028 return $parentHasIt if $parentHasIt; # 1 or 2
3030 # Now look in $classNode - including private methods
3031 my $doPrivate = $main::doPrivate;
3032 $main::doPrivate = 1;
3033 my $result;
3034 Iter::MembersByType ( $classNode, undef,
3035 sub { my ($classNode, $m ) = @_;
3036 return unless( $m->{NodeType} eq "method" && $m->{ReturnType} eq '~' );
3038 if ( $m->{Flags} =~ /[vp]/ && $classNode != $startNode) {
3039 if ( $m->{Access} =~ /private/ ) {
3040 $result=2; # private virtual
3041 } else {
3042 $result=1; # [protected or public] virtual
3046 undef
3048 $main::doPrivate = $doPrivate;
3049 $result=0 if (!defined $result);
3050 return $result;
3053 =head2 allVirtualMethods
3055 Parameters: class node, dict
3057 Adds to the dict, for all method nodes that are virtual, in this class and in parent classes :
3058 {method} the method node, {class} the class node (the one where the virtual is implemented)
3060 =cut
3062 sub allVirtualMethods($$$)
3064 my ( $classNode, $virtualMethods, $startNode ) = @_;
3065 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3066 return if ( $skippedClasses{$className} );
3068 # Look at ancestors, and (recursively) call allVirtualMethods for each
3069 # This is done first, so that virtual methods that are reimplemented as 'private'
3070 # can be removed from the list afterwards (below)
3071 Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
3072 allVirtualMethods( @_[0], $virtualMethods, $startNode );
3073 }, undef
3076 # Now look for virtual methods in $classNode - including private ones
3077 my $doPrivate = $main::doPrivate;
3078 $main::doPrivate = 1;
3079 Iter::MembersByType ( $classNode, undef,
3080 sub { my ($classNode, $m ) = @_;
3081 # Only interested in methods, and skip destructors
3082 return unless( $m->{NodeType} eq "method" && $m->{ReturnType} ne '~' );
3084 my @args = @{ $m->{ParamList} };
3085 my $last = $m->{FirstDefaultParam};
3086 $last = scalar @args unless defined $last;
3087 my $iterationCount = scalar(@args) - $last;
3088 while($iterationCount >= 0) {
3089 my $signature = methodSignature( $m, $#args );
3090 print STDERR $signature . " ($m->{Access})\n" if ($debug);
3092 # A method is virtual if marked as such (v=virtual p=pure virtual)
3093 # or if a parent method with same signature was virtual
3094 if ( $m->{Flags} =~ /[vp]/ or defined $virtualMethods->{$signature} ) {
3095 if ( $m->{Access} =~ /private/ ) {
3096 if ( defined $virtualMethods->{$signature} ) { # remove previously defined
3097 delete $virtualMethods->{$signature};
3099 # else, nothing, just ignore private virtual method
3100 } elsif ( $classNode->{astNodeName} ne $startNode->{astNodeName} ) {
3101 $virtualMethods->{$signature}{method} = $m;
3102 $virtualMethods->{$signature}{class} = $classNode;
3106 pop @args;
3107 $iterationCount--;
3110 undef
3112 $main::doPrivate = $doPrivate;
3115 sub allOverridenMethods($$$)
3117 my ( $classNode, $overridenMethods, $startNode ) = @_;
3118 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3119 return if ( $skippedClasses{$className} );
3121 my $qtnode;
3122 if ( $classNode->{astNodeName} eq 'QObject' ) {
3123 $qtnode = kdocAstUtil::findRef( $rootnode, "Qt" );
3124 if ( defined $qtnode ) {
3125 allOverridenMethods( $qtnode, $overridenMethods, $startNode );
3129 Iter::Ancestors( $classNode, $qtnode, undef, undef, sub {
3130 allOverridenMethods( @_[0], $overridenMethods, $startNode );
3131 }, undef
3134 # Look at ancestors, and (recursively) call allOverridenMethods for each
3135 # This is done first, so that virtual methods that are reimplemented as 'private'
3136 # can be removed from the list afterwards (below)
3137 Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
3138 allOverridenMethods( @_[0], $overridenMethods, $startNode );
3139 }, undef
3142 # Now look for virtual methods in $classNode - including private ones
3143 Iter::MembersByType ( $classNode, undef,
3144 sub { my ($classNode, $m ) = @_;
3145 # Only interested in methods, and skip destructors
3146 return unless( $m->{NodeType} eq "method" or $m->{NodeType} eq "enum" or $m->{NodeType} eq "property" );
3148 my $signature = methodSignature( $m, $#{$m->{ParamList}} );
3149 print STDERR $signature . " ($m->{Access})\n" if ($debug);
3151 if ( $classNode->{astNodeName} ne $startNode->{astNodeName} && $classNode->{astNodeName} ne 'Global' ) {
3152 if ( $m->{NodeType} eq "enum" ) {
3153 $overridenMethods->{$m->{astNodeName}}{method} = $m;
3154 $overridenMethods->{$m->{astNodeName}}{class} = $classNode;
3155 } elsif ( $m->{NodeType} eq "property" ) {
3156 my $name = $m->{astNodeName};
3157 if ( $name =~ s/Q_PROPERTY_([a-z])(.*)// ) {
3158 $name = uc($1) . $2;
3161 $overridenMethods->{$name}{method} = $m;
3162 $overridenMethods->{$name}{class} = $classNode;
3163 } elsif ( $m->{ReturnType} eq '~' ) {
3164 if ( ! exists $classNode->{Pure} ) {
3165 $overridenMethods->{~$startNode->{astNodeName}}{method} = $m;
3166 $overridenMethods->{~$startNode->{astNodeName}}{class} = $classNode;
3168 } elsif ( $m->{Access} =~ /private/ ) {
3169 if ( defined $overridenMethods->{$signature} ) { # remove previously defined
3170 delete $overridenMethods->{$signature};
3172 # else, nothing, just ignore private virtual method
3173 } else {
3174 my @args = @{ $m->{ParamList} };
3175 my $last = $m->{FirstDefaultParam};
3176 $last = scalar @args unless defined $last;
3177 my $iterationCount = scalar(@args) - $last;
3178 while($iterationCount >= 0) {
3179 my $signature = methodSignature( $m, $#args );
3181 my $propertyName = $m->{astNodeName};
3182 if ( @{$m->{ParamList}} == 1 && $propertyName =~ /^set(.)(.*)/ ) {
3183 $propertyName = "Q_PROPERTY_" . lc($1) . $2;
3184 my $item = kdocAstUtil::findRef( $classNode, $propertyName );
3185 if ( defined $item && $item->{NodeType} eq 'property' ) {
3186 # If there is a property with the same name, don't bother
3187 $signature = "";
3192 if ($signature ne "") {
3193 $overridenMethods->{$signature}{method} = $m;
3194 $overridenMethods->{$signature}{class} = $classNode;
3197 pop @args;
3198 $iterationCount--;
3203 undef
3207 # Known typedef? If so, apply it.
3208 sub applyTypeDef($)
3210 my $type = shift;
3211 # Parse 'const' in front of it, and '*' or '&' after it
3212 my $prefix = $type =~ s/^const\s+// ? 'const ' : '';
3213 my $suffix = $type =~ s/\s*([\&\*]+)$// ? $1 : '';
3215 if (exists $typedeflist{$type}) {
3216 return $prefix.$typedeflist{$type}.$suffix;
3218 return $prefix.$type.$suffix;
3221 # Register type ($1) into %allTypes if not already there
3222 sub registerType($$) {
3223 my $type = shift;
3224 #print "registerType: $type\n" if ($debug);
3226 $type =~ s/\s+const$//; # for 'char* const'
3227 $type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
3229 return if ( $type eq 'void' or $type eq '' or $type eq '~' );
3230 die if ( $type eq '...' ); # ouch
3232 # Let's register the real type, not its known equivalent
3233 #$type = applyTypeDef($type);
3235 # Enum _value_ -> get corresponding type
3236 if (exists $enumValueToType{$type}) {
3237 $type = $enumValueToType{$type};
3240 # Already in allTypes
3241 if(exists $allTypes{$type}) {
3242 return;
3245 die if $type eq 'QTextEdit::UndoRedoInfo::Type';
3246 die if $type eq '';
3248 my $realType = $type;
3250 # Look for references (&) and pointers (* or **) - this will not handle *& correctly.
3251 # We do this parsing here because both the type list and iterproto need it
3252 if($realType =~ s/&$//) {
3253 $allTypes{$type}{typeFlags} = 'Smoke::tf_ref';
3255 elsif($realType ne 'void*' && $realType =~ s/\*$//) {
3256 $allTypes{$type}{typeFlags} = 'Smoke::tf_ptr';
3258 else {
3259 $allTypes{$type}{typeFlags} = 'Smoke::tf_stack';
3262 if ( $realType =~ s/^const\s+// ) { # Remove 'const'
3263 $allTypes{$type}{typeFlags} .= ' | Smoke::tf_const';
3266 # Apply typedefs, and store the resulting type.
3267 # For instance, if $type was Q_UINT16&, realType will be ushort
3268 $allTypes{$type}{realType} = applyTypeDef( $realType );
3270 # In the first phase we only create entries into allTypes.
3271 # The values (indexes) are calculated afterwards, once the list is full.
3272 $allTypes{$type}{index} = -1;
3273 #print STDERR "Register $type. Realtype: $realType\n" if($debug);
3276 # Get type from %allTypes
3277 # This returns a hash with {index}, {isEnum}, {typeFlags}, {realType}
3278 # (and {typeId} after the types array is written by writeSmokeDataFile)
3279 sub findTypeEntry($) {
3280 my $type = shift;
3281 my $typeIndex = -1;
3282 $type =~ s/\s+const$//; # for 'char* const'
3283 $type =~ s/\s+const\s*\*$/\*/; # for 'char* const*'
3285 return undef if ( $type =~ '~' or $type eq 'void' or $type eq '' );
3287 # Enum _value_ -> get corresponding type
3288 if (exists $enumValueToType{$type}) {
3289 $type = $enumValueToType{$type};
3292 if ( ! defined $allTypes{$type} ) {
3293 print("type not known: $type\n");
3294 return undef;
3297 # die "type not known: $type" unless defined $allTypes{$type};
3298 return $allTypes{ $type };
3301 # List of all csharp super-classes for a given class, via single inheritance.
3302 # Excluding any which are mapped onto interfaces to avoid multiple inheritance.
3303 sub direct_superclass_list($)
3305 my $classNode = shift;
3306 my @super;
3307 my $has_ancestor = 0;
3308 my $direct_ancestor = undef;
3309 my $name;
3311 Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
3312 ( $direct_ancestor, $name ) = @_;
3313 if ($name =~ /QMemArray|QSqlFieldInfoList/) {
3314 # Template classes, give up for now..
3315 $has_ancestor = 1;
3316 } elsif (!defined $interfacemap{$name}) {
3317 push @super, $direct_ancestor;
3318 push @super, direct_superclass_list( $direct_ancestor );
3319 $has_ancestor = 1;
3321 }, undef );
3323 if (! $has_ancestor and defined $direct_ancestor) {
3324 push @super, $direct_ancestor;
3325 push @super, direct_superclass_list( $direct_ancestor );
3328 return @super;
3331 # List of all super-classes for a given class
3332 sub superclass_list($)
3334 my $classNode = shift;
3335 my @super;
3336 Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
3337 push @super, @_[0];
3338 push @super, superclass_list( @_[0] );
3339 }, undef );
3340 return @super;
3343 sub is_kindof($$)
3345 my $classNode = shift;
3346 my $className = shift;
3348 if ($classNode->{astNodeName} eq $className) {
3349 return 1;
3352 my @superclasses = superclass_list($classNode);
3353 foreach my $ancestor (@superclasses) {
3354 if ($ancestor->{astNodeName} eq $className) {
3355 return 1;
3359 return 0;
3362 # Store the {case} dict in the class Node (method signature -> index in the "case" switch)
3363 # This also determines which methods should NOT be in the switch, and sets {SkipFromSwitch} for them
3364 sub prepareCaseDict($) {
3366 my $classNode = shift;
3367 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3368 $classNode->AddProp("case", {});
3369 my $methodNumber = 0;
3371 # First look at all enums for this class
3372 Iter::MembersByType ( $classNode, undef,
3373 sub { my ($classNode, $m ) = @_;
3375 next unless $m->{NodeType} eq 'enum';
3376 foreach my $val ( @{$m->{ParamList}} ) {
3377 my $fullEnumName = "$className\::".$val->{ArgName};
3378 print STDERR "Enum: $fullEnumName -> case $methodNumber\n" if ($debug);
3379 $classNode->{case}{$fullEnumName} = $methodNumber;
3380 $enumValueToType{$fullEnumName} = "$className\::$m->{astNodeName}";
3381 $methodNumber++;
3383 }, undef );
3385 # Check for static vars
3386 Iter::MembersByType ( $classNode, undef,
3387 sub { my ($classNode, $m ) = @_;
3389 next unless $m->{NodeType} eq 'var';
3390 my $name = "$className\::".$m->{astNodeName};
3391 print STDERR "Var: $name -> case $methodNumber\n" if ($debug);
3392 $classNode->{case}{$name} = $methodNumber;
3393 $methodNumber++;
3395 }, undef );
3398 # Now look at all methods for this class
3399 Iter::MembersByType ( $classNode, undef,
3400 sub { my ($classNode, $m ) = @_;
3402 next unless $m->{NodeType} eq 'method';
3403 my $name = $m->{astNodeName};
3404 my $isConstructor = ($name eq $classNode->{astNodeName} );
3405 if ($isConstructor and ($m->{ReturnType} eq '~')) # destructor
3407 # Remember whether we'll generate a switch entry for the destructor
3408 $m->{SkipFromSwitch} = 1 unless ($classNode->{CanBeInstanciated} and $classNode->{HasPublicDestructor});
3409 next;
3412 # Don't generate bindings for protected methods (incl. signals) if
3413 # we're not deriving from the C++ class. Only take public and public_slots
3414 my $ok = ( $classNode->{BindingDerives} or $m->{Access} =~ /public/ ) ? 1 : 0;
3416 # Don't generate bindings for pure virtuals - we can't call them ;)
3417 $ok = 0 if ( $ok && $m->{Flags} =~ "p" );
3419 # Bugfix for Qt-3.0.4: those methods are NOT implemented (report sent).
3420 $ok = 0 if ( $ok && $className eq 'QLineEdit' && ( $name eq 'setPasswordChar' || $name eq 'passwordChar' ) );
3421 $ok = 0 if ( $ok && $className eq 'QWidgetItem' && $name eq 'widgetSizeHint' );
3423 if ( !$ok )
3425 #print STDERR "Skipping $className\::$name\n" if ($debug);
3426 $m->{SkipFromSwitch} = 1;
3427 next;
3430 my @args = @{ $m->{ParamList} };
3431 my $last = $m->{FirstDefaultParam};
3432 $last = scalar @args unless defined $last;
3433 my $iterationCount = scalar(@args) - $last;
3434 while($iterationCount >= 0) {
3435 my $sig = methodSignature( $m, $#args );
3436 $classNode->{case}{$sig} = $methodNumber;
3437 #print STDERR "prepareCaseDict: registered case number $methodNumber for $sig in $className()\n" if ($debug);
3438 pop @args;
3439 $iterationCount--;
3440 $methodNumber++;
3442 }, undef );
3444 # Add the destructor, at the end
3445 if ($classNode->{CanBeInstanciated} and $classNode->{HasPublicDestructor}) {
3446 $classNode->{case}{"~$className()"} = $methodNumber;
3447 # workaround for ~Sub::Class() being seen as Sub::~Class()
3448 $classNode->{case}{"~$classNode->{astNodeName}()"} = $methodNumber;
3449 #print STDERR "prepareCaseDict: registered case number $methodNumber for ~$className()\n" if ($debug);
3453 sub writeSmokeDataFile($) {
3454 my $rootnode = shift;
3456 # Make list of classes
3457 my %allImports; # list of all header files for all classes
3458 my @classlist;
3459 push @classlist, ""; # Prepend empty item for "no class"
3460 my %enumclasslist;
3461 Iter::LocalCompounds( $rootnode, sub {
3462 my $classNode = $_[0];
3463 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3465 return if $classNode->{NodeType} eq 'namespace';
3467 push @classlist, $className;
3468 $enumclasslist{$className}++ if keys %{$classNode->{enumerations}};
3469 $classNode->{ClassIndex} = $#classlist;
3470 addImportForClass( $classNode, \%allImports, undef );
3471 } );
3473 my %classidx = do { my $i = 0; map { $_ => $i++ } @classlist };
3475 my $file = "$outputdir/smokedata.cpp";
3476 # open OUT, ">$file" or die "Couldn't create $file\n";
3478 # foreach my $incl (sort{
3479 # return 1 if $a=~/qmotif/; # move qmotif* at bottom (they include dirty X11 headers)
3480 # return -1 if $b=~/qmotif/;
3481 # return -1 if substr($a,0,1) eq 'q' and substr($b,0,1) ne 'q'; # move Qt headers on top
3482 # return 1 if substr($a,0,1) ne 'q' and substr($b,0,1) eq 'q';
3483 # $a cmp $b
3484 # } keys %allIncludes) {
3485 # die if $imp eq '';
3486 # print OUT "import $imp;\n";
3487 # }
3489 # print OUT "\n";
3491 print STDERR "Writing ${libname}_cast function\n" if ($debug);
3493 # Prepare descendants information for each class
3494 my %descendants; # classname -> list of descendant nodes
3495 Iter::LocalCompounds( $rootnode, sub {
3496 my $classNode = shift;
3497 # Get _all_ superclasses (up any number of levels)
3498 # and store that $classNode is a descendant of $s
3499 my @super = superclass_list($classNode);
3500 for my $s (@super) {
3501 my $superClassName = join( "::", kdocAstUtil::heritage($s) );
3502 Ast::AddPropList( \%descendants, $superClassName, $classNode );
3504 } );
3506 # Iterate over all classes, to write the xtypecast function
3507 Iter::LocalCompounds( $rootnode, sub {
3508 my $classNode = shift;
3509 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3510 # @super will contain superclasses, the class itself, and all descendants
3511 my @super = superclass_list($classNode);
3512 push @super, $classNode;
3513 if ( defined $descendants{$className} ) {
3514 push @super, @{$descendants{$className}};
3516 my $cur = $classidx{$className};
3518 return if $classNode->{NodeType} eq 'namespace';
3520 # print OUT " case $cur:\t//$className\n";
3521 # print OUT "\tswitch(to) {\n";
3522 # $cur = -1;
3523 # my %casevalues;
3524 # for my $s (@super) {
3525 # my $superClassName = join( "::", kdocAstUtil::heritage($s) );
3526 # next if !defined $classidx{$superClassName}; # inherits from unknown class, see below
3527 # next if $classidx{$superClassName} == $cur; # shouldn't happen in Qt
3528 # next if $s->kdocAstUtil::inheritsAsVirtual($classNode); # can't cast from a virtual base class
3529 # $cur = $classidx{$superClassName}; # KDE has MI with diamond shaped cycles (cf. KXMLGUIClient)
3530 # next if $casevalues{$cur}; # ..so skip any duplicate parents
3531 # print OUT "\t case $cur: return (void*)($superClassName*)($className*)xptr;\n";
3532 # $casevalues{$cur} = 1;
3534 # print OUT "\t default: return xptr;\n";
3535 # print OUT "\t}\n";
3536 } );
3537 # print OUT " default: return xptr;\n";
3538 # print OUT " }\n";
3539 # print OUT "}\n\n";
3542 # Write inheritance array
3543 # Imagine you have "Class : public super1, super2"
3544 # The inheritlist array will get 3 new items: super1, super2, 0
3545 my %inheritfinder; # key = (super1, super2) -> data = (index in @inheritlist). This one allows reuse.
3546 my %classinherit; # we store that index in %classinherit{className}
3547 # We don't actually need to store inheritlist in memory, we write it
3548 # directly to the file. We only need to remember its current size.
3549 my $inheritlistsize = 1;
3551 # print OUT "// Group of class IDs (0 separated) used as super class lists.\n";
3552 # print OUT "// Classes with super classes have an index into this array.\n";
3553 # print OUT "static short ${libname}_inheritanceList[] = {\n";
3554 # print OUT "\t0,\t// 0: (no super class)\n";
3555 Iter::LocalCompounds( $rootnode, sub {
3556 my $classNode = shift;
3557 my $className = join( "__", kdocAstUtil::heritage($classNode) );
3559 return if $classNode->{NodeType} eq 'namespace';
3561 print STDERR "inheritanceList: looking at $className\n" if ($debug);
3563 # Make list of direct ancestors
3564 my @super;
3565 Iter::Ancestors( $classNode, $rootnode, undef, undef, sub {
3566 my $superClassName = join( "::", kdocAstUtil::heritage($_[0]) );
3567 push @super, $superClassName;
3568 }, undef );
3569 # Turn that into a list of class indexes
3570 my $key = '';
3571 foreach my $superClass( @super ) {
3572 if (defined $classidx{$superClass}) {
3573 $key .= ', ' if ( length $key > 0 );
3574 $key .= $classidx{$superClass};
3577 if ( $key ne '' ) {
3578 if ( !defined $inheritfinder{$key} ) {
3579 print OUT "\t";
3580 my $index = $inheritlistsize; # Index of first entry (for this group) in inheritlist
3581 foreach my $superClass( @super ) {
3582 if (defined $classidx{$superClass}) {
3583 print OUT "$classidx{$superClass}, ";
3584 $inheritlistsize++;
3587 $inheritlistsize++;
3588 my $comment = join( ", ", @super );
3589 print OUT "0,\t// $index: $comment\n";
3590 $inheritfinder{$key} = $index;
3592 $classinherit{$className} = $inheritfinder{$key};
3593 } else { # No superclass
3594 $classinherit{$className} = 0;
3596 } );
3597 # print OUT "};\n\n";
3600 # print OUT "// These are the xenum functions for manipulating enum pointers\n";
3601 for my $className (keys %enumclasslist) {
3602 my $c = $className;
3603 $c =~ s/::/__/g;
3604 # print OUT "void xenum_$c\(Smoke::EnumOperation, Smoke::Index, void*&, long&);\n";
3606 # print OUT "\n";
3607 # print OUT "// Those are the xcall functions defined in each x_*.cpp file, for dispatching method calls\n";
3608 my $firstClass = 1;
3609 for my $className (@classlist) {
3610 if ($firstClass) {
3611 $firstClass = 0;
3612 next;
3614 my $c = $className; # make a copy
3615 $c =~ s/::/__/g;
3616 # print OUT "void xcall_$c\(Smoke::Index, void*, Smoke::Stack);\n";
3618 # print OUT "\n";
3620 # Write class list afterwards because it needs offsets to the inheritance array.
3621 # print OUT "// List of all classes\n";
3622 # print OUT "// Name, index into inheritanceList, method dispatcher, enum dispatcher, class flags\n";
3623 # print OUT "static Smoke::Class ${libname}_classes[] = {\n";
3624 my $firstClass = 1;
3625 Iter::LocalCompounds( $rootnode, sub {
3626 my $classNode = shift;
3627 my $className = join( "__", kdocAstUtil::heritage($classNode) );
3629 return if $classNode->{NodeType} eq 'namespace';
3631 if ($firstClass) {
3632 $firstClass = 0;
3633 print OUT "\t{ 0L, 0, 0, 0, 0 }, \t// 0 (no class)\n";
3635 my $c = $className;
3636 $c =~ s/::/__/g;
3637 my $xcallFunc = "xcall_$c";
3638 my $xenumFunc = "0";
3639 $xenumFunc = "xenum_$c" if exists $enumclasslist{$className};
3640 # %classinherit needs Foo__Bar, not Foo::Bar?
3641 die "problem with $className" unless defined $classinherit{$c};
3643 my $xClassFlags = 0;
3644 $xClassFlags .= "|Smoke::cf_constructor" if $classNode->{CanBeInstanciated}; # correct?
3645 $xClassFlags .= "|Smoke::cf_deepcopy" if $classNode->{CanBeCopied}; # HasCopyConstructor would be wrong (when it's private)
3646 $xClassFlags .= "|Smoke::cf_virtual" if hasVirtualDestructor($classNode, $classNode) == 1;
3647 # $xClassFlags .= "|Smoke::cf_undefined" if ...;
3648 $xClassFlags =~ s/0\|//; # beautify
3649 # print OUT "\t{ \"$className\", $classinherit{$c}, $xcallFunc, $xenumFunc, $xClassFlags }, \t//$classidx{$className}\n";
3650 } );
3651 # print OUT "};\n\n";
3654 # print OUT "// List of all types needed by the methods (arguments and return values)\n";
3655 # print OUT "// Name, class ID if arg is a class, and TypeId\n";
3656 # print OUT "static Smoke::Type ${libname}_types[] = {\n";
3657 my $typeCount = 0;
3658 $allTypes{''}{index} = 0; # We need an "item 0"
3659 for my $type (sort keys %allTypes) {
3660 $allTypes{$type}{index} = $typeCount; # Register proper index in allTypes
3661 if ( $typeCount == 0 ) {
3662 # print OUT "\t{ 0, 0, 0 },\t//0 (no type)\n";
3663 $typeCount++;
3664 next;
3666 my $isEnum = $allTypes{$type}{isEnum};
3667 my $typeId;
3668 my $typeFlags = $allTypes{$type}{typeFlags};
3669 my $realType = $allTypes{$type}{realType};
3670 die "$type" if !defined $typeFlags;
3671 # die "$realType" if $realType =~ /\(/;
3672 # First write the name
3673 # print OUT "\t{ \"$type\", ";
3674 # Then write the classId (and find out the typeid at the same time)
3675 if(exists $classidx{$realType}) { # this one first, we want t_class for QBlah*
3676 $typeId = 't_class';
3677 # print OUT "$classidx{$realType}, ";
3679 elsif($type =~ /&$/ || $type =~ /\*$/) {
3680 $typeId = 't_voidp';
3681 # print OUT "0, "; # no classId
3683 elsif($isEnum || $allTypes{$realType}{isEnum}) {
3684 $typeId = 't_enum';
3685 if($realType =~ /(.*)::/) {
3686 my $c = $1;
3687 if($classidx{$c}) {
3688 # print OUT "$classidx{$c}, ";
3689 } else {
3690 # print OUT "0 /* unknown class $c */, ";
3692 } else {
3693 # print OUT "0 /* unknown $realType */, "; # no classId
3696 else {
3697 $typeId = $typeunion{$realType};
3698 if (defined $typeId) {
3699 $typeId =~ s/s_/t_/; # from s_short to t_short for instance
3701 else {
3702 # Not a known class - ouch, this happens quite a lot
3703 # (private classes, typedefs, template-based types, etc)
3704 if ( $skippedClasses{$realType} ) {
3705 # print STDERR "$realType has been skipped, using t_voidp for it\n";
3706 } else {
3707 unless( $realType =~ /</ ) { # Don't warn for template stuff...
3708 print STDERR "$realType isn't a known type (type=$type)\n";
3711 $typeId = 't_voidp'; # Unknown -> map to a void *
3713 # print OUT "0, "; # no classId
3715 # Then write the flags
3716 die "$type" if !defined $typeId;
3717 # print OUT "Smoke::$typeId | $typeFlags },";
3718 # print OUT "\t//$typeCount\n";
3719 $typeCount++;
3720 # Remember it for coerce_type
3721 $allTypes{$type}{typeId} = $typeId;
3723 # print OUT "};\n\n";
3726 my %arglist; # registers the needs for argumentList (groups of type ids)
3727 my %methods;
3728 # Look for all methods and all enums, in all classes
3729 # And fill in methods and arglist. This loop writes nothing to OUT.
3730 Iter::LocalCompounds( $rootnode, sub {
3731 my $classNode = shift;
3732 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3733 print STDERR "writeSmokeDataFile: arglist: looking at $className\n" if ($debug);
3735 Iter::MembersByType ( $classNode, undef,
3736 sub { my ($classNode, $m ) = @_;
3738 my $methName = $m->{astNodeName};
3739 # For destructors, get a proper signature that includes the '~'
3740 if ( $m->{ReturnType} eq '~' )
3742 $methName = '~' . $methName ;
3743 # Let's even store that change, otherwise we have to do it many times
3744 $m->{astNodeName} = $methName;
3747 if( $m->{NodeType} eq "enum" ) {
3749 foreach my $enum ( @{$m->{ParamList}} ) {
3750 my $enumName = $enum->{ArgName};
3751 $methods{$enumName}++;
3754 } elsif ( $m->{NodeType} eq 'var' ) {
3756 $methods{$m->{astNodeName}}++;
3758 } elsif( $m->{NodeType} eq "method" ) {
3760 $methods{$methName}++;
3761 my @protos;
3762 makeprotos(\%classidx, $m, \@protos);
3764 #print "made @protos from $className $methName $m->{Signature})\n" if ($debug);
3765 for my $p (@protos) {
3766 $methods{$p}++;
3767 my $argcnt = 0;
3768 $argcnt = length($1) if $p =~ /([\$\#\?]+)/;
3769 my $sig = methodSignature($m, $argcnt-1);
3770 # Store in a class hash named "proto", a proto+signature => method association
3771 $classNode->{proto}{$p}{$sig} = $m;
3772 #$classNode->{signature}{$sig} = $p;
3773 # There's probably a way to do this better, but this is the fastest way
3774 # to get the old code going: store classname into method
3775 $m->{class} = $className;
3778 my $firstDefaultParam = $m->{FirstDefaultParam};
3779 $firstDefaultParam = scalar(@{ $m->{ParamList} }) unless defined $firstDefaultParam;
3780 my $argNames = '';
3781 my $args = '';
3782 for(my $i = 0; $i < @{ $m->{ParamList} }; $i++) {
3783 $args .= ', ' if $i;
3784 $argNames .= ', ' if $i;
3785 my $argType = $m->{ParamList}[$i]{ArgType};
3786 my $typeEntry = findTypeEntry( $argType );
3787 $args .= defined $typeEntry ? $typeEntry->{index} : 0;
3788 $argNames .= $argType;
3790 if($i >= ($firstDefaultParam - 1)) {
3791 #print "arglist entry: $args\n";
3792 $arglist{$args} = $argNames;
3796 # create an entry for e.g. "arg0,arg1,arg2" where argN is index in allTypes of type for argN
3797 # The value, $argNames, is temporarily stored, to be written out as comment
3798 # It gets replaced with the index in the next loop.
3799 #print "arglist entry : $args\n";
3800 $arglist{$args} = $argNames;
3802 }, # end of sub
3803 undef
3808 $arglist{''} = 0;
3809 # Print arguments array
3810 # print OUT "static Smoke::Index ${libname}_argumentList[] = {\n";
3811 my $argListCount = 0;
3812 for my $args (sort keys %arglist) {
3813 my @dunnohowtoavoidthat = split(',',$args);
3814 my $numTypes = $#dunnohowtoavoidthat;
3815 if ($args eq '') {
3816 # print OUT "\t0,\t//0 (void)\n";
3817 } else {
3818 # This is a nice trick : args can be written in one go ;)
3819 # print OUT "\t$args, 0,\t//$argListCount $arglist{$args} \n";
3821 $arglist{$args} = $argListCount; # Register proper index in argList
3822 $argListCount += $numTypes + 2; # Move forward by as much as we wrote out
3824 # print OUT "};\n\n";
3826 $methods{''} = 0;
3827 my @methodlist = sort keys %methods;
3828 my %methodidx = do { my $i = 0; map { $_ => $i++ } @methodlist };
3830 # print OUT "// Raw list of all methods, using munged names\n";
3831 # print OUT "static const char *${libname}_methodNames[] = {\n";
3832 my $methodNameCount = $#methodlist;
3833 for my $m (@methodlist) {
3834 # print OUT qq( "$m",\t//$methodidx{$m}\n);
3836 # print OUT "};\n\n";
3838 # print OUT "// (classId, name (index in methodNames), argumentList index, number of args, method flags, return type (index in types), xcall() index)\n";
3839 # print OUT "static Smoke::Method ${libname}_methods[] = {\n";
3840 my @methods;
3841 %allMethods = ();
3842 my $methodCount = 0;
3843 # Look at all classes and all enums again
3844 Iter::LocalCompounds( $rootnode, sub {
3845 my $classNode = shift;
3846 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3847 return if $classNode->{NodeType} eq 'namespace';
3849 my $classIndex = $classidx{$className};
3850 print STDERR "writeSmokeDataFile: methods: looking at $className\n" if ($debug);
3852 Iter::MembersByType ( $classNode, undef,
3853 sub { my ($classNode, $m ) = @_;
3855 if( $m->{NodeType} eq "enum" ) {
3857 foreach my $enum ( @{$m->{ParamList}} ) {
3858 my $enumName = $enum->{ArgName};
3859 my $fullEnumName = "$className\::$enumName";
3860 my $sig = "$className\::$enumName\()";
3861 my $xmethIndex = $methodidx{$enumName};
3862 die "'Method index' for enum $sig not found" unless defined $xmethIndex;
3863 my $typeId = findTypeEntry( $fullEnumName )->{index};
3864 die "enum has no {case} value in $className: $fullEnumName" unless defined $classNode->{case}{$fullEnumName};
3865 # print OUT "\t{$classIndex, $xmethIndex, 0, 0, Smoke::mf_static, $typeId, $classNode->{case}{$fullEnumName}},\t//$methodCount $fullEnumName (enum)\n";
3866 $allMethods{$sig} = $methodCount;
3867 print STDERR "Added entry for " . $sig . " into \$allMethods\n" if ($debug);
3868 $methods[$methodCount] = {
3869 c => $classIndex,
3870 methIndex => $xmethIndex,
3871 argcnt => '0',
3872 args => 0,
3873 retTypeIndex => 0,
3874 idx => $classNode->{case}{$fullEnumName}
3876 $methodCount++;
3879 } elsif( $m->{NodeType} eq 'var' ) {
3881 my $name = $m->{astNodeName};
3882 my $fullName = "$className\::$name";
3883 my $sig = "$fullName\()";
3884 my $xmethIndex = $methodidx{$name};
3885 die "'Method index' for var $sig not found" unless defined $xmethIndex;
3886 my $varType = $m->{Type};
3887 $varType =~ s/static\s//;
3888 $varType =~ s/const\s+(.*)\s*&/$1/;
3889 $varType =~ s/\s*$//;
3890 my $typeId = findTypeEntry( $varType )->{index};
3891 die "var has no {case} value in $className: $fullName" unless defined $classNode->{case}{$fullName};
3892 # print OUT "\t{$classIndex, $xmethIndex, 0, 0, Smoke::mf_static, $typeId, $classNode->{case}{$fullName}},\t//$methodCount $fullName (static var)\n";
3893 $allMethods{$sig} = $methodCount;
3894 print STDERR "Added entry for " . $sig . " into \$allMethods\n" if ($debug);
3895 $methods[$methodCount] = {
3896 c => $classIndex,
3897 methIndex => $xmethIndex,
3898 argcnt => '0',
3899 args => 0,
3900 retTypeIndex => 0,
3901 idx => $classNode->{case}{$fullName}
3903 $methodCount++;
3906 } elsif( $m->{NodeType} eq "method" ) {
3908 # We generate a method entry only if the method is in the switch() code
3909 # BUT: for pure virtuals, they need to have a method entry, even though they
3910 # do NOT have a switch code.
3911 return if ( $m->{SkipFromSwitch} && $m->{Flags} !~ "p" );
3913 # No switch code for destructors if we didn't derive from the class (e.g. it has private ctors only)
3914 return if ( $m->{ReturnType} eq '~' && ! ( $classNode->{BindingDerives} and $classNode->{HasPublicDestructor}) );
3916 # Is this sorting really important?
3917 #for my $m (sort {$a->{name} cmp $b->{name}} @{ $self->{$c}{method} }) {
3919 my $methName = $m->{astNodeName};
3920 my $def = $m->{FirstDefaultParam};
3921 $def = scalar(@{ $m->{ParamList} }) unless defined $def;
3922 my $last = scalar(@{ $m->{ParamList} }) - 1;
3923 #print STDERR "writeSmokeDataFile: methods: generating for method $methName, def=$def last=$last\n" if ($debug);
3925 while($last >= ($def-1)) {
3926 last if $last < -1;
3927 my $args = [ @{ $m->{ParamList} }[0..$last] ];
3928 my $sig = methodSignature($m, $last);
3929 #my $methodSig = $classNode->{signature}{$sig}; # Munged signature
3930 #print STDERR "writeSmokeDataFile: methods: sig=$className\::$sig methodSig=$methodSig\n" if ($debug);
3931 #my $methodIndex = $methodidx{$methodSig};
3932 #die "$methodSig" if !defined $methodIndex;
3934 my $methodIndex = $methodidx{$methName};
3935 die "$methName" if !defined $methodIndex;
3936 my $case = $classNode->{case}{$sig};
3937 my $typeEntry = findTypeEntry( $m->{ReturnType} );
3938 my $retTypeIndex = defined $typeEntry ? $typeEntry->{index} : 0;
3940 my $i = 0;
3941 my $t = '';
3942 for my $arg (@$args) {
3943 $t .= ', ' if $i++;
3944 my $typeEntry = findTypeEntry( $arg->{ArgType} );
3945 $t .= defined $typeEntry ? $typeEntry->{index} : 0;
3947 my $arglist = $t eq '' ? 0 : $arglist{$t};
3948 die "arglist for $t not found" unless defined $arglist;
3949 if ( $m->{Flags} =~ "p" ) {
3950 # Pure virtuals don't have a {case} number, that's normal
3951 die if defined $case;
3952 $case = -1; # This remains -1, not 0 !
3953 } else {
3955 # die "$className\::$methName has no case number for sig=$sig" unless defined $case;
3957 my $argcnt = $last + 1;
3958 my $methodFlags = '0';
3959 $methodFlags .= "|Smoke::mf_static" if $m->{Flags} =~ "s";
3960 $methodFlags .= "|Smoke::mf_const" if $m->{Flags} =~ "c"; # useful?? probably not
3961 $methodFlags =~ s/0\|//; # beautify
3963 # print OUT "\t{$classIndex, $methodIndex, $arglist, $argcnt, $methodFlags, $retTypeIndex, $case},\t//$methodCount $className\::$sig";
3964 # print OUT " [pure virtual]" if ( $m->{Flags} =~ "p" ); # explain why $case = -1 ;)
3965 # print OUT "\n";
3967 $allMethods{$className . "::" . $sig} = $methodCount;
3968 $methods[$methodCount] = {
3969 c => $classIndex,
3970 methIndex => $methodIndex,
3971 argcnt => $argcnt,
3972 args => $arglist,
3973 retTypeIndex => $retTypeIndex,
3974 idx => $case
3976 $methodCount++;
3977 $last--;
3978 } # while
3979 } # if method
3980 } ); # Method Iter
3981 } ); # Class Iter
3982 # print OUT "};\n\n";
3984 my @protos;
3985 Iter::LocalCompounds( $rootnode, sub {
3986 my $classNode = shift;
3987 my $className = join( "::", kdocAstUtil::heritage($classNode) );
3989 return if $classNode->{NodeType} eq 'namespace';
3991 my $classIndex = $classidx{$className};
3992 print STDERR "writeSmokeDataFile: protos: looking at $className\n" if ($debug);
3994 Iter::MembersByType ( $classNode, undef,
3995 sub { my ($classNode, $m ) = @_;
3997 if( $m->{NodeType} eq "enum" ) {
3998 foreach my $enum ( @{$m->{ParamList}} ) {
3999 my $enumName = $enum->{ArgName};
4000 my $sig = "$className\::$enumName\()";
4001 my $xmeth = $allMethods{$sig};
4002 die "'Method' for enum $sig not found" unless defined $xmeth;
4003 my $xmethIndex = $methodidx{$enumName};
4004 die "'Method index' for enum $enumName not found" unless defined $xmethIndex;
4005 push @protos, {
4006 methIndex => $xmethIndex,
4007 c => $classIndex,
4008 over => {
4009 $sig => {
4010 sig => $sig,
4013 meth => $xmeth
4017 } elsif( $m->{NodeType} eq 'var' ) {
4019 my $name = $m->{astNodeName};
4020 my $fullName = "$className\::$name";
4021 my $sig = "$fullName\()";
4022 my $xmeth = $allMethods{$sig};
4023 die "'Method' for var $sig not found" unless defined $xmeth;
4024 my $xmethIndex = $methodidx{$name};
4025 die "'Method index' for var $name not found" unless defined $xmethIndex;
4026 push @protos, {
4027 methIndex => $xmethIndex,
4028 c => $classIndex,
4029 over => {
4030 $sig => {
4031 sig => $sig,
4034 meth => $xmeth
4040 for my $p (keys %{ $classNode->{proto} }) {
4041 # For each prototype
4042 my $scratch = { %{ $classNode->{proto}{$p} } }; # sig->method association
4043 # first, grab all the superclass voodoo
4044 for my $supNode (superclass_list($classNode)) {
4045 my $i = $supNode->{proto}{$p};
4046 next unless $i;
4047 for my $k (keys %$i) {
4048 $scratch->{$k} = $i->{$k} unless exists $scratch->{$k};
4052 # Ok, now we have a full list
4053 #if(scalar keys %$scratch > 1) {
4054 #print STDERR "Overload: $p (@{[keys %$scratch]})\n" if ($debug);
4056 my $xmethIndex = $methodidx{$p};
4057 my $classIndex = $classidx{$className};
4058 for my $sig (keys %$scratch) {
4059 #my $xsig = $scratch->{$sig}{class} . "::" . $sig;
4060 my $xsig = $className . "::" . $sig;
4061 $scratch->{$sig}{sig} = $xsig;
4062 delete $scratch->{$sig}
4063 if $scratch->{$sig}{Flags} =~ "p" # pure virtual
4064 or not exists $allMethods{$xsig};
4066 push @protos, {
4067 methIndex => $xmethIndex,
4068 c => $classIndex,
4069 over => $scratch
4070 } if scalar keys %$scratch;
4074 my @protolist = sort { $a->{c} <=> $b->{c} || $a->{methIndex} <=> $b->{methIndex} } @protos;
4075 #for my $abc (@protos) {
4076 #print "$abc->{methIndex}.$abc->{c}\n";
4079 print STDERR "Writing methodmap table\n" if ($debug);
4080 my @resolve = ();
4081 # print OUT "// Class ID, munged name ID (index into methodNames), method def (see methods) if >0 or number of overloads if <0\n";
4082 my $methodMapCount = 1;
4083 # print OUT "static Smoke::MethodMap ${libname}_methodMaps[] = {\n";
4084 # print OUT "\t{ 0, 0, 0 },\t//0 (no method)\n";
4085 for my $cur (@protolist) {
4086 if(scalar keys %{ $cur->{over} } > 1) {
4087 # print OUT "\t{$cur->{c}, $cur->{methIndex}, -@{[1+scalar @resolve]}},\t//$methodMapCount $classlist[$cur->{c}]\::$methodlist[$cur->{methIndex}]\n";
4088 $methodMapCount++;
4089 for my $k (keys %{ $cur->{over} }) {
4090 my $p = $cur->{over}{$k};
4091 my $xsig = $p->{class} ? "$p->{class}\::$k" : $p->{sig};
4092 push @resolve, { k => $k, p => $p, cur => $cur, id => $allMethods{$xsig} };
4094 push @resolve, 0;
4095 } else {
4096 for my $k (keys %{ $cur->{over} }) {
4097 my $p = $cur->{over}{$k};
4098 my $xsig = $p->{class} ? "$p->{class}\::$k" : $p->{sig};
4099 # print OUT "\t{$cur->{c}, $cur->{methIndex}, $allMethods{$xsig}},\t//$methodMapCount $classlist[$cur->{c}]\::$methodlist[$cur->{methIndex}]\n";
4100 $methodMapCount++;
4104 # print OUT "};\n\n";
4107 print STDERR "Writing ambiguousMethodList\n" if ($debug);
4108 # print OUT "static Smoke::Index ${libname}_ambiguousMethodList[] = {\n";
4109 # print OUT " 0,\n";
4110 for my $r (@resolve) {
4111 unless($r) {
4112 # print OUT " 0,\n";
4113 next;
4115 my $xsig = $r->{p}{class} ? "$r->{p}{class}\::$r->{k}" : $r->{p}{sig};
4116 die "ambiguousMethodList: no method found for $xsig\n" if !defined $allMethods{$xsig};
4117 # print OUT " $allMethods{$xsig}, // $xsig\n";
4119 # print OUT "};\n\n";
4121 # print OUT "extern \"C\" { // needed?\n";
4122 # print OUT " void init_${libname}_Smoke();\n";
4123 # print OUT "}\n";
4124 # print OUT "\n";
4125 # print OUT "Smoke* qt_Smoke = 0L;\n";
4126 # print OUT "\n";
4127 # print OUT "// Create the Smoke instance encapsulating all the above.\n";
4128 # print OUT "void init_${libname}_Smoke() {\n";
4129 # print OUT " qt_Smoke = new Smoke(\n";
4130 # print OUT " ${libname}_classes, ".$#classlist.",\n";
4131 # print OUT " ${libname}_methods, $methodCount,\n";
4132 # print OUT " ${libname}_methodMaps, $methodMapCount,\n";
4133 # print OUT " ${libname}_methodNames, $methodNameCount,\n";
4134 # print OUT " ${libname}_types, $typeCount,\n";
4135 # print OUT " ${libname}_inheritanceList,\n";
4136 # print OUT " ${libname}_argumentList,\n";
4137 # print OUT " ${libname}_ambiguousMethodList,\n";
4138 # print OUT " ${libname}_cast );\n";
4139 # print OUT "}\n";
4140 # close OUT;
4142 #print "@{[keys %allMethods ]}\n";
4145 sub indentText($$)
4147 my ( $indent, $text ) = @_;
4149 if ( $indent eq "" || $text eq "" ) {
4150 return $text;
4153 $text =~ s/\n(.)/\n$indent$1/g;
4154 return $indent . $text;
4157 =head2 printCSharpdocComment
4159 Parameters: docnode filehandle
4161 Converts a kdoc comment to csharpdoc format.
4162 @ref's are converted to <see>'s; @p's and @em's are converted
4163 to inline HTML.
4165 =cut
4167 sub printCSharpdocComment($$$$)
4169 my( $docnode, $name, $indent, $signalLink ) = @_;
4171 my $node;
4172 my $returntext = '<remarks>';
4173 foreach $node ( @{$docnode->{Text}} ) {
4174 next if $node->{NodeType} ne "DocText" and $node->{NodeType} ne "ListItem"
4175 and $node->{NodeType} ne "Param";
4176 my $line = '';
4178 if ($node->{NodeType} eq "Param") {
4179 if ($node->{Name} !~ /argc/) {
4180 $line = "<param> name=\"" . $node->{Name} . "\" " . $node->{astNodeName} . "</param>";
4182 } else {
4183 $line = $node->{astNodeName};
4185 $line =~ s/argc, ?argv/args/g;
4186 $line =~ s/int argc, ?char ?\* ?argv(\[\])?/string[] args/g;
4187 $line =~ s/int argc, ?char ?\*\* ?argv/string[] args/g;
4188 # if ($node->{NodeType} eq "Param") {
4189 # $line =~ s/(const )?QC?StringList(\s*&)?/string[]/g;
4190 # } else {
4191 $line =~ s/(const )?QC?StringList(\s*&)?/List<string>/g;
4193 $line =~ s/NodeList/ArrayList/g;
4194 $line =~ s/KTrader::OfferList/ArrayList/g;
4195 $line =~ s/QString::null/null/g;
4196 $line =~ s/(const )?QC?String(\s*&)?/string/g;
4197 $line =~ s/KCmdLineLastOption//g;
4198 $line =~ s/virtual //g;
4199 $line =~ s/~\w+\(\)((\s*{\s*})|;)//g;
4200 $line =~ s/0L/null/g;
4201 $line =~ s/(\([^\)]*\))\s*:\s*\w+\([^\)]*\)/$1/g;
4202 $line =~ s/\(void\)//g;
4203 $line =~ s/const char/string/g;
4204 $line =~ s/const (\w+)\&/$1/g;
4205 $line =~ s/bool/bool/g;
4206 $line =~ s/SLOT\(\s*([^\)]*)\) ?\)/SLOT("$1)")/g;
4207 $line =~ s/SIGNAL\(\s*([^\)]*)\) ?\)/SIGNAL("$1)")/g;
4208 $line =~ s/Q_OBJECT\n//g;
4209 $line =~ s/public\s*(slots)?:\n/public /g;
4210 $line =~ s/([^0-9"]\s*)\*(\s*[^0-9"-])/$1$2/g;
4211 $line =~ s/^(\s*)\*/$1/g;
4212 $line =~ s/\n \*/\n /g;
4213 $line =~ s!\@ref\s+([\w]+)::([\w]+)\s*(\([^\)]*\))(\.)?!<see cref=\"$1#$2\"></see>$4!g;
4214 $line =~ s!\@ref\s+#([\w:]+)(\(\))?!<see cref=\"#$1\"</see>!g;
4215 $line =~ s!\@ref\s+([\w]+)\s*(\([^\)]*\))!<see cref=\"#$1\"></see>!g;
4216 $line =~ s!\@ref\s+([\w]+)::([\w]+)!<see cref=\"$1#$2\"></see>!g;
4217 $line =~ s!\@ref\s+([a-z][\w]+)!<see cref=\"#$1\"></see>!g;
4218 $line =~ s!\@ref\s+([\w]+)!<see cref=\"$1\"></see>!g;
4219 while ($line =~ /\@c\s+([\w#\\\.<>]+)/ ) {
4220 my $code = $1;
4221 $code =~ s!<!&lt;!g;
4222 $code =~ s!>!&gt;!g;
4223 $code =~ s!\\#!#!g;
4224 $line =~ s!\@c\s+([\w#\\\.<>]+)!<code>$code</code>!;
4226 $line =~ s!\@em\s+(\w+)!<b>$1</b>!g;
4227 $line =~ s!\@p\s+([\w\._]*)!<code>$1</code>!g;
4228 $line =~ s!\\paragraph\s+[\w]+\s([\w]+)!<li><b>$1</b></li>!g;
4229 $line =~ s!\\b\s+([\w -]+)\\n!<li><b>$1</b></li>!g;
4230 $line =~ s!\\c\s+([\w\@&\\?;-]+)!<code>$1</code>!g;
4231 $line =~ s!\\p\s+([\w\@]+)!<pre>$1</pre>!g;
4232 $line =~ s!\\li\s+([\w\@]+)!<li>$1</li>!g;
4233 $line =~ s!<b>([\w\t \(\)-]*:?)</b>\\n!<li><b>$1</b></li>!g;
4234 $line =~ s!static_cast<\s*([\w\.]*)\s*>!($1)!g;
4235 # if ($name ne "") {
4236 # $line =~ s/\@link #/\@link $name\#/g;
4239 if ($node->{NodeType} eq "ListItem") {
4240 $line =~ s/^/\n<li>\n/;
4241 $line =~ s!$!\n</li>!;
4242 # $line =~ s/\n/\n$indent\t/g;
4243 } else {
4244 # $line =~ s/^/$indent/;
4245 # $line =~ s/\n/\n$indent/g;
4248 # $line =~ s/\n/\n$indent/g;
4249 $returntext .= $line;
4252 $returntext .= "$signalLink</remarks>";
4254 if ( defined $docnode->{Returns} ) {
4255 my $text = $docnode->{Returns};
4256 $text =~ s/QString::null/null/g;
4257 $returntext .= "\t\t<return> $text</return>\n";
4260 if ( defined $docnode->{Author} ) {
4261 $returntext .= "\t\t<author> " . $docnode->{Author} . "</author>\n"
4264 if ( defined $docnode->{Version} ) {
4265 my $versionStr = $docnode->{Version};
4266 $versionStr =~ s/\$\s*Id:([^\$]*) Exp \$/$1/;
4267 $returntext .= "\t\t<version> $versionStr</version>\n";
4270 if ( defined $docnode->{ClassShort} ) {
4271 my $shortText = $docnode->{ClassShort};
4272 $shortText =~ s![\*\n]! !g;
4273 $returntext .= "\t\t<short> $shortText</short>\n";
4276 if ( defined $docnode->{See} ) {
4277 foreach my $text ( @{$docnode->{See}} ) {
4278 next if ($text =~ /QString|^\s*and\s*$|^\s*$|^[^\w]*$/);
4279 $text =~ s/KIO:://g;
4280 $text =~ s/KParts:://g;
4281 while ($text =~ /((::)|(->))(.)/) {
4282 my $temp = uc($4);
4283 $text =~ s/$1$4/.$temp/;
4285 $text =~ s/\(\)//g;
4286 $text =~ s/^\s*([a-z].*)/$1/g;
4287 $returntext .= "\t\t<see> $text</see>\n";
4291 $returntext =~ s!\\link!<see>!g;
4292 $returntext =~ s!\\endlink!</see>!g;
4293 $returntext =~ s/DOM#([A-Z])/$1/g;
4294 $returntext =~ s/KIO#([A-Z])/$1/g;
4295 $returntext =~ s/KParts#([A-Z])/$1/g;
4296 $returntext =~ s/const\s+(\w+)\s*\&/$1/g;
4297 # $returntext =~ s/QChar/char/g;
4298 $returntext =~ s/QStringList/List<string>/g;
4299 $returntext =~ s/([Aa]) ArrayList/$1n ArrayList/g;
4300 $returntext =~ s/QString/string/g;
4301 $returntext =~ s!\\note!<b>Note:<\b>!g;
4302 $returntext =~ s!\\(code|verbatim)!<pre>!g;
4303 $returntext =~ s!\\(endcode|endverbatim)!</pre>!g;
4304 $returntext =~ s!\\addtogroup\s+[\w]+\s+"([^"\@]+)"\s+\@{!<li><b>$1</b></li>!g;
4305 $returntext =~ s![\\\@]relates\s+([a-z][\w]*)!<see cref=\"$1\"></see>!g;
4306 $returntext =~ s![\\\@]relates\s+(\w+)::(\w+)!<see cref=\"$1.$2\"></see>!g;
4307 $returntext =~ s![\\\@]relates\s+(#?\w+)!<see cref=\"$1\"></see>!g;
4308 $returntext =~ s!\\c\s+([\w\@&\\?";-]+)!<code>$1</code>!g;
4309 $returntext =~ s!\@p\s+([\w\._]*)!<code>$1</code>!g;
4310 $returntext =~ s!\@a\s+([:\w]+)!<b>$1</b>!g;
4311 $returntext =~ s![\@\\]b\s+[:\w]!<b>$1</b>!g;
4312 $returntext =~ s/};/}/g;
4314 while ($returntext =~ /((::)|(->))(.)/) {
4315 my $temp = uc($4);
4316 $returntext =~ s/$1$4/.$temp/;
4319 $returntext =~ s/\s*$//;
4320 if ($returntext =~ /^<remarks>\s*<\/remarks>$/) {
4321 return "";
4322 } else {
4323 $returntext =~ s/\n/\n$indent/g;
4324 $returntext =~ s/^/$indent/;
4325 return $returntext . "\n";