~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to kdevdesigner/shared/ui2uib.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2006-05-23 18:39:42 UTC
  • Revision ID: james.westby@ubuntu.com-20060523183942-hucifbvh68k2bwz7
Tags: upstream-3.3.2
Import upstream version 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************
 
2
** Copyright (C) 2000-2002 Trolltech AS.  All rights reserved.
 
3
**
 
4
** This file is part of Qt Designer.
 
5
**
 
6
** This file may be distributed and/or modified under the terms of the
 
7
** GNU General Public License version 2 as published by the Free Software
 
8
** Foundation and appearing in the file LICENSE.GPL included in the
 
9
** packaging of this file.
 
10
**
 
11
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
 
12
** licenses may use this file in accordance with the Qt Commercial License
 
13
** Agreement provided with the Software.
 
14
**
 
15
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
16
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
17
**
 
18
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
19
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
20
**   information about Qt Commercial License Agreements.
 
21
**
 
22
** Contact info@trolltech.com if any conditions of this licensing are
 
23
** not clear to you.
 
24
**
 
25
**********************************************************************/
 
26
 
 
27
#include "ui2uib.h"
 
28
#include "uib.h"
 
29
 
 
30
#include <domtool.h>
 
31
 
 
32
#include <qcolor.h>
 
33
#include <qcursor.h>
 
34
#include <qdatetime.h>
 
35
#include <qdom.h>
 
36
#include <qfile.h>
 
37
#include <qfont.h>
 
38
#include <qobject.h>
 
39
#include <qrect.h>
 
40
#include <qsizepolicy.h>
 
41
 
 
42
/*
 
43
    The .uib file format is the binary counterpart of the .ui file
 
44
    format. It is generated by the ui2uib converter and understood by
 
45
    QWidgetFactory; in a future version, it might also be understood
 
46
    by a uib2ui converter. Experiments show that .uib files are about
 
47
    2.5 times faster to load and 6 times smaller than .ui files.
 
48
 
 
49
    The .uib format, unlike the .ui format, is internal to Trolltech
 
50
    and is not officially documented; it is assumed that anybody who
 
51
    needs to understand the file format can read the ui2uib and
 
52
    QWidgetFactory source code, with some guidance. And here's some
 
53
    guidance.
 
54
 
 
55
    A .uib file starts with a 32-bit magic number that allows
 
56
    QWidgetFactory to determine the file type. The magic number is
 
57
    followed by '\n' (0x0a) and '\r' (0x0d), which ensure that the
 
58
    file wasn't corrupted during transfer between different
 
59
    platforms. For example, transferring a .ui file from Windows to
 
60
    Unix using FTP with type ASCII will produce a file with '\r\n\r'
 
61
    in place of '\n\r'. This is followed by the QDataStream format
 
62
    version number used.
 
63
 
 
64
    The rest of the file is made up of blocks, each of which starts
 
65
    with a block type (Block_XXX) and a block length. Block_Intro and
 
66
    Block_Widget are mandatory; the others are optional.
 
67
    QWidgetFactory makes certain assumptions about the order of the
 
68
    blocks; for example, it expects Block_String before any other
 
69
    block that refers to a string and Block_Images before
 
70
    Block_Widget. The order generated by ui2uib is one of the orders
 
71
    that make sense. Just after the last block, a Block_End marker
 
72
    indicates the end of the file.
 
73
 
 
74
    The division of .uib files into blocks corresponds grossly to the
 
75
    division of .ui files in top-level XML elements. Thus,
 
76
    Block_Widget corresponds to <widget> and Block_Toolbars to
 
77
    <toolbars>. The internal organization of each block also mimics
 
78
    the organization of the corresponding XML elements.
 
79
 
 
80
    These are the major differences, all of which contribute to
 
81
    making .uib files more compact:
 
82
 
 
83
    1.  The strings are gathered in Block_Strings, a string-table.
 
84
        When a string is needed later, it is referenced by a 32-bit
 
85
        index into that table. The UicStringTable class makes the
 
86
        whole process of inserting and looking up strings very
 
87
        simple. The advantage of this scheme is that if a string is
 
88
        used more than once, it is stored only once. Also, the
 
89
        string-table is preinitialized with very common strings, so
 
90
        that these need not be stored along with .uib files.
 
91
 
 
92
    2.  QObjects are referred to by index in a table rather than by
 
93
        name. The table itself is not stored in the .uib file; it is
 
94
        rather build dynamically by ui2uib and QWidgetFactory as new
 
95
        objects are specified. In ui2uib, the table is represented by
 
96
        a UibIndexMap object; in QWidgetFactory, a plain array of
 
97
        QObject pointers suffices.
 
98
 
 
99
    3.  The data is packed to take as little place as possible,
 
100
        without slowing down QLayoutFactory too much. For example, an
 
101
        index into the string-table is a 32-bit integer, but in
 
102
        practice it is rarely above 65534, so only 16 bits are used
 
103
        for them; when an index above 65534 is met, the index is
 
104
        saved as 65535 followed by the 32-bit index, for a total of
 
105
        48 bits.
 
106
 
 
107
    4.  The name of a signal or slot and its signature are saved
 
108
        separately. That way, if a signal 'foo(const QString&)' is
 
109
        connected to a slot 'bar(const QString&)', the string-table
 
110
        will only contain 'foo', 'bar', and '(const QString&)',
 
111
        instead of the longer 'foo(const QString&)' and 'bar(const
 
112
        QString&)'. The signatures are normalized beforehand to
 
113
        ensure that trivial spacing problems don't result in multiple
 
114
        string-table entries.
 
115
 
 
116
    5.  In a signal-to-slot connection, a sender, signal, receiver,
 
117
        or slot is not repeated if it's the same as for the previous
 
118
        connection. Bit flags indicate what is repeated and what is
 
119
        specified.
 
120
 
 
121
    6.  Some of the information stored in a .ui file is useful only
 
122
        by uic, not to QLayoutFactory. That information is, for now,
 
123
        not taken along in the .uib file. Likewise, needless
 
124
        QLayoutWidget objects are not taken along.
 
125
 
 
126
    The arbitrary constants related to the .uib file formats are
 
127
    defined in uib.h. Constants such as Block_Actions and
 
128
    Object_SubWidget are given values such as 'A' and 'W' to make
 
129
    .uib files easier to read in a hexadecimal editor.
 
130
 
 
131
    The file format isn't designed to be extensible. Any extension
 
132
    that prevents an older version of QLayoutWidget of reading the
 
133
    file correctly must have a different magic number. The plan is to
 
134
    use UibMagic + 1 for version 2, UibMagic + 2 for version 3, etc.
 
135
*/
 
