source: trunk/src/tools/uic/driver.cpp@ 636

Last change on this file since 636 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 10.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "driver.h"
43#include "uic.h"
44#include "ui4.h"
45
46#include <QtCore/QRegExp>
47#include <QtCore/QFileInfo>
48#include <QtCore/QDebug>
49
50QT_BEGIN_NAMESPACE
51
52Driver::Driver()
53 : m_stdout(stdout, QFile::WriteOnly | QFile::Text)
54{
55 m_output = &m_stdout;
56}
57
58Driver::~Driver()
59{
60}
61
62QString Driver::findOrInsertWidget(DomWidget *ui_widget)
63{
64 if (!m_widgets.contains(ui_widget))
65 m_widgets.insert(ui_widget, unique(ui_widget->attributeName(), ui_widget->attributeClass()));
66
67 return m_widgets.value(ui_widget);
68}
69
70QString Driver::findOrInsertSpacer(DomSpacer *ui_spacer)
71{
72 if (!m_spacers.contains(ui_spacer)) {
73 const QString name = ui_spacer->hasAttributeName() ? ui_spacer->attributeName() : QString();
74 m_spacers.insert(ui_spacer, unique(name, QLatin1String("QSpacerItem")));
75 }
76
77 return m_spacers.value(ui_spacer);
78}
79
80QString Driver::findOrInsertLayout(DomLayout *ui_layout)
81{
82 if (!m_layouts.contains(ui_layout)) {
83 const QString name = ui_layout->hasAttributeName() ? ui_layout->attributeName() : QString();
84 m_layouts.insert(ui_layout, unique(name, ui_layout->attributeClass()));
85 }
86
87 return m_layouts.value(ui_layout);
88}
89
90QString Driver::findOrInsertLayoutItem(DomLayoutItem *ui_layoutItem)
91{
92 switch (ui_layoutItem->kind()) {
93 case DomLayoutItem::Widget:
94 return findOrInsertWidget(ui_layoutItem->elementWidget());
95 case DomLayoutItem::Spacer:
96 return findOrInsertSpacer(ui_layoutItem->elementSpacer());
97 case DomLayoutItem::Layout:
98 return findOrInsertLayout(ui_layoutItem->elementLayout());
99 case DomLayoutItem::Unknown:
100 break;
101 }
102
103 Q_ASSERT( 0 );
104
105 return QString();
106}
107
108QString Driver::findOrInsertActionGroup(DomActionGroup *ui_group)
109{
110 if (!m_actionGroups.contains(ui_group))
111 m_actionGroups.insert(ui_group, unique(ui_group->attributeName(), QLatin1String("QActionGroup")));
112
113 return m_actionGroups.value(ui_group);
114}
115
116QString Driver::findOrInsertAction(DomAction *ui_action)
117{
118 if (!m_actions.contains(ui_action))
119 m_actions.insert(ui_action, unique(ui_action->attributeName(), QLatin1String("QAction")));
120
121 return m_actions.value(ui_action);
122}
123
124QString Driver::findOrInsertButtonGroup(const DomButtonGroup *ui_group)
125{
126 ButtonGroupNameHash::iterator it = m_buttonGroups.find(ui_group);
127 if (it == m_buttonGroups.end())
128 it = m_buttonGroups.insert(ui_group, unique(ui_group->attributeName(), QLatin1String("QButtonGroup")));
129 return it.value();
130}
131
132// Find a group by its non-uniqified name
133const DomButtonGroup *Driver::findButtonGroup(const QString &attributeName) const
134{
135 const ButtonGroupNameHash::const_iterator cend = m_buttonGroups.constEnd();
136 for (ButtonGroupNameHash::const_iterator it = m_buttonGroups.constBegin(); it != cend; ++it)
137 if (it.key()->attributeName() == attributeName)
138 return it.key();
139 return 0;
140}
141
142
143QString Driver::findOrInsertName(const QString &name)
144{
145 return unique(name);
146}
147
148QString Driver::normalizedName(const QString &name)
149{
150 QString result = name;
151 QChar *data = result.data();
152 for (int i = name.size(); --i >= 0; ++data) {
153 if (!data->isLetterOrNumber())
154 *data = QLatin1Char('_');
155 }
156 return result;
157}
158
159QString Driver::unique(const QString &instanceName, const QString &className)
160{
161 QString name;
162 bool alreadyUsed = false;
163
164 if (instanceName.size()) {
165 int id = 1;
166 name = instanceName;
167 name = normalizedName(name);
168 QString base = name;
169
170 while (m_nameRepository.contains(name)) {
171 alreadyUsed = true;
172 name = base + QString::number(id++);
173 }
174 } else if (className.size()) {
175 name = unique(qtify(className));
176 } else {
177 name = unique(QLatin1String("var"));
178 }
179
180 if (alreadyUsed && className.size()) {
181 fprintf(stderr, "Warning: name %s is already used\n", qPrintable(instanceName));
182 }
183
184 m_nameRepository.insert(name, true);
185 return name;
186}
187
188QString Driver::qtify(const QString &name)
189{
190 QString qname = name;
191
192 if (qname.at(0) == QLatin1Char('Q') || qname.at(0) == QLatin1Char('K'))
193 qname = qname.mid(1);
194
195 int i=0;
196 while (i < qname.length()) {
197 if (qname.at(i).toLower() != qname.at(i))
198 qname[i] = qname.at(i).toLower();
199 else
200 break;
201
202 ++i;
203 }
204
205 return qname;
206}
207
208static bool isAnsiCCharacter(const QChar& c)
209{
210 return (c.toUpper() >= QLatin1Char('A') && c.toUpper() <= QLatin1Char('Z'))
211 || c.isDigit() || c == QLatin1Char('_');
212}
213
214QString Driver::headerFileName() const
215{
216 QString name = m_option.outputFile;
217
218 if (name.isEmpty()) {
219 name = QLatin1String("ui_"); // ### use ui_ as prefix.
220 name.append(m_option.inputFile);
221 }
222
223 return headerFileName(name);
224}
225
226QString Driver::headerFileName(const QString &fileName)
227{
228 if (fileName.isEmpty())
229 return headerFileName(QLatin1String("noname"));
230
231 QFileInfo info(fileName);
232 QString baseName = info.baseName();
233 // Transform into a valid C++ identifier
234 if (!baseName.isEmpty() && baseName.at(0).isDigit())
235 baseName.prepend(QLatin1Char('_'));
236 for (int i = 0; i < baseName.size(); ++i) {
237 QChar c = baseName.at(i);
238 if (!isAnsiCCharacter(c)) {
239 // Replace character by its unicode value
240 QString hex = QString::number(c.unicode(), 16);
241 baseName.replace(i, 1, QLatin1Char('_') + hex + QLatin1Char('_'));
242 i += hex.size() + 1;
243 }
244 }
245 return baseName.toUpper() + QLatin1String("_H");
246}
247
248bool Driver::printDependencies(const QString &fileName)
249{
250 Q_ASSERT(m_option.dependencies == true);
251
252 m_option.inputFile = fileName;
253
254 Uic tool(this);
255 return tool.printDependencies();
256}
257
258bool Driver::uic(const QString &fileName, DomUI *ui, QTextStream *out)
259{
260 m_option.inputFile = fileName;
261
262 QTextStream *oldOutput = m_output;
263
264 m_output = out != 0 ? out : &m_stdout;
265
266 Uic tool(this);
267 bool rtn = false;
268#ifdef QT_UIC_CPP_GENERATOR
269 rtn = tool.write(ui);
270#else
271 Q_UNUSED(ui);
272 fprintf(stderr, "uic: option to generate cpp code not compiled in [%s:%d]\n",
273 __FILE__, __LINE__);
274#endif
275
276 m_output = oldOutput;
277
278 return rtn;
279}
280
281bool Driver::uic(const QString &fileName, QTextStream *out)
282{
283 QFile f;
284 if (fileName.isEmpty())
285 f.open(stdin, QIODevice::ReadOnly);
286 else {
287 f.setFileName(fileName);
288 if (!f.open(QIODevice::ReadOnly))
289 return false;
290 }
291
292 m_option.inputFile = fileName;
293
294 QTextStream *oldOutput = m_output;
295 bool deleteOutput = false;
296
297 if (out) {
298 m_output = out;
299 } else {
300#ifdef Q_WS_WIN
301 // As one might also redirect the output to a file on win,
302 // we should not create the textstream with QFile::Text flag.
303 // The redirected file is opened in TextMode and this will
304 // result in broken line endings as writing will replace \n again.
305 m_output = new QTextStream(stdout, QIODevice::WriteOnly);
306#else
307 m_output = new QTextStream(stdout, QIODevice::WriteOnly | QFile::Text);
308#endif
309 deleteOutput = true;
310 }
311
312 Uic tool(this);
313 bool rtn = tool.write(&f);
314 f.close();
315
316 if (deleteOutput)
317 delete m_output;
318
319 m_output = oldOutput;
320
321 return rtn;
322}
323
324void Driver::reset()
325{
326 Q_ASSERT( m_output == 0 );
327
328 m_option = Option();
329 m_output = 0;
330 m_problems.clear();
331
332 QStringList m_problems;
333
334 m_widgets.clear();
335 m_spacers.clear();
336 m_layouts.clear();
337 m_actionGroups.clear();
338 m_actions.clear();
339 m_nameRepository.clear();
340 m_pixmaps.clear();
341}
342
343void Driver::insertPixmap(const QString &pixmap)
344{
345 m_pixmaps.insert(pixmap, true);
346}
347
348bool Driver::containsPixmap(const QString &pixmap) const
349{
350 return m_pixmaps.contains(pixmap);
351}
352
353DomWidget *Driver::widgetByName(const QString &name) const
354{
355 return m_widgets.key(name);
356}
357
358DomSpacer *Driver::spacerByName(const QString &name) const
359{
360 return m_spacers.key(name);
361}
362
363DomLayout *Driver::layoutByName(const QString &name) const
364{
365 return m_layouts.key(name);
366}
367
368DomActionGroup *Driver::actionGroupByName(const QString &name) const
369{
370 return m_actionGroups.key(name);
371}
372
373DomAction *Driver::actionByName(const QString &name) const
374{
375 return m_actions.key(name);
376}
377
378QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.