diff options
43 files changed, 1381 insertions, 607 deletions
diff --git a/demos/declarative/contacts/Button.qml b/demos/declarative/contacts/Button.qml new file mode 100644 index 0000000..d9f1236 --- /dev/null +++ b/demos/declarative/contacts/Button.qml @@ -0,0 +1,57 @@ +Item { + id: button + width: 30 + height: 30 + property var icon: "" + signal clicked + Rect { + id: buttonRect + anchors.fill: parent + color: "lightgreen" + radius: 5 + Image { + id: iconImage + source: button.icon + anchors.horizontalCenter: buttonRect.horizontalCenter + anchors.verticalCenter: buttonRect.verticalCenter + } + MouseRegion { + id: buttonMouseRegion + anchors.fill: buttonRect + onClicked: { button.clicked.emit() } + } + states: [ + State { + name: "pressed" + when: buttonMouseRegion.pressed == true + SetProperty { + target: buttonRect + property: "color" + value: "green" + } + } + ] + transitions: [ + Transition { + fromState: "*" + toState: "pressed" + ColorAnimation { + duration: 200 + } + }, + Transition { + fromState: "pressed" + toState: "*" + ColorAnimation { + duration: 1000 + } + } + ] + } + opacity: Behaviour { + NumericAnimation { + property: "opacity" + duration: 250 + } + } +} diff --git a/demos/declarative/contacts/Contact.qml b/demos/declarative/contacts/Contact.qml new file mode 100644 index 0000000..342c356 --- /dev/null +++ b/demos/declarative/contacts/Contact.qml @@ -0,0 +1,93 @@ +Item { + id: contactDetails + anchors.fill: parent + + property var contactId: "" + property var label: "" + property var phone: "" + property var email: "" + + onLabelChanged: { labelField.value = label } + onEmailChanged: { emailField.value = email } + onPhoneChanged: { phoneField.value = phone } + + resources: [ + SqlQuery { + id: updateContactQuery + connection: contactDatabase + query: "UPDATE contacts SET label = :l, email = :e, phone = :p WHERE recid = :r" + bindings: SqlBind { + name: ":r" + value: contactId + } + bindings: SqlBind { + name: ":l" + value: labelField.value + } + bindings: SqlBind { + name: ":e" + value: emailField.value + } + bindings: SqlBind { + name: ":p" + value: phoneField.value + } + }, + SqlQuery { + id: insertContactQuery + connection: contactDatabase + query: "INSERT INTO contacts (label, email, phone) VALUES(:l, :e, :p)" + bindings: SqlBind { + name: ":l" + value: labelField.value + } + bindings: SqlBind { + name: ":e" + value: emailField.value + } + bindings: SqlBind { + name: ":p" + value: phoneField.value + } + } + + ] + function update() { + updateContactQuery.exec(); + } + function insert() { + insertContactQuery.exec(); + } + VerticalLayout { + id: layout + anchors.fill: parent + spacing: 5 + margin: 5 + ContactField { + id: labelField + anchors.left: layout.left + anchors.leftMargin: 5 + anchors.right: layout.right + anchors.rightMargin: 5 + label: "Name" + } + ContactField { + id: phoneField + anchors.left: layout.left + anchors.leftMargin: 5 + anchors.right: layout.right + anchors.rightMargin: 5 + icon: "pics/phone.png" + label: "Phone" + } + ContactField { + id: emailField + anchors.left: layout.left + anchors.leftMargin: 5 + anchors.right: layout.right + anchors.rightMargin: 5 + icon: "pics/email.png" + label: "Email" + } + } +} diff --git a/demos/declarative/contacts/ContactField.qml b/demos/declarative/contacts/ContactField.qml new file mode 100644 index 0000000..3ce2c1a --- /dev/null +++ b/demos/declarative/contacts/ContactField.qml @@ -0,0 +1,60 @@ +Item { + id: contactField + clip: true + height: 30 + property var label: "Name" + property var icon: "pics/phone.png" + property var value: "" + onValueChanged: { fieldText.text=field.value } + RemoveButton { + id: removeButton + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + expandedWidth: contactField.width + onConfirmed: { print('Clear field text'); fieldText.text='' } + } + FieldText { + id: fieldText + width: contactField.width-70 + anchors.right: removeButton.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + label: contactField.label + text: contactField.value + onConfirmed: { contactField.value=fieldText.text } + } + Image { + anchors.right: fieldText.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + source: contactField.icon + } + states: [ + State { + name: "editingText" + when: fieldText.state == 'editing' + SetProperty { + target: removeButton.anchors + property: "rightMargin" + value: -35 + } + SetProperty { + target: fieldText + property: "width" + value: contactField.width + } + } + ] + transitions: [ + Transition { + fromState: "" + toState: "*" + reversible: true + NumericAnimation { + properties: "width,rightMargin" + duration: 200 + } + } + ] +} diff --git a/demos/declarative/contacts/FieldText.qml b/demos/declarative/contacts/FieldText.qml new file mode 100644 index 0000000..eb18ef2 --- /dev/null +++ b/demos/declarative/contacts/FieldText.qml @@ -0,0 +1,160 @@ +Rect { + id: fieldText + height: 30 + radius: 5 + color: "black" + property var text: "" + property var label: "" + onTextChanged: { reset() } + signal confirmed + resources: [ + Script { + + function edit() { + if (!contacts.mouseGrabbed) { + fieldText.state='editing'; + contacts.mouseGrabbed=true; + } + } + function confirm() { + fieldText.text = textEdit.text; + fieldText.state=''; + contacts.mouseGrabbed=false; + fieldText.confirmed.emit(); + } + function reset() { + textEdit.text = fieldText.text; + fieldText.state=''; + contacts.mouseGrabbed=false; + } + + } + ] + Image { + id: cancelIcon + width: 22 + height: 22 + anchors.right: parent.right + anchors.rightMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "pics/cancel.png" + opacity: 0 + } + Image { + id: confirmIcon + width: 22 + height: 22 + anchors.left: parent.left + anchors.leftMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "pics/ok.png" + opacity: 0 + } + TextEdit { + id: textEdit + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.verticalCenter: parent.verticalCenter + color: "white" + font.bold: true + readOnly: true + wrap: false + } + Text { + id: textLabel + x: 5 + width: parent.width-10 + anchors.verticalCenter: parent.verticalCenter + hAlign: "AlignHCenter" + color: contactDetails.state == "editing" ? "#505050" : "#AAAAAA" + font.italic: true + font.bold: true + text: fieldText.label + opacity: textEdit.text == '' ? 1 : 0 + opacity: Behaviour { + NumericAnimation { + property: "opacity" + duration: 250 + } + } + } + MouseRegion { + anchors.fill: cancelIcon + onClicked: { reset() } + } + MouseRegion { + anchors.fill: confirmIcon + onClicked: { confirm() } + } + MouseRegion { + id: editRegion + anchors.fill: textEdit + onClicked: { edit() } + } + states: [ + State { + name: "editing" + SetProperty { + target: confirmIcon + property: "opacity" + value: 1 + } + SetProperty { + target: cancelIcon + property: "opacity" + value: 1 + } + SetProperty { + target: fieldText + property: "color" + value: "white" + } + SetProperty { + target: textEdit + property: "color" + value: "black" + } + SetProperty { + target: textEdit + property: "readOnly" + value: false + } + SetProperty { + target: textEdit + property: "focus" + value: true + } + SetProperty { + target: editRegion + property: "opacity" + value: 0 + } + SetProperty { + target: textEdit.anchors + property: "leftMargin" + value: 34 + } + SetProperty { + target: textEdit.anchors + property: "rightMargin" + value: 34 + } + } + ] + transitions: [ + Transition { + fromState: "" + toState: "*" + reversible: true + NumericAnimation { + properties: "opacity,leftMargin,rightMargin" + duration: 200 + } + ColorAnimation { + duration: 150 + } + } + ] +} diff --git a/demos/declarative/contacts/RemoveButton.qml b/demos/declarative/contacts/RemoveButton.qml new file mode 100644 index 0000000..114db2e --- /dev/null +++ b/demos/declarative/contacts/RemoveButton.qml @@ -0,0 +1,120 @@ +Rect { + id: removeButton + width: 30 + height: 30 + color: "red" + radius: 5 + property var expandedWidth: 230 + signal confirmed + resources: [ + Script { + function toggle() { + if (removeButton.state == 'opened') { + removeButton.state = ''; + contacts.mouseGrabbed=false; + } else { + if (!contacts.mouseGrabbed) { + removeButton.state = 'opened'; + contacts.mouseGrabbed=true; + } + } + } + } + ] + Image { + id: trashIcon + width: 22 + height: 22 + anchors.right: parent.right + anchors.rightMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "pics/trash.png" + opacity: 1 + MouseRegion { + anchors.fill: parent + onClicked: { toggle() } + } + } + Image { + id: cancelIcon + width: 22 + height: 22 + anchors.right: parent.right + anchors.rightMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "pics/cancel.png" + opacity: 0 + MouseRegion { + anchors.fill: parent + onClicked: { toggle() } + } + } + Image { + id: confirmIcon + width: 22 + height: 22 + anchors.left: parent.left + anchors.leftMargin: 4 + anchors.verticalCenter: parent.verticalCenter + source: "pics/ok.png" + opacity: 0 + MouseRegion { + anchors.fill: parent + onClicked: { toggle(); removeButton.confirmed.emit() } + } + } + Text { + id: text + anchors.verticalCenter: parent.verticalCenter + anchors.left: confirmIcon.right + anchors.leftMargin: 4 + anchors.right: cancelIcon.left + anchors.rightMargin: 4 + font.bold: true + color: "white" + hAlign: "AlignHCenter" + text: "Remove" + opacity: 0 + } + states: [ + State { + name: "opened" + SetProperty { + target: removeButton + property: "width" + value: removeButton.expandedWidth + } + SetProperty { + target: text + property: "opacity" + value: 1 + } + SetProperty { + target: confirmIcon + property: "opacity" + value: 1 + } + SetProperty { + target: cancelIcon + property: "opacity" + value: 1 + } + SetProperty { + target: trashIcon + property: "opacity" + value: 0 + } + } + ] + transitions: [ + Transition { + fromState: "*" + toState: "opened" + reversible: true + NumericAnimation { + properties: "opacity,x,width" + duration: 200 + } + } + ] +} diff --git a/demos/declarative/contacts/SearchBar.qml b/demos/declarative/contacts/SearchBar.qml new file mode 100644 index 0000000..3ee2665 --- /dev/null +++ b/demos/declarative/contacts/SearchBar.qml @@ -0,0 +1,24 @@ +Rect { + id: searchBar + color: "white" + property var text: searchEdit.text + Image { + id: searchIcon + anchors.left: parent.left + anchors.leftMargin: 5 + anchors.verticalCenter: parent.verticalCenter + source: "pics/search.png" + } + TextEdit { + id: searchEdit + anchors.left: searchIcon.right + anchors.right: parent.right + anchors.leftMargin: 5 + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + readOnly: false + wrap: false + focus: true + text: "" + } +} diff --git a/demos/declarative/contacts/contacts.qml b/demos/declarative/contacts/contacts.qml new file mode 100644 index 0000000..ce5a2b5 --- /dev/null +++ b/demos/declarative/contacts/contacts.qml @@ -0,0 +1,266 @@ +Rect { + id: contacts + width: 240 + height: 320 + color: "black" + property var mode: "list" + property var mouseGrabbed: false + resources: [ + SqlConnection { + id: contactDatabase + name: "qmlConnection" + driver: "QSQLITE" + databaseName: "contacts.sqlite" + }, + SqlQuery { + id: contactList + connection: contactDatabase + query: "SELECT recid, label, email, phone FROM contacts WHERE lower(label) LIKE lower(:searchTerm) ORDER BY label, recid" + bindings: SqlBind { + name: ":searchTerm" + value: '%' + searchBar.text + '%' + } + }, + Component { + id: contactDelegate + Item { + id: wrapper + x: 0 + width: ListView.view.width + height: 34 + Text { + id: label + x: 40 + y: 12 + width: parent.width-30 + text: model.label + color: "white" + font.bold: true + children: [ + MouseRegion { + anchors.fill: parent + onClicked: { Details.qml = 'Contact.qml'; + wrapper.state='opened'; + contacts.mode = 'edit'; } + } + ] + } + Item { + id: Details + anchors.fill: wrapper + opacity: 0 + Bind { + target: Details.qmlItem + property: "contactId" + value: model.recid + } + Bind { + target: Details.qmlItem + property: "label" + value: model.label + } + Bind { + target: Details.qmlItem + property: "phone" + value: model.phone + } + Bind { + target: Details.qmlItem + property: "email" + value: model.email + } + } + states: [ + State { + name: "opened" + SetProperty { + target: wrapper + property: "height" + value: contactListView.height + } + SetProperty { + target: contactListView + property: "yPosition" + value: wrapper.y + } + SetProperty { + target: contactListView + property: "locked" + value: 1 + } + SetProperty { + target: label + property: "opacity" + value: 0 + } + SetProperty { + target: Details + property: "opacity" + value: 1 + } + } + ] + transitions: [ + Transition { + NumericAnimation { + duration: 500 + properties: "yPosition,height,opacity" + } + } + ] + Connection { + sender: confirmEditButton + signal: "clicked()" + script: { + if (wrapper.state == 'opened' && !contacts.mouseGrabbed) { + Details.qmlItem.update(); + wrapper.state = ''; + contacts.mode = 'list'; + contactList.exec(); + } + + } + } + Connection { + sender: cancelEditButton + signal: "clicked()" + script: { + if (wrapper.state == 'opened' && !contacts.mouseGrabbed) { + wrapper.state = ''; + contacts.mode = 'list'; + } + + } + } + } + } + ] + Button { + id: newContactButton + anchors.top: parent.top + anchors.topMargin: 5 + anchors.right: parent.right + anchors.rightMargin: 5 + icon: "pics/new.png" + onClicked: { print("open new contact edit"); newContactItem.label = ''; newContactItem.phone = ''; newContactItem.email = ''; contacts.mode = 'new' } + opacity: contacts.mode == 'list' ? 1 : 0 + } + Button { + id: confirmEditButton + anchors.top: parent.top + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 5 + icon: "pics/ok.png" + opacity: contacts.mode == 'list' || contacts.mouseGrabbed ? 0 : 1 + } + Button { + id: cancelEditButton + anchors.top: parent.top + anchors.topMargin: 5 + anchors.right: parent.right + anchors.rightMargin: 5 + icon: "pics/cancel.png" + opacity: contacts.mode == 'list' || contacts.mouseGrabbed ? 0 : 1 + } + ListView { + id: contactListView + anchors.left: parent.left + anchors.right: parent.right + anchors.top: cancelEditButton.bottom + anchors.bottom: searchBarWrapper.bottom + clip: true + model: contactList + delegate: contactDelegate + focus: false + } + Contact { + id: newContactItem + anchors.fill: contactListView + opacity: 0 + } + Connection { + sender: confirmEditButton + signal: "clicked()" + script: { + if (contacts.mode == 'new' && contacts.mouseGrabbed != 'true') { + newContactItem.insert(); + contacts.mode = 'list'; + contactList.exec(); + } + } + } + Connection { + sender: cancelEditButton + signal: "clicked()" + script: { + if (contacts.mode == 'new' && contacts.mouseGrabbed != 'true') { + contacts.mode = 'list'; + } + } + } + FocusRealm { + id: searchBarWrapper + height: 30 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottomMargin: 0 + focus: false + SearchBar { + id: searchBar + anchors.fill: parent + } + states: [ + State { + name: "searchHidden" + when: searchBar.text == '' || contacts.mode != 'list' + SetProperty { + target: searchBarWrapper.anchors + property: "bottomMargin" + value: -30 + } + } + ] + transitions: [ + Transition { + fromState: "*" + toState: "*" + NumericAnimation { + property: "bottomMargin" + duration: 250 + } + } + ] + } + KeyProxy { + focus: true + targets: { contacts.mode == "list" ? [searchBarWrapper, contactListView] : [contactListView]} + } + states: [ + State { + name: "editNewState" + when: contacts.mode == 'new' + SetProperty { + target: contactListView + property: "opacity" + value: 0 + } + SetProperty { + target: newContactItem + property: "opacity" + value: 1 + } + } + ] + transitions: [ + Transition { + fromState: "*" + toState: "*" + NumericAnimation { + property: "opacity" + duration: 500 + } + } + ] +} diff --git a/demos/declarative/contacts/contacts.sqlite b/demos/declarative/contacts/contacts.sqlite Binary files differnew file mode 100644 index 0000000..d33e0c7 --- /dev/null +++ b/demos/declarative/contacts/contacts.sqlite diff --git a/demos/declarative/contacts/pics/cancel.png b/demos/declarative/contacts/pics/cancel.png Binary files differnew file mode 100644 index 0000000..ecc9533 --- /dev/null +++ b/demos/declarative/contacts/pics/cancel.png diff --git a/demos/declarative/contacts/pics/email.png b/demos/declarative/contacts/pics/email.png Binary files differnew file mode 100644 index 0000000..04b3865 --- /dev/null +++ b/demos/declarative/contacts/pics/email.png diff --git a/demos/declarative/contacts/pics/new.png b/demos/declarative/contacts/pics/new.png Binary files differnew file mode 100644 index 0000000..c7ebac3 --- /dev/null +++ b/demos/declarative/contacts/pics/new.png diff --git a/demos/declarative/contacts/pics/ok.png b/demos/declarative/contacts/pics/ok.png Binary files differnew file mode 100644 index 0000000..5795f04 --- /dev/null +++ b/demos/declarative/contacts/pics/ok.png diff --git a/demos/declarative/contacts/pics/phone.png b/demos/declarative/contacts/pics/phone.png Binary files differnew file mode 100644 index 0000000..fc9c222 --- /dev/null +++ b/demos/declarative/contacts/pics/phone.png diff --git a/demos/declarative/contacts/pics/search.png b/demos/declarative/contacts/pics/search.png Binary files differnew file mode 100644 index 0000000..cc74e69 --- /dev/null +++ b/demos/declarative/contacts/pics/search.png diff --git a/demos/declarative/contacts/pics/trash.png b/demos/declarative/contacts/pics/trash.png Binary files differnew file mode 100644 index 0000000..2042595 --- /dev/null +++ b/demos/declarative/contacts/pics/trash.png diff --git a/examples/declarative/tutorials/contacts/Final/Button.qml b/examples/declarative/tutorials/contacts/Final/Button.qml deleted file mode 100644 index 14965b5..0000000 --- a/examples/declarative/tutorials/contacts/Final/Button.qml +++ /dev/null @@ -1,38 +0,0 @@ -<Item id="button" width="30" height="30"> - <properties> - <Property name="icon"/> - </properties> - <signals> - <Signal name="clicked"/> - </signals> - <Rect id="buttonRect" - anchors.fill="{parent}" - color="lightgreen" - radius="5"> - <Image id="iconImage" - source="{button.icon}" - anchors.horizontalCenter="{buttonRect.horizontalCenter}" - anchors.verticalCenter="{buttonRect.verticalCenter}"/> - <MouseRegion id="buttonMouseRegion" - anchors.fill="{buttonRect}" - onClicked="button.clicked.emit()"/> - <states> - <State name="pressed" when="{buttonMouseRegion.pressed == true}"> - <SetProperty target="{buttonRect}" property="color" value="green"/> - </State> - </states> - <transitions> - <Transition fromState="*" toState="pressed"> - <ColorAnimation duration="200"/> - </Transition> - <Transition fromState="pressed" toState="*"> - <ColorAnimation duration="1000"/> - </Transition> - </transitions> - </Rect> - <opacity> - <Behaviour> - <NumericAnimation property="opacity" duration="250"/> - </Behaviour> - </opacity> -</Item> diff --git a/examples/declarative/tutorials/contacts/Final/Contact.qml b/examples/declarative/tutorials/contacts/Final/Contact.qml deleted file mode 100644 index 679f4a8..0000000 --- a/examples/declarative/tutorials/contacts/Final/Contact.qml +++ /dev/null @@ -1,57 +0,0 @@ -<Item id="contactDetails" - anchors.fill="{parent}"> - <properties> - <Property name="contactid" value=""/> - <Property name="label" onValueChanged="labelField.value = label"/> - <Property name="phone" onValueChanged="phoneField.value = phone"/> - <Property name="email" onValueChanged="emailField.value = email"/> - </properties> - <signals> - <Signal name="update"/> - <Signal name="insert"/> - </signals> - <resources> - <SqlQuery id="updateContactQuery" connection="{contactDatabase}"> - <query>UPDATE contacts SET label = :l, email = :e, phone = :p WHERE recid = :r</query> - <bindings> - <SqlBind name=":r" value="{contactid}"/> - <SqlBind name=":l" value="{labelField.value}"/> - <SqlBind name=":e" value="{emailField.value}"/> - <SqlBind name=":p" value="{phoneField.value}"/> - </bindings> - </SqlQuery> - <SqlQuery id="insertContactQuery" connection="{contactDatabase}"> - <query>INSERT INTO contacts (label, email, phone) VALUES(:l, :e, :p)</query> - <bindings> - <SqlBind name=":l" value="{labelField.value}"/> - <SqlBind name=":e" value="{emailField.value}"/> - <SqlBind name=":p" value="{phoneField.value}"/> - </bindings> - </SqlQuery> - </resources> - <Connection sender="{contactDetails}" signal="update()"> - updateContactQuery.exec(); - </Connection> - <Connection sender="{contactDetails}" signal="insert()"> - insertContactQuery.exec(); - </Connection> - <VerticalLayout id="layout" - anchors.fill="{parent}" - spacing="5" - margin="5"> - <ContactField id="labelField" - anchors.left="{layout.left}" anchors.leftMargin="5" - anchors.right="{layout.right}" anchors.rightMargin="5" - label="Name"/> - <ContactField id="phoneField" - anchors.left="{layout.left}" anchors.leftMargin="5" - anchors.right="{layout.right}" anchors.rightMargin="5" - icon="../shared/pics/phone.png" - label="Phone"/> - <ContactField id="emailField" - anchors.left="{layout.left}" anchors.leftMargin="5" - anchors.right="{layout.right}" anchors.rightMargin="5" - icon="../shared/pics/email.png" - label="Email"/> - </VerticalLayout> -</Item> diff --git a/examples/declarative/tutorials/contacts/Final/ContactField.qml b/examples/declarative/tutorials/contacts/Final/ContactField.qml deleted file mode 100644 index 80ffd30..0000000 --- a/examples/declarative/tutorials/contacts/Final/ContactField.qml +++ /dev/null @@ -1,36 +0,0 @@ -<Item id="contactField" - clip="true" - height="30"> - <properties> - <Property name="label"/> - <Property name="icon"/> - <Property name="value" onValueChanged="fieldText.text=field.value"/> - </properties> - <RemoveButton id="removeButton" - anchors.right="{parent.right}" - anchors.top="{parent.top}" anchors.bottom="{parent.bottom}" - expandedWidth="{contactField.width}" - onConfirmed="print('Clear field text'); fieldText.text=''"/> - <FieldText id="fieldText" - width="{contactField.width-70}" - anchors.right="{removeButton.left}" anchors.rightMargin="5" - anchors.verticalCenter="{parent.verticalCenter}" - label="{contactField.label}" - text="{contactField.value}" - onConfirmed="contactField.value=fieldText.text"/> - <Image - anchors.right="{fieldText.left}" anchors.rightMargin="5" - anchors.verticalCenter="{parent.verticalCenter}" - source="{contactField.icon}"/> - <states> - <State name="editingText" when="{fieldText.state == 'editing'}"> - <SetProperty target="{removeButton.anchors}" property="rightMargin" value="-35"/> - <SetProperty target="{fieldText}" property="width" value="{contactField.width}"/> - </State> - </states> - <transitions> - <Transition fromState='' toState="*" reversible="true"> - <NumericAnimation properties="width,rightMargin" duration="200"/> - </Transition> - </transitions> -</Item> diff --git a/examples/declarative/tutorials/contacts/Final/ContactView2.qml b/examples/declarative/tutorials/contacts/Final/ContactView2.qml deleted file mode 100644 index da1e5db..0000000 --- a/examples/declarative/tutorials/contacts/Final/ContactView2.qml +++ /dev/null @@ -1,62 +0,0 @@ -<Item id="contacts"> - <resources> - <SqlConnection id="contactDatabase" name="qmlConnection" driver="QSQLITE" databaseName="../shared/contacts.sqlite"/> - <SqlQuery id="contactList" connection="{contactDatabase}"> - <query>SELECT recid AS contactid, label, email, phone FROM contacts ORDER BY label, recid</query> - </SqlQuery> - <Component id="contactDelegate"> - <Item id="wrapper" - x="0" - width="{ListView.view.width}" height="34"> - <Text id="label" - x="40" y="12" - width="{parent.width-30}" - text="{model.label}" - color="white" - font.bold="true"> - </Text> - <MouseRegion - anchors.fill="{label}" - onClicked="wrapper.state='opened'"/> - <Contact id="details" - anchors.fill="{parent}" - contactid="{model.contactid}" - label="{model.label}" - email="{model.email}" - phone="{model.phone}" - opacity="0"/> - <states> - <State name='opened'> - <SetProperty target="{wrapper}" property="height" value="{contactListView.height}"/> - <SetProperty target="{contactListView}" property="yPosition" value="{wrapper.y}"/> - <SetProperty target="{contactListView}" property="locked" value="1"/> - <SetProperty target="{label}" property="opacity" value="0"/> - <SetProperty target="{details}" property="opacity" value="1"/> - </State> - </states> - <transitions> - <Transition> - <NumericAnimation duration="500" properties="yPosition,height,opacity"/> - </Transition> - </transitions> - <Connection sender="{cancelEditButton}" signal="clicked()"> - if (wrapper.state == 'opened') { - wrapper.state = ''; - } - </Connection> - </Item> - </Component> - </resources> - <Button id="cancelEditButton" - anchors.top="{parent.top}" anchors.topMargin="5" - anchors.right="{parent.right}" anchors.rightMargin="5" - icon="../shared/pics/cancel.png"/> - <ListView id="contactListView" - anchors.left="{parent.left}" - anchors.right="{parent.right}" - anchors.top="{cancelEditButton.bottom}" - anchors.bottom="{parent.bottom}" - clip="true" - model="{contactList}" - delegate="{contactDelegate}"/> -</Item> diff --git a/examples/declarative/tutorials/contacts/Final/FieldText.qml b/examples/declarative/tutorials/contacts/Final/FieldText.qml deleted file mode 100644 index ad7669d..0000000 --- a/examples/declarative/tutorials/contacts/Final/FieldText.qml +++ /dev/null @@ -1,98 +0,0 @@ -<Rect id="fieldText" - height="30" - radius="5" - color="black"> - <properties> - <Property - name="text" - value="" - onValueChanged="reset()"/> - <Property - name="label" - value=""/> - </properties> - <signals> - <Signal name="confirmed"/> - </signals> - <resources> - <Script> - function edit() { - if (!contacts.mouseGrabbed) { - fieldText.state='editing'; - contacts.mouseGrabbed=true; - } - } - function confirm() { - fieldText.text = textEdit.text; - fieldText.state=''; - contacts.mouseGrabbed=false; - fieldText.confirmed.emit(); - } - function reset() { - textEdit.text = fieldText.text; - fieldText.state=''; - contacts.mouseGrabbed=false; - } - </Script> - </resources> - <Image id="cancelIcon" - width="22" height="22" - anchors.right="{parent.right}" anchors.rightMargin="4" - anchors.verticalCenter="{parent.verticalCenter}" - source="../shared/pics/cancel.png" - opacity="0"/> - <Image id="confirmIcon" - width="22" height="22" - anchors.left="{parent.left}" anchors.leftMargin="4" - anchors.verticalCenter="{parent.verticalCenter}" - source="../shared/pics/ok.png" - opacity="0"/> - <TextEdit id="textEdit" - anchors.left="{parent.left}" anchors.leftMargin="0" - anchors.right="{parent.right}" anchors.rightMargin="0" - anchors.verticalCenter="{parent.verticalCenter}" - color="white" - font.bold="true" - readOnly="true" - wrap="false" - /> - <Text id="textLabel" - x="5" width="{parent.width-10}" - anchors.verticalCenter="{parent.verticalCenter}" - hAlign="AlignHCenter" - color="#505050" - font.italic="true" - text="{fieldText.label}" - opacity="{textEdit.text == '' ? 1 : 0}"> - <opacity> - <Behaviour> - <NumericAnimation property="opacity" duration="250"/> - </Behaviour> - </opacity> - </Text> - <MouseRegion anchors.fill="{cancelIcon}" onClicked="reset()"/> - <MouseRegion anchors.fill="{confirmIcon}" onClicked="confirm()"/> - <MouseRegion - id="editRegion" - anchors.fill="{textEdit}" - onClicked="edit()"/> - <states> - <State name="editing"> - <SetProperty target="{confirmIcon}" property="opacity" value="1"/> - <SetProperty target="{cancelIcon}" property="opacity" value="1"/> - <SetProperty target="{fieldText}" property="color" value="white"/> - <SetProperty target="{textEdit}" property="color" value="black"/> - <SetProperty target="{textEdit}" property="readOnly" value="false"/> - <SetProperty target="{textEdit}" property="focus" value="true"/> - <SetProperty target="{editRegion}" property="opacity" value="0"/> - <SetProperty target="{textEdit.anchors}" property="leftMargin" value="34"/> - <SetProperty target="{textEdit.anchors}" property="rightMargin" value="34"/> - </State> - </states> - <transitions> - <Transition fromState='' toState="*" reversible="true"> - <NumericAnimation properties="opacity,leftMargin,rightMargin" duration="200"/> - <ColorAnimation duration="150"/> - </Transition> - </transitions> -</Rect> diff --git a/examples/declarative/tutorials/contacts/Final/RemoveButton.qml b/examples/declarative/tutorials/contacts/Final/RemoveButton.qml deleted file mode 100644 index b096bca..0000000 --- a/examples/declarative/tutorials/contacts/Final/RemoveButton.qml +++ /dev/null @@ -1,80 +0,0 @@ -<Rect id="removeButton" - width="30" height="30" - color="red" - radius="5"> - <properties> - <Property name="expandedWidth" value="230"/> - </properties> - <signals> - <Signal name="confirmed"/> - </signals> - <resources> - <Script> - function toggle() { - print('removeButton.toggle()'); - if (removeButton.state == 'opened') { - removeButton.state = ''; - contacts.mouseGrabbed=false; - } else { - if (!contacts.mouseGrabbed) { - removeButton.state = 'opened'; - contacts.mouseGrabbed=true; - } - } - } - </Script> - </resources> - <Image id="trashIcon" - width="22" height="22" - anchors.right="{parent.right}" anchors.rightMargin="4" - anchors.verticalCenter="{parent.verticalCenter}" - source="../shared/pics/trash.png" - opacity="1"> - <MouseRegion - anchors.fill="{parent}" - onClicked="toggle()"/> - </Image> - <Image id="cancelIcon" - width="22" height="22" - anchors.right="{parent.right}" anchors.rightMargin="4" - anchors.verticalCenter="{parent.verticalCenter}" - source="../shared/pics/cancel.png" - opacity="0"> - <MouseRegion - anchors.fill="{parent}" - onClicked="toggle()"/> - </Image> - <Image id="confirmIcon" - width="22" height="22" - anchors.left="{parent.left}" anchors.leftMargin="4" - anchors.verticalCenter="{parent.verticalCenter}" - source="../shared/pics/ok.png" - opacity="0"> - <MouseRegion - anchors.fill="{parent}" - onClicked="toggle(); removeButton.confirmed.emit()"/> - </Image> - <Text id="text" - anchors.verticalCenter="{parent.verticalCenter}" - anchors.left="{confirmIcon.right}" anchors.leftMargin="4" - anchors.right="{cancelIcon.left}" anchors.rightMargin="4" - font.bold="true" - color="white" - hAlign="AlignHCenter" - text="Remove" - opacity="0"/> - <states> - <State name="opened"> - <SetProperty target="{removeButton}" property="width" value="{removeButton.expandedWidth}"/> - <SetProperty target="{text}" property="opacity" value="1"/> - <SetProperty target="{confirmIcon}" property="opacity" value="1"/> - <SetProperty target="{cancelIcon}" property="opacity" value="1"/> - <SetProperty target="{trashIcon}" property="opacity" value="0"/> - </State> - </states> - <transitions> - <Transition fromState="*" toState="opened" reversible="true"> - <NumericAnimation properties="opacity,x,width" duration="200"/> - </Transition> - </transitions> -</Rect> diff --git a/examples/declarative/tutorials/contacts/Final/SearchBar.qml b/examples/declarative/tutorials/contacts/Final/SearchBar.qml deleted file mode 100644 index 3965e39..0000000 --- a/examples/declarative/tutorials/contacts/Final/SearchBar.qml +++ /dev/null @@ -1,18 +0,0 @@ -<Rect id="searchBar" - color="white"> - <properties> - <Property name="text" value="{searchEdit.text}"/> - </properties> - <Image id="searchIcon" - anchors.left="{parent.left}" anchors.leftMargin="5" - anchors.verticalCenter="{parent.verticalCenter}" - source="../shared/pics/search.png"/> - <TextEdit id="searchEdit" - anchors.left="{searchIcon.right}" anchors.right="{parent.right}" - anchors.leftMargin="5" anchors.rightMargin="5" - anchors.verticalCenter="{parent.verticalCenter}" - readOnly="false" - wrap="false" - focus="true"/> -</Rect> - diff --git a/examples/declarative/tutorials/contacts/Final/contacts.qml b/examples/declarative/tutorials/contacts/Final/contacts.qml deleted file mode 100644 index 8b0d6d0..0000000 --- a/examples/declarative/tutorials/contacts/Final/contacts.qml +++ /dev/null @@ -1,148 +0,0 @@ -<Rect id="contacts" - width="240" - height="320" - color="black"> - <properties> - <Property name="mode" value="list"/> - <Property name="mouseGrabbed" value="false"/> - </properties> - <resources> - <SqlConnection id="contactDatabase" name="qmlConnection" driver="QSQLITE" databaseName="../shared/contacts.sqlite"/> - <SqlQuery id="contactList" connection="{contactDatabase}"> - <query>SELECT recid AS contactid, label, email, phone FROM contacts WHERE lower(label) LIKE lower(:searchTerm) ORDER BY label, recid</query> - <bindings> - <SqlBind name=":searchTerm" value="{searchBar.text + '%' }"/> - </bindings> - </SqlQuery> - <Component id="contactDelegate"> - <Item id="wrapper" - x="0" - width="{ListView.view.width}" - height="34"> - <Text id="label" - x="40" y="12" - width="{parent.width-30}" - text="{model.label}" - color="white" - font.bold="true"> - <children> - <MouseRegion - anchors.fill="{parent}"> - <onClicked> - Details.qml = 'Contact.qml'; - wrapper.state='opened'; - contacts.mode = 'edit'; - </onClicked> - </MouseRegion> - </children> - </Text> - <Item id="Details" - anchors.fill="{wrapper}" - opacity="0"> - <Bind target="{Details.qmlItem}" property="contactid" value="{model.contactid}"/> - <Bind target="{Details.qmlItem}" property="label" value="{model.label}"/> - <Bind target="{Details.qmlItem}" property="phone" value="{model.phone}"/> - <Bind target="{Details.qmlItem}" property="email" value="{model.email}"/> - </Item> - <states> - <State name='opened'> - <SetProperty target="{wrapper}" property="height" value="{contactListView.height}"/> - <SetProperty target="{contactListView}" property="yPosition" value="{wrapper.y}"/> - <SetProperty target="{contactListView}" property="locked" value="1"/> - <SetProperty target="{label}" property="opacity" value="0"/> - <SetProperty target="{Details}" property="opacity" value="1"/> - </State> - </states> - <transitions> - <Transition> - <NumericAnimation duration="500" properties="yPosition,height,opacity"/> - </Transition> - </transitions> - <Connection sender="{cancelEditButton}" signal="clicked()"> - if (wrapper.state == 'opened' && !contacts.mouseGrabbed) { - wrapper.state = ''; - contacts.mode = 'list'; - } - </Connection> - <Connection sender="{confirmEditButton}" signal="clicked()"> - if (wrapper.state == 'opened' && !contacts.mouseGrabbed) { - print('confirm and close edit'); - Details.qmlItem.update.emit(); - wrapper.state = ''; - contacts.mode = 'list'; - contactList.exec(); - } - </Connection> - </Item> - </Component> - </resources> - <Button id="newContactButton" - anchors.top="{parent.top}" anchors.topMargin="5" - anchors.right="{parent.right}" anchors.rightMargin="5" - icon="../shared/pics/new.png" - onClicked="newContactItem.label = ''; newContactItem.phone = ''; newContactItem.email = ''; contacts.mode = 'new'" - opacity="{contacts.mode == 'list' ? 1 : 0}"/> - <Button id="confirmEditButton" - anchors.top="{parent.top}" anchors.topMargin="5" - anchors.left="{parent.left}" anchors.leftMargin="5" - icon="../shared/pics/ok.png" - opacity="{contacts.mode == 'list' || contacts.mouseGrabbed ? 0 : 1}"/> - <Button id="cancelEditButton" - anchors.top="{parent.top}" anchors.topMargin="5" - anchors.right="{parent.right}" anchors.rightMargin="5" - icon="../shared/pics/cancel.png" - opacity="{contacts.mode == 'list' || contacts.mouseGrabbed ? 0 : 1}"/> - <ListView id="contactListView" - anchors.left="{parent.left}" - anchors.right="{parent.right}" - anchors.top="{cancelEditButton.bottom}" - anchors.bottom="{searchBarWrapper.bottom}" - clip="true" - model="{contactList}" - delegate="{contactDelegate}" - focus="{contacts.mode != 'list'}"/> - <Contact id="newContactItem" - anchors.fill="{contactListView}" - opacity="0"/> - <Connection sender="{confirmEditButton}" signal="clicked()"> - if (contacts.mode == 'new' && contacts.mouseGrabbed != 'true') { - newContactItem.insert.emit(); - contacts.mode = 'list'; - contactList.exec(); - } - </Connection> - <Connection sender="{cancelEditButton}" signal="clicked()"> - if (contacts.mode == 'new' && contacts.mouseGrabbed != 'true') { - contacts.mode = 'list'; - } - </Connection> - <FocusRealm id="searchBarWrapper" - height="30" - anchors.bottom="{parent.bottom}" - anchors.left="{parent.left}" anchors.right="{parent.right}" - anchors.bottomMargin="0" - focus="{contacts.mode == 'list'}"> - <SearchBar id="searchBar" anchors.fill="{parent}"/> - <states> - <State name="searchHidden" when="{searchBar.text == '' || contacts.mode != 'list'}"> - <SetProperty target="{searchBarWrapper.anchors}" property="bottomMargin" value="-30"/> - </State> - </states> - <transitions> - <Transition fromState="*" toState="*"> - <NumericAnimation property="bottomMargin" duration="250"/> - </Transition> - </transitions> - </FocusRealm> - <states> - <State name="editNewState" when="{contacts.mode == 'new'}"> - <SetProperty target="{contactListView}" property="opacity" value="0"/> - <SetProperty target="{newContactItem}" property="opacity" value="1"/> - </State> - </states> - <transitions> - <Transition fromState="*" toState="*"> - <NumericAnimation property="opacity" duration="500"/> - </Transition> - </transitions> -</Rect> diff --git a/src/declarative/canvas/qsimplecanvas.cpp b/src/declarative/canvas/qsimplecanvas.cpp index ce02a4c..e1dd0e8 100644 --- a/src/declarative/canvas/qsimplecanvas.cpp +++ b/src/declarative/canvas/qsimplecanvas.cpp @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(fullUpdate, GFX_CANVAS_FULL_UPDATE); DEFINE_BOOL_CONFIG_OPTION(continuousUpdate, GFX_CANVAS_CONTINUOUS_UPDATE); -DEFINE_BOOL_CONFIG_OPTION(useGraphicsView, QFX_USE_GRAPHICSVIEW); +DEFINE_BOOL_CONFIG_OPTION(useSimpleCanvas, QFX_USE_SIMPLECANVAS); template<class T, int s = 60> class CircularList @@ -556,7 +556,7 @@ QSimpleCanvas::QSimpleCanvas(CanvasMode mode, QWidget *parent) QSimpleCanvas::QSimpleCanvas(QWidget *parent) : QWidget(parent), d(new QSimpleCanvasPrivate(this)) { - d->init(useGraphicsView()?SimpleCanvas:GraphicsView); + d->init(useSimpleCanvas()?SimpleCanvas:GraphicsView); } void QSimpleCanvasPrivate::init(QSimpleCanvas::CanvasMode mode) @@ -904,6 +904,13 @@ QSimpleCanvasItem *QSimpleCanvas::activeFocusPanel() const return d->focusPanels.top(); } +QSimpleCanvasItem *QSimpleCanvas::focusItem(QSimpleCanvasItem *item) const +{ + while (item && d->focusPanelData.contains(item)) + item = d->focusPanelData.value(item); + return item; +} + bool QSimpleCanvas::event(QEvent *e) { if (e->type() == QEvent::User && d->isSimpleCanvas()) { diff --git a/src/declarative/canvas/qsimplecanvas.h b/src/declarative/canvas/qsimplecanvas.h index a35cbf5..20dab28 100644 --- a/src/declarative/canvas/qsimplecanvas.h +++ b/src/declarative/canvas/qsimplecanvas.h @@ -141,6 +141,8 @@ public: void checkState(); QSimpleCanvasItem *focusItem() const; + QSimpleCanvasItem *focusItem(QSimpleCanvasItem *item) const; + QSimpleCanvasItem *activeFocusPanel() const; QImage asImage() const; diff --git a/src/declarative/canvas/qsimplecanvas_software.cpp b/src/declarative/canvas/qsimplecanvas_software.cpp index c130a62..194024d 100644 --- a/src/declarative/canvas/qsimplecanvas_software.cpp +++ b/src/declarative/canvas/qsimplecanvas_software.cpp @@ -172,6 +172,11 @@ void QSimpleCanvasItemPrivate::paint(QPainter &p) if (clip) p.restore(); + + if (debuggerStatus && debuggerStatus->selected) { + p.setWorldTransform(data()->transformActive); + p.fillRect(q->boundingRect(), QColor(255, 0, 0, 80)); + } } void QSimpleCanvasItemPrivate::paintChild(QPainter &p, QSimpleCanvasItem *c) diff --git a/src/declarative/canvas/qsimplecanvasitem.cpp b/src/declarative/canvas/qsimplecanvasitem.cpp index 62a44e4..ba33a41 100644 --- a/src/declarative/canvas/qsimplecanvasitem.cpp +++ b/src/declarative/canvas/qsimplecanvasitem.cpp @@ -1380,6 +1380,14 @@ QSimpleCanvasItem::operator QGraphicsItem *() return d->graphicsItem; } +QSimpleCanvasItem::operator QmlDebuggerStatus *() +{ + Q_D(QSimpleCanvasItem); + if(!d->debuggerStatus) + d->debuggerStatus = new QSimpleCanvasItemDebuggerStatus(this); + return d->debuggerStatus; +} + QPointF QSimpleCanvasItemPrivate::transformOrigin() const { Q_Q(const QSimpleCanvasItem); diff --git a/src/declarative/canvas/qsimplecanvasitem.h b/src/declarative/canvas/qsimplecanvasitem.h index 83f19c3..cab8492 100644 --- a/src/declarative/canvas/qsimplecanvasitem.h +++ b/src/declarative/canvas/qsimplecanvasitem.h @@ -42,10 +42,11 @@ #ifndef QSIMPLECANVASITEM_H #define QSIMPLECANVASITEM_H -#include <qfxglobal.h> -#include <qsimplecanvas.h> -#include <QObject> -#include <QGraphicsItem> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qmldebuggerstatus.h> +#include <QtDeclarative/qsimplecanvas.h> +#include <QtCore/qobject.h> +#include <QtGui/qgraphicsitem.h> class QPainter; QT_BEGIN_HEADER @@ -70,6 +71,7 @@ class Q_DECLARATIVE_EXPORT QSimpleCanvasItem : public QObject { Q_OBJECT Q_CAST_INTERFACES(QGraphicsItem) + Q_CAST_INTERFACES(QmlDebuggerStatus) Q_DECLARE_PRIVATE(QSimpleCanvasItem) Q_ENUMS(TransformOrigin) Q_PROPERTY(TransformOrigin transformOrigin READ transformOrigin WRITE setTransformOrigin); @@ -94,6 +96,7 @@ public: QSimpleCanvasItem(QSimpleCanvasItem *parent=0); virtual ~QSimpleCanvasItem(); operator QGraphicsItem *(); + operator QmlDebuggerStatus *(); bool clip() const; void setClip(bool); diff --git a/src/declarative/canvas/qsimplecanvasitem_p.h b/src/declarative/canvas/qsimplecanvasitem_p.h index 27a75bd..cfe0bba 100644 --- a/src/declarative/canvas/qsimplecanvasitem_p.h +++ b/src/declarative/canvas/qsimplecanvasitem_p.h @@ -110,6 +110,22 @@ public: #endif }; +class QSimpleCanvasItemDebuggerStatus : public QmlDebuggerStatus +{ +public: + QSimpleCanvasItemDebuggerStatus(QSimpleCanvasItem *i) + : item(i), selected(false) {} + + virtual void setSelectedState(bool state) + { + selected = state; + item->update(); + } + + QSimpleCanvasItem *item; + bool selected; +}; + class QSimpleCanvasFilter; class QGraphicsQSimpleCanvasItem; class QSimpleCanvasItemPrivate : public QObjectPrivate @@ -117,7 +133,8 @@ class QSimpleCanvasItemPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QSimpleCanvasItem); public: QSimpleCanvasItemPrivate() - : parent(0), canvas(0), filter(0), clip(QSimpleCanvasItem::NoClip), + : parent(0), canvas(0), debuggerStatus(0), filter(0), + clip(QSimpleCanvasItem::NoClip), origin(QSimpleCanvasItem::TopLeft), options(QSimpleCanvasItem::NoOption), focusable(false), wantsActiveFocusPanelPendingCanvas(false), hasBeenActiveFocusPanel(false), @@ -127,12 +144,16 @@ public: { } - virtual ~QSimpleCanvasItemPrivate() {} + virtual ~QSimpleCanvasItemPrivate() + { + if(debuggerStatus) delete debuggerStatus; + } QSimpleCanvasItem *parent; QSimpleCanvas *canvas; QList<QSimpleCanvasItem *> children; + QSimpleCanvasItemDebuggerStatus *debuggerStatus; QSimpleCanvasFilter *filter; QSimpleCanvasItem::ClipType clip:3; diff --git a/src/declarative/debugger/debugger.pri b/src/declarative/debugger/debugger.pri index ea5219a..31a1d5b 100644 --- a/src/declarative/debugger/debugger.pri +++ b/src/declarative/debugger/debugger.pri @@ -1,3 +1,7 @@ -SOURCES += debugger/qmldebugger.cpp +SOURCES += debugger/qmldebugger.cpp \ + debugger/qmldebuggerstatus.cpp \ + debugger/qmlpropertyview.cpp -HEADERS += debugger/qmldebugger.h +HEADERS += debugger/qmldebugger.h \ + debugger/qmldebuggerstatus.h \ + debugger/qmlpropertyview_p.h diff --git a/src/declarative/debugger/qmldebugger.cpp b/src/declarative/debugger/qmldebugger.cpp index 033a15f..634385b 100644 --- a/src/declarative/debugger/qmldebugger.cpp +++ b/src/declarative/debugger/qmldebugger.cpp @@ -43,7 +43,10 @@ #include <QtGui/qtreewidget.h> #include <QtGui/qboxlayout.h> #include <QtGui/qplaintextedit.h> +#include <QTextBlock> +#include <QtGui/qtabwidget.h> #include <QtDeclarative/qmlbindablevalue.h> +#include <QtDeclarative/qmldebuggerstatus.h> #include <private/qmlboundsignal_p.h> #include <private/qmlcontext_p.h> #include <private/qmlengine_p.h> @@ -52,10 +55,13 @@ #include <QtCore/qurl.h> #include <QtGui/qsplitter.h> #include <QtGui/qpushbutton.h> +#include <QtGui/qtablewidget.h> #include <QtGui/qevent.h> +#include <private/qmlpropertyview_p.h> QmlDebugger::QmlDebugger(QWidget *parent) -: QWidget(parent), m_tree(0) +: QWidget(parent), m_tree(0), m_warnings(0), m_watchers(0), m_properties(0), + m_text(0) { QHBoxLayout *layout = new QHBoxLayout; setLayout(layout); @@ -69,18 +75,37 @@ QmlDebugger::QmlDebugger(QWidget *parent) splitter->addWidget(treeWid); m_tree = new QTreeWidget(treeWid); + m_tree->setSelectionMode(QTreeWidget::NoSelection); m_tree->setHeaderHidden(true); - QObject::connect(m_tree, SIGNAL(itemPressed(QTreeWidgetItem *, int)), this, SLOT(itemPressed(QTreeWidgetItem *))); + QObject::connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(itemClicked(QTreeWidgetItem *))); + QObject::connect(m_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem *))); vlayout->addWidget(m_tree); QPushButton *pb = new QPushButton("Refresh", treeWid); QObject::connect(pb, SIGNAL(clicked()), this, SLOT(refresh())); vlayout->addWidget(pb); + QTabWidget *tabs = new QTabWidget(this); + m_text = new QPlainTextEdit(this); m_text->setReadOnly(true); - splitter->addWidget(m_text); + tabs->addTab(m_text, "File"); + + m_warnings = new QTreeWidget(this); + m_warnings->setHeaderHidden(true); + tabs->addTab(m_warnings, "Warnings"); + + m_watchers = new QTableWidget(this); + m_watchers->setSelectionMode(QTableWidget::NoSelection); + tabs->addTab(m_watchers, "Watchers"); + + m_properties = new QmlPropertyView(this); + tabs->addTab(m_properties, "Properties"); + + splitter->addWidget(tabs); splitter->setStretchFactor(1, 2); + + setGeometry(0, 100, 800, 600); } class QmlDebuggerItem : public QTreeWidgetItem @@ -100,34 +125,53 @@ public: int endLine; QUrl url; + QPointer<QObject> object; QPointer<QmlBindableValue> bindableValue; }; -void QmlDebugger::itemPressed(QTreeWidgetItem *i) +void QmlDebugger::itemDoubleClicked(QTreeWidgetItem *i) { QmlDebuggerItem *item = static_cast<QmlDebuggerItem *>(i); if(item->bindableValue) { - QString str; - QmlExpressionPrivate *p = item->bindableValue->d; - if(p->log) { - QString str; - QDebug d(&str); - for(int ii = 0; ii < p->log->count(); ++ii) { - d << p->log->at(ii).result() << "\n"; - QStringList warnings = p->log->at(ii).warnings(); - foreach(const QString &warning, warnings) - d << " " << warning << "\n"; - } - m_text->setPlainText(str); + if(m_watchedIds.contains(p->id)) { + m_watchedIds.remove(p->id); + item->setForeground(0, Qt::green); } else { - m_text->setPlainText("No history"); + m_watchedIds.insert(p->id); + item->setForeground(0, QColor("purple")); } - } else if(item->url.scheme() == QLatin1String("file")) { + } +} + +void QmlDebugger::itemClicked(QTreeWidgetItem *i) +{ + QmlDebuggerItem *item = static_cast<QmlDebuggerItem *>(i); + + if(m_selectedItem) { + QmlDebuggerStatus *debug = + qobject_cast<QmlDebuggerStatus *>(m_selectedItem); + Q_ASSERT(debug); + debug->setSelectedState(false); + m_selectedItem = 0; + } + + if(item->object) { + QmlDebuggerStatus *debug = + qobject_cast<QmlDebuggerStatus *>(item->object); + if(debug) { + debug->setSelectedState(true); + m_selectedItem = item->object; + } + + m_properties->setObject(item->object); + } + + if(item->url.scheme() == QLatin1String("file")) { QString f = item->url.toLocalFile(); QFile file(f); file.open(QIODevice::ReadOnly); @@ -141,17 +185,11 @@ void QmlDebugger::itemPressed(QTreeWidgetItem *i) QTextDocument *document = m_text->document(); QTextCharFormat format; format.setForeground(Qt::lightGray); - { - QTextCursor cursor(document); - cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor, item->startLine - 1); - cursor.setCharFormat(format); - } { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, item->endLine); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->endLine); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.setCharFormat(format); } @@ -159,31 +197,89 @@ void QmlDebugger::itemPressed(QTreeWidgetItem *i) { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.setCharFormat(QTextCharFormat()); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor, item->startLine - 1); + cursor.setCharFormat(format); } { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, item->startLine - 1); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->startLine - 1); m_text->setTextCursor(cursor); m_text->centerCursor(); } + + } } } -static bool makeItem(QObject *obj, QmlDebuggerItem *item) +bool QmlDebugger::makeItem(QObject *obj, QmlDebuggerItem *item) { bool rv = true; QString text; + item->object = obj; + if(QmlBindableValue *bv = qobject_cast<QmlBindableValue *>(obj)) { + QmlExpressionPrivate *p = bv->d; + text = bv->property().name() + ": " + bv->expression(); - item->setForeground(0, Qt::green); + bool watched = m_watchedIds.contains(p->id); + if(watched) + item->setForeground(0, QColor("purple")); + else + item->setForeground(0, Qt::green); item->bindableValue = bv; + + if(p->log) { + QTreeWidgetItem *warningItem = 0; + + int column = m_watchers->columnCount(); + + if(watched) { + m_watchers->insertColumn(column); + QTableWidgetItem *tableheader = new QTableWidgetItem; + tableheader->setText(bv->expression()); + tableheader->setToolTip(bv->expression()); + m_watchers->setHorizontalHeaderItem(column, tableheader); + } + + for(int ii = 0; ii < p->log->count(); ++ii) { + const QmlExpressionLog &log = p->log->at(ii); + + QString variant; QDebug d(&variant); d << log.result(); + if(watched) { + QString str = log.result().toString(); + if(str.isEmpty()) + str = variant; + m_expressions << qMakePair(log.time(), qMakePair(column, str)); + } + + if(!log.warnings().isEmpty()) { + + if(!warningItem) { + warningItem = new QTreeWidgetItem(m_warnings); + warningItem->setText(0, bv->expression()); + } + + QTreeWidgetItem *entry = new QTreeWidgetItem(warningItem); + entry->setExpanded(true); + + entry->setText(0, variant); + + foreach(const QString &warning, log.warnings()) { + QTreeWidgetItem *w = new QTreeWidgetItem(entry); + w->setText(0, warning); + } + } + + } + + } + } else if(QmlBoundSignal *bs = qobject_cast<QmlBoundSignal *>(obj)) { QMetaMethod method = obj->parent()->metaObject()->method(bs->index()); QByteArray sig = method.signature(); @@ -237,7 +333,7 @@ static bool makeItem(QObject *obj, QmlDebuggerItem *item) return rv; } -static void buildTree(QObject *obj, QmlDebuggerItem *parent) +void QmlDebugger::buildTree(QObject *obj, QmlDebuggerItem *parent) { QObjectList children = obj->children(); @@ -253,9 +349,20 @@ void QmlDebugger::refresh() setDebugObject(m_object); } +bool operator<(const QPair<quint32, QPair<int, QString> > &lhs, + const QPair<quint32, QPair<int, QString> > &rhs) +{ + return lhs.first < rhs.first; +} + void QmlDebugger::setDebugObject(QObject *obj) { m_tree->clear(); + m_warnings->clear(); + m_watchers->clear(); + m_watchers->setColumnCount(0); + m_watchers->setRowCount(0); + m_expressions.clear(); m_object = obj; if(!obj) @@ -265,6 +372,20 @@ void QmlDebugger::setDebugObject(QObject *obj) makeItem(obj, item); buildTree(obj, item); item->setExpanded(true); - setGeometry(0, 100, 800, 600); + + m_watchers->setRowCount(m_expressions.count()); + + qSort(m_expressions.begin(), m_expressions.end()); + + for(int ii = 0; ii < m_expressions.count(); ++ii) { + + const QPair<quint32, QPair<int, QString> > &expr = m_expressions.at(ii); + QTableWidgetItem *item = new QTableWidgetItem; + item->setText(expr.second.second); + m_watchers->setItem(ii, expr.second.first, item); + + } + + } diff --git a/src/declarative/debugger/qmldebugger.h b/src/declarative/debugger/qmldebugger.h index 943abef..35ff92c 100644 --- a/src/declarative/debugger/qmldebugger.h +++ b/src/declarative/debugger/qmldebugger.h @@ -43,6 +43,7 @@ #define QMLDEBUGGER_H #include <QtCore/qpointer.h> +#include <QtCore/qset.h> #include <QtGui/qwidget.h> QT_BEGIN_HEADER @@ -54,6 +55,9 @@ QT_MODULE(Declarative) class QTreeWidget; class QTreeWidgetItem; class QPlainTextEdit; +class QmlDebuggerItem; +class QTableWidget; +class QmlPropertyView; class QmlDebugger : public QWidget { Q_OBJECT @@ -66,12 +70,21 @@ public slots: void refresh(); private slots: - void itemPressed(QTreeWidgetItem *); + void itemClicked(QTreeWidgetItem *); + void itemDoubleClicked(QTreeWidgetItem *); private: + void buildTree(QObject *obj, QmlDebuggerItem *parent); + bool makeItem(QObject *obj, QmlDebuggerItem *item); QTreeWidget *m_tree; + QTreeWidget *m_warnings; + QTableWidget *m_watchers; + QmlPropertyView *m_properties; QPlainTextEdit *m_text; QPointer<QObject> m_object; + QList<QPair<quint32, QPair<int, QString> > > m_expressions; + QSet<quint32> m_watchedIds; + QPointer<QObject> m_selectedItem; }; QT_END_NAMESPACE diff --git a/src/declarative/debugger/qmldebuggerstatus.cpp b/src/declarative/debugger/qmldebuggerstatus.cpp new file mode 100644 index 0000000..d46a21d --- /dev/null +++ b/src/declarative/debugger/qmldebuggerstatus.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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 "qmldebuggerstatus.h" + +QT_BEGIN_NAMESPACE + +QmlDebuggerStatus::~QmlDebuggerStatus() +{ +} + +void QmlDebuggerStatus::setSelectedState(bool) +{ +} + +QT_END_NAMESPACE diff --git a/src/declarative/debugger/qmldebuggerstatus.h b/src/declarative/debugger/qmldebuggerstatus.h new file mode 100644 index 0000000..8c6355d --- /dev/null +++ b/src/declarative/debugger/qmldebuggerstatus.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 QMLDEBUGGERSTATUS_P_H +#define QMLDEBUGGERSTATUS_P_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QmlDebuggerStatus +{ +public: + virtual ~QmlDebuggerStatus(); + + virtual void setSelectedState(bool); +}; +Q_DECLARE_INTERFACE(QmlDebuggerStatus, "com.trolltech.qml.QmlDebuggerStatus"); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QLMDEBUGGERSTATUS_P_H + diff --git a/src/declarative/debugger/qmlpropertyview.cpp b/src/declarative/debugger/qmlpropertyview.cpp new file mode 100644 index 0000000..2434c58 --- /dev/null +++ b/src/declarative/debugger/qmlpropertyview.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 "qmlpropertyview_p.h" +#include <QtGui/qboxlayout.h> +#include <QtGui/qtreewidget.h> +#include <QtCore/qmetaobject.h> + +QmlPropertyView::QmlPropertyView(QWidget *parent) +: QWidget(parent), m_tree(0) +{ + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + setLayout(layout); + + m_tree = new QTreeWidget(this); + m_tree->setHeaderLabels(QStringList() << "Property" << "Value"); + + m_tree->setColumnCount(2); + + layout->addWidget(m_tree); +} + +class QmlPropertyViewItem : public QObject, public QTreeWidgetItem +{ +Q_OBJECT +public: + QmlPropertyViewItem(QTreeWidget *widget); + + QObject *object; + QMetaProperty property; + +public slots: + void refresh(); +}; + +QmlPropertyViewItem::QmlPropertyViewItem(QTreeWidget *widget) +: QTreeWidgetItem(widget) +{ +} + +void QmlPropertyViewItem::refresh() +{ + setText(1, property.read(object).toString()); +} + +void QmlPropertyView::setObject(QObject *object) +{ + m_object = object; + + m_tree->clear(); + if(!m_object) + return; + + const QMetaObject *mo = object->metaObject(); + for(int ii = 0; ii < mo->propertyCount(); ++ii) { + QmlPropertyViewItem *item = new QmlPropertyViewItem(m_tree); + + QMetaProperty p = mo->property(ii); + item->object = object; + item->property = p; + + item->setText(0, QLatin1String(p.name())); + + static int refreshIdx = -1; + if(refreshIdx == -1) + refreshIdx = QmlPropertyViewItem::staticMetaObject.indexOfMethod("refresh()"); + + if(p.hasNotifySignal()) + QMetaObject::connect(object, p.notifySignalIndex(), + item, refreshIdx); + + item->refresh(); + } +} + +void QmlPropertyView::refresh() +{ + setObject(m_object); +} + +#include "qmlpropertyview.moc" diff --git a/src/declarative/debugger/qmlpropertyview_p.h b/src/declarative/debugger/qmlpropertyview_p.h new file mode 100644 index 0000000..fce9941 --- /dev/null +++ b/src/declarative/debugger/qmlpropertyview_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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 QMLPROPERTYVIEW_P_H +#define QMLPROPERTYVIEW_P_H + +#include <QtGui/qwidget.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +class QTreeWidget; +class QmlPropertyView : public QWidget +{ + Q_OBJECT +public: + QmlPropertyView(QWidget *parent = 0); + + void setObject(QObject *); + +public slots: + void refresh(); + +private: + QPointer<QObject> m_object; + QTreeWidget *m_tree; +}; + +QT_END_NAMESPACE + +#endif // QMLPROPERTYVIEW_P_H + diff --git a/src/declarative/fx/qfxkeyproxy.cpp b/src/declarative/fx/qfxkeyproxy.cpp index 6d9c6ab..1bb54ec 100644 --- a/src/declarative/fx/qfxkeyproxy.cpp +++ b/src/declarative/fx/qfxkeyproxy.cpp @@ -96,7 +96,7 @@ void QFxKeyProxy::keyPressEvent(QKeyEvent *e) for (int ii = 0; ii < d->targets.count(); ++ii) { QSimpleCanvasItem *i = d->targets.at(ii); if (i) - i->keyPressEvent(e); + canvas()->focusItem(i)->keyPressEvent(e); if (e->isAccepted()) return; } @@ -107,7 +107,7 @@ void QFxKeyProxy::keyReleaseEvent(QKeyEvent *e) for (int ii = 0; ii < d->targets.count(); ++ii) { QSimpleCanvasItem *i = d->targets.at(ii); if (i) - i->keyReleaseEvent(e); + canvas()->focusItem(i)->keyReleaseEvent(e); if (e->isAccepted()) return; } diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index a1b5484..bf7a16d 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -582,25 +582,17 @@ void QFxTextEdit::keyReleaseEvent(QKeyEvent *event) } /*! -\overload -Handles the given focus \a event. -*/ -void QFxTextEdit::focusInEvent(QFocusEvent *event) -{ - Q_D(QFxTextEdit); - QFxPaintedItem::focusInEvent(event); - d->control->processEvent(event, QPointF(0, 0)); -} - -/*! -\overload -Handles the given focus \a event. + \overload + Handles changing of the focus property. Focus is applied to the control + even if the edit does not have active focus. This is because things + like KeyProxy can give the behavior of focus even when activeFocus isn't + true. */ -void QFxTextEdit::focusOutEvent(QFocusEvent *event) +void QFxTextEdit::focusChanged(bool hasFocus) { Q_D(QFxTextEdit); - QFxPaintedItem::focusOutEvent(event); - d->control->processEvent(event, QPointF(0, 0)); + QFocusEvent focusEvent(hasFocus ? QEvent::FocusIn : QEvent::FocusOut); + d->control->processEvent(&focusEvent, QPointF(0, 0)); } static QMouseEvent *sceneMouseEventToMouseEvent(QGraphicsSceneMouseEvent *e) diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index b017635..e5e9421 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -161,8 +161,7 @@ protected: void keyPressEvent(QKeyEvent *); void keyReleaseEvent(QKeyEvent *); - void focusInEvent(QFocusEvent *); - void focusOutEvent(QFocusEvent *); + void focusChanged(bool); // mouse filter? void mousePressEvent(QGraphicsSceneMouseEvent *event); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index be5226e..15b5879 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -139,7 +139,7 @@ QStack<QmlEngine *> *QmlEngineStack::engines() QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentBindContext(0), currentExpression(0), q(e), - rootComponent(0), networkAccessManager(0), typeManager(e) + rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) { QScriptValue proto = scriptEngine.newObject(); proto.setProperty(QLatin1String("emit"), @@ -720,17 +720,17 @@ QmlEngine *QmlEngine::activeEngine() QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), log(0) +: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), 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), log(0) +: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0) { } QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr, bool ssecompile) -: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), log(0) +: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), id(0), log(0) { if (ssecompile) { #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -765,6 +765,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, : d(new QmlExpressionPrivate(this, expr, rc)) { d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); d->me = me; } @@ -774,6 +776,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expr, : d(new QmlExpressionPrivate(this, expr, ssecompile)) { d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); d->me = me; } @@ -789,6 +793,8 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, : d(new QmlExpressionPrivate(this, expression, true)) { d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); d->me = scope; } @@ -810,7 +816,7 @@ QmlEngine *QmlExpression::engine() const } /*! - Returns teh QmlContext this expression is associated with, or 0 if there + Returns the QmlContext this expression is associated with, or 0 if there is no association or the QmlContext has been destroyed. */ QmlContext *QmlExpression::context() const @@ -988,6 +994,7 @@ QVariant QmlExpression::value() if(qmlDebugger()) { QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); log.setExpression(expression()); log.setResult(rv); @@ -997,8 +1004,8 @@ QVariant QmlExpression::value() if (prop.hasChangedNotifier()) { prop.connectNotifier(d->proxy, changedIndex); - } else { - QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: ") + QLatin1String(prop.object()->metaObject()->className()) + QLatin1String(".") + prop.name(); + } else if (prop.needsChangedNotifier()) { + QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: [") + QLatin1String(prop.object()->metaObject()->className()) + QLatin1String("].") + prop.name(); log.addWarning(warn); } } @@ -1015,6 +1022,7 @@ QVariant QmlExpression::value() } } else { QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); log.setExpression(expression()); log.setResult(rv); d->addLog(log); @@ -1023,6 +1031,7 @@ QVariant QmlExpression::value() } else { if(qmlDebugger()) { QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); log.setExpression(expression()); log.setResult(rv); d->addLog(log); @@ -1421,7 +1430,8 @@ QmlExpressionLog::QmlExpressionLog() } QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o) -: m_expression(o.m_expression), +: m_time(o.m_time), + m_expression(o.m_expression), m_result(o.m_result), m_warnings(o.m_warnings) { @@ -1433,12 +1443,22 @@ QmlExpressionLog::~QmlExpressionLog() QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o) { + m_time = o.m_time; m_expression = o.m_expression; m_result = o.m_result; m_warnings = o.m_warnings; return *this; } +void QmlExpressionLog::setTime(quint32 time) +{ + m_time = time; +} + +quint32 QmlExpressionLog::time() const +{ + return m_time; +} QString QmlExpressionLog::expression() const { diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 7d5176e..63df0ba 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -114,6 +114,11 @@ public: QmlCompositeTypeManager typeManager; QMap<QString,QString> nameSpacePaths; + + mutable quint32 uniqueId; + quint32 getUniqueId() const { + return uniqueId++; + } }; @@ -201,6 +206,9 @@ public: QmlExpressionLog &operator=(const QmlExpressionLog &); + void setTime(quint32); + quint32 time() const; + QString expression() const; void setExpression(const QString &); @@ -211,6 +219,7 @@ public: void setResult(const QVariant &); private: + quint32 m_time; QString m_expression; QVariant m_result; QStringList m_warnings; @@ -233,6 +242,8 @@ public: QObject *me; bool trackChange; + quint32 id; + void addLog(const QmlExpressionLog &); QList<QmlExpressionLog> *log; }; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 40c9b0e..59d6b38 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -988,6 +988,18 @@ bool QmlMetaProperty::hasChangedNotifier() const } /*! + Returns true if the property needs a change notifier signal for bindings + to remain upto date, false otherwise. + + Some properties, such as attached properties or those whose value never + changes, do not require a change notifier. +*/ +bool QmlMetaProperty::needsChangedNotifier() const +{ + return type() & Property && !(type() & Attached); +} + +/*! Connects the property's change notifier signal to the specified \a method of the \a dest object and returns true. Returns false if this metaproperty does not diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h index 4836038..68b06e5 100644 --- a/src/declarative/qml/qmlmetaproperty.h +++ b/src/declarative/qml/qmlmetaproperty.h @@ -89,6 +89,7 @@ public: void emitSignal(); bool hasChangedNotifier() const; + bool needsChangedNotifier() const; bool connectNotifier(QObject *dest, const char *slot) const; bool connectNotifier(QObject *dest, int method) const; |