136
 
 
137
static QCString layoutForTag( const QString& tag )
 
138
{
 
139
    if ( tag == "grid" ) {
 
140
        return "QGridLayout";
 
141
    } else if ( tag == "hbox" ) {
 
142
        return "QHBoxLayout";
 
143
    } else if ( tag == "vbox" ) {
 
144
        return "QVBoxLayout";
 
145
    } else {
 
146
        return "QLayout";
 
147
    }
 
148
}
 
149
 
 
150
class UibHack : public QObject
 
151
{
 
152
public:
 
153
    static QString normalize( const QString& member ) {
 
154
        return QString::fromUtf8( QObject::normalizeSignalSlot(member.utf8()) );
 
155
    }
 
156
};
 
157
 
 
158
class UibIndexMap
 
159
{
 
160
public:
 
161
    UibIndexMap() : next( 0 ) { }
 
162
 
 
163
    void insert( const QString& name ) { setName( insert(), name ); }
 
164
    int insert() { return next++; }
 
165
    void setName( int no, const QString& name );
 
166
 
 
167
    int find( const QString& name, int deflt = -1 ) const;
 
168
    int count() const { return next; }
 
169
 
 
170
private:
 
171
    QMap<QString, int> nameMap;
 
172
    QMap<QString, int> conflicts;
 
173
    int next;
 
174
};
 
175
 
 
176
void UibIndexMap::setName( int no, const QString& name )
 
177
{
 
178
    if ( !name.isEmpty() ) {
 
179
        if ( *nameMap.insert(name, no, FALSE) != no )
 
180
            conflicts.insert( name, 0 );
 
181
    }
 
182
}
 
183
 
 
184
int UibIndexMap::find( const QString& name, int deflt ) const
 
185
{
 
186
    QMap<QString, int>::ConstIterator no = nameMap.find( name );
 
187
    if ( no == nameMap.end() || conflicts.contains(name) ) {
 
188
        return deflt;
 
189
    } else {
 
190
        return *no;
 
191
    }
 
192
}
 
193
 
 
194
static void packUInt16( QDataStream& out, Q_UINT16 n )
 
195
{
 
196
    if ( n < 255 ) {
 
197
        out << (Q_UINT8) n;
 
198
    } else {
 
199
        out << (Q_UINT8) 255;
 
200
        out << n;
 
201
    }
 
202
}
 
203
 
 
204
static void packUInt32( QDataStream& out, Q_UINT32 n )
 
205
{
 
206
    if ( n < 65535 ) {
 
207
        out << (Q_UINT16) n;
 
208
    } else {
 
209
        out << (Q_UINT16) 65535;
 
210
        out << n;
 
211
    }
 
212
}
 
213
 
 
214
static void packByteArray( QDataStream& out, const QByteArray& array )
 
215
{
 
216
    packUInt32( out, array.size() );
 
217
    out.writeRawBytes( array.data(), array.size() );
 
218
}
 
219
 
 
220
static void packCString( UibStrTable& strings, QDataStream& out,
 
221
                         const char *cstr )
 
222
{
 
223
    packUInt32( out, strings.insertCString(cstr) );
 
224
}
 
225
 
 
226
static void packString( UibStrTable& strings, QDataStream& out,
 
227
                        const QString& str )
 
228
{
 
229
    packUInt32( out, strings.insertString(str) );
 
230
}
 
