~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to tools/porting/src/projectporter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the porting application of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "projectporter.h"
 
30
#include <QDebug>
 
31
#include <QFile>
 
32
#include <QDir>
 
33
#include <QStringList>
 
34
#include <QFileInfo>
 
35
#include <QBuffer>
 
36
#include "proparser.h"
 
37
#include "textreplacement.h"
 
38
#include "fileporter.h"
 
39
#include "logger.h"
 
40
#include "translationunit.h"
 
41
#include "codemodelattributes.h"
 
42
 
 
43
using namespace TokenEngine;
 
44
 
 
45
ProjectPorter::ProjectPorter(QString basePath, QStringList includeDirectories, QStringList qt3HeadersFilenames)
 
46
:basePath(basePath)
 
47
,includeDirectories(includeDirectories)
 
48
,defaultDefinitions(defaultMacros(preprocessorCache))
 
49
,filePorter(preprocessorCache)
 
50
,qt3HeadersFilenames(qt3HeadersFilenames)
 
51
,analyze(true)
 
52
,warnings(false)
 
53
{}
 
54
 
 
55
void ProjectPorter::enableCppParsing(bool enable)
 
56
{
 
57
    analyze = enable;
 
58
}
 
59
 
 
60
void ProjectPorter::enableMissingFilesWarnings(bool enable)
 
61
{
 
62
    warnings = enable;
 
63
}
 
64
 
 
65
void ProjectPorter::portProject(QString fileName)
 
66
{
 
67
    QFileInfo fileInfo(fileName);
 
68
    portProject(fileInfo.path(), fileInfo.fileName());
 
69
}
 
70
 
 
71
/*
 
72
    Port a single file
 
73
*/
 
74
void ProjectPorter::portFile(QString fileName)
 
75
{
 
76
    if (analyze) {
 
77
        IncludeFiles includeFiles(basePath, includeDirectories);
 
78
 
 
79
        PreprocessorController preprocessor(includeFiles, preprocessorCache, qt3HeadersFilenames);
 
80
        connect(&preprocessor, SIGNAL(error(QString, QString)), SLOT(error(QString, QString)));
 
81
 
 
82
        Rpp::DefineMap definitionsCopy = *defaultDefinitions;
 
83
        // Preprocess
 
84
        TokenSectionSequence translationUnit = preprocessor.evaluate(fileName, &definitionsCopy);
 
85
        // Parse
 
86
        TranslationUnit translationUnitData = TranslationUnitAnalyzer().analyze(translationUnit);
 
87
 
 
88
        // Enable attribute generation for this file.
 
89
        enableAttributes(includeFiles, fileName);
 
90
        // Generate attributes.
 
91
        CodeModelAttributes().createAttributes(translationUnitData);
 
92
    }
 
93
 
 
94
    portFiles(QString(), QStringList() << fileName);
 
95
}
 
96
 
 
97
void ProjectPorter::error(QString type, QString text)
 
98
{
 
99
   if (warnings && type == "Error")
 
100
        cout << "Warning: " << text.toLocal8Bit().constData() << endl;
 
101
}
 
102
 
 
103
void ProjectPorter::portProject(QString basePath, QString proFileName)
 
