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

Last change on this file since 933 was 933, checked in by Dmitry A. Kuminov, 14 years ago

uic: Put stdin/stdout to binary mode on Windows and OS/2.

This is necessary to avoid duplication of CR symbols on output
and hangs in atEnd() due to unexpected CR on input (in particular,
seen when stdin and stdout are redirected to regular files). See
also r932.

Note: it actually may make sense to change QFile::open() so that
it implicitly makes this mode change and restores the origianl mode
on destruction. Just to be on the safe side.

File size: 10.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
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
50#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
51#include <io.h>
52#include <fcntl.h>
53#endif
54
55QT_BEGIN_NAMESPACE
56
57Driver::Driver()
58 : m_stdout(stdout, QFile::WriteOnly | QFile::Text)
59{
60 m_output = &m_stdout;
61}
62
63Driver::~Driver()
64{
65}
66
67QString Driver::findOrInsertWidget(DomWidget *ui_widget)
68{
69 if (!m_widgets.contains(ui_widget))
70 m_widgets.insert(ui_widget, unique(ui_widget->attributeName(), ui_widget->attributeClass()));
71
72 return m_widgets.value(ui_widget);
73}
74
75QString Driver::findOrInsertSpacer(DomSpacer *ui_spacer)
76{
77 if (!m_spacers.contains(ui_spacer)) {
78 const QString name = ui_spacer->hasAttributeName() ? ui_spacer->attributeName() : QString();
79 m_spacers.insert(ui_spacer, unique(name, QLatin1String("QSpacerItem")));
80 }
81
82 return m_spacers.value(ui_spacer);
83}
84
85QString Driver::findOrInsertLayout(DomLayout *ui_layout)
86{
87 if (!m_layouts.contains(ui_layout)) {
88 const QString name = ui_layout->hasAttributeName() ? ui_layout->attributeName() : QString();
89 m_layouts.insert(ui_layout, unique(name, ui_layout->attributeClass()));
90 }
91
92 return m_layouts.value(ui_layout);
93}
94
95QString Driver::findOrInsertLayoutItem(DomLayoutItem *ui_layoutItem)
96{
97 switch (ui_layoutItem->kind()) {
98 case DomLayoutItem::Widget:
99 return findOrInsertWidget(ui_layoutItem->elementWidget());
100 case DomLayoutItem::Spacer:
101 return findOrInsertSpacer(ui_layoutItem->elementSpacer());
102 case DomLayoutItem::Layout:
103 return findOrInsertLayout(ui_layoutItem->elementLayout());
104 case DomLayoutItem::Unknown:
105 break;
106 }
107
108 Q_ASSERT( 0 );
109
110 return QString();
111}
112
113QString Driver::findOrInsertActionGroup(DomActionGroup *ui_group)
114{
115 if (!m_actionGroups.contains(ui_group))
116 m_actionGroups.insert(ui_group, unique(ui_group->attributeName(), QLatin1String("QActionGroup")));
117
118 return m_actionGroups.value(ui_group);
119}
120
121QString Driver::findOrInsertAction(DomAction *ui_action)
122{
123 if (!m_actions.contains(ui_action))
124 m_actions.insert(ui_action, unique(ui_action->attributeName(), QLatin1String("QAction")));
125
126 return m_actions.value(ui_action);
127}
128
129QString Driver::findOrInsertButtonGroup(const DomButtonGroup *ui_group)
130{
131 ButtonGroupNameHash::iterator it = m_buttonGroups.find(ui_group);
132 if (it == m_buttonGroups.end())
133 it = m_buttonGroups.insert(ui_group, unique(ui_group->attributeName(), QLatin1String("QButtonGroup")));
134 return it.value();
135}
136
137// Find a group by its non-uniqified name
138const DomButtonGroup *Driver::findButtonGroup(const QString &attributeName) const
139{
140 const ButtonGroupNameHash::const_iterator cend = m_buttonGroups.constEnd();
141 for (ButtonGroupNameHash::const_iterator it = m_buttonGroups.constBegin(); it != cend; ++it)
142 if (it.key()->attributeName() == attributeName)
143 return it.key();
144 return 0;
145}
146
147
148QString Driver::findOrInsertName(const QString &name)
149{
150 return unique(name);
151}
152
153QString Driver::normalizedName(const QString &name)
154{
155 QString result = name;
156 QChar *data = result.data();
157 for (int i = name.size(); --i >= 0; ++data) {
158 if (!data->isLetterOrNumber())
159 *data = QLatin1Char('_');
160 }
161 return result;
162}
163
164QString Driver::unique(const QString &instanceName, const QString &className)
165{
166 QString name;
167 bool alreadyUsed = false;
168
169 if (instanceName.size()) {
170 int id = 1;
171 name = instanceName;
172 name = normalizedName(name);
173 QString base = name;
174
175 while (m_nameRepository.contains(name)) {
176 alreadyUsed = true;
177 name = base + QString::number(id++);
178 }
179 } else if (className.size()) {
180 name = unique(qtify(className));
181 } else {
182 name = unique(QLatin1String("var"));
183 }
184
185 if (alreadyUsed && className.size()) {
186 fprintf(stderr, "%s: Warning: The name '%s' (%s) is already in use, defaulting to '%s'.\n",
187 qPrintable(m_option.messagePrefix()),
188 qPrintable(instanceName), qPrintable(className),
189 qPrintable(name));
190 }
191
192 m_nameRepository.insert(name, true);
193 return name;
194}
195
196QString Driver::qtify(const QString &name)
197{
198 QString qname = name;
199
200 if (qname.at(0) == QLatin1Char('Q') || qname.at(0) == QLatin1Char('K'))
201 qname = qname.mid(1);
202
203 int i=0;
204 while (i < qname.length()) {
205 if (qname.at(i).toLower() != qname.at(i))
206 qname[i] = qname.at(i).toLower();
207 else
208 break;
209
210 ++i;
211 }
212
213 return qname;
214}
215
216static bool isAnsiCCharacter(const QChar& c)
217{
218 return (c.toUpper() >= QLatin1Char('A') && c.toUpper() <= QLatin1Char('Z'))
219 || c.isDigit() || c == QLatin1Char('_');
220}
221
222QString Driver::headerFileName() const
223{
224 QString name = m_option.outputFile;
225
226 if (name.isEmpty()) {
227 name = QLatin1String("ui_"); // ### use ui_ as prefix.
228 name.append(m_option.inputFile);
229 }
230
231 return headerFileName(name);
232}
233
234QString Driver::headerFileName(const QString &fileName)
235{
236 if (fileName.isEmpty())
237 return headerFileName(QLatin1String("noname"));
238
239 QFileInfo info(fileName);
240 QString baseName = info.baseName();
241 // Transform into a valid C++ identifier
242 if (!baseName.isEmpty() && baseName.at(0).isDigit())
243 baseName.prepend(QLatin1Char('_'));
244 for (int i = 0; i < baseName.size(); ++i) {
245 QChar c = baseName.at(i);
246 if (!isAnsiCCharacter(c)) {
247 // Replace character by its unicode value
248 QString hex = QString::number(c.unicode(), 16);
249 baseName.replace(i, 1, QLatin1Char('_') + hex + QLatin1Char('_'));
250 i += hex.size() + 1;
251 }
252 }
253 return baseName.toUpper() + QLatin1String("_H");
254}
255
256bool Driver::printDependencies(const QString &fileName)
257{
258 Q_ASSERT(m_option.dependencies == true);
259
260 m_option.inputFile = fileName;
261
262 Uic tool(this);
263 return tool.printDependencies();
264}
265
266bool Driver::uic(const QString &fileName, DomUI *ui, QTextStream *out)
267{
268 m_option.inputFile = fileName;
269
270 QTextStream *oldOutput = m_output;
271
272 m_output = out != 0 ? out : &m_stdout;
273
274 Uic tool(this);
275 bool rtn = false;
276#ifdef QT_UIC_CPP_GENERATOR
277 rtn = tool.write(ui);
278#else
279 Q_UNUSED(ui);
280 fprintf(stderr, "uic: option to generate cpp code not compiled in [%s:%d]\n",
281 __FILE__, __LINE__);
282#endif
283
284 m_output = oldOutput;
285
286 return rtn;
287}
288
289bool Driver::uic(const QString &fileName, QTextStream *out)
290{
291 QFile f;
292 if (fileName.isEmpty()) {
293#if defined(Q_OS_WIN)
294 _setmode(_fileno(stdin), _O_BINARY);
295#elif defined(Q_OS_OS2)
296 setmode(fileno(stdin), O_BINARY);
297#endif
298 f.open(stdin, QIODevice::ReadOnly);
299 } else {
300 f.setFileName(fileName);
301 if (!f.open(QIODevice::ReadOnly))
302 return false;
303 }
304
305 m_option.inputFile = fileName;
306
307 QTextStream *oldOutput = m_output;
308 bool deleteOutput = false;
309
310 if (out) {
311 m_output = out;
312 } else {
313#if defined(Q_WS_WIN)
314 _setmode(_fileno(stdout), _O_BINARY);
315#elif defined(Q_OS_OS2)
316 setmode(fileno(stdout), O_BINARY);
317#endif
318 m_output = new QTextStream(stdout, QIODevice::WriteOnly | QFile::Text);
319 deleteOutput = true;
320 }
321
322 Uic tool(this);
323 bool rtn = tool.write(&f);
324 f.close();
325
326 if (deleteOutput)
327 delete m_output;
328
329 m_output = oldOutput;
330
331 return rtn;
332}
333
334void Driver::reset()
335{
336 Q_ASSERT( m_output == 0 );
337
338 m_option = Option();
339 m_output = 0;
340 m_problems.clear();
341
342 QStringList m_problems;
343
344 m_widgets.clear();
345 m_spacers.clear();
346 m_layouts.clear();
347 m_actionGroups.clear();
348 m_actions.clear();
349 m_nameRepository.clear();
350 m_pixmaps.clear();
351}
352
353void Driver::insertPixmap(const QString &pixmap)
354{
355 m_pixmaps.insert(pixmap, true);
356}
357
358bool Driver::containsPixmap(const QString &pixmap) const
359{
360 return m_pixmaps.contains(pixmap);
361}
362
363DomWidget *Driver::widgetByName(const QString &name) const
364{
365 return m_widgets.key(name);
366}
367
368DomSpacer *Driver::spacerByName(const QString &name) const
369{
370 return m_spacers.key(name);
371}
372
373DomLayout *Driver::layoutByName(const QString &name) const
374{
375 return m_layouts.key(name);
376}
377
378DomActionGroup *Driver::actionGroupByName(const QString &name) const
379{
380 return m_actionGroups.key(name);
381}
382
383DomAction *Driver::actionByName(const QString &name) const
384{
385 return m_actions.key(name);
386}
387
388QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.