231
 
 
232
static void packStringSplit( UibStrTable& strings, QDataStream& out,
 
233
                             const QString& str, QChar sep )
 
234
{
 
235
    int pos = str.find( sep );
 
236
    if ( pos == -1 )
 
237
        pos = str.length();
 
238
    packString( strings, out, str.left(pos) );
 
239
    packString( strings, out, str.mid(pos) );
 
240
}
 
241
 
 
242
static void packVariant( UibStrTable& strings, QDataStream& out,
 
243
                         QVariant value, QString tag = "" )
 
244
{
 
245
    QStringList::ConstIterator s;
 
246
 
 
247
    Q_UINT8 type = value.type();
 
248
    if ( tag == "pixmap" ) {
 
249
        type = QVariant::Pixmap;
 
250
    } else if ( tag == "image" ) {
 
251
        type = QVariant::Image;
 
252
    } else if ( tag == "iconset" ) {
 
253
        type = QVariant::IconSet;
 
254
    }
 
255
    out << type;
 
256
 
 
257
    switch ( type ) {
 
258
    case QVariant::String:
 
259
    case QVariant::Pixmap:
 
260
    case QVariant::Image:
 
261
    case QVariant::IconSet:
 
262
        packString( strings, out, value.asString() );
 
263
        break;
 
264
    case QVariant::StringList:
 
265
        packUInt16( out, value.asStringList().count() );
 
266
        s = value.asStringList().begin();
 
267
        while ( s != value.asStringList().end() ) {
 
268
            packString( strings, out, *s );
 
269
            ++s;
 
270
        }
 
271
        break;
 
272
    case QVariant::Font:
 
273
        out << value.asFont();
 
274
        break;
 
275
    case QVariant::Rect:
 
276
        packUInt16( out, value.asRect().x() );
 
277
        packUInt16( out, value.asRect().y() );
 
278
        packUInt16( out, value.asRect().width() );
 
279
        packUInt16( out, value.asRect().height() );
 
280
        break;
 
281
    case QVariant::Size:
 
282
        packUInt16( out, value.asSize().width() );
 
283
        packUInt16( out, value.asSize().height() );
 
284
        break;
 
285
    case QVariant::Color:
 
286
        out << value.asColor();
 
287
        break;
 
288
    case QVariant::Point:
 
289
        packUInt16( out, value.asPoint().x() );
 
290
        packUInt16( out, value.asPoint().y() );
 
291
        break;
 
292
    case QVariant::Int:
 
293
        packUInt32( out, value.asInt() );
 
294
        break;
 
295
    case QVariant::Bool:
 
296
        out << (Q_UINT8) value.asBool();
 
297
        break;
 
298
    case QVariant::Double:
 
299
        out << value.asDouble();
 
300
        break;
 
301
    case QVariant::CString:
 
302
        packCString( strings, out, value.asCString() );
 
303
        break;
 
304
    case QVariant::Cursor:
 
305
        out << value.asCursor();
 
306
        break;
 
307
    case QVariant::Date:
 
308
        out << value.asDate();
 
309
        break;
 
310
    case QVariant::Time:
 
311
        out << value.asTime();
 
312
        break;
 
313
    case QVariant::DateTime:
 
314
        out << value.asDateTime();
 
315
        break;
 
316
    default:
 
317
        out << value;
 
318
    }
 
319
}
 
320
 
 
321
static void outputProperty( QMap<int, QStringList>& buddies, int objectNo,
 
322
                            UibStrTable& strings, QDataStream& out,
 
323
                            QDomElement elem )
 