104
{
 
105
    QString fullInFileName = basePath + "/" + proFileName;
 
106
    QFileInfo infileInfo(fullInFileName);
 
107
    if (!infileInfo.exists()) {
 
108
        cout << "Could not open file: " << QDir::convertSeparators(fullInFileName).toLocal8Bit().constData() << endl;
 
109
        return;
 
110
    }
 
111
 
 
112
    QString proFileContents = loadFile(fullInFileName);
 
113
    QMap<QString, QString> proFileMap = proFileTagMap(proFileContents, QDir(basePath).absolutePath());
 
114
 
 
115
 
 
116
    // Check if this is a TEMPLATE = subdirs .pro file, in that case we
 
117
    // process each subdir (recursively).
 
118
 
 
119
    QString templateTag = proFileMap["TEMPLATE"];
 
120
    if (templateTag == "subdirs") {
 
121
        QStringList subdirs = proFileMap["SUBDIRS"].split(" ", QString::SkipEmptyParts);
 
122
        foreach(QString subdir, subdirs) {
 
123
            QString newBasePath  = basePath + "/" + subdir;
 
124
            QStringList dirsInSubdir = subdir.split(QRegExp("/|\\\\"), QString::SkipEmptyParts);
 
125
            QString newProFileName = dirsInSubdir.last() + ".pro";
 
126
            portProject(newBasePath, newProFileName);
 
127
        }
 
128
        return;
 
129
    }
 
130
 
 
131
    // Get headers and sources file names from .pro file.
 
132
    QStringList sources = proFileMap["SOURCES"].split(" ", QString::SkipEmptyParts);
 
133
    QStringList headers = proFileMap["HEADERS"].split(" ", QString::SkipEmptyParts);
 
134
    QStringList forms = proFileMap["FORMS"].split(" ", QString::SkipEmptyParts);
 
135
    QStringList uidoth;
 
136
    for (int i = 0; i < forms.size(); ++i) {
 
137
        QString ui_h = forms.at(i) + ".h";
 
138
        if (QFile::exists(basePath + "/" + ui_h))
 
139
            uidoth += ui_h;
 
140
    }
 
141
 
 
142
    if (analyze) {
 
143
        cout << "Parsing";
 
144
        // Get include paths from the pro file.
 
145
        QStringList includeProPaths = proFileMap["INCLUDEPATH"].split(" ", QString::SkipEmptyParts);
 
146
        QStringList dependProPaths = proFileMap["DEPENDPATH"].split(" ", QString::SkipEmptyParts);
 
147
        IncludeFiles includeFiles(basePath, includeDirectories + includeProPaths + dependProPaths);
 
148
 
 
149
        PreprocessorController preprocessorController(includeFiles, preprocessorCache, qt3HeadersFilenames);
 
150
        connect(&preprocessorController, SIGNAL(error(QString, QString)), SLOT(error(QString, QString)));
 
151
 
 
152
        TranslationUnitAnalyzer translationUnitAnalyzer;
 
153
        CodeModelAttributes codeModelAttributes;
 
154
 
 
155
        // Enable attribute generation for header files.
 
156
        foreach(QString headerFile, headers)
 
157
            enableAttributes(includeFiles, headerFile);
 
158
 
 
159
        // Enable attribute generation for ui.h files.
 
160
        foreach(QString headerFile, uidoth)
 
161
            enableAttributes(includeFiles, headerFile);
 
162
 
 
163
        // Analyze each translation unit. (one per cpp file)
 
164
        foreach(QString sourceFile, sources) {
 
165
            cout << "." << std::flush;
 
166
            Rpp::DefineMap definitionsCopy = *defaultDefinitions;
 
167
            TokenSectionSequence translationUnit =
 
168
                preprocessorController.evaluate(sourceFile, &definitionsCopy);
 
169
            TranslationUnit translationUnitData =
 
170
                translationUnitAnalyzer.analyze(translationUnit);
 
171
 
 
172
            // Enable attribute generation for this file.
 
173
            enableAttributes(includeFiles, sourceFile);
 
174
 
 
175
            codeModelAttributes.createAttributes(translationUnitData);
 
176
        }
 
177
        cout << endl;
 
178
    }
 
179
 
 
180
 
 
181
    // Port files.
 
182
    portFiles(basePath, sources);
 
183
    portFiles(basePath, headers);
 
184
    if (!uidoth.isEmpty())
 
185
        portFiles(basePath, uidoth);
 
186
 
 
187
    Logger::instance()->globalState["currentFileName"] = proFileName;
 
188
    Logger::instance()->beginSection();
 
189
    portProFile(fullInFileName, proFileMap);
 
190
}
 
191
 
 
192
/*
 
193
    Port each file given in the fileNames list. If a file name is relative
 
194
    it is assumed to be relative to basePath.
 
195
*/
 
