diff options
112 files changed, 7035 insertions, 5022 deletions
diff --git a/demos/declarative/flickr/content/Star.qml b/demos/declarative/flickr/content/Star.qml index 2c2807a..0828bc0 100644 --- a/demos/declarative/flickr/content/Star.qml +++ b/demos/declarative/flickr/content/Star.qml @@ -3,8 +3,8 @@ Item { width: 24 height: 24 - property string rating - property string on + property int rating + property bool on signal clicked diff --git a/demos/declarative/samegame/README b/demos/declarative/samegame/README new file mode 100644 index 0000000..244b205 --- /dev/null +++ b/demos/declarative/samegame/README @@ -0,0 +1,10 @@ +This demo uses pictures from the KDE project (www.kde.org), +specifically the images from the KSame game. These images are + +background.png +blueStone.png +redStone.png +greenStone.png +yellowStone.png + +and are presumably under the same GPL2 license as the rest of kdegames diff --git a/demos/declarative/samegame/SameGame.qml b/demos/declarative/samegame/SameGame.qml new file mode 100644 index 0000000..c929c91 --- /dev/null +++ b/demos/declarative/samegame/SameGame.qml @@ -0,0 +1,41 @@ +import "content" + +Rect { + width: 460 + height: 700 + color: "white" + Script { source: "content/samegame.js" } + Rect{ + property int score: 0 + y:20; width:400; height:600; id: gameCanvas; + //For Fixed Size + anchors.horizontalCenter: parent.horizontalCenter + //For flexible width + //anchors.left: parent.left; anchors.leftMargin: 30 + //anchors.right: parent.right; anchors.rightMargin: 30 + color: "white" + pen.width: 1 + Image { id:background; + source: "content/pics/background.png" + anchors.fill: parent + } + + MouseRegion { id: gameMR; anchors.fill: parent; + onClicked: handleClick(mouseX, mouseY); + } + } + HorizontalLayout { + anchors.top: gameCanvas.bottom + anchors.topMargin: 10 + anchors.horizontalCenter: parent.horizontalCenter + MediaButton { id: btnA; text: "New Game"; onClicked: {initBoard();} } + MediaButton { id: btnB; text: "Swap Theme"; onClicked: {swapTileSrc(); dialog.opacity = 1;} + } + Text{ text: "Score: " + gameCanvas.score; width:100 } + } + SameDialog { + id: dialog + anchors.centeredIn: parent + text: "Takes effect next game." + } +} diff --git a/demos/declarative/samegame/TODO b/demos/declarative/samegame/TODO new file mode 100644 index 0000000..b02ce54 --- /dev/null +++ b/demos/declarative/samegame/TODO @@ -0,0 +1,5 @@ +Still to do before initial release +-Garbage collect on click +-Particles with count 0->50 should work properly +-Particles are too slow to start +-Everything is too slow, we should have four times the number of tiles there diff --git a/demos/declarative/samegame/content/BoomBlock.qml b/demos/declarative/samegame/content/BoomBlock.qml new file mode 100644 index 0000000..0d05772 --- /dev/null +++ b/demos/declarative/samegame/content/BoomBlock.qml @@ -0,0 +1,50 @@ +Item { id:block + property bool dying: false + property bool spawning: false + property int type: 0 + property int targetX: 0 + property int targetY: 0 + + x: Follow { source: targetX; spring: 1.2; damping: 0.1 } + y: Follow { source: targetY; spring: 1.2; damping: 0.1 } + + Image { id: img + source: { + if(type == 0){ + "pics/redStone.png"; + } else if(type == 1) { + "pics/blueStone.png"; + } else { + "pics/greenStone.png"; + } + } + opacity: 0 + opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } + anchors.fill: parent + } + Particles { id: particles + width:1; height:1; anchors.centeredIn: parent; opacity: 0 + lifeSpan: 1000000000; count:0; streamIn: false + angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30 + source: { + if(type == 0){ + "pics/redStar.png"; + } else if (type == 1) { + "pics/blueStar.png"; + } else { + "pics/greenStar.png"; + } + } + } + states: [ + + State{ name: "AliveState"; when: spawning == true && dying == false + SetProperties { target: img; opacity: 1 } + }, + State{ name: "DeathState"; when: dying == true + SetProperties { target: particles; count: 50 } + SetProperties { target: particles; opacity: 1 } + SetProperties { target: img; opacity: 0 } + } + ] +} diff --git a/demos/declarative/samegame/content/FastBlock.qml b/demos/declarative/samegame/content/FastBlock.qml new file mode 100644 index 0000000..04eb59b --- /dev/null +++ b/demos/declarative/samegame/content/FastBlock.qml @@ -0,0 +1,27 @@ +Rect { id:block + //Note: These properties are the interface used to control the blocks + property bool dying: false + property bool spawning: false + property int type: 0 + property int targetY: 0 + property int targetX: 0 + + color: {if(type==0){"red";}else if(type==1){"blue";}else{"green";}} + pen.width: 1 + pen.color: "black" + opacity: 0 + y: targetY + x: targetX + y: Behavior { NumberAnimation { properties:"y"; duration: 200 } } + opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } + + states: [ + + State{ name: "SpawnState"; when: spawning == true && dying == false + SetProperties { target: block; opacity: 1 } + }, + State{ name: "DeathState"; when: dying == true + SetProperties { target: block; opacity: 0 } + } + ] +} diff --git a/demos/declarative/samegame/content/MediaButton.qml b/demos/declarative/samegame/content/MediaButton.qml new file mode 100644 index 0000000..49922f0 --- /dev/null +++ b/demos/declarative/samegame/content/MediaButton.qml @@ -0,0 +1,39 @@ +Item { + id: Container + + signal clicked + + property string text + + Image { + id: Image + source: "pics/button.png" + } + Image { + id: Pressed + source: "pics/button-pressed.png" + opacity: 0 + } + MouseRegion { + id: MouseRegion + anchors.fill: Image + onClicked: { Container.clicked(); } + } + Text { + font.bold: true + color: "white" + anchors.centeredIn: Image + text: Container.text + } + width: Image.width + states: [ + State { + name: "Pressed" + when: MouseRegion.pressed == true + SetProperties { + target: Pressed + opacity: 1 + } + } + ] +} diff --git a/demos/declarative/samegame/content/SameDialog.qml b/demos/declarative/samegame/content/SameDialog.qml new file mode 100644 index 0000000..eed52f0 --- /dev/null +++ b/demos/declarative/samegame/content/SameDialog.qml @@ -0,0 +1,17 @@ +Rect { + property string text: "Hello World!" + property int show: 0 + id: page + opacity: 0 + opacity: Behavior { + SequentialAnimation { + NumberAnimation {property: "opacity"; duration: 1000 } + NumberAnimation {property: "opacity"; to: 0; duration: 1000 } + } + } + color: "white" + pen.width: 1 + width: 200 + height: 60 + Text { anchors.centeredIn: parent; text: parent.text } +} diff --git a/demos/declarative/samegame/content/pics/background.png b/demos/declarative/samegame/content/pics/background.png Binary files differnew file mode 100644 index 0000000..25e885f --- /dev/null +++ b/demos/declarative/samegame/content/pics/background.png diff --git a/demos/declarative/samegame/content/pics/blueStar.png b/demos/declarative/samegame/content/pics/blueStar.png Binary files differnew file mode 100644 index 0000000..822dc53 --- /dev/null +++ b/demos/declarative/samegame/content/pics/blueStar.png diff --git a/demos/declarative/samegame/content/pics/blueStone.png b/demos/declarative/samegame/content/pics/blueStone.png Binary files differnew file mode 100644 index 0000000..673f1ce --- /dev/null +++ b/demos/declarative/samegame/content/pics/blueStone.png diff --git a/demos/declarative/samegame/content/pics/button-pressed.png b/demos/declarative/samegame/content/pics/button-pressed.png Binary files differnew file mode 100644 index 0000000..e434d32 --- /dev/null +++ b/demos/declarative/samegame/content/pics/button-pressed.png diff --git a/demos/declarative/samegame/content/pics/button.png b/demos/declarative/samegame/content/pics/button.png Binary files differnew file mode 100644 index 0000000..56a63ce --- /dev/null +++ b/demos/declarative/samegame/content/pics/button.png diff --git a/demos/declarative/samegame/content/pics/greenStar.png b/demos/declarative/samegame/content/pics/greenStar.png Binary files differnew file mode 100644 index 0000000..1abbcf0 --- /dev/null +++ b/demos/declarative/samegame/content/pics/greenStar.png diff --git a/demos/declarative/samegame/content/pics/greenStone.png b/demos/declarative/samegame/content/pics/greenStone.png Binary files differnew file mode 100644 index 0000000..0c087d0 --- /dev/null +++ b/demos/declarative/samegame/content/pics/greenStone.png diff --git a/demos/declarative/samegame/content/pics/qtlogo.png b/demos/declarative/samegame/content/pics/qtlogo.png Binary files differnew file mode 100644 index 0000000..399bd0b --- /dev/null +++ b/demos/declarative/samegame/content/pics/qtlogo.png diff --git a/demos/declarative/samegame/content/pics/redStar.png b/demos/declarative/samegame/content/pics/redStar.png Binary files differnew file mode 100644 index 0000000..b18834f --- /dev/null +++ b/demos/declarative/samegame/content/pics/redStar.png diff --git a/demos/declarative/samegame/content/pics/redStone.png b/demos/declarative/samegame/content/pics/redStone.png Binary files differnew file mode 100644 index 0000000..80c2e2e --- /dev/null +++ b/demos/declarative/samegame/content/pics/redStone.png diff --git a/demos/declarative/samegame/content/pics/star.png b/demos/declarative/samegame/content/pics/star.png Binary files differnew file mode 100644 index 0000000..defbde5 --- /dev/null +++ b/demos/declarative/samegame/content/pics/star.png diff --git a/demos/declarative/samegame/content/pics/yellowStone.png b/demos/declarative/samegame/content/pics/yellowStone.png Binary files differnew file mode 100644 index 0000000..5349eff --- /dev/null +++ b/demos/declarative/samegame/content/pics/yellowStone.png diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js new file mode 100644 index 0000000..fe5ac87 --- /dev/null +++ b/demos/declarative/samegame/content/samegame.js @@ -0,0 +1,214 @@ +/* This script file handles the game logic */ + +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; +var tileSize = 40; +var maxIndex = maxX*maxY; +var board = new Array(maxIndex); +var tileSrc = "content/BoomBlock.qml"; +var backSrc = "content/pics/background.png"; +var swapped = false; + +var compSrc; +var component; + +function swapTileSrc(){ + if(swapped) + return; + if(tileSrc == "content/FastBlock.qml"){ + tileSrc = "content/BoomBlock.qml"; + backSrc = "content/pics/background.png"; + }else{ + backSrc = "content/pics/qtlogo.png"; + tileSrc = "content/FastBlock.qml"; + } + swapped = true; +} + +function index(xIdx,yIdx){ + return xIdx + (yIdx * maxX); +} + +function initBoard() +{ + for(i = 0; i<maxIndex; i++){ + //Delete old blocks + if(board[i] != null) + board[i].destroy(); + } + + background.source = backSrc; + swapped = false; + maxX = Math.floor(gameCanvas.width/tileSize); + maxY = Math.floor(gameCanvas.height/tileSize); + maxIndex = maxX*maxY; + board = new Array(maxIndex); + gameCanvas.score = 0; + + for(xIdx=0; xIdx<maxX; xIdx++){ + for(yIdx=0; yIdx<maxY; yIdx++){ + board[index(xIdx,yIdx)] = null; + startCreatingBlock(xIdx,yIdx); + } + } + //TODO: a flag that handleMouse uses to ignore clicks when we're loading +} + +var removed; +var floodBoard; +function handleClick(x,y) +{ + //NOTE: Be careful with vars named x,y - they can set to the calling object? + xIdx = Math.floor(x/tileSize); + yIdx = Math.floor(y/tileSize); + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + removed = 0; + floodBoard = new Array(maxIndex); + floodKill(xIdx,yIdx, -1); + if(removed <= 0) + return; + gameCanvas.score += (removed - 1) * (removed - 1); + shuffleDown(); + victoryCheck(); +} + +function floodKill(xIdx,yIdx,type) +{ + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(floodBoard[index(xIdx, yIdx)] == 1) + return; + if(board[index(xIdx, yIdx)] == null) + return; + var first = false; + if(type == -1){ + type = board[index(xIdx,yIdx)].type; + first = true; + }else{ + if(type != board[index(xIdx,yIdx)].type) + return; + } + floodBoard[index(xIdx, yIdx)] = 1; + floodKill(xIdx+1,yIdx,type); + floodKill(xIdx-1,yIdx,type); + floodKill(xIdx,yIdx+1,type); + floodKill(xIdx,yIdx-1,type); + if(first==true && removed == 0){ + //TODO: Provide a way to inform the delegate + return;//Can't remove single tiles + } + board[index(xIdx,yIdx)].dying = true; + board[index(xIdx,yIdx)] = null;//They'll have to destroy themselves(can we do that?) + removed += 1; +} + +function shuffleDown() +{ + //Fall down + for(xIdx=0; xIdx<maxX; xIdx++){ + fallDist = 0; + for(yIdx=maxY-1; yIdx>=0; yIdx--){ + if(board[index(xIdx,yIdx)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + obj = board[index(xIdx,yIdx)]; + obj.targetY += fallDist * tileSize; + board[index(xIdx,yIdx+fallDist)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } + //Fall to the left + fallDist = 0; + for(xIdx=0; xIdx<maxX; xIdx++){ + if(board[index(xIdx, maxY - 1)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + for(yIdx=0; yIdx<maxY; yIdx++){ + obj = board[index(xIdx,yIdx)]; + if(obj == null) + continue; + obj.targetX -= fallDist * tileSize; + board[index(xIdx-fallDist,yIdx)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } +} + +function victoryCheck() +{ + //Only awards bonuses at the moment + deservesBonus = true; + for(xIdx=maxX-1; xIdx>=0; xIdx--) + if(board[index(xIdx, maxY - 1)] != null) + deservesBonus = false; + if(deservesBonus) + gameCanvas.score += 250; +} + +//Need a simpler method of doing this? +var waitStack = new Array(maxIndex); +var waitTop = -1; + +function finishCreatingBlock(xIdx,yIdx){ + //TODO: Doc that the 'x', 'y' that were here are hidden properties from the calling QFxItem + if(component.isReady()){ + if(xIdx == undefined){ + //Called without arguments, create a previously stored (xIdx,yIdx) + if(waitTop == -1) + return;//Don't have a previously stored (xIdx,yIdx) + xIdx = waitStack[waitTop] % maxX; + yIdx = Math.floor(waitStack[waitTop] / maxX); + waitTop -= 1; + } + dynamicObject = component.createObject(); + if(dynamicObject == null){ + print("error creating block"); + print(component.errorsString()); + return false; + } + dynamicObject.type = Math.floor(Math.random() * 3); + dynamicObject.parent = gameCanvas; + dynamicObject.targetX = xIdx*tileSize; + dynamicObject.targetY = yIdx*tileSize; + dynamicObject.width = tileSize; + dynamicObject.height = tileSize; + dynamicObject.spawning = true; + board[index(xIdx,yIdx)] = dynamicObject; + return true; + }else if(component.isError()){ + print("error creating block"); + print(component.errorsString()); + }else{ + //It isn't ready, but we'll be called again when it is. + //So store the requested (xIdx,yIdx) for later use + waitTop += 1; + waitStack[waitTop] = index(xIdx,yIdx); + } + return false; +} + +function startCreatingBlock(xIdx,yIdx){ + if(component!=null && compSrc == tileSrc){ + finishCreatingBlock(xIdx,yIdx); + return; + } + + if(component!=null){//Changed source + //delete component; //Does the engine handle this? + compSrc = tileSrc; + } + component = createComponent(tileSrc); + if(finishCreatingBlock(xIdx,yIdx)) + return; + component.statusChanged.connect(finishCreatingBlock()); + return; +} diff --git a/examples/declarative/loader/Browser.qml b/examples/declarative/loader/Browser.qml index 280273b..aec373b 100644 --- a/examples/declarative/loader/Browser.qml +++ b/examples/declarative/loader/Browser.qml @@ -2,6 +2,7 @@ Rect { id: Root width: parent.width height: parent.height + color: activePalette.base FolderListModel { id: folders nameFilters: [ "*.qml" ] @@ -13,12 +14,26 @@ Rect { Rect { id: Wrapper width: Root.width - height: NameText.height + height: 32 + color: activePalette.base + Rect { + id: Highlight; visible: false + anchors.fill: parent + gradient: Gradient { + GradientStop { id: t1; position: 0.0; color: activePalette.highlight } + GradientStop { id: t2; position: 1.0; color: activePalette.lighter(activePalette.highlight) } + } + } + Item { + width: 32; height: 32 + Image { source: "images/fileopen.png"; anchors.centeredIn: parent; visible: folders.isFolder(index)} + } Text { id: NameText - text: fileName - font.bold: true - font.size: 12 + anchors.fill: parent; vAlign: "AlignVCenter" + text: fileName; anchors.leftMargin: 32 + font.size: 10 + color: activePalette.windowText } MouseRegion { id: Mouse @@ -35,7 +50,8 @@ Rect { State { name: "pressed" when: Mouse.pressed - SetProperties { target: Wrapper; color: "#bbbbbb" } + SetProperties { target: Highlight; visible: true } + SetProperties { target: NameText; color: activePalette.highlightedText } } ] } @@ -48,19 +64,8 @@ Rect { } } - Rect { - id: UpButton - width: 30 - height: UpText.height - color: "grey" - MouseRegion { anchors.fill: parent; onClicked: folders.folder = up(folders.folder) } - Text { id: UpText; text: "Up" } - } - - Text { anchors.left: UpButton.right; text: folders.folder } - ListView { - anchors.top: UpButton.bottom + anchors.top: TitleBar.bottom anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom @@ -68,4 +73,27 @@ Rect { delegate: FolderDelegate clip: true } + + Rect { + id: TitleBar + width: parent.width + height: 32 + color: activePalette.button; pen.color: activePalette.mid + + Rect { + id: UpButton + width: 30 + height: TitleBar.height + pen.color: activePalette.mid; color: "transparent" + MouseRegion { anchors.fill: parent; onClicked: folders.folder = up(folders.folder) } + Image { anchors.centeredIn: parent; source: "images/up.png" } + } + + Text { + anchors.left: UpButton.right; anchors.right: parent.right; height: parent.height + anchors.leftMargin: 4; anchors.rightMargin: 4 + text: folders.folder; color: activePalette.buttonText + elide: "ElideLeft"; hAlign: "AlignRight"; vAlign: "AlignVCenter" + } + } } diff --git a/examples/declarative/loader/images/fileopen.png b/examples/declarative/loader/images/fileopen.png Binary files differnew file mode 100644 index 0000000..4aaf149 --- /dev/null +++ b/examples/declarative/loader/images/fileopen.png diff --git a/examples/declarative/loader/images/up.png b/examples/declarative/loader/images/up.png Binary files differnew file mode 100644 index 0000000..b05f802 --- /dev/null +++ b/examples/declarative/loader/images/up.png diff --git a/examples/declarative/loader/loader.qrc b/examples/declarative/loader/loader.qrc index 1f0925f..bdbcd5c 100644 --- a/examples/declarative/loader/loader.qrc +++ b/examples/declarative/loader/loader.qrc @@ -2,5 +2,7 @@ <qresource prefix="/"> <file>loader.qml</file> <file>Browser.qml</file> + <file>images/fileopen.png</file> + <file>images/up.png</file> </qresource> </RCC> diff --git a/examples/declarative/loader/main.cpp b/examples/declarative/loader/main.cpp index 23125ce..aa86f8f 100644 --- a/examples/declarative/loader/main.cpp +++ b/examples/declarative/loader/main.cpp @@ -5,6 +5,7 @@ #include <QmlContext> #include <QmlComponent> #include <qfxview.h> +#include "qmlpalette.h" QFxView *canvas = 0; @@ -61,6 +62,7 @@ int main(int argc, char *argv[]) canvas = new QFxView; QmlContext *ctxt = canvas->rootContext(); ctxt->setContextProperty("qmlLauncher", launcher); + ctxt->setContextProperty("activePalette", new QmlPalette); canvas->setUrl(QUrl("qrc:/loader.qml")); canvas->execute(); canvas->show(); diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp index 8775c5c..e6817fe 100644 --- a/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1167,8 +1167,10 @@ static QByteArray buildParameterNames // Build a QMetaObject in "buf" based on the information in "d". // If "buf" is null, then return the number of bytes needed to -// build the QMetaObject. -static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) +// build the QMetaObject. Returns -1 if the metaobject if +// relocatable is set, but the metaobject contains extradata. +static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf, + bool relocatable) { int size = 0; int dataIndex; @@ -1176,18 +1178,23 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) int index; bool hasNotifySignals = false; + if (relocatable && + (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction)) + return -1; + // Create the main QMetaObject structure at the start of the buffer. QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf); size += sizeof(QMetaObject); ALIGN(size, int); if (buf) { - meta->d.superdata = d->superClass; + if (!relocatable) meta->d.superdata = d->superClass; meta->d.extradata = 0; } // Populate the QMetaObjectPrivate structure. QMetaObjectPrivate *pmeta = reinterpret_cast<QMetaObjectPrivate *>(buf + size); + int pmetaSize = size; dataIndex = 13; // Number of fields in the QMetaObjectPrivate. for (index = 0; index < d->properties.size(); ++index) { if (d->properties[index].notifySignal != -1) { @@ -1246,8 +1253,13 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) size += dataIndex * sizeof(int); char *str = reinterpret_cast<char *>(buf + size); if (buf) { - meta->d.stringdata = str; - meta->d.data = reinterpret_cast<uint *>(data); + if (relocatable) { + meta->d.stringdata = reinterpret_cast<const char *>((intptr_t)size); + meta->d.data = reinterpret_cast<uint *>((intptr_t)pmetaSize); + } else { + meta->d.stringdata = str; + meta->d.data = reinterpret_cast<uint *>(data); + } } // Reset the current data position to just past the QMetaObjectPrivate. @@ -1422,12 +1434,67 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf) */ QMetaObject *QMetaObjectBuilder::toMetaObject() const { - int size = buildMetaObject(d, 0); + int size = buildMetaObject(d, 0, false); char *buf = reinterpret_cast<char *>(qMalloc(size)); - buildMetaObject(d, buf); + buildMetaObject(d, buf, false); return reinterpret_cast<QMetaObject *>(buf); } +/* + \internal + + Converts this meta object builder into relocatable data. This data can + be stored, copied and later passed to fromRelocatableData() to create a + concrete QMetaObject. + + The data is specific to the architecture on which it was created, but is not + specific to the process that created it. Not all meta object builder's can + be converted to data in this way. If \a ok is provided, it will be set to + true if the conversion succeeds, and false otherwise. If a + staticMetacallFunction() or any relatedMetaObject()'s are specified the + conversion to relocatable data will fail. +*/ +QByteArray QMetaObjectBuilder::toRelocatableData(bool *ok) const +{ + int size = buildMetaObject(d, 0, true); + if (size == -1) { + if (ok) *ok = false; + return QByteArray(); + } + + QByteArray data; + data.resize(size); + char *buf = data.data(); + buildMetaObject(d, buf, true); + if (ok) *ok = true; + return data; +} + +/* + \internal + + Sets the \a data returned from toRelocatableData() onto a concrete + QMetaObject instance, \a output. As the meta object's super class is not + saved in the relocatable data, it must be passed as \a superClass. +*/ +void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output, + const QMetaObject *superclass, + const QByteArray &data) +{ + if (!output) + return; + + const char *buf = data.constData(); + const QMetaObject *dataMo = reinterpret_cast<const QMetaObject *>(buf); + + intptr_t stringdataOffset = (intptr_t)dataMo->d.stringdata; + intptr_t dataOffset = (intptr_t)dataMo->d.data; + + output->d.superdata = superclass; + output->d.stringdata = buf + stringdataOffset; + output->d.data = reinterpret_cast<const uint *>(buf + dataOffset); +} + /*! \typedef QMetaObjectBuilder::StaticMetacallFunction diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h index 952364a..d503163 100644 --- a/src/corelib/kernel/qmetaobjectbuilder_p.h +++ b/src/corelib/kernel/qmetaobjectbuilder_p.h @@ -169,6 +169,8 @@ public: void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value); QMetaObject *toMetaObject() const; + QByteArray toRelocatableData(bool * = 0) const; + static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &); #ifndef QT_NO_DATASTREAM void serialize(QDataStream& stream) const; diff --git a/src/declarative/extra/qfxparticles.cpp b/src/declarative/extra/qfxparticles.cpp index 322ec53..3d59022 100644 --- a/src/declarative/extra/qfxparticles.cpp +++ b/src/declarative/extra/qfxparticles.cpp @@ -459,8 +459,9 @@ void QFxParticlesPrivate::tick(int time) } } } - while(particles.count() < count && particles.count() < percCount && streamWidth--) - createParticle(time); + while(particles.count() < count && + (!stream || (particles.count() < percCount && streamWidth--))) + createParticle(time); } lastAdvTime = time; @@ -682,11 +683,13 @@ void QFxParticles::setCount(int cnt) { Q_D(QFxParticles); if (cnt != d->count) { - if (!d->count && d->clock.state() != QAbstractAnimation::Running) - d->clock.start(); // infinity?? + int oldCount = d->count; d->count = cnt; d->addParticleTime = 0; d->addParticleCount = d->particles.count(); + if (!oldCount && d->clock.state() != QAbstractAnimation::Running){ + d->clock.start(); // infinity?? + } update(); } } diff --git a/src/declarative/extra/qmlfolderlistmodel.cpp b/src/declarative/extra/qmlfolderlistmodel.cpp index acee5e1..4a71109 100644 --- a/src/declarative/extra/qmlfolderlistmodel.cpp +++ b/src/declarative/extra/qmlfolderlistmodel.cpp @@ -161,7 +161,9 @@ void QmlFolderListModel::classComplete() bool QmlFolderListModel::isFolder(int index) const { Q_D(const QmlFolderListModel); - return d->model.isDir(d->model.index(index, 0, d->folderIndex)); + if (index != -1) + return d->model.isDir(d->model.index(index, 0, d->folderIndex)); + return false; } void QmlFolderListModel::refresh() diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri index b4ba742..413b8db 100644 --- a/src/declarative/fx/fx.pri +++ b/src/declarative/fx/fx.pri @@ -30,6 +30,8 @@ HEADERS += \ fx/qfxrepeater.h \ fx/qfxrepeater_p.h \ fx/qfxscalegrid.h \ + fx/qfxlineedit.h \ + fx/qfxlineedit_p.h \ fx/qfxtextedit.h \ fx/qfxtextedit_p.h \ fx/qfxtext.h \ @@ -60,6 +62,7 @@ SOURCES += \ fx/qfxrect.cpp \ fx/qfxrepeater.cpp \ fx/qfxscalegrid.cpp \ + fx/qfxlineedit.cpp \ fx/qfxtext.cpp \ fx/qfxtextedit.cpp \ fx/qfxtransform.cpp \ diff --git a/src/declarative/fx/qfxlineedit.cpp b/src/declarative/fx/qfxlineedit.cpp new file mode 100644 index 0000000..d23c325 --- /dev/null +++ b/src/declarative/fx/qfxlineedit.cpp @@ -0,0 +1,543 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfxlineedit.h" +#include "qfxlineedit_p.h" +#include <QValidator> +#include <QApplication> +#include <QFontMetrics> + +QT_BEGIN_NAMESPACE +QML_DEFINE_TYPE(QFxLineEdit,LineEdit); +QML_DEFINE_TYPE(QIntValidator,QIntValidator); + +QFxLineEdit::QFxLineEdit(QFxItem* parent) + : QFxPaintedItem(*(new QFxLineEditPrivate), parent) +{ + Q_D(QFxLineEdit); + d->init(); +} + +/* + \internal +*/ +QFxLineEdit::QFxLineEdit(QFxLineEditPrivate &dd, QFxItem* parent) + : QFxPaintedItem(dd, parent) +{ + Q_D(QFxLineEdit); + d->init(); +} + +QFxLineEdit::~QFxLineEdit() +{ +} + +QString QFxLineEdit::text() const +{ + Q_D(const QFxLineEdit); + return d->control->text(); +} + +void QFxLineEdit::setText(const QString &s) +{ + Q_D(QFxLineEdit); + if(s == text()) + return; + d->control->setText(s); + //emit textChanged(); +} + +QmlFont *QFxLineEdit::font() +{ + Q_D(QFxLineEdit); + return d->font; +} + +QColor QFxLineEdit::color() const +{ + Q_D(const QFxLineEdit); + return d->color; +} + +void QFxLineEdit::setColor(const QColor &c) +{ + Q_D(QFxLineEdit); + d->color = c; +} + +/* +QFxText::TextStyle QFxLineEdit::style() const +{ + Q_D(const QFxLineEdit); + return d->style; +} + +void QFxLineEdit::setStyle(QFxText::TextStyle style) +{ + Q_D(QFxLineEdit); + d->style = style; +} + +QColor QFxLineEdit::styleColor() const +{ + Q_D(const QFxLineEdit); + return d->styleColor; +} + +void QFxLineEdit::setStyleColor(const QColor &c) +{ + Q_D(QFxLineEdit); + d->styleColor = c; +} +*/ + +QFxText::HAlignment QFxLineEdit::hAlign() const +{ + Q_D(const QFxLineEdit); + return d->hAlign; +} + +void QFxLineEdit::setHAlign(QFxText::HAlignment align) +{ + Q_D(QFxLineEdit); + d->hAlign = align; +} + +QFxText::VAlignment QFxLineEdit::vAlign() const +{ + Q_D(const QFxLineEdit); + return d->vAlign; +} + +void QFxLineEdit::setVAlign(QFxText::VAlignment align) +{ + Q_D(QFxLineEdit); + d->vAlign = align; +} + +//### Should this also toggle cursor visibility? +bool QFxLineEdit::isReadOnly() const +{ + Q_D(const QFxLineEdit); + return d->control->isReadOnly(); +} + +void QFxLineEdit::setReadOnly(bool ro) +{ + Q_D(QFxLineEdit); + d->control->setReadOnly(ro); +} + +int QFxLineEdit::maxLength() const +{ + Q_D(const QFxLineEdit); + return d->control->maxLength(); +} + +void QFxLineEdit::setMaxLength(int ml) +{ + Q_D(QFxLineEdit); + d->control->setMaxLength(ml); +} + +int QFxLineEdit::cursorPosition() const +{ + Q_D(const QFxLineEdit); + return d->control->cursor(); +} +void QFxLineEdit::setCursorPosition(int cp) +{ + Q_D(QFxLineEdit); + d->control->moveCursor(cp); +} + +int QFxLineEdit::selectionLength() const +{ + Q_D(const QFxLineEdit); + return d->control->selectionEnd() - d->control->selectionStart(); +} + +void QFxLineEdit::setSelectionLength(int len) +{ + Q_D(QFxLineEdit); + d->control->setSelection(d->control->cursor(), len); +} + +QString QFxLineEdit::selectedText() const +{ + Q_D(const QFxLineEdit); + return d->control->selectedText(); +} + +bool QFxLineEdit::isAwesome() const +{ + Q_D(const QFxLineEdit); + return d->awesome; +} + +#include <QTimer> //Can be removed along wit the property +void QFxLineEdit::setAwesome(bool a) +{ + Q_D(QFxLineEdit); + d->awesome = a; + if(a){ + setColor(QColor(0,0,255)); + rainbowRedraw(); + } +} + +QObject* QFxLineEdit::validator() const +{ + Q_D(const QFxLineEdit); + //###const cast isn't good, but needed for property system? + //###same should be said about using QObject* as the property type + return const_cast<QValidator*>(d->control->validator()); +} + +void QFxLineEdit::setValidator(QObject* v) +{ + Q_D(QFxLineEdit); + QValidator* valid = qobject_cast<QValidator*>(v); + if(!valid) + return; + d->control->setValidator(valid); + if(!d->control->hasAcceptableInput()){ + d->oldValidity = false; + emit acceptableInputChanged(); + } +} + +QString QFxLineEdit::inputMask() const +{ + Q_D(const QFxLineEdit); + return d->control->inputMask(); +} + +void QFxLineEdit::setInputMask(const QString &im) +{ + Q_D(QFxLineEdit); + d->control->setInputMask(im); +} + +bool QFxLineEdit::hasAcceptableInput() const +{ + Q_D(const QFxLineEdit); + return d->control->hasAcceptableInput(); +} + +uint QFxLineEdit::echoMode() const +{ + Q_D(const QFxLineEdit); + return d->control->echoMode(); +} + +void QFxLineEdit::setEchoMode(uint echo) +{ + Q_D(QFxLineEdit); + d->control->setEchoMode(echo); +} + +QmlComponent* QFxLineEdit::cursorDelegate() const +{ + Q_D(const QFxLineEdit); + return d->cursorComponent; +} + +void QFxLineEdit::setCursorDelegate(QmlComponent* c) +{ + Q_D(QFxLineEdit); + if(d->cursorComponent) + delete d->cursorComponent; + d->cursorComponent = c; + d->startCreatingCursor(); +} + +void QFxLineEditPrivate::startCreatingCursor() +{ + Q_Q(QFxLineEdit); + if(!cursorComponent){ + q->disconnect(control, SIGNAL(cursorPositionChanged(int, int)), + q, SLOT(moveCursor())); + return; + } + q->connect(control, SIGNAL(cursorPositionChanged(int, int)), + q, SLOT(moveCursor())); + if(cursorComponent->isReady()){ + q->createCursor(); + }else if(cursorComponent->isLoading()){ + q->connect(cursorComponent, SIGNAL(statusChanged(int)), + q, SLOT(createCursor())); + }else{//isError + qWarning() << "You could really use the error checking for QFxLineEdit. We'll implement it soon."; + } +} + +void QFxLineEdit::createCursor() +{ + Q_D(QFxLineEdit); + //Handle isError too + if(!d->cursorComponent->isReady()) + return; + + if(d->cursorItem) + delete d->cursorItem; + d->cursorItem = qobject_cast<QFxItem*>(d->cursorComponent->create()); + if(!d->cursorItem){ + qWarning() << "You could really use the error reporting for QFxLineEdit. We'll implement it soon."; + return; + } + + d->cursorItem->setItemParent(this); + d->cursorItem->setX(d->control->cursorToX()); + d->cursorItem->setHeight(d->control->height()); +} + +void QFxLineEdit::moveCursor() +{ + Q_D(QFxLineEdit); + if(!d->cursorItem) + return; + d->cursorItem->setX(d->control->cursorToX() - d->hscroll); +} + +/* +int QFxLineEdit::scrollDuration() const +{ + Q_D(const QFxLineEdit); + return d->scrollDur; +} + +void QFxLineEdit::setScrollDuration(int s) +{ + Q_D(QFxLineEdit); + d->scrollDur = s; + //Need to update cur anims as well +} +*/ +int QFxLineEdit::xToPos(int x) +{ + Q_D(const QFxLineEdit); + return d->control->xToPos(x - d->hscroll); +} + +void QFxLineEdit::focusChanged(bool hasFocus) +{ + Q_D(QFxLineEdit); + if(d->focused && !hasFocus){ + d->focused = false; + d->control->setCursorBlinkPeriod(0); + updateAll();//Only need the cursor rect + }else{ + d->focused = hasFocus; + updateAll();//Only need the cursor rect + } +} + +void QFxLineEdit::keyPressEvent(QKeyEvent* ev) +{ + Q_D(QFxLineEdit); + d->control->processKeyEvent(ev); +} + +void QFxLineEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + Q_D(QFxLineEdit); + setFocus(true); + d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime()); + d->focused = true; + d->control->processEvent(event); + //event->accept(); +} + +bool QFxLineEdit::event(QEvent* ev) +{ + Q_D(QFxLineEdit); + //Anything we don't deal with ourselves, pass to the control + switch(ev->type()){ + case QEvent::GraphicsSceneMousePress: + break; + default: + return d->control->processEvent(ev); + } + return false; +} + +void QFxLineEdit::geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) +{ + if (newGeometry.width() != oldGeometry.width()) + updateSize(); + QFxPaintedItem::geometryChanged(newGeometry, oldGeometry); +} + +void QFxLineEdit::drawContents(QPainter *p, const QRect &r) +{ + Q_D(QFxLineEdit); + p->setRenderHint(QPainter::TextAntialiasing, true); + p->save(); + p->setPen(QPen(d->color)); + int flags = QLineControl::DrawText; + if(!isReadOnly() && d->focused && !d->cursorItem) + flags |= QLineControl::DrawCursor; + if (d->control->hasSelectedText()) + flags |= QLineControl::DrawSelections; + + //TODO: Clean up this cut'n'pasted section from QLineEdit + QRect lineRect(r); + + int cix = qRound(d->control->cursorToX()); + + // horizontal scrolling. d->hscroll is the left indent from the beginning + // of the text line to the left edge of lineRect. we update this value + // depending on the delta from the last paint event; in effect this means + // the below code handles all scrolling based on the textline (widthUsed, + // minLB, minRB), the line edit rect (lineRect) and the cursor position + // (cix). + QFontMetrics fm = QApplication::fontMetrics(); + int minLB = qMax(0, -fm.minLeftBearing()); + int minRB = qMax(0, -fm.minRightBearing()); + int widthUsed = d->control->width() + minRB; + if ((minLB + widthUsed) <= lineRect.width()) { + // text fits in lineRect; use hscroll for alignment + d->hscroll = 0; + d->hscroll -= minLB; + } else if (cix - d->hscroll >= lineRect.width()) { + // text doesn't fit, cursor is to the right of lineRect (scroll right) + d->hscroll = cix - lineRect.width() + 1; + } else if (cix - d->hscroll < 0 && d->hscroll < widthUsed) { + // text doesn't fit, cursor is to the left of lineRect (scroll left) + d->hscroll = cix; + } + // the y offset is there to keep the baseline constant in case we have script changes in the text. + QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent()); + + if(d->hscroll != d->oldScroll) + moveCursor(); + + d->control->draw(p, topLeft, r, flags); + + d->oldScroll = d->hscroll; + p->restore(); +} + +void QFxLineEditPrivate::init() +{ + Q_Q(QFxLineEdit); + control->setCursorWidth(1); + control->setPasswordCharacter('*'); + control->setLayoutDirection(Qt::LeftToRight); + control->setSelection(0,0); + q->setSmooth(true); + q->setAcceptedMouseButtons(Qt::LeftButton); + q->setOptions(QFxLineEdit::AcceptsInputMethods | QFxLineEdit::SimpleItem + | QFxLineEdit::HasContents | QFxLineEdit::MouseEvents); + q->connect(control, SIGNAL(cursorPositionChanged(int,int)), + q, SIGNAL(cursorPositionChanged())); + q->connect(control, SIGNAL(selectionChanged()), + q, SLOT(selectionChanged())); + q->connect(control, SIGNAL(textChanged(const QString &)), + q, SLOT(q_textChanged())); + q->connect(control, SIGNAL(accepted()), + q, SIGNAL(accepted())); + q->connect(control, SIGNAL(updateNeeded(const QRect &)), + // q, SLOT(dirtyCache(const QRect &))); + q, SLOT(updateAll())); + q->connect(control, SIGNAL(cursorPositionChanged(int,int)), + q, SLOT(updateAll())); + q->connect(control, SIGNAL(selectionChanged()), + q, SLOT(updateAll())); + if(!font) + font = new QmlFont(); + q->updateSize(); + oldValidity = control->hasAcceptableInput(); + oldSelectLength = q->selectionLength(); +} + +void QFxLineEdit::selectionChanged() +{ + Q_D(QFxLineEdit); + emit selectedTextChanged(); + if(selectionLength() != d->oldSelectLength){ + d->oldSelectLength = selectionLength(); + emit selectionLengthChanged(); + } +} + +void QFxLineEdit::q_textChanged() +{ + Q_D(QFxLineEdit); + updateAll(); + emit textChanged(); + if(hasAcceptableInput() != d->oldValidity){ + d->oldValidity = hasAcceptableInput(); + emit acceptableInputChanged(); + } +} + +//### Please replace this function with proper updating +void QFxLineEdit::updateAll() +{ + clearCache(); + updateSize(); + update(); +} + +void QFxLineEdit::updateSize() +{ + Q_D(QFxLineEdit); + setImplicitHeight(d->control->height()); + //d->control->width() is max width, not current width + QFontMetrics fm = QFontMetrics(d->font->font()); + setImplicitWidth(fm.boundingRect(d->control->text()).width()+1); + setContentsSize(QSize(width(), height())); +} + +void QFxLineEdit::rainbowRedraw() +{ + Q_D(QFxLineEdit); + if(!d->awesome) + return; + setColor(QColor::fromHsv((d->color.hue() + 5)%360, d->color.saturation(), d->color.value())); + updateAll(); + QTimer::singleShot(50, this, SLOT(rainbowRedraw())); +} +QT_END_NAMESPACE + diff --git a/src/declarative/fx/qfxlineedit.h b/src/declarative/fx/qfxlineedit.h new file mode 100644 index 0000000..5abb418 --- /dev/null +++ b/src/declarative/fx/qfxlineedit.h @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXLINEEDIT_H +#define QFXLINEEDIT_H + +#include "qfxtext.h" +#include "qfxpainteditem.h" +#include <QGraphicsSceneMouseEvent> +#include <QIntValidator> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QFxLineEditPrivate; +class QValidator; +class Q_DECLARATIVE_EXPORT QFxLineEdit : public QFxPaintedItem +{ + Q_OBJECT + + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(QmlFont *font READ font) + Q_PROPERTY(QColor color READ color WRITE setColor) + /* + Q_PROPERTY(QFxText::TextStyle style READ style WRITE setStyle) + Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor) + Q_PROPERTY(QFxText::HAlignment hAlign READ hAlign WRITE setHAlign) + Q_PROPERTY(QFxText::VAlignment vAlign READ vAlign WRITE setVAlign) + */ + + Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly); + Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength); + Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged); + Q_PROPERTY(int selectionLength READ selectionLength WRITE setSelectionLength NOTIFY selectionLengthChanged); + Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged); + + Q_PROPERTY(QObject* validator READ validator WRITE setValidator); + Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask); + Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged); + Q_PROPERTY(uint echoMode READ echoMode WRITE setEchoMode); + + Q_PROPERTY(QmlComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate); + /* + Q_PROPERTY(int scrollDuration READ scrollDuration SET setScrollDuration NOTIFY scrollDurationChanged); + */ + //### Requested by Aaron K.(Remove before release?) + Q_PROPERTY(bool awesome READ isAwesome WRITE setAwesome); +public: + QFxLineEdit(QFxItem* parent=0); + ~QFxLineEdit(); + + QString text() const; + void setText(const QString &); + + QmlFont *font(); + + QColor color() const; + void setColor(const QColor &c); + + //### Should we have this function or x variants of properties? + Q_INVOKABLE int xToPos(int x); + + /* + QFxText::TextStyle style() const; + void setStyle(QFxText::TextStyle style); + + QColor styleColor() const; + void setStyleColor(const QColor &c); + */ + + QFxText::HAlignment hAlign() const; + void setHAlign(QFxText::HAlignment align); + + QFxText::VAlignment vAlign() const; + void setVAlign(QFxText::VAlignment align); + + bool isReadOnly() const; + void setReadOnly(bool); + + int maxLength() const; + void setMaxLength(int ml); + + int cursorPosition() const; + void setCursorPosition(int cp); + + int selectionLength() const; + void setSelectionLength(int len); + + QString selectedText() const; + + QObject * validator() const; + void setValidator(QObject* v); + + QString inputMask() const; + void setInputMask(const QString &im); + + uint echoMode() const; + void setEchoMode(uint echo); + + QmlComponent* cursorDelegate() const; + void setCursorDelegate(QmlComponent*); + + /* + int scrollDuration() const; + void setScrollDuration(int); + */ + + bool hasAcceptableInput() const; + + bool isAwesome() const; + void setAwesome(bool a); + + void drawContents(QPainter *p,const QRect &r); +Q_SIGNALS: + void textChanged(); + void cursorPositionChanged(); + void selectionLengthChanged(); + void selectedTextChanged(); + void accepted(); + void acceptableInputChanged(); + +protected: + QFxLineEdit(QFxLineEditPrivate &dd, QFxItem *parent); + virtual void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry); + + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void keyPressEvent(QKeyEvent* ev); + bool event(QEvent *e); + + void focusChanged(bool hasFocus); + +private slots: + void updateSize(); + void q_textChanged(); + void selectionChanged(); + void updateAll(); + void createCursor(); + void moveCursor(); + void rainbowRedraw(); + +private: + Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QFxLineEdit); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QFxLineEdit) +QML_DECLARE_TYPE(QIntValidator) + +QT_END_HEADER +#endif // QFXLINEEDIT_H diff --git a/src/declarative/qml/qmlcompiledcomponent_p.h b/src/declarative/fx/qfxlineedit_p.h index 0945892..8ee5cca 100644 --- a/src/declarative/qml/qmlcompiledcomponent_p.h +++ b/src/declarative/fx/qfxlineedit_p.h @@ -39,9 +39,14 @@ ** ****************************************************************************/ -#ifndef QMLCOMPILEDCOMPONENT_P_H -#define QMLCOMPILEDCOMPONENT_P_H +#ifndef QFXLINEEDIT_P_H +#define QFXLINEEDIT_P_H +#include "qfxlineedit.h" +#include "qml.h" +#include "qfxpainteditem_p.h" +#include "private/qlinecontrol_p.h" +#include <QPointer> // // W A R N I N G // ------------- @@ -51,42 +56,51 @@ // version without notice, or even be removed. // // We mean it. -// - -#include <QtDeclarative/qml.h> -#include <private/qmlinstruction_p.h> -#include <private/qmlcompiler_p.h> -#include <private/qmlrefcount_p.h> - -QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -namespace QmlParser { - class Property; - class Object; - class Value; -}; - -class QmlCompiledComponent : public QmlRefCount, public QmlCompiledData +class QFxLineEditPrivate : public QFxPaintedItemPrivate { + Q_DECLARE_PUBLIC(QFxLineEdit); public: - QmlCompiledComponent(); - ~QmlCompiledComponent(); + QFxLineEditPrivate() : control(new QLineControl(QString())), + font(0), color((QRgb)0), style(QFxText::Normal), + hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), + styleColor((QRgb)0), oldScroll(0), hscroll(0), + focused(false), awesome(false) + { + } + + ~QFxLineEditPrivate() + { + } + + void init(); + void startCreatingCursor(); + + QLineControl* control; + + QmlFont *font; + QColor color; + QFxText::TextStyle style; + QColor styleColor; + QFxText::HAlignment hAlign; + QFxText::VAlignment vAlign; + QPointer<QmlComponent> cursorComponent; + QPointer<QFxItem> cursorItem; - void dumpPre(); - void dumpPost(); + int oldSelectLength; + int oldHeight; + int oldWidth; + bool oldValidity; + int hscroll; + int oldScroll; + bool focused; + bool awesome; -private: - enum DumpStatus { NoDump = 0x00, DumpPre = 0x01, DumpPost = 0x02 } dumpStatus; - void dumpInstructions(); - void dump(QmlInstruction *, int idx = -1); - friend class QmlCompiler; - friend class QmlDomDocument; }; QT_END_NAMESPACE -QT_END_HEADER +#endif -#endif // QMLCOMPILEDCOMPONENT_P_H diff --git a/src/declarative/qml/parser/qmljs.g b/src/declarative/qml/parser/qmljs.g index 8297c08..43cce40 100644 --- a/src/declarative/qml/parser/qmljs.g +++ b/src/declarative/qml/parser/qmljs.g @@ -86,11 +86,16 @@ %token T_IMPORT "import" %token T_AS "as" +--- feed tokens +%token T_FEED_UI_PROGRAM +%token T_FEED_JS_STATEMENT +%token T_FEED_JS_EXPRESSION + %nonassoc SHIFT_THERE %nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY %nonassoc REDUCE_HERE -%start UiProgram +%start TopLevel /. /**************************************************************************** @@ -272,10 +277,29 @@ public: Parser(Engine *engine); ~Parser(); - bool parse(); + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + + AST::UiProgram *ast() const + { return AST::cast<AST::UiProgram *>(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; - AST::UiProgram *ast() - { return program; } + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } QList<DiagnosticMessage> diagnosticMessages() const { return diagnostic_messages; } @@ -300,6 +324,8 @@ public: { return diagnosticMessage().loc.startColumn; } protected: + bool parse(int startToken); + void reallocateStack(); inline Value &sym(int index) @@ -318,7 +344,7 @@ protected: int *state_stack; AST::SourceLocation *location_stack; - AST::UiProgram *program; + AST::Node *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; @@ -439,14 +465,16 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) return 0; } -bool Parser::parse() +bool Parser::parse(int startToken) { Lexer *lexer = driver->lexer(); bool hadErrors = false; int yytoken = -1; int action = 0; - first_token = last_token = 0; + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; tos = -1; program = 0; @@ -494,12 +522,35 @@ bool Parser::parse() -- Declarative UI -------------------------------------------------------------------------------------------------------- +TopLevel: T_FEED_UI_PROGRAM UiProgram ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_STATEMENT Statement ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + +TopLevel: T_FEED_JS_EXPRESSION Expression ; +/. +case $rule_number: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; +./ + UiProgram: UiImportListOpt UiRootMember ; /. case $rule_number: { - program = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, + sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, sym(2).UiObjectMemberList->finish()); - sym(1).UiProgram = program; } break; ./ @@ -2962,7 +3013,8 @@ PropertyNameAndValueListOpt: PropertyNameAndValueList ; } for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { - if (tk == T_AUTOMATIC_SEMICOLON) + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION) continue; int a = t_action(errorState, tk); diff --git a/src/declarative/qml/parser/qmljsgrammar.cpp b/src/declarative/qml/parser/qmljsgrammar.cpp index ff25d65..4fba480 100644 --- a/src/declarative/qml/parser/qmljsgrammar.cpp +++ b/src/declarative/qml/parser/qmljsgrammar.cpp @@ -52,930 +52,556 @@ const char *const QmlJSGrammar::spell [] = { ")", ";", 0, "*", "*=", "string literal", "property", "signal", "switch", "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^", "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "public", "import", "as", - 0, 0, -#ifndef QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO -"UiProgram", "UiImportListOpt", "UiRootMember", "Empty", "UiImportList", "UiImport", "JsIdentifier", "UiQualifiedId", - "UiObjectDefinition", "UiObjectMemberList", "UiObjectMember", "UiArrayMemberList", "UiObjectInitializer", "UiMultilineStringLiteral", "UiMultilineStringStatement", "Expression", "Block", "EmptyStatement", - "ExpressionStatement", "DebuggerStatement", "IfStatement", "UiPropertyType", "UiParameterListOpt", "UiParameterList", "FunctionDeclaration", "VariableStatement", "PrimaryExpression", "Elision", - "ElementList", "PropertyNameAndValueListOpt", "PropertyNameAndValueList", "AssignmentExpression", "PropertyName", "ReservedIdentifier", "PropertyIdentifier", "MemberExpression", "FunctionExpression", "ArgumentListOpt", - "NewExpression", "CallExpression", "ArgumentList", "LeftHandSideExpression", "PostfixExpression", "UnaryExpression", "MultiplicativeExpression", "AdditiveExpression", "ShiftExpression", "RelationalExpression", - "RelationalExpressionNotIn", "EqualityExpression", "EqualityExpressionNotIn", "BitwiseANDExpression", "BitwiseANDExpressionNotIn", "BitwiseXORExpression", "BitwiseXORExpressionNotIn", "BitwiseORExpression", "BitwiseORExpressionNotIn", "LogicalANDExpression", - "LogicalANDExpressionNotIn", "LogicalORExpression", "LogicalORExpressionNotIn", "ConditionalExpression", "ConditionalExpressionNotIn", "AssignmentExpressionNotIn", "AssignmentOperator", "ExpressionOpt", "ExpressionNotIn", "ExpressionNotInOpt", - "Statement", "IterationStatement", "ContinueStatement", "BreakStatement", "ReturnStatement", "WithStatement", "LabelledStatement", "SwitchStatement", "ThrowStatement", "TryStatement", - "StatementListOpt", "StatementList", "VariableDeclarationKind", "VariableDeclarationList", "VariableDeclaration", "VariableDeclarationListNotIn", "VariableDeclarationNotIn", "InitialiserOpt", "InitialiserNotInOpt", "Initialiser", - "InitialiserNotIn", "CaseBlock", "CaseClausesOpt", "DefaultClause", "CaseClauses", "CaseClause", "Catch", "Finally", "FormalParameterListOpt", "FunctionBodyOpt", - "IdentifierOpt", "FormalParameterList", "FunctionBody", "SourceElements", "SourceElement", "$accept" -#endif // QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO -}; + 0, 0, 0, 0, 0}; const int QmlJSGrammar::lhs [] = { - 92, 93, 93, 96, 96, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 95, 94, 101, - 101, 103, 103, 104, 104, 100, 102, 102, 105, 106, - 106, 102, 102, 102, 102, 102, 102, 102, 113, 113, - 113, 114, 114, 115, 115, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 99, 99, 98, - 98, 98, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 118, 118, 99, - 99, 120, 120, 120, 120, 119, 119, 122, 122, 124, - 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 126, 126, 127, 127, - 127, 127, 127, 130, 130, 131, 131, 131, 131, 129, - 129, 132, 132, 133, 133, 134, 134, 134, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 136, 136, - 136, 136, 137, 137, 137, 138, 138, 138, 138, 139, - 139, 139, 139, 139, 139, 139, 140, 140, 140, 140, - 140, 140, 141, 141, 141, 141, 141, 142, 142, 142, - 142, 142, 143, 143, 144, 144, 145, 145, 146, 146, - 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, - 152, 152, 153, 153, 154, 154, 123, 123, 155, 155, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 107, 107, 157, 157, 158, 158, 159, 159, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, - 160, 160, 160, 160, 160, 108, 171, 171, 170, 170, - 117, 117, 172, 172, 173, 173, 175, 175, 174, 176, - 179, 177, 177, 180, 178, 178, 109, 110, 110, 112, - 112, 161, 161, 161, 161, 161, 161, 161, 162, 162, - 162, 162, 163, 163, 163, 163, 164, 164, 165, 167, - 181, 181, 184, 184, 182, 182, 185, 183, 166, 166, - 166, 168, 168, 169, 169, 169, 186, 187, 111, 111, - 116, 128, 191, 191, 188, 188, 189, 189, 192, 193, - 193, 194, 194, 190, 190, 121, 121, 195}; + 95, 95, 95, 96, 99, 99, 102, 102, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 101, 100, 107, 107, 109, 109, 110, 110, 106, 108, + 108, 111, 112, 112, 108, 108, 108, 108, 108, 108, + 108, 118, 118, 118, 119, 119, 120, 120, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, + 105, 105, 104, 104, 104, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 105, 105, 125, 125, 125, 125, 124, 124, + 127, 127, 129, 129, 129, 129, 129, 129, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 131, + 131, 132, 132, 132, 132, 132, 135, 135, 136, 136, + 136, 136, 134, 134, 137, 137, 138, 138, 139, 139, + 139, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 141, 141, 141, 141, 142, 142, 142, 143, 143, + 143, 143, 144, 144, 144, 144, 144, 144, 144, 145, + 145, 145, 145, 145, 145, 146, 146, 146, 146, 146, + 147, 147, 147, 147, 147, 148, 148, 149, 149, 150, + 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, + 155, 156, 156, 157, 157, 158, 158, 159, 159, 128, + 128, 160, 160, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 98, 98, 162, 162, 163, + 163, 164, 164, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 113, 175, + 175, 174, 174, 122, 122, 176, 176, 177, 177, 179, + 179, 178, 180, 183, 181, 181, 184, 182, 182, 114, + 115, 115, 117, 117, 165, 165, 165, 165, 165, 165, + 165, 166, 166, 166, 166, 167, 167, 167, 167, 168, + 168, 169, 171, 185, 185, 188, 188, 186, 186, 189, + 187, 170, 170, 170, 172, 172, 173, 173, 173, 190, + 191, 116, 116, 121, 133, 195, 195, 192, 192, 193, + 193, 196, 197, 197, 198, 198, 194, 194, 126, 126, + 199}; const int QmlJSGrammar:: rhs[] = { - 2, 1, 1, 1, 2, 3, 3, 5, 5, 3, - 3, 4, 4, 6, 6, 5, 5, 0, 1, 1, - 2, 1, 3, 2, 3, 2, 1, 5, 1, 2, - 2, 4, 3, 3, 3, 3, 3, 3, 1, 1, - 1, 0, 1, 2, 4, 5, 2, 4, 4, 5, - 5, 6, 6, 7, 7, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 1, 1, 1, 2, 3, 3, + 5, 5, 3, 3, 4, 4, 6, 6, 5, 5, + 0, 1, 1, 2, 1, 3, 2, 3, 2, 1, + 5, 1, 2, 2, 4, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 0, 1, 2, 4, 5, 2, + 4, 4, 5, 5, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 3, 3, 4, 5, 3, 4, 3, 1, - 3, 1, 2, 3, 4, 1, 2, 3, 5, 1, + 1, 1, 1, 1, 2, 3, 3, 4, 5, 3, + 4, 3, 1, 3, 1, 2, 3, 4, 1, 2, + 3, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 4, 3, 5, 1, 2, 4, 4, 4, 3, 0, - 1, 1, 3, 1, 1, 1, 2, 2, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, - 3, 3, 1, 3, 3, 1, 3, 3, 3, 1, - 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, - 3, 3, 1, 3, 3, 3, 3, 1, 3, 3, - 3, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 5, 1, 5, 1, 3, 1, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 0, 1, 1, 3, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 1, 2, 0, 1, - 3, 3, 1, 1, 1, 3, 1, 3, 2, 2, - 2, 0, 1, 2, 0, 1, 1, 2, 2, 7, - 5, 7, 7, 5, 9, 10, 7, 8, 2, 2, - 3, 3, 2, 2, 3, 3, 3, 3, 5, 5, - 3, 5, 1, 2, 0, 1, 4, 3, 3, 3, - 3, 3, 3, 3, 3, 4, 5, 2, 2, 2, - 8, 8, 1, 3, 0, 1, 0, 1, 1, 1, - 2, 1, 1, 0, 1, 0, 1, 2}; - - -#ifndef QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO -const int QmlJSGrammar::rule_info [] = { - 92, 93, 94 - , 93, 95 - , 93, 96 - , 96, 97 - , 96, 96, 97 - , 97, 88, 65, 62 - , 97, 88, 65, 61 - , 97, 88, 65, 89, 98, 62 - , 97, 88, 65, 89, 98, 61 - , 97, 88, 99, 62 - , 97, 88, 99, 61 - , 97, 88, 99, 47, 62 - , 97, 88, 99, 47, 61 - , 97, 88, 99, 47, 89, 98, 62 - , 97, 88, 99, 47, 89, 98, 61 - , 97, 88, 99, 89, 98, 62 - , 97, 88, 99, 89, 98, 61 - , 95 - , 94, 100 - , 101, 102 - , 101, 101, 102 - , 103, 100 - , 103, 103, 8, 100 - , 104, 33, 55 - , 104, 33, 101, 55 - , 100, 99, 104 - , 102, 100 - , 102, 99, 7, 34, 103, 56 - , 105, 86 - , 106, 105, 62 - , 106, 105, 61 - , 102, 99, 7, 107, 104 - , 102, 99, 7, 108 - , 102, 99, 7, 109 - , 102, 99, 7, 110 - , 102, 99, 7, 111 - , 102, 99, 7, 106 - , 102, 99, 7, 112 - , 113, 74 - , 113, 85 - , 113, 29 - , 114 - , 114, 115 - , 115, 113, 98 - , 115, 115, 8, 113, 98 - , 102, 67, 29, 36, 114, 60 - , 102, 67, 29 - , 102, 66, 113, 29, 62 - , 102, 66, 113, 29, 61 - , 102, 10, 66, 113, 29, 62 - , 102, 10, 66, 113, 29, 61 - , 102, 66, 113, 29, 7, 107, 62 - , 102, 66, 113, 29, 7, 107, 61 - , 102, 10, 66, 113, 29, 7, 107, 62 - , 102, 10, 66, 113, 29, 7, 107, 61 - , 102, 116 - , 102, 117 - , 99, 85 - , 99, 59 - , 98, 29 - , 98, 66 - , 98, 67 - , 118, 69 - , 118, 98 - , 118, 80 - , 118, 81 - , 118, 82 - , 118, 47 - , 118, 65 - , 118, 12 - , 118, 13 - , 118, 34, 56 - , 118, 34, 119, 56 - , 118, 34, 120, 56 - , 118, 34, 120, 8, 56 - , 118, 34, 120, 8, 119, 56 - , 118, 33, 121, 55 - , 118, 33, 122, 8, 55 - , 118, 36, 107, 60 - , 99, 98 - , 99, 99, 15, 98 - , 120, 123 - , 120, 119, 123 - , 120, 120, 8, 123 - , 120, 120, 8, 119, 123 - , 119, 8 - , 119, 119, 8 - , 122, 124, 7, 123 - , 122, 122, 8, 124, 7, 123 - , 124, 29 - , 124, 67 - , 124, 66 - , 124, 65 - , 124, 47 - , 124, 125 - , 125, 4 - , 125, 5 - , 125, 6 - , 125, 9 - , 125, 10 - , 125, 11 - , 125, 14 - , 125, 16 - , 125, 82 - , 125, 20 - , 125, 21 - , 125, 22 - , 125, 30 - , 125, 31 - , 125, 32 - , 125, 43 - , 125, 80 - , 125, 59 - , 125, 68 - , 125, 69 - , 125, 70 - , 125, 81 - , 125, 72 - , 125, 73 - , 125, 74 - , 125, 75 - , 125, 76 - , 125, 83 - , 125, 84 - , 125, 85 - , 125, 77 - , 126, 98 - , 126, 125 - , 127, 118 - , 127, 128 - , 127, 127, 34, 107, 56 - , 127, 127, 15, 126 - , 127, 43, 127, 36, 129, 60 - , 130, 127 - , 130, 43, 130 - , 131, 127, 36, 129, 60 - , 131, 131, 36, 129, 60 - , 131, 131, 34, 107, 56 - , 131, 131, 15, 126 - , 129 - , 129, 132 - , 132, 123 - , 132, 132, 8, 123 - , 133, 130 - , 133, 131 - , 134, 133 - , 134, 133, 53 - , 134, 133, 42 - , 135, 134 - , 135, 11, 135 - , 135, 75, 135 - , 135, 73, 135 - , 135, 53, 135 - , 135, 42, 135 - , 135, 51, 135 - , 135, 40, 135 - , 135, 71, 135 - , 135, 44, 135 - , 136, 135 - , 136, 136, 63, 135 - , 136, 136, 12, 135 - , 136, 136, 57, 135 - , 137, 136 - , 137, 137, 51, 136 - , 137, 137, 40, 136 - , 138, 137 - , 138, 138, 38, 137 - , 138, 138, 25, 137 - , 138, 138, 27, 137 - , 139, 138 - , 139, 139, 37, 138 - , 139, 139, 24, 138 - , 139, 139, 35, 138 - , 139, 139, 23, 138 - , 139, 139, 32, 138 - , 139, 139, 31, 138 - , 140, 138 - , 140, 140, 37, 138 - , 140, 140, 24, 138 - , 140, 140, 35, 138 - , 140, 140, 23, 138 - , 140, 140, 32, 138 - , 141, 139 - , 141, 141, 18, 139 - , 141, 141, 45, 139 - , 141, 141, 19, 139 - , 141, 141, 46, 139 - , 142, 140 - , 142, 142, 18, 140 - , 142, 142, 45, 140 - , 142, 142, 19, 140 - , 142, 142, 46, 140 - , 143, 141 - , 143, 143, 1, 141 - , 144, 142 - , 144, 144, 1, 142 - , 145, 143 - , 145, 145, 78, 143 - , 146, 144 - , 146, 146, 78, 144 - , 147, 145 - , 147, 147, 48, 145 - , 148, 146 - , 148, 148, 48, 146 - , 149, 147 - , 149, 149, 2, 147 - , 150, 148 - , 150, 150, 2, 148 - , 151, 149 - , 151, 151, 50, 149 - , 152, 150 - , 152, 152, 50, 150 - , 153, 151 - , 153, 151, 54, 123, 7, 123 - , 154, 152 - , 154, 152, 54, 155, 7, 155 - , 123, 153 - , 123, 133, 156, 123 - , 155, 154 - , 155, 133, 156, 155 - , 156, 17 - , 156, 64 - , 156, 13 - , 156, 58 - , 156, 52 - , 156, 41 - , 156, 39 - , 156, 26 - , 156, 28 - , 156, 3 - , 156, 79 - , 156, 49 - , 107, 123 - , 107, 107, 8, 123 - , 157 - , 157, 107 - , 158, 155 - , 158, 158, 8, 155 - , 159 - , 159, 158 - , 160, 108 - , 160, 117 - , 160, 109 - , 160, 110 - , 160, 112 - , 160, 161 - , 160, 162 - , 160, 163 - , 160, 164 - , 160, 165 - , 160, 166 - , 160, 167 - , 160, 168 - , 160, 169 - , 160, 111 - , 108, 33, 170, 55 - , 171, 160 - , 171, 171, 160 - , 170 - , 170, 171 - , 117, 172, 173, 62 - , 117, 172, 173, 61 - , 172, 83 - , 172, 74 - , 173, 174 - , 173, 173, 8, 174 - , 175, 176 - , 175, 175, 8, 176 - , 174, 98, 177 - , 176, 98, 178 - , 179, 17, 123 - , 177 - , 177, 179 - , 180, 17, 155 - , 178 - , 178, 180 - , 109, 61 - , 110, 107, 62 - , 110, 107, 61 - , 112, 30, 36, 107, 60, 160, 16, 160 - , 112, 30, 36, 107, 60, 160 - , 161, 14, 160, 76, 36, 107, 60, 62 - , 161, 14, 160, 76, 36, 107, 60, 61 - , 161, 76, 36, 107, 60, 160 - , 161, 21, 36, 159, 61, 157, 61, 157, 60, 160 - , 161, 21, 36, 74, 175, 61, 157, 61, 157, 60, 160 - , 161, 21, 36, 133, 31, 107, 60, 160 - , 161, 21, 36, 74, 176, 31, 107, 60, 160 - , 162, 9, 62 - , 162, 9, 61 - , 162, 9, 98, 62 - , 162, 9, 98, 61 - , 163, 4, 62 - , 163, 4, 61 - , 163, 4, 98, 62 - , 163, 4, 98, 61 - , 164, 59, 157, 62 - , 164, 59, 157, 61 - , 165, 77, 36, 107, 60, 160 - , 167, 68, 36, 107, 60, 181 - , 181, 33, 182, 55 - , 181, 33, 182, 183, 182, 55 - , 184, 185 - , 184, 184, 185 - , 182 - , 182, 184 - , 185, 5, 107, 7, 170 - , 183, 10, 7, 170 - , 166, 67, 7, 160 - , 166, 66, 7, 160 - , 166, 29, 7, 160 - , 168, 70, 107, 62 - , 168, 70, 107, 61 - , 169, 72, 108, 186 - , 169, 72, 108, 187 - , 169, 72, 108, 186, 187 - , 186, 6, 36, 98, 60, 108 - , 187, 20, 108 - , 111, 84, 62 - , 111, 84, 61 - , 116, 22, 98, 36, 188, 60, 33, 189, 55 - , 128, 22, 190, 36, 188, 60, 33, 189, 55 - , 191, 98 - , 191, 191, 8, 98 - , 188 - , 188, 191 - , 189 - , 189, 192 - , 192, 193 - , 193, 194 - , 193, 193, 194 - , 194, 160 - , 194, 116 - , 190 - , 190, 98 - , 121 - , 121, 122 - , 195, 92, 0}; - -const int QmlJSGrammar::rule_index [] = { - 0, 3, 5, 7, 9, 12, 16, 20, 26, 32, - 36, 40, 45, 50, 57, 64, 70, 76, 77, 79, - 81, 84, 86, 90, 93, 97, 100, 102, 108, 110, - 113, 116, 121, 125, 129, 133, 137, 141, 145, 147, - 149, 151, 152, 154, 157, 162, 168, 171, 176, 181, - 187, 193, 200, 207, 215, 223, 225, 227, 229, 231, - 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, - 253, 255, 258, 262, 266, 271, 277, 281, 286, 290, - 292, 296, 298, 301, 305, 310, 312, 315, 319, 325, - 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, - 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, - 367, 369, 371, 373, 375, 377, 379, 381, 383, 385, - 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, - 407, 412, 416, 422, 424, 427, 432, 437, 442, 446, - 447, 449, 451, 455, 457, 459, 461, 464, 467, 469, - 472, 475, 478, 481, 484, 487, 490, 493, 496, 498, - 502, 506, 510, 512, 516, 520, 522, 526, 530, 534, - 536, 540, 544, 548, 552, 556, 560, 562, 566, 570, - 574, 578, 582, 584, 588, 592, 596, 600, 602, 606, - 610, 614, 618, 620, 624, 626, 630, 632, 636, 638, - 642, 644, 648, 650, 654, 656, 660, 662, 666, 668, - 672, 674, 678, 680, 686, 688, 694, 696, 700, 702, - 706, 708, 710, 712, 714, 716, 718, 720, 722, 724, - 726, 728, 730, 732, 736, 737, 739, 741, 745, 746, - 748, 750, 752, 754, 756, 758, 760, 762, 764, 766, - 768, 770, 772, 774, 776, 778, 782, 784, 787, 788, - 790, 794, 798, 800, 802, 804, 808, 810, 814, 817, - 820, 823, 824, 826, 829, 830, 832, 834, 837, 840, - 848, 854, 862, 870, 876, 886, 897, 905, 914, 917, - 920, 924, 928, 931, 934, 938, 942, 946, 950, 956, - 962, 966, 972, 974, 977, 978, 980, 985, 989, 993, - 997, 1001, 1005, 1009, 1013, 1017, 1022, 1028, 1031, 1034, - 1037, 1046, 1055, 1057, 1061, 1062, 1064, 1065, 1067, 1069, - 1071, 1074, 1076, 1078, 1079, 1081, 1082, 1084}; -#endif // QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO + 1, 1, 1, 4, 3, 5, 1, 2, 4, 4, + 4, 3, 0, 1, 1, 3, 1, 1, 1, 2, + 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 3, 3, 3, 1, 3, 3, 1, 3, + 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, + 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 5, 1, 5, 1, + 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 0, 1, 1, + 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, + 2, 0, 1, 3, 3, 1, 1, 1, 3, 1, + 3, 2, 2, 2, 0, 1, 2, 0, 1, 1, + 2, 2, 7, 5, 7, 7, 5, 9, 10, 7, + 8, 2, 2, 3, 3, 2, 2, 3, 3, 3, + 3, 5, 5, 3, 5, 1, 2, 0, 1, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, + 2, 2, 2, 8, 8, 1, 3, 0, 1, 0, + 1, 1, 1, 2, 1, 1, 0, 1, 0, 1, + 2}; const int QmlJSGrammar::action_default [] = { - 18, 2, 0, 4, 3, 0, 0, 80, 60, 61, - 58, 59, 62, 0, 0, 0, 6, 7, 0, 8, - 9, 0, 10, 0, 0, 11, 0, 16, 17, 81, - 0, 12, 13, 0, 14, 15, 5, 19, 0, 1, - 0, 26, 56, 263, 0, 0, 61, 24, 62, 264, - 27, 20, 0, 0, 0, 57, 0, 41, 40, 39, - 0, 0, 50, 0, 51, 166, 233, 197, 205, 201, - 145, 217, 193, 0, 130, 64, 146, 209, 213, 134, - 163, 144, 149, 129, 183, 170, 0, 70, 71, 67, - 334, 336, 0, 0, 0, 0, 0, 0, 65, 68, - 0, 0, 69, 63, 0, 66, 0, 0, 159, 0, - 0, 146, 165, 148, 147, 0, 0, 0, 161, 162, - 160, 164, 0, 194, 0, 0, 0, 0, 184, 0, - 0, 0, 0, 0, 0, 174, 0, 0, 0, 168, - 169, 167, 172, 176, 175, 173, 171, 186, 185, 187, - 0, 202, 0, 198, 0, 0, 140, 127, 139, 128, - 96, 97, 98, 123, 99, 124, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 125, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 126, 0, 0, 138, 234, 141, 0, 142, 0, 143, - 137, 54, 55, 0, 230, 223, 221, 228, 229, 227, - 226, 232, 225, 224, 222, 231, 218, 0, 206, 0, - 0, 210, 0, 0, 214, 0, 0, 140, 132, 0, - 131, 0, 136, 150, 0, 335, 325, 326, 0, 323, - 0, 324, 0, 327, 241, 248, 247, 255, 243, 0, - 244, 328, 0, 333, 245, 246, 251, 249, 330, 329, - 332, 252, 0, 0, 0, 0, 0, 334, 60, 0, - 336, 61, 235, 277, 62, 0, 0, 0, 0, 0, - 253, 254, 242, 250, 278, 279, 322, 331, 0, 293, - 294, 295, 296, 0, 289, 290, 291, 292, 319, 320, - 0, 0, 0, 0, 0, 282, 283, 239, 237, 199, - 207, 203, 219, 195, 240, 0, 146, 211, 215, 188, - 177, 0, 0, 196, 0, 0, 0, 0, 189, 0, - 0, 0, 0, 0, 181, 179, 182, 180, 178, 191, - 190, 192, 0, 204, 0, 200, 0, 238, 146, 0, - 220, 235, 236, 0, 235, 0, 0, 285, 0, 0, - 0, 287, 0, 208, 0, 0, 212, 0, 0, 216, - 275, 0, 267, 276, 270, 0, 274, 0, 235, 268, - 0, 235, 0, 0, 286, 0, 0, 0, 288, 335, - 325, 0, 0, 327, 0, 321, 0, 311, 0, 0, - 0, 281, 0, 280, 0, 337, 0, 95, 257, 260, - 0, 96, 263, 99, 124, 101, 102, 67, 106, 107, - 60, 108, 111, 65, 68, 61, 235, 62, 69, 114, - 63, 116, 66, 118, 119, 264, 121, 122, 126, 0, - 88, 0, 0, 90, 94, 92, 78, 91, 93, 0, - 89, 77, 258, 256, 134, 135, 140, 0, 133, 0, - 310, 0, 297, 298, 0, 309, 0, 0, 0, 300, - 305, 303, 306, 0, 0, 304, 305, 0, 301, 0, - 302, 259, 308, 0, 259, 307, 0, 312, 313, 0, - 259, 314, 315, 0, 0, 316, 0, 0, 0, 317, - 318, 152, 151, 0, 0, 0, 284, 0, 0, 0, - 299, 82, 0, 0, 86, 72, 0, 74, 84, 0, - 75, 85, 87, 76, 83, 73, 0, 79, 156, 154, - 158, 155, 153, 157, 0, 0, 0, 48, 0, 49, - 0, 52, 53, 47, 42, 43, 0, 0, 0, 0, - 45, 46, 44, 25, 21, 0, 33, 36, 34, 0, - 35, 38, 259, 0, 29, 0, 37, 32, 96, 263, - 99, 124, 101, 102, 67, 106, 107, 60, 108, 111, - 65, 68, 61, 235, 62, 69, 114, 63, 116, 66, - 118, 119, 264, 121, 122, 126, 64, 0, 22, 0, - 28, 23, 30, 31, 272, 265, 0, 273, 269, 0, - 271, 261, 0, 262, 266, 338}; + 0, 0, 0, 21, 0, 169, 236, 200, 208, 204, + 148, 220, 196, 3, 133, 67, 149, 212, 216, 137, + 166, 147, 152, 132, 186, 173, 0, 73, 74, 70, + 337, 63, 339, 0, 0, 0, 0, 0, 0, 68, + 71, 0, 0, 64, 65, 72, 66, 0, 69, 0, + 0, 162, 0, 0, 149, 168, 151, 150, 0, 0, + 0, 164, 165, 163, 167, 0, 197, 0, 0, 0, + 0, 187, 0, 0, 0, 0, 0, 0, 177, 0, + 0, 0, 171, 172, 170, 175, 179, 178, 176, 174, + 189, 188, 190, 0, 205, 0, 201, 0, 0, 143, + 130, 142, 131, 99, 100, 101, 126, 102, 127, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 128, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 129, 0, 0, 141, 237, 144, 0, + 145, 0, 146, 140, 0, 233, 226, 224, 231, 232, + 230, 229, 235, 228, 227, 225, 234, 221, 0, 209, + 0, 0, 213, 0, 0, 217, 0, 0, 143, 135, + 0, 134, 0, 139, 153, 0, 338, 328, 329, 0, + 326, 0, 327, 0, 330, 244, 251, 250, 258, 246, + 0, 247, 331, 0, 336, 248, 249, 254, 252, 333, + 332, 335, 255, 0, 266, 0, 0, 0, 0, 337, + 63, 0, 339, 64, 238, 280, 65, 0, 0, 0, + 267, 0, 0, 256, 257, 0, 245, 253, 281, 282, + 325, 334, 0, 296, 297, 298, 299, 0, 292, 293, + 294, 295, 322, 323, 0, 0, 0, 0, 0, 285, + 286, 242, 240, 202, 210, 206, 222, 198, 243, 0, + 149, 214, 218, 191, 180, 0, 0, 199, 0, 0, + 0, 0, 192, 0, 0, 0, 0, 0, 184, 182, + 185, 183, 181, 194, 193, 195, 0, 207, 0, 203, + 0, 241, 149, 0, 223, 238, 239, 0, 238, 0, + 0, 288, 0, 0, 0, 290, 0, 211, 0, 0, + 215, 0, 0, 219, 278, 0, 270, 279, 273, 0, + 277, 0, 238, 271, 0, 238, 0, 0, 289, 0, + 0, 0, 291, 338, 328, 0, 0, 330, 0, 324, + 0, 314, 0, 0, 0, 284, 0, 283, 0, 340, + 0, 98, 260, 263, 0, 99, 266, 102, 127, 104, + 105, 70, 109, 110, 63, 111, 114, 68, 71, 64, + 238, 65, 72, 117, 66, 119, 69, 121, 122, 267, + 124, 125, 129, 0, 91, 0, 0, 93, 97, 95, + 81, 94, 96, 0, 92, 80, 261, 259, 137, 138, + 143, 0, 136, 0, 313, 0, 300, 301, 0, 312, + 0, 0, 0, 303, 308, 306, 309, 0, 0, 307, + 308, 0, 304, 0, 305, 262, 311, 0, 262, 310, + 0, 315, 316, 0, 262, 317, 318, 0, 0, 319, + 0, 0, 0, 320, 321, 155, 154, 0, 0, 0, + 287, 0, 0, 0, 302, 275, 268, 0, 276, 272, + 0, 274, 264, 0, 265, 269, 85, 0, 0, 89, + 75, 0, 77, 87, 0, 78, 88, 90, 79, 86, + 76, 0, 82, 159, 157, 161, 158, 156, 160, 2, + 5, 0, 7, 6, 0, 1, 83, 61, 62, 0, + 0, 0, 9, 10, 0, 11, 12, 0, 13, 0, + 0, 14, 0, 19, 20, 84, 0, 15, 16, 0, + 17, 18, 8, 22, 0, 4, 0, 29, 59, 0, + 0, 64, 27, 65, 30, 23, 0, 0, 60, 0, + 44, 43, 42, 0, 0, 53, 0, 54, 0, 57, + 58, 0, 0, 0, 51, 0, 52, 0, 55, 56, + 50, 45, 46, 0, 0, 0, 0, 48, 49, 47, + 28, 24, 0, 36, 39, 37, 0, 38, 41, 262, + 0, 32, 0, 40, 35, 99, 266, 102, 127, 104, + 105, 70, 109, 110, 63, 111, 114, 68, 71, 64, + 238, 65, 72, 117, 66, 119, 69, 121, 122, 267, + 124, 125, 129, 67, 0, 25, 0, 31, 26, 33, + 34, 341}; const int QmlJSGrammar::goto_default [] = { - 6, 5, 39, 1, 4, 3, 75, 38, 50, 52, - 51, 597, 41, 565, 566, 249, 244, 248, 250, 247, - 254, 535, 546, 545, 253, 282, 83, 513, 512, 406, - 405, 66, 404, 407, 158, 79, 74, 196, 81, 70, - 195, 76, 82, 108, 80, 65, 85, 84, 319, 72, - 313, 67, 309, 69, 311, 68, 310, 77, 317, 78, - 318, 71, 312, 308, 349, 461, 314, 315, 408, 255, - 246, 245, 257, 283, 256, 261, 280, 281, 410, 409, - 54, 606, 605, 371, 372, 608, 374, 607, 373, 469, - 473, 476, 472, 471, 491, 492, 238, 252, 234, 237, - 251, 259, 258, 0}; + 4, 495, 352, 190, 494, 525, 490, 493, 492, 15, + 524, 534, 536, 535, 614, 527, 582, 583, 185, 189, + 191, 188, 195, 552, 563, 562, 194, 226, 23, 468, + 467, 350, 349, 6, 348, 351, 101, 19, 14, 139, + 21, 10, 138, 16, 22, 51, 20, 5, 25, 24, + 263, 12, 257, 7, 253, 9, 255, 8, 254, 17, + 261, 18, 262, 11, 256, 252, 293, 405, 258, 259, + 196, 187, 186, 198, 227, 197, 202, 223, 224, 354, + 353, 225, 457, 456, 315, 316, 459, 318, 458, 317, + 413, 417, 420, 416, 415, 435, 436, 179, 193, 175, + 178, 192, 200, 199, 0}; const int QmlJSGrammar::action_index [] = { - 7, -92, 389, -92, -10, 343, 168, -92, -92, -92, - -92, -92, -92, 233, 308, 178, -92, -92, 86, -92, - -92, 173, -92, 151, 137, -92, 108, -92, -92, -92, - 184, -92, -92, 105, -92, -92, -92, -92, 82, -92, - 456, -92, -92, -92, 44, 190, 195, -92, -27, -92, - -92, -92, 431, 208, 187, -92, 214, -92, -92, -92, - -15, 224, -92, 764, -92, 109, -92, 8, -47, -78, - 194, -92, 376, 143, -92, -92, 603, 6, 85, 186, - 213, -92, -92, -92, 514, 302, 764, -92, -92, -92, - 237, 1607, 1014, 764, 764, 764, 683, 764, -92, -92, - 764, 764, -92, -92, 764, -92, 764, 764, -92, 764, - 764, 133, 220, -92, -92, 764, 764, 764, -92, -92, - -92, 149, 764, 376, 764, 764, 764, 764, 412, 764, - 764, 764, 764, 764, 764, 302, 764, 764, 764, 131, - 152, 145, 302, 235, 235, 302, 235, 514, 427, 392, - 764, -73, 764, 11, 1519, 764, 764, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, -92, -92, -92, - -92, 94, 764, -92, -92, 91, 78, -92, 764, -92, - -92, -92, -92, 764, -92, -92, -92, -92, -92, -92, - -92, -92, -92, -92, -92, -92, -92, 764, -41, 764, - 764, 45, 37, 764, -92, 1519, 764, 764, -92, 120, - -92, 41, -92, -92, 73, -92, 171, 54, 26, -92, - 258, -92, 52, 1871, -92, -92, -92, -92, -92, 253, - -92, -92, 2, -92, -92, -92, -92, -92, -92, 1871, - -92, -92, 346, 364, 126, 1783, 30, 250, 56, 25, - 2047, 58, 764, -92, 61, 40, 764, 39, 35, 34, - -92, -92, -92, -92, -92, -92, -92, -92, 122, -92, - -92, -92, -92, 128, -92, -92, -92, -92, -92, -92, - 27, 70, 764, 118, 132, -92, -92, 930, -92, 89, - 65, 67, -92, 320, 83, -2, 516, 92, 141, 445, - 235, 192, 764, 312, 764, 764, 764, 764, 445, 764, - 764, 764, 764, 764, 235, 235, 235, 235, 235, 336, - 445, 445, 764, -67, 764, 76, 764, -92, 603, 764, - -92, 764, -4, -37, 764, -12, 1783, -92, 764, 119, - 1783, -92, 764, 3, 764, 764, 50, 46, 764, -92, - 33, 136, 9, -92, -92, 764, -92, 245, 764, -92, - -30, 764, -22, 1783, -92, 764, 117, 1783, -92, -3, - 234, 69, 12, 1871, -23, -92, 1783, -92, 764, 97, - 1783, 20, 1783, -92, 28, 29, -13, -92, -92, 1783, - -21, 280, 18, 372, 81, 764, 1783, 19, -9, 284, - 23, -8, 683, 22, 36, -92, 849, -92, 42, 24, - 49, 764, 48, 21, 764, 32, 764, 5, 10, 764, - -92, 1695, 16, -92, -92, -92, -92, -92, -92, 764, - -92, -92, -92, -92, 193, -92, 764, -57, -92, 1783, - -92, 111, -92, -92, 1783, -92, 764, 114, -16, -92, - 13, -92, 17, 110, 764, -92, 15, 14, -92, -45, - -92, 1783, -92, 116, 1783, -92, 206, -92, -92, 112, - 1783, -7, -92, -20, -14, -92, 205, -54, -18, -92, - -92, -92, -92, 764, 99, 1783, -92, 764, 103, 1783, - -92, -92, 106, 1266, -92, -92, 1098, -92, -92, 1182, - -92, -92, -92, -92, -92, -92, 104, -92, -92, -92, - -92, -92, -92, -92, 60, 64, 174, -92, 764, -92, - 203, -92, -92, 72, 217, 90, 71, 226, 204, 181, - -92, -92, -92, -92, -92, 1431, -92, -92, -92, 274, - -92, -92, 1959, 1350, -92, 79, -92, -92, 323, 80, - 325, 93, 764, 1783, 62, 38, 297, 51, 31, 683, - 57, 66, -92, 849, -92, 68, 43, 74, 764, 75, - 59, 764, 77, 764, 53, 47, 55, 96, -92, 315, - -92, -92, -92, -92, 63, -92, 244, -92, -92, 764, - -92, -92, 252, -92, -92, -92, + 236, 824, 1879, -3, 176, 80, -95, 102, 36, -14, + 266, -95, 337, 90, -95, -95, 528, 100, 78, 344, + 220, -95, -95, -95, 565, 177, 824, -95, -95, -95, + 209, -95, 1697, 1083, 824, 824, 824, 740, 824, -95, + -95, 824, 824, -95, -95, -95, -95, 824, -95, 824, + 824, -95, 824, 824, 136, 183, -95, -95, 824, 824, + 824, -95, -95, -95, 146, 824, 342, 824, 824, 690, + 824, 565, 824, 824, 824, 824, 824, 824, 156, 824, + 824, 824, 134, 124, 84, 232, 255, 261, 260, 218, + 487, 472, 565, 824, 49, 824, 73, 1606, 824, 824, + -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, + -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, + -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, + -95, -95, -95, -95, 137, 824, -95, -95, 63, 35, + -95, 824, -95, -95, 824, -95, -95, -95, -95, -95, + -95, -95, -95, -95, -95, -95, -95, -95, 824, 38, + 824, 824, 70, 62, 824, -95, 1606, 824, 824, -95, + 104, -95, 37, -95, -95, 40, -95, 198, 67, 46, + -95, 168, -95, 45, 1970, -95, -95, -95, -95, -95, + 205, -95, -95, 44, -95, -95, -95, -95, -95, -95, + 1970, -95, -95, 375, -95, 427, 82, 1879, 32, 243, + 59, 53, 2152, 74, 824, -95, 76, 58, 824, 57, + -95, 65, 64, -95, -95, 300, -95, -95, -95, -95, + -95, -95, 79, -95, -95, -95, -95, 77, -95, -95, + -95, -95, -95, -95, 50, 68, 824, 110, 72, -95, + -95, 996, -95, 60, 34, -8, -95, 421, 71, 19, + 582, 61, 92, 420, 287, 249, 824, 304, 824, 824, + 824, 824, 394, 824, 824, 824, 824, 824, 308, 279, + 286, 293, 294, 379, 373, 493, 824, -5, 824, 66, + 824, -95, 657, 824, -95, 824, 54, 30, 824, 33, + 1879, -95, 824, 117, 1879, -95, 824, 69, 824, 824, + 94, 52, 824, -95, 75, 111, 56, -95, -95, 824, + -95, 278, 824, -95, 55, 824, -15, 1879, -95, 824, + 122, 1879, -95, -22, 305, -42, -27, 1970, -51, -95, + 1879, -95, 824, 113, 1879, -1, 1879, -95, 6, 3, + -45, -95, -95, 1879, -32, 409, 14, 424, 107, 824, + 1879, 2, -34, 318, 81, -35, 740, -4, -7, -95, + 912, -95, 0, -12, 21, 824, 41, 20, 824, 43, + 824, 16, 15, 824, -95, 1788, 31, -95, -95, -95, + -95, -95, -95, 824, -95, -95, -95, -95, 269, -95, + 824, 17, -95, 1879, -95, 86, -95, -95, 1879, -95, + 824, 103, 23, -95, 42, -95, 26, 112, 824, -95, + 28, 25, -95, -25, -95, 1879, -95, 101, 1879, -95, + 281, -95, -95, 109, 1879, 9, -95, -10, 11, -95, + 272, -17, 8, -95, -95, -95, -95, 824, 99, 1879, + -95, 824, 106, 1879, -95, 22, -95, 190, -95, -95, + 824, -95, -95, 229, -95, -95, -95, 105, 1257, -95, + -95, 1344, -95, -95, 1170, -95, -95, -95, -95, -95, + -95, 97, -95, -95, -95, -95, -95, -95, -95, -95, + -95, 468, -95, -39, 334, -95, -95, -95, -95, 201, + 359, 194, -95, -95, 88, -95, -95, 202, -95, 207, + 164, -95, 129, -95, -95, -95, 181, -95, -95, 91, + -95, -95, -95, -95, 121, -95, 491, -95, -95, -9, + 225, 170, -95, 7, -95, -95, 477, 264, -95, 126, + -95, -95, -95, 5, 144, -95, 824, -95, 188, -95, + -95, 4, 13, 158, -95, 824, -95, 180, -95, -95, + 1, 133, 27, -33, 155, 127, 163, -95, -95, -95, + -95, -95, 1428, -95, -95, -95, 329, -95, -95, 2061, + 1515, -95, 125, -95, -95, 398, 51, 384, 118, 824, + 1879, 18, 24, 328, 81, 29, 740, 48, 47, -95, + 912, -95, 39, -28, -2, 824, 12, -11, 824, 10, + 824, -20, -24, -13, 115, -95, 395, -95, -95, -95, + -95, -95, - -104, -104, 82, -104, 6, 78, -104, -104, -104, -104, - -104, -104, -104, -104, -104, 28, -104, -104, -104, -104, - -104, 15, -104, 11, -104, -104, -104, -104, -104, -104, - 19, -104, -104, -104, -104, -104, -104, -104, -104, -104, - 343, -104, -104, -104, -104, 27, -104, -104, -104, -104, - -104, -104, 260, -104, 26, -104, -6, -104, -104, -104, - -104, -104, -104, -11, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -56, -104, -104, -104, - -104, -104, -104, -104, -104, -104, 137, -104, -104, -104, - 60, -104, 50, 64, 141, 144, 90, 147, -104, -104, - 126, 106, -104, -104, 109, -104, 105, 110, -104, 182, - 121, -104, -104, -104, -104, 113, 101, 171, -104, -104, - -104, -104, 164, -104, 170, 152, 150, 151, -104, 154, - 99, 155, 161, 81, 55, -104, 57, 66, 63, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - 80, -104, 69, -104, 93, 36, 38, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, 41, -104, -104, -104, -104, -104, -12, -104, - -104, -104, -104, -17, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, 118, -104, 165, - -2, -104, -104, 25, -104, 209, 16, 172, -104, -104, - -104, -104, -104, -104, -104, -104, 17, -104, -104, -104, - 18, -104, -104, -46, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, 56, - -104, -104, 0, 30, -104, -65, -104, 12, -104, -104, - -104, -104, 119, -104, -104, -104, 13, 14, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, 23, -104, -104, -104, -104, 148, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, 7, 178, -104, 179, 188, 245, 191, -104, 133, - 131, 129, 140, 130, -104, -104, -104, -104, -104, -104, - -104, -104, 207, -104, 205, -104, 217, -104, -104, 199, - -104, 70, -104, -104, 65, -104, -10, -104, 45, -104, - -16, -104, 203, -104, 223, 219, -104, -104, 192, -104, - -104, -104, -104, -104, -104, 189, -104, 77, 76, -104, - -104, 72, -104, 2, -104, 47, -104, 49, -104, -104, - 87, -104, -104, 71, -104, -104, 10, -104, 34, -104, - -1, -104, -20, -104, -104, -104, -104, -104, -104, -5, - -104, 48, -104, 53, -104, 73, 3, -104, -104, 39, - -104, -104, 68, -104, -104, -104, 119, -104, -104, -104, - -104, 58, -104, 59, 54, -104, 114, -104, -104, 46, - -104, 44, -104, -104, -104, -104, -104, -104, -104, 43, - -104, -104, -104, -104, -104, -104, 173, -104, -104, -4, - -104, -104, -104, -104, -7, -104, 42, -104, -104, -104, - -104, -104, -49, -104, 40, -104, -40, -104, -104, -104, - -104, -31, -104, -104, 4, -104, -104, -104, -104, -104, - -104, -30, -104, -104, 52, -104, 37, -104, -15, -104, - -104, -104, -104, -13, -104, -68, -104, -3, -104, -63, - -104, -104, -104, -24, -104, -104, 92, -104, -104, -22, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, - -104, -104, -104, -104, -104, -104, -104, -104, 22, -104, - -104, -104, -104, -104, 21, -104, -104, 35, 32, 33, - -104, -104, -104, -104, -104, 256, -104, -104, -104, 8, - -104, -104, -104, 210, -104, -104, -104, -104, 20, -104, - 30, -104, 51, -41, -104, -104, 29, -104, -104, 74, - -104, -104, -104, 1, -104, -104, -104, -104, 31, -104, - 24, 88, -104, 95, -104, -104, -104, -104, -104, 107, - -104, -104, -104, -104, -104, -104, -104, -104, -104, -21, - -104, -104, 84, -104, -104, -104}; + -105, 21, 23, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -45, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 82, -105, -105, -105, + 35, -105, -105, 31, 33, 179, 161, 176, 165, -105, + -105, 183, 182, -105, -105, -105, -105, 140, -105, 143, + 139, -105, 159, 135, -105, -105, -105, -105, 156, 155, + 152, -105, -105, -105, -105, 90, -105, 126, 128, 130, + 160, -105, 169, 115, 87, 89, 124, 97, -105, 73, + 76, 39, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, 168, -105, 108, -105, 80, 74, 70, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, 62, -105, -105, -105, -105, + -105, 55, -105, -105, 66, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, 100, -105, + 148, -31, -105, -105, -33, -105, 206, 37, 103, -105, + -105, -105, -105, -105, -105, -105, -105, 22, -105, -105, + -105, 19, -105, -105, 28, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + 91, -105, -105, 64, -105, 50, -105, 41, -105, 43, + -105, -105, -105, -105, 54, -105, -105, -105, 42, 67, + -105, -105, -105, -105, -105, 4, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 34, -105, -105, -105, + -105, 107, -105, -105, -105, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, 17, 197, -105, 230, 234, + 242, 211, -105, 122, 116, 105, 96, 78, -105, -105, + -105, -105, -105, -105, -105, -105, 188, -105, 215, -105, + 214, -105, -105, 203, -105, 153, -105, -105, 273, -105, + 5, -105, 3, -105, 12, -105, 217, -105, 223, 190, + -105, -105, 187, -105, -105, -105, -105, -105, -105, 238, + -105, 129, 186, -105, -105, 189, -105, 52, -105, 53, + -105, 56, -105, -105, 137, -105, -105, 98, -105, -105, + 40, -105, 45, -105, 44, -105, 59, -105, -105, -105, + -105, -105, -105, 61, -105, 57, -105, 60, -105, 109, + 68, -105, -105, 46, -105, -105, 150, -105, -105, -105, + 29, -105, -105, -105, -105, 0, -105, 32, 86, -105, + 123, -105, -105, -6, -105, -26, -105, -105, -105, -105, + -105, -105, -105, -24, -105, -105, -105, -105, -105, -105, + 95, -105, -105, 16, -105, -105, -105, -105, 2, -105, + 8, -105, -105, -105, -105, -105, -19, -105, 75, -105, + -38, -105, -105, -105, -105, -17, -105, -105, -30, -105, + -105, -105, -105, -105, -105, -58, -105, -105, 58, -105, + 51, -105, 49, -105, -105, -105, -105, 171, -105, 72, + -105, 65, -105, 63, -105, -105, -105, -105, -105, -105, + 38, -105, -105, 184, -105, -105, -105, -105, 47, -105, + -105, 147, -105, -105, 48, -105, -105, -105, -105, -105, + -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, + -105, 88, -105, 71, 85, -105, -105, -105, -105, -105, + -105, 1, -105, -105, -105, -105, -105, -4, -105, 6, + -105, -105, -105, -105, -105, -105, 7, -105, -105, -105, + -105, -105, -105, -105, -105, -105, 369, -105, -105, -105, + 10, -105, -105, -105, -105, -105, 278, -105, -105, -22, + -105, -105, -105, -105, -105, -105, 69, -105, -105, -105, + -105, -105, -105, -105, -105, 9, -105, -105, -105, -105, + -105, 24, -105, -105, 11, 18, 25, -105, -105, -105, + -105, -105, 290, -105, -105, -105, 36, -105, -105, -105, + 210, -105, -105, -105, -105, 30, -105, 26, -105, 79, + 27, -105, -105, 13, -105, -105, 77, -105, -105, -105, + 20, -105, -105, -105, -105, 14, -105, 15, 117, -105, + 104, -105, -105, -105, -105, -105, 81, -105, -105, -105, + -105, -105}; const int QmlJSGrammar::action_info [] = { - 152, 150, 543, 458, 192, 152, 498, 150, 217, 122, - 480, 344, 122, 494, 61, 490, 496, 470, 474, 490, - 474, 481, 474, 449, 354, -123, -104, 307, 398, -112, - -90, 381, 395, 390, 453, 439, 402, 441, 383, -120, - 385, 503, 451, -94, 223, 393, 507, 217, 356, -93, - 375, 342, 362, 368, 490, -117, -115, 286, -90, 351, - 466, 398, 240, 396, -112, 459, 307, 398, 464, -104, - 507, 503, 490, -94, 307, -93, 466, 322, 2, 466, - 609, -115, -117, 507, -120, 243, 242, -123, -80, 503, - 322, 346, 490, 536, 362, 2, 390, 23, 548, 198, - 0, 232, 192, 301, 599, 192, 302, 192, 544, 236, - 56, 192, 192, 342, 516, 40, 0, 0, 493, 0, - 477, 0, 192, 484, 192, 192, 192, 192, 192, 392, - 0, 551, 494, 0, 0, 219, 0, 0, 200, 220, - 603, 602, 299, 298, 377, 344, 0, 20, 19, 109, - 193, 192, 600, 0, 299, 298, 0, 400, 0, 505, - 110, 115, 517, 509, 527, 478, 35, 34, 615, 28, - 27, 109, 463, 462, 468, 113, 230, 387, 304, 360, - 8, 538, 110, 292, 291, 109, 114, 299, 298, 297, - 296, 364, 109, 306, 305, 365, 110, 378, 32, 31, - 8, 225, 8, 110, 202, 201, 116, 8, 225, 154, - 8, 192, 117, 8, 192, 555, 8, 9, 12, 8, - 226, 8, 227, 23, 57, 115, 30, 226, 155, 456, - 156, 63, 115, 57, 8, 539, 537, 9, 12, 9, - 12, 40, 0, 57, 9, 12, 57, 9, 12, 0, - 9, 12, 612, 9, 12, 8, 9, 12, 9, 12, - 136, 192, 137, 8, 542, 541, 8, 488, 487, 59, - 116, 9, 12, 138, 8, 0, 117, 116, 59, 8, - 58, 8, 192, 117, 0, 64, 62, 8, 59, 58, - 0, 59, 9, 12, 17, 16, 0, 0, 0, 58, - 9, 12, 58, 9, 12, 613, 611, 40, 0, 8, - 0, 9, 12, 8, 285, 284, 9, 12, 9, 12, - -334, 0, 15, 23, 9, 12, 8, 136, 0, 137, - 324, 325, 0, -334, 0, 285, 284, 0, 324, 325, - 138, 290, 289, 0, 8, 0, 9, 12, 0, 0, - 9, 12, 8, 0, 8, 24, 0, 326, 327, 329, - 330, 0, 0, 9, 12, 326, 327, 0, 331, 25, - 22, 332, 8, 333, 11, 8, 0, 0, 0, 0, - 0, 9, 12, 0, 290, 289, 295, 294, 0, 9, - 12, 9, 12, 8, 124, 125, 0, 21, 0, 0, - 10, 8, 11, 0, 0, 0, 0, 290, 289, 9, - 12, 0, 9, 12, 0, 129, 130, 0, 8, 0, - 0, 126, 127, 131, 132, 295, 294, 133, 10, 134, - 9, 12, 0, 295, 294, 129, 130, 0, 9, 12, - 0, 44, 0, 131, 132, 0, 0, 133, 11, 134, - 129, 130, 0, 45, 13, 9, 12, 0, 131, 132, - 8, 0, 133, 0, 134, 0, 44, 0, 329, 330, - 0, 0, 0, 0, 10, 0, 0, 331, 45, 0, - 332, 0, 333, 0, 0, 8, 553, 0, 0, 0, - 11, 0, 0, 0, 0, 0, 0, 46, 48, 0, - 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, - 0, 47, 0, 0, 43, 11, 10, 0, 0, 204, - 0, 0, 46, 48, 0, 0, 0, 0, 0, 205, - 49, 0, 0, 206, 0, 0, 0, 129, 130, 43, - 0, 10, 207, 0, 208, 131, 132, 358, 0, 133, - 0, 134, 0, 0, 0, 209, 0, 210, 113, 0, - 0, 0, 0, 0, 0, 211, 0, 0, 212, 114, - 0, 0, 0, 0, 213, 0, 0, 0, 0, 0, - 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 204, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 205, 0, 0, 0, - 206, 0, 0, 0, 0, 0, 0, 0, 0, 207, - 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 209, 0, 210, 113, 0, 0, 0, 0, - 0, 0, 211, 0, 0, 212, 114, 0, 0, 0, - 0, 213, 0, 0, 0, 0, 0, 214, 0, 0, + -97, 342, 251, -115, 339, -118, 337, -96, 410, -107, + 395, 385, 451, 383, 334, 346, 447, -123, 336, -120, + -83, -126, 434, 397, 410, -107, 440, 568, -118, 438, + 424, 418, 425, 418, 544, 565, 560, 561, 393, 460, + 334, 434, 553, 442, 434, 327, -96, 418, -120, 491, + -123, 451, 447, 434, -97, -115, 414, 539, -126, 312, + 251, 266, 135, 306, 95, 342, 340, 266, 251, 164, + 288, 141, 158, 288, 65, 181, 177, 402, 184, 290, + 295, 403, 286, 408, 93, 491, 93, 329, -93, 342, + 434, 298, 319, 300, 410, 143, 306, 173, 135, 230, + 451, 447, 158, 65, 246, 135, 183, 135, 428, 135, + 0, 135, 135, 471, 135, 437, 325, 286, 135, 321, + 52, 135, 421, 616, 52, 135, 245, 95, 160, 438, + 135, 53, 161, 250, 249, 53, 509, 0, 241, 240, + 236, 235, 308, 243, 242, 135, 309, 407, 406, 506, + 505, 546, 521, 520, 526, 540, 540, 482, 58, 449, + 171, 472, 540, 412, 52, 555, 453, 422, 243, 242, + 248, 617, 322, 344, 52, 53, 621, 304, 56, 243, + 242, 79, 331, 80, 31, 53, 620, 619, 135, 57, + 514, 513, 31, 136, 81, 58, 135, 31, 463, 540, + 542, 542, 79, 59, 80, 547, 545, 542, 0, 60, + 31, 541, 541, 135, 0, 81, 0, 0, 541, 556, + 554, 43, 44, 31, 0, 518, 517, 31, 0, 43, + 44, 31, 58, 0, 43, 44, 31, 0, 31, 0, + 59, 559, 558, 79, 542, 80, 60, 43, 44, 550, + 549, 464, 462, 516, 31, 541, 81, 79, 31, 80, + 43, 44, 503, 502, 43, 44, 229, 228, 43, 44, + 81, 572, 31, 43, 44, 43, 44, 59, 31, 509, + 79, 97, 80, 60, 166, 79, 79, 80, 80, 135, + 501, 43, 44, 81, 0, 43, 44, 526, 81, 81, + 98, 31, 99, 167, 79, 400, 80, 31, 0, 43, + 44, 79, 79, 80, 80, 43, 44, 81, 79, 79, + 80, 80, 268, 269, 81, 81, 3, 2, 1, 31, + 0, 81, 81, 79, 31, 80, 0, 135, 43, 44, + 0, 0, 432, 431, 43, 44, 81, 31, 0, 270, + 271, 0, 0, 0, -337, 67, 68, 31, 0, 166, + 67, 68, 526, 31, -337, 0, 43, 44, 0, 0, + 0, 43, 44, 0, 509, 0, 0, 0, 167, 0, + 168, 0, 69, 70, 43, 44, 0, 69, 70, 0, + 229, 228, 0, 498, 43, 44, 273, 274, 0, 0, + 43, 44, 273, 274, 31, 275, 510, 0, 276, 0, + 277, 275, 0, 31, 276, 0, 277, 273, 274, 497, + 511, 508, 0, 0, 31, 0, 275, 31, 0, 276, + 0, 277, 0, 0, 0, 0, 234, 233, 31, 268, + 269, 43, 44, 273, 274, 239, 238, 0, 507, 0, + 43, 44, 275, 31, 498, 276, 31, 277, 0, 234, + 233, 43, 44, 0, 43, 44, 270, 271, 0, 0, + 234, 233, 0, 0, 0, 43, 44, 0, 0, 0, + 497, 0, 0, 0, 0, 239, 238, 529, 239, 238, + 43, 44, 0, 43, 44, 72, 73, 31, 0, 530, + 0, 529, 0, 74, 75, 0, 31, 76, 0, 77, + 72, 73, 0, 530, 0, 0, 273, 274, 74, 75, + 31, 0, 76, 0, 77, 275, 0, 498, 276, 0, + 277, 145, 570, 499, 43, 44, 498, 0, 0, 0, + 0, 146, 0, 531, 533, 147, 532, 0, 0, 0, + 498, 220, 0, 497, 148, 0, 149, 531, 533, 0, + 204, 0, 497, 0, 0, 220, 0, 150, 0, 151, + 56, 0, 0, 0, 204, 0, 497, 152, 0, 0, + 153, 57, 0, 0, 0, 145, 154, 0, 72, 73, + 0, 0, 155, 0, 0, 146, 74, 75, 0, 147, + 76, 0, 77, 0, 0, 0, 0, 156, 148, 0, + 149, 0, 0, 302, 0, 0, 0, 0, 0, 0, + 0, 150, 0, 151, 56, 0, 0, 0, 0, 0, + 0, 152, 0, 0, 153, 57, 0, 0, 0, 0, + 154, 0, 0, 0, 0, 0, 155, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 145, 156, 0, 0, 0, 0, 0, 0, 0, 0, + 146, 0, 0, 0, 147, 0, 0, 0, 0, 0, + 0, 0, 0, 148, 0, 149, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 150, 0, 151, 56, + 0, 26, 27, 28, 0, 0, 152, 0, 0, 153, + 57, 0, 30, 0, 0, 154, 0, 0, 0, 31, + 0, 155, 0, 32, 33, 0, 34, 0, 0, 0, + 35, 0, 36, 37, 38, 0, 156, 40, 0, 0, + 0, 41, 0, 42, 0, 0, 0, 0, 0, 0, + 0, 0, 27, 28, 0, 45, 43, 44, 0, 46, + 0, 47, 30, 49, 0, 50, 0, 0, 0, 31, + 39, 48, 29, 32, 33, 0, 34, 0, 0, 0, + 0, 0, 0, 37, 0, 0, 0, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 45, 43, 44, 0, 46, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 39, 48, 29, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 27, 28, 0, 0, + 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, + 0, 0, 0, 31, 0, 0, 0, 32, 33, 0, + 34, 0, 0, 0, 35, 0, 36, 37, 38, 0, + 0, 40, 0, 0, 0, 41, 0, 42, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 43, 44, 0, 46, 0, 47, 0, 49, 0, 50, + 0, 0, 0, 0, 39, 48, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -116, + 0, 0, 0, 26, 27, 28, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, + 0, 31, 0, 0, 0, 32, 33, 0, 34, 0, + 0, 0, 35, 0, 36, 37, 38, 0, 0, 40, + 0, 0, 0, 41, 0, 42, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 45, 43, 44, + 0, 46, 0, 47, 0, 49, 0, 50, 0, 0, + 0, 0, 39, 48, 29, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, 27, 28, + 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, + 0, 0, 0, 0, 0, 31, 0, 0, 0, 32, + 33, 0, 34, 0, 0, 0, 35, 0, 36, 37, + 38, 0, 0, 40, 0, 0, 0, 41, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 45, 43, 44, 0, 46, 0, 47, 0, 49, + 265, 50, 0, 0, 0, 0, 39, 48, 29, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 469, 0, 0, 26, 27, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, + 0, 0, 31, 0, 0, 0, 32, 33, 0, 34, + 0, 0, 0, 35, 0, 36, 37, 38, 0, 0, + 40, 0, 0, 0, 41, 0, 42, 0, 0, 470, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 43, + 44, 0, 46, 0, 47, 0, 49, 0, 50, 0, + 0, 0, 0, 39, 48, 29, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 477, 0, + 0, 26, 27, 28, 0, 0, 0, 0, 0, 0, + 0, 0, 30, 0, 0, 0, 0, 0, 0, 31, + 0, 0, 0, 32, 33, 0, 34, 0, 0, 0, + 35, 0, 36, 37, 38, 0, 0, 40, 0, 0, + 0, 41, 0, 42, 0, 0, 478, 0, 0, 0, + 0, 0, 0, 0, 0, 45, 43, 44, 0, 46, + 0, 47, 0, 49, 0, 50, 0, 0, 0, 0, + 39, 48, 29, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 477, 0, 0, 26, 27, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 30, + 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, + 32, 33, 0, 34, 0, 0, 0, 35, 0, 36, + 37, 38, 0, 0, 40, 0, 0, 0, 41, 0, + 42, 0, 0, 480, 0, 0, 0, 0, 0, 0, + 0, 0, 45, 43, 44, 0, 46, 0, 47, 0, + 49, 0, 50, 0, 0, 0, 0, 39, 48, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 87, 88, 0, 0, 0, - 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, - 0, 0, 8, 0, 0, 0, 91, 92, 0, 93, - 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, - 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 102, 9, - 12, 0, 103, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 98, 105, 89, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 86, 87, 88, 0, 0, - 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, - 0, 0, 0, 8, 0, 0, 0, 91, 92, 0, - 93, 0, 0, 0, 94, 0, 95, 96, 97, 0, - 0, 99, 0, 0, 0, 100, 0, 101, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, - 9, 12, 0, 103, 0, 104, 0, 106, 0, 107, - 0, 0, 0, 0, 98, 105, 89, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -113, 0, 0, 0, - 86, 87, 88, 0, 0, 0, 0, 0, 0, 0, - 0, 90, 0, 0, 0, 0, 0, 0, 8, 0, - 0, 0, 91, 92, 0, 93, 0, 0, 0, 94, - 0, 95, 96, 97, 0, 0, 99, 0, 0, 0, - 100, 0, 101, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 102, 9, 12, 0, 103, 0, - 104, 0, 106, 0, 107, 0, 0, 0, 0, 98, - 105, 89, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 87, 88, 0, 0, 0, 0, 0, 0, - 0, 0, 90, 0, 0, 0, 0, 0, 0, 8, - 0, 0, 0, 91, 92, 0, 93, 0, 0, 0, - 94, 0, 95, 96, 97, 0, 0, 99, 0, 0, - 0, 100, 0, 101, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 102, 9, 12, 0, 103, - 0, 104, 0, 106, 321, 107, 0, 0, 0, 0, - 98, 105, 89, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 514, 0, 0, 86, 87, 88, 0, 0, - 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, - 0, 0, 0, 8, 0, 0, 0, 91, 92, 0, - 93, 0, 0, 0, 94, 0, 95, 96, 97, 0, - 0, 99, 0, 0, 0, 100, 0, 101, 0, 0, - 515, 0, 0, 0, 0, 0, 0, 0, 0, 102, - 9, 12, 0, 103, 0, 104, 0, 106, 0, 107, - 0, 0, 0, 0, 98, 105, 89, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 514, 0, 0, 86, - 87, 88, 0, 0, 0, 0, 0, 0, 0, 0, - 90, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 91, 92, 0, 93, 0, 0, 0, 94, 0, - 95, 96, 97, 0, 0, 99, 0, 0, 0, 100, - 0, 101, 0, 0, 520, 0, 0, 0, 0, 0, - 0, 0, 0, 102, 9, 12, 0, 103, 0, 104, - 0, 106, 0, 107, 0, 0, 0, 0, 98, 105, - 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 522, 0, 0, 86, 87, 88, 0, 0, 0, 0, - 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, - 0, 8, 0, 0, 0, 91, 92, 0, 93, 0, - 0, 0, 94, 0, 95, 96, 97, 0, 0, 99, - 0, 0, 0, 100, 0, 101, 0, 0, 523, 0, - 0, 0, 0, 0, 0, 0, 0, 102, 9, 12, - 0, 103, 0, 104, 0, 106, 0, 107, 0, 0, - 0, 0, 98, 105, 89, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 522, 0, 0, 86, 87, 88, - 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, - 0, 0, 0, 0, 0, 8, 0, 0, 0, 91, - 92, 0, 93, 0, 0, 0, 94, 0, 95, 96, - 97, 0, 0, 99, 0, 0, 0, 100, 0, 101, - 0, 0, 525, 0, 0, 0, 0, 0, 0, 0, - 0, 102, 9, 12, 0, 103, 0, 104, 0, 106, - 0, 107, 0, 0, 0, 0, 98, 105, 89, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 514, 0, - 0, 86, 87, 88, 0, 0, 0, 0, 0, 0, - 0, 0, 90, 0, 0, 0, 0, 0, 0, 8, - 0, 0, 0, 91, 92, 0, 93, 0, 0, 0, - 94, 0, 95, 96, 97, 0, 0, 99, 0, 0, - 0, 100, 0, 101, 0, 0, 515, 0, 0, 11, - 0, 0, 0, 0, 0, 102, 9, 12, 0, 103, - 0, 104, 0, 106, 0, 107, 0, 0, 0, 0, - 98, 105, 89, 0, 0, 10, 0, 0, 0, 0, - 0, 0, 86, 87, 88, 0, 0, 0, 0, 0, - 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, - 8, 269, 0, 0, 562, 563, 0, 93, 0, 0, - 0, 94, 0, 95, 96, 97, 0, 0, 99, 0, - 0, 0, 100, 0, 101, 0, 0, 0, 0, 0, - 0, 0, 273, 0, 0, 0, 102, 9, 12, 0, - 103, 0, 104, 0, 106, 0, 107, 0, 0, 0, - 0, 98, 105, 89, 0, 264, 0, 564, 0, 0, - 0, 0, 0, 160, 161, 162, 0, 0, 164, 166, - 167, 0, 0, 168, 0, 169, 0, 0, 0, 171, - 172, 173, 0, 0, 0, 0, 0, 0, 8, 174, - 175, 176, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 177, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 180, 0, - 0, 0, 0, 0, 0, 9, 12, 181, 182, 183, - 0, 185, 186, 187, 188, 189, 190, 0, 0, 178, - 184, 170, 163, 165, 179, 0, 0, 0, 0, 0, - 0, 160, 161, 162, 0, 0, 164, 166, 167, 0, - 0, 168, 0, 169, 0, 0, 0, 171, 172, 173, - 0, 0, 0, 0, 0, 0, 443, 174, 175, 176, + 0, 0, 469, 0, 0, 26, 27, 28, 0, 0, + 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, + 0, 0, 0, 31, 0, 0, 0, 32, 33, 0, + 34, 0, 0, 0, 35, 0, 36, 37, 38, 0, + 0, 40, 0, 0, 0, 41, 0, 42, 0, 0, + 475, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 43, 44, 0, 46, 0, 47, 0, 49, 0, 50, + 0, 0, 0, 0, 39, 48, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, + 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 30, 0, 0, 0, 0, 0, 0, 31, 211, 0, + 0, 579, 580, 0, 34, 0, 0, 0, 35, 0, + 36, 37, 38, 0, 0, 40, 0, 0, 0, 41, + 0, 42, 0, 0, 0, 0, 0, 0, 0, 215, + 0, 0, 0, 45, 43, 44, 0, 46, 0, 47, + 0, 49, 0, 50, 0, 0, 0, 0, 39, 48, + 29, 0, 206, 0, 581, 0, 0, 0, 0, 0, + 0, 0, 0, 469, 0, 0, 26, 27, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, + 0, 0, 0, 0, 31, 0, 0, 0, 32, 33, + 0, 34, 0, 0, 0, 35, 0, 36, 37, 38, + 0, 0, 40, 0, 0, 0, 41, 0, 42, 0, + 0, 470, 0, 0, 498, 0, 0, 0, 0, 0, + 45, 43, 44, 0, 46, 0, 47, 0, 49, 0, + 50, 0, 0, 0, 0, 39, 48, 29, 0, 0, + 497, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 103, 104, 105, 0, 0, 107, 109, 110, 0, 0, + 111, 0, 112, 0, 0, 0, 114, 115, 116, 0, + 0, 0, 0, 0, 0, 31, 117, 118, 119, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 177, 0, 0, 0, 444, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, - 0, 0, 448, 445, 447, 181, 182, 183, 0, 185, - 186, 187, 188, 189, 190, 0, 0, 178, 184, 170, - 163, 165, 179, 0, 0, 0, 0, 0, 0, 160, - 161, 162, 0, 0, 164, 166, 167, 0, 0, 168, - 0, 169, 0, 0, 0, 171, 172, 173, 0, 0, - 0, 0, 0, 0, 443, 174, 175, 176, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 177, 0, - 0, 0, 444, 0, 0, 0, 0, 0, 0, 0, - 446, 0, 0, 0, 180, 0, 0, 0, 0, 0, - 448, 445, 447, 181, 182, 183, 0, 185, 186, 187, - 188, 189, 190, 0, 0, 178, 184, 170, 163, 165, - 179, 0, 0, 0, 0, 0, 0, 262, 0, 0, - 0, 0, 263, 0, 86, 87, 88, 265, 0, 0, - 0, 0, 0, 0, 266, 90, 0, 0, 0, 0, - 0, 0, 268, 269, 0, 0, 270, 92, 0, 93, - 0, 0, 0, 94, 0, 95, 96, 97, 0, 0, - 99, 0, 0, 0, 100, 0, 101, 0, 0, 0, - 0, 0, 272, 0, 273, 0, 0, 0, 102, 271, - 274, 275, 103, 276, 104, 277, 106, 49, 107, 278, - 279, 0, 0, 98, 105, 89, 43, 264, 0, 0, - 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, - 263, 0, 86, 87, 88, 265, 0, 0, 0, 0, - 0, 0, 266, 267, 0, 0, 0, 0, 0, 0, - 268, 269, 0, 0, 270, 92, 0, 93, 0, 0, - 0, 94, 0, 95, 96, 97, 0, 0, 99, 0, - 0, 0, 100, 0, 101, 0, 0, 0, 0, 0, - 272, 0, 273, 0, 0, 0, 102, 271, 274, 275, - 103, 276, 104, 277, 106, 49, 107, 278, 279, 0, - 0, 98, 105, 89, 43, 264, 0, 0, 0, 0, - 0, 0, 0, 568, 161, 162, 0, 0, 570, 166, - 572, 87, 88, 573, 0, 169, 0, 0, 0, 171, - 575, 576, 0, 0, 0, 0, 0, 0, 577, 578, - 175, 176, 270, 92, 0, 93, 0, 0, 0, 94, - 0, 95, 579, 97, 0, 0, 581, 0, 0, 0, - 100, 0, 101, 0, 0, 0, 0, 0, 583, 0, - 273, 0, 0, 0, 585, 582, 584, 586, 587, 588, - 104, 590, 591, 592, 593, 594, 595, 0, 0, 580, - 589, 574, 569, 571, 179, 0, 0, 0, 0, 0, - 0, 411, 161, 162, 0, 0, 413, 166, 415, 87, - 88, 416, 0, 169, 0, 0, 0, 171, 418, 419, - 0, 0, 0, 0, 0, 0, 420, 421, 175, 176, - 270, 92, 0, 93, 0, 0, 0, 94, 0, 95, - 422, 97, 0, 0, 424, 0, 0, 0, 100, 0, - 101, 0, -259, 0, 0, 0, 426, 0, 273, 0, - 0, 0, 428, 425, 427, 429, 430, 431, 104, 433, - 434, 435, 436, 437, 438, 0, 0, 423, 432, 417, - 412, 414, 179, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, + 0, 0, 43, 44, 124, 125, 126, 0, 128, 129, + 130, 131, 132, 133, 0, 0, 121, 127, 113, 106, + 108, 122, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 103, 104, 105, 0, 0, 107, 109, 110, 0, + 0, 111, 0, 112, 0, 0, 0, 114, 115, 116, + 0, 0, 0, 0, 0, 0, 387, 117, 118, 119, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 120, 0, 0, 0, 388, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, + 0, 0, 392, 389, 391, 124, 125, 126, 0, 128, + 129, 130, 131, 132, 133, 0, 0, 121, 127, 113, + 106, 108, 122, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 103, 104, 105, 0, 0, 107, 109, 110, + 0, 0, 111, 0, 112, 0, 0, 0, 114, 115, + 116, 0, 0, 0, 0, 0, 0, 387, 117, 118, + 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 120, 0, 0, 0, 388, 0, 0, 0, 0, + 0, 0, 0, 390, 0, 0, 0, 123, 0, 0, + 0, 0, 0, 392, 389, 391, 124, 125, 126, 0, + 128, 129, 130, 131, 132, 133, 0, 0, 121, 127, + 113, 106, 108, 122, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 203, 0, 0, 0, 0, 205, 0, + 26, 27, 28, 207, 0, 0, 0, 0, 0, 0, + 208, 30, 0, 0, 0, 0, 0, 0, 210, 211, + 0, 0, 212, 33, 0, 34, 0, 0, 0, 35, + 0, 36, 37, 38, 0, 0, 40, 0, 0, 0, + 41, 0, 42, 0, 0, 0, 0, 0, 214, 0, + 215, 0, 0, 0, 45, 213, 216, 217, 46, 218, + 47, 219, 49, 220, 50, 221, 222, 0, 0, 39, + 48, 29, 204, 206, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 203, 0, 0, 0, 0, 205, + 0, 26, 27, 28, 207, 0, 0, 0, 0, 0, + 0, 208, 209, 0, 0, 0, 0, 0, 0, 210, + 211, 0, 0, 212, 33, 0, 34, 0, 0, 0, + 35, 0, 36, 37, 38, 0, 0, 40, 0, 0, + 0, 41, 0, 42, 0, 0, 0, 0, 0, 214, + 0, 215, 0, 0, 0, 45, 213, 216, 217, 46, + 218, 47, 219, 49, 220, 50, 221, 222, 0, 0, + 39, 48, 29, 204, 206, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 585, 104, 105, 0, 0, + 587, 109, 589, 27, 28, 590, 0, 112, 0, 0, + 0, 114, 592, 593, 0, 0, 0, 0, 0, 0, + 594, 595, 118, 119, 212, 33, 0, 34, 0, 0, + 0, 35, 0, 36, 596, 38, 0, 0, 598, 0, + 0, 0, 41, 0, 42, 0, 0, 0, 0, 0, + 600, 0, 215, 0, 0, 0, 602, 599, 601, 603, + 604, 605, 47, 607, 608, 609, 610, 611, 612, 0, + 0, 597, 606, 591, 586, 588, 122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 355, 104, 105, 0, + 0, 357, 109, 359, 27, 28, 360, 0, 112, 0, + 0, 0, 114, 362, 363, 0, 0, 0, 0, 0, + 0, 364, 365, 118, 119, 212, 33, 0, 34, 0, + 0, 0, 35, 0, 36, 366, 38, 0, 0, 368, + 0, 0, 0, 41, 0, 42, 0, -262, 0, 0, + 0, 370, 0, 215, 0, 0, 0, 372, 369, 371, + 373, 374, 375, 47, 377, 378, 379, 380, 381, 382, + 0, 0, 367, 376, 361, 356, 358, 122, 0, 0, + 0, 0, 0, 0, 0, 0, 0, - 506, 499, 504, 300, 73, 510, 288, 524, 203, 521, - 610, 36, 508, 370, 216, 60, 352, 29, 389, 199, - 567, 26, 260, 239, 241, 33, 288, 300, 486, 222, - 489, 229, 604, 534, 18, 235, 293, 540, 303, 550, - 489, 552, 547, 497, 475, 235, 486, 482, 403, 399, - 479, 191, 361, 549, 288, 483, 224, 467, 357, 293, - 359, 465, 386, 452, 460, 495, 235, 401, 500, 197, - 384, 300, 194, 486, 450, 489, 442, 440, 397, 526, - 352, 511, 485, 370, 7, 352, 37, 352, 7, 14, - 604, 352, 111, 239, 233, 111, 111, 501, 111, 157, - 0, 146, 139, 454, 111, 0, 455, 111, 141, 454, - 111, 140, 455, 7, 111, 601, 233, 388, 0, 519, - 153, 111, 111, 518, 260, 454, 159, 145, 455, 111, - 355, 501, 0, 151, 352, 353, 111, 382, 502, 260, - 111, 380, 111, 0, 119, 142, 111, 111, 501, 532, - 111, 111, 533, 502, 111, 111, 118, 502, 287, 111, - 0, 379, 111, 0, 0, 121, 614, 111, 394, 531, - 111, 111, 111, 218, 111, 336, 338, 335, 111, 334, - 233, 111, 111, 391, 528, 111, 337, 529, 111, 316, - 530, 111, 111, 111, 320, 111, 111, 148, 149, 147, - 135, 143, 111, 197, 197, 111, 111, 144, 0, 231, - 457, 111, 111, 123, 120, 157, 596, 128, 598, 111, - 111, 0, 221, 111, 320, 320, 112, 328, 323, 111, - 348, 0, 111, 348, 320, 320, 339, 320, 320, 341, - 348, 511, 159, 228, 111, 320, 111, 0, 111, 320, - 0, 320, 376, 320, 0, 369, 0, 345, 348, 363, - 348, 343, 350, 320, 111, 320, 7, 53, 0, 320, - 554, 559, 556, 558, 560, 557, 561, 0, 0, 0, - 347, 366, 367, 0, 42, 55, 111, 0, 0, 0, - 0, 320, 0, 340, 0, 0, 0, 0, 0, 0, + 165, 543, 163, 430, 409, 512, 303, 301, 386, 394, + 504, 411, 557, 455, 305, 515, 519, 430, 404, 551, + 569, 144, 176, 296, 13, 489, 314, 384, 182, 244, + 201, 180, 296, 433, 567, 237, 481, 247, 439, 232, + 170, 566, 341, 244, 176, 430, 345, 564, 343, 429, + 433, 584, 333, 423, 328, 176, 330, 296, 332, 237, + 441, 347, 426, 396, 466, 454, 232, 443, 452, 237, + 244, 461, 548, 232, 450, 419, 444, 134, 427, 522, + 479, 476, 54, 0, 0, 433, 84, 0, 142, 100, + 496, 0, 618, 201, 496, 137, 523, 496, 500, 157, + 201, 0, 0, 140, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 398, 102, 54, 399, 0, 54, + 82, 54, 54, 83, 174, 54, 282, 174, 140, 54, + 54, 445, 54, 54, 401, 86, 140, 87, 314, 54, + 54, 66, 172, 54, 281, 89, 180, 54, 54, 446, + 260, 54, 54, 280, 174, 264, 296, 159, 54, 54, + 54, 96, 445, 85, 279, 54, 54, 54, 446, 54, + 278, 54, 88, 54, 448, 71, 474, 90, 54, 91, + 473, 64, 54, 54, 446, 488, 54, 398, 445, 296, + 399, 54, 296, 455, 231, 54, 338, 63, 54, 54, + 62, 61, 54, 54, 54, 55, 484, 162, 54, 92, + 485, 54, 54, 398, 323, 100, 399, 78, 0, 613, + 297, 615, 54, 94, 483, 54, 54, 487, 486, 0, + 292, 54, 0, 292, 335, 264, 264, 0, 264, 0, + 54, 102, 169, 466, 287, 264, 292, 0, 0, 267, + 0, 264, 313, 324, 54, 311, 326, 292, 54, 264, + 54, 285, 264, 264, 0, 264, 54, 465, 294, 289, + 0, 264, 0, 54, 0, 307, 296, 54, 264, 291, + 272, 292, 264, 310, 283, 54, 264, 496, 537, 0, + 264, 571, 284, 576, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 320, 528, 538, 0, 0, 573, 575, + 577, 574, 578, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 496, 537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, - 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 42, 55, 0, + 0, 0, 0, 0, 0, 528, 538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -983,170 +609,179 @@ const int QmlJSGrammar::action_info [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0}; + 0, 0, 0, 0}; const int QmlJSGrammar::action_check [] = { - 78, 48, 29, 60, 8, 78, 60, 48, 2, 1, - 55, 78, 1, 20, 29, 33, 36, 33, 5, 33, - 5, 7, 5, 7, 61, 7, 7, 36, 36, 7, - 7, 61, 55, 36, 55, 7, 16, 8, 60, 7, - 31, 36, 55, 7, 7, 33, 36, 2, 60, 7, - 17, 48, 2, 7, 33, 7, 7, 55, 7, 61, - 36, 36, 8, 7, 7, 7, 36, 36, 7, 7, - 36, 36, 33, 7, 36, 7, 36, 1, 88, 36, - 17, 7, 7, 36, 7, 33, 60, 7, 33, 36, - 1, 8, 33, 29, 2, 88, 36, 15, 8, 8, - -1, 60, 8, 76, 8, 8, 36, 8, 36, 36, - 66, 8, 8, 48, 8, 33, -1, -1, 6, -1, - 10, -1, 8, 7, 8, 8, 8, 8, 8, 60, - -1, 60, 20, -1, -1, 50, -1, -1, 60, 54, - 61, 62, 61, 62, 8, 78, -1, 61, 62, 40, - 56, 8, 56, -1, 61, 62, -1, 60, -1, 60, - 51, 12, 56, 60, 60, 55, 61, 62, 0, 61, - 62, 40, 61, 62, 60, 42, 56, 60, 60, 60, - 29, 7, 51, 61, 62, 40, 53, 61, 62, 61, - 62, 50, 40, 61, 62, 54, 51, 61, 61, 62, - 29, 15, 29, 51, 61, 62, 57, 29, 15, 15, - 29, 8, 63, 29, 8, 7, 29, 66, 67, 29, - 34, 29, 36, 15, 29, 12, 89, 34, 34, 36, - 36, 7, 12, 29, 29, 61, 62, 66, 67, 66, - 67, 33, -1, 29, 66, 67, 29, 66, 67, -1, - 66, 67, 8, 66, 67, 29, 66, 67, 66, 67, - 25, 8, 27, 29, 61, 62, 29, 61, 62, 74, - 57, 66, 67, 38, 29, -1, 63, 57, 74, 29, - 85, 29, 8, 63, -1, 61, 62, 29, 74, 85, - -1, 74, 66, 67, 61, 62, -1, -1, -1, 85, - 66, 67, 85, 66, 67, 61, 62, 33, -1, 29, - -1, 66, 67, 29, 61, 62, 66, 67, 66, 67, - 36, -1, 89, 15, 66, 67, 29, 25, -1, 27, - 18, 19, -1, 36, -1, 61, 62, -1, 18, 19, - 38, 61, 62, -1, 29, -1, 66, 67, -1, -1, - 66, 67, 29, -1, 29, 47, -1, 45, 46, 23, - 24, -1, -1, 66, 67, 45, 46, -1, 32, 61, - 62, 35, 29, 37, 59, 29, -1, -1, -1, -1, - -1, 66, 67, -1, 61, 62, 61, 62, -1, 66, - 67, 66, 67, 29, 18, 19, -1, 89, -1, -1, - 85, 29, 59, -1, -1, -1, -1, 61, 62, 66, - 67, -1, 66, 67, -1, 23, 24, -1, 29, -1, - -1, 45, 46, 31, 32, 61, 62, 35, 85, 37, - 66, 67, -1, 61, 62, 23, 24, -1, 66, 67, - -1, 10, -1, 31, 32, -1, -1, 35, 59, 37, - 23, 24, -1, 22, 65, 66, 67, -1, 31, 32, - 29, -1, 35, -1, 37, -1, 10, -1, 23, 24, - -1, -1, -1, -1, 85, -1, -1, 32, 22, -1, - 35, -1, 37, -1, -1, 29, 55, -1, -1, -1, - 59, -1, -1, -1, -1, -1, -1, 66, 67, -1, - -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, - -1, 55, -1, -1, 83, 59, 85, -1, -1, 3, - -1, -1, 66, 67, -1, -1, -1, -1, -1, 13, - 74, -1, -1, 17, -1, -1, -1, 23, 24, 83, - -1, 85, 26, -1, 28, 31, 32, 31, -1, 35, - -1, 37, -1, -1, -1, 39, -1, 41, 42, -1, - -1, -1, -1, -1, -1, 49, -1, -1, 52, 53, - -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, - 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 79, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 13, -1, -1, -1, - 17, -1, -1, -1, -1, -1, -1, -1, -1, 26, - -1, 28, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 39, -1, 41, 42, -1, -1, -1, -1, - -1, -1, 49, -1, -1, 52, 53, -1, -1, -1, - -1, 58, -1, -1, -1, -1, -1, 64, -1, -1, + 7, 36, 36, 7, 55, 7, 33, 7, 36, 7, + 55, 8, 36, 7, 36, 16, 36, 7, 60, 7, + 33, 7, 33, 55, 36, 7, 36, 60, 7, 20, + 55, 5, 7, 5, 29, 8, 29, 36, 7, 17, + 36, 33, 29, 60, 33, 60, 7, 5, 7, 88, + 7, 36, 36, 33, 7, 7, 33, 66, 7, 7, + 36, 1, 8, 2, 78, 36, 7, 1, 36, 7, + 78, 8, 2, 78, 1, 8, 36, 60, 33, 8, + 61, 7, 48, 7, 48, 88, 48, 31, 7, 36, + 33, 61, 17, 60, 36, 60, 2, 60, 8, 55, + 36, 36, 2, 1, 36, 8, 60, 8, 7, 8, + -1, 8, 8, 8, 8, 6, 61, 48, 8, 8, + 40, 8, 10, 8, 40, 8, 76, 78, 50, 20, + 8, 51, 54, 61, 62, 51, 15, -1, 61, 62, + 61, 62, 50, 61, 62, 8, 54, 61, 62, 61, + 62, 7, 61, 62, 33, 29, 29, 60, 12, 60, + 56, 56, 29, 60, 40, 7, 60, 55, 61, 62, + 60, 56, 61, 60, 40, 51, 0, 60, 42, 61, + 62, 25, 60, 27, 29, 51, 61, 62, 8, 53, + 61, 62, 29, 56, 38, 12, 8, 29, 8, 29, + 74, 74, 25, 57, 27, 61, 62, 74, -1, 63, + 29, 85, 85, 8, -1, 38, -1, -1, 85, 61, + 62, 66, 67, 29, -1, 61, 62, 29, -1, 66, + 67, 29, 12, -1, 66, 67, 29, -1, 29, -1, + 57, 61, 62, 25, 74, 27, 63, 66, 67, 61, + 62, 61, 62, 89, 29, 85, 38, 25, 29, 27, + 66, 67, 61, 62, 66, 67, 61, 62, 66, 67, + 38, 7, 29, 66, 67, 66, 67, 57, 29, 15, + 25, 15, 27, 63, 15, 25, 25, 27, 27, 8, + 89, 66, 67, 38, -1, 66, 67, 33, 38, 38, + 34, 29, 36, 34, 25, 36, 27, 29, -1, 66, + 67, 25, 25, 27, 27, 66, 67, 38, 25, 25, + 27, 27, 18, 19, 38, 38, 90, 91, 92, 29, + -1, 38, 38, 25, 29, 27, -1, 8, 66, 67, + -1, -1, 61, 62, 66, 67, 38, 29, -1, 45, + 46, -1, -1, -1, 36, 18, 19, 29, -1, 15, + 18, 19, 33, 29, 36, -1, 66, 67, -1, -1, + -1, 66, 67, -1, 15, -1, -1, -1, 34, -1, + 36, -1, 45, 46, 66, 67, -1, 45, 46, -1, + 61, 62, -1, 59, 66, 67, 23, 24, -1, -1, + 66, 67, 23, 24, 29, 32, 47, -1, 35, -1, + 37, 32, -1, 29, 35, -1, 37, 23, 24, 85, + 61, 62, -1, -1, 29, -1, 32, 29, -1, 35, + -1, 37, -1, -1, -1, -1, 61, 62, 29, 18, + 19, 66, 67, 23, 24, 61, 62, -1, 89, -1, + 66, 67, 32, 29, 59, 35, 29, 37, -1, 61, + 62, 66, 67, -1, 66, 67, 45, 46, -1, -1, + 61, 62, -1, -1, -1, 66, 67, -1, -1, -1, + 85, -1, -1, -1, -1, 61, 62, 10, 61, 62, + 66, 67, -1, 66, 67, 23, 24, 29, -1, 22, + -1, 10, -1, 31, 32, -1, 29, 35, -1, 37, + 23, 24, -1, 22, -1, -1, 23, 24, 31, 32, + 29, -1, 35, -1, 37, 32, -1, 59, 35, -1, + 37, 3, 55, 65, 66, 67, 59, -1, -1, -1, + -1, 13, -1, 66, 67, 17, 55, -1, -1, -1, + 59, 74, -1, 85, 26, -1, 28, 66, 67, -1, + 83, -1, 85, -1, -1, 74, -1, 39, -1, 41, + 42, -1, -1, -1, 83, -1, 85, 49, -1, -1, + 52, 53, -1, -1, -1, 3, 58, -1, 23, 24, + -1, -1, 64, -1, -1, 13, 31, 32, -1, 17, + 35, -1, 37, -1, -1, -1, -1, 79, 26, -1, + 28, -1, -1, 31, -1, -1, -1, -1, -1, -1, + -1, 39, -1, 41, 42, -1, -1, -1, -1, -1, + -1, 49, -1, -1, 52, 53, -1, -1, -1, -1, + 58, -1, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 12, 13, -1, -1, -1, - -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, - -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, - -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, - 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, - 67, -1, 69, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, - -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, - -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, - 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, - 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, - -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, - 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, - -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, - -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, - -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, - 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, - 71, -1, 73, -1, 75, -1, -1, -1, -1, 80, - 81, 82, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, - -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, - -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, - 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + 3, 79, -1, -1, -1, -1, -1, -1, -1, -1, + 13, -1, -1, -1, 17, -1, -1, -1, -1, -1, + -1, -1, -1, 26, -1, 28, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 39, -1, 41, 42, + -1, 11, 12, 13, -1, -1, 49, -1, -1, 52, + 53, -1, 22, -1, -1, 58, -1, -1, -1, 29, + -1, 64, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, 79, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, + -1, -1, 12, 13, -1, 65, 66, 67, -1, 69, + -1, 71, 22, 73, -1, 75, -1, -1, -1, 29, + 80, 81, 82, 33, 34, -1, 36, -1, -1, -1, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, - -1, 71, -1, 73, 74, 75, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, - 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, - 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, - -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, - -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, - -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, - 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, - -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, + -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, - -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, - -1, 75, -1, -1, -1, -1, 80, 81, 82, -1, + 74, 75, -1, -1, -1, -1, 80, 81, 82, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, + -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, + -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, + -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, + 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, + -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, + 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, + -1, -1, -1, 80, 81, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, - -1, 51, -1, 53, -1, -1, 56, -1, -1, 59, + -1, 51, -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, -1, - 80, 81, 82, -1, -1, 85, -1, -1, -1, -1, - -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, - -1, -1, 61, -1, -1, -1, 65, 66, 67, -1, - 69, -1, 71, -1, 73, -1, 75, -1, -1, -1, - -1, 80, 81, 82, -1, 84, -1, 86, -1, -1, - -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, - 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, - 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, - 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, - -1, -1, -1, -1, -1, 66, 67, 68, 69, 70, - -1, 72, 73, 74, 75, 76, 77, -1, -1, 80, - 81, 82, 83, 84, 85, -1, -1, -1, -1, -1, + 80, 81, 82, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, + 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, + -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, + 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, + 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, + 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, + -1, -1, 65, 66, 67, -1, 69, -1, 71, -1, + 73, -1, 75, -1, -1, -1, -1, 80, 81, 82, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + 66, 67, -1, 69, -1, 71, -1, 73, -1, 75, + -1, -1, -1, -1, 80, 81, 82, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, -1, -1, -1, -1, -1, 61, + -1, -1, -1, 65, 66, 67, -1, 69, -1, 71, + -1, 73, -1, 75, -1, -1, -1, -1, 80, 81, + 82, -1, 84, -1, 86, -1, -1, -1, -1, -1, + -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, + -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, + -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, + -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, + -1, 56, -1, -1, 59, -1, -1, -1, -1, -1, + 65, 66, 67, -1, 69, -1, 71, -1, 73, -1, + 75, -1, -1, -1, -1, 80, 81, 82, -1, -1, + 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, + 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, + -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, + -1, -1, 66, 67, 68, 69, 70, -1, 72, 73, + 74, 75, 76, 77, -1, -1, 80, 81, 82, 83, + 84, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, @@ -1155,89 +790,94 @@ const int QmlJSGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, 75, 76, 77, -1, -1, 80, 81, 82, - 83, 84, 85, -1, -1, -1, -1, -1, -1, 4, - 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, - -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, - -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, - -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, - 55, -1, -1, -1, 59, -1, -1, -1, -1, -1, - 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, - 75, 76, 77, -1, -1, 80, 81, 82, 83, 84, - 85, -1, -1, -1, -1, -1, -1, 4, -1, -1, - -1, -1, 9, -1, 11, 12, 13, 14, -1, -1, - -1, -1, -1, -1, 21, 22, -1, -1, -1, -1, - -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, - -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, - 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, - -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, -1, -1, 80, 81, 82, 83, 84, -1, -1, - -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, - 9, -1, 11, 12, 13, 14, -1, -1, -1, -1, - -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, - 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, - 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, -1, - -1, 80, 81, 82, 83, 84, -1, -1, -1, -1, - -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, - 11, 12, 13, 14, -1, 16, -1, -1, -1, 20, + 83, 84, 85, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, + -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, + 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, + 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, -1, -1, 55, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, + 72, 73, 74, 75, 76, 77, -1, -1, 80, 81, + 82, 83, 84, 85, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 4, -1, -1, -1, -1, 9, -1, + 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, - 31, 32, 33, 34, -1, 36, -1, -1, -1, 40, + -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, -1, -1, 80, - 81, 82, 83, 84, 85, -1, -1, -1, -1, -1, - -1, 4, 5, 6, -1, -1, 9, 10, 11, 12, - 13, 14, -1, 16, -1, -1, -1, 20, 21, 22, - -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, - 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, - 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, 55, -1, -1, -1, 59, -1, 61, -1, - -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, -1, -1, 80, 81, 82, - 83, 84, 85, -1, -1, -1, -1, -1, -1, + 81, 82, 83, 84, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 4, -1, -1, -1, -1, 9, + -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, + -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, + 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, + -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, -1, -1, + 80, 81, 82, 83, 84, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, + 9, 10, 11, 12, 13, 14, -1, 16, -1, -1, + -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, + 29, 30, 31, 32, 33, 34, -1, 36, -1, -1, + -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, + -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, + 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, -1, + -1, 80, 81, 82, 83, 84, 85, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, + -1, 9, 10, 11, 12, 13, 14, -1, 16, -1, + -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, + -1, 29, 30, 31, 32, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, 55, -1, -1, + -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + -1, -1, 80, 81, 82, 83, 84, 85, -1, -1, + -1, -1, -1, -1, -1, -1, -1, - 68, 16, 15, 68, 15, 68, 6, 31, 64, 31, - 31, 5, 15, 6, 31, 21, 15, 6, 6, 31, - 12, 6, 68, 6, 6, 6, 6, 68, 15, 31, - 16, 15, 6, 6, 6, 6, 6, 15, 15, 6, - 16, 6, 21, 6, 93, 6, 15, 78, 68, 15, - 90, 15, 68, 21, 6, 15, 31, 15, 68, 6, - 15, 68, 15, 68, 68, 95, 6, 68, 16, 31, - 68, 68, 31, 15, 31, 16, 32, 31, 68, 15, - 15, 31, 78, 6, 6, 15, 8, 15, 6, 7, - 6, 15, 41, 6, 43, 41, 41, 43, 41, 6, - -1, 46, 45, 35, 41, -1, 38, 41, 45, 35, - 41, 45, 38, 6, 41, 8, 43, 68, -1, 27, - 51, 41, 41, 31, 68, 35, 33, 46, 38, 41, - 65, 43, -1, 53, 15, 65, 41, 65, 43, 68, - 41, 65, 41, -1, 43, 46, 41, 41, 43, 43, - 41, 41, 43, 43, 41, 41, 43, 43, 102, 41, - -1, 84, 41, -1, -1, 44, 82, 41, 97, 43, - 41, 41, 41, 55, 41, 46, 46, 46, 41, 46, - 43, 41, 41, 96, 43, 41, 46, 43, 41, 41, - 43, 41, 41, 41, 46, 41, 41, 47, 47, 47, - 46, 46, 41, 31, 31, 41, 41, 46, -1, 37, - 37, 41, 41, 49, 43, 6, 6, 47, 8, 41, - 41, -1, 57, 41, 46, 46, 44, 48, 50, 41, - 41, -1, 41, 41, 46, 46, 48, 46, 46, 48, - 41, 31, 33, 34, 41, 46, 41, -1, 41, 46, - -1, 46, 63, 46, -1, 63, -1, 52, 41, 56, - 41, 54, 63, 46, 41, 46, 6, 7, -1, 46, - 10, 15, 16, 17, 18, 19, 20, -1, -1, -1, - 63, 58, 63, -1, 24, 25, 41, -1, -1, -1, - -1, 46, -1, 48, -1, -1, -1, -1, -1, -1, + 33, 23, 33, 3, 2, 9, 3, 2, 34, 33, + 9, 3, 3, 9, 2, 9, 9, 3, 2, 9, + 9, 66, 9, 3, 3, 2, 9, 33, 9, 2, + 2, 9, 3, 18, 9, 9, 3, 3, 96, 9, + 3, 23, 2, 2, 9, 3, 2, 23, 3, 79, + 18, 15, 9, 91, 2, 9, 3, 3, 2, 9, + 9, 2, 79, 2, 33, 2, 9, 18, 3, 9, + 2, 33, 3, 9, 2, 94, 18, 3, 3, 8, + 33, 33, 43, -1, -1, 18, 47, -1, 33, 9, + 9, -1, 11, 2, 9, 33, 11, 9, 10, 33, + 2, -1, -1, 33, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 37, 35, 43, 40, -1, 43, + 47, 43, 43, 47, 45, 43, 48, 45, 33, 43, + 43, 45, 43, 43, 39, 48, 33, 48, 9, 43, + 43, 51, 39, 43, 48, 48, 9, 43, 43, 45, + 43, 43, 43, 48, 45, 48, 3, 57, 43, 43, + 43, 53, 45, 48, 48, 43, 43, 43, 45, 43, + 48, 43, 48, 43, 3, 49, 29, 49, 43, 49, + 33, 46, 43, 43, 45, 45, 43, 37, 45, 3, + 40, 43, 3, 9, 103, 43, 98, 45, 43, 43, + 45, 45, 43, 43, 43, 46, 45, 59, 43, 49, + 45, 43, 43, 37, 85, 9, 40, 48, -1, 9, + 67, 11, 43, 55, 45, 43, 43, 45, 45, -1, + 43, 43, -1, 43, 97, 48, 48, -1, 48, -1, + 43, 35, 36, 33, 56, 48, 43, -1, -1, 52, + -1, 48, 65, 67, 43, 65, 67, 43, 43, 48, + 43, 50, 48, 48, -1, 48, 43, 83, 65, 54, + -1, 48, -1, 43, -1, 58, 3, 43, 48, 65, + 50, 43, 48, 60, 50, 43, 48, 9, 10, -1, + 48, 13, 50, 3, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 26, 27, -1, -1, 18, 19, + 20, 21, 22, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, - 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 24, 25, -1, + -1, -1, -1, -1, -1, 26, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -1245,5 +885,5 @@ const int QmlJSGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1}; + -1, -1, -1, -1}; diff --git a/src/declarative/qml/parser/qmljsgrammar_p.h b/src/declarative/qml/parser/qmljsgrammar_p.h index 1590274..da42f8c 100644 --- a/src/declarative/qml/parser/qmljsgrammar_p.h +++ b/src/declarative/qml/parser/qmljsgrammar_p.h @@ -59,8 +59,8 @@ class QmlJSGrammar public: enum { EOF_SYMBOL = 0, - REDUCE_HERE = 91, - SHIFT_THERE = 90, + REDUCE_HERE = 94, + SHIFT_THERE = 93, T_AND = 1, T_AND_AND = 2, T_AND_EQ = 3, @@ -85,6 +85,9 @@ public: T_EQ_EQ = 18, T_EQ_EQ_EQ = 19, T_FALSE = 82, + T_FEED_JS_EXPRESSION = 92, + T_FEED_JS_STATEMENT = 91, + T_FEED_UI_PROGRAM = 90, T_FINALLY = 20, T_FOR = 21, T_FUNCTION = 22, @@ -151,26 +154,20 @@ public: T_XOR = 78, T_XOR_EQ = 79, - ACCEPT_STATE = 615, - RULE_COUNT = 338, - STATE_COUNT = 616, - TERMINAL_COUNT = 92, - NON_TERMINAL_COUNT = 104, + ACCEPT_STATE = 621, + RULE_COUNT = 341, + STATE_COUNT = 622, + TERMINAL_COUNT = 95, + NON_TERMINAL_COUNT = 105, - GOTO_INDEX_OFFSET = 616, - GOTO_INFO_OFFSET = 2139, - GOTO_CHECK_OFFSET = 2139 + GOTO_INDEX_OFFSET = 622, + GOTO_INFO_OFFSET = 2247, + GOTO_CHECK_OFFSET = 2247 }; static const char *const spell []; static const int lhs []; static const int rhs []; - -#ifndef QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO - static const int rule_index []; - static const int rule_info []; -#endif // QLALR_NO_QMLJSGRAMMAR_DEBUG_INFO - static const int goto_default []; static const int action_default []; static const int action_index []; diff --git a/src/declarative/qml/parser/qmljsparser.cpp b/src/declarative/qml/parser/qmljsparser.cpp index a13b425..08a424e 100644 --- a/src/declarative/qml/parser/qmljsparser.cpp +++ b/src/declarative/qml/parser/qmljsparser.cpp @@ -1,7 +1,5 @@ // This file was generated by qlalr - DO NOT EDIT! -#line 95 "qmljs.g" - /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). @@ -53,8 +51,6 @@ #include "qmljsnodepool_p.h" -#line 349 "qmljs.g" - #include "qmljsparser_p.h" #include <QVarLengthArray> @@ -147,14 +143,16 @@ AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr) return 0; } -bool Parser::parse() +bool Parser::parse(int startToken) { Lexer *lexer = driver->lexer(); bool hadErrors = false; int yytoken = -1; int action = 0; - first_token = last_token = 0; + token_buffer[0].token = startToken; + first_token = &token_buffer[0]; + last_token = &token_buffer[1]; tos = -1; program = 0; @@ -197,36 +195,40 @@ bool Parser::parse() switch (r) { -#line 498 "qmljs.g" - case 0: { - program = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, - sym(2).UiObjectMemberList->finish()); - sym(1).UiProgram = program; + sym(1).Node = sym(2).Node; + program = sym(1).Node; } break; -#line 508 "qmljs.g" +case 1: { + sym(1).Node = sym(2).Node; + program = sym(1).Node; +} break; case 2: { - sym(1).Node = sym(1).UiImportList->finish(); + sym(1).Node = sym(2).Node; + program = sym(1).Node; } break; -#line 515 "qmljs.g" - case 3: { - sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport); + sym(1).UiProgram = makeAstNode<AST::UiProgram> (driver->nodePool(), sym(1).UiImportList, + sym(2).UiObjectMemberList->finish()); } break; -#line 522 "qmljs.g" +case 5: { + sym(1).Node = sym(1).UiImportList->finish(); +} break; -case 4: { +case 6: { + sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImport); +} break; + +case 7: { sym(1).Node = makeAstNode<AST::UiImportList> (driver->nodePool(), sym(1).UiImportList, sym(2).UiImport); } break; -#line 531 "qmljs.g" - -case 6: { +case 9: { AST::UiImport *node = makeAstNode<AST::UiImport>(driver->nodePool(), sym(2).sval); node->importToken = loc(1); node->fileNameToken = loc(2); @@ -234,9 +236,7 @@ case 6: { sym(1).Node = node; } break; -#line 543 "qmljs.g" - -case 8: { +case 11: { AST::UiImport *node = makeAstNode<AST::UiImport>(driver->nodePool(), sym(2).sval); node->importId = sym(4).sval; node->importToken = loc(1); @@ -247,9 +247,7 @@ case 8: { sym(1).Node = node; } break; -#line 558 "qmljs.g" - -case 10: { +case 13: { AST::UiImport *node = makeAstNode<AST::UiImport>(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importToken = loc(1); node->fileNameToken = loc(2); @@ -257,9 +255,7 @@ case 10: { sym(1).Node = node; } break; -#line 570 "qmljs.g" - -case 12: { +case 15: { AST::UiImport *node = makeAstNode<AST::UiImport>(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importToken = loc(1); node->fileNameToken = loc(2); @@ -268,9 +264,7 @@ case 12: { sym(1).Node = node; } break; -#line 583 "qmljs.g" - -case 14: { +case 17: { AST::UiImport *node = makeAstNode<AST::UiImport>(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importId = sym(5).sval; node->importToken = loc(1); @@ -282,9 +276,7 @@ case 14: { sym(1).Node = node; } break; -#line 599 "qmljs.g" - -case 16: { +case 19: { AST::UiImport *node = makeAstNode<AST::UiImport>(driver->nodePool(), sym(2).UiQualifiedId->finish()); node->importId = sym(4).sval; node->importToken = loc(1); @@ -295,76 +287,56 @@ case 16: { sym(1).Node = node; } break; -#line 613 "qmljs.g" - -case 17: { +case 20: { sym(1).Node = 0; } break; -#line 620 "qmljs.g" - -case 18: { +case 21: { sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); } break; -#line 627 "qmljs.g" - -case 19: { +case 22: { sym(1).Node = makeAstNode<AST::UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMember); } break; -#line 634 "qmljs.g" - -case 20: { +case 23: { AST::UiObjectMemberList *node = makeAstNode<AST:: UiObjectMemberList> (driver->nodePool(), sym(1).UiObjectMemberList, sym(2).UiObjectMember); sym(1).Node = node; } break; -#line 643 "qmljs.g" - -case 21: { +case 24: { sym(1).Node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiObjectMember); } break; -#line 650 "qmljs.g" - -case 22: { +case 25: { AST::UiArrayMemberList *node = makeAstNode<AST::UiArrayMemberList> (driver->nodePool(), sym(1).UiArrayMemberList, sym(3).UiObjectMember); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 660 "qmljs.g" - -case 23: { +case 26: { AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), (AST::UiObjectMemberList*)0); node->lbraceToken = loc(1); node->rbraceToken = loc(2); sym(1).Node = node; } break; -#line 670 "qmljs.g" - -case 24: { +case 27: { AST::UiObjectInitializer *node = makeAstNode<AST::UiObjectInitializer> (driver->nodePool(), sym(2).UiObjectMemberList->finish()); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -#line 680 "qmljs.g" - -case 25: { +case 28: { AST::UiObjectDefinition *node = makeAstNode<AST::UiObjectDefinition> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(2).UiObjectInitializer); sym(1).Node = node; } break; -#line 691 "qmljs.g" - -case 27: { +case 30: { AST::UiArrayBinding *node = makeAstNode<AST::UiArrayBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(4).UiArrayMemberList->finish()); node->colonToken = loc(2); @@ -373,25 +345,19 @@ case 27: { sym(1).Node = node; } break; -#line 703 "qmljs.g" - -case 28: { +case 31: { AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); node->literalToken = loc(1); sym(1).Node = node; } break; -#line 713 "qmljs.g" - -case 30: { +case 33: { AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 723 "qmljs.g" - -case 31: { +case 34: { if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(3).Expression)) { AST::UiObjectBinding *node = makeAstNode<AST::UiObjectBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), qualifiedId, sym(4).UiObjectInitializer); @@ -406,21 +372,7 @@ case 31: { return false; // ### recover } } break; - -#line 742 "qmljs.g" -case 32: -#line 745 "qmljs.g" -case 33: -#line 748 "qmljs.g" -case 34: -#line 751 "qmljs.g" -case 35: -#line 754 "qmljs.g" -case 36: -#line 757 "qmljs.g" -case 37: -#line 759 "qmljs.g" - +case 35:case 36:case 37:case 38:case 39:case 40: { AST::UiScriptBinding *node = makeAstNode<AST::UiScriptBinding> (driver->nodePool(), sym(1).UiQualifiedId->finish(), sym(3).Statement); @@ -428,49 +380,35 @@ case 37: sym(1).Node = node; } break; -#line 769 "qmljs.g" - -case 38: - -#line 773 "qmljs.g" +case 41: -case 39: { +case 42: { sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); break; } -#line 783 "qmljs.g" - -case 41: { +case 44: { sym(1).Node = 0; } break; -#line 790 "qmljs.g" - -case 42: { +case 45: { sym(1).Node = sym(1).UiParameterList->finish (); } break; -#line 797 "qmljs.g" - -case 43: { +case 46: { AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).sval, sym(2).sval); node->identifierToken = loc(2); sym(1).Node = node; } break; -#line 806 "qmljs.g" - -case 44: { +case 47: { AST::UiParameterList *node = makeAstNode<AST::UiParameterList> (driver->nodePool(), sym(1).UiParameterList, sym(3).sval, sym(4).sval); node->commaToken = loc(2); node->identifierToken = loc(4); sym(1).Node = node; } break; -#line 816 "qmljs.g" - -case 45: { +case 48: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); @@ -480,9 +418,7 @@ case 45: { sym(1).Node = node; } break; -#line 829 "qmljs.g" - -case 46: { +case 49: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), (NameId *)0, sym(2).sval); node->type = AST::UiPublicMember::Signal; node->propertyToken = loc(1); @@ -491,9 +427,7 @@ case 46: { sym(1).Node = node; } break; -#line 842 "qmljs.g" - -case 48: { +case 51: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval); node->propertyToken = loc(1); node->typeToken = loc(2); @@ -502,9 +436,7 @@ case 48: { sym(1).Node = node; } break; -#line 855 "qmljs.g" - -case 50: { +case 53: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval); node->isDefaultMember = true; node->defaultToken = loc(1); @@ -515,9 +447,7 @@ case 50: { sym(1).Node = node; } break; -#line 870 "qmljs.g" - -case 52: { +case 55: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(2).sval, sym(3).sval, sym(5).Expression); node->propertyToken = loc(1); @@ -528,9 +458,7 @@ case 52: { sym(1).Node = node; } break; -#line 885 "qmljs.g" - -case 54: { +case 57: { AST::UiPublicMember *node = makeAstNode<AST::UiPublicMember> (driver->nodePool(), sym(3).sval, sym(4).sval, sym(6).Expression); node->isDefaultMember = true; @@ -543,104 +471,76 @@ case 54: { sym(1).Node = node; } break; -#line 901 "qmljs.g" - -case 55: { +case 58: { sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); } break; -#line 908 "qmljs.g" - -case 56: { +case 59: { sym(1).Node = makeAstNode<AST::UiSourceElement>(driver->nodePool(), sym(1).Node); } break; - -#line 915 "qmljs.g" -case 57: -#line 918 "qmljs.g" - -case 58: +case 60: +case 61: { AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 930 "qmljs.g" - -case 60: { +case 63: { QString s = QLatin1String(QmlJSGrammar::spell[T_PROPERTY]); sym(1).sval = driver->intern(s.constData(), s.length()); break; } -#line 939 "qmljs.g" - -case 61: { +case 64: { QString s = QLatin1String(QmlJSGrammar::spell[T_SIGNAL]); sym(1).sval = driver->intern(s.constData(), s.length()); break; } -#line 952 "qmljs.g" - -case 62: { +case 65: { AST::ThisExpression *node = makeAstNode<AST::ThisExpression> (driver->nodePool()); node->thisToken = loc(1); sym(1).Node = node; } break; -#line 961 "qmljs.g" - -case 63: { +case 66: { AST::IdentifierExpression *node = makeAstNode<AST::IdentifierExpression> (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 970 "qmljs.g" - -case 64: { +case 67: { AST::NullExpression *node = makeAstNode<AST::NullExpression> (driver->nodePool()); node->nullToken = loc(1); sym(1).Node = node; } break; -#line 979 "qmljs.g" - -case 65: { +case 68: { AST::TrueLiteral *node = makeAstNode<AST::TrueLiteral> (driver->nodePool()); node->trueToken = loc(1); sym(1).Node = node; } break; -#line 988 "qmljs.g" - -case 66: { +case 69: { AST::FalseLiteral *node = makeAstNode<AST::FalseLiteral> (driver->nodePool()); node->falseToken = loc(1); sym(1).Node = node; } break; -#line 997 "qmljs.g" - -case 67: { +case 70: { AST::NumericLiteral *node = makeAstNode<AST::NumericLiteral> (driver->nodePool(), sym(1).dval, lexer->flags); node->literalToken = loc(1); sym(1).Node = node; } break; -#line 1006 "qmljs.g" - -case 68: { +case 71: { AST::StringLiteral *node = makeAstNode<AST::StringLiteral> (driver->nodePool(), sym(1).sval); node->literalToken = loc(1); sym(1).Node = node; } break; -#line 1018 "qmljs.g" - -case 69: { +case 72: { bool rx = lexer->scanRegExp(Lexer::NoPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -651,9 +551,7 @@ case 69: { sym(1).Node = node; } break; -#line 1035 "qmljs.g" - -case 70: { +case 73: { bool rx = lexer->scanRegExp(Lexer::EqualPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -664,36 +562,28 @@ case 70: { sym(1).Node = node; } break; -#line 1049 "qmljs.g" - -case 71: { +case 74: { AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), (AST::Elision *) 0); node->lbracketToken = loc(1); node->rbracketToken = loc(2); sym(1).Node = node; } break; -#line 1059 "qmljs.g" - -case 72: { +case 75: { AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).Elision->finish()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -#line 1069 "qmljs.g" - -case 73: { +case 76: { AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish ()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -#line 1079 "qmljs.g" - -case 74: { +case 77: { AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), (AST::Elision *) 0); node->lbracketToken = loc(1); @@ -702,9 +592,7 @@ case 74: { sym(1).Node = node; } break; -#line 1091 "qmljs.g" - -case 75: { +case 78: { AST::ArrayLiteral *node = makeAstNode<AST::ArrayLiteral> (driver->nodePool(), sym(2).ElementList->finish (), sym(4).Elision->finish()); node->lbracketToken = loc(1); @@ -713,9 +601,7 @@ case 75: { sym(1).Node = node; } break; -#line 1110 "qmljs.g" - -case 76: { +case 79: { AST::ObjectLiteral *node = 0; if (sym(2).Node) node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), @@ -727,9 +613,7 @@ case 76: { sym(1).Node = node; } break; -#line 1125 "qmljs.g" - -case 77: { +case 80: { AST::ObjectLiteral *node = makeAstNode<AST::ObjectLiteral> (driver->nodePool(), sym(2).PropertyNameAndValueList->finish ()); node->lbraceToken = loc(1); @@ -737,89 +621,67 @@ case 77: { sym(1).Node = node; } break; -#line 1136 "qmljs.g" - -case 78: { +case 81: { AST::NestedExpression *node = makeAstNode<AST::NestedExpression>(driver->nodePool(), sym(2).Expression); node->lparenToken = loc(1); node->rparenToken = loc(3); sym(1).Node = node; } break; -#line 1146 "qmljs.g" - -case 79: { +case 82: { AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 1155 "qmljs.g" - -case 80: { +case 83: { AST::UiQualifiedId *node = makeAstNode<AST::UiQualifiedId> (driver->nodePool(), sym(1).UiQualifiedId, sym(3).sval); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 1164 "qmljs.g" - -case 81: { +case 84: { sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), (AST::Elision *) 0, sym(1).Expression); } break; -#line 1171 "qmljs.g" - -case 82: { +case 85: { sym(1).Node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).Elision->finish(), sym(2).Expression); } break; -#line 1178 "qmljs.g" - -case 83: { +case 86: { AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, (AST::Elision *) 0, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1188 "qmljs.g" - -case 84: { +case 87: { AST::ElementList *node = makeAstNode<AST::ElementList> (driver->nodePool(), sym(1).ElementList, sym(3).Elision->finish(), sym(4).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1198 "qmljs.g" - -case 85: { +case 88: { AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool()); node->commaToken = loc(1); sym(1).Node = node; } break; -#line 1207 "qmljs.g" - -case 86: { +case 89: { AST::Elision *node = makeAstNode<AST::Elision> (driver->nodePool(), sym(1).Elision); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1216 "qmljs.g" - -case 87: { +case 90: { AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyName, sym(3).Expression); node->colonToken = loc(2); sym(1).Node = node; } break; -#line 1226 "qmljs.g" - -case 88: { +case 91: { AST::PropertyNameAndValueList *node = makeAstNode<AST::PropertyNameAndValueList> (driver->nodePool(), sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression); node->commaToken = loc(2); @@ -827,196 +689,116 @@ case 88: { sym(1).Node = node; } break; -#line 1237 "qmljs.g" - -case 89: { +case 92: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; - -#line 1246 "qmljs.g" -case 90: -#line 1249 "qmljs.g" - -case 91: { +case 93: +case 94: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount())); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1258 "qmljs.g" - -case 92: { +case 95: { AST::StringLiteralPropertyName *node = makeAstNode<AST::StringLiteralPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1267 "qmljs.g" - -case 93: { +case 96: { AST::NumericLiteralPropertyName *node = makeAstNode<AST::NumericLiteralPropertyName> (driver->nodePool(), sym(1).dval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1276 "qmljs.g" - -case 94: { +case 97: { AST::IdentifierPropertyName *node = makeAstNode<AST::IdentifierPropertyName> (driver->nodePool(), sym(1).sval); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -#line 1285 "qmljs.g" - -case 95: - -#line 1289 "qmljs.g" - -case 96: - -#line 1293 "qmljs.g" - -case 97: - -#line 1297 "qmljs.g" - case 98: -#line 1301 "qmljs.g" - case 99: -#line 1305 "qmljs.g" - case 100: -#line 1309 "qmljs.g" - case 101: -#line 1313 "qmljs.g" - case 102: -#line 1317 "qmljs.g" - case 103: -#line 1321 "qmljs.g" - case 104: -#line 1325 "qmljs.g" - case 105: -#line 1329 "qmljs.g" - case 106: -#line 1333 "qmljs.g" - case 107: -#line 1337 "qmljs.g" - case 108: -#line 1341 "qmljs.g" - case 109: -#line 1345 "qmljs.g" - case 110: -#line 1349 "qmljs.g" - case 111: -#line 1353 "qmljs.g" - case 112: -#line 1357 "qmljs.g" - case 113: -#line 1361 "qmljs.g" - case 114: -#line 1365 "qmljs.g" - case 115: -#line 1369 "qmljs.g" - case 116: -#line 1373 "qmljs.g" - case 117: -#line 1377 "qmljs.g" - case 118: -#line 1381 "qmljs.g" - case 119: -#line 1385 "qmljs.g" - case 120: -#line 1389 "qmljs.g" - case 121: -#line 1393 "qmljs.g" - case 122: -#line 1397 "qmljs.g" - case 123: -#line 1401 "qmljs.g" - case 124: -#line 1405 "qmljs.g" - case 125: + +case 126: + +case 127: + +case 128: { sym(1).sval = driver->intern(lexer->characterBuffer(), lexer->characterCount()); } break; -#line 1419 "qmljs.g" - -case 130: { +case 133: { AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -#line 1429 "qmljs.g" - -case 131: { +case 134: { AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 1439 "qmljs.g" - -case 132: { +case 135: { AST::NewMemberExpression *node = makeAstNode<AST::NewMemberExpression> (driver->nodePool(), sym(2).Expression, sym(4).ArgumentList); node->newToken = loc(1); node->lparenToken = loc(3); @@ -1024,500 +806,384 @@ case 132: { sym(1).Node = node; } break; -#line 1452 "qmljs.g" - -case 134: { +case 137: { AST::NewExpression *node = makeAstNode<AST::NewExpression> (driver->nodePool(), sym(2).Expression); node->newToken = loc(1); sym(1).Node = node; } break; -#line 1461 "qmljs.g" - -case 135: { +case 138: { AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -#line 1471 "qmljs.g" - -case 136: { +case 139: { AST::CallExpression *node = makeAstNode<AST::CallExpression> (driver->nodePool(), sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -#line 1481 "qmljs.g" - -case 137: { +case 140: { AST::ArrayMemberExpression *node = makeAstNode<AST::ArrayMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -#line 1491 "qmljs.g" - -case 138: { +case 141: { AST::FieldMemberExpression *node = makeAstNode<AST::FieldMemberExpression> (driver->nodePool(), sym(1).Expression, sym(3).sval); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 1501 "qmljs.g" - -case 139: { +case 142: { sym(1).Node = 0; } break; -#line 1508 "qmljs.g" - -case 140: { +case 143: { sym(1).Node = sym(1).ArgumentList->finish(); } break; -#line 1515 "qmljs.g" - -case 141: { +case 144: { sym(1).Node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).Expression); } break; -#line 1522 "qmljs.g" - -case 142: { +case 145: { AST::ArgumentList *node = makeAstNode<AST::ArgumentList> (driver->nodePool(), sym(1).ArgumentList, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 1535 "qmljs.g" - -case 146: { +case 149: { AST::PostIncrementExpression *node = makeAstNode<AST::PostIncrementExpression> (driver->nodePool(), sym(1).Expression); node->incrementToken = loc(2); sym(1).Node = node; } break; -#line 1544 "qmljs.g" - -case 147: { +case 150: { AST::PostDecrementExpression *node = makeAstNode<AST::PostDecrementExpression> (driver->nodePool(), sym(1).Expression); node->decrementToken = loc(2); sym(1).Node = node; } break; -#line 1555 "qmljs.g" - -case 149: { +case 152: { AST::DeleteExpression *node = makeAstNode<AST::DeleteExpression> (driver->nodePool(), sym(2).Expression); node->deleteToken = loc(1); sym(1).Node = node; } break; -#line 1564 "qmljs.g" - -case 150: { +case 153: { AST::VoidExpression *node = makeAstNode<AST::VoidExpression> (driver->nodePool(), sym(2).Expression); node->voidToken = loc(1); sym(1).Node = node; } break; -#line 1573 "qmljs.g" - -case 151: { +case 154: { AST::TypeOfExpression *node = makeAstNode<AST::TypeOfExpression> (driver->nodePool(), sym(2).Expression); node->typeofToken = loc(1); sym(1).Node = node; } break; -#line 1582 "qmljs.g" - -case 152: { +case 155: { AST::PreIncrementExpression *node = makeAstNode<AST::PreIncrementExpression> (driver->nodePool(), sym(2).Expression); node->incrementToken = loc(1); sym(1).Node = node; } break; -#line 1591 "qmljs.g" - -case 153: { +case 156: { AST::PreDecrementExpression *node = makeAstNode<AST::PreDecrementExpression> (driver->nodePool(), sym(2).Expression); node->decrementToken = loc(1); sym(1).Node = node; } break; -#line 1600 "qmljs.g" - -case 154: { +case 157: { AST::UnaryPlusExpression *node = makeAstNode<AST::UnaryPlusExpression> (driver->nodePool(), sym(2).Expression); node->plusToken = loc(1); sym(1).Node = node; } break; -#line 1609 "qmljs.g" - -case 155: { +case 158: { AST::UnaryMinusExpression *node = makeAstNode<AST::UnaryMinusExpression> (driver->nodePool(), sym(2).Expression); node->minusToken = loc(1); sym(1).Node = node; } break; -#line 1618 "qmljs.g" - -case 156: { +case 159: { AST::TildeExpression *node = makeAstNode<AST::TildeExpression> (driver->nodePool(), sym(2).Expression); node->tildeToken = loc(1); sym(1).Node = node; } break; -#line 1627 "qmljs.g" - -case 157: { +case 160: { AST::NotExpression *node = makeAstNode<AST::NotExpression> (driver->nodePool(), sym(2).Expression); node->notToken = loc(1); sym(1).Node = node; } break; -#line 1638 "qmljs.g" - -case 159: { +case 162: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mul, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1648 "qmljs.g" - -case 160: { +case 163: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Div, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1658 "qmljs.g" - -case 161: { +case 164: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Mod, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1670 "qmljs.g" - -case 163: { +case 166: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Add, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1680 "qmljs.g" - -case 164: { +case 167: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Sub, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1692 "qmljs.g" - -case 166: { +case 169: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::LShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1702 "qmljs.g" - -case 167: { +case 170: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::RShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1712 "qmljs.g" - -case 168: { +case 171: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::URShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1724 "qmljs.g" - -case 170: { +case 173: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1734 "qmljs.g" - -case 171: { +case 174: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1744 "qmljs.g" - -case 172: { +case 175: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1754 "qmljs.g" - -case 173: { +case 176: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1764 "qmljs.g" - -case 174: { +case 177: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1774 "qmljs.g" - -case 175: { +case 178: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::In, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1786 "qmljs.g" - -case 177: { +case 180: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1796 "qmljs.g" - -case 178: { +case 181: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1806 "qmljs.g" - -case 179: { +case 182: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1816 "qmljs.g" - -case 180: { +case 183: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1826 "qmljs.g" - -case 181: { +case 184: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1838 "qmljs.g" - -case 183: { +case 186: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1848 "qmljs.g" - -case 184: { +case 187: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1858 "qmljs.g" - -case 185: { +case 188: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1868 "qmljs.g" - -case 186: { +case 189: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1880 "qmljs.g" - -case 188: { +case 191: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1890 "qmljs.g" - -case 189: { +case 192: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1900 "qmljs.g" - -case 190: { +case 193: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1910 "qmljs.g" - -case 191: { +case 194: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1922 "qmljs.g" - -case 193: { +case 196: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1934 "qmljs.g" - -case 195: { +case 198: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1946 "qmljs.g" - -case 197: { +case 200: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1958 "qmljs.g" - -case 199: { +case 202: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1970 "qmljs.g" - -case 201: { +case 204: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1982 "qmljs.g" - -case 203: { +case 206: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 1994 "qmljs.g" - -case 205: { +case 208: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2006 "qmljs.g" - -case 207: { +case 210: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2018 "qmljs.g" - -case 209: { +case 212: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2030 "qmljs.g" - -case 211: { +case 214: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2042 "qmljs.g" - -case 213: { +case 216: { AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1525,9 +1191,7 @@ case 213: { sym(1).Node = node; } break; -#line 2055 "qmljs.g" - -case 215: { +case 218: { AST::ConditionalExpression *node = makeAstNode<AST::ConditionalExpression> (driver->nodePool(), sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1535,160 +1199,112 @@ case 215: { sym(1).Node = node; } break; -#line 2068 "qmljs.g" - -case 217: { +case 220: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2080 "qmljs.g" - -case 219: { +case 222: { AST::BinaryExpression *node = makeAstNode<AST::BinaryExpression> (driver->nodePool(), sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -#line 2090 "qmljs.g" - -case 220: { +case 223: { sym(1).ival = QSOperator::Assign; } break; -#line 2097 "qmljs.g" - -case 221: { +case 224: { sym(1).ival = QSOperator::InplaceMul; } break; -#line 2104 "qmljs.g" - -case 222: { +case 225: { sym(1).ival = QSOperator::InplaceDiv; } break; -#line 2111 "qmljs.g" - -case 223: { +case 226: { sym(1).ival = QSOperator::InplaceMod; } break; -#line 2118 "qmljs.g" - -case 224: { +case 227: { sym(1).ival = QSOperator::InplaceAdd; } break; -#line 2125 "qmljs.g" - -case 225: { +case 228: { sym(1).ival = QSOperator::InplaceSub; } break; -#line 2132 "qmljs.g" - -case 226: { +case 229: { sym(1).ival = QSOperator::InplaceLeftShift; } break; -#line 2139 "qmljs.g" - -case 227: { +case 230: { sym(1).ival = QSOperator::InplaceRightShift; } break; -#line 2146 "qmljs.g" - -case 228: { +case 231: { sym(1).ival = QSOperator::InplaceURightShift; } break; -#line 2153 "qmljs.g" - -case 229: { +case 232: { sym(1).ival = QSOperator::InplaceAnd; } break; -#line 2160 "qmljs.g" - -case 230: { +case 233: { sym(1).ival = QSOperator::InplaceXor; } break; -#line 2167 "qmljs.g" - -case 231: { +case 234: { sym(1).ival = QSOperator::InplaceOr; } break; -#line 2176 "qmljs.g" - -case 233: { +case 236: { AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 2185 "qmljs.g" - -case 234: { +case 237: { sym(1).Node = 0; } break; -#line 2196 "qmljs.g" - -case 237: { +case 240: { AST::Expression *node = makeAstNode<AST::Expression> (driver->nodePool(), sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 2205 "qmljs.g" - -case 238: { +case 241: { sym(1).Node = 0; } break; -#line 2231 "qmljs.g" - -case 255: { +case 258: { AST::Block *node = makeAstNode<AST::Block> (driver->nodePool(), sym(2).StatementList); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -#line 2241 "qmljs.g" - -case 256: { +case 259: { sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).Statement); } break; -#line 2248 "qmljs.g" - -case 257: { +case 260: { sym(1).Node = makeAstNode<AST::StatementList> (driver->nodePool(), sym(1).StatementList, sym(2).Statement); } break; -#line 2255 "qmljs.g" - -case 258: { +case 261: { sym(1).Node = 0; } break; -#line 2262 "qmljs.g" - -case 259: { +case 262: { sym(1).Node = sym(1).StatementList->finish (); } break; -#line 2270 "qmljs.g" - -case 261: { +case 264: { AST::VariableStatement *node = makeAstNode<AST::VariableStatement> (driver->nodePool(), sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); node->declarationKindToken = loc(1); @@ -1696,106 +1312,76 @@ case 261: { sym(1).Node = node; } break; -#line 2281 "qmljs.g" - -case 262: { +case 265: { sym(1).ival = T_CONST; } break; -#line 2288 "qmljs.g" - -case 263: { +case 266: { sym(1).ival = T_VAR; } break; -#line 2295 "qmljs.g" - -case 264: { +case 267: { sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); } break; -#line 2302 "qmljs.g" - -case 265: { +case 268: { AST::VariableDeclarationList *node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); node->commaToken = loc(2); sym(1).Node = node; } break; -#line 2312 "qmljs.g" - -case 266: { +case 269: { sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclaration); } break; -#line 2319 "qmljs.g" - -case 267: { +case 270: { sym(1).Node = makeAstNode<AST::VariableDeclarationList> (driver->nodePool(), sym(1).VariableDeclarationList, sym(3).VariableDeclaration); } break; -#line 2326 "qmljs.g" - -case 268: { +case 271: { AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 2335 "qmljs.g" - -case 269: { +case 272: { AST::VariableDeclaration *node = makeAstNode<AST::VariableDeclaration> (driver->nodePool(), sym(1).sval, sym(2).Expression); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 2344 "qmljs.g" - -case 270: { +case 273: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -#line 2352 "qmljs.g" - -case 271: { +case 274: { sym(1).Node = 0; } break; -#line 2361 "qmljs.g" - -case 273: { +case 276: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -#line 2369 "qmljs.g" - -case 274: { +case 277: { sym(1).Node = 0; } break; -#line 2378 "qmljs.g" - -case 276: { +case 279: { AST::EmptyStatement *node = makeAstNode<AST::EmptyStatement> (driver->nodePool()); node->semicolonToken = loc(1); sym(1).Node = node; } break; -#line 2388 "qmljs.g" - -case 278: { +case 281: { AST::ExpressionStatement *node = makeAstNode<AST::ExpressionStatement> (driver->nodePool(), sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2397 "qmljs.g" - -case 279: { +case 282: { AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement, sym(7).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1804,9 +1390,7 @@ case 279: { sym(1).Node = node; } break; -#line 2409 "qmljs.g" - -case 280: { +case 283: { AST::IfStatement *node = makeAstNode<AST::IfStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1814,9 +1398,7 @@ case 280: { sym(1).Node = node; } break; -#line 2422 "qmljs.g" - -case 282: { +case 285: { AST::DoWhileStatement *node = makeAstNode<AST::DoWhileStatement> (driver->nodePool(), sym(2).Statement, sym(5).Expression); node->doToken = loc(1); node->whileToken = loc(3); @@ -1826,9 +1408,7 @@ case 282: { sym(1).Node = node; } break; -#line 2435 "qmljs.g" - -case 283: { +case 286: { AST::WhileStatement *node = makeAstNode<AST::WhileStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->whileToken = loc(1); node->lparenToken = loc(2); @@ -1836,9 +1416,7 @@ case 283: { sym(1).Node = node; } break; -#line 2446 "qmljs.g" - -case 284: { +case 287: { AST::ForStatement *node = makeAstNode<AST::ForStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); node->forToken = loc(1); @@ -1849,9 +1427,7 @@ case 284: { sym(1).Node = node; } break; -#line 2460 "qmljs.g" - -case 285: { +case 288: { AST::LocalForStatement *node = makeAstNode<AST::LocalForStatement> (driver->nodePool(), sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); @@ -1864,9 +1440,7 @@ case 285: { sym(1).Node = node; } break; -#line 2476 "qmljs.g" - -case 286: { +case 289: { AST:: ForEachStatement *node = makeAstNode<AST::ForEachStatement> (driver->nodePool(), sym(3).Expression, sym(5).Expression, sym(7).Statement); node->forToken = loc(1); @@ -1876,9 +1450,7 @@ case 286: { sym(1).Node = node; } break; -#line 2489 "qmljs.g" - -case 287: { +case 290: { AST::LocalForEachStatement *node = makeAstNode<AST::LocalForEachStatement> (driver->nodePool(), sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); node->forToken = loc(1); @@ -1889,18 +1461,14 @@ case 287: { sym(1).Node = node; } break; -#line 2504 "qmljs.g" - -case 289: { +case 292: { AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool()); node->continueToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2515 "qmljs.g" - -case 291: { +case 294: { AST::ContinueStatement *node = makeAstNode<AST::ContinueStatement> (driver->nodePool(), sym(2).sval); node->continueToken = loc(1); node->identifierToken = loc(2); @@ -1908,18 +1476,14 @@ case 291: { sym(1).Node = node; } break; -#line 2527 "qmljs.g" - -case 293: { +case 296: { AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2538 "qmljs.g" - -case 295: { +case 298: { AST::BreakStatement *node = makeAstNode<AST::BreakStatement> (driver->nodePool(), sym(2).sval); node->breakToken = loc(1); node->identifierToken = loc(2); @@ -1927,18 +1491,14 @@ case 295: { sym(1).Node = node; } break; -#line 2550 "qmljs.g" - -case 297: { +case 300: { AST::ReturnStatement *node = makeAstNode<AST::ReturnStatement> (driver->nodePool(), sym(2).Expression); node->returnToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -#line 2560 "qmljs.g" - -case 298: { +case 301: { AST::WithStatement *node = makeAstNode<AST::WithStatement> (driver->nodePool(), sym(3).Expression, sym(5).Statement); node->withToken = loc(1); node->lparenToken = loc(2); @@ -1946,9 +1506,7 @@ case 298: { sym(1).Node = node; } break; -#line 2571 "qmljs.g" - -case 299: { +case 302: { AST::SwitchStatement *node = makeAstNode<AST::SwitchStatement> (driver->nodePool(), sym(3).Expression, sym(5).CaseBlock); node->switchToken = loc(1); node->lparenToken = loc(2); @@ -1956,122 +1514,90 @@ case 299: { sym(1).Node = node; } break; -#line 2582 "qmljs.g" - -case 300: { +case 303: { AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -#line 2592 "qmljs.g" - -case 301: { +case 304: { AST::CaseBlock *node = makeAstNode<AST::CaseBlock> (driver->nodePool(), sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(5); sym(1).Node = node; } break; -#line 2602 "qmljs.g" - -case 302: { +case 305: { sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClause); } break; -#line 2609 "qmljs.g" - -case 303: { +case 306: { sym(1).Node = makeAstNode<AST::CaseClauses> (driver->nodePool(), sym(1).CaseClauses, sym(2).CaseClause); } break; -#line 2616 "qmljs.g" - -case 304: { +case 307: { sym(1).Node = 0; } break; -#line 2623 "qmljs.g" - -case 305: { +case 308: { sym(1).Node = sym(1).CaseClauses->finish (); } break; -#line 2630 "qmljs.g" - -case 306: { +case 309: { AST::CaseClause *node = makeAstNode<AST::CaseClause> (driver->nodePool(), sym(2).Expression, sym(4).StatementList); node->caseToken = loc(1); node->colonToken = loc(3); sym(1).Node = node; } break; -#line 2640 "qmljs.g" - -case 307: { +case 310: { AST::DefaultClause *node = makeAstNode<AST::DefaultClause> (driver->nodePool(), sym(3).StatementList); node->defaultToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; - -#line 2650 "qmljs.g" -case 308: -#line 2653 "qmljs.g" - -case 309: { +case 311: +case 312: { AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), driver->intern(lexer->characterBuffer(), lexer->characterCount()), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -#line 2663 "qmljs.g" - -case 310: { +case 313: { AST::LabelledStatement *node = makeAstNode<AST::LabelledStatement> (driver->nodePool(), sym(1).sval, sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -#line 2674 "qmljs.g" - -case 312: { +case 315: { AST::ThrowStatement *node = makeAstNode<AST::ThrowStatement> (driver->nodePool(), sym(2).Expression); node->throwToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -#line 2684 "qmljs.g" - -case 313: { +case 316: { AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch); node->tryToken = loc(1); sym(1).Node = node; } break; -#line 2693 "qmljs.g" - -case 314: { +case 317: { AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -#line 2702 "qmljs.g" - -case 315: { +case 318: { AST::TryStatement *node = makeAstNode<AST::TryStatement> (driver->nodePool(), sym(2).Statement, sym(3).Catch, sym(4).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -#line 2711 "qmljs.g" - -case 316: { +case 319: { AST::Catch *node = makeAstNode<AST::Catch> (driver->nodePool(), sym(3).sval, sym(5).Block); node->catchToken = loc(1); node->lparenToken = loc(2); @@ -2080,26 +1606,20 @@ case 316: { sym(1).Node = node; } break; -#line 2723 "qmljs.g" - -case 317: { +case 320: { AST::Finally *node = makeAstNode<AST::Finally> (driver->nodePool(), sym(2).Block); node->finallyToken = loc(1); sym(1).Node = node; } break; -#line 2733 "qmljs.g" - -case 319: { +case 322: { AST::DebuggerStatement *node = makeAstNode<AST::DebuggerStatement> (driver->nodePool()); node->debuggerToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -#line 2743 "qmljs.g" - -case 320: { +case 323: { AST::FunctionDeclaration *node = makeAstNode<AST::FunctionDeclaration> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); node->identifierToken = loc(2); @@ -2110,9 +1630,7 @@ case 320: { sym(1).Node = node; } break; -#line 2757 "qmljs.g" - -case 321: { +case 324: { AST::FunctionExpression *node = makeAstNode<AST::FunctionExpression> (driver->nodePool(), sym(2).sval, sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); if (sym(2).sval) @@ -2124,85 +1642,59 @@ case 321: { sym(1).Node = node; } break; -#line 2772 "qmljs.g" - -case 322: { +case 325: { AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).sval); node->identifierToken = loc(1); sym(1).Node = node; } break; -#line 2781 "qmljs.g" - -case 323: { +case 326: { AST::FormalParameterList *node = makeAstNode<AST::FormalParameterList> (driver->nodePool(), sym(1).FormalParameterList, sym(3).sval); node->commaToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -#line 2791 "qmljs.g" - -case 324: { +case 327: { sym(1).Node = 0; } break; -#line 2798 "qmljs.g" - -case 325: { +case 328: { sym(1).Node = sym(1).FormalParameterList->finish (); } break; -#line 2805 "qmljs.g" - -case 326: { +case 329: { sym(1).Node = 0; } break; -#line 2814 "qmljs.g" - -case 328: { +case 331: { sym(1).Node = makeAstNode<AST::FunctionBody> (driver->nodePool(), sym(1).SourceElements->finish ()); } break; -#line 2829 "qmljs.g" - -case 329: { +case 332: { sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElement); } break; -#line 2836 "qmljs.g" - -case 330: { +case 333: { sym(1).Node = makeAstNode<AST::SourceElements> (driver->nodePool(), sym(1).SourceElements, sym(2).SourceElement); } break; -#line 2843 "qmljs.g" - -case 331: { +case 334: { sym(1).Node = makeAstNode<AST::StatementSourceElement> (driver->nodePool(), sym(1).Statement); } break; -#line 2850 "qmljs.g" - -case 332: { +case 335: { sym(1).Node = makeAstNode<AST::FunctionSourceElement> (driver->nodePool(), sym(1).FunctionDeclaration); } break; -#line 2857 "qmljs.g" - -case 333: { +case 336: { sym(1).sval = 0; } break; -#line 2866 "qmljs.g" - -case 335: { +case 338: { sym(1).Node = 0; } break; -#line 2874 "qmljs.g" - } // switch action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT); } // if @@ -2293,7 +1785,8 @@ case 335: { } for (int tk = 1; tk < TERMINAL_COUNT; ++tk) { - if (tk == T_AUTOMATIC_SEMICOLON) + if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM || + tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION) continue; int a = t_action(errorState, tk); diff --git a/src/declarative/qml/parser/qmljsparser_p.h b/src/declarative/qml/parser/qmljsparser_p.h index e4ca20a..9273039 100644 --- a/src/declarative/qml/parser/qmljsparser_p.h +++ b/src/declarative/qml/parser/qmljsparser_p.h @@ -1,7 +1,5 @@ // This file was generated by qlalr - DO NOT EDIT! -#line 148 "qmljs.g" - /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). @@ -128,10 +126,29 @@ public: Parser(Engine *engine); ~Parser(); - bool parse(); + // parse a UI program + bool parse() { return parse(T_FEED_UI_PROGRAM); } + bool parseStatement() { return parse(T_FEED_JS_STATEMENT); } + bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); } + + AST::UiProgram *ast() const + { return AST::cast<AST::UiProgram *>(program); } + + AST::Statement *statement() const + { + if (! program) + return 0; - AST::UiProgram *ast() - { return program; } + return program->statementCast(); + } + + AST::ExpressionNode *expression() const + { + if (! program) + return 0; + + return program->expressionCast(); + } QList<DiagnosticMessage> diagnosticMessages() const { return diagnostic_messages; } @@ -156,6 +173,8 @@ public: { return diagnosticMessage().loc.startColumn; } protected: + bool parse(int startToken); + void reallocateStack(); inline Value &sym(int index) @@ -174,7 +193,7 @@ protected: int *state_stack; AST::SourceLocation *location_stack; - AST::UiProgram *program; + AST::Node *program; // error recovery enum { TOKEN_BUFFER_SIZE = 3 }; @@ -200,15 +219,9 @@ protected: -#line 1015 "qmljs.g" - -#define J_SCRIPT_REGEXPLITERAL_RULE1 69 - -#line 1032 "qmljs.g" - -#define J_SCRIPT_REGEXPLITERAL_RULE2 70 +#define J_SCRIPT_REGEXPLITERAL_RULE1 72 -#line 2994 "qmljs.g" +#define J_SCRIPT_REGEXPLITERAL_RULE2 73 QT_END_NAMESPACE diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 04c0ca2..857b07e 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -12,7 +12,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlproxymetaobject.cpp \ qml/qmlvme.cpp \ qml/qmlcompiler.cpp \ - qml/qmlcompiledcomponent.cpp \ + qml/qmlcompileddata.cpp \ qml/qmlboundsignal.cpp \ qml/qmldom.cpp \ qml/qmlrefcount.cpp \ @@ -43,7 +43,6 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlboundsignal_p.h \ qml/qmlparserstatus.h \ qml/qmlproxymetaobject_p.h \ - qml/qmlcompiledcomponent_p.h \ qml/qmlvme_p.h \ qml/qmlcompiler_p.h \ qml/qmlengine_p.h \ diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index 478491f..d6d6625 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -181,6 +181,9 @@ static QVariant toObjectOrVariant(const QVariant &v) static QVariant fetch_value(QObject *o, int idx, int type) { + if (!o) + return QVariant(); + switch(type) { case QVariant::String: { @@ -823,7 +826,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(0); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; @@ -835,7 +838,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(1); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; @@ -848,7 +851,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = qvariant_cast<QObject *>(o); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (instr.constant.notify != 0) + if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; diff --git a/src/declarative/qml/qmlcompiledcomponent.cpp b/src/declarative/qml/qmlcompiledcomponent.cpp deleted file mode 100644 index bea736a..0000000 --- a/src/declarative/qml/qmlcompiledcomponent.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmlcompiledcomponent_p.h" -#include "qmlparser_p.h" -#include <QtCore/qdebug.h> -#include <QmlComponent> -using namespace QmlParser; - -QT_BEGIN_NAMESPACE - -DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); - -QmlCompiledComponent::QmlCompiledComponent() -: dumpStatus(NoDump) -{ -} - -QmlCompiledComponent::~QmlCompiledComponent() -{ - for (int ii = 0; ii < synthesizedMetaObjects.count(); ++ii) - qFree(synthesizedMetaObjects.at(ii)); -} - - -void QmlCompiledComponent::dumpInstructions() -{ - if (!compilerDump()) - return; - - if (!name.isEmpty()) - qWarning() << name; - qWarning() << "Index\tLine\tOperation\t\tData1\tData2\t\tComments"; - qWarning() << "-------------------------------------------------------------------------------"; - for (int ii = 0; ii < bytecode.count(); ++ii) { - dump(&bytecode[ii], ii); - } - qWarning() << "-------------------------------------------------------------------------------"; -} - -void QmlCompiledComponent::dumpPre() -{ - if (!(dumpStatus & DumpPre)) { - dumpInstructions(); - dumpStatus = (DumpStatus)(dumpStatus | DumpPre); - } -} - -void QmlCompiledComponent::dumpPost() -{ - if (!(dumpStatus & DumpPost)) { - dumpInstructions(); - dumpStatus = (DumpStatus)(dumpStatus | DumpPost); - } - -} - -QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp new file mode 100644 index 0000000..0834794 --- /dev/null +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcompiler_p.h" +#include "qmlengine.h" +#include "qmlcomponent.h" +#include "qmlcomponent_p.h" +#include "qmlcontext.h" +#include "qmlcontext_p.h" +#include <private/qobject_p.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); + +int QmlCompiledData::pack(const char *data, size_t size) +{ + const char *p = packData.constData(); + unsigned int ps = packData.size(); + + for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) { + if (0 == ::memcmp(p + ii, data, size)) + return ii; + } + + int rv = packData.size(); + packData.append(data, size); + return rv; +} + +int QmlCompiledData::indexForString(const QString &data) +{ + int idx = primitives.indexOf(data); + if (idx == -1) { + idx = primitives.count(); + primitives << data; + } + return idx; +} + +int QmlCompiledData::indexForByteArray(const QByteArray &data) +{ + int idx = datas.indexOf(data); + if (idx == -1) { + idx = datas.count(); + datas << data; + } + return idx; +} + +int QmlCompiledData::indexForFloat(float *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= floatData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (floatData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = floatData.count(); + for (int ii = 0; ii < count; ++ii) + floatData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForInt(int *data, int count) +{ + Q_ASSERT(count > 0); + + for (int ii = 0; ii <= intData.count() - count; ++ii) { + bool found = true; + for (int jj = 0; jj < count; ++jj) { + if (intData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if (found) + return ii; + } + + int idx = intData.count(); + for (int ii = 0; ii < count; ++ii) + intData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForLocation(const QmlParser::Location &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l; + return rv; +} + +int QmlCompiledData::indexForLocation(const QmlParser::LocationSpan &l) +{ + // ### FIXME + int rv = locations.count(); + locations << l.start << l.end; + return rv; +} + +QmlCompiledData::QmlCompiledData() +{ +} + +QmlCompiledData::~QmlCompiledData() +{ + for (int ii = 0; ii < types.count(); ++ii) { + if (types.at(ii).ref) + types.at(ii).ref->release(); + } +} + +QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt) const +{ + if (type) { + QObject *rv = type->create(); + if (rv) + QmlEngine::setContextForObject(rv, ctxt); + return rv; + } else { + Q_ASSERT(component); + QObject *rv = component->create(ctxt); + QmlContext *ctxt = qmlContext(rv); + if(ctxt) { + static_cast<QmlContextPrivate *>(QObjectPrivate::get(ctxt))->typeName = className; + } + return rv; + } +} + +const QMetaObject *QmlCompiledData::TypeReference::metaObject() const +{ + if (type) { + return type->metaObject(); + } else { + Q_ASSERT(component); + return &static_cast<QmlComponentPrivate *>(QObjectPrivate::get(component))->cc->root; + } +} + +void QmlCompiledData::dumpInstructions() +{ + if (!compilerDump()) + return; + + if (!name.isEmpty()) + qWarning() << name; + qWarning() << "Index\tLine\tOperation\t\tData1\tData2\t\tComments"; + qWarning() << "-------------------------------------------------------------------------------"; + for (int ii = 0; ii < bytecode.count(); ++ii) { + dump(&bytecode[ii], ii); + } + qWarning() << "-------------------------------------------------------------------------------"; +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index b04c932..ed9df03 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -52,7 +52,6 @@ #include <QPointF> #include <QSizeF> #include <QRectF> -#include <private/qmlcompiledcomponent_p.h> #include <private/qmlstringconverters_p.h> #include <private/qmlengine_p.h> #include <qmlengine.h> @@ -71,90 +70,6 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; -int QmlCompiledData::indexForString(const QString &data) -{ - int idx = primitives.indexOf(data); - if (idx == -1) { - idx = primitives.count(); - primitives << data; - } - return idx; -} - -int QmlCompiledData::indexForByteArray(const QByteArray &data) -{ - int idx = datas.indexOf(data); - if (idx == -1) { - idx = datas.count(); - datas << data; - } - return idx; -} - -int QmlCompiledData::indexForFloat(float *data, int count) -{ - Q_ASSERT(count > 0); - - for (int ii = 0; ii <= floatData.count() - count; ++ii) { - bool found = true; - for (int jj = 0; jj < count; ++jj) { - if (floatData.at(ii + jj) != data[jj]) { - found = false; - break; - } - } - - if (found) - return ii; - } - - int idx = floatData.count(); - for (int ii = 0; ii < count; ++ii) - floatData << data[ii]; - - return idx; -} - -int QmlCompiledData::indexForInt(int *data, int count) -{ - Q_ASSERT(count > 0); - - for (int ii = 0; ii <= intData.count() - count; ++ii) { - bool found = true; - for (int jj = 0; jj < count; ++jj) { - if (intData.at(ii + jj) != data[jj]) { - found = false; - break; - } - } - - if (found) - return ii; - } - - int idx = intData.count(); - for (int ii = 0; ii < count; ++ii) - intData << data[ii]; - - return idx; -} - -int QmlCompiledData::indexForLocation(const QmlParser::Location &l) -{ - // ### FIXME - int rv = locations.count(); - locations << l; - return rv; -} - -int QmlCompiledData::indexForLocation(const QmlParser::LocationSpan &l) -{ - // ### FIXME - int rv = locations.count(); - locations << l.start << l.end; - return rv; -} - QmlCompiler::QmlCompiler() : output(0) { @@ -241,14 +156,13 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name) } // Compile a simple assignment of v to prop into instr -bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - QmlParser::Value *v) +bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) { QString string = v->value.asScript(); if (!prop.isWritable()) - COMPILE_EXCEPTION2(v, "Cannot assign literal value to read-only property" << prop.name()); + COMPILE_EXCEPTION2(v, "Invalid property assignment: read-only property"); if (prop.isEnumType()) { int value; @@ -257,12 +171,136 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, } else value = prop.enumerator().keyToValue(string.toLatin1().constData()); if (value == -1) - COMPILE_EXCEPTION2(v, "Cannot assign unknown enumeration to property" << prop.name()); + COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown enumeration"); + return true; + } + int type = prop.userType(); + switch(type) { + case -1: + break; + case QVariant::String: + if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: string expected"); + break; + case QVariant::Url: + if (!v->value.isString()) COMPILE_EXCEPTION2(v, "Invalid property assignment: url expected"); + break; + case QVariant::UInt: + { + bool ok; + string.toUInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: unsigned int expected"); + } + break; + case QVariant::Int: + { + bool ok; + string.toInt(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: int expected"); + } + break; + case QMetaType::Float: + { + bool ok; + string.toFloat(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: float expected"); + } + break; + case QVariant::Double: + { + bool ok; + string.toDouble(&ok); + if (!v->value.isNumber() || !ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: double expected"); + } + break; + case QVariant::Color: + { + QColor c = QmlStringConverters::colorFromString(string); + if (!c.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: color expected"); + } + break; + case QVariant::Date: + { + QDate d = QDate::fromString(string, Qt::ISODate); + if (!d.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: date expected"); + } + break; + case QVariant::Time: + { + QTime time = QTime::fromString(string, Qt::ISODate); + if (!time.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: time expected"); + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + if (!dateTime.isValid()) COMPILE_EXCEPTION2(v, "Invalid property assignment: datetime expected"); + } + break; + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = QmlStringConverters::pointFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: point expected"); + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: size expected"); + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION2(v, "Invalid property assignment: rect expected"); + } + break; + case QVariant::Bool: + { + if (!v->value.isBoolean()) COMPILE_EXCEPTION2(v, "Invalid property assignment: boolean expected"); + } + break; + default: + { + int t = prop.type(); + if (t == QVariant::UserType) + t = prop.userType(); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(t); + if (!converter) + COMPILE_EXCEPTION2(v, "Invalid property assignment: unknown type" << prop.type()); + } + break; + } + return true; +} + +void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *v) +{ + QString string = v->value.asScript(); + + QmlInstruction instr; + instr.line = v->location.start.line; + if (prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string.toLatin1().constData()); + } else + value = prop.enumerator().keyToValue(string.toLatin1().constData()); + instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); instr.storeInteger.value = value; - return true; + output->bytecode << instr; + return; } + int type = prop.userType(); switch(type) { case -1: @@ -291,51 +329,33 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, { instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); - bool ok; - int value = string.toUInt(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to unsigned integer"); - instr.storeInteger.value = value; + instr.storeInteger.value = string.toUInt(); } break; case QVariant::Int: { instr.type = QmlInstruction::StoreInteger; instr.storeInteger.propertyIndex = prop.propertyIndex(); - bool ok; - int value = string.toInt(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to integer"); - instr.storeInteger.value = value; + instr.storeInteger.value = string.toInt(); } break; case QMetaType::Float: { instr.type = QmlInstruction::StoreFloat; instr.storeFloat.propertyIndex = prop.propertyIndex(); - bool ok; - float value = string.toFloat(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to float number"); - instr.storeFloat.value = value; + instr.storeFloat.value = string.toFloat(); } break; case QVariant::Double: { instr.type = QmlInstruction::StoreDouble; instr.storeDouble.propertyIndex = prop.propertyIndex(); - bool ok; - double value = string.toDouble(&ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to double number"); - instr.storeDouble.value = value; + instr.storeDouble.value = string.toDouble(); } break; case QVariant::Color: { QColor c = QmlStringConverters::colorFromString(string); - if (!c.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to color"); instr.type = QmlInstruction::StoreColor; instr.storeColor.propertyIndex = prop.propertyIndex(); instr.storeColor.value = c.rgba(); @@ -344,8 +364,6 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Date: { QDate d = QDate::fromString(string, Qt::ISODate); - if (!d.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to date"); instr.type = QmlInstruction::StoreDate; instr.storeDate.propertyIndex = prop.propertyIndex(); instr.storeDate.value = d.toJulianDay(); @@ -354,9 +372,8 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Time: { QTime time = QTime::fromString(string, Qt::ISODate); - if (!time.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to time"); - int data[] = { time.hour(), time.minute(), time.second(), time.msec() }; + int data[] = { time.hour(), time.minute(), + time.second(), time.msec() }; int index = output->indexForInt(data, 4); instr.type = QmlInstruction::StoreTime; instr.storeTime.propertyIndex = prop.propertyIndex(); @@ -366,8 +383,6 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::DateTime: { QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); - if (!dateTime.isValid()) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to date and time"); int data[] = { dateTime.date().toJulianDay(), dateTime.time().hour(), dateTime.time().minute(), @@ -382,93 +397,79 @@ bool QmlCompiler::compileStoreInstruction(QmlInstruction &instr, case QVariant::Point: case QVariant::PointF: { - bool ok; - QPointF point = QmlStringConverters::pointFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to point"); - float data[] = { point.x(), point.y() }; - int index = output->indexForFloat(data, 2); - if (type == QVariant::PointF) - instr.type = QmlInstruction::StorePointF; - else - instr.type = QmlInstruction::StorePoint; - instr.storeRealPair.propertyIndex = prop.propertyIndex(); - instr.storeRealPair.valueIndex = index; + bool ok; + QPointF point = + QmlStringConverters::pointFFromString(string, &ok); + float data[] = { point.x(), point.y() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::PointF) + instr.type = QmlInstruction::StorePointF; + else + instr.type = QmlInstruction::StorePoint; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; } break; case QVariant::Size: case QVariant::SizeF: { - bool ok; - QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to size"); - float data[] = { size.width(), size.height() }; - int index = output->indexForFloat(data, 2); - if (type == QVariant::SizeF) - instr.type = QmlInstruction::StoreSizeF; - else - instr.type = QmlInstruction::StoreSize; - instr.storeRealPair.propertyIndex = prop.propertyIndex(); - instr.storeRealPair.valueIndex = index; + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(string, &ok); + float data[] = { size.width(), size.height() }; + int index = output->indexForFloat(data, 2); + if (type == QVariant::SizeF) + instr.type = QmlInstruction::StoreSizeF; + else + instr.type = QmlInstruction::StoreSize; + instr.storeRealPair.propertyIndex = prop.propertyIndex(); + instr.storeRealPair.valueIndex = index; } break; case QVariant::Rect: case QVariant::RectF: { - bool ok; - QRectF rect = QmlStringConverters::rectFFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to rect"); - float data[] = { rect.x(), rect.y(), - rect.width(), rect.height() }; - int index = output->indexForFloat(data, 4); - if (type == QVariant::RectF) - instr.type = QmlInstruction::StoreRectF; - else - instr.type = QmlInstruction::StoreRect; - instr.storeRect.propertyIndex = prop.propertyIndex(); - instr.storeRect.valueIndex = index; + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(string, &ok); + float data[] = { rect.x(), rect.y(), + rect.width(), rect.height() }; + int index = output->indexForFloat(data, 4); + if (type == QVariant::RectF) + instr.type = QmlInstruction::StoreRectF; + else + instr.type = QmlInstruction::StoreRect; + instr.storeRect.propertyIndex = prop.propertyIndex(); + instr.storeRect.valueIndex = index; } break; case QVariant::Bool: { - bool ok; - bool b = QmlStringConverters::boolFromString(string, &ok); - if (!ok) - COMPILE_EXCEPTION2(v, "Cannot convert value" << string << "to boolean"); - instr.type = QmlInstruction::StoreBool; - instr.storeBool.propertyIndex = prop.propertyIndex(); - instr.storeBool.value = b; + bool b = v->value.asBoolean(); + instr.type = QmlInstruction::StoreBool; + instr.storeBool.propertyIndex = prop.propertyIndex(); + instr.storeBool.value = b; } break; default: { - int t = prop.type(); - if (t == QVariant::UserType) - t = prop.userType(); - QmlMetaType::StringConverter converter = - QmlMetaType::customStringConverter(t); - if (converter) { - int index = output->customTypeData.count(); - instr.type = QmlInstruction::AssignCustomType; - instr.assignCustomType.propertyIndex = prop.propertyIndex(); - instr.assignCustomType.valueIndex = index; - - QmlCompiledData::CustomTypeData data; - data.index = output->indexForString(string); - data.type = t; - output->customTypeData << data; - break; - } + int t = prop.type(); + if (t == QVariant::UserType) + t = prop.userType(); + int index = output->customTypeData.count(); + instr.type = QmlInstruction::AssignCustomType; + instr.assignCustomType.propertyIndex = prop.propertyIndex(); + instr.assignCustomType.valueIndex = index; + + QmlCompiledData::CustomTypeData data; + data.index = output->indexForString(string); + data.type = t; + output->customTypeData << data; } - COMPILE_EXCEPTION2(v, "Cannot assign to property" << prop.name() << "of unknown type" << prop.type()); break; } - return true; + output->bytecode << instr; } -void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) +void QmlCompiler::reset(QmlCompiledData *cc) { cc->types.clear(); cc->primitives.clear(); @@ -476,17 +477,12 @@ void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) cc->intData.clear(); cc->customTypeData.clear(); cc->datas.clear(); - if (deleteMemory) { - for (int ii = 0; ii < cc->synthesizedMetaObjects.count(); ++ii) - qFree(cc->synthesizedMetaObjects.at(ii)); - } - cc->synthesizedMetaObjects.clear(); cc->bytecode.clear(); } bool QmlCompiler::compile(QmlEngine *engine, QmlCompositeTypeData *unit, - QmlCompiledComponent *out) + QmlCompiledData *out) { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer<QFxPerf::Compilation> pc; @@ -494,14 +490,14 @@ bool QmlCompiler::compile(QmlEngine *engine, exceptions.clear(); Q_ASSERT(out); - reset(out, true); + reset(out); output = out; // Compile types for (int ii = 0; ii < unit->types.count(); ++ii) { QmlCompositeTypeData::TypeReference &tref = unit->types[ii]; - QmlCompiledComponent::TypeReference ref; + QmlCompiledData::TypeReference ref; if (tref.type) ref.type = tref.type; else if (tref.unit) { @@ -514,7 +510,7 @@ bool QmlCompiler::compile(QmlEngine *engine, unit->data.types().at(ii)); exceptions << error; exceptions << ref.component->errors(); - reset(out, true); + reset(out); return false; } ref.ref = tref.unit; @@ -530,9 +526,9 @@ bool QmlCompiler::compile(QmlEngine *engine, compileTree(root); if (!isError()) { - out->dumpPre(); + out->dumpInstructions(); } else { - reset(out, true); + reset(out); } output = 0; @@ -544,24 +540,23 @@ void QmlCompiler::compileTree(Object *tree) { compileState.root = tree; + if (!buildObject(tree, BindingContext()) || !completeComponentBuild()) + return; + QmlInstruction init; init.type = QmlInstruction::Init; init.line = 0; - init.init.dataSize = 0; - init.init.bindingsSize = 0; - init.init.parserStatusSize = 0; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; output->bytecode << init; - if (!compileObject(tree, 0)) // Compile failed - return; + genObject(tree); QmlInstruction def; init.line = 0; def.type = QmlInstruction::SetDefault; output->bytecode << def; - finalizeComponent(0); - if (tree->metatype) static_cast<QMetaObject &>(output->root) = *tree->metaObject(); else @@ -569,55 +564,35 @@ void QmlCompiler::compileTree(Object *tree) } -bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT (obj->type != -1); - const QmlCompiledData::TypeReference &tr = output->types.at(obj->type); + const QmlCompiledData::TypeReference &tr = + output->types.at(obj->type); obj->metatype = tr.metaObject(); + if (tr.component) obj->url = tr.component->url(); - if (output->types.at(obj->type).className == "Component") { - COMPILE_CHECK(compileComponent(obj, ctxt)); + // This object is a "Component" element + if (obj->metatype == &QmlComponent::staticMetaObject) { + COMPILE_CHECK(buildComponent(obj, ctxt)); return true; } + // Object instantiations reset the binding context BindingContext objCtxt(obj); - int createInstrIdx = output->bytecode.count(); - // Create the object - QmlInstruction create; - create.type = QmlInstruction::CreateObject; - create.line = obj->location.start.line; - create.create.data = -1; - create.create.type = obj->type; - output->bytecode << create; - - // Create the synthesized meta object - COMPILE_CHECK(compileDynamicMeta(obj)); + // Create the synthesized meta object, ignoring aliases + COMPILE_CHECK(mergeDynamicMetaProperties(obj)); + COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); // Find the native type and check for the QmlParserStatus interface - // ### Optimize - const QMetaObject *mo = obj->metatype; - QmlType *type = 0; - while (!type && mo) { - type = QmlMetaType::qmlType(mo); - mo = mo->superClass(); - } + QmlType *type = toQmlType(obj); Q_ASSERT(type); - int parserStatusCast = type->parserStatusCast(); - - // If the type support the QmlParserStatusInterface we need to invoke - // classBegin() - if (parserStatusCast != -1) { - QmlInstruction begin; - begin.type = QmlInstruction::BeginObject; - begin.begin.castValue = parserStatusCast; - begin.line = obj->location.start.line; - output->bytecode << begin; - + obj->parserStatusCast = type->parserStatusCast(); + if (obj->parserStatusCast != -1) compileState.parserStatusCount++; - } // Check if this is a custom parser type. Custom parser types allow // assignments to non-existant properties. These assignments are then @@ -626,57 +601,72 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) output->types.at(obj->type).type->customParser() != 0; QList<QmlCustomParserProperty> customProps; - QStringList deferred = deferredProperties(obj); - QList<Property *> deferredProps; + // Fetch the list of deferred properties + QStringList deferredList = deferredProperties(obj); + + // Must do id property first. This is to ensure that the id given to any + // id reference created matches the order in which the objects are + // instantiated + foreach(Property *prop, obj->properties) { + if (prop->name == "id") { + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + break; + } + } - // Compile all explicit properties specified + // Build all explicit properties specified foreach(Property *prop, obj->properties) { + if (prop->name == "id") + continue; + + bool canDefer = false; if (isCustomParser) { - // Custom parser types don't support signal properties if (testProperty(prop, obj)) { - if (deferred.contains(QString::fromLatin1(prop->name.constData()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } else { customProps << QmlCustomParserNodePrivate::fromProperty(prop); } } else { - if (isSignalPropertyName(prop->name)) { - COMPILE_CHECK(compileSignal(prop,obj)); + if (isSignalPropertyName(prop->name)) { + COMPILE_CHECK(buildSignal(prop,obj,objCtxt)); } else { - if (deferred.contains(QString::fromLatin1(prop->name.constData()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } } + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(prop->name)) + prop->isDeferred = true; + } - // Compile the default property + // Build the default property if (obj->defaultProperty) { Property *prop = obj->defaultProperty; + bool canDefer = false; if (isCustomParser) { if (testProperty(prop, obj)) { - QMetaProperty p = deferred.isEmpty()?QMetaProperty():QmlMetaType::defaultProperty(obj->metaObject()); - if (deferred.contains(QString::fromLatin1(p.name()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } else { customProps << QmlCustomParserNodePrivate::fromProperty(prop); } } else { - QMetaProperty p = deferred.isEmpty()?QMetaProperty():QmlMetaType::defaultProperty(obj->metaObject()); - if (deferred.contains(QString::fromLatin1(p.name()))) - deferredProps << prop; - else - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + int ids = compileState.ids.count(); + COMPILE_CHECK(buildProperty(prop, obj, objCtxt)); + canDefer = ids == compileState.ids.count(); } + if (canDefer && !deferredList.isEmpty() && + deferredList.contains(prop->name)) + prop->isDeferred = true; } // Compile custom parser parts @@ -684,16 +674,83 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) // ### Check for failure bool ok = false; QmlCustomParser *cp = output->types.at(obj->type).type->customParser(); - QByteArray customData = cp->compile(customProps, &ok); + obj->custom = cp->compile(customProps, &ok); if(!ok) COMPILE_EXCEPTION("Failure compiling custom type"); - if(!customData.isEmpty()) - output->bytecode[createInstrIdx].create.data = - output->indexForByteArray(customData); } - // Build the deferred block - if (!deferredProps.isEmpty()) { + return true; +} + +void QmlCompiler::genObject(QmlParser::Object *obj) +{ + if (obj->metatype == &QmlComponent::staticMetaObject) { + genComponent(obj); + return; + } + + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->location.start.line; + create.create.data = -1; + if (!obj->custom.isEmpty()) + create.create.data = output->indexForByteArray(obj->custom); + create.create.type = obj->type; + output->bytecode << create; + + // Setup the synthesized meta object if necessary + if (!obj->metadata.isEmpty()) { + QmlInstruction meta; + meta.type = QmlInstruction::StoreMetaObject; + meta.line = -1; + meta.storeMeta.data = output->indexForByteArray(obj->metadata); + meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); + meta.storeMeta.slotData = -1; + output->bytecode << meta; + } + + // Set the object id + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = -1; + id.setId.value = output->indexForString(obj->id); + output->bytecode << id; + } + + // Begin the class + if (obj->parserStatusCast != -1) { + QmlInstruction begin; + begin.type = QmlInstruction::BeginObject; + begin.begin.castValue = obj->parserStatusCast; + begin.line = obj->location.start.line; + output->bytecode << begin; + } + + genObjectBody(obj); + + // Complete the the class + if (obj->parserStatusCast != -1) { + QmlInstruction complete; + complete.type = QmlInstruction::CompleteObject; + complete.complete.castValue = obj->parserStatusCast; + complete.line = obj->location.start.line; + output->bytecode << complete; + } +} + +void QmlCompiler::genObjectBody(QmlParser::Object *obj) +{ + bool seenDefer = false; + foreach(Property *prop, obj->valueProperties) { + if (prop->isDeferred) { + seenDefer = true; + continue; + } + genValueProperty(prop, obj); + } + if (seenDefer) { QmlInstruction defer; defer.type = QmlInstruction::Defer; defer.line = 0; @@ -701,44 +758,147 @@ bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) int deferIdx = output->bytecode.count(); output->bytecode << defer; - // ### This is lame, we should check if individual properties have - // ids defined within them - int idCount = compileState.ids.count(); - foreach (Property *prop, deferredProps) { - COMPILE_CHECK(compileProperty(prop, obj, objCtxt)); + foreach(Property *prop, obj->valueProperties) { + if (!prop->isDeferred) + continue; + genValueProperty(prop, obj); } - if (idCount == compileState.ids.count()) - output->bytecode[deferIdx].defer.deferCount = - output->bytecode.count() - deferIdx - 1; + + output->bytecode[deferIdx].defer.deferCount = + output->bytecode.count() - deferIdx - 1; } - // If the type support the QmlParserStatusInterface we need to invoke - // classComplete() - if (parserStatusCast != -1) { - QmlInstruction complete; - complete.type = QmlInstruction::CompleteObject; - complete.complete.castValue = parserStatusCast; - complete.line = obj->location.start.line; - output->bytecode << complete; - } + foreach(Property *prop, obj->signalProperties) { - return true; + QmlParser::Value *v = prop->values.at(0); + + if (v->type == Value::SignalObject) { + + genObject(v->object); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignalObject; + assign.line = v->location.start.line; + assign.assignSignalObject.signal = + output->indexForByteArray(prop->name); + output->bytecode << assign; + + } else if (v->type == Value::SignalExpression) { + + QmlInstruction store; + store.type = QmlInstruction::StoreSignal; + store.line = v->location.start.line; + store.storeSignal.signalIndex = prop->index; + store.storeSignal.value = + output->indexForString(v->value.asScript().trimmed()); + output->bytecode << store; + + } + + } + + foreach(Property *prop, obj->attachedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchAttached; + fetch.line = prop->location.start.line; + fetch.fetchAttached.id = prop->index; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } + + foreach(Property *prop, obj->groupedProperties) { + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchObject; + fetch.fetch.property = prop->index; + fetch.line = prop->location.start.line; + output->bytecode << fetch; + + genObjectBody(prop->value); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->location.start.line; + output->bytecode << pop; + } +} + +void QmlCompiler::genComponent(QmlParser::Object *obj) +{ + QmlParser::Object *root = obj->defaultProperty->values.at(0)->object; + Q_ASSERT(root); + + QmlInstruction create; + create.type = QmlInstruction::CreateComponent; + create.line = root->location.start.line; + create.createComponent.endLine = root->location.end.line; + output->bytecode << create; + int count = output->bytecode.count(); + + ComponentCompileState oldCompileState = compileState; + compileState = componentState(root); + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.bindingsSize = compileState.bindings.count(); + init.init.parserStatusSize = compileState.parserStatusCount; + init.line = obj->location.start.line; + output->bytecode << init; + + genObject(root); + + output->bytecode[count - 1].createComponent.count = + output->bytecode.count() - count; + + compileState = oldCompileState; + + if (!obj->id.isEmpty()) { + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = -1; + id.setId.value = output->indexForString(obj->id);; + output->bytecode << id; + } } -bool QmlCompiler::compileComponent(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildComponent(QmlParser::Object *obj, + const BindingContext &ctxt) { + // The special "Component" element can only have the id property and a + // default property, that actually defines the component's tree + + // Find, check and set the "id" property (if any) Property *idProp = 0; if (obj->properties.count() > 1 || (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) COMPILE_EXCEPTION("Invalid component specification"); + + if (obj->properties.count()) + idProp = *obj->properties.begin(); + if (idProp && (idProp->value || idProp->values.count() > 1 || !isValidId(idProp->values.first()->primitive()))) + COMPILE_EXCEPTION("Invalid component id specification"); + + if (idProp) { + QString idVal = idProp->values.first()->primitive().toUtf8(); + + if (compileState.ids.contains(idVal)) + COMPILE_EXCEPTION("id is not unique"); + + addId(idVal, obj); + + obj->id = idVal.toUtf8(); + } + + // Check the Component tree is well formed if (obj->defaultProperty && (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) COMPILE_EXCEPTION("Invalid component body specification"); - if (obj->properties.count()) - idProp = *obj->properties.begin(); - if (idProp && (idProp->value || idProp->values.count() > 1)) - COMPILE_EXCEPTION("Invalid component id specification"); Object *root = 0; if (obj->defaultProperty && obj->defaultProperty->values.count()) @@ -747,84 +907,68 @@ bool QmlCompiler::compileComponent(Object *obj, const BindingContext &ctxt) if (!root) COMPILE_EXCEPTION("Cannot create empty component specification"); - COMPILE_CHECK(compileComponentFromRoot(root, ctxt)); - - if (idProp && idProp->values.count()) { - QString val = idProp->values.at(0)->primitive(); - if (!isValidId(val)) - COMPILE_EXCEPTION("Invalid id property value"); - - if (compileState.ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); - - IdReference reference; - reference.id = val; - reference.object = obj; - reference.instructionIdx = output->bytecode.count(); - reference.idx = compileState.ids.count(); - compileState.ids.insert(val, reference); - - int pref = output->indexForString(val); - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = idProp->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - - output->bytecode << id; - } + // Build the component tree + COMPILE_CHECK(buildComponentFromRoot(root, ctxt)); return true; } -bool QmlCompiler::compileComponentFromRoot(Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildComponentFromRoot(QmlParser::Object *obj, + const BindingContext &ctxt) { - output->bytecode.push_back(QmlInstruction()); - QmlInstruction &create = output->bytecode.last(); - create.type = QmlInstruction::CreateComponent; - create.line = obj->location.start.line; - create.createComponent.endLine = obj->location.end.line; - int count = output->bytecode.count(); - - QmlInstruction init; - init.type = QmlInstruction::Init; - init.init.dataSize = 0; - init.init.bindingsSize = 0; - init.init.parserStatusSize = 0; - init.line = obj->location.start.line; - output->bytecode << init; - ComponentCompileState oldComponentCompileState = compileState; compileState = ComponentCompileState(); compileState.root = obj; + if (obj) - COMPILE_CHECK(compileObject(obj, ctxt)); + COMPILE_CHECK(buildObject(obj, ctxt)); + + COMPILE_CHECK(completeComponentBuild()); - COMPILE_CHECK(finalizeComponent(count)); - create.createComponent.count = output->bytecode.count() - count; compileState = oldComponentCompileState; + return true; } -bool QmlCompiler::compileFetchedObject(Object *obj, const BindingContext &ctxt) + +// Build a sub-object. A sub-object is one that was not created directly by +// QML - such as a grouped property object, or an attached object. Sub-object's +// can't have an id, involve a custom parser, have attached properties etc. +bool QmlCompiler::buildSubObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metatype); + Q_ASSERT(ctxt.isSubContext()); // sub-objects must always be in a binding + // sub-context if (obj->defaultProperty) - COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + COMPILE_CHECK(buildProperty(obj->defaultProperty, obj, ctxt)); foreach(Property *prop, obj->properties) { if (isSignalPropertyName(prop->name)) { - COMPILE_CHECK(compileSignal(prop, obj)); + COMPILE_CHECK(buildSignal(prop, obj, ctxt)); } else { - COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); } } return true; } -int QmlCompiler::signalByName(const QMetaObject *mo, const QByteArray &name) +int QmlCompiler::componentTypeRef() +{ + QmlType *t = QmlMetaType::qmlType("Component"); + for (int ii = output->types.count() - 1; ii >= 0; --ii) { + if (output->types.at(ii).type == t) + return ii; + } + QmlCompiledData::TypeReference ref; + ref.className = "Component"; + ref.type = t; + output->types << ref; + return output->types.count() - 1; +} + +int QmlCompiler::findSignalByName(const QMetaObject *mo, const QByteArray &name) { int methods = mo->methodCount(); for (int ii = methods - 1; ii >= 0; --ii) { @@ -839,15 +983,13 @@ int QmlCompiler::signalByName(const QMetaObject *mo, const QByteArray &name) return -1; } -bool QmlCompiler::compileSignal(Property *prop, Object *obj) +bool QmlCompiler::buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(obj->metaObject()); - if (prop->values.isEmpty() && !prop->value) - return true; - - if (prop->value || prop->values.count() > 1) - COMPILE_EXCEPTION("Incorrectly specified signal"); + if (prop->isEmpty()) + COMPILE_EXCEPTION2(prop, "Empty property assignment"); QByteArray name = prop->name; Q_ASSERT(name.startsWith("on")); @@ -855,47 +997,26 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj) if(name[0] >= 'A' && name[0] <= 'Z') name[0] = name[0] - 'A' + 'a'; - int sigIdx = signalByName(obj->metaObject(), name); + int sigIdx = findSignalByName(obj->metaObject(), name); if (sigIdx == -1) { - COMPILE_CHECK(compileProperty(prop, obj, 0)); + // If the "on<Signal>" name doesn't resolve into a signal, try it as a + // property. + COMPILE_CHECK(buildProperty(prop, obj, ctxt)); } else { - if (prop->values.at(0)->object) { - int pr = output->indexForByteArray(prop->name); - - bool rv = compileObject(prop->values.at(0)->object, 0); + if (prop->value || prop->values.count() > 1) + COMPILE_EXCEPTION("Incorrectly specified signal"); - if (rv) { - QmlInstruction assign; - assign.type = QmlInstruction::AssignSignalObject; - assign.line = prop->values.at(0)->location.start.line; - assign.assignSignalObject.signal = pr; - - output->bytecode << assign; - - prop->values.at(0)->type = Value::SignalObject; - } - - return rv; + prop->index = sigIdx; + obj->addSignalProperty(prop); + if (prop->values.at(0)->object) { + COMPILE_CHECK(buildObject(prop->values.at(0)->object, ctxt)); + prop->values.at(0)->type = Value::SignalObject; } else { - QString script = prop->values.at(0)->value.asScript().trimmed(); - if (script.isEmpty()) - return true; - - int idx = output->indexForString(script); - - QmlInstruction store; - store.line = prop->values.at(0)->location.start.line; - store.type = QmlInstruction::StoreSignal; - store.storeSignal.signalIndex = sigIdx; - store.storeSignal.value = idx; - - output->bytecode << store; - prop->values.at(0)->type = Value::SignalExpression; } } @@ -903,6 +1024,7 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj) return true; } + // Returns true if prop exists on obj, false otherwise bool QmlCompiler::testProperty(QmlParser::Property *prop, QmlParser::Object *obj) @@ -924,9 +1046,11 @@ bool QmlCompiler::testProperty(QmlParser::Property *prop, return false; } -bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingContext &ctxt) +bool QmlCompiler::buildProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { - if (prop->values.isEmpty() && !prop->value) + if (prop->isEmpty()) COMPILE_EXCEPTION2(prop, "Empty property assignment"); const QMetaObject *metaObject = obj->metaObject(); @@ -934,13 +1058,21 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingCont if (isAttachedPropertyName(prop->name)) { // Setup attached property data + + if (ctxt.isSubContext()) { + // Attached properties cannot be used on sub-objects. Sub-objects + // always exist in a binding sub-context, which is what we test + // for here. + COMPILE_EXCEPTION2(prop, "Attached properties cannot be used here"); + } + QmlType *type = QmlMetaType::qmlType(prop->name); if (!type || !type->attachedPropertiesType()) COMPILE_EXCEPTION2(prop, "Non-existant attached object"); if (!prop->value) - COMPILE_EXCEPTION2(prop, "Cannot assign directly to attached object"); + COMPILE_EXCEPTION2(prop, "Invalid attached object assignment"); prop->value->metatype = type->attachedPropertiesType(); } else { @@ -976,125 +1108,259 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, const BindingCont } } - if (!prop->isDefault && prop->name == "id") { + if (!prop->isDefault && prop->name == "id" && !ctxt.isSubContext()) { - COMPILE_CHECK(compileIdProperty(prop, obj)); + // The magic "id" behaviour doesn't apply when "id" is resolved as a + // default property or to sub-objects (which are always in binding + // sub-contexts) + COMPILE_CHECK(buildIdProperty(prop, obj)); + if (prop->type == QVariant::String && + prop->values.at(0)->value.isString()) + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); } else if (isAttachedPropertyName(prop->name)) { - COMPILE_CHECK(compileAttachedProperty(prop, ctxt)); + COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); } else if (prop->index == -1) { if (prop->isDefault) { - COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant default property"); + COMPILE_EXCEPTION2(prop->values.first(), "Cannot assign to non-existant default property"); } else { COMPILE_EXCEPTION2(prop, "Cannot assign to non-existant property" << prop->name); } } else if (prop->value) { - COMPILE_CHECK(compileNestedProperty(prop, ctxt)); + COMPILE_CHECK(buildGroupedProperty(prop, obj, ctxt)); } else if (QmlMetaType::isQmlList(prop->type) || QmlMetaType::isList(prop->type)) { - COMPILE_CHECK(compileListProperty(prop, obj, ctxt)); + COMPILE_CHECK(buildListProperty(prop, obj, ctxt)); } else { - COMPILE_CHECK(compilePropertyAssignment(prop, obj, ctxt)); + COMPILE_CHECK(buildPropertyAssignment(prop, obj, ctxt)); } return true; } -bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, - QmlParser::Object *obj) +void QmlCompiler::genValueProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if (QmlMetaType::isQmlList(prop->type) || QmlMetaType::isList(prop->type)) { + genListProperty(prop, obj); + } else { + genPropertyAssignment(prop, obj); + } +} + +void QmlCompiler::genListProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + QmlInstruction::Type fetchType; + QmlInstruction::Type storeType; + int listType; + + if (QmlMetaType::isQmlList(prop->type)) { + fetchType = QmlInstruction::FetchQmlList; + storeType = QmlInstruction::StoreObjectQmlList; + listType = QmlMetaType::qmlListType(prop->type); + } else { + fetchType = QmlInstruction::FetchQList; + storeType = QmlInstruction::StoreObjectQList; + listType = QmlMetaType::listType(prop->type); + } + + QmlInstruction fetch; + fetch.type = fetchType; + fetch.line = prop->location.start.line; + fetch.fetchQmlList.property = prop->index; + bool listTypeIsInterface = QmlMetaType::isInterface(listType); + fetch.fetchQmlList.type = listType; + output->bytecode << fetch; + + for (int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + if (listTypeIsInterface) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = prop->location.start.line; + output->bytecode << assign; + } else { + QmlInstruction store; + store.type = storeType; + store.line = prop->location.start.line; + output->bytecode << store; + } + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj); + + } + + } + + QmlInstruction pop; + pop.type = QmlInstruction::PopQList; + pop.line = prop->location.start.line; + output->bytecode << pop; +} + +void QmlCompiler::genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + for (int ii = 0; ii < prop->values.count(); ++ii) { + QmlParser::Value *v = prop->values.at(ii); + + if (v->type == Value::CreatedObject) { + + genObject(v->object); + + if (QmlMetaType::isInterface(prop->type)) { + + QmlInstruction store; + store.type = QmlInstruction::StoreInterface; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else if (prop->type == -1) { + + QmlInstruction store; + store.type = QmlInstruction::StoreVariantObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } else { + + QmlInstruction store; + store.type = QmlInstruction::StoreObject; + store.line = v->object->location.start.line; + store.storeObject.propertyIndex = prop->index; + output->bytecode << store; + + } + } else if (v->type == Value::ValueSource) { + + genObject(v->object); + + QmlInstruction store; + store.type = QmlInstruction::StoreValueSource; + store.line = v->object->location.start.line; + store.assignValueSource.property = prop->index; + output->bytecode << store; + + } else if (v->type == Value::PropertyBinding) { + + genBindingAssignment(v, prop, obj); + + } else if (v->type == Value::Literal) { + + QMetaProperty mp = obj->metaObject()->property(prop->index); + genLiteralAssignment(mp, v); + + } + + } +} + +bool QmlCompiler::buildIdProperty(QmlParser::Property *prop, + QmlParser::Object *obj) { - if (prop->value) - COMPILE_EXCEPTION2(prop,"The id property cannot be fetched"); - if (prop->values.count() > 1) - COMPILE_EXCEPTION2(prop, "The object id may only be set once"); + if (prop->value || + prop->values.count() > 1 || + prop->values.at(0)->object) + COMPILE_EXCEPTION2(prop, "Invalid use of id property"); - if (prop->values.at(0)->object) - COMPILE_EXCEPTION("Cannot assign an object as an id"); QString val = prop->values.at(0)->primitive(); + if (!isValidId(val)) - COMPILE_EXCEPTION(val << "is not a valid id"); + COMPILE_EXCEPTION2(prop, val << "is not a valid object id"); + if (compileState.ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); + COMPILE_EXCEPTION2(prop, "id is not unique"); - int pref = output->indexForString(val); + obj->id = val.toUtf8(); - if (prop->type == QVariant::String) { - QmlInstruction assign; - assign.type = QmlInstruction::StoreString; - assign.storeString.propertyIndex = prop->index; - assign.storeString.value = pref; - assign.line = prop->values.at(0)->location.start.line; - output->bytecode << assign; + prop->values.at(0)->type = Value::Id; - prop->values.at(0)->type = Value::Id; - } else { - prop->values.at(0)->type = Value::Literal; - } + addId(val, obj); + return true; +} + +void QmlCompiler::addId(const QString &id, QmlParser::Object *obj) +{ IdReference reference; - reference.id = val; + reference.id = id; reference.object = obj; - reference.instructionIdx = output->bytecode.count(); reference.idx = compileState.ids.count(); - compileState.ids.insert(val, reference); + compileState.ids.insert(id, reference); +} - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = prop->values.at(0)->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - output->bytecode << id; +void QmlCompiler::addBindingReference(const BindingReference &ref) +{ + int id = compileState.bindings.count(); + compileState.bindings << ref; + compileState.bindingMap.insert(ref.value, id); +} - obj->id = val.toLatin1(); +void QmlCompiler::saveComponentState() +{ + Q_ASSERT(compileState.root); + Q_ASSERT(!savedCompileStates.contains(compileState.root)); - return true; + savedCompileStates.insert(compileState.root, compileState); } -// Compile attached property object. In this example, +QmlCompiler::ComponentCompileState +QmlCompiler::componentState(QmlParser::Object *obj) +{ + Q_ASSERT(savedCompileStates.contains(obj)); + return savedCompileStates.value(obj); +} + +// Build attached property object. In this example, // Text { // GridView.row: 10 // } // GridView is an attached property object. -bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, - const BindingContext &ctxt) +bool QmlCompiler::buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(prop->value); int id = QmlMetaType::attachedPropertiesFuncId(prop->name); Q_ASSERT(id != -1); // This is checked in compileProperty() - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchAttached; - fetch.line = prop->location.start.line; - fetch.fetchAttached.id = id; - output->bytecode << fetch; - - COMPILE_CHECK(compileFetchedObject(prop->value, ctxt.incr())); + prop->index = id; + obj->addAttachedProperty(prop); - QmlInstruction pop; - pop.type = QmlInstruction::PopFetchedObject; - pop.line = prop->location.start.line; - output->bytecode << pop; + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); return true; } -// Compile "nested" properties. In this example: + +// Build "grouped" properties. In this example: // Text { // font.size: 12 +// font.family: "Helvetica" // } -// font is a nested property. size is not. -bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, - const BindingContext &ctxt) +// font is a nested property. size and family are not. +bool QmlCompiler::buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(prop->type != 0); Q_ASSERT(prop->index != -1); @@ -1104,132 +1370,90 @@ bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, if (!prop->value->metatype) COMPILE_EXCEPTION2(prop, "Cannot nest non-QObject property" << prop->name); - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchObject; - fetch.fetch.property = prop->index; - fetch.fetch.isObject = true; - fetch.line = prop->location.start.line; - output->bytecode << fetch; + obj->addGroupedProperty(prop); - COMPILE_CHECK(compileFetchedObject(prop->value, ctxt.incr())); - - QmlInstruction pop; - pop.type = QmlInstruction::PopFetchedObject; - pop.line = prop->location.start.line; - output->bytecode << pop; + COMPILE_CHECK(buildSubObject(prop->value, ctxt.incr())); return true; } -// Compile assignments to QML lists. QML lists are properties of type + +// Build assignments to QML lists. QML lists are properties of type // QList<T *> * and QmlList<T *> *. // // QList<T *> * types can accept a list of objects, or a single binding // QmlList<T *> * types can accept a list of objects -bool QmlCompiler::compileListProperty(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt) +bool QmlCompiler::buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { Q_ASSERT(QmlMetaType::isList(prop->type) || QmlMetaType::isQmlList(prop->type)); int t = prop->type; + obj->addValueProperty(prop); + if (QmlMetaType::isQmlList(t)) { - QmlInstruction fetch; - fetch.line = prop->location.start.line; - fetch.type = QmlInstruction::FetchQmlList; - fetch.fetchQmlList.property = prop->index; int listType = QmlMetaType::qmlListType(t); bool listTypeIsInterface = QmlMetaType::isInterface(listType); - fetch.fetchQmlList.type = listType; - output->bytecode << fetch; for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { v->type = Value::CreatedObject; - COMPILE_CHECK(compileObject(v->object, ctxt)); + COMPILE_CHECK(buildObject(v->object, ctxt)); + // We check object coercian here. We check interface assignment + // at runtime. if (!listTypeIsInterface) { - if (canConvert(listType, v->object)) { - QmlInstruction store; - store.type = QmlInstruction::StoreObjectQmlList; - store.line = prop->location.start.line; - output->bytecode << store; - } else { + if (!canCoerce(listType, v->object)) { COMPILE_EXCEPTION("Cannot assign object to list"); } - - } else { - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = prop->location.start.line; - output->bytecode << assign; } + } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); } } - QmlInstruction pop; - pop.type = QmlInstruction::PopQList; - pop.line = prop->location.start.line; - output->bytecode << pop; } else { - QmlInstruction fetch; - fetch.type = QmlInstruction::FetchQList; - fetch.line = prop->location.start.line; - fetch.fetchQmlList.property = prop->index; int listType = QmlMetaType::listType(t); bool listTypeIsInterface = QmlMetaType::isInterface(listType); - fetch.fetchQmlList.type = listType; - output->bytecode << fetch; bool assignedBinding = false; for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { v->type = Value::CreatedObject; - COMPILE_CHECK(compileObject(v->object, ctxt)); + COMPILE_CHECK(buildObject(v->object, ctxt)); + // We check object coercian here. We check interface assignment + // at runtime. if (!listTypeIsInterface) { - if (canConvert(listType, v->object)) { - QmlInstruction store; - store.type = QmlInstruction::StoreObjectQList; - store.line = prop->location.start.line; - output->bytecode << store; - } else { + if (!canCoerce(listType, v->object)) { COMPILE_EXCEPTION("Cannot assign object to list"); } - } else { - QmlInstruction assign; - assign.type = QmlInstruction::AssignObjectList; - assign.line = v->location.start.line; - output->bytecode << assign; - } + } + } else if (v->value.isScript()) { if (assignedBinding) COMPILE_EXCEPTION("Can only assign one binding to lists"); assignedBinding = true; - COMPILE_CHECK(compileBinding(v, prop, ctxt)); + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); } } - QmlInstruction pop; - pop.line = prop->location.start.line; - pop.type = QmlInstruction::PopQList; - output->bytecode << pop; } return true; } -// Compile regular property assignments of the form property: <value> +// Compile regular property assignments of the form "property: <value>" // // ### The following problems exist // @@ -1244,19 +1468,21 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, // } // // We allow assignming multiple values to single value properties -bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt) { + obj->addValueProperty(prop); + for (int ii = 0; ii < prop->values.count(); ++ii) { Value *v = prop->values.at(ii); if (v->object) { - COMPILE_CHECK(compilePropertyObjectAssignment(prop, v, ctxt)); + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); } else { - COMPILE_CHECK(compilePropertyLiteralAssignment(prop, obj, v, ctxt)); + COMPILE_CHECK(buildPropertyLiteralAssignment(prop, obj, v, ctxt)); } } @@ -1265,9 +1491,10 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, } // Compile assigning a single object instance to a regular property -bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Value *v, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); Q_ASSERT(v->object->type != -1); @@ -1275,30 +1502,18 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, if (QmlMetaType::isInterface(prop->type)) { // Assigning an object to an interface ptr property - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreInterface; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else if (prop->type == -1) { // Assigning an object to a QVariant - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreVariantObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else { - // Normally compileObject() will set this up, but we need the static + // Normally buildObject() will set this up, but we need the static // meta object earlier to test for assignability. It doesn't matter // that there may still be outstanding synthesized meta object changes // on this type, as they are not relevant for assignability testing @@ -1333,39 +1548,29 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, if (isAssignable) { // Simple assignment - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; } else if (propertyMetaObject == &QmlComponent::staticMetaObject) { // Automatic "Component" insertion - COMPILE_CHECK(compileComponentFromRoot(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreObject; - assign.line = v->object->location.start.line; - assign.storeObject.propertyIndex = prop->index; - output->bytecode << assign; - - v->type = Value::Component; + QmlParser::Object *root = v->object; + QmlParser::Object *component = new QmlParser::Object; + component->type = componentTypeRef(); + component->typeName = "Component"; + component->metatype = &QmlComponent::staticMetaObject; + component->location = root->location; + QmlParser::Value *componentValue = new QmlParser::Value; + componentValue->object = root; + component->getDefaultProperty()->addValue(componentValue); + v->object = component; + COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); } else if (isPropertyValue) { // Assign as a property value source - COMPILE_CHECK(compileObject(v->object, ctxt)); - - QmlInstruction assign; - assign.type = QmlInstruction::StoreValueSource; - assign.line = v->object->location.start.line; - assign.assignValueSource.property = prop->index; - output->bytecode << assign; + COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::ValueSource; } else { - COMPILE_EXCEPTION2(v->object, "Unassignable object"); + COMPILE_EXCEPTION2(v->object, "Cannot assign object to property"); } } @@ -1373,25 +1578,22 @@ bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, } // Compile assigning a literal or binding to a regular property -bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - QmlParser::Value *v, - const BindingContext &ctxt) +bool QmlCompiler::buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + const BindingContext &ctxt) { Q_ASSERT(prop->index != -1); if (v->value.isScript()) { - COMPILE_CHECK(compileBinding(v, prop, ctxt)); + COMPILE_CHECK(buildBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { - QmlInstruction assign; - assign.line = v->location.start.line; - COMPILE_CHECK(compileStoreInstruction(assign, obj->metaObject()->property(prop->index), v)); - output->bytecode << assign; + COMPILE_CHECK(testLiteralAssignment(obj->metaObject()->property(prop->index), v)); v->type = Value::Literal; } @@ -1399,31 +1601,99 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, return true; } -bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) +// Ensures that the dynamic meta specification on obj is valid +bool QmlCompiler::checkDynamicMeta(QmlParser::Object *obj) +{ + QSet<QByteArray> propNames; + QSet<QByteArray> methodNames; + bool seenDefaultProperty = false; + + // Check properties + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const QmlParser::Object::DynamicProperty &prop = + obj->dynamicProperties.at(ii); + + if (prop.isDefaultProperty) { + if (seenDefaultProperty) + COMPILE_EXCEPTION("Duplicate default property"); + seenDefaultProperty = true; + } + + if (propNames.contains(prop.name)) + COMPILE_EXCEPTION("Duplicate property name"); + + propNames.insert(prop.name); + } + + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + QByteArray name = obj->dynamicSignals.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION("Duplicate signal name"); + methodNames.insert(name); + } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + QByteArray name = obj->dynamicSlots.at(ii).name; + if (methodNames.contains(name)) + COMPILE_EXCEPTION("Duplicate method name"); + methodNames.insert(name); + } + + return true; +} + +bool QmlCompiler::mergeDynamicMetaProperties(QmlParser::Object *obj) +{ + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (!p.defaultValue || p.type == Object::DynamicProperty::Alias) + continue; + + Property *property = 0; + if (p.isDefaultProperty) + property = obj->getDefaultProperty(); + else + property = obj->getProperty(p.name); + + if (property->value) + COMPILE_EXCEPTION2(property, "Invalid property nesting"); + + for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { + Value *v = p.defaultValue->values.at(ii); + v->addref(); + property->values.append(v); + } + } + return true; +} + +bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) { - // ### FIXME - Check that there is only one default property etc. if (obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty() && obj->dynamicSlots.isEmpty()) return true; + COMPILE_CHECK(checkDynamicMeta(obj)); + QByteArray dynamicData(sizeof(QmlVMEMetaData), (char)0); QMetaObjectBuilder builder; if (obj->metatype) - builder.setClassName(QByteArray(obj->metatype->className()) + "QML"); - + builder.setClassName(QByteArray(obj->metatype->className()) + "_QML"); builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + bool hasAlias = false; for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); if (p.isDefaultProperty && - (p.type != Object::DynamicProperty::Alias || preAlias != -1)) + (p.type != Object::DynamicProperty::Alias || + mode == ResolveAliases)) builder.addClassInfo("DefaultProperty", p.name); QByteArray type; - int propertyType; + int propertyType = 0; switch(p.type) { case Object::DynamicProperty::Alias: hasAlias = true; @@ -1471,7 +1741,7 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) builder.addProperty(p.name, type, ii); } - if (preAlias != -1) { + if (mode == ResolveAliases) { for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); @@ -1495,8 +1765,6 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) ((QmlVMEMetaData *)dynamicData.data())->signalCount++; } - int slotStart = obj->dynamicSlots.isEmpty()?-1:output->primitives.count(); - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); QByteArray sig(s.name + "("); @@ -1509,57 +1777,37 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) b.setParameterNames(s.parameterNames); ((QmlVMEMetaData *)dynamicData.data())->methodCount++; - QmlVMEMetaData::MethodData methodData = { s.parameterNames.count() }; - dynamicData.append((char *)&methodData, sizeof(methodData)); + QmlVMEMetaData::MethodData methodData = + { s.parameterNames.count(), 0, s.body.length(), 0 }; - if (preAlias == -1) - output->primitives << s.body; + dynamicData.append((char *)&methodData, sizeof(methodData)); } - if (obj->metatype) - builder.setSuperClass(obj->metatype); - - obj->extObjectData = builder.toMetaObject(); - static_cast<QMetaObject &>(obj->extObject) = *obj->extObjectData; - - if (preAlias != -1) { - QmlInstruction &store = output->bytecode[preAlias]; - - store.storeMeta.aliasData = output->indexForByteArray(dynamicData); - qFree(output->synthesizedMetaObjects.at(store.storeMeta.data)); - output->synthesizedMetaObjects[store.storeMeta.data] = obj->extObjectData; - - } else { - output->synthesizedMetaObjects << obj->extObjectData; - QmlInstruction store; - store.type = QmlInstruction::StoreMetaObject; - store.storeMeta.data = output->synthesizedMetaObjects.count() - 1; - store.storeMeta.slotData = slotStart; - store.storeMeta.aliasData = output->indexForByteArray(dynamicData); - store.line = obj->location.start.line; - output->bytecode << store; - - if (hasAlias) { - AliasReference alias; - alias.object = obj; - alias.instructionIdx = output->bytecode.count() - 1; - compileState.aliases << alias; - } + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); + QmlVMEMetaData::MethodData *data = + ((QmlVMEMetaData *)dynamicData.data())->methodData() + ii; + + data->bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)s.body.constData(), + (s.body.length() * sizeof(QChar))); } - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + obj->metadata = builder.toRelocatableData(); + builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); - if (p.type == Object::DynamicProperty::Alias) - continue; + // ### Remove me + obj->extObjectData = &obj->extObject; - if (p.defaultValue) { - p.defaultValue->name = p.name; - p.defaultValue->isDefault = false; - COMPILE_CHECK(compileProperty(p.defaultValue, obj, 0)); - } + if (mode == IgnoreAliases && hasAlias) { + AliasReference alias; + alias.object = obj; + compileState.aliases << alias; } + obj->synthdata = dynamicData; + return true; } @@ -1623,9 +1871,9 @@ bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, return true; } -bool QmlCompiler::compileBinding(QmlParser::Value *value, - QmlParser::Property *prop, - const BindingContext &ctxt) +bool QmlCompiler::buildBinding(QmlParser::Value *value, + QmlParser::Property *prop, + const BindingContext &ctxt) { Q_ASSERT(prop->index); Q_ASSERT(prop->parent); @@ -1633,7 +1881,7 @@ bool QmlCompiler::compileBinding(QmlParser::Value *value, QMetaProperty mp = prop->parent->metaObject()->property(prop->index); if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) - COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); + COMPILE_EXCEPTION2(prop, "Invalid property assignment: read-only property"); BindingReference reference; reference.expression = value->value; @@ -1641,185 +1889,104 @@ bool QmlCompiler::compileBinding(QmlParser::Value *value, reference.value = value; reference.instructionIdx = output->bytecode.count(); reference.bindingContext = ctxt; - compileState.bindings << reference; - - output->bytecode << QmlInstruction();; + addBindingReference(reference); return true; } -#if 0 - -#include <iostream> -#ifdef Q_CC_GNU -#include <cxxabi.h> -#endif - -//////////////////////////////////////////////////////////////////////////////// -// AST Dump -//////////////////////////////////////////////////////////////////////////////// -class Dump: protected QmlJS::AST::Visitor -{ - std::ostream &out; - int depth; - -public: - Dump(std::ostream &out) - : out(out), depth(-1) - { } - - void operator()(QmlJS::AST::Node *node) - { QmlJS::AST::Node::acceptChild(node, this); } - -protected: - virtual bool preVisit(QmlJS::AST::Node *node) - { - const char *name = typeid(*node).name(); -#ifdef Q_CC_GNU - name = abi::__cxa_demangle(name, 0, 0, 0) + 17; -#endif - std::cout << std::string(++depth, ' ') << name << std::endl; - return true; - } - - virtual void postVisit(QmlJS::AST::Node *) - { - --depth; - } -}; -#endif - -// Update the init instruction with final data, and optimize some simple -// bindings -bool QmlCompiler::finalizeComponent(int patch) +void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj) { - for (int ii = 0; ii < compileState.bindings.count(); ++ii) { - const BindingReference &binding = compileState.bindings.at(ii); - finalizeBinding(binding); - } + Q_ASSERT(compileState.bindingMap.contains(binding)); - for (int ii = 0; ii < compileState.aliases.count(); ++ii) { - const AliasReference &alias = compileState.aliases.at(ii); - COMPILE_CHECK(finalizeAlias(alias)); + const BindingReference &ref = + compileState.bindings.at(compileState.bindingMap.value(binding)); + + QMetaProperty mp = obj->metaObject()->property(prop->index); + + QmlInstruction store; + int dataRef; + if (ref.compiledData.isEmpty()) { + dataRef = output->indexForString(ref.expression.asScript()); + store.type = QmlInstruction::StoreBinding; + } else { + dataRef = output->indexForByteArray(ref.compiledData); + store.type = QmlInstruction::StoreCompiledBinding; } - output->bytecode[patch].init.dataSize = compileState.savedObjects;; - output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); - output->bytecode[patch].init.parserStatusSize = - compileState.parserStatusCount; + store.assignBinding.property = prop->index; + store.assignBinding.value = dataRef; + store.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + store.assignBinding.context = ref.bindingContext.stack; - return true; + output->bytecode << store; } -bool QmlCompiler::finalizeAlias(const AliasReference &alias) +bool QmlCompiler::completeComponentBuild() { - COMPILE_CHECK(compileDynamicMeta(alias.object, alias.instructionIdx)); -} + saveComponentState(); + + for (int ii = 0; ii < compileState.aliases.count(); ++ii) { + const AliasReference &alias = compileState.aliases.at(ii); + COMPILE_CHECK(buildDynamicMeta(alias.object, ResolveAliases)); + } + -void QmlCompiler::finalizeBinding(const BindingReference &binding) -{ - QmlBasicScript bs; QmlBasicScript::Expression expr; expr.component = compileState.root; - expr.context = binding.bindingContext.object; - expr.property = binding.property; - expr.expression = binding.expression; - foreach (const IdReference &id, compileState.ids) + foreach (const IdReference &id, compileState.ids) { expr.ids.insert(id.id, qMakePair(id.object, id.idx)); + } - bs.compile(expr); - - QmlInstruction &instr = output->bytecode[binding.instructionIdx]; - instr.line = binding.value->location.start.line; - - // Single load optimization - if (bs.isValid() && bs.isSingleLoad()) { - - QString singleLoadTarget = QLatin1String(bs.singleLoadTarget()); - - if (singleLoadTarget.at(0).isUpper() && - compileState.ids.contains(singleLoadTarget) && - QmlMetaType::isObject(binding.property->type)) { - - IdReference reference = compileState.ids[singleLoadTarget]; - - const QMetaObject *idMo = reference.object->metaObject(); - const QMetaObject *storeMo = - QmlMetaType::rawMetaObjectForType(binding.property->type); - - Q_ASSERT(idMo); - Q_ASSERT(storeMo); - - bool canAssign = false; - while (!canAssign && idMo) { - if (idMo == storeMo) - canAssign = true; - else - idMo = idMo->superClass(); - } - - if (canAssign) { - int instructionIdx = reference.instructionIdx; - if (output->bytecode.at(instructionIdx).setId.save == -1) { - output->bytecode[instructionIdx].setId.save = - compileState.savedObjects++; - } - int saveId = output->bytecode.at(instructionIdx).setId.save; + for (int ii = 0; ii < compileState.bindings.count(); ++ii) { + BindingReference &binding = compileState.bindings[ii]; - instr.type = QmlInstruction::PushProperty; - instr.pushProperty.property = binding.property->index; - QmlInstruction store; - store.type = QmlInstruction::StoreStackObject; - store.line = 0; - store.assignStackObject.property = - compileState.pushedProperties++; - store.assignStackObject.object = saveId; - output->bytecode << store; - return; - } - } - } + QmlBasicScript bs; + expr.context = binding.bindingContext.object; + expr.property = binding.property; + expr.expression = binding.expression; - // General binding fallback - int bref; - if (bs.isValid()) { - bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); - } else { - bref = output->indexForString(binding.expression.asScript()); + bs.compile(expr); + if (bs.isValid()) + binding.compiledData = + QByteArray(bs.compileData(), bs.compileDataSize()); } - instr.assignBinding.context = binding.bindingContext.stack; - - if (bs.isValid()) - instr.type = QmlInstruction::StoreCompiledBinding; - else - instr.type = QmlInstruction::StoreBinding; - - instr.assignBinding.property = binding.property->index; - instr.assignBinding.value = bref; - QMetaProperty mp = binding.property->parent->metaObject()->property(binding.property->index); - instr.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + return true; } /*! - Returns true if object can be assigned to a (QObject) property of type - convertType. + Returns true if from can be assigned to a (QObject) property of type + to. */ -bool QmlCompiler::canConvert(int convertType, QmlParser::Object *object) +bool QmlCompiler::canCoerce(int to, QmlParser::Object *from) { - const QMetaObject *convertTypeMo = - QmlMetaType::rawMetaObjectForType(convertType); - const QMetaObject *objectMo = object->metaObject(); + const QMetaObject *toMo = + QmlMetaType::rawMetaObjectForType(to); + const QMetaObject *fromMo = from->metaObject(); - while (objectMo) { - if (objectMo == convertTypeMo) + while (fromMo) { + if (fromMo == toMo) return true; - objectMo = objectMo->superClass(); + fromMo = fromMo->superClass(); } return false; } +QmlType *QmlCompiler::toQmlType(QmlParser::Object *from) +{ + // ### Optimize + const QMetaObject *mo = from->metatype; + QmlType *type = 0; + while (!type && mo) { + type = QmlMetaType::qmlType(mo); + mo = mo->superClass(); + } + return type; +} + QStringList QmlCompiler::deferredProperties(QmlParser::Object *obj) { const QMetaObject *mo = obj->metatype; @@ -1833,63 +2000,4 @@ QStringList QmlCompiler::deferredProperties(QmlParser::Object *obj) return rv; } -QmlCompiledData::QmlCompiledData() -{ -} - -QmlCompiledData::QmlCompiledData(const QmlCompiledData &other) -{ - *this = other; -} - -QmlCompiledData::~QmlCompiledData() -{ - for (int ii = 0; ii < types.count(); ++ii) { - if (types.at(ii).ref) - types.at(ii).ref->release(); - } -} - -QmlCompiledData &QmlCompiledData::operator=(const QmlCompiledData &other) -{ - types = other.types; - root = other.root; - primitives = other.primitives; - floatData = other.floatData; - intData = other.intData; - customTypeData = other.customTypeData; - datas = other.datas; - synthesizedMetaObjects = other.synthesizedMetaObjects; - bytecode = other.bytecode; - return *this; -} - -QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt) const -{ - if (type) { - QObject *rv = type->create(); - if (rv) - QmlEngine::setContextForObject(rv, ctxt); - return rv; - } else { - Q_ASSERT(component); - QObject *rv = component->create(ctxt); - QmlContext *ctxt = qmlContext(rv); - if(ctxt) { - static_cast<QmlContextPrivate *>(QObjectPrivate::get(ctxt))->typeName = className; - } - return rv; - } -} - -const QMetaObject *QmlCompiledData::TypeReference::metaObject() const -{ - if (type) { - return type->metaObject(); - } else { - Q_ASSERT(component); - return &static_cast<QmlComponentPrivate *>(QObjectPrivate::get(component))->cc->root; - } -} - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 1c45f57..e09665f 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -65,15 +65,12 @@ QT_BEGIN_NAMESPACE class QmlEngine; class QmlComponent; -class QmlCompiledComponent; class QmlContext; -class QmlCompiledData +class QmlCompiledData : public QmlRefCount { public: QmlCompiledData(); - QmlCompiledData(const QmlCompiledData &other); - QmlCompiledData &operator=(const QmlCompiledData &other); virtual ~QmlCompiledData(); QByteArray name; @@ -104,12 +101,18 @@ public: QList<int> intData; QList<CustomTypeData> customTypeData; QList<QByteArray> datas; - QList<QMetaObject *> synthesizedMetaObjects; QList<QmlParser::Location> locations; QList<QmlInstruction> bytecode; + void dumpInstructions(); private: + void dump(QmlInstruction *, int idx = -1); + QmlCompiledData(const QmlCompiledData &other); + QmlCompiledData &operator=(const QmlCompiledData &other); + QByteArray packData; friend class QmlCompiler; + int pack(const char *, size_t); + int indexForString(const QString &); int indexForByteArray(const QByteArray &); int indexForFloat(float *, int); @@ -124,7 +127,7 @@ class Q_DECLARATIVE_EXPORT QmlCompiler public: QmlCompiler(); - bool compile(QmlEngine *, QmlCompositeTypeData *, QmlCompiledComponent *); + bool compile(QmlEngine *, QmlCompositeTypeData *, QmlCompiledData *); bool isError() const; QList<QmlError> errors() const; @@ -134,7 +137,7 @@ public: static bool isSignalPropertyName(const QByteArray &); private: - void reset(QmlCompiledComponent *, bool); + void reset(QmlCompiledData *); struct BindingContext { BindingContext() @@ -146,57 +149,79 @@ private: rv.stack = stack + 1; return rv; } + bool isSubContext() const { return stack != 0; } int stack; QmlParser::Object *object; }; void compileTree(QmlParser::Object *tree); - bool compileObject(QmlParser::Object *obj, const BindingContext &); - bool compileComponent(QmlParser::Object *obj, const BindingContext &); - bool compileComponentFromRoot(QmlParser::Object *obj, const BindingContext &); - bool compileFetchedObject(QmlParser::Object *obj, const BindingContext &); - bool compileSignal(QmlParser::Property *prop, QmlParser::Object *obj); - bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj); - int signalByName(const QMetaObject *, const QByteArray &name); - bool compileProperty(QmlParser::Property *prop, QmlParser::Object *obj, const BindingContext &); - bool compileIdProperty(QmlParser::Property *prop, - QmlParser::Object *obj); - bool compileAttachedProperty(QmlParser::Property *prop, - const BindingContext &ctxt); - bool compileNestedProperty(QmlParser::Property *prop, + + + bool buildObject(QmlParser::Object *obj, const BindingContext &); + bool buildComponent(QmlParser::Object *obj, const BindingContext &); + bool buildSubObject(QmlParser::Object *obj, const BindingContext &); + bool buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildProperty(QmlParser::Property *prop, QmlParser::Object *obj, + const BindingContext &); + bool buildIdProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool buildAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, const BindingContext &ctxt); - bool compileListProperty(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt); - bool compilePropertyAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - const BindingContext &ctxt); - bool compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Value *value, - const BindingContext &ctxt); - bool compilePropertyLiteralAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, - QmlParser::Value *value, - const BindingContext &ctxt); - bool compileStoreInstruction(QmlInstruction &instr, - const QMetaProperty &prop, - QmlParser::Value *value); - - bool compileDynamicMeta(QmlParser::Object *obj, int preAlias = -1); + bool buildGroupedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + const BindingContext &ctxt); + bool buildPropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool buildPropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + const BindingContext &ctxt); + bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj); + bool testLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + enum DynamicMetaMode { IgnoreAliases, ResolveAliases }; + bool mergeDynamicMetaProperties(QmlParser::Object *obj); + bool buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode); + bool checkDynamicMeta(QmlParser::Object *obj); + bool buildBinding(QmlParser::Value *, QmlParser::Property *prop, + const BindingContext &ctxt); + bool buildComponentFromRoot(QmlParser::Object *obj, const BindingContext &); bool compileAlias(QMetaObjectBuilder &, QByteArray &data, QmlParser::Object *obj, const QmlParser::Object::DynamicProperty &); - bool compileBinding(QmlParser::Value *, QmlParser::Property *prop, - const BindingContext &ctxt); + bool completeComponentBuild(); + + + void genObject(QmlParser::Object *obj); + void genObjectBody(QmlParser::Object *obj); + void genComponent(QmlParser::Object *obj); + void genValueProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genListProperty(QmlParser::Property *prop, QmlParser::Object *obj); + void genPropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj); + void genLiteralAssignment(const QMetaProperty &prop, + QmlParser::Value *value); + void genBindingAssignment(QmlParser::Value *binding, + QmlParser::Property *prop, + QmlParser::Object *obj); + - bool finalizeComponent(int patch); - struct BindingReference; - void finalizeBinding(const BindingReference &); - struct AliasReference; - bool finalizeAlias(const AliasReference &); + int componentTypeRef(); + + static int findSignalByName(const QMetaObject *, const QByteArray &name); + static bool canCoerce(int to, QmlParser::Object *from); + static QmlType *toQmlType(QmlParser::Object *from); - bool canConvert(int, QmlParser::Object *); QStringList deferredProperties(QmlParser::Object *); struct IdReference { @@ -205,6 +230,7 @@ private: int instructionIdx; int idx; }; + void addId(const QString &, QmlParser::Object *); struct AliasReference { QmlParser::Object *object; @@ -215,28 +241,35 @@ private: QmlParser::Variant expression; QmlParser::Property *property; QmlParser::Value *value; + QByteArray compiledData; int instructionIdx; BindingContext bindingContext; }; + void addBindingReference(const BindingReference &); struct ComponentCompileState { - ComponentCompileState() : parserStatusCount(0), savedObjects(0), pushedProperties(0), root(0) {} + ComponentCompileState() + : parserStatusCount(0), savedObjects(0), + pushedProperties(0), root(0) {} QHash<QString, IdReference> ids; int parserStatusCount; int savedObjects; int pushedProperties; QList<BindingReference> bindings; + QHash<QmlParser::Value *, int> bindingMap; QList<AliasReference> aliases; QmlParser::Object *root; }; ComponentCompileState compileState; + void saveComponentState(); + ComponentCompileState componentState(QmlParser::Object *); + QHash<QmlParser::Object *, ComponentCompileState> savedCompileStates; + QList<QmlError> exceptions; QmlCompiledData *output; - }; - QT_END_NAMESPACE #endif // QMLCOMPILER_P_H diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 52315f9..0e68f8a 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -41,6 +41,7 @@ #include "qmlcomponent.h" #include "qmlcomponent_p.h" +#include "qmlcompiler_p.h" #include "private/qmlcontext_p.h" #include "private/qmlengine_p.h" #include "qmlvme_p.h" @@ -51,7 +52,6 @@ #include <qmlengine.h> #include <QFileInfo> #include <qmlbindablevalue.h> -#include "qmlcompiledcomponent_p.h" #include <QtCore/qdebug.h> #include <QApplication> @@ -123,7 +123,7 @@ void QmlComponentPrivate::typeDataReady() void QmlComponentPrivate::fromTypeData(QmlCompositeTypeData *data) { url = data->imports.baseUrl(); - QmlCompiledComponent *c = data->toCompiledComponent(engine); + QmlCompiledData *c = data->toCompiledComponent(engine); if (!c) { Q_ASSERT(data->status == QmlCompositeTypeData::Error); @@ -303,7 +303,7 @@ QmlComponent::QmlComponent(QmlEngine *engine, const QByteArray &data, const QUrl /*! \internal */ -QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledComponent *cc, int start, int count, QObject *parent) +QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledData *cc, int start, int count, QObject *parent) : QObject(*(new QmlComponentPrivate), parent) { Q_D(QmlComponent); diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h index 5e6dce9..9c712df 100644 --- a/src/declarative/qml/qmlcomponent.h +++ b/src/declarative/qml/qmlcomponent.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QmlCompiledComponent; +class QmlCompiledData; class QByteArray; class QmlComponentPrivate; class QmlEngine; @@ -102,7 +102,7 @@ protected: QmlComponent(QmlComponentPrivate &dd, QObject* parent); private: - QmlComponent(QmlEngine *, QmlCompiledComponent *, int, int, QObject *parent); + QmlComponent(QmlEngine *, QmlCompiledData *, int, int, QObject *parent); friend class QmlVME; friend struct QmlCompositeTypeData; diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 0be3dc6..25af342 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE class QmlComponent; class QmlEngine; -class QmlCompiledComponent; +class QmlCompiledData; class QmlComponentPrivate : public QObjectPrivate { @@ -86,7 +86,7 @@ public: int start; int count; - QmlCompiledComponent *cc; + QmlCompiledData *cc; QList<QmlEnginePrivate::SimpleList<QmlBindableValue> > bindValues; QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus; diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index 5be86c2..9af5c3c 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -41,7 +41,6 @@ #include <private/qmlcompositetypemanager_p.h> #include <private/qmlscriptparser_p.h> -#include <private/qmlcompiledcomponent_p.h> #include <QtDeclarative/qmlengine.h> #include <QtNetwork/qnetworkreply.h> #include <private/qmlengine_p.h> @@ -49,6 +48,7 @@ #include <QtCore/qfile.h> #include <QtDeclarative/qmlcomponent.h> #include <private/qmlcomponent_p.h> +#include <private/qmlcompiler_p.h> QT_BEGIN_NAMESPACE @@ -83,7 +83,7 @@ QmlComponent *QmlCompositeTypeData::toComponent(QmlEngine *engine) { if (!component) { - QmlCompiledComponent *cc = toCompiledComponent(engine); + QmlCompiledData *cc = toCompiledComponent(engine); if (cc) { component = new QmlComponent(engine, cc, -1, -1, 0); } else { @@ -97,12 +97,12 @@ QmlComponent *QmlCompositeTypeData::toComponent(QmlEngine *engine) return component; } -QmlCompiledComponent * +QmlCompiledData * QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) { if (status == Complete && !compiledComponent) { - compiledComponent = new QmlCompiledComponent; + compiledComponent = new QmlCompiledData; compiledComponent->url = imports.baseUrl(); compiledComponent->name = compiledComponent->url.toString().toLatin1(); // ### @@ -110,8 +110,6 @@ QmlCompositeTypeData::toCompiledComponent(QmlEngine *engine) if (!compiler.compile(engine, this, compiledComponent)) { status = Error; errors = compiler.errors(); - for(int ii = 0; ii < errors.count(); ++ii) - errors[ii].setUrl(compiledComponent->url); compiledComponent->release(); compiledComponent = 0; } diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index a393da4..0685b03 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE -class QmlCompiledComponent; +class QmlCompiledData; class QmlComponentPrivate; class QmlComponent; class QmlDomDocument; @@ -94,9 +94,9 @@ struct QmlCompositeTypeData : public QmlRefCount // state. The QmlComponent is owned by the QmlCompositeTypeData, so a // reference should be kept to keep the QmlComponent alive. QmlComponent *toComponent(QmlEngine *); - // Return a QmlCompiledComponent if possible, or 0 if an error + // Return a QmlCompiledData if possible, or 0 if an error // occurs - QmlCompiledComponent *toCompiledComponent(QmlEngine *); + QmlCompiledData *toCompiledComponent(QmlEngine *); struct TypeReference { @@ -123,7 +123,7 @@ private: QmlScriptParser data; QList<QmlComponentPrivate *> waiters; QmlComponent *component; - QmlCompiledComponent *compiledComponent; + QmlCompiledData *compiledComponent; }; class QmlCompositeTypeManager : public QObject diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 980e1df..440f4b8 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -73,6 +73,8 @@ void QmlContextPrivate::dump(int depth) void QmlContextPrivate::destroyed(QObject *obj) { + Q_Q(QmlContext); + defaultObjects.removeAll(obj); QVariant variantObject = QVariant::fromValue(obj); @@ -84,10 +86,16 @@ void QmlContextPrivate::destroyed(QObject *obj) } } - // ### Work around bug in shutdown - // for (int ii = 0; ii < notifies.count(); ++ii) { - // QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); - // } + // There is no need to emit these notifications if our parent is in the + // process of being deleted (which is *probably* why obj has been destroyed + // anyway), as we're about to get deleted which will invalidate all the + // expressions that could depend on us + QObject *parent = q->parent(); + if (!parent || !QObjectPrivate::get(parent)->wasDeleted) { + for (int ii = 0; ii < notifies.count(); ++ii) { + QMetaObject::activate(q, notifies[ii] + notifyIndex, 0); + } + } } void QmlContextPrivate::init() diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index f896873..fc615b6 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -66,7 +66,6 @@ class QmlContext; class QmlExpression; class QmlEngine; class QmlExpression; -class QmlCompiledComponent; class QmlContextPrivate : public QObjectPrivate { diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index 559f0ee..b473e77 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -71,7 +71,7 @@ public: bool create = false); }; -class QmlCompiledComponent; +class QmlCompiledData; class QmlInstanceDeclarativeData : public QmlSimpleDeclarativeData { public: @@ -79,7 +79,7 @@ public: virtual void destroyed(QObject *); - QmlCompiledComponent *deferredComponent; + QmlCompiledData *deferredComponent; unsigned int deferredIdx; static inline QmlInstanceDeclarativeData *get(QObject *object, diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp index e293a93..e3cb563 100644 --- a/src/declarative/qml/qmldom.cpp +++ b/src/declarative/qml/qmldom.cpp @@ -43,7 +43,6 @@ #include "qmldom_p.h" #include "private/qmlcompiler_p.h" #include "private/qmlengine_p.h" -#include "qmlcompiledcomponent_p.h" #include <QtCore/QByteArray> #include <QtCore/QDebug> #include <QtCore/QString> @@ -165,7 +164,7 @@ bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data, const QUrl d->errors.clear(); d->imports.clear(); - QmlCompiledComponent component; + QmlCompiledData component; QmlCompiler compiler; QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, url); @@ -1384,7 +1383,6 @@ QmlDomValue::Type QmlDomValue::type() const return PropertyBinding; case QmlParser::Value::ValueSource: return ValueSource; - case QmlParser::Value::Component: case QmlParser::Value::CreatedObject: return Object; case QmlParser::Value::SignalObject: diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 46c8b30..acbeb26 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -43,6 +43,7 @@ #include <private/qmlengine_p.h> #include <private/qmlcontext_p.h> #include <private/qobject_p.h> +#include <private/qmlcompiler_p.h> #ifdef QT_SCRIPTTOOLS_LIB #include <QScriptEngineDebugger> @@ -60,7 +61,6 @@ #include <private/qfxperf_p.h> #include <QStack> #include "private/qmlbasicscript_p.h" -#include "private/qmlcompiledcomponent_p.h" #include "qmlengine.h" #include "qmlcontext.h" #include "qmlexpression.h" diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 84352b8..4fe7d0c 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -43,6 +43,10 @@ #include "qmlexpression_p.h" #include "qmlengine_p.h" #include "qmlcontext_p.h" +#include "rewriter/textwriter_p.h" +#include "parser/qmljslexer_p.h" +#include "parser/qmljsparser_p.h" +#include "parser/qmljsnodepool_p.h" #include "QtCore/qdebug.h" Q_DECLARE_METATYPE(QList<QObject *>); @@ -51,18 +55,109 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) +namespace { + +using namespace QmlJS; + +class RewriteBinding: protected AST::Visitor +{ + unsigned _position; + TextWriter *_writer; + +public: + QString operator()(const QString &code) + { + Engine engine; + NodePool pool(QString(), &engine); + Lexer lexer(&engine); + Parser parser(&engine); + lexer.setCode(code, 0); + parser.parseStatement(); + return rewrite(code, 0, parser.statement()); + } + +protected: + using AST::Visitor::visit; + + void accept(AST::Node *node) + { + AST::Node::acceptChild(node, this); + } + + QString rewrite(QString code, unsigned position, AST::Statement *node) + { + TextWriter w; + _writer = &w; + _position = position; + + accept(node); + + unsigned startOfStatement = node->firstSourceLocation().begin() - _position; + unsigned endOfStatement = node->lastSourceLocation().end() - _position; + + _writer->replace(startOfStatement, 0, QLatin1String("function() {\n")); + _writer->replace(endOfStatement, 0, QLatin1String("\n}")); + + w.write(&code); + + return code; + } + + virtual bool visit(AST::Block *ast) + { + for (AST::StatementList *it = ast->statements; it; it = it->next) { + if (! it->next) { + // we need to rewrite only the last statement of a block. + accept(it->statement); + } + } + + return false; + } + + virtual bool visit(AST::ExpressionStatement *ast) + { + unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position; + _writer->replace(startOfExpressionStatement, 0, QLatin1String("return ")); + + return false; + } + + virtual bool visit(AST::NumericLiteral *node) + { + if (node->suffix != AST::NumericLiteral::noSuffix) { + const int suffixLength = AST::NumericLiteral::suffixLength[node->suffix]; + const char *suffixSpell = AST::NumericLiteral::suffixSpell[node->suffix]; + QString pre; + pre += QLatin1String("qmlNumberFrom"); + pre += QChar(QLatin1Char(suffixSpell[0])).toUpper(); + pre += QLatin1String(&suffixSpell[1]); + pre += QLatin1Char('('); + _writer->replace(node->literalToken.begin() - _position, 0, pre); + _writer->replace(node->literalToken.end() - _position - suffixLength, + suffixLength, + QLatin1String(")")); + } + + return false; + } +}; + +} // end of anonymous namespace + + QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) +: q(b), ctxt(0), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), expressionFunctionValid(false), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) -: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +: q(b), ctxt(0), expression(expr), expressionFunctionValid(false), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { } @@ -77,7 +172,7 @@ QmlExpressionPrivate::~QmlExpressionPrivate() /*! Create an invalid QmlExpression. - As the expression will not have an associated QmlContext, this will be a + As the expression will not have an associated QmlContext, this will be a null expression object and its value will always be an invalid QVariant. */ QmlExpression::QmlExpression() @@ -86,7 +181,7 @@ QmlExpression::QmlExpression() } /*! \internal */ -QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, +QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, QmlRefCount *rc, QObject *me) : d(new QmlExpressionPrivate(this, expr, rc)) { @@ -105,7 +200,7 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, If specified, the \a scope object's properties will also be in scope during the expression's execution. */ -QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, QObject *scope) : d(new QmlExpressionPrivate(this, expression)) { @@ -177,13 +272,15 @@ void QmlExpression::setExpression(const QString &expression) delete d->proxy; d->proxy = 0; d->expression = expression; + d->expressionFunctionValid = false; + d->expressionFunction = QScriptValue(); d->sse.clear(); } /*! Called by QmlExpression each time the expression value changes from the - last time it was evaluated. The expression must have been evaluated at + last time it was evaluated. The expression must have been evaluated at least once (by calling QmlExpression::value()) before this callback will be made. @@ -226,16 +323,24 @@ QVariant QmlExpressionPrivate::evalQtScript() ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me); QScriptEngine *scriptEngine = engine->scriptEngine(); - QScriptValueList oldScopeChain = + QScriptValueList oldScopeChain = scriptEngine->currentContext()->scopeChain(); for (int i = 0; i < oldScopeChain.size(); ++i) scriptEngine->currentContext()->popScope(); - for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) + for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) scriptEngine->currentContext()->pushScope(ctxtPriv->scopeChain.at(i)); - - QScriptValue svalue = - scriptEngine->evaluate(expression, fileName.toString(), line); + + if (!expressionFunctionValid) { + RewriteBinding rewriteBinding; + + const QString code = rewriteBinding(expression); + expressionFunction = scriptEngine->evaluate(code, fileName.toString(), line); + expressionFunctionValid = true; + } + + QScriptValue svalue = expressionFunction.call(); + if (scriptEngine->hasUncaughtException()) { if (scriptEngine->uncaughtException().isError()){ @@ -262,7 +367,7 @@ QVariant QmlExpressionPrivate::evalQtScript() QList<QObject *> list; for (int ii = 0; ii < length; ++ii) { QScriptValue arrayItem = svalue.property(ii); - QObject *d = + QObject *d = qvariant_cast<QObject *>(arrayItem.data().toVariant()); if (d) { list << d; @@ -272,11 +377,11 @@ QVariant QmlExpressionPrivate::evalQtScript() } rv = QVariant::fromValue(list); } - } else if (svalue.isObject() && + } else if (svalue.isObject() && !svalue.isNumber() && !svalue.isString() && - !svalue.isDate() && - !svalue.isError() && + !svalue.isDate() && + !svalue.isError() && !svalue.isFunction() && !svalue.isNull() && !svalue.isQMetaObject() && @@ -290,19 +395,19 @@ QVariant QmlExpressionPrivate::evalQtScript() rv = var; } } - if (rv.isNull()) + if (rv.isNull()) rv = svalue.toVariant(); - for (int i = 0; i < ctxtPriv->scopeChain.size(); ++i) + for (int i = 0; i < ctxtPriv->scopeChain.size(); ++i) scriptEngine->currentContext()->popScope(); - for (int i = oldScopeChain.size() - 1; i > -1; --i) + for (int i = oldScopeChain.size() - 1; i > -1; --i) scriptEngine->currentContext()->pushScope(oldScopeChain.at(i)); return rv; } /*! - Returns the value of the expression, or an invalid QVariant if the + Returns the value of the expression, or an invalid QVariant if the expression is invalid or has an error. */ QVariant QmlExpression::value() @@ -358,12 +463,12 @@ QVariant QmlExpression::value() d->proxy, changedIndex); } else { const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = + QMetaProperty metaProp = metaObj->property(prop.coreIndex); - QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") + - QLatin1String(metaObj->className()) + - QLatin1String("::") + + QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") + + QLatin1String(metaObj->className()) + + QLatin1String("::") + QLatin1String(metaProp.name()); log.addWarning(warn); } @@ -386,10 +491,10 @@ QVariant QmlExpression::value() } const QMetaObject *metaObj = prop.object->metaObject(); - QMetaProperty metaProp = + QMetaProperty metaProp = metaObj->property(prop.coreIndex); - qWarning().nospace() << " " << metaObj->className() + qWarning().nospace() << " " << metaObj->className() << "::" << metaProp.name(); } } @@ -438,14 +543,14 @@ bool QmlExpression::trackChange() const /*! Set whether changes are tracked in the expression's value to \a trackChange. - If true, the QmlExpression will monitor properties involved in the + If true, the QmlExpression will monitor properties involved in the expression's evaluation, and call QmlExpression::valueChanged() if they have changed. This allows an application to ensure that any value associated with the result of the expression remains up to date. If false, the QmlExpression will not montitor properties involved in the expression's evaluation, and QmlExpression::valueChanged() will never be - called. This is more efficient if an application wants a "one off" + called. This is more efficient if an application wants a "one off" evaluation of the expression. By default, trackChange is true. @@ -468,7 +573,7 @@ void QmlExpression::setSourceLocation(const QUrl &fileName, int line) /*! Returns the expression's scope object, if provided, otherwise 0. - In addition to data provided by the expression's QmlContext, the scope + In addition to data provided by the expression's QmlContext, the scope object's properties are also in scope during the expression's evaluation. */ QObject *QmlExpression::scopeObject() const @@ -498,13 +603,13 @@ quint32 QmlExpression::id() const more convenient in an application, QmlExpressionObject can be used instead. QmlExpressionObject behaves identically to QmlExpression, except that the - QmlExpressionObject::value() method is a slot, and the + QmlExpressionObject::value() method is a slot, and the QmlExpressionObject::valueChanged() callback is a signal. */ /*! Create a QmlExpression with the specified \a parent. - As the expression will not have an associated QmlContext, this will be a + As the expression will not have an associated QmlContext, this will be a null expression object and its value will always be an invalid QVariant. */ QmlExpressionObject::QmlExpressionObject(QObject *parent) @@ -531,7 +636,7 @@ QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount } /*! - Returns the value of the expression, or an invalid QVariant if the + Returns the value of the expression, or an invalid QVariant if the expression is invalid or has an error. */ QVariant QmlExpressionObject::value() @@ -543,8 +648,8 @@ QVariant QmlExpressionObject::value() \fn void QmlExpressionObject::valueChanged() Emitted each time the expression value changes from the last time it was - evaluated. The expression must have been evaluated at least once (by - calling QmlExpressionObject::value()) before this signal will be emitted. + evaluated. The expression must have been evaluated at least once (by + calling QmlExpressionObject::value()) before this signal will be emitted. */ void QmlExpressionPrivate::addLog(const QmlExpressionLog &l) diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 5883125..09745a3 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -55,6 +55,7 @@ #include "qmlbasicscript_p.h" #include "qmlexpression.h" +#include <QtScript/qscriptvalue.h> QT_BEGIN_NAMESPACE @@ -73,6 +74,9 @@ public: QmlExpression *q; QmlContext *ctxt; QString expression; + bool expressionFunctionValid; + QScriptValue expressionFunction; + QmlBasicScript sse; void *sseData; QmlExpressionBindProxy *proxy; diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 1647a12..83fb18b 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -39,13 +39,13 @@ ** ****************************************************************************/ -#include "private/qmlinstruction_p.h" -#include "private/qmlcompiledcomponent_p.h" -#include <QDebug> +#include "qmlinstruction_p.h" +#include "qmlcompiler_p.h" +#include <QtCore/qdebug.h> QT_BEGIN_NAMESPACE -void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) +void QmlCompiledData::dump(QmlInstruction *instr, int idx) { QByteArray lineNumber = QByteArray::number(instr->line); if (instr->line == (unsigned short)-1) @@ -54,13 +54,13 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) switch(instr->type) { case QmlInstruction::Init: - qWarning() << idx << "\t" << line << "\t" << "INIT\t\t\t" << instr->init.dataSize; + qWarning() << idx << "\t" << line << "\t" << "INIT"; break; case QmlInstruction::CreateObject: qWarning() << idx << "\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; break; case QmlInstruction::SetId: - qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t" << instr->setId.save << "\t\t" << primitives.at(instr->setId.value); + qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t\t\t\t" << primitives.at(instr->setId.value); break; case QmlInstruction::SetDefault: qWarning() << idx << "\t" << line << "\t" << "SET_DEFAULT"; @@ -125,8 +125,11 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::StoreObject: qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex; break; - case QmlInstruction::AssignCustomType: - qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + case QmlInstruction::StoreVariantObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_VARIANT_OBJECT\t" << instr->storeObject.propertyIndex; + break; + case QmlInstruction::StoreInterface: + qWarning() << idx << "\t" << line << "\t" << "STORE_INTERFACE\t\t" << instr->storeObject.propertyIndex; break; case QmlInstruction::StoreSignal: qWarning() << idx << "\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); @@ -134,6 +137,9 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::AssignSignalObject: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); break; + case QmlInstruction::AssignCustomType: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + break; case QmlInstruction::StoreBinding: qWarning() << idx << "\t" << line << "\t" << "STORE_BINDING\t\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << primitives.at(instr->assignBinding.value); break; @@ -149,6 +155,12 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::CompleteObject: qWarning() << idx << "\t" << line << "\t" << "COMPLETE\t\t" << instr->complete.castValue; break; + case QmlInstruction::StoreObjectQmlList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QMLLIST"; + break; + case QmlInstruction::StoreObjectQList: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT_QLIST"; + break; case QmlInstruction::AssignObjectList: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_OBJECT_LIST\t"; break; @@ -170,14 +182,11 @@ void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) case QmlInstruction::PopQList: qWarning() << idx << "\t" << line << "\t" << "POP_QLIST"; break; - case QmlInstruction::PushProperty: - qWarning() << idx << "\t" << line << "\t" << "PUSH_PROPERTY" << "\t\t" << instr->pushProperty.property; - break; - case QmlInstruction::StoreStackObject: - qWarning() << idx << "\t" << line << "\t" << "STORE_STACK_OBJ" << "\t" << instr->assignStackObject.property << "\t" << instr->assignStackObject.object; + case QmlInstruction::Defer: + qWarning() << idx << "\t" << line << "\t" << "DEFER" << "\t\t" << instr->defer.deferCount; break; default: - qWarning() << idx << "\t" << line << "\t" << "XXX UNKOWN INSTRUCTION"; + qWarning() << idx << "\t" << line << "\t" << "XXX UNKOWN INSTRUCTION" << "\t" << instr->type; break; } } diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 40f9a32..a7221c0 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE -class QmlCompiledComponent; +class QmlCompiledData; class Q_DECLARATIVE_EXPORT QmlInstruction { public: @@ -118,8 +118,6 @@ public: StoreSignal, /* storeSignal */ - // XXX need to handle storing objects in variants - // // Unresolved single assignment // @@ -154,14 +152,6 @@ public: // Deferred creation // Defer, /* defer */ - - // - // Expression optimizations - // - // PushProperty - Save the property for later use - // StoreStackObject - Assign the stack object (no checks) - PushProperty, /* pushProperty */ - StoreStackObject /* assignStackObject */ }; QmlInstruction() : line(0) {} @@ -170,7 +160,6 @@ public: unsigned short line; union { struct { - int dataSize; int bindingsSize; int parserStatusSize; } init; @@ -185,7 +174,6 @@ public: } storeMeta; struct { int value; - int save; } setId; struct { int property; @@ -198,7 +186,6 @@ public: } assignBinding; struct { int property; - bool isObject; } fetch; struct { int property; @@ -281,18 +268,11 @@ public: int id; } fetchAttached; struct { - int property; - } pushProperty; - struct { - int property; - int object; - } assignStackObject; - struct { int deferCount; } defer; }; - void dump(QmlCompiledComponent *); + void dump(QmlCompiledData *); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index e158adf..6602021 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -663,9 +663,6 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) return; } - if (!value.isValid()) - return; - int t = propertyType(); int vt = value.userType(); int category = propertyCategory(); @@ -684,19 +681,22 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value) QObject *o = QmlMetaType::toQObject(value); - if (!o) - return; + const QMetaObject *valMo = 0; - const QMetaObject *valMo = o->metaObject(); - const QMetaObject *propMo = QmlMetaType::rawMetaObjectForType(t); + if (o) { + + valMo = o->metaObject(); + const QMetaObject *propMo = QmlMetaType::rawMetaObjectForType(t); + + while (valMo) { + if (valMo == propMo) + break; + valMo = valMo->superClass(); + } - while (valMo) { - if (valMo == propMo) - break; - valMo = valMo->superClass(); } - if (valMo) { + if (valMo || !o) { void *args[] = { &o, 0 }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 8daab6a..8ee3b4e 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -62,7 +62,8 @@ QT_BEGIN_NAMESPACE using namespace QmlParser; QmlParser::Object::Object() -: type(-1), metatype(0), extObjectData(0), defaultProperty(0) +: type(-1), metatype(0), extObjectData(0), defaultProperty(0), + parserStatusCast(-1) { } @@ -71,6 +72,14 @@ QmlParser::Object::~Object() if (defaultProperty) defaultProperty->release(); foreach(Property *prop, properties) prop->release(); + foreach(Property *prop, valueProperties) + prop->release(); + foreach(Property *prop, signalProperties) + prop->release(); + foreach(Property *prop, attachedProperties) + prop->release(); + foreach(Property *prop, groupedProperties) + prop->release(); } const QMetaObject *Object::metaObject() const @@ -90,6 +99,30 @@ QmlParser::Property *Object::getDefaultProperty() return defaultProperty; } +void QmlParser::Object::addValueProperty(Property *p) +{ + p->addref(); + valueProperties << p; +} + +void QmlParser::Object::addSignalProperty(Property *p) +{ + p->addref(); + signalProperties << p; +} + +void QmlParser::Object::addAttachedProperty(Property *p) +{ + p->addref(); + attachedProperties << p; +} + +void QmlParser::Object::addGroupedProperty(Property *p) +{ + p->addref(); + groupedProperties << p; +} + Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { @@ -160,12 +193,13 @@ void QmlParser::Object::dump(int indent) const } QmlParser::Property::Property() -: parent(0), type(0), index(-1), value(0), isDefault(true) +: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false) { } QmlParser::Property::Property(const QByteArray &n) -: parent(0), type(0), index(-1), value(0), name(n), isDefault(false) +: parent(0), type(0), index(-1), value(0), name(n), isDefault(false), + isDeferred(false) { } @@ -187,6 +221,11 @@ void QmlParser::Property::addValue(Value *v) values << v; } +bool QmlParser::Property::isEmpty() const +{ + return !value && values.isEmpty(); +} + void QmlParser::Property::dump(int indent) const { QByteArray ba(indent * 4, ' '); @@ -232,9 +271,6 @@ void QmlParser::Value::dump(int indent) const case Value::SignalExpression: type = "SignalExpression"; break; - case Value::Component: - type = "Component"; - break; case Value::Id: type = "Id"; break; diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 7550870..d96a43e 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -110,8 +110,8 @@ namespace QmlParser virtual ~Object(); // Type of the object. The integer is an index into the - // QmlCompiledData::types array, or -1 if the object is a fetched - // object. + // QmlCompiledData::types array, or -1 if the object is a property + // group. int type; // The url of this object if it is an external type. Used by the DOM QUrl url; @@ -131,6 +131,8 @@ namespace QmlParser // this type. Otherwise null QMetaObject *extObjectData; QAbstractDynamicMetaObject extObject; + QByteArray metadata; // Generated by compiler + QByteArray synthdata; // Generated by compiler Property *getDefaultProperty(); Property *getProperty(const QByteArray &name, bool create=true); @@ -138,6 +140,22 @@ namespace QmlParser Property *defaultProperty; QHash<QByteArray, Property *> properties; + // Output of the compilation phase (these properties continue to exist + // in either the defaultProperty or properties members too) + void addValueProperty(Property *); + void addSignalProperty(Property *); + void addAttachedProperty(Property *); + void addGroupedProperty(Property *); + QList<Property *> valueProperties; + QList<Property *> signalProperties; + QList<Property *> attachedProperties; + QList<Property *> groupedProperties; + + // The bytes to cast instances by to get to the QmlParserStatus + // interface. -1 indicates the type doesn't support this interface. + // Set by the QmlCompiler. + int parserStatusCast; + LocationSpan location; struct DynamicProperty { @@ -242,8 +260,6 @@ namespace QmlParser SignalObject, // This is used as a signal expression assignment SignalExpression, - // This is used as an implicit component creation - Component, // This is used as an id assignment only Id }; @@ -281,6 +297,9 @@ namespace QmlParser // The metaobject index of this property, or -1 if unknown. int index; + // Returns true if this is an empty property - both value and values + // are unset. + bool isEmpty() const; // The list of values assigned to this property. Content in values // and value are mutually exclusive QList<Value *> values; @@ -291,6 +310,9 @@ namespace QmlParser QByteArray name; // True if this property was accessed as the default property. bool isDefault; + // True if the setting of this property will be deferred. Set by the + // QmlCompiler + bool isDeferred; LocationSpan location; LocationRange listValueRange; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 2acf1e2..3b33686 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qmlvme_p.h" +#include "qmlcompiler_p.h" #include <private/qfxperf_p.h> #include <private/qmlboundsignal_p.h> #include <private/qmlstringconverters_p.h> @@ -49,7 +50,6 @@ #include <private/qmlcustomparser_p.h> #include <QStack> #include <QWidget> -#include <private/qmlcompiledcomponent_p.h> #include <QColor> #include <QPointF> #include <QSizeF> @@ -98,7 +98,7 @@ struct ListInstance QmlPrivate::ListInterface *qmlListInterface; }; -QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, int count) +QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledData *comp, int start, int count) { QStack<QObject *> stack; @@ -117,7 +117,7 @@ void QmlVME::runDeferred(QObject *object) QmlContext *ctxt = data->context; ctxt->activate(); - QmlCompiledComponent *comp = data->deferredComponent; + QmlCompiledData *comp = data->deferredComponent; int start = data->deferredIdx + 1; int count = data->deferredComponent->bytecode.at(data->deferredIdx).defer.deferCount; QStack<QObject *> stack; @@ -127,7 +127,7 @@ void QmlVME::runDeferred(QObject *object) ctxt->deactivate(); } -QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComponent *comp, int start, int count) +QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData *comp, int start, int count) { // XXX - All instances of QmlContext::activeContext() here should be // replaced with the use of ctxt. However, this cannot be done until @@ -137,10 +137,9 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp // sub-instances on that type. Q_ASSERT(comp); Q_ASSERT(ctxt); - const QList<QmlCompiledComponent::TypeReference> &types = comp->types; + const QList<QmlCompiledData::TypeReference> &types = comp->types; const QList<QString> &primitives = comp->primitives; const QList<QByteArray> &datas = comp->datas; - const QList<QMetaObject *> &synthesizedMetaObjects = comp->synthesizedMetaObjects;; const QList<QmlCompiledData::CustomTypeData> &customTypeData = comp->customTypeData; const QList<int> &intData = comp->intData; const QList<float> &floatData = comp->floatData; @@ -152,7 +151,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp QStack<ListInstance> qliststack; QStack<QmlMetaProperty> pushedProperties; - QObject **savedObjects = 0; vmeErrors.clear(); @@ -162,12 +160,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp switch(instr.type) { case QmlInstruction::Init: { - if (instr.init.dataSize) { - savedObjects = new QObject*[instr.init.dataSize]; - ::memset(savedObjects, 0, - sizeof(QObject *)*instr.init.dataSize); - } - if (instr.init.bindingsSize) bindValues = QmlEnginePrivate::SimpleList<QmlBindableValue>(instr.init.bindingsSize); if (instr.init.parserStatusSize) @@ -214,9 +206,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp QmlContext *ctxt = QmlContext::activeContext(); ctxt->setContextProperty(primitives.at(instr.setId.value), target); - - if (instr.setId.save != -1) - savedObjects[instr.setId.save] = target; } break; @@ -239,7 +228,14 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp case QmlInstruction::StoreMetaObject: { QObject *target = stack.top(); - new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp); + + QMetaObject mo; + const QByteArray &metadata = datas.at(instr.storeMeta.data); + QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); + + const QmlVMEMetaData *data = (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + + (void)new QmlVMEMetaObject(target, &mo, data, comp); } break; @@ -465,7 +461,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp { QObject *target = stack.top(); void *a[1]; - QmlCompiledComponent::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); + QmlCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); const QString &primitive = primitives.at(data.index); QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(data.type); @@ -545,15 +541,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp } break; - case QmlInstruction::PushProperty: - { - QObject *target = stack.top(); - QmlMetaProperty mp(target, instr.pushProperty.property, - QmlMetaProperty::Object); - pushedProperties.push(mp); - } - break; - case QmlInstruction::StoreCompiledBinding: { QObject *target = stack.top(); @@ -745,22 +732,12 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp QObject *target = stack.top(); QObject *obj = 0; - if (instr.fetch.isObject) { - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - void *a[1]; - a[0] = &obj; - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.fetch.property, a); - } else { - void *a[1]; - QVariant var; - a[0] = &var; - QMetaObject::metacall(target, QMetaObject::ReadProperty, - instr.fetch.property, a); - obj = QmlMetaType::toQObject(var); - - } + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + void *a[1]; + a[0] = &obj; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetch.property, a); if (!obj) VME_EXCEPTION("Cannot set properties on" << target->metaObject()->property(instr.fetch.property).name() << "as it is null"); @@ -795,23 +772,8 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp } break; - case QmlInstruction::StoreStackObject: - { - const QmlMetaProperty &prop = - pushedProperties.at(instr.assignStackObject.property); - QObject *obj = savedObjects[instr.assignStackObject.object]; - - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - void *a[1]; - a[0] = (void *)&obj; - QMetaObject::metacall(prop.object(), QMetaObject::WriteProperty, - prop.coreIndex(), a); - } - break; - default: - qFatal("QmlCompiledComponent: Internal error - unknown instruction %d", instr.type); + qFatal("QmlCompiledData: Internal error - unknown instruction %d", instr.type); break; } } @@ -832,11 +794,6 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp if (parserStatus.count) ep->parserStatus << parserStatus; - comp->dumpPost(); - - if (savedObjects) - delete [] savedObjects; - if (stack.isEmpty()) return 0; else diff --git a/src/declarative/qml/qmlvme_p.h b/src/declarative/qml/qmlvme_p.h index 2da7bb4..30a6e4f 100644 --- a/src/declarative/qml/qmlvme_p.h +++ b/src/declarative/qml/qmlvme_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE class QObject; class QmlInstruction; -class QmlCompiledComponent; +class QmlCompiledData; class QmlCompiledData; class QmlContext; @@ -70,14 +70,14 @@ class QmlVME public: QmlVME(); - QObject *run(QmlContext *, QmlCompiledComponent *, int start = -1, int count = -1); + QObject *run(QmlContext *, QmlCompiledData *, int start = -1, int count = -1); void runDeferred(QObject *); bool isError() const; QList<QmlError> errors() const; private: - QObject *run(QStack<QObject *> &, QmlContext *, QmlCompiledComponent *, int start, int count); + QObject *run(QStack<QObject *> &, QmlContext *, QmlCompiledData *, int start, int count); QList<QmlError> vmeErrors; }; diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index 6d14689..33a31a4 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -53,12 +53,9 @@ QT_BEGIN_NAMESPACE QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, - QList<QString> *strData, - int slotData, const QmlVMEMetaData *meta, QmlRefCount *rc) -: object(obj), ref(rc), metaData(meta), slotData(strData), - slotDataIdx(slotData), parent(0) +: object(obj), ref(rc), metaData(meta), parent(0) { if (ref) ref->addref(); @@ -208,7 +205,11 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) id -= plainSignals; if (id < metaData->methodCount) { - QString code = slotData->at(id + slotDataIdx); + QmlVMEMetaData::MethodData *data = metaData->methodData() + id; + const QChar *body = + (const QChar *)(((const char*)metaData) + data->bodyOffset); + + QString code = QString::fromRawData(body, data->bodyLength); QmlContext *ctxt = qmlContext(object); if (0 == (metaData->methodData() + id)->parameterCount) { diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index 6421c3f..931d22c 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -78,6 +78,9 @@ struct QmlVMEMetaData struct MethodData { int parameterCount; + int bodyOffset; + int bodyLength; + int _dummy; }; PropertyData *propertyData() const { @@ -89,7 +92,7 @@ struct QmlVMEMetaData } MethodData *methodData() const { - return (MethodData *)(aliasData() + propertyCount); + return (MethodData *)(aliasData() + aliasCount); } }; @@ -97,7 +100,8 @@ class QmlRefCount; class QmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, const QmlVMEMetaData *data, QmlRefCount * = 0); + QmlVMEMetaObject(QObject *, const QMetaObject *, const QmlVMEMetaData *data, + QmlRefCount * = 0); ~QmlVMEMetaObject(); protected: @@ -114,8 +118,10 @@ private: QVariant *data; QBitArray aConnected; +#if 0 QList<QString> *slotData; int slotDataIdx; +#endif QAbstractDynamicMetaObject *parent; diff --git a/src/declarative/util/qmlpalette.cpp b/src/declarative/util/qmlpalette.cpp index 670966d..40cfa71 100644 --- a/src/declarative/util/qmlpalette.cpp +++ b/src/declarative/util/qmlpalette.cpp @@ -41,6 +41,7 @@ #include "private/qobject_p.h" #include "qmlpalette.h" +#include <QApplication> QT_BEGIN_NAMESPACE @@ -63,7 +64,9 @@ QmlPalette::QmlPalette(QObject *parent) : QObject(*(new QmlPalettePrivate), parent) { Q_D(QmlPalette); + d->palette = qApp->palette(); d->group = QPalette::Active; + qApp->installEventFilter(this); } QmlPalette::~QmlPalette() @@ -148,6 +151,16 @@ QColor QmlPalette::highlightedText() const return d->palette.color(d->group, QPalette::HighlightedText); } +QColor QmlPalette::lighter(const QColor& color) const +{ + return color.lighter(); +} + +QColor QmlPalette::darker(const QColor& color) const +{ + return color.darker(); +} + void QmlPalette::setColorGroup(QPalette::ColorGroup colorGroup) { Q_D(QmlPalette); @@ -160,4 +173,26 @@ QPalette QmlPalette::palette() const return d->palette; } +bool QmlPalette::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == qApp) { + if (event->type() == QEvent::ApplicationPaletteChange) { + QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange)); + return false; + } + } + return QObject::eventFilter(watched, event); +} + +bool QmlPalette::event(QEvent *event) +{ + Q_D(QmlPalette); + if (event->type() == QEvent::ApplicationPaletteChange) { + d->palette = qApp->palette(); + emit paletteChanged(); + return true; + } + return QObject::event(event); +} + QT_END_NAMESPACE diff --git a/src/declarative/util/qmlpalette.h b/src/declarative/util/qmlpalette.h index f176764..7f26f9a 100644 --- a/src/declarative/util/qmlpalette.h +++ b/src/declarative/util/qmlpalette.h @@ -62,19 +62,19 @@ public: QmlPalette(QObject *parent=0); ~QmlPalette(); - Q_PROPERTY(QColor window READ window CONSTANT) - Q_PROPERTY(QColor windowText READ windowText CONSTANT) - Q_PROPERTY(QColor base READ base CONSTANT) - Q_PROPERTY(QColor alternateBase READ alternateBase CONSTANT) - Q_PROPERTY(QColor button READ button CONSTANT) - Q_PROPERTY(QColor buttonText READ buttonText CONSTANT) - Q_PROPERTY(QColor light READ light CONSTANT) - Q_PROPERTY(QColor midlight READ midlight CONSTANT) - Q_PROPERTY(QColor dark READ dark CONSTANT) - Q_PROPERTY(QColor mid READ mid CONSTANT) - Q_PROPERTY(QColor shadow READ shadow CONSTANT) - Q_PROPERTY(QColor highlight READ highlight CONSTANT) - Q_PROPERTY(QColor highlightedText READ highlightedText CONSTANT) + Q_PROPERTY(QColor window READ window NOTIFY paletteChanged) + Q_PROPERTY(QColor windowText READ windowText NOTIFY paletteChanged) + Q_PROPERTY(QColor base READ base NOTIFY paletteChanged) + Q_PROPERTY(QColor alternateBase READ alternateBase NOTIFY paletteChanged) + Q_PROPERTY(QColor button READ button NOTIFY paletteChanged) + Q_PROPERTY(QColor buttonText READ buttonText NOTIFY paletteChanged) + Q_PROPERTY(QColor light READ light NOTIFY paletteChanged) + Q_PROPERTY(QColor midlight READ midlight NOTIFY paletteChanged) + Q_PROPERTY(QColor dark READ dark NOTIFY paletteChanged) + Q_PROPERTY(QColor mid READ mid NOTIFY paletteChanged) + Q_PROPERTY(QColor shadow READ shadow NOTIFY paletteChanged) + Q_PROPERTY(QColor highlight READ highlight NOTIFY paletteChanged) + Q_PROPERTY(QColor highlightedText READ highlightedText NOTIFY paletteChanged) QColor window() const; QColor windowText() const; @@ -98,8 +98,14 @@ public: void setColorGroup(QPalette::ColorGroup); + bool virtual eventFilter(QObject *watched, QEvent *event); + bool virtual event(QEvent *event); + + Q_INVOKABLE QColor lighter(const QColor&) const; + Q_INVOKABLE QColor darker(const QColor&) const; + Q_SIGNALS: - void updated(); + void paletteChanged(); }; QT_END_NAMESPACE diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index 433406c..7fa26ae 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -976,7 +976,7 @@ void QAbstractSpinBox::keyPressEvent(QKeyEvent *event) #endif case Qt::Key_Enter: case Qt::Key_Return: - d->edit->d_func()->modifiedState = d->edit->d_func()->undoState = 0; + d->edit->d_func()->control->clearUndo(); d->interpret(d->keyboardTracking ? AlwaysEmit : EmitIfChanged); selectAll(); event->ignore(); diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp new file mode 100644 index 0000000..97f4a45 --- /dev/null +++ b/src/gui/widgets/qlinecontrol.cpp @@ -0,0 +1,1745 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlinecontrol_p.h" + +#ifndef QT_NO_LINEEDIT + +#include "qabstractitemview.h" +#include "qclipboard.h" +#ifndef QT_NO_ACCESSIBILITY +#include "qaccessible.h" +#endif +#ifndef QT_NO_IM +#include "qinputcontext.h" +#include "qlist.h" +#endif +#include "qapplication.h" +#ifndef QT_NO_GRAPHICSVIEW +#include "qgraphicssceneevent.h" +#endif + +QT_BEGIN_NAMESPACE + +/*! + \internal + + Updates the display text based of the current edit text + If the text has changed will emit displayTextChanged() +*/ +void QLineControl::updateDisplayText() +{ + QString orig = m_textLayout.text(); + QString str; + if (m_echoMode == QLineEdit::NoEcho) + str = QString::fromLatin1(""); + else + str = m_text; + + if (m_echoMode == QLineEdit::Password || (m_echoMode == QLineEdit::PasswordEchoOnEdit + && !m_passwordEchoEditing)) + str.fill(m_passwordCharacter); + + // replace certain non-printable characters with spaces (to avoid + // drawing boxes when using fonts that don't have glyphs for such + // characters) + QChar* uc = str.data(); + for (int i = 0; i < (int)str.length(); ++i) { + if ((uc[i] < 0x20 && uc[i] != 0x09) + || uc[i] == QChar::LineSeparator + || uc[i] == QChar::ParagraphSeparator + || uc[i] == QChar::ObjectReplacementCharacter) + uc[i] = QChar(0x0020); + } + + m_textLayout.setText(str); + + QTextOption option; + option.setTextDirection(m_layoutDirection); + option.setFlags(QTextOption::IncludeTrailingSpaces); + m_textLayout.setTextOption(option); + + m_textLayout.beginLayout(); + QTextLine l = m_textLayout.createLine(); + m_textLayout.endLayout(); + m_ascent = qRound(l.ascent()); + + if (str != orig) + emit displayTextChanged(str); +} + +#ifndef QT_NO_CLIPBOARD +/*! + \internal + + Copies the currently selected text into the clipboard using the given + \a mode. + + \note If the echo mode is set to a mode other than Normal then copy + will not work. This is to prevent using copy as a method of bypassing + password features of the line control. +*/ +void QLineControl::copy(QClipboard::Mode mode) const +{ + QString t = selectedText(); + if (!t.isEmpty() && m_echoMode == QLineEdit::Normal) { + disconnect(QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0); + QApplication::clipboard()->setText(t, mode); + connect(QApplication::clipboard(), SIGNAL(selectionChanged()), + this, SLOT(_q_clipboardChanged())); + } +} + +/*! + \internal + + Inserts the text stored in the application clipboard into the line + control. + + \sa insert() +*/ +void QLineControl::paste() +{ + insert(QApplication::clipboard()->text(QClipboard::Clipboard)); +} + +#endif // !QT_NO_CLIPBOARD + +/*! + \internal + + Handles the behavior for the backspace key or function. + Removes the current selection if there is a selection, otherwise + removes the character prior to the cursor position. + + \sa del() +*/ +void QLineControl::backspace() +{ + int priorState = m_undoState; + if (hasSelectedText()) { + removeSelectedText(); + } else if (m_cursor) { + --m_cursor; + if (m_maskData) + m_cursor = prevMaskBlank(m_cursor); + QChar uc = m_text.at(m_cursor); + if (m_cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { + // second half of a surrogate, check if we have the first half as well, + // if yes delete both at once + uc = m_text.at(m_cursor - 1); + if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) { + internalDelete(true); + --m_cursor; + } + } + internalDelete(true); + } + finishChange(priorState); +} + +/*! + \internal + + Handles the behavior for the delete key or function. + Removes the current selection if there is a selection, otherwise + removes the character after the cursor position. + + \sa del() +*/ +void QLineControl::del() +{ + int priorState = m_undoState; + if (hasSelectedText()) { + removeSelectedText(); + } else { + int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor; + while (n--) + internalDelete(); + } + finishChange(priorState); +} + +/*! + \internal + + Inserts the given \a newText at the current cursor position. + If there is any selected text it is removed prior to insertion of + the new text. +*/ +void QLineControl::insert(const QString &newText) +{ + int priorState = m_undoState; + removeSelectedText(); + internalInsert(newText); + finishChange(priorState); +} + +/*! + \internal + + Clears the line control text. +*/ +void QLineControl::clear() +{ + int priorState = m_undoState; + m_selstart = 0; + m_selend = m_text.length(); + removeSelectedText(); + separate(); + finishChange(priorState, /*update*/false, /*edited*/false); +} + +/*! + \internal + + Sets \a length characters from the given \a start position as selected. + The given \a start position must be within the current text for + the line control. If \a length characters cannot be selected, then + the selection will extend to the end of the current text. +*/ +void QLineControl::setSelection(int start, int length) +{ + if(start < 0 || start > (int)m_text.length()){ + qWarning("QLineControl::setSelection: Invalid start position"); + return; + } + + if (length > 0) { + m_selstart = start; + m_selend = qMin(start + length, (int)m_text.length()); + m_cursor = m_selend; + } else { + m_selstart = qMax(start + length, 0); + m_selend = start; + m_cursor = m_selstart; + } +} + +void QLineControl::_q_clipboardChanged() +{ +} + +void QLineControl::_q_deleteSelected() +{ + if (!hasSelectedText()) + return; + + int priorState = m_undoState; + emit resetInputContext(); + removeSelectedText(); + separate(); + finishChange(priorState); +} + +/*! + \internal + + Initializes the line control with a starting text value of \a txt. +*/ +void QLineControl::init(const QString &txt) +{ + m_text = txt; + updateDisplayText(); + m_cursor = m_text.length(); +} + +/*! + \internal + + Sets the password echo editing to \a editing. If password echo editing + is true, then the text of the password is displayed even if the echo + mode is set to QLineEdit::PasswordEchoOnEdit. Password echoing editing + does not affect other echo modes. +*/ +void QLineControl::updatePasswordEchoEditing(bool editing) +{ + m_passwordEchoEditing = editing; + updateDisplayText(); +} + +/*! + \internal + + Returns the cursor position of the given \a x pixel value in relation + to the displayed text. The given \a betweenOrOn specified what kind + of cursor position is requested. +*/ +int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const +{ + return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn); +} + +/*! + \internal + + Returns the bounds of the current cursor, as defined as a + between characters cursor. +*/ +QRect QLineControl::cursorRect() const +{ + QTextLine l = m_textLayout.lineAt(0); + int c = m_cursor; + if (m_preeditCursor != -1) + c += m_preeditCursor; + int cix = qRound(l.cursorToX(c)); + int w = m_cursorWidth; + int ch = l.height() + 1; + + return QRect(cix-5, 0, w+9, ch); +} + +/*! + \internal + + Fixes the current text so that it is valid given any set validators. + + Returns true if the text was changed. Otherwise returns false. +*/ +bool QLineControl::fixup() // this function assumes that validate currently returns != Acceptable +{ +#ifndef QT_NO_VALIDATOR + if (m_validator) { + QString textCopy = m_text; + int cursorCopy = m_cursor; + m_validator->fixup(textCopy); + if (m_validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) { + if (textCopy != m_text || cursorCopy != m_cursor) + internalSetText(textCopy, cursorCopy); + return true; + } + } +#endif + return false; +} + +/*! + \internal + + Moves the cursor to the given position \a pos. If \a mark is true will + adjust the currently selected text. +*/ +void QLineControl::moveCursor(int pos, bool mark) +{ + if (pos != m_cursor) { + separate(); + if (m_maskData) + pos = pos > m_cursor ? nextMaskBlank(pos) : prevMaskBlank(pos); + } + if (mark) { + int anchor; + if (m_selend > m_selstart && m_cursor == m_selstart) + anchor = m_selend; + else if (m_selend > m_selstart && m_cursor == m_selend) + anchor = m_selstart; + else + anchor = m_cursor; + m_selstart = qMin(anchor, pos); + m_selend = qMax(anchor, pos); + updateDisplayText(); + } else { + internalDeselect(); + } + m_cursor = pos; + if (mark || m_selDirty) { + m_selDirty = false; + emit selectionChanged(); + } + emitCursorPositionChanged(); +} + +/*! + \internal + + Applies the given input method event \a event to the text of the line + control +*/ +void QLineControl::processInputMethodEvent(QInputMethodEvent *event) +{ + int priorState = m_undoState; + removeSelectedText(); + + int c = m_cursor; // cursor position after insertion of commit string + if (event->replacementStart() <= 0) + c += event->commitString().length() + qMin(-event->replacementStart(), event->replacementLength()); + + m_cursor += event->replacementStart(); + + // insert commit string + if (event->replacementLength()) { + m_selstart = m_cursor; + m_selend = m_selstart + event->replacementLength(); + removeSelectedText(); + } + if (!event->commitString().isEmpty()) + insert(event->commitString()); + + m_cursor = qMin(c, m_text.length()); + + setPreeditArea(m_cursor, event->preeditString()); + m_preeditCursor = event->preeditString().length(); + m_hideCursor = false; + QList<QTextLayout::FormatRange> formats; + for (int i = 0; i < event->attributes().size(); ++i) { + const QInputMethodEvent::Attribute &a = event->attributes().at(i); + if (a.type == QInputMethodEvent::Cursor) { + m_preeditCursor = a.start; + m_hideCursor = !a.length; + } else if (a.type == QInputMethodEvent::TextFormat) { + QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat(); + if (f.isValid()) { + QTextLayout::FormatRange o; + o.start = a.start + m_cursor; + o.length = a.length; + o.format = f; + formats.append(o); + } + } + } + m_textLayout.setAdditionalFormats(formats); + updateDisplayText(); + if (!event->commitString().isEmpty()) + emitCursorPositionChanged(); + finishChange(priorState); +} + +/*! + \internal + + Draws the display text for the line control using the given + \a painter, \a clip, and \a offset. Which aspects of the display text + are drawn is specified by the given \a flags. + + If the flags contain DrawSelections, then the selection or input mask + backgrounds and foregrounds will be applied before drawing the text. + + If the flags contain DrawCursor a cursor of the current cursorWidth() + will be drawn after drawing the text. + + The display text will only be drawn if the flags contain DrawText +*/ +void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &clip, int flags) +{ + QVector<QTextLayout::FormatRange> selections; + if (flags & DrawSelections) { + QTextLayout::FormatRange o; + if (m_selstart < m_selend) { + o.start = m_selstart; + o.length = m_selend - m_selstart; + o.format.setBackground(m_palette.brush(QPalette::Highlight)); + o.format.setForeground(m_palette.brush(QPalette::HighlightedText)); + } else { + // mask selection + o.start = m_cursor; + o.length = 1; + o.format.setBackground(m_palette.brush(QPalette::Text)); + o.format.setForeground(m_palette.brush(QPalette::Window)); + } + selections.append(o); + } + + if (flags & DrawText) + m_textLayout.draw(painter, offset, selections, clip); + + if (flags & DrawCursor){ + if(!m_blinkPeriod || m_blinkStatus) + m_textLayout.drawCursor(painter, offset, m_cursor, m_cursorWidth); + } +} + +/*! + \internal + + Sets the selection to cover the word at the given cursor position. + The word boundries is defined by the behavior of QTextLayout::SkipWords + cursor mode. +*/ +void QLineControl::selectWordAtPos(int cursor) +{ + int c = m_textLayout.previousCursorPosition(cursor, QTextLayout::SkipWords); + moveCursor(c, false); + // ## text layout should support end of words. + int end = m_textLayout.nextCursorPosition(cursor, QTextLayout::SkipWords); + while (end > cursor && m_text[end-1].isSpace()) + --end; + moveCursor(end, true); +} + +/*! + \internal + + Completes a change to the line control text. If the change is not valid + will undo the line control state back to the given \a validateFromState. + + If \a edited is true and the change is valid, will emit textEdited() in + addition to textChanged(). Otherwise only emits textChanged() on a valid + change. + + The \a update value is currently unused. +*/ +bool QLineControl::finishChange(int validateFromState, bool update, bool edited) +{ + Q_UNUSED(update) + bool lineDirty = m_selDirty; + if (m_textDirty) { + // do validation + bool wasValidInput = m_validInput; + m_validInput = true; +#ifndef QT_NO_VALIDATOR + if (m_validator) { + m_validInput = false; + QString textCopy = m_text; + int cursorCopy = m_cursor; + m_validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid); + if (m_validInput) { + if (m_text != textCopy) { + internalSetText(textCopy, cursorCopy); + return true; + } + m_cursor = cursorCopy; + } + } +#endif + if (validateFromState >= 0 && wasValidInput && !m_validInput) { + if (m_transactions.count()) + return false; + internalUndo(validateFromState); + m_history.resize(m_undoState); + if (m_modifiedState > m_undoState) + m_modifiedState = -1; + m_validInput = true; + m_textDirty = false; + } + updateDisplayText(); + lineDirty |= m_textDirty; + if (m_textDirty) { + m_textDirty = false; + QString actualText = text(); + if (edited) + emit textEdited(actualText); + emit textChanged(actualText); + } + } + if (m_selDirty) { + m_selDirty = false; + emit selectionChanged(); + } + emitCursorPositionChanged(); + return true; +} + +/*! + \internal + + An internal function for setting the text of the line control. +*/ +void QLineControl::internalSetText(const QString &txt, int pos, bool edited) +{ + internalDeselect(); + emit resetInputContext(); + QString oldText = m_text; + if (m_maskData) { + m_text = maskString(0, txt, true); + m_text += clearString(m_text.length(), m_maxLength - m_text.length()); + } else { + m_text = txt.isEmpty() ? txt : txt.left(m_maxLength); + } + m_history.clear(); + m_modifiedState = m_undoState = 0; + m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos; + m_textDirty = (oldText != m_text); + finishChange(-1, true, edited); +} + + +/*! + \internal + + Adds the given \a command to the undo history + of the line control. Does not apply the command. +*/ +void QLineControl::addCommand(const Command &cmd) +{ + if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) { + m_history.resize(m_undoState + 2); + m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend); + } else { + m_history.resize(m_undoState + 1); + } + m_separator = false; + m_history[m_undoState++] = cmd; +} + +/*! + \internal + + Inserts the given string \a s into the line + control. + + Also adds the appropriate commands into the undo history. + This function does not call finishChange(), and may leave the text + in an invalid state. +*/ +void QLineControl::internalInsert(const QString &s) +{ + if (hasSelectedText()) + addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); + if (m_maskData) { + QString ms = maskString(m_cursor, s); + for (int i = 0; i < (int) ms.length(); ++i) { + addCommand (Command(DeleteSelection, m_cursor + i, m_text.at(m_cursor + i), -1, -1)); + addCommand(Command(Insert, m_cursor + i, ms.at(i), -1, -1)); + } + m_text.replace(m_cursor, ms.length(), ms); + m_cursor += ms.length(); + m_cursor = nextMaskBlank(m_cursor); + m_textDirty = true; + } else { + int remaining = m_maxLength - m_text.length(); + if (remaining != 0) { + m_text.insert(m_cursor, s.left(remaining)); + for (int i = 0; i < (int) s.left(remaining).length(); ++i) + addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1)); + m_textDirty = true; + } + } +} + +/*! + \internal + + deletes a single character from the current text. If \a wasBackspace, + the character prior to the cursor is removed. Otherwise the character + after the cursor is removed. + + Also adds the appropriate commands into the undo history. + This function does not call finishChange(), and may leave the text + in an invalid state. +*/ +void QLineControl::internalDelete(bool wasBackspace) +{ + if (m_cursor < (int) m_text.length()) { + if (hasSelectedText()) + addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); + addCommand(Command((CommandType)((m_maskData ? 2 : 0) + (wasBackspace ? Remove : Delete)), + m_cursor, m_text.at(m_cursor), -1, -1)); + if (m_maskData) { + m_text.replace(m_cursor, 1, clearString(m_cursor, 1)); + addCommand(Command(Insert, m_cursor, m_text.at(m_cursor), -1, -1)); + } else { + m_text.remove(m_cursor, 1); + } + m_textDirty = true; + } +} + +/*! + \internal + + removes the currently selected text from the line control. + + Also adds the appropriate commands into the undo history. + This function does not call finishChange(), and may leave the text + in an invalid state. +*/ +void QLineControl::removeSelectedText() +{ + if (m_selstart < m_selend && m_selend <= (int) m_text.length()) { + separate(); + int i ; + addCommand(Command(SetSelection, m_cursor, 0, m_selstart, m_selend)); + if (m_selstart <= m_cursor && m_cursor < m_selend) { + // cursor is within the selection. Split up the commands + // to be able to restore the correct cursor position + for (i = m_cursor; i >= m_selstart; --i) + addCommand (Command(DeleteSelection, i, m_text.at(i), -1, 1)); + for (i = m_selend - 1; i > m_cursor; --i) + addCommand (Command(DeleteSelection, i - m_cursor + m_selstart - 1, m_text.at(i), -1, -1)); + } else { + for (i = m_selend-1; i >= m_selstart; --i) + addCommand (Command(RemoveSelection, i, m_text.at(i), -1, -1)); + } + if (m_maskData) { + m_text.replace(m_selstart, m_selend - m_selstart, clearString(m_selstart, m_selend - m_selstart)); + for (int i = 0; i < m_selend - m_selstart; ++i) + addCommand(Command(Insert, m_selstart + i, m_text.at(m_selstart + i), -1, -1)); + } else { + m_text.remove(m_selstart, m_selend - m_selstart); + } + if (m_cursor > m_selstart) + m_cursor -= qMin(m_cursor, m_selend) - m_selstart; + internalDeselect(); + m_textDirty = true; + } +} + +/*! + \internal + + Parses the input mask specified by \a maskFields to generate + the mask data used to handle input masks. +*/ +void QLineControl::parseInputMask(const QString &maskFields) +{ + int delimiter = maskFields.indexOf(QLatin1Char(';')); + if (maskFields.isEmpty() || delimiter == 0) { + if (m_maskData) { + delete [] m_maskData; + m_maskData = 0; + m_maxLength = 32767; + internalSetText(QString()); + } + return; + } + + if (delimiter == -1) { + m_blank = QLatin1Char(' '); + m_inputMask = maskFields; + } else { + m_inputMask = maskFields.left(delimiter); + m_blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' '); + } + + // calculate m_maxLength / m_maskData length + m_maxLength = 0; + QChar c = 0; + for (int i=0; i<m_inputMask.length(); i++) { + c = m_inputMask.at(i); + if (i > 0 && m_inputMask.at(i-1) == QLatin1Char('\\')) { + m_maxLength++; + continue; + } + if (c != QLatin1Char('\\') && c != QLatin1Char('!') && + c != QLatin1Char('<') && c != QLatin1Char('>') && + c != QLatin1Char('{') && c != QLatin1Char('}') && + c != QLatin1Char('[') && c != QLatin1Char(']')) + m_maxLength++; + } + + delete [] m_maskData; + m_maskData = new MaskInputData[m_maxLength]; + + MaskInputData::Casemode m = MaskInputData::NoCaseMode; + c = 0; + bool s; + bool escape = false; + int index = 0; + for (int i = 0; i < m_inputMask.length(); i++) { + c = m_inputMask.at(i); + if (escape) { + s = true; + m_maskData[index].maskChar = c; + m_maskData[index].separator = s; + m_maskData[index].caseMode = m; + index++; + escape = false; + } else if (c == QLatin1Char('<')) { + m = MaskInputData::Lower; + } else if (c == QLatin1Char('>')) { + m = MaskInputData::Upper; + } else if (c == QLatin1Char('!')) { + m = MaskInputData::NoCaseMode; + } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) { + switch (c.unicode()) { + case 'A': + case 'a': + case 'N': + case 'n': + case 'X': + case 'x': + case '9': + case '0': + case 'D': + case 'd': + case '#': + case 'H': + case 'h': + case 'B': + case 'b': + s = false; + break; + case '\\': + escape = true; + default: + s = true; + break; + } + + if (!escape) { + m_maskData[index].maskChar = c; + m_maskData[index].separator = s; + m_maskData[index].caseMode = m; + index++; + } + } + } + internalSetText(m_text); +} + + +/*! + \internal + + checks if the key is valid compared to the inputMask +*/ +bool QLineControl::isValidInput(QChar key, QChar mask) const +{ + switch (mask.unicode()) { + case 'A': + if (key.isLetter()) + return true; + break; + case 'a': + if (key.isLetter() || key == m_blank) + return true; + break; + case 'N': + if (key.isLetterOrNumber()) + return true; + break; + case 'n': + if (key.isLetterOrNumber() || key == m_blank) + return true; + break; + case 'X': + if (key.isPrint()) + return true; + break; + case 'x': + if (key.isPrint() || key == m_blank) + return true; + break; + case '9': + if (key.isNumber()) + return true; + break; + case '0': + if (key.isNumber() || key == m_blank) + return true; + break; + case 'D': + if (key.isNumber() && key.digitValue() > 0) + return true; + break; + case 'd': + if ((key.isNumber() && key.digitValue() > 0) || key == m_blank) + return true; + break; + case '#': + if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == m_blank) + return true; + break; + case 'B': + if (key == QLatin1Char('0') || key == QLatin1Char('1')) + return true; + break; + case 'b': + if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == m_blank) + return true; + break; + case 'H': + if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F'))) + return true; + break; + case 'h': + if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == m_blank) + return true; + break; + default: + break; + } + return false; +} + +/*! + \internal + + Returns true if the given text \a str is valid for any + validator or input mask set for the line control. + + Otherwise returns false +*/ +bool QLineControl::hasAcceptableInput(const QString &str) const +{ +#ifndef QT_NO_VALIDATOR + QString textCopy = str; + int cursorCopy = m_cursor; + if (m_validator && m_validator->validate(textCopy, cursorCopy) + != QValidator::Acceptable) + return false; +#endif + + if (!m_maskData) + return true; + + if (str.length() != m_maxLength) + return false; + + for (int i=0; i < m_maxLength; ++i) { + if (m_maskData[i].separator) { + if (str.at(i) != m_maskData[i].maskChar) + return false; + } else { + if (!isValidInput(str.at(i), m_maskData[i].maskChar)) + return false; + } + } + return true; +} + +/*! + \internal + + Applies the inputMask on \a str starting from position \a pos in the mask. \a clear + specifies from where characters should be gotten when a separator is met in \a str - true means + that blanks will be used, false that previous input is used. + Calling this when no inputMask is set is undefined. +*/ +QString QLineControl::maskString(uint pos, const QString &str, bool clear) const +{ + if (pos >= (uint)m_maxLength) + return QString::fromLatin1(""); + + QString fill; + fill = clear ? clearString(0, m_maxLength) : m_text; + + int strIndex = 0; + QString s = QString::fromLatin1(""); + int i = pos; + while (i < m_maxLength) { + if (strIndex < str.length()) { + if (m_maskData[i].separator) { + s += m_maskData[i].maskChar; + if (str[(int)strIndex] == m_maskData[i].maskChar) + strIndex++; + ++i; + } else { + if (isValidInput(str[(int)strIndex], m_maskData[i].maskChar)) { + switch (m_maskData[i].caseMode) { + case MaskInputData::Upper: + s += str[(int)strIndex].toUpper(); + break; + case MaskInputData::Lower: + s += str[(int)strIndex].toLower(); + break; + default: + s += str[(int)strIndex]; + } + ++i; + } else { + // search for separator first + int n = findInMask(i, true, true, str[(int)strIndex]); + if (n != -1) { + if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) { + s += fill.mid(i, n-i+1); + i = n + 1; // update i to find + 1 + } + } else { + // search for valid m_blank if not + n = findInMask(i, true, false, str[(int)strIndex]); + if (n != -1) { + s += fill.mid(i, n-i); + switch (m_maskData[n].caseMode) { + case MaskInputData::Upper: + s += str[(int)strIndex].toUpper(); + break; + case MaskInputData::Lower: + s += str[(int)strIndex].toLower(); + break; + default: + s += str[(int)strIndex]; + } + i = n + 1; // updates i to find + 1 + } + } + } + ++strIndex; + } + } else + break; + } + + return s; +} + + + +/*! + \internal + + Returns a "cleared" string with only separators and blank chars. + Calling this when no inputMask is set is undefined. +*/ +QString QLineControl::clearString(uint pos, uint len) const +{ + if (pos >= (uint)m_maxLength) + return QString(); + + QString s; + int end = qMin((uint)m_maxLength, pos + len); + for (int i = pos; i < end; ++i) + if (m_maskData[i].separator) + s += m_maskData[i].maskChar; + else + s += m_blank; + + return s; +} + +/*! + \internal + + Strips blank parts of the input in a QLineControl when an inputMask is set, + separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1". +*/ +QString QLineControl::stripString(const QString &str) const +{ + if (!m_maskData) + return str; + + QString s; + int end = qMin(m_maxLength, (int)str.length()); + for (int i = 0; i < end; ++i) + if (m_maskData[i].separator) + s += m_maskData[i].maskChar; + else + if (str[i] != m_blank) + s += str[i]; + + return s; +} + +/*! + \internal + searches forward/backward in m_maskData for either a separator or a m_blank +*/ +int QLineControl::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const +{ + if (pos >= m_maxLength || pos < 0) + return -1; + + int end = forward ? m_maxLength : -1; + int step = forward ? 1 : -1; + int i = pos; + + while (i != end) { + if (findSeparator) { + if (m_maskData[i].separator && m_maskData[i].maskChar == searchChar) + return i; + } else { + if (!m_maskData[i].separator) { + if (searchChar.isNull()) + return i; + else if (isValidInput(searchChar, m_maskData[i].maskChar)) + return i; + } + } + i += step; + } + return -1; +} + +void QLineControl::internalUndo(int until) +{ + if (!isUndoAvailable()) + return; + internalDeselect(); + while (m_undoState && m_undoState > until) { + Command& cmd = m_history[--m_undoState]; + switch (cmd.type) { + case Insert: + m_text.remove(cmd.pos, 1); + m_cursor = cmd.pos; + break; + case SetSelection: + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + case Remove: + case RemoveSelection: + m_text.insert(cmd.pos, cmd.uc); + m_cursor = cmd.pos + 1; + break; + case Delete: + case DeleteSelection: + m_text.insert(cmd.pos, cmd.uc); + m_cursor = cmd.pos; + break; + case Separator: + continue; + } + if (until < 0 && m_undoState) { + Command& next = m_history[m_undoState-1]; + if (next.type != cmd.type && next.type < RemoveSelection + && (cmd.type < RemoveSelection || next.type == Separator)) + break; + } + } + m_textDirty = true; + emitCursorPositionChanged(); +} + +void QLineControl::internalRedo() +{ + if (!isRedoAvailable()) + return; + internalDeselect(); + while (m_undoState < (int)m_history.size()) { + Command& cmd = m_history[m_undoState++]; + switch (cmd.type) { + case Insert: + m_text.insert(cmd.pos, cmd.uc); + m_cursor = cmd.pos + 1; + break; + case SetSelection: + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + case Remove: + case Delete: + case RemoveSelection: + case DeleteSelection: + m_text.remove(cmd.pos, 1); + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + case Separator: + m_selstart = cmd.selStart; + m_selend = cmd.selEnd; + m_cursor = cmd.pos; + break; + } + if (m_undoState < (int)m_history.size()) { + Command& next = m_history[m_undoState]; + if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator + && (next.type < RemoveSelection || cmd.type == Separator)) + break; + } + } + m_textDirty = true; + emitCursorPositionChanged(); +} + +/*! + \internal + + If the current cursor position differs from the last emited cursor + position, emits cursorPositionChanged(). +*/ +void QLineControl::emitCursorPositionChanged() +{ + if (m_cursor != m_lastCursorPos) { + const int oldLast = m_lastCursorPos; + m_lastCursorPos = m_cursor; + cursorPositionChanged(oldLast, m_cursor); + } +} + +#ifndef QT_NO_COMPLETER +// iterating forward(dir=1)/backward(dir=-1) from the +// current row based. dir=0 indicates a new completion prefix was set. +bool QLineControl::advanceToEnabledItem(int dir) +{ + int start = m_completer->currentRow(); + if (start == -1) + return false; + int i = start + dir; + if (dir == 0) dir = 1; + do { + if (!m_completer->setCurrentRow(i)) { + if (!m_completer->wrapAround()) + break; + i = i > 0 ? 0 : m_completer->completionCount() - 1; + } else { + QModelIndex currentIndex = m_completer->currentIndex(); + if (m_completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled) + return true; + i += dir; + } + } while (i != start); + + m_completer->setCurrentRow(start); // restore + return false; +} + +void QLineControl::complete(int key) +{ + if (!m_completer || isReadOnly() || echoMode() != QLineEdit::Normal) + return; + + QString text = this->text(); + if (m_completer->completionMode() == QCompleter::InlineCompletion) { + if (key == Qt::Key_Backspace) + return; + int n = 0; + if (key == Qt::Key_Up || key == Qt::Key_Down) { + if (textAfterSelection().length()) + return; + QString prefix = hasSelectedText() ? textBeforeSelection() + : text; + if (text.compare(m_completer->currentCompletion(), m_completer->caseSensitivity()) != 0 + || prefix.compare(m_completer->completionPrefix(), m_completer->caseSensitivity()) != 0) { + m_completer->setCompletionPrefix(prefix); + } else { + n = (key == Qt::Key_Up) ? -1 : +1; + } + } else { + m_completer->setCompletionPrefix(text); + } + if (!advanceToEnabledItem(n)) + return; + } else { +#ifndef QT_KEYPAD_NAVIGATION + if (text.isEmpty()) { + m_completer->popup()->hide(); + return; + } +#endif + m_completer->setCompletionPrefix(text); + } + + m_completer->complete(); +} +#endif + +void QLineControl::setCursorBlinkPeriod(int msec) +{ + if (msec == m_blinkPeriod) + return; + if (m_blinkTimer) { + killTimer(m_blinkTimer); + } + if (msec) { + m_blinkTimer = startTimer(msec / 2); + m_blinkStatus = 1; + } else { + m_blinkTimer = 0; + if (m_blinkStatus == 0) + emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect()); + } + m_blinkPeriod = msec; +} + +void QLineControl::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == m_blinkTimer) { + m_blinkStatus = !m_blinkStatus; + emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect()); + } else if (event->timerId() == m_deleteAllTimer) { + killTimer(m_deleteAllTimer); + m_deleteAllTimer = 0; + clear(); + } else if (event->timerId() == m_tripleClickTimer) { + killTimer(m_tripleClickTimer); + m_tripleClickTimer = 0; + } +} + +bool QLineControl::processEvent(QEvent* ev) +{ +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) { + if ((ev->type() == QEvent::KeyPress) || (ev->type() == QEvent::KeyRelease)) { + QKeyEvent *ke = (QKeyEvent *)ev; + if (ke->key() == Qt::Key_Back) { + if (ke->isAutoRepeat()) { + // Swallow it. We don't want back keys running amok. + ke->accept(); + return true; + } + if ((ev->type() == QEvent::KeyRelease) + && !isReadOnly() + && deleteAllTimer) { + killTimer(m_deleteAllTimer); + m_deleteAllTimer = 0; + backspace(); + ke->accept(); + return true; + } + } + } + } +#endif + switch(ev->type()){ +#ifndef QT_NO_GRAPHICSVIEW + case QEvent::GraphicsSceneMouseMove: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMousePress:{ + QGraphicsSceneMouseEvent *gvEv = static_cast<QGraphicsSceneMouseEvent*>(ev); + QMouseEvent* mouse = new QMouseEvent(ev->type(), + gvEv->pos().toPoint(), gvEv->button(), gvEv->buttons(), gvEv->modifiers()); + processMouseEvent(mouse); break; + } +#endif + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + processMouseEvent(static_cast<QMouseEvent*>(ev)); break; + case QEvent::KeyPress: + case QEvent::KeyRelease: + processKeyEvent(static_cast<QKeyEvent*>(ev)); break; + case QEvent::InputMethod: + processInputMethodEvent(static_cast<QInputMethodEvent*>(ev)); break; +#ifndef QT_NO_SHORTCUT + case QEvent::ShortcutOverride:{ + QKeyEvent* ke = static_cast<QKeyEvent*>(ev); + if (ke == QKeySequence::Copy + || ke == QKeySequence::Paste + || ke == QKeySequence::Cut + || ke == QKeySequence::Redo + || ke == QKeySequence::Undo + || ke == QKeySequence::MoveToNextWord + || ke == QKeySequence::MoveToPreviousWord + || ke == QKeySequence::MoveToStartOfDocument + || ke == QKeySequence::MoveToEndOfDocument + || ke == QKeySequence::SelectNextWord + || ke == QKeySequence::SelectPreviousWord + || ke == QKeySequence::SelectStartOfLine + || ke == QKeySequence::SelectEndOfLine + || ke == QKeySequence::SelectStartOfBlock + || ke == QKeySequence::SelectEndOfBlock + || ke == QKeySequence::SelectStartOfDocument + || ke == QKeySequence::SelectAll + || ke == QKeySequence::SelectEndOfDocument) { + ke->accept(); + } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier + || ke->modifiers() == Qt::KeypadModifier) { + if (ke->key() < Qt::Key_Escape) { + ke->accept(); + } else { + switch (ke->key()) { + case Qt::Key_Delete: + case Qt::Key_Home: + case Qt::Key_End: + case Qt::Key_Backspace: + case Qt::Key_Left: + case Qt::Key_Right: + ke->accept(); + default: + break; + } + } + } + } +#endif + default: + return false; + } + return true; +} + +void QLineControl::processMouseEvent(QMouseEvent* ev) +{ + + switch (ev->type()) { + case QEvent::GraphicsSceneMousePress: + case QEvent::MouseButtonPress:{ + if (m_tripleClickTimer + && (ev->pos() - m_tripleClick).manhattanLength() + < QApplication::startDragDistance()) { + selectAll(); + return; + } + if (ev->button() == Qt::RightButton) + return; + + bool mark = ev->modifiers() & Qt::ShiftModifier; + int cursor = xToPos(ev->pos().x()); + moveCursor(cursor, mark); + break; + } + case QEvent::MouseButtonDblClick: + if (ev->button() == Qt::LeftButton) { + selectWordAtPos(xToPos(ev->pos().x())); + if (m_tripleClickTimer) + killTimer(m_tripleClickTimer); + m_tripleClickTimer = startTimer(QApplication::doubleClickInterval()); + m_tripleClick = ev->pos(); + } + break; + case QEvent::GraphicsSceneMouseRelease: + case QEvent::MouseButtonRelease: +#ifndef QT_NO_CLIPBOARD + if (QApplication::clipboard()->supportsSelection()) { + if (ev->button() == Qt::LeftButton) { + copy(QClipboard::Selection); + } else if (!isReadOnly() && ev->button() == Qt::MidButton) { + deselect(); + insert(QApplication::clipboard()->text(QClipboard::Selection)); + } + } +#endif + break; + case QEvent::GraphicsSceneMouseMove: + case QEvent::MouseMove: + if (ev->buttons() & Qt::LeftButton) { + moveCursor(xToPos(ev->pos().x()), true); + } + break; + default: + break; + } +} + +void QLineControl::processKeyEvent(QKeyEvent* event) +{ + bool inlineCompletionAccepted = false; + +#ifndef QT_NO_COMPLETER + if (m_completer) { + QCompleter::CompletionMode completionMode = m_completer->completionMode(); + if ((completionMode == QCompleter::PopupCompletion + || completionMode == QCompleter::UnfilteredPopupCompletion) + && m_completer->popup() + && m_completer->popup()->isVisible()) { + // The following keys are forwarded by the completer to the widget + // Ignoring the events lets the completer provide suitable default behavior + switch (event->key()) { + case Qt::Key_Escape: + event->ignore(); + return; + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_F4: +#ifdef QT_KEYPAD_NAVIGATION + case Qt::Key_Select: + if (!QApplication::keypadNavigationEnabled()) + break; +#endif + m_completer->popup()->hide(); // just hide. will end up propagating to parent + default: + break; // normal key processing + } + } else if (completionMode == QCompleter::InlineCompletion) { + switch (event->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_F4: +#ifdef QT_KEYPAD_NAVIGATION + case Qt::Key_Select: + if (!QApplication::keypadNavigationEnabled()) + break; +#endif + if (!m_completer->currentCompletion().isEmpty() && hasSelectedText() + && textAfterSelection().isEmpty()) { + setText(m_completer->currentCompletion()); + inlineCompletionAccepted = true; + } + default: + break; // normal key processing + } + } + } +#endif // QT_NO_COMPLETER + + if (echoMode() == QLineEdit::PasswordEchoOnEdit + && !passwordEchoEditing() + && !isReadOnly() + && !event->text().isEmpty() +#ifdef QT_KEYPAD_NAVIGATION + && event->key() != Qt::Key_Select + && event->key() != Qt::Key_Up + && event->key() != Qt::Key_Down + && event->key() != Qt::Key_Back +#endif + && !(event->modifiers() & Qt::ControlModifier)) { + // Clear the edit and reset to normal echo mode while editing; the + // echo mode switches back when the edit loses focus + // ### resets current content. dubious code; you can + // navigate with keys up, down, back, and select(?), but if you press + // "left" or "right" it clears? + updatePasswordEchoEditing(true); + clear(); + } + + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { + if (hasAcceptableInput() || fixup()) { + emit accepted(); + emit editingFinished(); + } + if (inlineCompletionAccepted) + event->accept(); + else + event->ignore(); + return; + } + bool unknown = false; + + if (false) { + } +#ifndef QT_NO_SHORTCUT + else if (event == QKeySequence::Undo) { + if (!isReadOnly()) + undo(); + } + else if (event == QKeySequence::Redo) { + if (!isReadOnly()) + redo(); + } + else if (event == QKeySequence::SelectAll) { + selectAll(); + } +#ifndef QT_NO_CLIPBOARD + else if (event == QKeySequence::Copy) { + copy(); + } + else if (event == QKeySequence::Paste) { + if (!isReadOnly()) + paste(); + } + else if (event == QKeySequence::Cut) { + if (!isReadOnly()) { + copy(); + del(); + } + } + else if (event == QKeySequence::DeleteEndOfLine) { + if (!isReadOnly()) { + setSelection(cursor(), end()); + copy(); + del(); + } + } +#endif //QT_NO_CLIPBOARD + else if (event == QKeySequence::MoveToStartOfLine) { + home(0); + } + else if (event == QKeySequence::MoveToEndOfLine) { + end(0); + } + else if (event == QKeySequence::SelectStartOfLine) { + home(1); + } + else if (event == QKeySequence::SelectEndOfLine) { + end(1); + } + else if (event == QKeySequence::MoveToNextChar) { +#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) + if (hasSelectedText()) { +#else + if (hasSelectedText() && m_completer + && m_completer->completionMode() == QCompleter::InlineCompletion) { +#endif + moveCursor(selectionEnd(), false); + } else { + cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); + } + } + else if (event == QKeySequence::SelectNextChar) { + cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); + } + else if (event == QKeySequence::MoveToPreviousChar) { +#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) + if (hasSelectedText()) { +#else + if (hasSelectedText() && m_completer + && m_completer->completionMode() == QCompleter::InlineCompletion) { +#endif + moveCursor(selectionStart(), false); + } else { + cursorForward(0, layoutDirection() == Qt::LeftToRight ? -1 : 1); + } + } + else if (event == QKeySequence::SelectPreviousChar) { + cursorForward(1, layoutDirection() == Qt::LeftToRight ? -1 : 1); + } + else if (event == QKeySequence::MoveToNextWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0); + else + layoutDirection() == Qt::LeftToRight ? end(0) : home(0); + } + else if (event == QKeySequence::MoveToPreviousWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0); + else if (!isReadOnly()) { + layoutDirection() == Qt::LeftToRight ? home(0) : end(0); + } + } + else if (event == QKeySequence::SelectNextWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1); + else + layoutDirection() == Qt::LeftToRight ? end(1) : home(1); + } + else if (event == QKeySequence::SelectPreviousWord) { + if (echoMode() == QLineEdit::Normal) + layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1); + else + layoutDirection() == Qt::LeftToRight ? home(1) : end(1); + } + else if (event == QKeySequence::Delete) { + if (!isReadOnly()) + del(); + } + else if (event == QKeySequence::DeleteEndOfWord) { + if (!isReadOnly()) { + cursorWordForward(true); + del(); + } + } + else if (event == QKeySequence::DeleteStartOfWord) { + if (!isReadOnly()) { + cursorWordBackward(true); + del(); + } + } +#endif // QT_NO_SHORTCUT + else { +#ifdef Q_WS_MAC + if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) { + Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier); + if (myModifiers & Qt::ShiftModifier) { + if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier) + || myModifiers == (Qt::AltModifier|Qt::ShiftModifier) + || myModifiers == Qt::ShiftModifier) { + + event->key() == Qt::Key_Up ? home(1) : end(1); + } + } else { + if ((myModifiers == Qt::ControlModifier + || myModifiers == Qt::AltModifier + || myModifiers == Qt::NoModifier)) { + event->key() == Qt::Key_Up ? home(0) : end(0); + } + } + } +#endif + if (event->modifiers() & Qt::ControlModifier) { + switch (event->key()) { + case Qt::Key_Backspace: + if (!isReadOnly()) { + cursorWordBackward(true); + del(); + } + break; +#ifndef QT_NO_COMPLETER + case Qt::Key_Up: + case Qt::Key_Down: + complete(event->key()); + break; +#endif +#if defined(Q_WS_X11) + case Qt::Key_E: + end(0); + break; + + case Qt::Key_U: + if (!isReadOnly()) { + setSelection(0, text().size()); +#ifndef QT_NO_CLIPBOARD + copy(); +#endif + del(); + } + break; +#endif + default: + unknown = true; + } + } else { // ### check for *no* modifier + switch (event->key()) { + case Qt::Key_Backspace: + if (!isReadOnly()) { + backspace(); +#ifndef QT_NO_COMPLETER + complete(Qt::Key_Backspace); +#endif + } + break; +#ifdef QT_KEYPAD_NAVIGATION + case Qt::Key_Back: + if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat() + && !isReadOnly()) { + if (text().length() == 0) { + setText(m_cancelText); + + if (passwordEchoEditing) + updatePasswordEchoEditing(false); + + setEditFocus(false); + } else if (!deleteAllTimer) { + deleteAllTimer = startTimer(750); + } + } else { + unknown = true; + } + break; +#endif + + default: + unknown = true; + } + } + } + + if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) { + setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft); + unknown = false; + } + + if (unknown && !isReadOnly()) { + QString t = event->text(); + if (!t.isEmpty() && t.at(0).isPrint() && + ((event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) == Qt::NoModifier)) { + insert(t); +#ifndef QT_NO_COMPLETER + complete(event->key()); +#endif + event->accept(); + return; + } + } + + if (unknown) + event->ignore(); + else + event->accept(); +} + + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h new file mode 100644 index 0000000..1e5c144 --- /dev/null +++ b/src/gui/widgets/qlinecontrol_p.h @@ -0,0 +1,741 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLINECONTROL_P_H +#define QLINECONTROL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qglobal.h" + +#ifndef QT_NO_LINEEDIT +#include "private/qwidget_p.h" +#include "QtGui/qlineedit.h" +#include "QtGui/qtextlayout.h" +#include "QtGui/qstyleoption.h" +#include "QtCore/qpointer.h" +#include "QtGui/qlineedit.h" +#include "QtGui/qclipboard.h" +#include "QtCore/qpoint.h" +#include "QtGui/qcompleter.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class Q_GUI_EXPORT QLineControl : public QObject +{ + Q_OBJECT + +public: + QLineControl(const QString &txt = QString()) + : m_cursor(0), m_preeditCursor(0), m_layoutDirection(Qt::LeftToRight), + m_hideCursor(false), m_separator(0), m_readOnly(0), + m_dragEnabled(0), m_echoMode(0), m_textDirty(0), m_selDirty(0), + m_validInput(1), m_blinkPeriod(0), m_blinkTimer(0), m_deleteAllTimer(0), + m_ascent(0), m_maxLength(32767), m_lastCursorPos(-1), + m_tripleClickTimer(0), m_maskData(0), m_modifiedState(0), m_undoState(0), + m_selstart(0), m_selend(0), m_passwordEchoEditing(false) + { + init(txt); + } + + ~QLineControl() + { + delete [] m_maskData; + } + + int nextMaskBlank(int pos); + int prevMaskBlank(int pos); + + bool isUndoAvailable() const; + bool isRedoAvailable() const; + void clearUndo(); + bool isModified() const; + void setModified(bool modified); + + bool allSelected() const; + bool hasSelectedText() const; + + int width() const; + int height() const; + int ascent() const; + + void setSelection(int start, int length); + + QString selectedText() const; + QString textBeforeSelection() const; + QString textAfterSelection() const; + + int selectionStart() const; + int selectionEnd() const; + bool inSelection(int x) const; + + void removeSelection(); + + int start() const; + int end() const; + +#ifndef QT_NO_CLIPBOARD + void copy(QClipboard::Mode mode = QClipboard::Clipboard) const; + void paste(); +#endif + + int cursor() const; + int preeditCursor() const; + + int cursorWidth() const; + void setCursorWidth(int value); + + void moveCursor(int pos, bool mark = false); + void cursorForward(bool mark, int steps); + void cursorWordForward(bool mark); + void cursorWordBackward(bool mark); + void home(bool mark); + void end(bool mark); + + int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; + QRect cursorRect() const; + + qreal cursorToX(int cursor) const; + qreal cursorToX() const; + + bool isReadOnly() const; + void setReadOnly(bool enable); + + QString text() const; + void setText(const QString &txt); + + QString displayText() const; + + void backspace(); + void del(); + void deselect(); + void selectAll(); + void insert(const QString &); + void clear(); + void undo(); + void redo(); + void selectWordAtPos(int); + + uint echoMode() const; + void setEchoMode(uint mode); + + void setMaxLength(int maxLength); + int maxLength() const; + + const QValidator *validator() const; + void setValidator(const QValidator *); + +#ifndef QT_NO_COMPLETER + QCompleter *completer() const; + void setCompleter(const QCompleter*); + void complete(int key); +#endif + + void setCursorPosition(int pos); + int cursorPosition() const; + + bool hasAcceptableInput() const; + bool fixup(); + + QString inputMask() const; + void setInputMask(const QString &mask); + + // input methods +#ifndef QT_NO_IM + bool composeMode() const; + void setPreeditArea(int cursor, const QString &text); +#endif + + QString preeditAreaText() const; + + void updatePasswordEchoEditing(bool editing); + bool passwordEchoEditing() const; + + QChar passwordCharacter() const; + void setPasswordCharacter(const QChar &character); + + Qt::LayoutDirection layoutDirection() const; + void setLayoutDirection(Qt::LayoutDirection direction); + void setFont(const QFont &font); + + void processInputMethodEvent(QInputMethodEvent *event); + void processMouseEvent(QMouseEvent* ev); + void processKeyEvent(QKeyEvent* ev); + + int cursorBlinkPeriod() const; + void setCursorBlinkPeriod(int msec); + + QString cancelText() const; + void setCancelText(const QString &text); + + enum DrawFlags { + DrawText = 0x01, + DrawSelections = 0x02, + DrawCursor = 0x04, + DrawAll = DrawText | DrawSelections | DrawCursor + }; + void draw(QPainter *, const QPoint &, const QRect &, int flags = DrawAll); + + bool processEvent(QEvent *ev); + +private: + void init(const QString &txt); + void removeSelectedText(); + void internalSetText(const QString &txt, int pos = -1, bool edited = true); + void updateDisplayText(); + + void internalInsert(const QString &s); + void internalDelete(bool wasBackspace = false); + void internalRemove(int pos); + + inline void internalDeselect() + { + m_selDirty |= (m_selend > m_selstart); + m_selstart = m_selend = 0; + } + + void internalUndo(int until = -1); + void internalRedo(); + + QString m_text; + QPalette m_palette; + int m_cursor; + int m_preeditCursor; + int m_cursorWidth; + Qt::LayoutDirection m_layoutDirection; + uint m_hideCursor : 1; // used to hide the m_cursor inside preedit areas + uint m_separator : 1; + uint m_readOnly : 1; + uint m_dragEnabled : 1; + uint m_echoMode : 2; + uint m_textDirty : 1; + uint m_selDirty : 1; + uint m_validInput : 1; + int m_blinkPeriod; // 0 for non-blinking cursor + int m_blinkTimer; + int m_deleteAllTimer; + int m_blinkStatus; + int m_ascent; + int m_maxLength; + int m_lastCursorPos; + QList<int> m_transactions; + QPoint m_tripleClick; + int m_tripleClickTimer; + QString m_cancelText; + + void emitCursorPositionChanged(); + + bool finishChange(int validateFromState = -1, bool update = false, bool edited = true); + + QPointer<QValidator> m_validator; + QPointer<QCompleter> m_completer; +#ifndef QT_NO_COMPLETER + bool advanceToEnabledItem(int dir); +#endif + + struct MaskInputData { + enum Casemode { NoCaseMode, Upper, Lower }; + QChar maskChar; // either the separator char or the inputmask + bool separator; + Casemode caseMode; + }; + QString m_inputMask; + QChar m_blank; + MaskInputData *m_maskData; + + // undo/redo handling + enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection }; + struct Command { + inline Command() {} + inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {} + uint type : 4; + QChar uc; + int pos, selStart, selEnd; + }; + int m_modifiedState; + int m_undoState; + QVector<Command> m_history; + void addCommand(const Command& cmd); + + inline void separate() { m_separator = true; } + + // selection + int m_selstart; + int m_selend; + + // masking + void parseInputMask(const QString &maskFields); + bool isValidInput(QChar key, QChar mask) const; + bool hasAcceptableInput(const QString &text) const; + QString maskString(uint pos, const QString &str, bool clear = false) const; + QString clearString(uint pos, uint len) const; + QString stripString(const QString &str) const; + int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const; + + // complex text layout + QTextLayout m_textLayout; + + bool m_passwordEchoEditing; + QChar m_passwordCharacter; + +Q_SIGNALS: + void cursorPositionChanged(int, int); + void selectionChanged(); + + void displayTextChanged(const QString &); + void textChanged(const QString &); + void textEdited(const QString &); + + void resetInputContext(); + + void accepted(); + void editingFinished(); + void updateNeeded(const QRect &); + +protected: + virtual void timerEvent(QTimerEvent *event); + +private slots: + void _q_clipboardChanged(); + void _q_deleteSelected(); + +}; + +inline int QLineControl::nextMaskBlank(int pos) +{ + int c = findInMask(pos, true, false); + m_separator |= (c != pos); + return (c != -1 ? c : m_maxLength); +} + +inline int QLineControl::prevMaskBlank(int pos) +{ + int c = findInMask(pos, false, false); + m_separator |= (c != pos); + return (c != -1 ? c : 0); +} + +inline bool QLineControl::isUndoAvailable() const +{ + return !m_readOnly && m_undoState; +} + +inline bool QLineControl::isRedoAvailable() const +{ + return !m_readOnly && m_undoState < (int)m_history.size(); +} + +inline void QLineControl::clearUndo() +{ + m_history.clear(); + m_modifiedState = m_undoState = 0; +} + +inline bool QLineControl::isModified() const +{ + return m_modifiedState != m_undoState; +} + +inline void QLineControl::setModified(bool modified) +{ + m_modifiedState = modified ? -1 : m_undoState; +} + +inline bool QLineControl::allSelected() const +{ + return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); +} + +inline bool QLineControl::hasSelectedText() const +{ + return !m_text.isEmpty() && m_selend > m_selstart; +} + +inline int QLineControl::width() const +{ + return qRound(m_textLayout.lineAt(0).width()) + 1; +} + +inline int QLineControl::height() const +{ + return qRound(m_textLayout.lineAt(0).height()) + 1; +} + +inline int QLineControl::ascent() const +{ + return m_ascent; +} + +inline QString QLineControl::selectedText() const +{ + if (hasSelectedText()) + return m_text.mid(m_selstart, m_selend - m_selstart); + return QString(); +} + +inline QString QLineControl::textBeforeSelection() const +{ + if (hasSelectedText()) + return m_text.left(m_selstart); + return QString(); +} + +inline QString QLineControl::textAfterSelection() const +{ + if (hasSelectedText()) + return m_text.mid(m_selend); + return QString(); +} + +inline int QLineControl::selectionStart() const +{ + return hasSelectedText() ? m_selstart : -1; +} + +inline int QLineControl::selectionEnd() const +{ + return hasSelectedText() ? m_selend : -1; +} + +inline int QLineControl::start() const +{ + return 0; +} + +inline int QLineControl::end() const +{ + return m_text.length(); +} + +inline void QLineControl::removeSelection() +{ + int priorState = m_undoState; + removeSelectedText(); + finishChange(priorState); +} + +inline bool QLineControl::inSelection(int x) const +{ + if (m_selstart >= m_selend) + return false; + int pos = xToPos(x, QTextLine::CursorOnCharacter); + return pos >= m_selstart && pos < m_selend; +} + +inline int QLineControl::cursor() const +{ + return m_cursor; +} + +inline int QLineControl::preeditCursor() const +{ + return m_preeditCursor; +} + +inline int QLineControl::cursorWidth() const +{ + return m_cursorWidth; +} + +inline void QLineControl::setCursorWidth(int value) +{ + m_cursorWidth = value; +} + +inline void QLineControl::cursorForward(bool mark, int steps) +{ + int c = m_cursor; + if (steps > 0) { + while (steps--) + c = m_textLayout.nextCursorPosition(c); + } else if (steps < 0) { + while (steps++) + c = m_textLayout.previousCursorPosition(c); + } + moveCursor(c, mark); +} + +inline void QLineControl::cursorWordForward(bool mark) +{ + moveCursor(m_textLayout.nextCursorPosition(m_cursor, QTextLayout::SkipWords), mark); +} + +inline void QLineControl::home(bool mark) +{ + moveCursor(0, mark); +} + +inline void QLineControl::end(bool mark) +{ + moveCursor(text().length(), mark); +} + +inline void QLineControl::cursorWordBackward(bool mark) +{ + moveCursor(m_textLayout.previousCursorPosition(m_cursor, QTextLayout::SkipWords), mark); +} + +inline qreal QLineControl::cursorToX(int cursor) const +{ + return m_textLayout.lineAt(0).cursorToX(cursor); +} + +inline qreal QLineControl::cursorToX() const +{ + return cursorToX(m_cursor); +} + +inline bool QLineControl::isReadOnly() const +{ + return m_readOnly; +} + +inline void QLineControl::setReadOnly(bool enable) +{ + m_readOnly = enable; +} + +inline QString QLineControl::text() const +{ + QString res = m_maskData ? stripString(m_text) : m_text; + return (res.isNull() ? QString::fromLatin1("") : res); +} + +inline void QLineControl::setText(const QString &txt) +{ + internalSetText(txt, -1, false); +} + +inline QString QLineControl::displayText() const +{ + return m_textLayout.text(); +} + +inline void QLineControl::deselect() +{ + internalDeselect(); + finishChange(); +} + +inline void QLineControl::selectAll() +{ + m_selstart = m_selend = m_cursor = 0; + moveCursor(m_text.length(), true); +} + +inline void QLineControl::undo() +{ + internalUndo(); + finishChange(-1, true); +} + +inline void QLineControl::redo() +{ + internalRedo(); + finishChange(); +} + +inline uint QLineControl::echoMode() const +{ + return m_echoMode; +} + +inline void QLineControl::setEchoMode(uint mode) +{ + m_echoMode = mode; + m_passwordEchoEditing = false; + updateDisplayText(); +} + +inline void QLineControl::setMaxLength(int maxLength) +{ + if (m_maskData) + return; + m_maxLength = maxLength; + setText(m_text); +} + +inline int QLineControl::maxLength() const +{ + return m_maxLength; +} + +inline const QValidator *QLineControl::validator() const +{ + return m_validator; +} + +inline void QLineControl::setValidator(const QValidator *v) +{ + m_validator = const_cast<QValidator*>(v); +} + +#ifndef QT_NO_COMPLETER +inline QCompleter *QLineControl::completer() const +{ + return m_completer; +} + +/* Note that you must set the widget for the completer seperately */ +inline void QLineControl::setCompleter(const QCompleter* c) +{ + m_completer = const_cast<QCompleter*>(c); +} +#endif + +inline void QLineControl::setCursorPosition(int pos) +{ + if (pos < 0) + pos = 0; + if (pos < m_text.length()) + moveCursor(pos); +} + +inline int QLineControl::cursorPosition() const +{ + return m_cursor; +} + +inline bool QLineControl::hasAcceptableInput() const +{ + return hasAcceptableInput(m_text); +} + +inline QString QLineControl::inputMask() const +{ + return m_maskData ? m_inputMask + QLatin1Char(';') + m_blank : QString(); +} + +inline void QLineControl::setInputMask(const QString &mask) +{ + parseInputMask(mask); + if (m_maskData) + moveCursor(nextMaskBlank(0)); +} + +// input methods +#ifndef QT_NO_IM +inline bool QLineControl::composeMode() const +{ + return !m_textLayout.preeditAreaText().isEmpty(); +} + +inline void QLineControl::setPreeditArea(int cursor, const QString &text) +{ + m_textLayout.setPreeditArea(cursor, text); +} +#endif + +inline QString QLineControl::preeditAreaText() const +{ + return m_textLayout.preeditAreaText(); +} + +inline bool QLineControl::passwordEchoEditing() const +{ + return m_passwordEchoEditing; +} + +inline QChar QLineControl::passwordCharacter() const +{ + return m_passwordCharacter; +} + +inline void QLineControl::setPasswordCharacter(const QChar &character) +{ + m_passwordCharacter = character; + updateDisplayText(); +} + +inline Qt::LayoutDirection QLineControl::layoutDirection() const +{ + return m_layoutDirection; +} + +inline void QLineControl::setLayoutDirection(Qt::LayoutDirection direction) +{ + if (direction != m_layoutDirection) { + m_layoutDirection = direction; + updateDisplayText(); + } +} + +inline void QLineControl::setFont(const QFont &font) +{ + m_textLayout.setFont(font); + updateDisplayText(); +} + +inline int QLineControl::cursorBlinkPeriod() const +{ + return m_blinkPeriod; +} + +inline QString QLineControl::cancelText() const +{ + return m_cancelText; +} + +inline void QLineControl::setCancelText(const QString &text) +{ + m_cancelText = text; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_LINEEDIT + +#endif // QLINECONTROL_P_H diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index d1067a8..e0f5bc9 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -86,21 +86,12 @@ #include <limits.h> -#define verticalMargin 1 -#define horizontalMargin 2 - QT_BEGIN_NAMESPACE #ifdef Q_WS_MAC extern void qt_mac_secure_keyboard(bool); //qapplication_mac.cpp #endif -static inline bool shouldEnableInputMethod(QLineEdit *lineedit) -{ - const QLineEdit::EchoMode mode = lineedit->echoMode(); - return !lineedit->isReadOnly() && (mode == QLineEdit::Normal || mode == QLineEdit::PasswordEchoOnEdit); -} - /*! Initialize \a option with the values from this QLineEdit. This method is useful for subclasses when they need a QStyleOptionFrame or QStyleOptionFrameV2, but don't want @@ -122,7 +113,7 @@ void QLineEdit::initStyleOption(QStyleOptionFrame *option) const : 0; option->midLineWidth = 0; option->state |= QStyle::State_Sunken; - if (d->readOnly) + if (d->control->isReadOnly()) option->state |= QStyle::State_ReadOnly; #ifdef QT_KEYPAD_NAVIGATION if (hasEditFocus()) @@ -350,14 +341,9 @@ QLineEdit::QLineEdit(const QString& contents, const QString &inputMask, QWidget* { Q_D(QLineEdit); setObjectName(QString::fromAscii(name)); - d->parseInputMask(inputMask); - if (d->maskData) { - QString ms = d->maskString(0, contents); - d->init(ms + d->clearString(ms.length(), d->maxLength - ms.length())); - d->cursor = d->nextMaskBlank(ms.length()); - } else { - d->init(contents); - } + d->init(contents); + d->control->setInputMask(inputMask); + d->control->moveCursor(d->control->nextMaskBlank(contents.length())); } #endif @@ -388,19 +374,13 @@ QLineEdit::~QLineEdit() QString QLineEdit::text() const { Q_D(const QLineEdit); - QString res = d->text; - if (d->maskData) - res = d->stripString(d->text); - return (res.isNull() ? QString::fromLatin1("") : res); + return d->control->text(); } void QLineEdit::setText(const QString& text) { Q_D(QLineEdit); - d->setText(text, -1, false); -#ifdef QT_KEYPAD_NAVIGATION - d->origText = d->text; -#endif + d->control->setText(text); } @@ -421,17 +401,7 @@ void QLineEdit::setText(const QString& text) QString QLineEdit::displayText() const { Q_D(const QLineEdit); - if (d->echoMode == NoEcho) - return QString::fromLatin1(""); - QString res = d->text; - - if (d->echoMode == Password || (d->echoMode == PasswordEchoOnEdit - && !d->passwordEchoEditing)) { - QStyleOptionFrameV2 opt; - initStyleOption(&opt); - res.fill(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, this)); - } - return (res.isNull() ? QString::fromLatin1("") : res); + return d->control->displayText(); } @@ -456,20 +426,15 @@ QString QLineEdit::displayText() const int QLineEdit::maxLength() const { Q_D(const QLineEdit); - return d->maxLength; + return d->control->maxLength(); } void QLineEdit::setMaxLength(int maxLength) { Q_D(QLineEdit); - if (d->maskData) - return; - d->maxLength = maxLength; - setText(d->text); + d->control->setMaxLength(maxLength); } - - /*! \property QLineEdit::frame \brief whether the line edit draws itself with a frame @@ -536,22 +501,20 @@ void QLineEdit::setFrame(bool enable) QLineEdit::EchoMode QLineEdit::echoMode() const { Q_D(const QLineEdit); - return (EchoMode) d->echoMode; + return (EchoMode) d->control->echoMode(); } void QLineEdit::setEchoMode(EchoMode mode) { Q_D(QLineEdit); - if (mode == (EchoMode)d->echoMode) + if (mode == (EchoMode)d->control->echoMode()) return; - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); - d->echoMode = mode; - d->passwordEchoEditing = false; - d->updateTextLayout(); + setAttribute(Qt::WA_InputMethodEnabled, d->shouldEnableInputMethod()); + d->control->setEchoMode(mode); update(); #ifdef Q_WS_MAC if (hasFocus()) - qt_mac_secure_keyboard(d->echoMode == Password || d->echoMode == NoEcho); + qt_mac_secure_keyboard(mode == Password || mode == NoEcho); #endif } @@ -567,7 +530,7 @@ void QLineEdit::setEchoMode(EchoMode mode) const QValidator * QLineEdit::validator() const { Q_D(const QLineEdit); - return d->validator; + return d->control->validator(); } /*! @@ -585,7 +548,7 @@ const QValidator * QLineEdit::validator() const void QLineEdit::setValidator(const QValidator *v) { Q_D(QLineEdit); - d->validator = const_cast<QValidator*>(v); + d->control->setValidator(v); } #endif // QT_NO_VALIDATOR @@ -609,23 +572,23 @@ void QLineEdit::setValidator(const QValidator *v) void QLineEdit::setCompleter(QCompleter *c) { Q_D(QLineEdit); - if (c == d->completer) + if (c == d->control->completer()) return; - if (d->completer) { - disconnect(d->completer, 0, this, 0); - d->completer->setWidget(0); - if (d->completer->parent() == this) - delete d->completer; + if (d->control->completer()) { + disconnect(d->control->completer(), 0, this, 0); + d->control->completer()->setWidget(0); + if (d->control->completer()->parent() == this) + delete d->control->completer(); } - d->completer = c; + d->control->setCompleter(c); if (!c) return; if (c->widget() == 0) c->setWidget(this); if (hasFocus()) { - QObject::connect(d->completer, SIGNAL(activated(QString)), + QObject::connect(d->control->completer(), SIGNAL(activated(QString)), this, SLOT(setText(QString))); - QObject::connect(d->completer, SIGNAL(highlighted(QString)), + QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)), this, SLOT(_q_completionHighlighted(QString))); } } @@ -638,83 +601,9 @@ void QLineEdit::setCompleter(QCompleter *c) QCompleter *QLineEdit::completer() const { Q_D(const QLineEdit); - return d->completer; -} - -// looks for an enabled item iterating forward(dir=1)/backward(dir=-1) from the -// current row based. dir=0 indicates a new completion prefix was set. -bool QLineEditPrivate::advanceToEnabledItem(int dir) -{ - int start = completer->currentRow(); - if (start == -1) - return false; - int i = start + dir; - if (dir == 0) dir = 1; - do { - if (!completer->setCurrentRow(i)) { - if (!completer->wrapAround()) - break; - i = i > 0 ? 0 : completer->completionCount() - 1; - } else { - QModelIndex currentIndex = completer->currentIndex(); - if (completer->completionModel()->flags(currentIndex) & Qt::ItemIsEnabled) - return true; - i += dir; - } - } while (i != start); - - completer->setCurrentRow(start); // restore - return false; -} - -void QLineEditPrivate::complete(int key) -{ - if (!completer || readOnly || echoMode != QLineEdit::Normal) - return; - - if (completer->completionMode() == QCompleter::InlineCompletion) { - if (key == Qt::Key_Backspace) - return; - int n = 0; - if (key == Qt::Key_Up || key == Qt::Key_Down) { - if (selend != 0 && selend != text.length()) - return; - QString prefix = hasSelectedText() ? text.left(selstart) : text; - if (text.compare(completer->currentCompletion(), completer->caseSensitivity()) != 0 - || prefix.compare(completer->completionPrefix(), completer->caseSensitivity()) != 0) { - completer->setCompletionPrefix(prefix); - } else { - n = (key == Qt::Key_Up) ? -1 : +1; - } - } else { - completer->setCompletionPrefix(text); - } - if (!advanceToEnabledItem(n)) - return; - } else { -#ifndef QT_KEYPAD_NAVIGATION - if (text.isEmpty()) { - completer->popup()->hide(); - return; - } -#endif - completer->setCompletionPrefix(text); - } - - completer->complete(); + return d->control->completer(); } -void QLineEditPrivate::_q_completionHighlighted(QString newText) -{ - Q_Q(QLineEdit); - if (completer->completionMode() != QCompleter::InlineCompletion) - q->setText(newText); - else { - int c = cursor; - q->setText(text.left(c) + newText.mid(c)); - q->setSelection(text.length(), c - newText.length()); - } -} #endif // QT_NO_COMPLETER /*! @@ -729,10 +618,10 @@ QSize QLineEdit::sizeHint() const Q_D(const QLineEdit); ensurePolished(); QFontMetrics fm(font()); - int h = qMax(fm.lineSpacing(), 14) + 2*verticalMargin + int h = qMax(fm.lineSpacing(), 14) + 2*d->verticalMargin + d->topTextMargin + d->bottomTextMargin + d->topmargin + d->bottommargin; - int w = fm.width(QLatin1Char('x')) * 17 + 2*horizontalMargin + int w = fm.width(QLatin1Char('x')) * 17 + 2*d->horizontalMargin + d->leftTextMargin + d->rightTextMargin + d->leftmargin + d->rightmargin; // "some" QStyleOptionFrameV2 opt; @@ -753,7 +642,7 @@ QSize QLineEdit::minimumSizeHint() const Q_D(const QLineEdit); ensurePolished(); QFontMetrics fm = fontMetrics(); - int h = fm.height() + qMax(2*verticalMargin, fm.leading()) + int h = fm.height() + qMax(2*d->verticalMargin, fm.leading()) + d->topmargin + d->bottommargin; int w = fm.maxWidth() + d->leftmargin + d->rightmargin; QStyleOptionFrameV2 opt; @@ -775,17 +664,13 @@ QSize QLineEdit::minimumSizeHint() const int QLineEdit::cursorPosition() const { Q_D(const QLineEdit); - return d->cursor; + return d->control->cursorPosition(); } void QLineEdit::setCursorPosition(int pos) { Q_D(QLineEdit); - if (pos < 0) - pos = 0; - - if (pos <= d->text.length()) - d->moveCursor(pos); + d->control->setCursorPosition(pos); } /*! @@ -807,22 +692,17 @@ int QLineEdit::cursorPositionAt(const QPoint &pos) bool QLineEdit::validateAndSet(const QString &newText, int newPos, int newMarkAnchor, int newMarkDrag) { - Q_D(QLineEdit); - int priorState = d->undoState; - d->selstart = 0; - d->selend = d->text.length(); - d->removeSelectedText(); - d->insert(newText); - d->finishChange(priorState); - if (d->undoState > priorState) { - d->cursor = newPos; - d->selstart = qMin(newMarkAnchor, newMarkDrag); - d->selend = qMax(newMarkAnchor, newMarkDrag); - update(); - d->emitCursorPositionChanged(); - return true; + // The suggested functions above in the docs don't seem to validate, + // below code tries to mimic previous behaviour. + QString oldText = text(); + setText(newText); + if(!hasAcceptableInput()){ + setText(oldText); + return false; } - return false; + setCursorPosition(newPos); + setSelection(qMin(newMarkAnchor, newMarkDrag), qAbs(newMarkAnchor - newMarkDrag)); + return true; } #endif //QT3_SUPPORT @@ -863,15 +743,7 @@ void QLineEdit::setAlignment(Qt::Alignment alignment) void QLineEdit::cursorForward(bool mark, int steps) { Q_D(QLineEdit); - int cursor = d->cursor; - if (steps > 0) { - while(steps--) - cursor = d->textLayout.nextCursorPosition(cursor); - } else if (steps < 0) { - while (steps++) - cursor = d->textLayout.previousCursorPosition(cursor); - } - d->moveCursor(cursor, mark); + d->control->cursorForward(mark, steps); } @@ -896,7 +768,7 @@ void QLineEdit::cursorBackward(bool mark, int steps) void QLineEdit::cursorWordForward(bool mark) { Q_D(QLineEdit); - d->moveCursor(d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords), mark); + d->control->cursorWordForward(mark); } /*! @@ -909,7 +781,7 @@ void QLineEdit::cursorWordForward(bool mark) void QLineEdit::cursorWordBackward(bool mark) { Q_D(QLineEdit); - d->moveCursor(d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords), mark); + d->control->cursorWordBackward(mark); } @@ -924,26 +796,7 @@ void QLineEdit::cursorWordBackward(bool mark) void QLineEdit::backspace() { Q_D(QLineEdit); - int priorState = d->undoState; - if (d->hasSelectedText()) { - d->removeSelectedText(); - } else if (d->cursor) { - --d->cursor; - if (d->maskData) - d->cursor = d->prevMaskBlank(d->cursor); - QChar uc = d->text.at(d->cursor); - if (d->cursor > 0 && uc.unicode() >= 0xdc00 && uc.unicode() < 0xe000) { - // second half of a surrogate, check if we have the first half as well, - // if yes delete both at once - uc = d->text.at(d->cursor - 1); - if (uc.unicode() >= 0xd800 && uc.unicode() < 0xdc00) { - d->del(true); - --d->cursor; - } - } - d->del(true); - } - d->finishChange(priorState); + d->control->backspace(); } /*! @@ -957,15 +810,7 @@ void QLineEdit::backspace() void QLineEdit::del() { Q_D(QLineEdit); - int priorState = d->undoState; - if (d->hasSelectedText()) { - d->removeSelectedText(); - } else { - int n = d->textLayout.nextCursorPosition(d->cursor) - d->cursor; - while (n--) - d->del(); - } - d->finishChange(priorState); + d->control->del(); } /*! @@ -980,7 +825,7 @@ void QLineEdit::del() void QLineEdit::home(bool mark) { Q_D(QLineEdit); - d->moveCursor(0, mark); + d->control->home(mark); } /*! @@ -995,7 +840,7 @@ void QLineEdit::home(bool mark) void QLineEdit::end(bool mark) { Q_D(QLineEdit); - d->moveCursor(d->text.length(), mark); + d->control->end(mark); } @@ -1020,16 +865,13 @@ void QLineEdit::end(bool mark) bool QLineEdit::isModified() const { Q_D(const QLineEdit); - return d->modifiedState != d->undoState; + return d->control->isModified(); } void QLineEdit::setModified(bool modified) { Q_D(QLineEdit); - if (modified) - d->modifiedState = -1; - else - d->modifiedState = d->undoState; + d->control->setModified(modified); } @@ -1057,7 +899,7 @@ Use setModified(false) instead. bool QLineEdit::hasSelectedText() const { Q_D(const QLineEdit); - return d->hasSelectedText(); + return d->control->hasSelectedText(); } /*! @@ -1075,9 +917,7 @@ bool QLineEdit::hasSelectedText() const QString QLineEdit::selectedText() const { Q_D(const QLineEdit); - if (d->hasSelectedText()) - return d->text.mid(d->selstart, d->selend - d->selstart); - return QString(); + return d->control->selectedText(); } /*! @@ -1090,7 +930,7 @@ QString QLineEdit::selectedText() const int QLineEdit::selectionStart() const { Q_D(const QLineEdit); - return d->hasSelectedText() ? d->selstart : -1; + return d->control->selectionStart(); } @@ -1120,9 +960,10 @@ void QLineEdit::setEdited(bool on) { setModified(on); } int QLineEdit::characterAt(int xpos, QChar *chr) const { Q_D(const QLineEdit); - int pos = d->xToPos(xpos + contentsRect().x() - d->hscroll + horizontalMargin); - if (chr && pos < (int) d->text.length()) - *chr = d->text.at(pos); + int pos = d->xToPos(xpos + contentsRect().x() - d->hscroll + d->horizontalMargin); + QString txt = d->control->text(); + if (chr && pos < (int) txt.length()) + *chr = txt.at(pos); return pos; } @@ -1133,9 +974,9 @@ int QLineEdit::characterAt(int xpos, QChar *chr) const bool QLineEdit::getSelection(int *start, int *end) { Q_D(QLineEdit); - if (d->hasSelectedText() && start && end) { - *start = d->selstart; - *end = d->selend; + if (d->control->hasSelectedText() && start && end) { + *start = selectionStart(); + *end = *start + selectedText().length(); return true; } return false; @@ -1153,30 +994,19 @@ bool QLineEdit::getSelection(int *start, int *end) void QLineEdit::setSelection(int start, int length) { Q_D(QLineEdit); - if (start < 0 || start > (int)d->text.length()) { + if (start < 0 || start > (int)d->control->text().length()) { qWarning("QLineEdit::setSelection: Invalid start position (%d)", start); return; - } else { - if (length > 0) { - d->selstart = start; - d->selend = qMin(start + length, (int)d->text.length()); - d->cursor = d->selend; - } else { - d->selstart = qMax(start + length, 0); - d->selend = start; - d->cursor = d->selstart; - } } - if (d->hasSelectedText()){ + d->control->setSelection(start, length); + + if (d->control->hasSelectedText()){ QStyleOptionFrameV2 opt; initStyleOption(&opt); if (!style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) d->setCursorVisible(false); } - - update(); - d->emitCursorPositionChanged(); } @@ -1192,7 +1022,7 @@ void QLineEdit::setSelection(int start, int length) bool QLineEdit::isUndoAvailable() const { Q_D(const QLineEdit); - return d->isUndoAvailable(); + return d->control->isUndoAvailable(); } /*! @@ -1208,7 +1038,7 @@ bool QLineEdit::isUndoAvailable() const bool QLineEdit::isRedoAvailable() const { Q_D(const QLineEdit); - return d->isRedoAvailable(); + return d->control->isRedoAvailable(); } /*! @@ -1244,7 +1074,7 @@ void QLineEdit::setDragEnabled(bool b) bool QLineEdit::hasAcceptableInput() const { Q_D(const QLineEdit); - return d->hasAcceptableInput(d->text); + return d->control->hasAcceptableInput(); } /*! @@ -1350,15 +1180,13 @@ void QLineEdit::getTextMargins(int *left, int *top, int *right, int *bottom) con QString QLineEdit::inputMask() const { Q_D(const QLineEdit); - return (d->maskData ? d->inputMask + QLatin1Char(';') + d->blank : QString()); + return d->control->inputMask(); } void QLineEdit::setInputMask(const QString &inputMask) { Q_D(QLineEdit); - d->parseInputMask(inputMask); - if (d->maskData) - d->moveCursor(d->nextMaskBlank(0)); + d->control->setInputMask(inputMask); } /*! @@ -1373,8 +1201,7 @@ void QLineEdit::setInputMask(const QString &inputMask) void QLineEdit::selectAll() { Q_D(QLineEdit); - d->selstart = d->selend = d->cursor = 0; - d->moveCursor(d->text.length(), true); + d->control->selectAll(); } /*! @@ -1386,8 +1213,7 @@ void QLineEdit::selectAll() void QLineEdit::deselect() { Q_D(QLineEdit); - d->deselect(); - d->finishChange(); + d->control->deselect(); } @@ -1402,10 +1228,7 @@ void QLineEdit::insert(const QString &newText) { // q->resetInputContext(); //#### FIX ME IN QT Q_D(QLineEdit); - int priorState = d->undoState; - d->removeSelectedText(); - d->insert(newText); - d->finishChange(priorState); + d->control->insert(newText); } /*! @@ -1416,13 +1239,8 @@ void QLineEdit::insert(const QString &newText) void QLineEdit::clear() { Q_D(QLineEdit); - int priorState = d->undoState; resetInputContext(); - d->selstart = 0; - d->selend = d->text.length(); - d->removeSelectedText(); - d->separate(); - d->finishChange(priorState, /*update*/false, /*edited*/false); + d->control->clear(); } /*! @@ -1435,8 +1253,7 @@ void QLineEdit::undo() { Q_D(QLineEdit); resetInputContext(); - d->undo(); - d->finishChange(-1, true); + d->control->undo(); } /*! @@ -1447,8 +1264,7 @@ void QLineEdit::redo() { Q_D(QLineEdit); resetInputContext(); - d->redo(); - d->finishChange(); + d->control->redo(); } @@ -1470,16 +1286,16 @@ void QLineEdit::redo() bool QLineEdit::isReadOnly() const { Q_D(const QLineEdit); - return d->readOnly; + return d->control->isReadOnly(); } void QLineEdit::setReadOnly(bool enable) { Q_D(QLineEdit); - if (d->readOnly != enable) { - d->readOnly = enable; - setAttribute(Qt::WA_MacShowFocusRect, !d->readOnly); - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); + if (d->control->isReadOnly() != enable) { + d->control->setReadOnly(enable); + setAttribute(Qt::WA_MacShowFocusRect, !enable); + setAttribute(Qt::WA_InputMethodEnabled, d->shouldEnableInputMethod()); #ifndef QT_NO_CURSOR setCursor(enable ? Qt::ArrowCursor : Qt::IBeamCursor); #endif @@ -1518,7 +1334,7 @@ void QLineEdit::cut() void QLineEdit::copy() const { Q_D(const QLineEdit); - d->copy(); + d->control->copy(); } /*! @@ -1535,23 +1351,7 @@ void QLineEdit::copy() const void QLineEdit::paste() { Q_D(QLineEdit); - if (echoMode() == PasswordEchoOnEdit && !d->passwordEchoEditing) { - // Clear the edit and reset to normal echo mode when pasting; the echo - // mode switches back when the edit loses focus. ### changes a public - // property, resets current content - d->updatePasswordEchoEditing(true); - clear(); - } - insert(QApplication::clipboard()->text(QClipboard::Clipboard)); -} - -void QLineEditPrivate::copy(bool clipboard) const -{ - Q_Q(const QLineEdit); - QString t = q->selectedText(); - if (!t.isEmpty() && echoMode == QLineEdit::Normal) { - QApplication::clipboard()->setText(t, clipboard ? QClipboard::Clipboard : QClipboard::Selection); - } + d->control->paste(); } #endif // !QT_NO_CLIPBOARD @@ -1561,57 +1361,10 @@ void QLineEditPrivate::copy(bool clipboard) const bool QLineEdit::event(QEvent * e) { Q_D(QLineEdit); -#ifndef QT_NO_SHORTCUT - if (e->type() == QEvent::ShortcutOverride && !d->readOnly) { - QKeyEvent* ke = (QKeyEvent*) e; - if (ke == QKeySequence::Copy - || ke == QKeySequence::Paste - || ke == QKeySequence::Cut - || ke == QKeySequence::Redo - || ke == QKeySequence::Undo - || ke == QKeySequence::MoveToNextWord - || ke == QKeySequence::MoveToPreviousWord - || ke == QKeySequence::MoveToStartOfDocument - || ke == QKeySequence::MoveToEndOfDocument - || ke == QKeySequence::SelectNextWord - || ke == QKeySequence::SelectPreviousWord - || ke == QKeySequence::SelectStartOfLine - || ke == QKeySequence::SelectEndOfLine - || ke == QKeySequence::SelectStartOfBlock - || ke == QKeySequence::SelectEndOfBlock - || ke == QKeySequence::SelectStartOfDocument - || ke == QKeySequence::SelectAll - || ke == QKeySequence::SelectEndOfDocument) { - ke->accept(); - } else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier - || ke->modifiers() == Qt::KeypadModifier) { - if (ke->key() < Qt::Key_Escape) { - ke->accept(); - } else { - switch (ke->key()) { - case Qt::Key_Delete: - case Qt::Key_Home: - case Qt::Key_End: - case Qt::Key_Backspace: - case Qt::Key_Left: - case Qt::Key_Right: - ke->accept(); - default: - break; - } - } - } - } else -#endif - if (e->type() == QEvent::Timer) { + if (e->type() == QEvent::Timer) { // should be timerEvent, is here for binary compatibility int timerId = ((QTimerEvent*)e)->timerId(); - if (timerId == d->cursorTimer) { - QStyleOptionFrameV2 opt; - initStyleOption(&opt); - if(!hasSelectedText() - || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) - d->setCursorVisible(!d->cursorVisible); + if (false) { #ifndef QT_NO_DRAGANDDROP } else if (timerId == d->dndTimer.timerId()) { d->drag(); @@ -1619,60 +1372,31 @@ bool QLineEdit::event(QEvent * e) } else if (timerId == d->tripleClickTimer.timerId()) d->tripleClickTimer.stop(); -#ifdef QT_KEYPAD_NAVIGATION - else if (timerId == d->deleteAllTimer.timerId()) { - d->deleteAllTimer.stop(); - clear(); - } -#endif } else if (e->type() == QEvent::ContextMenu) { #ifndef QT_NO_IM - if (d->composeMode()) + if (d->control->composeMode()) return true; #endif - d->separate(); + //d->separate(); } else if (e->type() == QEvent::WindowActivate) { QTimer::singleShot(0, this, SLOT(_q_handleWindowActivate())); + }else if(e->type() == QEvent::ShortcutOverride){ + d->control->processEvent(e); } + #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled()) { - if ((e->type() == QEvent::KeyPress) || (e->type() == QEvent::KeyRelease)) { - QKeyEvent *ke = (QKeyEvent *)e; - if (ke->key() == Qt::Key_Back) { - if (ke->isAutoRepeat()) { - // Swallow it. We don't want back keys running amok. - ke->accept(); - return true; - } - if ((e->type() == QEvent::KeyRelease) - && !isReadOnly() - && d->deleteAllTimer.isActive()) { - d->deleteAllTimer.stop(); - backspace(); - ke->accept(); - return true; - } - } - } else if (e->type() == QEvent::EnterEditFocus) { + if (e->type() == QEvent::EnterEditFocus) { end(false); - if (!d->cursorTimer) { - int cft = QApplication::cursorFlashTime(); - d->cursorTimer = cft ? startTimer(cft/2) : -1; - } + int cft = QApplication::cursorFlashTime(); + d->control->setCursorBlinkPeriod(cft/2); } else if (e->type() == QEvent::LeaveEditFocus) { d->setCursorVisible(false); - if (d->cursorTimer > 0) - killTimer(d->cursorTimer); - d->cursorTimer = 0; - - if (!d->emitingEditingFinished) { - if (hasAcceptableInput() || d->fixup()) { - d->emitingEditingFinished = true; - emit editingFinished(); - d->emitingEditingFinished = false; - } - } + d->control->setCursorBlinkPeriod(0); + if (d->control->hasAcceptableInput() || d->control->fixup()) + emit editingFinished(); } + return true; } #endif return QWidget::event(e); @@ -1684,15 +1408,15 @@ void QLineEdit::mousePressEvent(QMouseEvent* e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; if (e->button() == Qt::RightButton) return; #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { setEditFocus(true); // Get the completion list to pop up. - if (d->completer) - d->completer->complete(); + if (d->control->completer()) + d->control->completer()->complete(); } #endif if (d->tripleClickTimer.isActive() && (e->pos() - d->tripleClick).manhattanLength() < @@ -1703,18 +1427,16 @@ void QLineEdit::mousePressEvent(QMouseEvent* e) bool mark = e->modifiers() & Qt::ShiftModifier; int cursor = d->xToPos(e->pos().x()); #ifndef QT_NO_DRAGANDDROP - if (!mark && d->dragEnabled && d->echoMode == Normal && - e->button() == Qt::LeftButton && d->inSelection(e->pos().x())) { - d->cursor = cursor; - update(); + if (!mark && d->dragEnabled && d->control->echoMode() == Normal && + e->button() == Qt::LeftButton && d->control->inSelection(e->pos().x())) { + d->control->moveCursor(cursor); d->dndPos = e->pos(); if (!d->dndTimer.isActive()) d->dndTimer.start(QApplication::startDragTime(), this); - d->emitCursorPositionChanged(); } else #endif { - d->moveCursor(cursor, mark); + d->control->moveCursor(cursor, mark); } } @@ -1724,7 +1446,7 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; if (e->buttons() & Qt::LeftButton) { #ifndef QT_NO_DRAGANDDROP @@ -1734,7 +1456,7 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) } else #endif { - d->moveCursor(d->xToPos(e->pos().x()), true); + d->control->moveCursor(d->xToPos(e->pos().x()), true); } } } @@ -1745,7 +1467,7 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; #ifndef QT_NO_DRAGANDDROP if (e->button() == Qt::LeftButton) { if (d->dndTimer.isActive()) { @@ -1758,9 +1480,9 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) #ifndef QT_NO_CLIPBOARD if (QApplication::clipboard()->supportsSelection()) { if (e->button() == Qt::LeftButton) { - d->copy(false); - } else if (!d->readOnly && e->button() == Qt::MidButton) { - d->deselect(); + d->control->copy(QClipboard::Selection); + } else if (!d->control->isReadOnly() && e->button() == Qt::MidButton) { + deselect(); insert(QApplication::clipboard()->text(QClipboard::Selection)); } } @@ -1773,16 +1495,9 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) { Q_D(QLineEdit); if (d->sendMouseEventToInputContext(e)) - return; + return; if (e->button() == Qt::LeftButton) { - deselect(); - d->cursor = d->xToPos(e->pos().x()); - d->cursor = d->textLayout.previousCursorPosition(d->cursor, QTextLayout::SkipWords); - // ## text layout should support end of words. - int end = d->textLayout.nextCursorPosition(d->cursor, QTextLayout::SkipWords); - while (end > d->cursor && d->text[end-1].isSpace()) - --end; - d->moveCursor(end, true); + d->control->selectWordAtPos(d->xToPos(e->pos().x())); d->tripleClickTimer.start(QApplication::doubleClickInterval(), this); d->tripleClick = e->pos(); } @@ -1822,65 +1537,15 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) void QLineEdit::keyPressEvent(QKeyEvent *event) { Q_D(QLineEdit); - - bool inlineCompletionAccepted = false; - -#ifndef QT_NO_COMPLETER - if (d->completer) { - QCompleter::CompletionMode completionMode = d->completer->completionMode(); - if ((completionMode == QCompleter::PopupCompletion - || completionMode == QCompleter::UnfilteredPopupCompletion) - &&d->completer->popup() - && d->completer->popup()->isVisible()) { - // The following keys are forwarded by the completer to the widget - // Ignoring the events lets the completer provide suitable default behavior - switch (event->key()) { - case Qt::Key_Escape: - event->ignore(); - return; - case Qt::Key_Enter: - case Qt::Key_Return: - case Qt::Key_F4: -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Select: - if (!QApplication::keypadNavigationEnabled()) - break; -#endif - d->completer->popup()->hide(); // just hide. will end up propagating to parent - default: - break; // normal key processing - } - } else if (completionMode == QCompleter::InlineCompletion) { - switch (event->key()) { - case Qt::Key_Enter: - case Qt::Key_Return: - case Qt::Key_F4: -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Select: - if (!QApplication::keypadNavigationEnabled()) - break; -#endif - if (!d->completer->currentCompletion().isEmpty() && d->selend > d->selstart - && d->selend == d->text.length()) { - setText(d->completer->currentCompletion()); - inlineCompletionAccepted = true; - } - default: - break; // normal key processing - } - } - } -#endif // QT_NO_COMPLETER - -#ifdef QT_KEYPAD_NAVIGATION + #ifdef QT_KEYPAD_NAVIGATION bool select = false; switch (event->key()) { case Qt::Key_Select: if (QApplication::keypadNavigationEnabled()) { if (hasEditFocus()) { setEditFocus(false); - if (d->completer && d->completer->popup()->isVisible()) - d->completer->popup()->hide(); + if (d->control->completer() && d->control->completer()->popup()->isVisible()) + d->control->completer()->popup()->hide(); select = true; } } @@ -1916,274 +1581,7 @@ void QLineEdit::keyPressEvent(QKeyEvent *event) return; // Just start. No action. } #endif - - if (echoMode() == PasswordEchoOnEdit - && !d->passwordEchoEditing - && !isReadOnly() - && !event->text().isEmpty() -#ifdef QT_KEYPAD_NAVIGATION - && event->key() != Qt::Key_Select - && event->key() != Qt::Key_Up - && event->key() != Qt::Key_Down - && event->key() != Qt::Key_Back -#endif - && !(event->modifiers() & Qt::ControlModifier)) { - // Clear the edit and reset to normal echo mode while editing; the - // echo mode switches back when the edit loses focus. ### changes a - // public property, resets current content. dubious code; you can - // navigate with keys up, down, back, and select(?), but if you press - // "left" or "right" it clears? - d->updatePasswordEchoEditing(true); - clear(); - } - - d->setCursorVisible(true); - if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { - if (hasAcceptableInput() || d->fixup()) { - emit returnPressed(); - d->emitingEditingFinished = true; - emit editingFinished(); - d->emitingEditingFinished = false; - } - if (inlineCompletionAccepted) - event->accept(); - else - event->ignore(); - return; - } - bool unknown = false; - - if (false) { - } -#ifndef QT_NO_SHORTCUT - else if (event == QKeySequence::Undo) { - if (!d->readOnly) - undo(); - } - else if (event == QKeySequence::Redo) { - if (!d->readOnly) - redo(); - } - else if (event == QKeySequence::SelectAll) { - selectAll(); - } -#ifndef QT_NO_CLIPBOARD - else if (event == QKeySequence::Copy) { - copy(); - } - else if (event == QKeySequence::Paste) { - if (!d->readOnly) - paste(); - } - else if (event == QKeySequence::Cut) { - if (!d->readOnly) { - cut(); - } - } - else if (event == QKeySequence::DeleteEndOfLine) { - if (!d->readOnly) { - setSelection(d->cursor, d->text.size()); - copy(); - del(); - } - } -#endif //QT_NO_CLIPBOARD - else if (event == QKeySequence::MoveToStartOfLine) { - home(0); - } - else if (event == QKeySequence::MoveToEndOfLine) { - end(0); - } - else if (event == QKeySequence::SelectStartOfLine) { - home(1); - } - else if (event == QKeySequence::SelectEndOfLine) { - end(1); - } - else if (event == QKeySequence::MoveToNextChar) { -#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) - if (d->hasSelectedText()) { -#else - if (d->hasSelectedText() && d->completer - && d->completer->completionMode() == QCompleter::InlineCompletion) { -#endif - d->moveCursor(d->selend, false); - } else { - cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - } - else if (event == QKeySequence::SelectNextChar) { - cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - else if (event == QKeySequence::MoveToPreviousChar) { -#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) - if (d->hasSelectedText()) { -#else - if (d->hasSelectedText() && d->completer - && d->completer->completionMode() == QCompleter::InlineCompletion) { -#endif - d->moveCursor(d->selstart, false); - } else { - cursorBackward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - } - else if (event == QKeySequence::SelectPreviousChar) { - cursorBackward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); - } - else if (event == QKeySequence::MoveToNextWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordForward(0) : cursorWordBackward(0); - else - layoutDirection() == Qt::LeftToRight ? end(0) : home(0); - } - else if (event == QKeySequence::MoveToPreviousWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordBackward(0) : cursorWordForward(0); - else if (!d->readOnly) { - layoutDirection() == Qt::LeftToRight ? home(0) : end(0); - } - } - else if (event == QKeySequence::SelectNextWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordForward(1) : cursorWordBackward(1); - else - layoutDirection() == Qt::LeftToRight ? end(1) : home(1); - } - else if (event == QKeySequence::SelectPreviousWord) { - if (echoMode() == Normal) - layoutDirection() == Qt::LeftToRight ? cursorWordBackward(1) : cursorWordForward(1); - else - layoutDirection() == Qt::LeftToRight ? home(1) : end(1); - } - else if (event == QKeySequence::Delete) { - if (!d->readOnly) - del(); - } - else if (event == QKeySequence::DeleteEndOfWord) { - if (!d->readOnly) { - cursorWordForward(true); - del(); - } - } - else if (event == QKeySequence::DeleteStartOfWord) { - if (!d->readOnly) { - cursorWordBackward(true); - del(); - } - } -#endif // QT_NO_SHORTCUT - else { -#ifdef Q_WS_MAC - if (event->key() == Qt::Key_Up || event->key() == Qt::Key_Down) { - Qt::KeyboardModifiers myModifiers = (event->modifiers() & ~Qt::KeypadModifier); - if (myModifiers & Qt::ShiftModifier) { - if (myModifiers == (Qt::ControlModifier|Qt::ShiftModifier) - || myModifiers == (Qt::AltModifier|Qt::ShiftModifier) - || myModifiers == Qt::ShiftModifier) { - - event->key() == Qt::Key_Up ? home(1) : end(1); - } - } else { - if ((myModifiers == Qt::ControlModifier - || myModifiers == Qt::AltModifier - || myModifiers == Qt::NoModifier)) { - event->key() == Qt::Key_Up ? home(0) : end(0); - } - } - } -#endif - if (event->modifiers() & Qt::ControlModifier) { - switch (event->key()) { - case Qt::Key_Backspace: - if (!d->readOnly) { - cursorWordBackward(true); - del(); - } - break; -#ifndef QT_NO_COMPLETER - case Qt::Key_Up: - case Qt::Key_Down: - d->complete(event->key()); - break; -#endif -#if defined(Q_WS_X11) - case Qt::Key_E: - end(0); - break; - - case Qt::Key_U: - if (!d->readOnly) { - setSelection(0, d->text.size()); -#ifndef QT_NO_CLIPBOARD - copy(); -#endif - del(); - } - break; -#endif - default: - unknown = true; - } - } else { // ### check for *no* modifier - switch (event->key()) { - case Qt::Key_Backspace: - if (!d->readOnly) { - backspace(); -#ifndef QT_NO_COMPLETER - d->complete(Qt::Key_Backspace); -#endif - } - break; -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Back: - if (QApplication::keypadNavigationEnabled() && !event->isAutoRepeat() - && !isReadOnly()) { - if (text().length() == 0) { - setText(d->origText); - - if (d->passwordEchoEditing) - d->updatePasswordEchoEditing(false); - - setEditFocus(false); - } else if (!d->deleteAllTimer.isActive()) { - d->deleteAllTimer.start(750, this); - } - } else { - unknown = true; - } - break; -#endif - - default: - unknown = true; - } - } - } - - if (event->key() == Qt::Key_Direction_L || event->key() == Qt::Key_Direction_R) { - setLayoutDirection((event->key() == Qt::Key_Direction_L) ? Qt::LeftToRight : Qt::RightToLeft); - d->updateTextLayout(); - update(); - unknown = false; - } - - if (unknown && !d->readOnly) { - QString t = event->text(); - if (!t.isEmpty() && t.at(0).isPrint() && - ((event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) == Qt::NoModifier)) { - insert(t); -#ifndef QT_NO_COMPLETER - d->complete(event->key()); -#endif - event->accept(); - return; - } - } - - if (unknown) - event->ignore(); - else - event->accept(); + d->control->processKeyEvent(event); } /*! @@ -2197,50 +1595,17 @@ QRect QLineEdit::cursorRect() const return d->cursorRect(); } -/*! - This function is not intended as polymorphic usage. Just a shared code - fragment that calls QInputContext::mouseHandler for this - class. -*/ -bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e ) -{ -#if !defined QT_NO_IM - Q_Q(QLineEdit); - if ( composeMode() ) { - int tmp_cursor = xToPos(e->pos().x()); - int mousePos = tmp_cursor - cursor; - if ( mousePos < 0 || mousePos > textLayout.preeditAreaText().length() ) { - mousePos = -1; - // don't send move events outside the preedit area - if ( e->type() == QEvent::MouseMove ) - return true; - } - - QInputContext *qic = q->inputContext(); - if ( qic ) - // may be causing reset() in some input methods - qic->mouseHandler(mousePos, e); - if (!textLayout.preeditAreaText().isEmpty()) - return true; - } -#else - Q_UNUSED(e); -#endif - - return false; -} - /*! \reimp */ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) { Q_D(QLineEdit); - if (d->readOnly) { + if (d->control->isReadOnly()) { e->ignore(); return; } - if (echoMode() == PasswordEchoOnEdit && !d->passwordEchoEditing) { + if (echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing()) { // Clear the edit and reset to normal echo mode while entering input // method data; the echo mode switches back when the edit loses focus. // ### changes a public property, resets current content. @@ -2260,55 +1625,11 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) } #endif - int priorState = d->undoState; - d->removeSelectedText(); - - int c = d->cursor; // cursor position after insertion of commit string - if (e->replacementStart() <= 0) - c += e->commitString().length() + qMin(-e->replacementStart(), e->replacementLength()); - - d->cursor += e->replacementStart(); + d->control->processInputMethodEvent(e); - // insert commit string - if (e->replacementLength()) { - d->selstart = d->cursor; - d->selend = d->selstart + e->replacementLength(); - d->removeSelectedText(); - } - if (!e->commitString().isEmpty()) - d->insert(e->commitString()); - - d->cursor = qMin(c, d->text.length()); - - d->textLayout.setPreeditArea(d->cursor, e->preeditString()); - d->preeditCursor = e->preeditString().length(); - d->hideCursor = false; - QList<QTextLayout::FormatRange> formats; - for (int i = 0; i < e->attributes().size(); ++i) { - const QInputMethodEvent::Attribute &a = e->attributes().at(i); - if (a.type == QInputMethodEvent::Cursor) { - d->preeditCursor = a.start; - d->hideCursor = !a.length; - } else if (a.type == QInputMethodEvent::TextFormat) { - QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat(); - if (f.isValid()) { - QTextLayout::FormatRange o; - o.start = a.start + d->cursor; - o.length = a.length; - o.format = f; - formats.append(o); - } - } - } - d->textLayout.setAdditionalFormats(formats); - d->updateTextLayout(); - update(); - if (!e->commitString().isEmpty()) - d->emitCursorPositionChanged(); - d->finishChange(priorState); #ifndef QT_NO_COMPLETER if (!e->commitString().isEmpty()) - d->complete(Qt::Key_unknown); + d->control->complete(Qt::Key_unknown); #endif } @@ -2323,9 +1644,9 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const case Qt::ImFont: return font(); case Qt::ImCursorPosition: - return QVariant((d->selend - d->selstart == 0) ? d->cursor : d->selend); + return QVariant(d->control->hasSelectedText() ? d->control->selectionEnd() : d->control->cursor()); case Qt::ImSurroundingText: - return QVariant(d->text); + return QVariant(text()); case Qt::ImCurrentSelection: return QVariant(selectedText()); default: @@ -2342,36 +1663,34 @@ void QLineEdit::focusInEvent(QFocusEvent *e) if (e->reason() == Qt::TabFocusReason || e->reason() == Qt::BacktabFocusReason || e->reason() == Qt::ShortcutFocusReason) { - if (d->maskData) - d->moveCursor(d->nextMaskBlank(0)); - else if (!d->hasSelectedText()) + if (!d->control->inputMask().isEmpty()) + d->control->moveCursor(d->control->nextMaskBlank(0)); + else if (!d->control->hasSelectedText()) selectAll(); } #ifdef QT_KEYPAD_NAVIGATION if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && e->reason() == Qt::PopupFocusReason)) #endif - if (!d->cursorTimer) { - int cft = QApplication::cursorFlashTime(); - d->cursorTimer = cft ? startTimer(cft/2) : -1; - } + int cft = QApplication::cursorFlashTime(); + d->control->setCursorBlinkPeriod(cft/2); QStyleOptionFrameV2 opt; initStyleOption(&opt); - if((!hasSelectedText() && d->textLayout.preeditAreaText().isEmpty()) + if((!hasSelectedText() && d->control->preeditAreaText().isEmpty()) || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) d->setCursorVisible(true); #ifdef Q_WS_MAC - if (d->echoMode == Password || d->echoMode == NoEcho) + if (d->control->echoMode() == Password || d->control->echoMode() == NoEcho) qt_mac_secure_keyboard(true); #endif #ifdef QT_KEYPAD_NAVIGATION - d->origText = d->text; + d->control->setCancelText(d->text); #endif #ifndef QT_NO_COMPLETER - if (d->completer) { - d->completer->setWidget(this); - QObject::connect(d->completer, SIGNAL(activated(QString)), + if (d->control->completer()) { + d->control->completer()->setWidget(this); + QObject::connect(d->control->completer(), SIGNAL(activated(QString)), this, SLOT(setText(QString))); - QObject::connect(d->completer, SIGNAL(highlighted(QString)), + QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)), this, SLOT(_q_completionHighlighted(QString))); } #endif @@ -2384,7 +1703,7 @@ void QLineEdit::focusInEvent(QFocusEvent *e) void QLineEdit::focusOutEvent(QFocusEvent *e) { Q_D(QLineEdit); - if (d->passwordEchoEditing) { + if (d->control->passwordEchoEditing()) { // Reset the echomode back to PasswordEchoOnEdit when the widget loses // focus. d->updatePasswordEchoEditing(false); @@ -2396,37 +1715,29 @@ void QLineEdit::focusOutEvent(QFocusEvent *e) deselect(); d->setCursorVisible(false); - if (d->cursorTimer > 0) - killTimer(d->cursorTimer); - d->cursorTimer = 0; - + d->control->setCursorBlinkPeriod(0); #ifdef QT_KEYPAD_NAVIGATION // editingFinished() is already emitted on LeaveEditFocus if (!QApplication::keypadNavigationEnabled()) #endif if (reason != Qt::PopupFocusReason || !(QApplication::activePopupWidget() && QApplication::activePopupWidget()->parentWidget() == this)) { - if (!d->emitingEditingFinished) { - if (hasAcceptableInput() || d->fixup()) { - d->emitingEditingFinished = true; + if (hasAcceptableInput() || d->control->fixup()) emit editingFinished(); - d->emitingEditingFinished = false; - } - } #ifdef QT3_SUPPORT emit lostFocus(); #endif } #ifdef Q_WS_MAC - if (d->echoMode == Password || d->echoMode == NoEcho) + if (d->control->echoMode() == Password || d->control->echoMode() == NoEcho) qt_mac_secure_keyboard(false); #endif #ifdef QT_KEYPAD_NAVIGATION - d->origText = QString(); + d->control->setCancelText(QString()); #endif #ifndef QT_NO_COMPLETER - if (d->completer) { - QObject::disconnect(d->completer, 0, this, 0); + if (d->control->completer()) { + QObject::disconnect(d->control->completer(), 0, this, 0); } #endif update(); @@ -2456,24 +1767,19 @@ void QLineEdit::paintEvent(QPaintEvent *) Qt::Alignment va = QStyle::visualAlignment(layoutDirection(), QFlag(d->alignment)); switch (va & Qt::AlignVertical_Mask) { case Qt::AlignBottom: - d->vscroll = r.y() + r.height() - fm.height() - verticalMargin; + d->vscroll = r.y() + r.height() - fm.height() - d->verticalMargin; break; case Qt::AlignTop: - d->vscroll = r.y() + verticalMargin; + d->vscroll = r.y() + d->verticalMargin; break; default: //center d->vscroll = r.y() + (r.height() - fm.height() + 1) / 2; break; } - QRect lineRect(r.x() + horizontalMargin, d->vscroll, r.width() - 2*horizontalMargin, fm.height()); - QTextLine line = d->textLayout.lineAt(0); + QRect lineRect(r.x() + d->horizontalMargin, d->vscroll, r.width() - 2*d->horizontalMargin, fm.height()); - int cursor = d->cursor; - if (d->preeditCursor != -1) - cursor += d->preeditCursor; - // locate cursor position - int cix = qRound(line.cursorToX(cursor)); + int cix = qRound(d->control->cursorToX()); // horizontal scrolling. d->hscroll is the left indent from the beginning // of the text line to the left edge of lineRect. we update this value @@ -2483,7 +1789,7 @@ void QLineEdit::paintEvent(QPaintEvent *) // (cix). int minLB = qMax(0, -fm.minLeftBearing()); int minRB = qMax(0, -fm.minRightBearing()); - int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB; + int widthUsed = d->control->width() + minRB; if ((minLB + widthUsed) <= lineRect.width()) { // text fits in lineRect; use hscroll for alignment switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { @@ -2511,7 +1817,7 @@ void QLineEdit::paintEvent(QPaintEvent *) d->hscroll = widthUsed - lineRect.width() + 1; } // the y offset is there to keep the baseline constant in case we have script changes in the text. - QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->ascent - fm.ascent()); + QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent()); // draw text, selections and cursors #ifndef QT_NO_STYLE_STYLESHEET @@ -2521,33 +1827,23 @@ void QLineEdit::paintEvent(QPaintEvent *) #endif p.setPen(pal.text().color()); - QVector<QTextLayout::FormatRange> selections; + int flags = QLineControl::DrawText; + #ifdef QT_KEYPAD_NAVIGATION if (!QApplication::keypadNavigationEnabled() || hasEditFocus()) #endif - if (d->selstart < d->selend || (d->cursorVisible && d->maskData && !d->readOnly)) { - QTextLayout::FormatRange o; - if (d->selstart < d->selend) { - o.start = d->selstart; - o.length = d->selend - d->selstart; - o.format.setBackground(pal.brush(QPalette::Highlight)); - o.format.setForeground(pal.brush(QPalette::HighlightedText)); - } else { - // mask selection - o.start = d->cursor; - o.length = 1; - o.format.setBackground(pal.brush(QPalette::Text)); - o.format.setForeground(pal.brush(QPalette::Window)); - } - selections.append(o); - } + if (d->control->hasSelectedText() || (d->cursorVisible && !d->control->inputMask().isEmpty() && !d->control->isReadOnly())) + flags |= QLineControl::DrawSelections; // Asian users see an IM selection text as cursor on candidate // selection phase of input method, so the ordinary cursor should be // invisible if we have a preedit string. - d->textLayout.draw(&p, topLeft, selections, r); - if (d->cursorVisible && !d->readOnly && !d->hideCursor) - d->textLayout.drawCursor(&p, topLeft, cursor, style()->pixelMetric(QStyle::PM_TextCursorWidth)); + if (d->cursorVisible && !d->control->isReadOnly()) + flags |= QLineControl::DrawCursor; + + d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth)); + d->control->draw(&p, topLeft, r, flags); + } @@ -2557,12 +1853,11 @@ void QLineEdit::paintEvent(QPaintEvent *) void QLineEdit::dragMoveEvent(QDragMoveEvent *e) { Q_D(QLineEdit); - if (!d->readOnly && e->mimeData()->hasFormat(QLatin1String("text/plain"))) { + if (!d->control->isReadOnly() && e->mimeData()->hasFormat(QLatin1String("text/plain"))) { e->acceptProposedAction(); - d->cursor = d->xToPos(e->pos().x()); + d->control->moveCursor(d->xToPos(e->pos().x()), false); d->cursorVisible = true; update(); - d->emitCursorPositionChanged(); } } @@ -2588,13 +1883,14 @@ void QLineEdit::dropEvent(QDropEvent* e) Q_D(QLineEdit); QString str = e->mimeData()->text(); - if (!str.isNull() && !d->readOnly) { + if (!str.isNull() && !d->control->isReadOnly()) { if (e->source() == this && e->dropAction() == Qt::CopyAction) deselect(); - d->cursor =d->xToPos(e->pos().x()); - int selStart = d->cursor; - int oldSelStart = d->selstart; - int oldSelEnd = d->selend; + int cursorPos = d->xToPos(e->pos().x()); + int selStart = cursorPos; + int oldSelStart = d->control->selectionStart(); + int oldSelEnd = d->control->selectionEnd(); + d->control->moveCursor(cursorPos, false); d->cursorVisible = false; e->acceptProposedAction(); insert(str); @@ -2616,22 +1912,6 @@ void QLineEdit::dropEvent(QDropEvent* e) } } -void QLineEditPrivate::drag() -{ - Q_Q(QLineEdit); - dndTimer.stop(); - QMimeData *data = new QMimeData; - data->setText(q->selectedText()); - QDrag *drag = new QDrag(q); - drag->setMimeData(data); - Qt::DropAction action = drag->start(); - if (action == Qt::MoveAction && !readOnly && drag->target() != q) { - int priorState = undoState; - removeSelectedText(); - finishChange(priorState); - } -} - #endif // QT_NO_DRAGANDDROP #ifndef QT_NO_CONTEXTMENU @@ -2676,37 +1956,39 @@ QMenu *QLineEdit::createStandardContextMenu() popup->setObjectName(QLatin1String("qt_edit_menu")); QAction *action = popup->addAction(QLineEdit::tr("&Undo") + ACCEL_KEY(QKeySequence::Undo)); - action->setEnabled(d->isUndoAvailable()); + action->setEnabled(d->control->isUndoAvailable()); connect(action, SIGNAL(triggered()), SLOT(undo())); action = popup->addAction(QLineEdit::tr("&Redo") + ACCEL_KEY(QKeySequence::Redo)); - action->setEnabled(d->isRedoAvailable()); + action->setEnabled(d->control->isRedoAvailable()); connect(action, SIGNAL(triggered()), SLOT(redo())); popup->addSeparator(); #ifndef QT_NO_CLIPBOARD action = popup->addAction(QLineEdit::tr("Cu&t") + ACCEL_KEY(QKeySequence::Cut)); - action->setEnabled(!d->readOnly && d->hasSelectedText() && d->echoMode == QLineEdit::Normal); + action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText() + && d->control->echoMode() == QLineEdit::Normal); connect(action, SIGNAL(triggered()), SLOT(cut())); action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy)); - action->setEnabled(d->hasSelectedText() && d->echoMode == QLineEdit::Normal); + action->setEnabled(d->control->hasSelectedText() + && d->control->echoMode() == QLineEdit::Normal); connect(action, SIGNAL(triggered()), SLOT(copy())); action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste)); - action->setEnabled(!d->readOnly && !QApplication::clipboard()->text().isEmpty()); + action->setEnabled(!d->control->isReadOnly() && !QApplication::clipboard()->text().isEmpty()); connect(action, SIGNAL(triggered()), SLOT(paste())); #endif action = popup->addAction(QLineEdit::tr("Delete")); - action->setEnabled(!d->readOnly && !d->text.isEmpty() && d->hasSelectedText()); + action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText()); connect(action, SIGNAL(triggered()), SLOT(_q_deleteSelected())); popup->addSeparator(); action = popup->addAction(QLineEdit::tr("Select All") + ACCEL_KEY(QKeySequence::SelectAll)); - action->setEnabled(!d->text.isEmpty() && !d->allSelected()); + action->setEnabled(!d->control->text().isEmpty() && !d->control->allSelected()); d->selectAllAction = action; connect(action, SIGNAL(triggered()), SLOT(selectAll())); @@ -2720,9 +2002,9 @@ QMenu *QLineEdit::createStandardContextMenu() #endif #if defined(Q_WS_WIN) - if (!d->readOnly && qt_use_rtl_extensions) { + if (!d->control->isReadOnly() && qt_use_rtl_extensions) { #else - if (!d->readOnly) { + if (!d->control->isReadOnly()) { #endif popup->addSeparator(); QUnicodeControlCharacterMenu *ctrlCharacterMenu = new QUnicodeControlCharacterMenu(this, popup); @@ -2736,806 +2018,26 @@ QMenu *QLineEdit::createStandardContextMenu() void QLineEdit::changeEvent(QEvent *ev) { Q_D(QLineEdit); - if(ev->type() == QEvent::ActivationChange) { + switch(ev->type()) + { + case QEvent::ActivationChange: if (!palette().isEqual(QPalette::Active, QPalette::Inactive)) update(); - } else if (ev->type() == QEvent::FontChange - || ev->type() == QEvent::StyleChange - || ev->type() == QEvent::LayoutDirectionChange) { - d->updateTextLayout(); - } - QWidget::changeEvent(ev); -} - -void QLineEditPrivate::_q_handleWindowActivate() -{ - Q_Q(QLineEdit); - if (!q->hasFocus() && q->hasSelectedText()) - q->deselect(); -} - -void QLineEditPrivate::_q_deleteSelected() -{ - Q_Q(QLineEdit); - if (!hasSelectedText()) - return; - - int priorState = undoState; - q->resetInputContext(); - removeSelectedText(); - separate(); - finishChange(priorState); -} - -void QLineEditPrivate::init(const QString& txt) -{ - Q_Q(QLineEdit); -#ifndef QT_NO_CURSOR - q->setCursor(Qt::IBeamCursor); -#endif - q->setFocusPolicy(Qt::StrongFocus); - q->setAttribute(Qt::WA_InputMethodEnabled); - // Specifies that this widget can use more, but is able to survive on - // less, horizontal space; and is fixed vertically. - q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit)); - q->setBackgroundRole(QPalette::Base); - q->setAttribute(Qt::WA_KeyCompression); - q->setMouseTracking(true); - q->setAcceptDrops(true); - text = txt; - updateTextLayout(); - cursor = text.length(); - - q->setAttribute(Qt::WA_MacShowFocusRect); -} - -void QLineEditPrivate::updatePasswordEchoEditing(bool editing) -{ - Q_Q(QLineEdit); - passwordEchoEditing = editing; - q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(q)); - updateTextLayout(); - q->update(); -} - -void QLineEditPrivate::updateTextLayout() -{ - // replace certain non-printable characters with spaces (to avoid - // drawing boxes when using fonts that don't have glyphs for such - // characters) - Q_Q(QLineEdit); - QString str = q->displayText(); - QChar* uc = str.data(); - for (int i = 0; i < (int)str.length(); ++i) { - if ((uc[i] < 0x20 && uc[i] != 0x09) - || uc[i] == QChar::LineSeparator - || uc[i] == QChar::ParagraphSeparator - || uc[i] == QChar::ObjectReplacementCharacter) - uc[i] = QChar(0x0020); - } - textLayout.setFont(q->font()); - textLayout.setText(str); - QTextOption option; - option.setTextDirection(q->layoutDirection()); - option.setFlags(QTextOption::IncludeTrailingSpaces); - textLayout.setTextOption(option); - - textLayout.beginLayout(); - QTextLine l = textLayout.createLine(); - textLayout.endLayout(); - ascent = qRound(l.ascent()); -} - -int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const -{ - QRect cr = adjustedContentsRect(); - x-= cr.x() - hscroll + horizontalMargin; - QTextLine l = textLayout.lineAt(0); - return l.xToCursor(x, betweenOrOn); -} - -QRect QLineEditPrivate::cursorRect() const -{ - Q_Q(const QLineEdit); - QRect cr = adjustedContentsRect(); - int cix = cr.x() - hscroll + horizontalMargin; - QTextLine l = textLayout.lineAt(0); - int c = cursor; - if (preeditCursor != -1) - c += preeditCursor; - cix += qRound(l.cursorToX(c)); - int ch = qMin(cr.height(), q->fontMetrics().height() + 1); - int w = q->style()->pixelMetric(QStyle::PM_TextCursorWidth); - return QRect(cix-5, vscroll, w + 9, ch); -} - -QRect QLineEditPrivate::adjustedContentsRect() const -{ - Q_Q(const QLineEdit); - QStyleOptionFrameV2 opt; - q->initStyleOption(&opt); - QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q); - r.setX(r.x() + leftTextMargin); - r.setY(r.y() + topTextMargin); - r.setRight(r.right() - rightTextMargin); - r.setBottom(r.bottom() - bottomTextMargin); - return r; -} - -bool QLineEditPrivate::fixup() // this function assumes that validate currently returns != Acceptable -{ -#ifndef QT_NO_VALIDATOR - if (validator) { - QString textCopy = text; - int cursorCopy = cursor; - validator->fixup(textCopy); - if (validator->validate(textCopy, cursorCopy) == QValidator::Acceptable) { - if (textCopy != text || cursorCopy != cursor) - setText(textCopy, cursorCopy); - return true; - } - } -#endif - return false; -} - -void QLineEditPrivate::moveCursor(int pos, bool mark) -{ - Q_Q(QLineEdit); - if (pos != cursor) { - separate(); - if (maskData) - pos = pos > cursor ? nextMaskBlank(pos) : prevMaskBlank(pos); - } - bool fullUpdate = mark || hasSelectedText(); - if (mark) { - int anchor; - if (selend > selstart && cursor == selstart) - anchor = selend; - else if (selend > selstart && cursor == selend) - anchor = selstart; - else - anchor = cursor; - selstart = qMin(anchor, pos); - selend = qMax(anchor, pos); - updateTextLayout(); - } else { - deselect(); - } - if (fullUpdate) { - cursor = pos; - q->update(); - } else { - setCursorVisible(false); - cursor = pos; - setCursorVisible(true); - if (!adjustedContentsRect().contains(cursorRect())) - q->update(); - } - QStyleOptionFrameV2 opt; - q->initStyleOption(&opt); - if (mark && !q->style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, q)) - setCursorVisible(false); - if (mark || selDirty) { - selDirty = false; - emit q->selectionChanged(); - } - emitCursorPositionChanged(); -} - -void QLineEditPrivate::finishChange(int validateFromState, bool update, bool edited) -{ - Q_Q(QLineEdit); - bool lineDirty = selDirty; - if (textDirty) { - // do validation - bool wasValidInput = validInput; - validInput = true; -#ifndef QT_NO_VALIDATOR - if (validator) { - validInput = false; - QString textCopy = text; - int cursorCopy = cursor; - validInput = (validator->validate(textCopy, cursorCopy) != QValidator::Invalid); - if (validInput) { - if (text != textCopy) { - setText(textCopy, cursorCopy); - return; - } - cursor = cursorCopy; - } - } -#endif - if (validateFromState >= 0 && wasValidInput && !validInput) { - undo(validateFromState); - history.resize(undoState); - if (modifiedState > undoState) - modifiedState = -1; - validInput = true; - textDirty = false; - } - updateTextLayout(); - lineDirty |= textDirty; - if (textDirty) { - textDirty = false; - QString actualText = maskData ? stripString(text) : text; - if (edited) - emit q->textEdited(actualText); - q->updateMicroFocus(); -#ifndef QT_NO_COMPLETER - if (edited && completer && completer->completionMode() != QCompleter::InlineCompletion) - complete(-1); // update the popup on cut/paste/del -#endif - emit q->textChanged(actualText); - } -#ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(q, 0, QAccessible::ValueChanged); -#endif - } - if (selDirty) { - selDirty = false; - emit q->selectionChanged(); - } - if (lineDirty || update) - q->update(); - emitCursorPositionChanged(); -} - -void QLineEditPrivate::emitCursorPositionChanged() -{ - Q_Q(QLineEdit); - if (cursor != lastCursorPos) { - const int oldLast = lastCursorPos; - lastCursorPos = cursor; - emit q->cursorPositionChanged(oldLast, cursor); - } -} - -void QLineEditPrivate::setText(const QString& txt, int pos, bool edited) -{ - Q_Q(QLineEdit); - q->resetInputContext(); - deselect(); - QString oldText = text; - if (maskData) { - text = maskString(0, txt, true); - text += clearString(text.length(), maxLength - text.length()); - } else { - text = txt.isEmpty() ? txt : txt.left(maxLength); - } - history.clear(); - modifiedState = undoState = 0; - cursor = (pos < 0 || pos > text.length()) ? text.length() : pos; - textDirty = (oldText != text); - finishChange(-1, true, edited); -} - - -void QLineEditPrivate::setCursorVisible(bool visible) -{ - Q_Q(QLineEdit); - if ((bool)cursorVisible == visible) - return; - if (cursorTimer) - cursorVisible = visible; - QRect r = cursorRect(); - if (maskData) - q->update(); - else - q->update(r); -} - -void QLineEditPrivate::addCommand(const Command& cmd) -{ - if (separator && undoState && history[undoState-1].type != Separator) { - history.resize(undoState + 2); - history[undoState++] = Command(Separator, cursor, 0, selstart, selend); - } else { - history.resize(undoState + 1); - } - separator = false; - history[undoState++] = cmd; -} - -void QLineEditPrivate::insert(const QString& s) -{ - if (hasSelectedText()) - addCommand(Command(SetSelection, cursor, 0, selstart, selend)); - if (maskData) { - QString ms = maskString(cursor, s); - for (int i = 0; i < (int) ms.length(); ++i) { - addCommand (Command(DeleteSelection, cursor+i, text.at(cursor+i), -1, -1)); - addCommand(Command(Insert, cursor+i, ms.at(i), -1, -1)); - } - text.replace(cursor, ms.length(), ms); - cursor += ms.length(); - cursor = nextMaskBlank(cursor); - textDirty = true; - } else { - int remaining = maxLength - text.length(); - if (remaining != 0) { - text.insert(cursor, s.left(remaining)); - for (int i = 0; i < (int) s.left(remaining).length(); ++i) - addCommand(Command(Insert, cursor++, s.at(i), -1, -1)); - textDirty = true; - } - } -} - -void QLineEditPrivate::del(bool wasBackspace) -{ - if (cursor < (int) text.length()) { - if (hasSelectedText()) - addCommand(Command(SetSelection, cursor, 0, selstart, selend)); - addCommand (Command((CommandType)((maskData?2:0)+(wasBackspace?Remove:Delete)), cursor, text.at(cursor), -1, -1)); - if (maskData) { - text.replace(cursor, 1, clearString(cursor, 1)); - addCommand(Command(Insert, cursor, text.at(cursor), -1, -1)); - } else { - text.remove(cursor, 1); - } - textDirty = true; - } -} - -void QLineEditPrivate::removeSelectedText() -{ - if (selstart < selend && selend <= (int) text.length()) { - separate(); - int i ; - addCommand(Command(SetSelection, cursor, 0, selstart, selend)); - if (selstart <= cursor && cursor < selend) { - // cursor is within the selection. Split up the commands - // to be able to restore the correct cursor position - for (i = cursor; i >= selstart; --i) - addCommand (Command(DeleteSelection, i, text.at(i), -1, 1)); - for (i = selend - 1; i > cursor; --i) - addCommand (Command(DeleteSelection, i - cursor + selstart - 1, text.at(i), -1, -1)); - } else { - for (i = selend-1; i >= selstart; --i) - addCommand (Command(RemoveSelection, i, text.at(i), -1, -1)); - } - if (maskData) { - text.replace(selstart, selend - selstart, clearString(selstart, selend - selstart)); - for (int i = 0; i < selend - selstart; ++i) - addCommand(Command(Insert, selstart + i, text.at(selstart + i), -1, -1)); - } else { - text.remove(selstart, selend - selstart); - } - if (cursor > selstart) - cursor -= qMin(cursor, selend) - selstart; - deselect(); - textDirty = true; - - // adjust hscroll to avoid gap - const int minRB = qMax(0, -q_func()->fontMetrics().minRightBearing()); - updateTextLayout(); - const QTextLine line = textLayout.lineAt(0); - const int widthUsed = qRound(line.naturalTextWidth()) + 1 + minRB; - hscroll = qMin(hscroll, widthUsed); - } -} - -void QLineEditPrivate::parseInputMask(const QString &maskFields) -{ - int delimiter = maskFields.indexOf(QLatin1Char(';')); - if (maskFields.isEmpty() || delimiter == 0) { - if (maskData) { - delete [] maskData; - maskData = 0; - maxLength = 32767; - setText(QString()); - } - return; - } - - if (delimiter == -1) { - blank = QLatin1Char(' '); - inputMask = maskFields; - } else { - inputMask = maskFields.left(delimiter); - blank = (delimiter + 1 < maskFields.length()) ? maskFields[delimiter + 1] : QLatin1Char(' '); - } - - // calculate maxLength / maskData length - maxLength = 0; - QChar c = 0; - for (int i=0; i<inputMask.length(); i++) { - c = inputMask.at(i); - if (i > 0 && inputMask.at(i-1) == QLatin1Char('\\')) { - maxLength++; - continue; - } - if (c != QLatin1Char('\\') && c != QLatin1Char('!') && - c != QLatin1Char('<') && c != QLatin1Char('>') && - c != QLatin1Char('{') && c != QLatin1Char('}') && - c != QLatin1Char('[') && c != QLatin1Char(']')) - maxLength++; - } - - delete [] maskData; - maskData = new MaskInputData[maxLength]; - - MaskInputData::Casemode m = MaskInputData::NoCaseMode; - c = 0; - bool s; - bool escape = false; - int index = 0; - for (int i = 0; i < inputMask.length(); i++) { - c = inputMask.at(i); - if (escape) { - s = true; - maskData[index].maskChar = c; - maskData[index].separator = s; - maskData[index].caseMode = m; - index++; - escape = false; - } else if (c == QLatin1Char('<')) { - m = MaskInputData::Lower; - } else if (c == QLatin1Char('>')) { - m = MaskInputData::Upper; - } else if (c == QLatin1Char('!')) { - m = MaskInputData::NoCaseMode; - } else if (c != QLatin1Char('{') && c != QLatin1Char('}') && c != QLatin1Char('[') && c != QLatin1Char(']')) { - switch (c.unicode()) { - case 'A': - case 'a': - case 'N': - case 'n': - case 'X': - case 'x': - case '9': - case '0': - case 'D': - case 'd': - case '#': - case 'H': - case 'h': - case 'B': - case 'b': - s = false; - break; - case '\\': - escape = true; - default: - s = true; - break; - } - - if (!escape) { - maskData[index].maskChar = c; - maskData[index].separator = s; - maskData[index].caseMode = m; - index++; - } - } - } - setText(text); -} - - -/* checks if the key is valid compared to the inputMask */ -bool QLineEditPrivate::isValidInput(QChar key, QChar mask) const -{ - switch (mask.unicode()) { - case 'A': - if (key.isLetter()) - return true; break; - case 'a': - if (key.isLetter() || key == blank) - return true; + case QEvent::FontChange: + d->control->setFont(font()); break; - case 'N': - if (key.isLetterOrNumber()) - return true; - break; - case 'n': - if (key.isLetterOrNumber() || key == blank) - return true; - break; - case 'X': - if (key.isPrint()) - return true; - break; - case 'x': - if (key.isPrint() || key == blank) - return true; - break; - case '9': - if (key.isNumber()) - return true; - break; - case '0': - if (key.isNumber() || key == blank) - return true; - break; - case 'D': - if (key.isNumber() && key.digitValue() > 0) - return true; - break; - case 'd': - if ((key.isNumber() && key.digitValue() > 0) || key == blank) - return true; - break; - case '#': - if (key.isNumber() || key == QLatin1Char('+') || key == QLatin1Char('-') || key == blank) - return true; - break; - case 'B': - if (key == QLatin1Char('0') || key == QLatin1Char('1')) - return true; - break; - case 'b': - if (key == QLatin1Char('0') || key == QLatin1Char('1') || key == blank) - return true; - break; - case 'H': - if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F'))) - return true; + case QEvent::StyleChange: + d->control->setPasswordCharacter(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter)); + update(); break; - case 'h': - if (key.isNumber() || (key >= QLatin1Char('a') && key <= QLatin1Char('f')) || (key >= QLatin1Char('A') && key <= QLatin1Char('F')) || key == blank) - return true; + case QEvent::LayoutDirectionChange: + d->control->setLayoutDirection(layoutDirection()); break; default: break; } - return false; -} - -bool QLineEditPrivate::hasAcceptableInput(const QString &str) const -{ -#ifndef QT_NO_VALIDATOR - QString textCopy = str; - int cursorCopy = cursor; - if (validator && validator->validate(textCopy, cursorCopy) - != QValidator::Acceptable) - return false; -#endif - - if (!maskData) - return true; - - if (str.length() != maxLength) - return false; - - for (int i=0; i < maxLength; ++i) { - if (maskData[i].separator) { - if (str.at(i) != maskData[i].maskChar) - return false; - } else { - if (!isValidInput(str.at(i), maskData[i].maskChar)) - return false; - } - } - return true; -} - -/* - Applies the inputMask on \a str starting from position \a pos in the mask. \a clear - specifies from where characters should be gotten when a separator is met in \a str - true means - that blanks will be used, false that previous input is used. - Calling this when no inputMask is set is undefined. -*/ -QString QLineEditPrivate::maskString(uint pos, const QString &str, bool clear) const -{ - if (pos >= (uint)maxLength) - return QString::fromLatin1(""); - - QString fill; - fill = clear ? clearString(0, maxLength) : text; - - int strIndex = 0; - QString s = QString::fromLatin1(""); - int i = pos; - while (i < maxLength) { - if (strIndex < str.length()) { - if (maskData[i].separator) { - s += maskData[i].maskChar; - if (str[(int)strIndex] == maskData[i].maskChar) - strIndex++; - ++i; - } else { - if (isValidInput(str[(int)strIndex], maskData[i].maskChar)) { - switch (maskData[i].caseMode) { - case MaskInputData::Upper: - s += str[(int)strIndex].toUpper(); - break; - case MaskInputData::Lower: - s += str[(int)strIndex].toLower(); - break; - default: - s += str[(int)strIndex]; - } - ++i; - } else { - // search for separator first - int n = findInMask(i, true, true, str[(int)strIndex]); - if (n != -1) { - if (str.length() != 1 || i == 0 || (i > 0 && (!maskData[i-1].separator || maskData[i-1].maskChar != str[(int)strIndex]))) { - s += fill.mid(i, n-i+1); - i = n + 1; // update i to find + 1 - } - } else { - // search for valid blank if not - n = findInMask(i, true, false, str[(int)strIndex]); - if (n != -1) { - s += fill.mid(i, n-i); - switch (maskData[n].caseMode) { - case MaskInputData::Upper: - s += str[(int)strIndex].toUpper(); - break; - case MaskInputData::Lower: - s += str[(int)strIndex].toLower(); - break; - default: - s += str[(int)strIndex]; - } - i = n + 1; // updates i to find + 1 - } - } - } - strIndex++; - } - } else - break; - } - - return s; -} - - - -/* - Returns a "cleared" string with only separators and blank chars. - Calling this when no inputMask is set is undefined. -*/ -QString QLineEditPrivate::clearString(uint pos, uint len) const -{ - if (pos >= (uint)maxLength) - return QString(); - - QString s; - int end = qMin((uint)maxLength, pos + len); - for (int i=pos; i<end; i++) - if (maskData[i].separator) - s += maskData[i].maskChar; - else - s += blank; - - return s; -} - -/* - Strips blank parts of the input in a QLineEdit when an inputMask is set, - separators are still included. Typically "127.0__.0__.1__" becomes "127.0.0.1". -*/ -QString QLineEditPrivate::stripString(const QString &str) const -{ - if (!maskData) - return str; - - QString s; - int end = qMin(maxLength, (int)str.length()); - for (int i=0; i < end; i++) - if (maskData[i].separator) - s += maskData[i].maskChar; - else - if (str[i] != blank) - s += str[i]; - - return s; -} - -/* searches forward/backward in maskData for either a separator or a blank */ -int QLineEditPrivate::findInMask(int pos, bool forward, bool findSeparator, QChar searchChar) const -{ - if (pos >= maxLength || pos < 0) - return -1; - - int end = forward ? maxLength : -1; - int step = forward ? 1 : -1; - int i = pos; - - while (i != end) { - if (findSeparator) { - if (maskData[i].separator && maskData[i].maskChar == searchChar) - return i; - } else { - if (!maskData[i].separator) { - if (searchChar.isNull()) - return i; - else if (isValidInput(searchChar, maskData[i].maskChar)) - return i; - } - } - i += step; - } - return -1; -} - -void QLineEditPrivate::undo(int until) -{ - if (!isUndoAvailable()) - return; - deselect(); - while (undoState && undoState > until) { - Command& cmd = history[--undoState]; - switch (cmd.type) { - case Insert: - text.remove(cmd.pos, 1); - cursor = cmd.pos; - break; - case SetSelection: - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - case Remove: - case RemoveSelection: - text.insert(cmd.pos, cmd.uc); - cursor = cmd.pos + 1; - break; - case Delete: - case DeleteSelection: - text.insert(cmd.pos, cmd.uc); - cursor = cmd.pos; - break; - case Separator: - continue; - } - if (until < 0 && undoState) { - Command& next = history[undoState-1]; - if (next.type != cmd.type && next.type < RemoveSelection - && (cmd.type < RemoveSelection || next.type == Separator)) - break; - } - } - textDirty = true; - emitCursorPositionChanged(); -} - -void QLineEditPrivate::redo() { - if (!isRedoAvailable()) - return; - deselect(); - while (undoState < (int)history.size()) { - Command& cmd = history[undoState++]; - switch (cmd.type) { - case Insert: - text.insert(cmd.pos, cmd.uc); - cursor = cmd.pos + 1; - break; - case SetSelection: - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - case Remove: - case Delete: - case RemoveSelection: - case DeleteSelection: - text.remove(cmd.pos, 1); - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - case Separator: - selstart = cmd.selStart; - selend = cmd.selEnd; - cursor = cmd.pos; - break; - } - if (undoState < (int)history.size()) { - Command& next = history[undoState]; - if (next.type != cmd.type && cmd.type < RemoveSelection && next.type != Separator - && (next.type < RemoveSelection || cmd.type == Separator)) - break; - } - } - textDirty = true; - emitCursorPositionChanged(); + QWidget::changeEvent(ev); } /*! diff --git a/src/gui/widgets/qlineedit.h b/src/gui/widgets/qlineedit.h index a97dc9a..daac6a7 100644 --- a/src/gui/widgets/qlineedit.h +++ b/src/gui/widgets/qlineedit.h @@ -268,6 +268,8 @@ private: Q_DECLARE_PRIVATE(QLineEdit) Q_PRIVATE_SLOT(d_func(), void _q_handleWindowActivate()) Q_PRIVATE_SLOT(d_func(), void _q_deleteSelected()) + Q_PRIVATE_SLOT(d_func(), void _q_textEdited(const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged(int, int)) #ifndef QT_NO_COMPLETER Q_PRIVATE_SLOT(d_func(), void _q_completionHighlighted(QString)) #endif diff --git a/src/gui/widgets/qlineedit_p.cpp b/src/gui/widgets/qlineedit_p.cpp new file mode 100644 index 0000000..0e39304 --- /dev/null +++ b/src/gui/widgets/qlineedit_p.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlineedit.h" +#include "qlineedit_p.h" + +#ifndef QT_NO_LINEEDIT + +#include "qabstractitemview.h" +#include "qclipboard.h" +#ifndef QT_NO_ACCESSIBILITY +#include "qaccessible.h" +#endif +#ifndef QT_NO_IM +#include "qinputcontext.h" +#include "qlist.h" +#endif + +QT_BEGIN_NAMESPACE + +const int QLineEditPrivate::verticalMargin(1); +const int QLineEditPrivate::horizontalMargin(2); + +int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const +{ + QRect cr = adjustedContentsRect(); + x-= cr.x() - hscroll + horizontalMargin; + return control->xToPos(x, betweenOrOn); +} + +QRect QLineEditPrivate::cursorRect() const +{ + QRect cr = adjustedContentsRect(); + int cix = cr.x() - hscroll + horizontalMargin; + QRect crect = control->cursorRect(); + crect.moveTo(crect.topLeft() + QPoint(cix, vscroll)); + return crect; +} + +#ifndef QT_NO_COMPLETER + +void QLineEditPrivate::_q_completionHighlighted(QString newText) +{ + Q_Q(QLineEdit); + if (control->completer()->completionMode() != QCompleter::InlineCompletion) { + q->setText(newText); + } else { + int c = control->cursor(); + QString text = control->text(); + q->setText(text.left(c) + newText.mid(c)); + control->moveCursor(control->end(), false); + control->moveCursor(c, true); + } +} + +#endif // QT_NO_COMPLETER + +void QLineEditPrivate::_q_clipboardChanged() +{ +} + +void QLineEditPrivate::_q_handleWindowActivate() +{ + Q_Q(QLineEdit); + if (!q->hasFocus() && control->hasSelectedText()) + control->deselect(); +} + +void QLineEditPrivate::_q_deleteSelected() +{ +} + +void QLineEditPrivate::_q_textEdited(const QString &text) +{ + Q_Q(QLineEdit); +#ifndef QT_NO_COMPLETER + if (control->completer() && + control->completer()->completionMode() != QCompleter::InlineCompletion) + control->complete(-1); // update the popup on cut/paste/del +#endif + emit q->textEdited(text); +} + +void QLineEditPrivate::_q_cursorPositionChanged(int from, int to) +{ + Q_Q(QLineEdit); + q->update(); + emit q->cursorPositionChanged(from, to); +} + +void QLineEditPrivate::init(const QString& txt) +{ + Q_Q(QLineEdit); + control = new QLineControl(txt); + QObject::connect(control, SIGNAL(textChanged(const QString &)), + q, SIGNAL(textChanged(const QString &))); + QObject::connect(control, SIGNAL(textEdited(const QString &)), + q, SLOT(_q_textEdited(const QString &))); + QObject::connect(control, SIGNAL(cursorPositionChanged(int, int)), + q, SLOT(_q_cursorPositionChanged(int, int))); + QObject::connect(control, SIGNAL(selectionChanged()), + q, SIGNAL(selectionChanged())); + QObject::connect(control, SIGNAL(accepted()), + q, SIGNAL(returnPressed())); + QObject::connect(control, SIGNAL(editingFinished()), + q, SIGNAL(editingFinished())); + + // for now, going completely overboard with updates. + QObject::connect(control, SIGNAL(selectionChanged()), + q, SLOT(update())); + + QObject::connect(control, SIGNAL(displayTextChanged(const QString &)), + q, SLOT(update())); + control->setPasswordCharacter(q->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter)); +#ifndef QT_NO_CURSOR + q->setCursor(Qt::IBeamCursor); +#endif + q->setFocusPolicy(Qt::StrongFocus); + q->setAttribute(Qt::WA_InputMethodEnabled); + // Specifies that this widget can use more, but is able to survive on + // less, horizontal space; and is fixed vertically. + q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit)); + q->setBackgroundRole(QPalette::Base); + q->setAttribute(Qt::WA_KeyCompression); + q->setMouseTracking(true); + q->setAcceptDrops(true); + + q->setAttribute(Qt::WA_MacShowFocusRect); +} + +QRect QLineEditPrivate::adjustedContentsRect() const +{ + Q_Q(const QLineEdit); + QStyleOptionFrameV2 opt; + q->initStyleOption(&opt); + QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q); + r.setX(r.x() + leftTextMargin); + r.setY(r.y() + topTextMargin); + r.setRight(r.right() - rightTextMargin); + r.setBottom(r.bottom() - bottomTextMargin); + return r; +} + +void QLineEditPrivate::setCursorVisible(bool visible) +{ + Q_Q(QLineEdit); + if ((bool)cursorVisible == visible) + return; + cursorVisible = visible; + QRect r = cursorRect(); + if (control->inputMask().isEmpty()) + q->update(r); + else + q->update(); +} + +void QLineEditPrivate::updatePasswordEchoEditing(bool editing) +{ + Q_Q(QLineEdit); + control->updatePasswordEchoEditing(editing); + q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod()); +} + +/*! + This function is not intended as polymorphic usage. Just a shared code + fragment that calls QInputContext::mouseHandler for this + class. +*/ +bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e ) +{ +#if !defined QT_NO_IM + Q_Q(QLineEdit); + if ( control->composeMode() ) { + int tmp_cursor = xToPos(e->pos().x()); + int mousePos = tmp_cursor - control->cursor(); + if ( mousePos < 0 || mousePos > control->preeditAreaText().length() ) { + mousePos = -1; + // don't send move events outside the preedit area + if ( e->type() == QEvent::MouseMove ) + return true; + } + + QInputContext *qic = q->inputContext(); + if ( qic ) + // may be causing reset() in some input methods + qic->mouseHandler(mousePos, e); + if (!control->preeditAreaText().isEmpty()) + return true; + } +#else + Q_UNUSED(e); +#endif + + return false; +} + +#ifndef QT_NO_DRAGANDDROP +void QLineEditPrivate::drag() +{ + Q_Q(QLineEdit); + dndTimer.stop(); + QMimeData *data = new QMimeData; + data->setText(control->selectedText()); + QDrag *drag = new QDrag(q); + drag->setMimeData(data); + Qt::DropAction action = drag->start(); + if (action == Qt::MoveAction && !control->isReadOnly() && drag->target() != q) + control->removeSelection(); +} + +#endif // QT_NO_DRAGANDDROP + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index 7a4ff26..230023d 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -65,6 +65,8 @@ #include "QtCore/qpointer.h" #include "QtGui/qlineedit.h" +#include "private/qlinecontrol_p.h" + QT_BEGIN_NAMESPACE class QLineEditPrivate : public QWidgetPrivate @@ -73,167 +75,64 @@ class QLineEditPrivate : public QWidgetPrivate public: QLineEditPrivate() - : cursor(0), preeditCursor(0), cursorTimer(0), frame(1), - cursorVisible(0), hideCursor(false), separator(0), readOnly(0), - dragEnabled(0), contextMenuEnabled(1), echoMode(0), textDirty(0), - selDirty(0), validInput(1), alignment(Qt::AlignLeading | Qt::AlignVCenter), ascent(0), - maxLength(32767), hscroll(0), vscroll(0), lastCursorPos(-1), maskData(0), - modifiedState(0), undoState(0), selstart(0), selend(0), userInput(false), - emitingEditingFinished(false), passwordEchoEditing(false) -#ifndef QT_NO_COMPLETER - , completer(0) -#endif - , leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0) - { - } + : control(0), frame(1), contextMenuEnabled(1), cursorVisible(0), + dragEnabled(0), hscroll(0), vscroll(0), + alignment(Qt::AlignLeading | Qt::AlignVCenter), + leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0) + { + } ~QLineEditPrivate() { - delete [] maskData; } + + QLineControl *control; + +#ifndef QT_NO_CONTEXTMENU + QPointer<QAction> selectAllAction; +#endif void init(const QString&); - QString text; - int cursor; - int preeditCursor; - int cursorTimer; // -1 for non blinking cursor. + int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; + QRect cursorRect() const; + void setCursorVisible(bool visible); + + void updatePasswordEchoEditing(bool); + + inline bool shouldEnableInputMethod() const + { + return !control->isReadOnly() && (control->echoMode() == QLineEdit::Normal || control->echoMode() == QLineEdit::PasswordEchoOnEdit); + } + QPoint tripleClick; QBasicTimer tripleClickTimer; uint frame : 1; + uint contextMenuEnabled : 1; uint cursorVisible : 1; - uint hideCursor : 1; // used to hide the cursor inside preedit areas - uint separator : 1; - uint readOnly : 1; uint dragEnabled : 1; - uint contextMenuEnabled : 1; - uint echoMode : 2; - uint textDirty : 1; - uint selDirty : 1; - uint validInput : 1; - uint alignment; - int ascent; - int maxLength; int hscroll; int vscroll; - int lastCursorPos; - -#ifndef QT_NO_CONTEXTMENU - QPointer<QAction> selectAllAction; -#endif + uint alignment; + static const int verticalMargin; + static const int horizontalMargin; - inline void emitCursorPositionChanged(); bool sendMouseEventToInputContext(QMouseEvent *e); - void finishChange(int validateFromState = -1, bool update = false, bool edited = true); - - QPointer<QValidator> validator; - struct MaskInputData { - enum Casemode { NoCaseMode, Upper, Lower }; - QChar maskChar; // either the separator char or the inputmask - bool separator; - Casemode caseMode; - }; - QString inputMask; - QChar blank; - MaskInputData *maskData; - inline int nextMaskBlank(int pos) { - int c = findInMask(pos, true, false); - separator |= (c != pos); - return (c != -1 ? c : maxLength); - } - inline int prevMaskBlank(int pos) { - int c = findInMask(pos, false, false); - separator |= (c != pos); - return (c != -1 ? c : 0); - } - - void setCursorVisible(bool visible); - - - // undo/redo handling - enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection }; - struct Command { - inline Command() {} - inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {} - uint type : 4; - QChar uc; - int pos, selStart, selEnd; - }; - int modifiedState; - int undoState; - QVector<Command> history; - void addCommand(const Command& cmd); - void insert(const QString& s); - void del(bool wasBackspace = false); - void remove(int pos); - - inline void separate() { separator = true; } - void undo(int until = -1); - void redo(); - inline bool isUndoAvailable() const { return !readOnly && undoState; } - inline bool isRedoAvailable() const { return !readOnly && undoState < (int)history.size(); } - - // selection - int selstart, selend; - inline bool allSelected() const { return !text.isEmpty() && selstart == 0 && selend == (int)text.length(); } - inline bool hasSelectedText() const { return !text.isEmpty() && selend > selstart; } - inline void deselect() { selDirty |= (selend > selstart); selstart = selend = 0; } - void removeSelectedText(); -#ifndef QT_NO_CLIPBOARD - void copy(bool clipboard = true) const; -#endif - inline bool inSelection(int x) const - { if (selstart >= selend) return false; - int pos = xToPos(x, QTextLine::CursorOnCharacter); return pos >= selstart && pos < selend; } - - // masking - void parseInputMask(const QString &maskFields); - bool isValidInput(QChar key, QChar mask) const; - bool hasAcceptableInput(const QString &text) const; - QString maskString(uint pos, const QString &str, bool clear = false) const; - QString clearString(uint pos, uint len) const; - QString stripString(const QString &str) const; - int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const; - - // input methods - bool composeMode() const { return !textLayout.preeditAreaText().isEmpty(); } - - // complex text layout - QTextLayout textLayout; - void updateTextLayout(); - void moveCursor(int pos, bool mark = false); - void setText(const QString& txt, int pos = -1, bool edited = true); - int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const; - QRect cursorRect() const; - bool fixup(); - QRect adjustedContentsRect() const; -#ifndef QT_NO_DRAGANDDROP - // drag and drop - QPoint dndPos; - QBasicTimer dndTimer; - void drag(); -#endif - + void _q_clipboardChanged(); void _q_handleWindowActivate(); void _q_deleteSelected(); - bool userInput; - bool emitingEditingFinished; - -#ifdef QT_KEYPAD_NAVIGATION - QBasicTimer deleteAllTimer; // keypad navigation - QString origText; -#endif - - bool passwordEchoEditing; - void updatePasswordEchoEditing(bool editing); + void _q_textEdited(const QString &); + void _q_cursorPositionChanged(int, int); #ifndef QT_NO_COMPLETER - QPointer<QCompleter> completer; - void complete(int key = -1); void _q_completionHighlighted(QString); - bool advanceToEnabledItem(int n); +#endif +#ifndef QT_NO_DRAGANDDROP + QPoint dndPos; + QBasicTimer dndTimer; + void drag(); #endif int leftTextMargin; diff --git a/src/gui/widgets/qvalidator.h b/src/gui/widgets/qvalidator.h index ce78959..5c27d1d 100644 --- a/src/gui/widgets/qvalidator.h +++ b/src/gui/widgets/qvalidator.h @@ -61,7 +61,7 @@ class Q_GUI_EXPORT QValidator : public QObject { Q_OBJECT public: - explicit QValidator(QObject * parent); + explicit QValidator(QObject * parent=0); ~QValidator(); enum State { @@ -100,7 +100,7 @@ class Q_GUI_EXPORT QIntValidator : public QValidator Q_PROPERTY(int top READ top WRITE setTop) public: - explicit QIntValidator(QObject * parent); + explicit QIntValidator(QObject * parent=0); QIntValidator(int bottom, int top, QObject * parent); ~QIntValidator(); diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index 2d809a1..8f24fac 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -30,6 +30,7 @@ HEADERS += \ widgets/qlcdnumber.h \ widgets/qlineedit.h \ widgets/qlineedit_p.h \ + widgets/qlinecontrol_p.h \ widgets/qmainwindow.h \ widgets/qmainwindowlayout_p.h \ widgets/qmdiarea.h \ @@ -101,7 +102,9 @@ SOURCES += \ widgets/qgroupbox.cpp \ widgets/qlabel.cpp \ widgets/qlcdnumber.cpp \ + widgets/qlineedit_p.cpp \ widgets/qlineedit.cpp \ + widgets/qlinecontrol.cpp \ widgets/qmainwindow.cpp \ widgets/qmainwindowlayout.cpp \ widgets/qmdiarea.cpp \ diff --git a/tests/auto/declarative/qmlbindengine/testtypes.h b/tests/auto/declarative/qmlbindengine/testtypes.h index df31f7a..f5b309e 100644 --- a/tests/auto/declarative/qmlbindengine/testtypes.h +++ b/tests/auto/declarative/qmlbindengine/testtypes.h @@ -8,8 +8,8 @@ class MyQmlObject : public QObject { Q_OBJECT - Q_PROPERTY(bool trueProperty READ trueProperty) - Q_PROPERTY(bool falseProperty READ falseProperty) + Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT) + Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged); public: @@ -64,14 +64,14 @@ QML_DECLARE_TYPE(MyQmlObject); class MyQmlContainer : public QObject { Q_OBJECT - Q_PROPERTY(QList<MyQmlContainer*>* children READ children) + Q_PROPERTY(QList<MyQmlObject*>* children READ children) public: MyQmlContainer() {} - QList<MyQmlContainer*> *children() { return &m_children; } + QList<MyQmlObject*> *children() { return &m_children; } private: - QList<MyQmlContainer*> m_children; + QList<MyQmlObject*> m_children; }; QML_DECLARE_TYPE(MyQmlContainer); @@ -94,8 +94,8 @@ public: class MyDefaultObject1 : public QObject { Q_OBJECT - Q_PROPERTY(int horseLegs READ horseLegs); - Q_PROPERTY(int antLegs READ antLegs); + Q_PROPERTY(int horseLegs READ horseLegs CONSTANT); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); public: int horseLegs() const { return 4; } int antLegs() const { return 6; } @@ -104,8 +104,8 @@ public: class MyDefaultObject2 : public QObject { Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int emuLegs READ emuLegs); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); + Q_PROPERTY(int emuLegs READ emuLegs CONSTANT); public: int antLegs() const { return 5; } // Had an accident int emuLegs() const { return 2; } @@ -114,8 +114,8 @@ public: class MyDefaultObject3 : public QObject { Q_OBJECT - Q_PROPERTY(int antLegs READ antLegs); - Q_PROPERTY(int humanLegs READ humanLegs); + Q_PROPERTY(int antLegs READ antLegs CONSTANT); + Q_PROPERTY(int humanLegs READ humanLegs CONSTANT); public: int antLegs() const { return 7; } // Mutant int humanLegs() const { return 2; } diff --git a/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt b/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt index b03f735..99f4c7c 100644 --- a/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt +++ b/tests/auto/declarative/qmlparser/duplicateIDs.errors.txt @@ -1 +1 @@ -3:5:id is not unique +3:19:id is not unique diff --git a/tests/auto/declarative/qmlparser/failingComponent.errors.txt b/tests/auto/declarative/qmlparser/failingComponent.errors.txt index 12fb4e7..a18f2e7 100644 --- a/tests/auto/declarative/qmlparser/failingComponent.errors.txt +++ b/tests/auto/declarative/qmlparser/failingComponent.errors.txt @@ -1,2 +1,2 @@ -1:-1:Unable to create type FailingComponent -2:5:Cannot assign value to non-existant property "a" +2:5:Cannot assign to non-existant property "a" diff --git a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt index a94b38e..25f22ce 100644 --- a/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt +++ b/tests/auto/declarative/qmlparser/fakeDotProperty.errors.txt @@ -1 +1 @@ -2:11:Cannot assign value to non-existant property "something" +2:5:Cannot nest non-QObject property "value" diff --git a/tests/auto/declarative/qmlparser/idProperty.txt b/tests/auto/declarative/qmlparser/idProperty.txt index 9c7d6fb..c3c2e50 100644 --- a/tests/auto/declarative/qmlparser/idProperty.txt +++ b/tests/auto/declarative/qmlparser/idProperty.txt @@ -2,6 +2,6 @@ MyContainer { property var object : MyObjectId MyTypeObject { - id: MyObjectId + id: "MyObjectId" } } diff --git a/tests/auto/declarative/qmlparser/invalidID.2.errors.txt b/tests/auto/declarative/qmlparser/invalidID.2.errors.txt index 6380750..9c54aab 100644 --- a/tests/auto/declarative/qmlparser/invalidID.2.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.2.errors.txt @@ -1,2 +1,2 @@ -1:1:"" is not a valid id +2:5:"" is not a valid object id diff --git a/tests/auto/declarative/qmlparser/invalidID.3.errors.txt b/tests/auto/declarative/qmlparser/invalidID.3.errors.txt index 05937f0..36cd489 100644 --- a/tests/auto/declarative/qmlparser/invalidID.3.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.3.errors.txt @@ -1 +1 @@ -2:5:The id property cannot be fetched +2:5:Invalid use of id property diff --git a/tests/auto/declarative/qmlparser/invalidID.4.errors.txt b/tests/auto/declarative/qmlparser/invalidID.4.errors.txt index 50c8960..bb811cf 100644 --- a/tests/auto/declarative/qmlparser/invalidID.4.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.4.errors.txt @@ -1 +1 @@ -3:5:The object id may only be set once +3:5:Invalid use of id property diff --git a/tests/auto/declarative/qmlparser/invalidID.errors.txt b/tests/auto/declarative/qmlparser/invalidID.errors.txt index eed1869..7cefb7e 100644 --- a/tests/auto/declarative/qmlparser/invalidID.errors.txt +++ b/tests/auto/declarative/qmlparser/invalidID.errors.txt @@ -1 +1 @@ -1:1:"1" is not a valid id +2:5:"1" is not a valid object id diff --git a/tests/auto/declarative/qmlparser/missingSignal.errors.txt b/tests/auto/declarative/qmlparser/missingSignal.errors.txt index 5c612cc..bcee331 100644 --- a/tests/auto/declarative/qmlparser/missingSignal.errors.txt +++ b/tests/auto/declarative/qmlparser/missingSignal.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "onClicked" +2:5:Cannot assign to non-existant property "onClicked" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt index e8f1a91..6f85946 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.1.errors.txt @@ -1 +1 @@ -1:15:Cannot assign value to non-existant property "something" +1:15:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt index c154f91..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.2.errors.txt @@ -1 +1 @@ -2:5:Cannot assign value to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt index a254d7d..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.3.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt index a254d7d..8d6dfb4 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.4.errors.txt @@ -1 +1 @@ -2:5:Cannot assign binding to non-existant property "something" +2:5:Cannot assign to non-existant property "something" diff --git a/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt b/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt index 3183b6d..fac833e 100644 --- a/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt +++ b/tests/auto/declarative/qmlparser/nonexistantProperty.6.errors.txt @@ -1 +1 @@ -2:-1:Cannot assign to default property +2:5:Cannot assign to non-existant default property diff --git a/tests/auto/declarative/qmlparser/readOnly.1.errors.txt b/tests/auto/declarative/qmlparser/readOnly.1.errors.txt index 89009ce..8608370 100644 --- a/tests/auto/declarative/qmlparser/readOnly.1.errors.txt +++ b/tests/auto/declarative/qmlparser/readOnly.1.errors.txt @@ -1 +1 @@ -2:21:Cannot assign value "Hello World" to the read-only property readOnlyString +2:21:Invalid property assignment: read-only property diff --git a/tests/auto/declarative/qmlparser/readOnly.2.errors.txt b/tests/auto/declarative/qmlparser/readOnly.2.errors.txt index ab27946..633d56f 100644 --- a/tests/auto/declarative/qmlparser/readOnly.2.errors.txt +++ b/tests/auto/declarative/qmlparser/readOnly.2.errors.txt @@ -1 +1 @@ -2:-1:Cannot assign a binding to read-only property "readOnlyString" +2:5:Invalid property assignment: read-only property diff --git a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp index cdc2a72..7023263 100644 --- a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp +++ b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp @@ -98,7 +98,7 @@ void tst_qmlparser::errors_data() QTest::newRow("nonExistantProperty.3") << "nonexistantProperty.3.txt" << "nonexistantProperty.3.errors.txt" << false; QTest::newRow("nonExistantProperty.4") << "nonexistantProperty.4.txt" << "nonexistantProperty.4.errors.txt" << false; QTest::newRow("nonExistantProperty.5") << "nonexistantProperty.5.txt" << "nonexistantProperty.5.errors.txt" << false; - QTest::newRow("nonExistantProperty.6") << "nonexistantProperty.6.txt" << "nonexistantProperty.6.errors.txt" << true; + QTest::newRow("nonExistantProperty.6") << "nonexistantProperty.6.txt" << "nonexistantProperty.6.errors.txt" << false; QTest::newRow("wrongType (string for int)") << "wrongType.1.txt" << "wrongType.1.errors.txt" << false; QTest::newRow("wrongType (int for bool)") << "wrongType.2.txt" << "wrongType.2.errors.txt" << false; @@ -117,7 +117,7 @@ void tst_qmlparser::errors_data() QTest::newRow("wrongType (int for string)") << "wrongType.14.txt" << "wrongType.14.errors.txt" << false; QTest::newRow("readOnly.1") << "readOnly.1.txt" << "readOnly.1.errors.txt" << false; - QTest::newRow("readOnly.2") << "readOnly.2.txt" << "readOnly.2.errors.txt" << true; + QTest::newRow("readOnly.2") << "readOnly.2.txt" << "readOnly.2.errors.txt" << false; QTest::newRow("listAssignment.1") << "listAssignment.1.txt" << "listAssignment.1.errors.txt" << false; QTest::newRow("listAssignment.2") << "listAssignment.2.txt" << "listAssignment.2.errors.txt" << false; @@ -344,8 +344,8 @@ void tst_qmlparser::dynamicProperties() QVERIFY(object != 0); QCOMPARE(object->property("intProperty"), QVariant(10)); QCOMPARE(object->property("boolProperty"), QVariant(false)); - QCOMPARE(object->property("doubleProperty"), QVariant((float)-10.1)); - QCOMPARE(object->property("realProperty"), QVariant((float)-19.9)); + QCOMPARE(object->property("doubleProperty"), QVariant(-10.1)); + QCOMPARE(object->property("realProperty"), QVariant((qreal)-19.9)); QCOMPARE(object->property("stringProperty"), QVariant("Hello World!")); QCOMPARE(object->property("colorProperty"), QVariant(QColor("red"))); QCOMPARE(object->property("dateProperty"), QVariant(QDate(1945, 9, 2))); diff --git a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt index a067ecb..7ccfc75 100644 --- a/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt +++ b/tests/auto/declarative/qmlparser/unsupportedProperty.errors.txt @@ -1 +1 @@ -2:5:Cannot assign value to property matrix of unknown type +2:13:Invalid property assignment: unknown type QVariant::QMatrix diff --git a/tests/auto/declarative/qmlparser/wrongType.1.errors.txt b/tests/auto/declarative/qmlparser/wrongType.1.errors.txt index 8976ee1..194da94 100644 --- a/tests/auto/declarative/qmlparser/wrongType.1.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.1.errors.txt @@ -1 +1 @@ -2:12:Cannot assign value "hello" to property value +2:12:Invalid property assignment: int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.10.errors.txt b/tests/auto/declarative/qmlparser/wrongType.10.errors.txt index 562cd6c..f391e2a 100644 --- a/tests/auto/declarative/qmlparser/wrongType.10.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.10.errors.txt @@ -1 +1 @@ -2:23:Cannot assign value "12" to property dateTimeProperty +2:23:Invalid property assignment: datetime expected diff --git a/tests/auto/declarative/qmlparser/wrongType.11.errors.txt b/tests/auto/declarative/qmlparser/wrongType.11.errors.txt index 24d27d5..9f5ebc9 100644 --- a/tests/auto/declarative/qmlparser/wrongType.11.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.11.errors.txt @@ -1 +1 @@ -2:20:Cannot assign value "apples" to property pointProperty +2:20:Invalid property assignment: point expected diff --git a/tests/auto/declarative/qmlparser/wrongType.12.errors.txt b/tests/auto/declarative/qmlparser/wrongType.12.errors.txt index b57e70e..4bbb2bf 100644 --- a/tests/auto/declarative/qmlparser/wrongType.12.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.12.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "red" to property sizeProperty +2:19:Invalid property assignment: size expected diff --git a/tests/auto/declarative/qmlparser/wrongType.13.errors.txt b/tests/auto/declarative/qmlparser/wrongType.13.errors.txt index 7ff4bf3..194da94 100644 --- a/tests/auto/declarative/qmlparser/wrongType.13.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.13.errors.txt @@ -1 +1 @@ -2:12:Cannot assign value "12" to property value +2:12:Invalid property assignment: int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.14.errors.txt b/tests/auto/declarative/qmlparser/wrongType.14.errors.txt index ec41e01..f90b8c6 100644 --- a/tests/auto/declarative/qmlparser/wrongType.14.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.14.errors.txt @@ -1 +1 @@ -2:23:Cannot assign value 10 to property stringProperty +2:21:Invalid property assignment: string expected diff --git a/tests/auto/declarative/qmlparser/wrongType.2.errors.txt b/tests/auto/declarative/qmlparser/wrongType.2.errors.txt index 301d258..4353165 100644 --- a/tests/auto/declarative/qmlparser/wrongType.2.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.2.errors.txt @@ -1 +1 @@ -2:14:Cannot assign value "5" to property enabled +2:14:Invalid property assignment: boolean expected diff --git a/tests/auto/declarative/qmlparser/wrongType.3.errors.txt b/tests/auto/declarative/qmlparser/wrongType.3.errors.txt index 3afcc2b..87b4eed 100644 --- a/tests/auto/declarative/qmlparser/wrongType.3.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.3.errors.txt @@ -1 +1 @@ -2:11:Cannot assign value "5,5x10" to property rect +2:11:Invalid property assignment: rect expected diff --git a/tests/auto/declarative/qmlparser/wrongType.4.errors.txt b/tests/auto/declarative/qmlparser/wrongType.4.errors.txt index 6bf88be..57a0744 100644 --- a/tests/auto/declarative/qmlparser/wrongType.4.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.4.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "InvalidEnumName" to property enumProperty +2:19:Invalid property assignment: unknown enumeration diff --git a/tests/auto/declarative/qmlparser/wrongType.5.errors.txt b/tests/auto/declarative/qmlparser/wrongType.5.errors.txt index 0e40d84..0023d1d 100644 --- a/tests/auto/declarative/qmlparser/wrongType.5.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.5.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "-13" to property uintProperty +2:19:Invalid property assignment: unsigned int expected diff --git a/tests/auto/declarative/qmlparser/wrongType.6.errors.txt b/tests/auto/declarative/qmlparser/wrongType.6.errors.txt index 9692997..06349e7 100644 --- a/tests/auto/declarative/qmlparser/wrongType.6.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.6.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "Hello" to property realProperty +2:19:Invalid property assignment: double expected diff --git a/tests/auto/declarative/qmlparser/wrongType.7.errors.txt b/tests/auto/declarative/qmlparser/wrongType.7.errors.txt index f44073a..e053f3b 100644 --- a/tests/auto/declarative/qmlparser/wrongType.7.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.7.errors.txt @@ -1 +1 @@ -2:20:Cannot assign value "12" to property colorProperty +2:20:Invalid property assignment: color expected diff --git a/tests/auto/declarative/qmlparser/wrongType.8.errors.txt b/tests/auto/declarative/qmlparser/wrongType.8.errors.txt index 8a45ffb..b11f92b 100644 --- a/tests/auto/declarative/qmlparser/wrongType.8.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.8.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "12" to property dateProperty +2:19:Invalid property assignment: date expected diff --git a/tests/auto/declarative/qmlparser/wrongType.9.errors.txt b/tests/auto/declarative/qmlparser/wrongType.9.errors.txt index cba3339..419a5ce 100644 --- a/tests/auto/declarative/qmlparser/wrongType.9.errors.txt +++ b/tests/auto/declarative/qmlparser/wrongType.9.errors.txt @@ -1 +1 @@ -2:19:Cannot assign value "12" to property timeProperty +2:19:Invalid property assignment: time expected diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index e9af477..c9d70e8 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -191,7 +191,7 @@ void QmlViewer::createMenu(QMenuBar *menu, QMenu *flatmenu) QAction *snapshotAction = new QAction(tr("&Take Snapsot\tF3"), parent); connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot())); recordMenu->addAction(snapshotAction); - + recordAction = new QAction(tr("Start Recording &Video\tF2"), parent); connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection())); recordMenu->addAction(recordAction); @@ -499,15 +499,6 @@ void QmlViewer::setRecordFile(const QString& f) record_file = f; } -bool QmlViewer::event(QEvent *event) -{ - if (event->type() == QEvent::PaletteChange) { - setupPalettes(); - return true; - } - return QWidget::event(event); -} - void QmlViewer::setRecordPeriod(int ms) { record_period = ms; diff --git a/tools/qmlviewer/qmlviewer.h b/tools/qmlviewer/qmlviewer.h index 365d6b2..4714bdc 100644 --- a/tools/qmlviewer/qmlviewer.h +++ b/tools/qmlviewer/qmlviewer.h @@ -61,7 +61,6 @@ public slots: protected: virtual void keyPressEvent(QKeyEvent *); virtual void timerEvent(QTimerEvent *); - virtual bool event(QEvent *event); void createMenu(QMenuBar *menu, QMenu *flatmenu); |