324
{
 
325
    QCString name = elem.attribute( "name" ).latin1();
 
326
    QDomElement f = elem.firstChild().toElement();
 
327
    QString tag = f.tagName();
 
328
    QString comment;
 
329
    QVariant value;
 
330
 
 
331
    if ( name == "resizeable" )
 
332
        name = "resizable";
 
333
 
 
334
    if ( tag == "font" ) {
 
335
        QString family;
 
336
        Q_UINT16 pointSize = 65535;
 
337
        Q_UINT8 fontFlags = 0;
 
338
 
 
339
        QDomElement g = f.firstChild().toElement();
 
340
        while ( !g.isNull() ) {
 
341
            QString text = g.firstChild().toText().data();
 
342
            if ( g.tagName() == "family" ) {
 
343
                fontFlags |= Font_Family;
 
344
                family = text;
 
345
            } else if ( g.tagName() == "pointsize" ) {
 
346
                fontFlags |= Font_PointSize;
 
347
                pointSize = (Q_UINT16) text.toUInt();
 
348
            } else {
 
349
                if ( g.firstChild().toText().data().toInt() != 0 ) {
 
350
                    if ( g.tagName() == "bold" ) {
 
351
                        fontFlags |= Font_Bold;
 
352
                    } else if ( g.tagName() == "italic" ) {
 
353
                        fontFlags |= Font_Italic;
 
354
                    } else if ( g.tagName() == "underline" ) {
 
355
                        fontFlags |= Font_Underline;
 
356
                    } else if ( g.tagName() == "strikeout" ) {
 
357
                        fontFlags |= Font_StrikeOut;
 
358
                    }
 
359
                }
 
360
            }
 
361
            g = g.nextSibling().toElement();
 
362
        }
 
363
 
 
364
        out << (Q_UINT8) Object_FontProperty;
 
365
        packCString( strings, out, name );
 
366
        out << fontFlags;
 
367
        if ( fontFlags & Font_Family )
 
368
            packString( strings, out, family );
 
369
        if ( fontFlags & Font_PointSize )
 
370
            packUInt16( out, pointSize );
 
371
    } else if ( tag == "palette" ) {
 
372
        out << (Q_UINT8) Object_PaletteProperty;
 
373
        packCString( strings, out, name );
 
374
 
 
375
        QDomElement g = f.firstChild().toElement();
 
376
        while ( !g.isNull() ) {
 
377
            QDomElement h = g.firstChild().toElement();
 
378
            while ( !h.isNull() ) {
 
379
                value = DomTool::elementToVariant( h, Qt::gray );
 
380
                if ( h.tagName() == "color" ) {
 
381
                    out << (Q_UINT8) Palette_Color;
 
382
                    out << value.asColor();
 
383
                } else if ( h.tagName() == "pixmap" ) {
 
384
                    out << (Q_UINT8) Palette_Pixmap;
 
385
                    packVariant( strings, out, value, "pixmap" );
 
386
                }
 
387
                h = h.nextSibling().toElement();
 
388
            }
 
389
 
 
390
            if ( g.tagName() == "active" ) {
 
391
                out << (Q_UINT8) Palette_Active;
 
392
            } else if ( g.tagName() == "inactive" ) {
 
393
                out << (Q_UINT8) Palette_Inactive;
 
394
            } else {
 
395
                out << (Q_UINT8) Palette_Disabled;
 
396
            }
 
397
            g = g.nextSibling().toElement();
 
398
        }
 
399
        out << (Q_UINT8) Palette_End;
 
400
    } else {
 
401
        value = DomTool::elementToVariant( f, value, comment );
 
402
        if ( value.isValid() ) {
 
403
            if ( name == "buddy" ) {
 
404
                buddies[objectNo] += value.asString();
 
405
            } else {
 
406
                if ( tag == "string" ) {
 
407
                    out << (Q_UINT8) Object_TextProperty;
 
408
                    packCString( strings, out, name );
 
409
                    packCString( strings, out, value.asString().utf8() );
 
410
                    packCString( strings, out, comment.utf8() );
 
411
                } else {
 
412
                    out << (Q_UINT8) Object_VariantProperty;
 
413
                    packCString( strings, out, name );
 
414
                    packVariant( strings, out, value, tag );
 
415
                }
 
416
            }
 
417
        }
 
418
    }
 
419
}
 
420
 
 
421
static void outputGridCell( QDataStream& out, QDomElement elem )
 
422
{
 
423
    int column = elem.attribute( "column", "0" ).toInt();
 
424
    int row = elem.attribute( "row", "0" ).toInt();
 
425
    int colspan = elem.attribute( "colspan", "1" ).toInt();
 
426
    int rowspan = elem.attribute( "rowspan", "1" ).toInt();
 
427
    if ( colspan < 1 )
 
428
        colspan = 1;
 
429
    if ( rowspan < 1 )
 
430
        rowspan = 1;
 
431
 
 
432
    if ( column != 0 || row != 0 || colspan != 1 || rowspan != 1 ) {
 
433
        out << (Q_UINT8) Object_GridCell;
 
434
        packUInt16( out, column );
 
435
        packUInt16( out, row );
 
436
        packUInt16( out, colspan );
 
437
        packUInt16( out, rowspan );
 
438
    }
 
439
}
 
440
 
 
441
static int outputObject( QMap<int, QStringList>& buddies,
 
442
                         UibIndexMap& objects, UibStrTable& strings,
 
443
                         QDataStream& out, QDomElement elem,
 
444
                         QCString className = "" );
 
445
 
 
446
static void outputLayoutWidgetsSubLayout( QMap<int, QStringList>& buddies,
 
447
                                          UibIndexMap& objects,
 
448
                                          UibStrTable& strings,
 
449
                                          QDataStream& out, QDomElement elem )
 
