Merge remote branch 'origin/2.2'

This commit is contained in:
Oswald Buddenhagen
2011-04-07 10:12:39 +02:00
21 changed files with 375 additions and 219 deletions

View File

@@ -174,26 +174,62 @@
Ubuntu or Debian?}
\code
@
sudo apt-get install libglib2.0-dev libSM-dev libxrender-dev libfontconfig1-dev libxext-dev
@
\endcode
If you use QtOpenGL, you also need:
\code
@
sudo apt-get install libgl-dev libglu-dev
@
\endcode
\section1 Platform Releated Questions
\bold {Can I develop Qt for Symbian applications with Qt Creator?}
\bold {Where is application output shown in Qt Creator?}
Qt Creator comes with support for developing Qt applications that target
the Symbian platform. For more information, see
\l{Creating a Mobile Application with Qt SDK}.
\bold {On Unix (Linux and Mac OS):} \c qDebug() and related functions use
the standard output and error output. When you run or debug the
application, you can view the output in the \gui{Application Output} pane.
For console applications that require input, select \gui {Projects > Run
Settings > Run in terminal}.
\bold {On Windows:} Output is displayed differently for \e{console
applications} and \e{GUI applications}.
The setting \c {CONFIG += console} in the .pro file specifies that the
application is built as a console application using some other runtime.
When you run a console application, you can view the output in the console
window of the calling application. If the
calling application is a GUI application (for example, a release-built
version of Qt Creator), a new console window is opened. For this
type of application, \c qDebug() and related functions use standard output
and error output.
We recommend that you select \gui {Projects > Run Settings > Run in
terminal} for console applications.
For GUI applications, \c qDebug() and related functions use the Windows API
function \c OutputDebugString(). The output is displayed in the
\gui{Application Output} pane. However, only one output pane tab may be
open at a time or the output is not displayed correctly. You can use an
external debug output viewer, such as the
\l{http://technet.microsoft.com/en-us/sysinternals/bb896647}{DebugView for Windows}
to display output from GUI applications.
\bold {On Symbian OS}: \c qDebug() and related functions use the native
\c RDebug::Print functionality.
When you use the Symbian emulator on Windows, the output is redirected to
standard debug output. To view it, you can use a Windows debug output
viewer, such as the DebugView for Windows.
On devices, the \c RDebug output is intercepted by \e CODA or \e {App TRK}
and then propagated to Qt Creator, which displays it in the
\gui {Application Output} pane.
Symbian OS provides no support for differentiating between standard output
and error output.
\section1 Questions about New Features

View File

@@ -1024,17 +1024,48 @@
\title Developing Widget Based Applications
Widgets and forms created with \QD are integrated seamlessly with programmed code,
using the Qt signals and slots mechanism, that lets you easily assign behavior to
Widgets and forms created with \QD are integrated seamlessly with
programmed code by using the Qt signals and slots mechanism that allows you
to easily assign behavior to
graphical elements. All properties set in \QD can be changed dynamically within the code.
Furthermore, features like widget promotion and custom plugins allow you to use your
own widgets with \QD.
Furthermore, features such as widget promotion and custom plugins allow you to use your
own widgets with \QD. For more information, see
\l{Adding Qt Designer Plugins}.
Qt Creator automatically opens all .ui files in \QD.
Qt Creator automatically opens all .ui files in the integrated \QD, in
\gui Design mode.
\image qtcreator-formedit.png
For more information about \QD, see the
\l{http://doc.qt.nokia.com/4.7/designer-manual.html}{Qt Designer Manual}.
Generally, the integrated \QD contains the same functions as the standalone
\QD. The following sections describe the differences.
\section1 Code Editor Integration
To switch between forms (\gui Design mode) and code (\gui Edit mode),
press \key Shift+F4.
You can use Qt Creator to create stub implementations of slot functions.
In the \gui Design mode, right-click a widget to open a context menu, and
then select \gui {Go to Slot...}. Select a signal in the list to go to an
existing slot function or to create a new slot function.
\section1 Managing Image Resources
In standalone \QD, image resources are created using the built-in
\gui {Resource Editor}. In Qt Creator, .ui files are usually part of a
project, which may contain several resource files (.qrc). They are created
and maintained by using the Qt Creator Resource Editor. The \QD
\gui {Resource Editor} is de-activated and the image resources are
displayed in the \QD \gui {Resource Browser}.
\section1 Specifying Settings for Qt Designer
To change the layout of \QD user interface elements:
\list 1
\o Select \gui Tools > \gui{Form Editor} > \gui Views >
\gui Locked.
@@ -1044,29 +1075,50 @@
position.
\endlist
To change \QD properties, select \gui Tools > \gui Options... >
\gui Designer.
To specify settings for \QD:
\list
\o Set the class properties and code generation preferences in \gui
{Class Generation}.
\o Set an additional folder for saving templates in \gui{Template
\o Select \gui Tools > \gui Options... > \gui Designer.
\o Specify settins for generating classes and code in \gui {Class
Generation}.
\o Specify embedded device profiles, that determine style, font, and
screen resolution, for example, in \gui{Embedded Design}.
\o Specify settings for the grid and previewing forms in \gui Forms.
\o Specify an additional folder for saving templates in \gui{Template
Paths}.
\o Set the grid settings and preview preferences in \gui Forms. To
preview your form with skins, enable \gui{Print/Preview
Configuration} and select your skin. Otherwise default preview
settings are used.
\endlist
To preview the settings, select \gui Tools > \gui{Form Editor} >
\gui Preview, or press \key Alt+Shift+R.
\o To specify embedded device profiles, such as style, font, and screen
resolution, select \gui{Embedded Design}.
\section1 Previewing Forms Using Device Skins
A \e {device skin} is a set of configuration files that describe a mobile
device. It includes a border image that surrounds the form and depicts a
mobile device with its buttons.
To preview your form using device skins:
\list 1
\o Select \gui Tools > \gui Options... > \gui Designer.
\o Select the \gui{Print/Preview Configuration} check box.
\o In the \gui {Device skin} field, select a device skin.
\o When the form is open in \gui Design mode, press \key Alt+Shift+R.
\o To end the preview, right-click the skin and select \gui Close in
the context menu.
\endlist
To switch between forms and code, use \key Shift+F4.
For more information on \QD, see
\l{http://doc.qt.nokia.com/4.7/designer-manual.html}{Qt Designer Manual}.
*/
@@ -5212,12 +5264,6 @@
(using the Certified Signed path or the manufacturer-specific channel).
For more information, see \l{Deploying Applications to Symbian Devices}.
\note At the time of writing this document, the distribution of Qt 4.7.x based
applications is supported by neither Ovi Store nor Smart Installer.
For up-to-date information about the packages available for distribution, see the
\l{http://wiki.forum.nokia.com/index.php/Nokia_Smart_Installer_for_Symbian}{Nokia Smart Installer for Symbian}
wiki.
To use the publishing wizard:
\list 1
@@ -8826,13 +8872,6 @@
.qml file in your project. All the other files in the project are automatically added
to the application project.
For example, you can open and run the
\l {http://doc.qt.nokia.com/4.7/qdeclarativeexamples.html} {QML examples and demos}
to learn how to use various aspects of QML. To run the examples in the QML Viewer
on the desktop, open them in the \gui Welcome mode. To view the examples on
mobile devices, use the \gui {Qt Quick Application} wizard to convert them into
Qt Quick Applications.
To import QML applications:
\list 1

View File

@@ -183,6 +183,28 @@ void Link::populateImportedTypes(TypeEnvironment *typeEnv, Document::Ptr doc)
// explicit imports, whether directories, files or libraries
foreach (const ImportInfo &info, doc->bind()->imports()) {
ObjectValue *import = d->importCache.value(ImportCacheKey(info));
//### Hack: if this document is in a library, and if there is an qmldir file in the same directory, and if the prefix is an import-path, the import means to import everything in this library.
if (info.ast() && info.ast()->fileName && info.ast()->fileName->asString() == QLatin1String(".")) {
const QString importInfoName(info.name());
if (QFileInfo(QDir(importInfoName), QLatin1String("qmldir")).exists()) {
foreach (const QString &importPath, d->importPaths) {
if (importInfoName.startsWith(importPath)) {
// Got it.
const QString cleanPath = QFileInfo(importInfoName).canonicalFilePath();
const QString forcedPackageName = cleanPath.mid(importPath.size() + 1).replace('/', '.').replace('\\', '.');
import = importNonFile(doc, info, forcedPackageName);
if (import)
d->importCache.insert(ImportCacheKey(info), import);
break;
}
}
}
}
//### End of hack.
if (!import) {
switch (info.type()) {
case ImportInfo::FileImport:
@@ -245,12 +267,12 @@ ObjectValue *Link::importFileOrDirectory(Document::Ptr doc, const ImportInfo &im
import Qt 4.6 as Xxx
(import com.nokia.qt is the same as the ones above)
*/
ObjectValue *Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo)
ObjectValue *Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo, const QString &forcedPackageName)
{
Q_D(Link);
ObjectValue *import = new ObjectValue(engine());
const QString packageName = Bind::toString(importInfo.ast()->importUri, '.');
const QString packageName = forcedPackageName.isEmpty() ? Bind::toString(importInfo.ast()->importUri, '.') : forcedPackageName;
const ComponentVersion version = importInfo.version();
bool importFound = false;
@@ -277,7 +299,7 @@ ObjectValue *Link::importNonFile(Document::Ptr doc, const ImportInfo &importInfo
}
}
if (!importFound) {
if (!importFound && importInfo.ast()) {
error(doc, locationFromRange(importInfo.ast()->firstSourceLocation(),
importInfo.ast()->lastSourceLocation()),
tr("package not found"));

View File

@@ -71,7 +71,7 @@ private:
void populateImportedTypes(Interpreter::TypeEnvironment *typeEnv, Document::Ptr doc);
Interpreter::ObjectValue *importFileOrDirectory(Document::Ptr doc, const Interpreter::ImportInfo &importInfo);
Interpreter::ObjectValue *importNonFile(Document::Ptr doc, const Interpreter::ImportInfo &importInfo);
Interpreter::ObjectValue *importNonFile(Document::Ptr doc, const Interpreter::ImportInfo &importInfo, const QString &forcedPackageName = QString::null);
void importObject(Bind *bind, const QString &name, Interpreter::ObjectValue *object, NameId *targetNamespace);
bool importLibrary(Document::Ptr doc,

View File

@@ -1705,9 +1705,15 @@ QList<MimeType> MimeDatabasePrivate::readUserModifiedMimeTypes()
void MimeDatabasePrivate::writeUserModifiedMimeTypes(const QList<MimeType> &mimeTypes)
{
// Keep mime types modified which are already on file.
// Keep mime types modified which are already on file, unless they are part of the current set.
QSet<QString> currentMimeTypes;
foreach (const MimeType &mimeType, mimeTypes)
currentMimeTypes.insert(mimeType.type());
const QList<MimeType> &inFileMimeTypes = readUserModifiedMimeTypes();
QList<MimeType> allModifiedMimeTypes = mimeTypes;
allModifiedMimeTypes.append(readUserModifiedMimeTypes());
foreach (const MimeType &mimeType, inFileMimeTypes)
if (!currentMimeTypes.contains(mimeType.type()))
allModifiedMimeTypes.append(mimeType);
if (QFile::exists(kModifiedMimeTypesPath) || QDir().mkpath(kModifiedMimeTypesPath)) {
QFile file(kModifiedMimeTypesPath + kModifiedMimeTypesFile);

View File

@@ -204,7 +204,7 @@ void MimeTypeSettingsModel::updateKnownPatterns(const QStringList &oldPatterns,
}
}
// MimeTypeSettingsPagePrivate
// MimeTypeSettingsPrivate
class MimeTypeSettingsPrivate : public QObject
{
Q_OBJECT
@@ -231,6 +231,7 @@ public:
void editMagicHeaderRowData(const int row, const MagicData &data);
void updateMimeDatabase();
void resetState();
public slots:
void syncData(const QModelIndex &current, const QModelIndex &previous);
@@ -249,6 +250,7 @@ public:
int m_mimeForPatternSync;
int m_mimeForMagicSync;
bool m_reset;
bool m_persist;
QList<int> m_modifiedMimeTypes;
Ui::MimeTypeSettingsPage m_ui;
};
@@ -261,6 +263,7 @@ MimeTypeSettingsPrivate::MimeTypeSettingsPrivate()
, m_mimeForPatternSync(-1)
, m_mimeForMagicSync(-1)
, m_reset(false)
, m_persist(false)
{}
MimeTypeSettingsPrivate::~MimeTypeSettingsPrivate()
@@ -507,13 +510,16 @@ void MimeTypeSettingsPrivate::editMagicHeader()
void MimeTypeSettingsPrivate::updateMimeDatabase()
{
MimeDatabase *db = ICore::instance()->mimeDatabase();
if (m_modifiedMimeTypes.isEmpty())
return;
// For this case it is a better approach to simply use a list and to remove duplicates
// afterwards than to keep a more complex data structure like a hash table.
qSort(m_modifiedMimeTypes.begin(), m_modifiedMimeTypes.end());
m_modifiedMimeTypes.erase(std::unique(m_modifiedMimeTypes.begin(), m_modifiedMimeTypes.end()),
m_modifiedMimeTypes.end());
if (!m_modifiedMimeTypes.isEmpty()) {
MimeDatabase *db = ICore::instance()->mimeDatabase();
QList<MimeType> allModified;
foreach (int index, m_modifiedMimeTypes) {
const MimeType &mimeType = m_model->m_mimeTypes.at(index);
@@ -522,7 +528,14 @@ void MimeTypeSettingsPrivate::updateMimeDatabase()
allModified.append(mimeType);
}
db->writeUserModifiedMimeTypes(allModified);
}
}
void MimeTypeSettingsPrivate::resetState()
{
clearSyncData();
m_modifiedMimeTypes.clear();
m_reset = false;
m_persist = false;
}
void MimeTypeSettingsPrivate::resetMimeTypes()
@@ -581,9 +594,7 @@ QWidget *MimeTypeSettings::createPage(QWidget *parent)
void MimeTypeSettings::apply()
{
if (m_d->m_reset) {
ICore::instance()->mimeDatabase()->clearUserModifiedMimeTypes();
} else if (!m_d->m_modifiedMimeTypes.isEmpty()) {
if (!m_d->m_modifiedMimeTypes.isEmpty()) {
const QModelIndex &modelIndex =
m_d->m_ui.mimeTypesTableView->selectionModel()->currentIndex();
if (modelIndex.isValid()) {
@@ -592,12 +603,23 @@ void MimeTypeSettings::apply()
if (m_d->m_mimeForMagicSync == modelIndex.row())
m_d->syncMimeMagic();
}
m_d->updateMimeDatabase();
m_d->clearSyncData();
}
if (!m_d->m_persist)
m_d->m_persist = true;
}
void MimeTypeSettings::finish()
{}
{
if (m_d->m_persist) {
if (m_d->m_reset)
ICore::instance()->mimeDatabase()->clearUserModifiedMimeTypes();
else
m_d->updateMimeDatabase();
}
m_d->resetState();
}
} // Internal
} // Core

View File

@@ -21,7 +21,14 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QTableView" name="mimeTypesTableView"/>
<widget class="QTableView" name="mimeTypesTableView">
<property name="showGrid">
<bool>false</bool>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="resetButton">
@@ -85,6 +92,12 @@
<height>100</height>
</size>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
<column>
<property name="text">
<string>Magic Header</string>

View File

@@ -1661,8 +1661,7 @@ void GdbEngine::handleExecuteContinue(const GdbResponse &response)
return;
}
QByteArray msg = response.data.findChild("msg").data();
if (msg.startsWith("Cannot find bounds of current function")
|| msg.startsWith("\"finish\" not meaningful in the outermost frame")) {
if (msg.startsWith("Cannot find bounds of current function")) {
notifyInferiorRunFailed();
if (isDying())
return;
@@ -1671,9 +1670,14 @@ void GdbEngine::handleExecuteContinue(const GdbResponse &response)
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
showStatusMessage(tr("Stopped."), 5000);
reloadStack(true);
//showStatusMessage(tr("No debug information available. "
// "Leaving function..."));
//executeStepOut();
} else if (msg.startsWith("\"finish\" not meaningful in the outermost frame")) {
notifyInferiorRunFailed();
if (isDying())
return;
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
// FIXME: Fix translation in master.
showStatusMessage(QString::fromLocal8Bit(msg), 5000);
gotoLocation(stackHandler()->currentFrame());
} else {
showExecutionError(QString::fromLocal8Bit(msg));
notifyInferiorIll();

View File

@@ -83,9 +83,7 @@ FormEditorScene::~FormEditorScene()
void FormEditorScene::setupScene()
{
m_formLayerItem = new LayerItem(this);
qDebug() << "formLayerItem" << m_formLayerItem.data();
m_manipulatorLayerItem = new LayerItem(this);
qDebug() << "manipulatorLayerItem" << m_manipulatorLayerItem.data();
m_manipulatorLayerItem->setZValue(1.0);
m_formLayerItem->setZValue(0.0);
m_formLayerItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);

View File

@@ -81,7 +81,7 @@ void SiblingComboBox::setup()
//We currently have no instanceChildren().
//So we double check here if the instanceParents are equal.
foreach (const QmlItemNode &node, m_itemList)
if (node.instanceParent().modelNode() != m_itemNode.instanceParent().modelNode())
if (node.isValid() && (node.instanceParent().modelNode() != m_itemNode.instanceParent().modelNode()))
m_itemList.removeAll(node);
disconnect(this, SIGNAL(currentIndexChanged (int)), this, SLOT(changeSelection(int)));

View File

@@ -67,7 +67,7 @@ void NodeAbstractProperty::reparentHere(const ModelNode &modelNode)
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeAbstractProperty())
reparentHere(modelNode, isNodeListProperty());
else
reparentHere(modelNode, parentModelNode().metaInfo().propertyIsListProperty(name())); //we could use the metasystem instead?
reparentHere(modelNode, parentModelNode().metaInfo().propertyIsListProperty(name()) || isDefaultProperty()); //we could use the metasystem instead?
}
void NodeAbstractProperty::reparentHere(const ModelNode &modelNode, bool isNodeList)

View File

@@ -292,7 +292,7 @@ NodeInstance QmlModelView::instanceForModelNode(const ModelNode &modelNode)
bool QmlModelView::hasInstanceForModelNode(const ModelNode &modelNode)
{
return nodeInstanceView()->hasInstanceForNode(modelNode);
return nodeInstanceView() && nodeInstanceView()->hasInstanceForNode(modelNode);
}
void QmlModelView::modelAttached(Model *model)

View File

@@ -155,7 +155,7 @@ QList<QToolButton *> ItemLibrarySideBarItem::createToolBarWidgets()
void DocumentWarningWidget::goToError()
{
m_designModeWidget->textEditor()->gotoLine(m_error.line(), m_error.column());
m_designModeWidget->textEditor()->gotoLine(m_error.line(), m_error.column() - 1);
Core::ModeManager::instance()->activateMode(Core::Constants::MODE_EDIT);
}

View File

@@ -336,7 +336,7 @@ bool QMakeStep::isQmlDebuggingLibrarySupported(QString *reason) const
return false;
}
if (qt4BuildConfiguration()->qtVersion()->qtVersion() < QtVersionNumber(4, 7 ,0)) {
if (qt4BuildConfiguration()->qtVersion()->qtVersion() < QtVersionNumber(4, 7, 1)) {
if (reason)
*reason = tr("Requires Qt 4.7.1 or newer.");
return false;
@@ -449,6 +449,7 @@ void QMakeStepConfigWidget::qtVersionChanged()
{
updateSummaryLabel();
updateEffectiveQMakeCall();
updateQmlDebuggingWarningsLabel();
}
void QMakeStepConfigWidget::qmakeBuildConfigChanged()

View File

@@ -322,11 +322,13 @@ void S60DeployStep::stop()
void S60DeployStep::setupConnections()
{
if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection) {
if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection
|| m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection)
connect(SymbianUtils::SymbianDeviceManager::instance(), SIGNAL(deviceRemoved(SymbianUtils::SymbianDevice)),
this, SLOT(deviceRemoved(SymbianUtils::SymbianDevice)));
connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
if (m_channel == S60DeployConfiguration::CommunicationTrkSerialConnection) {
connect(m_launcher, SIGNAL(finished()), this, SLOT(launcherFinished()));
connect(m_launcher, SIGNAL(canNotConnect(QString)), this, SLOT(connectFailed(QString)));
connect(m_launcher, SIGNAL(copyingStarted(QString)), this, SLOT(printCopyingNotice(QString)));
connect(m_launcher, SIGNAL(canNotCreateFile(QString,QString)), this, SLOT(createFileFailed(QString,QString)));

View File

@@ -34,6 +34,12 @@
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
<property name="columnCount">
<number>3</number>
</property>

View File

@@ -50,6 +50,12 @@
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
</widget>
</item>
<item>

View File

@@ -909,6 +909,7 @@ ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProBlock(
case TokCondition:
if (!m_skipLevel && okey != or_op) {
if (curr.size() != 1) {
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Conditional must expand to exactly one word."));
okey = false;
} else {
@@ -922,6 +923,7 @@ ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProBlock(
case TokTestCall:
if (!m_skipLevel && okey != or_op) {
if (curr.size() != 1) {
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Test name must expand to exactly one word."));
skipExpression(tokPtr);
okey = false;
@@ -1067,6 +1069,7 @@ void ProFileEvaluator::Private::visitProVariable(
if (curr.size() != 1) {
skipExpression(tokPtr);
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
return;
}

View File

@@ -115,13 +115,7 @@ void ProFileParser::initialize()
}
ProFileParser::ProFileParser(ProFileCache *cache, ProFileParserHandler *handler)
: m_lineNo(0)
, m_state(StNew)
, m_markLine(0)
, m_canElse(false)
, m_invert(false)
, m_operator(NoOperator)
, m_cache(cache)
: m_cache(cache)
, m_handler(handler)
{
// So that single-threaded apps don't have to call initialize() for now.
@@ -241,7 +235,7 @@ void ProFileParser::finalizeHashStr(ushort *buf, uint len)
bool ProFileParser::read(ProFile *pro, const QString &in)
{
m_fileName = pro->fileName();
m_proFile = pro;
m_lineNo = 1;
// Final precompiled token stream buffer
@@ -275,7 +269,7 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
// Expression precompiler buffer.
QString xprBuff;
xprBuff.reserve(tokBuff.capacity()); // Excessive, but simple
ushort *buf = (ushort *)xprBuff.constData();
ushort * const buf = (ushort *)xprBuff.constData();
// Parser state
m_blockstack.clear();
@@ -292,15 +286,14 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
m_invert = false;
m_operator = NoOperator;
m_markLine = m_lineNo;
m_inError = false;
Context context = CtxTest;
int parens = 0; // Braces in value context
int argc = 0;
int litCount = 0;
int expCount = 0;
bool inError = false;
int wordCount = 0; // Number of words in currently accumulated expression
bool putSpace = false; // Only ever true inside quoted string
bool lineMarked = true; // For in-expression markers
ushort needSep = 0; // Complementary to putSpace: separator outside quotes
ushort needSep = TokNewStr; // Complementary to putSpace: separator outside quotes
ushort quote = 0;
ushort term = 0;
@@ -308,44 +301,53 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
ptr += 4;
ushort *xprPtr = ptr;
ushort *oldTokPtr = tokPtr;
#define FLUSH_LHS_LITERAL(setSep) \
#define FLUSH_LHS_LITERAL() \
do { \
if ((tlen = ptr - xprPtr)) { \
if (needSep) \
goto extraChars; \
finalizeHashStr(xprPtr, tlen); \
if (setSep) \
needSep = TokNewStr; \
if (needSep) { \
wordCount++; \
needSep = 0; \
} \
} else { \
ptr -= 4; \
if (setSep && ptr != buf) \
needSep = TokNewStr; \
} \
} while (0)
#define FLUSH_RHS_LITERAL(setSep) \
#define FLUSH_RHS_LITERAL() \
do { \
if ((tlen = ptr - xprPtr)) { \
xprPtr[-2] = TokLiteral | needSep; \
xprPtr[-1] = tlen; \
if (setSep) \
needSep = TokNewStr; \
litCount++; \
if (needSep) { \
wordCount++; \
needSep = 0; \
} \
} else { \
ptr -= 2; \
if (setSep && ptr != ((context == CtxValue) ? tokPtr : buf)) \
needSep = TokNewStr; \
} \
} while (0)
#define FLUSH_LITERAL(setSep) \
#define FLUSH_LITERAL() \
do { \
if (context == CtxTest) \
FLUSH_LHS_LITERAL(setSep); \
FLUSH_LHS_LITERAL(); \
else \
FLUSH_RHS_LITERAL(setSep); \
FLUSH_RHS_LITERAL(); \
} while (0)
#define FLUSH_VALUE_LIST() \
do { \
if (wordCount > 1) { \
xprPtr = tokPtr; \
if (*xprPtr == TokLine) \
xprPtr += 2; \
tokPtr[-1] = ((*xprPtr & TokMask) == TokLiteral) ? wordCount : 0; \
} else { \
tokPtr[-1] = 0; \
} \
tokPtr = ptr; \
putTok(tokPtr, TokValueTerminator); \
} while (0)
forever {
@@ -356,14 +358,9 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
c = *cur;
if (c == '\n') {
++cur;
if (!inError)
goto flushLine;
++m_lineNo;
goto freshLine;
} else if (!c) {
if (!inError)
goto flushLine;
goto flushFile;
} else if (c != ' ' && c != '\t' && c != '\r') {
break;
}
@@ -417,11 +414,10 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
--end;
}
if (!inError) {
// Finally, do the tokenization
ushort tok, rtok;
int tlen;
newToken:
newWord:
do {
if (cur == end)
goto lineEnd;
@@ -435,27 +431,7 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
putSpace = false;
*ptr++ = ' ';
}
tlen = ptr - xprPtr;
if (context == CtxTest) {
if (needSep) {
extraChars:
parseError(fL1S("Extra characters after test expression."));
goto parseErr;
}
if (tlen)
finalizeHashStr(xprPtr, tlen);
else
ptr -= 4;
} else {
if (tlen) {
xprPtr[-2] = TokLiteral | needSep;
xprPtr[-1] = tlen;
needSep = 0;
litCount++;
} else {
ptr -= 2;
}
}
FLUSH_LITERAL();
if (!lineMarked) {
lineMarked = true;
*ptr++ = TokLine;
@@ -499,9 +475,10 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
notfunc:
if (quote)
tok |= TokQuoted;
if (needSep) {
tok |= needSep;
needSep = 0;
expCount++;
wordCount++;
}
tlen = ptr - xprPtr;
if (rtok == TokVariable) {
xprPtr[-4] = tok;
@@ -523,8 +500,7 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
top.terminator = term;
top.context = context;
top.argc = argc;
top.litCount = litCount;
top.expCount = expCount;
top.wordCount = wordCount;
}
parens = 0;
quote = 0;
@@ -532,9 +508,12 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
argc = 1;
context = CtxArgs;
nextToken:
wordCount = 0;
nextWord:
ptr += (context == CtxTest) ? 4 : 2;
xprPtr = ptr;
goto newToken;
needSep = TokNewStr;
goto newWord;
}
if (term) {
cur++;
@@ -543,17 +522,17 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
parseError(fL1S("Missing %1 terminator [found %2]")
.arg(QChar(term))
.arg(c ? QString(c) : QString::fromLatin1("end-of-line")));
parseErr:
pro->setOk(false);
xprStack.resize(0);
tokPtr = oldTokPtr;
inError = true;
goto skip;
m_inError = true;
if (c)
cur--;
// Just parse on, as if there was a terminator ...
}
}
joinToken:
ptr += (context == CtxTest) ? 4 : 2;
xprPtr = ptr;
needSep = 0;
goto nextChr;
}
} else if (c == '\\' && cur != end) {
@@ -582,15 +561,15 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
quote = c;
goto nextChr;
} else if (c == ' ' || c == '\t') {
FLUSH_LITERAL(true);
goto nextToken;
FLUSH_LITERAL();
goto nextWord;
} else if (context == CtxArgs) {
// Function arg context
if (c == '(') {
++parens;
} else if (c == ')') {
if (--parens < 0) {
FLUSH_RHS_LITERAL(false);
FLUSH_RHS_LITERAL();
*ptr++ = TokFuncTerminator;
int theargc = argc;
{
@@ -600,74 +579,71 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
term = top.terminator;
context = top.context;
argc = top.argc;
litCount = top.litCount;
expCount = top.expCount;
wordCount = top.wordCount;
xprStack.resize(xprStack.size() - 1);
}
if (term == ':') {
finalizeCall(tokPtr, buf, ptr, theargc);
needSep = TokNewStr;
goto nextItem;
} else if (term == '}') {
c = (cur == end) ? 0 : *cur++;
needSep = 0;
goto checkTerm;
} else {
Q_ASSERT(!term);
needSep = 0;
goto joinToken;
}
}
} else if (!parens && c == ',') {
FLUSH_RHS_LITERAL(false);
FLUSH_RHS_LITERAL();
*ptr++ = TokArgSeparator;
argc++;
needSep = 0;
goto nextToken;
}
} else if (context == CtxTest) {
// Test or LHS context
if (c == '(') {
FLUSH_LHS_LITERAL(false);
if (ptr == buf) {
FLUSH_LHS_LITERAL();
if (wordCount != 1) {
if (wordCount)
parseError(fL1S("Extra characters after test expression."));
else
parseError(fL1S("Opening parenthesis without prior test name."));
goto parseErr;
pro->setOk(false);
ptr = buf; // Put empty function name
}
*ptr++ = TokTestCall;
term = ':';
needSep = 0;
goto funcCall;
} else if (c == '!' && ptr == xprPtr) {
m_invert ^= true;
goto nextChr;
} else if (c == ':') {
FLUSH_LHS_LITERAL(false);
finalizeCond(tokPtr, buf, ptr);
FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount);
if (m_state == StNew)
parseError(fL1S("And operator without prior condition."));
else
m_operator = AndOperator;
nextItem:
ptr = buf;
needSep = 0;
goto nextToken;
} else if (c == '|') {
FLUSH_LHS_LITERAL(false);
finalizeCond(tokPtr, buf, ptr);
FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount);
if (m_state != StCond)
parseError(fL1S("Or operator without prior condition."));
else
m_operator = OrOperator;
goto nextItem;
} else if (c == '{') {
FLUSH_LHS_LITERAL(false);
finalizeCond(tokPtr, buf, ptr);
FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount);
flushCond(tokPtr);
++m_blockstack.top().braceLevel;
goto nextItem;
} else if (c == '}') {
FLUSH_LHS_LITERAL(false);
finalizeCond(tokPtr, buf, ptr);
FLUSH_LHS_LITERAL();
finalizeCond(tokPtr, buf, ptr, wordCount);
flushScopes(tokPtr);
closeScope:
if (!m_blockstack.top().braceLevel) {
@@ -699,19 +675,19 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
} else if (c == '=') {
tok = TokAssign;
doOp:
FLUSH_LHS_LITERAL(false);
FLUSH_LHS_LITERAL();
flushCond(tokPtr);
putLineMarker(tokPtr);
if (!(tlen = ptr - buf)) {
parseError(fL1S("Assignment operator without prior variable name."));
goto parseErr;
if (wordCount != 1) {
parseError(fL1S("Assignment needs exactly one word on the left hand side."));
pro->setOk(false);
// Put empty variable name.
} else {
putBlock(tokPtr, buf, ptr - buf);
}
putBlock(tokPtr, buf, tlen);
putTok(tokPtr, tok);
context = CtxValue;
ptr = ++tokPtr;
litCount = expCount = 0;
needSep = 0;
goto nextToken;
}
} else { // context == CtxValue
@@ -719,10 +695,8 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
++parens;
} else if (c == '}') {
if (!parens) {
FLUSH_RHS_LITERAL(false);
tokPtr[-1] = litCount ? litCount + expCount : 0;
tokPtr = ptr;
putTok(tokPtr, TokValueTerminator);
FLUSH_RHS_LITERAL();
FLUSH_VALUE_LIST();
context = CtxTest;
goto closeScope;
}
@@ -745,7 +719,8 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
if (quote) {
putSpace = true;
} else {
FLUSH_LITERAL(true);
FLUSH_LITERAL();
needSep = TokNewStr;
ptr += (context == CtxTest) ? 4 : 2;
xprPtr = ptr;
}
@@ -753,29 +728,37 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
c = '\n';
cur = cptr;
flushLine:
FLUSH_LITERAL(false);
FLUSH_LITERAL();
if (quote) {
parseError(fL1S("Missing closing %1 quote").arg(QChar(quote)));
goto parseErr;
}
if (!xprStack.isEmpty()) {
parseError(fL1S("Missing closing parenthesis in function call"));
goto parseErr;
context = xprStack.at(0).context;
xprStack.clear();
}
goto flErr;
} else if (!xprStack.isEmpty()) {
parseError(fL1S("Missing closing parenthesis in function call"));
context = xprStack.at(0).context;
xprStack.clear();
flErr:
pro->setOk(false);
if (context == CtxValue) {
tokPtr[-1] = litCount ? litCount + expCount : 0;
tokPtr = ptr;
tokPtr[-1] = 0; // sizehint
putTok(tokPtr, TokValueTerminator);
} else {
finalizeCond(tokPtr, buf, ptr);
bogusTest(tokPtr);
}
} else if (context == CtxValue) {
FLUSH_VALUE_LIST();
} else {
finalizeCond(tokPtr, buf, ptr, wordCount);
}
if (!c)
break;
++m_lineNo;
goto freshLine;
}
} // !inError
skip:
if (!lineCont) {
cur = cptr;
++m_lineNo;
@@ -787,7 +770,6 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
++m_lineNo;
}
flushFile:
flushScopes(tokPtr);
if (m_blockstack.size() > 1) {
parseError(fL1S("Missing closing brace(s)."));
@@ -799,6 +781,7 @@ bool ProFileParser::read(ProFile *pro, const QString &in)
*pro->itemsRef() = QString(tokBuff.constData(), tokPtr - (ushort *)tokBuff.constData());
return true;
#undef FLUSH_VALUE_LIST
#undef FLUSH_LITERAL
#undef FLUSH_LHS_LITERAL
#undef FLUSH_RHS_LITERAL
@@ -883,10 +866,25 @@ void ProFileParser::finalizeTest(ushort *&tokPtr)
m_canElse = true;
}
void ProFileParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr)
void ProFileParser::bogusTest(ushort *&tokPtr)
{
if (ptr == uc)
flushScopes(tokPtr);
m_operator = NoOperator;
m_invert = false;
m_state = StCond;
m_canElse = true;
m_proFile->setOk(false);
}
void ProFileParser::finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount)
{
if (wordCount != 1) {
if (wordCount) {
parseError(fL1S("Extra characters after test expression."));
bogusTest(tokPtr);
}
return;
}
// Check for magic tokens
if (*uc == TokHashLiteral) {
@@ -950,7 +948,7 @@ void ProFileParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int a
parseError(fL1S("Unexpected operator in front of for()."));
return;
}
if (*uce == TokLiteral) {
if (*uce == (TokLiteral|TokNewStr)) {
nlen = uce[1];
uc = uce + 2 + nlen;
if (*uc == TokFuncTerminator) {
@@ -998,7 +996,7 @@ void ProFileParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int a
parseError(fL1S("Unexpected operator in front of function definition."));
return;
}
if (*uce == TokLiteral) {
if (*uce == (TokLiteral|TokNewStr)) {
uint nlen = uce[1];
if (uce[nlen + 2] == TokFuncTerminator) {
if (m_operator != NoOperator) {
@@ -1024,8 +1022,8 @@ void ProFileParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int a
void ProFileParser::parseError(const QString &msg) const
{
if (m_handler)
m_handler->parseError(m_fileName, m_lineNo, msg);
if (!m_inError && m_handler)
m_handler->parseError(m_proFile->fileName(), m_lineNo, msg);
}
QT_END_NAMESPACE

View File

@@ -81,9 +81,7 @@ public:
private:
struct BlockScope {
BlockScope() : start(0), braceLevel(0), special(false), inBranch(false) {}
BlockScope(BlockScope &other) :
start(other.start), braceLevel(other.braceLevel),
special(other.special), inBranch(other.inBranch) {}
BlockScope(const BlockScope &other) { *this = other; }
ushort *start; // Where this block started; store length here
int braceLevel; // Nesting of braces in scope
bool special; // Single-line conditionals inside loops, etc. cannot have else branches
@@ -100,8 +98,7 @@ private:
struct ParseCtx {
int parens; // Nesting of non-functional parentheses
int argc; // Number of arguments in current function call
int litCount; // Number of literals in current expression
int expCount; // Number of expansions in current expression
int wordCount; // Number of words in current expression
Context context;
ushort quote; // Enclosing quote type
ushort terminator; // '}' if replace function call is braced, ':' if test function
@@ -116,9 +113,10 @@ private:
void putHashStr(ushort *&pTokPtr, const ushort *buf, uint len);
void finalizeHashStr(ushort *buf, uint len);
void putLineMarker(ushort *&tokPtr);
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr);
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
void finalizeTest(ushort *&tokPtr);
void bogusTest(ushort *&tokPtr);
void enterScope(ushort *&tokPtr, bool special, ScopeState state);
void leaveScope(ushort *&tokPtr);
void flushCond(ushort *&tokPtr);
@@ -127,12 +125,13 @@ private:
void parseError(const QString &msg) const;
// Current location
QString m_fileName;
ProFile *m_proFile;
int m_lineNo;
QStack<BlockScope> m_blockstack;
ScopeState m_state;
int m_markLine; // Put marker for this line
bool m_inError; // Current line had a parsing error; suppress followup error messages
bool m_canElse; // Conditionals met on previous line, but no scope was opened
bool m_invert; // Pending conditional is negated
enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed

View File

@@ -169,6 +169,7 @@ int main(int argc, char **argv)
} props[] = {
{ "QT_INSTALL_DATA", QLibraryInfo::DataPath },
{ "QT_INSTALL_LIBS", QLibraryInfo::LibrariesPath },
{ "QT_INSTALL_IMPORTS", QLibraryInfo::ImportsPath },
{ "QT_INSTALL_HEADERS", QLibraryInfo::HeadersPath },
{ "QT_INSTALL_DEMOS", QLibraryInfo::DemosPath },
{ "QT_INSTALL_EXAMPLES", QLibraryInfo::ExamplesPath },