196
void ProjectPorter::portFiles(QString basePath, QStringList fileNames)
 
197
{
 
198
    foreach(QString fileName, fileNames) {
 
199
        QString fullFilePath;
 
200
        QFileInfo fileInfo(fileName);
 
201
        if (fileInfo.isAbsolute()) {
 
202
            fullFilePath = QDir::cleanPath(fileName);
 
203
        } else {
 
204
            fullFilePath = QDir::cleanPath(basePath + "/" + fileName);
 
205
        }
 
206
 
 
207
        QFileInfo fullFilePathInfo(fullFilePath);
 
208
        if (!fullFilePathInfo.exists()) {
 
209
            cout << "Could not find file:" <<
 
210
                QDir::convertSeparators(fullFilePath).toLocal8Bit().constData() <<endl;
 
211
            continue;
 
212
        }
 
213
 
 
214
        if (!processedFilesSet.contains(fullFilePath)){
 
215
            Logger::instance()->globalState["currentFileName"] = fullFilePath;
 
216
            filePorter.port(fullFilePath);
 
217
            processedFilesSet.insert(fullFilePath);
 
218
        }
 
219
    }
 
220
}
 
221
 
 
222
void ProjectPorter::portProFile(QString fileName, QMap<QString, QString> tagMap)
 