450
{
 
451
    int subLayoutNo = -1;
 
452
    QCString name;
 
453
    QDomElement nameElem;
 
454
 
 
455
    QDomElement f = elem.firstChild().toElement();
 
456
    while ( !f.isNull() ) {
 
457
        QString tag = f.tagName();
 
458
        if ( tag == "grid" || tag == "hbox" || tag == "vbox" ) {
 
459
            out << (Q_UINT8) Object_SubLayout;
 
460
            subLayoutNo = outputObject( buddies, objects, strings, out, f,
 
461
                                        layoutForTag(tag) );
 
462
        } else if ( tag == "property" ) {
 
463
            if ( f.attribute("name") == "name" ) {
 
464
                name = DomTool::elementToVariant( f, name ).asCString();
 
465
                nameElem = f;
 
466
            }
 
467
        }
 
468
        f = f.nextSibling().toElement();
 
469
    }
 
470
 
 
471
    if ( subLayoutNo != -1 ) {
 
472
        /*
 
473
          Remove the sub-layout's Object_End marker, append the grid
 
474
          cell and the correct name property, and put the Object_End
 
475
          marker back.
 
476
        */
 
477
        out.device()->at( out.device()->at() - 1 );
 
478
        outputGridCell( out, elem );
 
479
        outputProperty( buddies, subLayoutNo, strings, out, nameElem );
 
480
        out << (Q_UINT8) Object_End;
 
481
 
 
482
        objects.setName( subLayoutNo, name );
 
483
    }
 
484
}
 
485
 
 
486
static int outputObject( QMap<int, QStringList>& buddies,
 
487
                         UibIndexMap& objects, UibStrTable& strings,
 
488
                         QDataStream& out, QDomElement elem,
 
489
                         QCString className )
 
490
{
 
491
    bool isQObject = !className.isEmpty();
 
492
 
 
493
    if ( className == "QToolBar" )
 
494
        out << (Q_UINT8) elem.attribute( "dock", "0" ).toInt();
 
495
    if ( className == "QWidget" )
 
496
        className = elem.attribute( "class", className ).latin1();
 
497
 
 
498
    int objectNo = -1;
 
499
    if ( isQObject ) {
 
500
        packCString( strings, out, className );
 
501
        objectNo = objects.insert();
 
502
    }
 
503
 
 
504
    outputGridCell( out, elem );
 
505
 
 
506
    // optimization: insert '&Foo' into string-table before 'Foo'
 
507
    if ( className == "QAction" || className == "QActionGroup" ) {
 
508
        QVariant value = DomTool::readProperty( elem, "menuText", QVariant() );
 
509
        if ( value.asString().startsWith("&") )
 
510
            strings.insertString( value.asString() );
 
511
    }
 
512
 
 
513
    QDomElement f = elem.firstChild().toElement();
 
514
    while ( !f.isNull() ) {
 
515
        QString tag = f.tagName();
 
516
        if ( tag == "action" ) {
 
517
            if ( elem.tagName() == "item" || elem.tagName() == "toolbar" ) {
 
518
                QString actionName = f.attribute( "name" );
 
519
                int no = objects.find( actionName );
 
520
                if ( no != -1 ) {
 
521
                    out << (Q_UINT8) Object_ActionRef;
 
522
                    packUInt16( out, no );
 
523
                }
 
524
            } else {
 
525
                out << (Q_UINT8) Object_SubAction;
 
526
                outputObject( buddies, objects, strings, out, f, "QAction" );
 
527
            }
 
528
        } else if ( tag == "actiongroup" ) {
 
529
            out << (Q_UINT8) Object_SubAction;
 
530
            outputObject( buddies, objects, strings, out, f, "QActionGroup" );
 
531
        } else if ( tag == "attribute" ) {
 
532
            out << (Q_UINT8) Object_Attribute;
 
533
            outputProperty( buddies, objectNo, strings, out, f );
 
534
        } else if ( tag == "column" ) {
 
535
            out << (Q_UINT8) Object_Column;
 
536
            outputObject( buddies, objects, strings, out, f );
 
537
        } else if ( tag == "event" ) {
 
538
            out << (Q_UINT8) Object_Event;
 
539
            packCString( strings, out, f.attribute("name").latin1() );
 
540
            packVariant( strings, out,
 
541
                         QStringList::split(',', f.attribute("functions")) );
 
542
        } else if ( tag == "grid" || tag == "hbox" || tag == "vbox" ) {
 
543
            out << (Q_UINT8) Object_SubLayout;
 
544
            outputObject( buddies, objects, strings, out, f,
 
545
                          layoutForTag(tag) );
 
546
        } else if ( tag == "item" ) {
 
547
            if ( elem.tagName() == "menubar" ) {
 
548
                out << (Q_UINT8) Object_MenuItem;
 
549
                packCString( strings, out, f.attribute("name").latin1() );
 
550
                packCString( strings, out, f.attribute("text").utf8() );
 
551
                outputObject( buddies, objects, strings, out, f );
 
552
            } else {
 
553
                out << (Q_UINT8) Object_Item;
 
554
                outputObject( buddies, objects, strings, out, f );
 
555
            }
 
556
        } else if ( tag == "property" ) {
 
557
            outputProperty( buddies, objectNo, strings, out, f );
 
558
        } else if ( tag == "row" ) {
 
559
            out << (Q_UINT8) Object_Row;
 
560
            outputObject( buddies, objects, strings, out, f );
 
561
        } else if ( tag == "separator" ) {
 
562
            out << (Q_UINT8) Object_Separator;
 
563
        } else if ( tag == "spacer" ) {
 
564
            out << (Q_UINT8) Object_Spacer;
 
565
            outputObject( buddies, objects, strings, out, f );
 
566
        } else if ( tag == "widget" ) {
 
567
            if ( f.attribute("class") == "QLayoutWidget" &&
 
568
                 elem.tagName() != "widget" ) {
 
569
                outputLayoutWidgetsSubLayout( buddies, objects, strings, out,
 
570
                                              f );
 
571
            } else {
 
572
                out << (Q_UINT8) Object_SubWidget;
 
573
                outputObject( buddies, objects, strings, out, f, "QWidget" );
 
574
            }
 
575
        }
 
576
        f = f.nextSibling().toElement();
 
577
    }
 
578
    out << (Q_UINT8) Object_End;
 
579
    if ( isQObject )
 
580
        objects.setName( objectNo,
 
581
                         DomTool::readProperty(elem, "name", "").asString() );
 
582
    return objectNo;
 
583
}
 
584
 
 
585
static void outputBlock( QDataStream& out, BlockTag tag,
 
586
                         const QByteArray& data )
 
587
{
 
588
    if ( !data.isEmpty() ) {
 
589
        out << (Q_UINT8) tag;
 
590
        packByteArray( out, data );
 
591
    }
 
592
}
 
593
 
 
594
void convertUiToUib( QDomDocument& doc, QDataStream& out )
 
595
{
 
596
    QByteArray introBlock;
 
597
    QByteArray actionsBlock;
 
598
    QByteArray buddiesBlock;
 
599
    QByteArray connectionsBlock;
 
600
    QByteArray functionsBlock;
 
601
    QByteArray imagesBlock;
 
602
    QByteArray menubarBlock;
 
603
    QByteArray slotsBlock;
 
604
    QByteArray tabstopsBlock;
 
605
    QByteArray toolbarsBlock;
 
606
    QByteArray variablesBlock;
 
607
    QByteArray widgetBlock;
 
608
 
 
609
    QDomElement actionsElem;
 
610
    QDomElement connectionsElem;
 
611
    QDomElement imagesElem;
 
612
    QDomElement menubarElem;
 
613
    QDomElement tabstopsElem;
 
614
    QDomElement toolbarsElem;
 
615
    QDomElement widgetElem;
 
616
 
 
617
    QMap<int, QStringList> buddies;
 
618
    UibStrTable strings;
 
619
    UibIndexMap objects;
 
620
    int widgetNo = -1;
 
621
    QCString className;
 
622
    Q_INT16 defaultMargin = -32768;
 
623
    Q_INT16 defaultSpacing = -32768;
 
624
    Q_UINT8 introFlags = 0;
 
625
 
 
626
    QDomElement elem = doc.firstChild().toElement().firstChild().toElement();
 
627
    while ( !elem.isNull() ) {
 
628
        QString tag = elem.tagName();
 
629
 
 
630
        switch ( tag[0].latin1() ) {
 
631
        case 'a':
 
632
            if ( tag == "actions" )
 
633
                actionsElem = elem;
 
634
            break;
 
635
        case 'c':
 
636
            if ( tag == "class" ) {
 
637
                className = elem.firstChild().toText().data().latin1();
 
638
            } else if ( tag == "connections" ) {
 
639
                connectionsElem = elem;
 
640
            }
 
641
            break;
 
642
        case 'f':
 
643
            if ( tag == "functions" ) {
 
644
                QDataStream out2( functionsBlock, IO_WriteOnly );
 
645
                QDomElement f = elem.firstChild().toElement();
 
646
                while ( !f.isNull() ) {
 
647
                    if ( f.tagName() == "function" ) {
 
648
                        packStringSplit( strings, out2,
 
649
                                         f.attribute("name").latin1(), '(' );
 
650
                        packString( strings, out2,
 
651
                                    f.firstChild().toText().data() );
 
652
                    }
 
653
                    f = f.nextSibling().toElement();
 
654
                }
 
655
            }
 
656
            break;
 
657
        case 'i':
 
658
            if ( tag == "images" ) {
 
659
                QDataStream out2( imagesBlock, IO_WriteOnly );
 
660
                QDomElement f = elem.firstChild().toElement();
 
661
                while ( !f.isNull() ) {
 
662
                    if ( f.tagName() == "image" ) {
 
663
                        QString name = f.attribute( "name" );
 
664
                        QDomElement g = f.firstChild().toElement();
 
665
                        if ( g.tagName() == "data" ) {
 
666
                            QString format = g.attribute( "format", "PNG" );
 
667
                            QString hex = g.firstChild().toText().data();
 
668
                            int n = hex.length() / 2;
 
669
                            QByteArray data( n );
 
670
                            for ( int i = 0; i < n; i++ )
 
671
                                data[i] = (char) hex.mid( 2 * i, 2 )
 
672
                                                    .toUInt( 0, 16 );
 
673
 
 
674
                            packString( strings, out2, name );
 
675
                            packString( strings, out2, format );
 
676
                            packUInt32( out2, g.attribute("length").toInt() );
 
677
                            packByteArray( out2, data );
 
678
                        }
 
679
                    }
 
680
                    f = f.nextSibling().toElement();
 
681
                }
 
682
            }
 
683
            break;
 
684
        case 'l':
 
685
            if ( tag == "layoutdefaults" ) {
 
686
                QString margin = elem.attribute( "margin" );
 
687
                if ( !margin.isEmpty() )
 
688
                    defaultMargin = margin.toInt();
 
689
                QString spacing = elem.attribute( "spacing" );
 
690
                if ( !spacing.isEmpty() )
 
691
                    defaultSpacing = spacing.toInt();
 
692
            }
 
693
            break;
 
694
        case 'm':
 
695
            if ( tag == "menubar" )
 
696
                menubarElem = elem;
 
697
            break;
 
698
        case 'p':
 
699
            if ( tag == "pixmapinproject" )
 
700
                introFlags |= Intro_Pixmapinproject;
 
701
            break;
 
702
        case 's':
 
703
            if ( tag == "slots" ) {
 
704
                QDataStream out2( slotsBlock, IO_WriteOnly );
 
705
                QDomElement f = elem.firstChild().toElement();
 
706
                while ( !f.isNull() ) {
 
707
                    if ( f.tagName() == "slot" ) {
 
708
                        QString language = f.attribute( "language", "C++" );
 
709
                        QString slot = UibHack::normalize(
 
710
                                f.firstChild().toText().data() );
 
711
                        packString( strings, out2, language );
 
712
                        packStringSplit( strings, out2, slot, '(' );
 
713
                    }
 
714
                    f = f.nextSibling().toElement();
 
715
                }
 
716
            }
 
717
            break;
 
718
        case 't':
 
719
            if ( tag == "tabstops" ) {
 
720
                tabstopsElem = elem;
 
721
            } else if ( tag == "toolbars" ) {
 
722
                toolbarsElem = elem;
 
723
            }
 
724
            break;
 
725
        case 'v':
 
726
            if ( tag == "variable" ) {
 
727
                QDataStream out2( variablesBlock, IO_WriteOnly | IO_Append );
 
728
                packString( strings, out2, elem.firstChild().toText().data() );
 
729
            } else if ( tag == "variables" ) {
 
730
                QDataStream out2( variablesBlock, IO_WriteOnly );
 
731
                QDomElement f = elem.firstChild().toElement();
 
732
                while ( !f.isNull() ) {
 
733
                    if ( f.tagName() == "variable" )
 
734
                        packString( strings, out2,
 
735
                                    f.firstChild().toText().data() );
 
736
                    f = f.nextSibling().toElement();
 
737
                }
 
738
            }
 
739
            break;
 
740
        case 'w':
 
741
            if ( tag == "widget" )
 
742
                widgetElem = elem;
 
743
        }
 
744
        elem = elem.nextSibling().toElement();
 
745
    }
 
746
 
 
747
    {
 
748
        QDataStream out2( widgetBlock, IO_WriteOnly );
 
749
        widgetNo = outputObject( buddies, objects, strings, out2, widgetElem,
 
750
                                 "QWidget" );
 
751
    }
 
752
 
 
753
    if ( !tabstopsElem.isNull() ) {
 
754
        QDataStream out2( tabstopsBlock, IO_WriteOnly );
 
755
        QDomElement f = tabstopsElem.firstChild().toElement();
 
756
        while ( !f.isNull() ) {
 
757
            if ( f.tagName() == "tabstop" ) {
 
758
                QString widgetName = f.firstChild().toText().data();
 
759
                int no = objects.find( widgetName );
 
760
                if ( no != -1 )
 
761
                    packUInt16( out2, no );
 
762
            }
 
763
            f = f.nextSibling().toElement();
 
764
        }
 
765
    }
 
766
 
 
767
    if ( !actionsElem.isNull() ) {
 
768
        QDataStream out2( actionsBlock, IO_WriteOnly );
 
769
        outputObject( buddies, objects, strings, out2, actionsElem );
 
770
    }
 
771
 
 
772
    if ( !menubarElem.isNull() ) {
 
773
        QDataStream out2( menubarBlock, IO_WriteOnly );
 
774
        outputObject( buddies, objects, strings, out2, menubarElem,
 
775
                      "QMenuBar" );
 
776
    }
 
777
 
 
778
    if ( !toolbarsElem.isNull() ) {
 
779
        QDataStream out2( toolbarsBlock, IO_WriteOnly );
 
780
        QDomElement f = toolbarsElem.firstChild().toElement();
 
781
        while ( !f.isNull() ) {
 
782
            if ( f.tagName() == "toolbar" )
 
783
                outputObject( buddies, objects, strings, out2, f, "QToolBar" );
 
784
            f = f.nextSibling().toElement();
 
785
        }
 
786
    }
 
787
 
 
788
    if ( !buddies.isEmpty() ) {
 
789
        QDataStream out2( buddiesBlock, IO_WriteOnly );
 
790
        QMap<int, QStringList>::ConstIterator a = buddies.begin();
 
791
        while ( a != buddies.end() ) {
 
792
            QStringList::ConstIterator b = (*a).begin();
 
793
            while ( b != (*a).end() ) {
 
794
                int no = objects.find( *b );
 
795
                if ( no != -1 ) {
 
796
                    packUInt16( out2, a.key() );
 
797
                    packUInt16( out2, no );
 
798
                }
 
799
                ++b;
 
800
            }
 
801
            ++a;
 
802
        }
 
803
    }
 
804
 
 
805
    if ( !connectionsElem.isNull() ) {
 
806
        QString prevLanguage = "C++";
 
807
        int prevSenderNo = 0;
 
808
        QString prevSignal = "clicked()";
 
809
        int prevReceiverNo = 0;
 
810
        QString prevSlot = "accept()";
 
811
 
 
812
        QDataStream out2( connectionsBlock, IO_WriteOnly );
 
813
        QDomElement f = connectionsElem.firstChild().toElement();
 
814
        while ( !f.isNull() ) {
 
815
            if ( f.tagName() == "connection" ) {
 
816
                QMap<QString, QString> argMap;
 
817
 
 
818
                QDomElement g = f.firstChild().toElement();
 
819
                while ( !g.isNull() ) {
 
820
                    argMap[g.tagName()] = g.firstChild().toText().data();
 
821
                    g = g.nextSibling().toElement();
 
822
                }
 
823
 
 
824
                QString language = f.attribute( "language", "C++" );
 
825
                int senderNo = objects.find( argMap["sender"], widgetNo );
 
826
                int receiverNo = objects.find( argMap["receiver"], widgetNo );
 
827
                QString signal = UibHack::normalize( argMap["signal"] );
 
828
                QString slot = UibHack::normalize( argMap["slot"] );
 
829
 
 
830
                Q_UINT8 connectionFlags = 0;
 
831
                if ( language != prevLanguage )
 
832
                    connectionFlags |= Connection_Language;
 
833
                if ( senderNo != prevSenderNo )
 
834
                    connectionFlags |= Connection_Sender;
 
835
                if ( signal != prevSignal )
 
836
                    connectionFlags |= Connection_Signal;
 
837
                if ( receiverNo != prevReceiverNo )
 
838
                    connectionFlags |= Connection_Receiver;
 
839
                if ( slot != prevSlot )
 
840
                    connectionFlags |= Connection_Slot;
 
841
                out2 << connectionFlags;
 
842
 
 
843
                if ( connectionFlags & Connection_Language )
 
844
                    packString( strings, out2, language );
 
845
                if ( connectionFlags & Connection_Sender )
 
846
                    packUInt16( out2, senderNo );
 
847
                if ( connectionFlags & Connection_Signal )
 
848
                    packStringSplit( strings, out2, signal, '(' );
 
849
                if ( connectionFlags & Connection_Receiver )
 
850
                    packUInt16( out2, receiverNo );
 
851
                if ( connectionFlags & Connection_Slot )
 
852
                    packStringSplit( strings, out2, slot, '(' );
 
853
 
 
854
                prevLanguage = language;
 
855
                prevSenderNo = senderNo;
 
856
                prevSignal = signal;
 
857
                prevReceiverNo = receiverNo;
 
858
                prevSlot = slot;
 
859
            } else if ( f.tagName() == "slot" ) {
 
860
                // ###
 
861
            }
 
862
            f = f.nextSibling().toElement();
 
863
        }
 
864
    }
 
865
 
 
866
    {
 
867
        QDataStream out2( introBlock, IO_WriteOnly );
 
868
        out2 << introFlags;
 
869
        out2 << defaultMargin;
 
870
        out2 << defaultSpacing;
 
871
        packUInt16( out2, objects.count() );
 
872
        packCString( strings, out2, className );
 
873
    }
 
874
 
 
875
    out << UibMagic;
 
876
    out << (Q_UINT8) '\n';
 
877
    out << (Q_UINT8) '\r';
 
878
    out << (Q_UINT8) out.version();
 
879
    outputBlock( out, Block_Strings, strings.block() );
 
880
    outputBlock( out, Block_Intro, introBlock );
 
881
    outputBlock( out, Block_Images, imagesBlock );
 
882
    outputBlock( out, Block_Widget, widgetBlock );
 
883
    outputBlock( out, Block_Slots, slotsBlock );
 
884
    outputBlock( out, Block_Tabstops, tabstopsBlock );
 
885
    outputBlock( out, Block_Actions, actionsBlock );
 
886
    outputBlock( out, Block_Menubar, menubarBlock );
 
887
    outputBlock( out, Block_Toolbars, toolbarsBlock );
 
888
    outputBlock( out, Block_Variables, variablesBlock );
 
889
    outputBlock( out, Block_Functions, functionsBlock );
 
890
    outputBlock( out, Block_Buddies, buddiesBlock );
 
891
    outputBlock( out, Block_Connections, connectionsBlock );
 
892
    out << (Q_UINT8) Block_End;
 
893
}