223
{
 
224
    // Read pro file.
 
225
    QFile proFile(fileName);
 
226
    if (!proFile.open(QIODevice::ReadOnly))
 
227
        return;
 
228
    QTextStream proTextStream(&proFile);
 
229
    QStringList lines;
 
230
    while (!proTextStream.atEnd())
 
231
        lines += proTextStream.readLine();
 
232
 
 
233
    proFile.close();
 
234
 
 
235
    // Find out what modules we should add to the QT variable.
 
236
     QSet<QByteArray> qtModules;
 
237
 
 
238
    // Add qt3support to the Qt tag
 
239
    qtModules.insert("qt3support");
 
240
 
 
241
    // Read CONFIG and add other modules.
 
242
    QStringList config = tagMap["CONFIG"].split(" ", QString::SkipEmptyParts);
 
243
    if (config.contains("opengl"))
 
244
        qtModules.insert("opengl");
 
245
    if (config.contains("xml"))
 
246
        qtModules.insert("xml");
 
247
    if (config.contains("sql"))
 
248
        qtModules.insert("sql");
 
249
    if (config.contains("network"))
 
250
        qtModules.insert("network");
 
251
 
 
252
    // Get set of used modules from the file porter.
 
253
    qtModules += filePorter.usedQtModules();
 
254
 
 
255
    // Remove gui and core.
 
256
    qtModules.remove("gui");
 
257
    qtModules.remove("core");
 
258
 
 
259
    // Qt3Support is already added.
 
260
    qtModules.remove("3support");
 
261
 
 
262
    // Remove modules already present in the QT variable.
 
263
    QStringList qt = tagMap["QT"].split(" ", QString::SkipEmptyParts);
 
264
    foreach(QString name, qt) {
 
265
        qtModules.remove(name.toLatin1());
 
266
    }
 
267
 
 
268
    Logger *logger = Logger::instance();
 
269
    bool changesMade = false;
 
270
 
 
271
    if (!qtModules.isEmpty()) {
 
272
        changesMade = true;
 
273
        QString insertText = "QT += ";
 
274
        foreach(QByteArray module, qtModules) {
 
275
            insertText += module + QLatin1Char(' ');
 
276
        }
 
277
        lines += QString("#The following line was inserted by qt3to4");
 
278
        lines += insertText;
 
279
         QString logText = "In file "
 
280
                        + logger->globalState.value("currentFileName")
 
281
                        + ": Added entry "
 
282
                        + insertText;
 
283
        logger->addEntry(new PlainLogEntry("Info", "Porting", logText));
 
284
    }
 
285
 
 
286
    // Add uic3 if we have forms.
 
287
    if (!tagMap["FORMS"].isEmpty() || !tagMap["INTERFACES"].isEmpty()) {
 
288
        changesMade = true;
 
289
        lines += QString("#The following line was inserted by qt3to4");
 
290
        QString insertText = "CONFIG += uic3\n";
 
291
        lines += insertText;
 
292
        QString logText = "In file "
 
293
                        + logger->globalState.value("currentFileName")
 
294
                        + ": Added entry "
 
295
                        + insertText;
 
296
        logger->addEntry(new PlainLogEntry("Info", "Porting", logText));
 
297
    }
 
298
 
 
299
    // Comment out any REQUIRES tag.
 
300
    if (!tagMap["REQUIRES"].isEmpty()) {
 
301
        changesMade = true;
 
302
        QString insertText("#The following line was commented out by qt3to4");
 
303
        for (int i = 0; i < lines.count(); ++i) {
 
304
            if (lines.at(i).startsWith("REQUIRES")) {
 
305
                QString lineCopy = lines.at(i);
 
306
                lineCopy.prepend('#');
 
307
                lines[i] = lineCopy;
 
308
                lines.insert(i, insertText);
 
309
                ++i; //skip ahead, we just insertet a line at i.
 
310
                QString logText = "In file "
 
311
                            + logger->globalState.value("currentFileName")
 
312
                            + ": Commented out REQUIRES section";
 
313
                logger->addEntry(new PlainLogEntry("Info", "Porting", logText));
 
314
            }
 
315
        }
 
316
    }
 
317
 
 
318
    // Check if any changes has been made.
 
319
    if (!changesMade) {
 
320
        Logger::instance()->addEntry(
 
321
            new PlainLogEntry("Info", "Porting",  QLatin1String("No changes made to file ") + fileName));
 
322
        Logger::instance()->commitSection();
 
323
        return;
 
324
    }
 
325
 
 
326
    // Write lines to array.
 
327
    QByteArray bob;
 
328
    QTextStream outProFileStream(&bob);
 
329
    foreach(QString line, lines)
 
330
        outProFileStream << line << QLatin1Char('\n');
 
331
    outProFileStream.flush();
 
332
 
 
333
    // Write array to file, commit log if write was successful.
 
334
    FileWriter::WriteResult result = FileWriter::instance()->writeFileVerbously(fileName, bob);
 
335
    if (result == FileWriter::WriteSucceeded) {
 
336
        logger->commitSection();
 
337
    } else if (result == FileWriter::WriteFailed) {
 
338
        logger->revertSection();
 
339
        logger->addEntry(
 
340
            new PlainLogEntry("Error", "Porting",  QLatin1String("Error writing to file ") + fileName));
 
341
    } else if (result == FileWriter::WriteSkipped) {
 
342
        logger->revertSection();
 
343
        logger->addEntry(
 
344
            new PlainLogEntry("Error", "Porting",  QLatin1String("User skipped file ") + fileName));
 
345
    } else {
 
346
        // Internal error.
 
347
        logger->revertSection();
 
348
        const QString errorString = QLatin1String("Internal error in qt3to4 - FileWriter returned invalid result code while writing to ") + fileName;
 
349
        logger->addEntry(new PlainLogEntry("Error", "Porting", errorString));
 
350
    }
 
351
}
 
352
 
 
353
/*
 
354
    Enables attribute generation for fileName. The file is looked up using the
 
355
    provied includeFiles object.
 
356
*/
 
357
void ProjectPorter::enableAttributes(const IncludeFiles &includeFiles, const QString &fileName)
 
358
{
 
359
    QString resolvedFilePath = includeFiles.resolve(fileName);
 
360
    if (!QFile::exists(resolvedFilePath))
 
361
            resolvedFilePath = includeFiles.angleBracketLookup(fileName);
 
362
    if (!QFile::exists(resolvedFilePath))
 
363
        return;
 
364
 
 
365
    TokenContainer tokenContainer = preprocessorCache.sourceTokens(resolvedFilePath);
 
366
    TokenAttributes *attributes = tokenContainer.tokenAttributes();
 
367
    attributes->addAttribute("CreateAttributes", "True");
 
368
}