diff --git a/.gitignore b/.gitignore index b5c02f5c46f..4fbf6838b3c 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,7 @@ share/doc/qtcreator/qtcreator.qch src/tools/gen-cpp-ast/generate-ast src/tools/mkvisitor/cplusplus0 src/tools/qml/qmldump/qmldump +src/tools/examplesscanner/examplesscanner src/tools/valgrindfake/valgrind-fake # Tests diff --git a/share/qtcreator/static.pro b/share/qtcreator/static.pro index 2c416cd57d9..815d869e919 100644 --- a/share/qtcreator/static.pro +++ b/share/qtcreator/static.pro @@ -24,6 +24,7 @@ isEmpty(vcproj) { } DATA_DIRS = \ + welcomescreen \ examplebrowser \ snippets \ templates \ diff --git a/share/qtcreator/welcomescreen/components/Button.qml b/share/qtcreator/welcomescreen/components/Button.qml new file mode 100644 index 00000000000..2cc4d434ef1 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/Button.qml @@ -0,0 +1,63 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.Button { + id:button + + // dm: this is wrong + width: Math.max(100, button.iconSource !== "" ? labelItem.contentsWidth+12 : 0 ) + height: Math.max(22, sizehint.height) + + property variant sizehint: backgroundItem.sizeFromContents(80, 6) + property bool defaultbutton + property string hint + + background: QStyleItem { + id: styleitem + anchors.fill: parent + elementType: "button" + sunken: pressed || checked + raised: !(pressed || checked) + hover: containsMouse + text: button.iconSource === "" ? button.text : "" + focus: button.focus + hint: button.hint + + // If no icon, let the style do the drawing + activeControl: focus ? "default" : "" + Connections{ + target: button + onToolTipTriggered: styleitem.showTip() + } + function showTip(){ + showToolTip(tooltip); + } + } + + label: Item { + // Used as a fallback since I can't pass the imageURL + // directly to the style object + visible: button.iconSource !== "" + property int contentsWidth : row.width + Row { + id: row + anchors.centerIn: parent + spacing: 4 + Image { + source: iconSource + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.Stretch //mm Image should shrink if button is too small, depends on QTBUG-14957 + } + Text { + id:text + color: textColor + anchors.verticalCenter: parent.verticalCenter + text: button.text + horizontalAlignment: Text.Center + } + } + } + Keys.onSpacePressed:clicked() +} + diff --git a/share/qtcreator/welcomescreen/components/ButtonRow.qml b/share/qtcreator/welcomescreen/components/ButtonRow.qml new file mode 100644 index 00000000000..7123b415b94 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ButtonRow.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 +import "custom" as Components + +Components.ButtonRow { +} diff --git a/share/qtcreator/welcomescreen/components/CheckBox.qml b/share/qtcreator/welcomescreen/components/CheckBox.qml new file mode 100644 index 00000000000..51055f84670 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/CheckBox.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.CheckBox{ + id:checkbox + property string text + property string hint + height:20 + width: Math.max(110, backgroundItem.textWidth(text) + 40) + + background: QStyleItem { + elementType:"checkbox" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:checkbox.text + enabled:checkbox.enabled + focus:checkbox.focus + hint:checkbox.hint + } + Keys.onSpacePressed:checked = !checked +} + diff --git a/share/qtcreator/welcomescreen/components/ChoiceList.qml b/share/qtcreator/welcomescreen/components/ChoiceList.qml new file mode 100644 index 00000000000..eb6b5fddbe9 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ChoiceList.qml @@ -0,0 +1,61 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.ChoiceList { + + id: choicelist + + property int buttonHeight: backgroundItem.sizeFromContents(100, 18).height + property int buttonWidth: backgroundItem.sizeFromContents(100, 18).width + + property string hint + + height: buttonHeight + width: buttonWidth + topMargin: 4 + bottomMargin: 4 + + background: QStyleItem { + anchors.fill: parent + elementType: "combobox" + sunken: pressed + raised: !pressed + hover: containsMouse + enabled: choicelist.enabled + text: currentItemText + focus: choicelist.focus + hint: choicelist.hint + } + + listItem: Item { + id:item + + height: 22 + anchors.left: parent.left + width: choicelist.width + QStyleItem { + anchors.fill: parent + elementType: "comboboxitem" + text: itemText + selected: highlighted + + } + } + popupFrame: QStyleItem { + property string popupLocation: backgroundItem.styleHint("comboboxpopup") ? "center" : "below" + property int fw: backgroundItem.pixelMetric("menupanelwidth"); + anchors.leftMargin: backgroundItem.pixelMetric("menuhmargin") + fw + anchors.rightMargin: backgroundItem.pixelMetric("menuhmargin") + fw + anchors.topMargin: backgroundItem.pixelMetric("menuvmargin") + fw + anchors.bottomMargin: backgroundItem.pixelMetric("menuvmargin") + fw + elementType: "menu" + + effect: DropShadow { + blurRadius: 18 + color: "#90000000" + xOffset: 1 + yOffset: 1 + } + } +} diff --git a/share/qtcreator/welcomescreen/components/ContextMenu.qml b/share/qtcreator/welcomescreen/components/ContextMenu.qml new file mode 100644 index 00000000000..14fbc8da9dd --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ContextMenu.qml @@ -0,0 +1,8 @@ +import QtQuick 1.0 +import "custom" as Components + +MenuBase { + id: choiceList + + property ListModel model +} diff --git a/share/qtcreator/welcomescreen/components/Dial.qml b/share/qtcreator/welcomescreen/components/Dial.qml new file mode 100644 index 00000000000..e1b367b9a4b --- /dev/null +++ b/share/qtcreator/welcomescreen/components/Dial.qml @@ -0,0 +1,113 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +// jens: ContainsMouse breaks drag functionality + +QStyleItem { + id: dial + + width:100 + height:100 + + property alias maximumValue: range.maximumValue + property alias minimumValue: range.minimumValue + property alias containsMouse: mouseArea.containsMouse + property alias value: range.value + + property bool wrapping: false + property bool tickmarks: true // not implemented + + RangeModel { + id: range + minimumValue: 0.0 + maximumValue: 1.0 + stepSize: 0.0 + value: 0 + } + + MouseArea { + id: mouseArea + anchors.fill:parent + property bool inDrag + hoverEnabled:true + + onPositionChanged: { + if (pressed) { + value = valueFromPoint(mouseX, mouseY) + inDrag = true + } + } + onPressed: { + value = valueFromPoint(mouseX, mouseY) + dial.focus = true + } + + onReleased:inDrag = false; + function bound(val) { return Math.max(minimumValue, Math.min(maximumValue, val)); } + + function valueFromPoint(x, y) + { + var yy = height/2.0 - y; + var xx = x - width/2.0; + var a = (xx || yy) ? Math.atan2(yy, xx) : 0; + + if (a < Math.PI/ -2) + a = a + Math.PI * 2; + + var dist = 0; + var minv = minimumValue*100, maxv = maximumValue*100; + + if (minimumValue < 0) { + dist = -minimumValue; + minv = 0; + maxv = maximumValue + dist; + } + + var r = maxv - minv; + var v; + if (wrapping) + v = (0.5 + minv + r * (Math.PI * 3 / 2 - a) / (2 * Math.PI)); + else + v = (0.5 + minv + r* (Math.PI * 4 / 3 - a) / (Math.PI * 10 / 6)); + + if (dist > 0) + v -= dist; + return maximumValue - bound(v/100) + } + } + + WheelArea { + id: wheelarea + anchors.fill: parent + horizontalMinimumValue: dial.minimumValue + horizontalMaximumValue: dial.maximumValue + verticalMinimumValue: dial.minimumValue + verticalMaximumValue: dial.maximumValue + property double step: (dial.maximumValue - dial.minimumValue)/100 + + onVerticalWheelMoved: { + value += verticalDelta/4*step + } + + onHorizontalWheelMoved: { + value += horizontalDelta/4*step + } + } + + elementType:"dial" + sunken: mouseArea.pressed + maximum: range.maximumValue*90 + minimum: range.minimumValue*90 + focus:dial.focus + value: visualPos*90 + enabled: dial.enabled + property double visualPos : range.value + Behavior on visualPos { + enabled: !mouseArea.inDrag + NumberAnimation { + duration: 300 + easing.type: Easing.OutSine + } + } +} diff --git a/share/qtcreator/welcomescreen/components/Frame.qml b/share/qtcreator/welcomescreen/components/Frame.qml new file mode 100644 index 00000000000..24a8e8332ef --- /dev/null +++ b/share/qtcreator/welcomescreen/components/Frame.qml @@ -0,0 +1,25 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + + +QStyleBackground { + + width: 100 + height: 100 + + default property alias children: content.children + + style: QStyleItem { + id: styleitem + elementType: "frame" + } + + Item { + id: content + anchors.fill: parent + anchors.margins: frameWidth + property int frameWidth: styleitem.pixelMetric("defaultframewidth"); + } +} + diff --git a/share/qtcreator/welcomescreen/components/GroupBox.qml b/share/qtcreator/welcomescreen/components/GroupBox.qml new file mode 100644 index 00000000000..d2184d515f6 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/GroupBox.qml @@ -0,0 +1,22 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.GroupBox { + id: groupbox + width: Math.max(200, contentWidth + sizeHint.width) + height: contentHeight + sizeHint.height + 4 + property variant sizeHint: backgroundItem.sizeFromContents(0, 24) + property bool flat: false + background : QStyleItem { + id: styleitem + elementType: "groupbox" + anchors.fill: parent + text: groupbox.title + hover: checkbox.containsMouse + on: checkbox.checked + focus: checkbox.activeFocus + activeControl: checkable ? "checkbox" : "" + sunken: !flat + } +} diff --git a/share/qtcreator/welcomescreen/components/Menu.qml b/share/qtcreator/welcomescreen/components/Menu.qml new file mode 100644 index 00000000000..000219ece9d --- /dev/null +++ b/share/qtcreator/welcomescreen/components/Menu.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 +import "../components/plugin" + +MenuBase { + +} diff --git a/share/qtcreator/welcomescreen/components/MenuItem.qml b/share/qtcreator/welcomescreen/components/MenuItem.qml new file mode 100644 index 00000000000..52a0511f0f9 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/MenuItem.qml @@ -0,0 +1,6 @@ +import QtQuick 1.0 +import "../components/plugin" + +MenuItemBase { + +} diff --git a/share/qtcreator/welcomescreen/components/ProgressBar.qml b/share/qtcreator/welcomescreen/components/ProgressBar.qml new file mode 100644 index 00000000000..9b2d368a371 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ProgressBar.qml @@ -0,0 +1,29 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.ProgressBar { + id:progressbar + + property variant sizehint: backgroundItem.sizeFromContents(23, 23) + property int orientation: Qt.Horizontal + property string hint + + height: orientation === Qt.Horizontal ? sizehint.height : 200 + width: orientation === Qt.Horizontal ? 200 : sizehint.height + + background: QStyleItem { + anchors.fill: parent + elementType: "progressbar" + // XXX: since desktop uses int instead of real, the progressbar + // range [0..1] must be stretched to a good precision + property int factor : 1000 + value: indeterminate ? 0 : progressbar.value * factor // does indeterminate value need to be 1 on windows? + minimum: indeterminate ? 0 : progressbar.minimumValue * factor + maximum: indeterminate ? 0 : progressbar.maximumValue * factor + enabled: progressbar.enabled + horizontal: progressbar.orientation == Qt.Horizontal + hint: progressbar.hint + } +} + diff --git a/share/qtcreator/welcomescreen/components/RadioButton.qml b/share/qtcreator/welcomescreen/components/RadioButton.qml new file mode 100644 index 00000000000..cfc16c95951 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/RadioButton.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +// jb : Size should not depend on background, we should make it consistent + +Components.CheckBox { + id:radiobutton + property string text + property string hint + width:110 + height:20 + + background: QStyleItem { + elementType:"radiobutton" + sunken:pressed + on:checked || pressed + hover:containsMouse + text:radiobutton.text + enabled:radiobutton.enabled + focus:radiobutton.focus + hint:radiobutton.hint + } + Keys.onSpacePressed:clicked() +} + diff --git a/share/qtcreator/welcomescreen/components/ScrollArea.qml b/share/qtcreator/welcomescreen/components/ScrollArea.qml new file mode 100644 index 00000000000..4c79a093d01 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ScrollArea.qml @@ -0,0 +1,140 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +FocusScope { + id: scrollarea + width: 100 + height: 100 + + property int frameWidth: frame ? styleitem.pixelMetric("defaultframewidth") : 0; + property int contentHeight : content.childrenRect.height + property int contentWidth: content.childrenRect.width + property alias color: colorRect.color + property bool frame: true + property bool highlightOnFocus: false + property bool frameAroundContents: styleitem.styleHint("framearoundcontents") + property alias verticalValue: vscrollbar.value + property alias horizontalValue: hscrollbar.value + + default property alias data: content.data + + property int contentY + property int contentX + + onContentYChanged: { + vscrollbar.value = contentY + wheelarea.verticalValue = contentY + } + onContentXChanged: { + hscrollbar.value = contentX + wheelarea.horizontalValue = contentX + } + + Rectangle { + id: colorRect + color: "transparent" + anchors.fill:styleitem + anchors.margins: frameWidth + } + + QStyleItem { + id: styleitem + elementType: "frame" + onElementTypeChanged: scrollarea.frameWidth = styleitem.pixelMetric("defaultframewidth"); + sunken: true + visible: frame + anchors.fill: parent + anchors.rightMargin: frame ? (frameAroundContents ? (vscrollbar.visible ? vscrollbar.width + 2 * frameMargins : 0) : -frameWidth) : 0 + anchors.bottomMargin: frame ? (frameAroundContents ? (hscrollbar.visible ? hscrollbar.height + 2 * frameMargins : 0) : -frameWidth) : 0 + anchors.topMargin: frame ? (frameAroundContents ? 0 : -frameWidth) : 0 + property int scrollbarspacing: styleitem.pixelMetric("scrollbarspacing"); + property int frameMargins : frame ? scrollbarspacing : 0 + property int frameoffset: style === "mac" ? -1 : 0 + } + + Item { + id: flickable + anchors.fill: styleitem + anchors.margins: frameWidth + clip: true + + Item { + id: content + x: -scrollarea.contentX + y: -scrollarea.contentY + } + } + + WheelArea { + id: wheelarea + anchors.fill: parent + horizontalMinimumValue: hscrollbar.minimumValue + horizontalMaximumValue: hscrollbar.maximumValue + verticalMinimumValue: vscrollbar.minimumValue + verticalMaximumValue: vscrollbar.maximumValue + + onVerticalValueChanged: { + contentY = verticalValue + } + + onHorizontalValueChanged: { + contentX = horizontalValue + } + } + + ScrollBar { + id: hscrollbar + orientation: Qt.Horizontal + property int availableWidth : scrollarea.width - (frame ? (vscrollbar.width) : 0) + visible: contentWidth > availableWidth + maximumValue: contentWidth > availableWidth ? scrollarea.contentWidth - availableWidth: 0 + minimumValue: 0 + anchors.bottom: parent.bottom + anchors.bottomMargin: styleitem.frameoffset + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: (frame ? frameWidth : 0) + anchors.rightMargin: { vscrollbar.visible ? scrollbarExtent : (frame ? 1 : 0) } + onValueChanged: contentX = value + property int scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + } + + ScrollBar { + id: vscrollbar + orientation: Qt.Vertical + property int availableHeight : scrollarea.height - (frame ? (hscrollbar.height) : 0) + visible: contentHeight > availableHeight + maximumValue: contentHeight > availableHeight ? scrollarea.contentHeight - availableHeight : 0 + minimumValue: 0 + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: styleitem.style == "mac" ? 1 : 0 + onValueChanged: contentY = value + anchors.rightMargin: styleitem.frameoffset + anchors.bottomMargin: hscrollbar.visible ? hscrollbar.height : styleitem.frameoffset + } + + Rectangle { + // This is the filled corner between scrollbars + id: cornerFill + anchors.left: vscrollbar.left + anchors.right: vscrollbar.right + anchors.top: hscrollbar.top + anchors.bottom: hscrollbar.bottom + visible: hscrollbar.visible && vscrollbar.visible + SystemPalette { id: syspal } + color: syspal.window + } + + QStyleItem { + z: 2 + anchors.fill: parent + anchors.margins: -3 + anchors.rightMargin: -4 + anchors.bottomMargin: -4 + visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget") + elementType: "focusframe" + } +} diff --git a/share/qtcreator/welcomescreen/components/ScrollBar.qml b/share/qtcreator/welcomescreen/components/ScrollBar.qml new file mode 100644 index 00000000000..ef1a93779d6 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ScrollBar.qml @@ -0,0 +1,127 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Item { + id: scrollbar + + property bool upPressed + property bool downPressed + property int orientation : Qt.Horizontal + property alias minimumValue: slider.minimumValue + property alias maximumValue: slider.maximumValue + property alias value: slider.value + + width: orientation == Qt.Horizontal ? 200 : internal.scrollbarExtent + height: orientation == Qt.Horizontal ? internal.scrollbarExtent : 200 + + onValueChanged: internal.updateHandle() + // onMaximumValueChanged: internal.updateHandle() + // onMinimumValueChanged: internal.updateHandle() + + MouseArea { + id: internal + + anchors.fill: parent + + property bool autoincrement: false + property int scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + + // Update hover item + onEntered: styleitem.activeControl = styleitem.hitTest(mouseX, mouseY) + onExited: styleitem.activeControl = "none" + onMouseXChanged: styleitem.activeControl = styleitem.hitTest(mouseX, mouseY) + hoverEnabled: true + + Timer { + running: upPressed || downPressed + interval: 350 + onTriggered: internal.autoincrement = true + } + + Timer { + running: internal.autoincrement + interval: 60 + repeat: true + onTriggered: upPressed ? internal.decrement() : internal.increment() + } + + onPressed: { + var control = styleitem.hitTest(mouseX,mouseY) + if (control == "up") { + upPressed = true + } else if (control == "down") { + downPressed = true + } + } + + onReleased: { + autoincrement = false; + if (upPressed) { + upPressed = false; + decrement() + } else if (downPressed) { + increment() + downPressed = false; + } + } + + function increment() { + value += 30 + if (value > maximumValue) + value = maximumValue + } + + function decrement() { + value -= 30 + if (value < minimumValue) + value = minimumValue + } + + QStyleItem { + id: styleitem + anchors.fill:parent + elementType: "scrollbar" + hover: activeControl != "none" + activeControl: "none" + sunken: upPressed | downPressed + minimum: slider.minimumValue + maximum: slider.maximumValue + value: slider.value + horizontal: orientation == Qt.Horizontal + enabled: parent.enabled + } + + property variant handleRect: Qt.rect(0,0,0,0) + function updateHandle() { + internal.handleRect = styleitem.subControlRect("handle") + var grooveRect = styleitem.subControlRect("groove"); + var extra = 0 + if (orientation == Qt.Vertical) { + slider.anchors.topMargin = grooveRect.y + extra + slider.anchors.bottomMargin = height - grooveRect.y - grooveRect.height + extra + } else { + slider.anchors.leftMargin = grooveRect.x + extra + slider.anchors.rightMargin = width - grooveRect.x - grooveRect.width + extra + } + } + + + Components.Slider { + id: slider + hoverEnabled: false // Handled by the scrollbar background + orientation: scrollbar.orientation + anchors.fill: parent + leftMargin: (orientation === Qt.Horizontal) ? internal.handleRect.width / 2 : internal.handleRect.height / 2 + rightMargin: leftMargin + handle: Item { + width: orientation == Qt.Vertical ? internal.handleRect.height : internal.handleRect.width; + height: orientation == Qt.Vertical ? internal.handleRect.width : internal.handleRect.height + } + groove:null + containsMouse: false + valueIndicator:null + inverted:orientation != Qt.Horizontal + } + } +} diff --git a/share/qtcreator/welcomescreen/components/Slider.qml b/share/qtcreator/welcomescreen/components/Slider.qml new file mode 100644 index 00000000000..b8720351fbc --- /dev/null +++ b/share/qtcreator/welcomescreen/components/Slider.qml @@ -0,0 +1,60 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +// jens: ContainsMouse breaks drag functionality + +Components.Slider{ + id: slider + + property bool tickmarksEnabled: true + property string tickPosition: "Below" // "Top", "Below", "BothSides" + + QStyleItem { id:buttonitem; elementType: "slider" } + + property variant sizehint: buttonitem.sizeFromContents(23, 23) + property int orientation: Qt.Horizontal + + height: orientation === Qt.Horizontal ? sizehint.height : 200 + width: orientation === Qt.Horizontal ? 200 : sizehint.height + property string hint; + + groove: QStyleItem { + anchors.fill:parent + elementType: "slider" + sunken: pressed + maximum: slider.maximumValue*100 + minimum: slider.minimumValue*100 + value: slider.value*100 + horizontal: slider.orientation == Qt.Horizontal + enabled: slider.enabled + focus: slider.focus + hint: slider.hint + activeControl: tickmarksEnabled ? tickPosition.toLowerCase() : "" + } + + handle: null + valueIndicator: null + + Keys.onRightPressed: value += (maximumValue - minimumValue)/10.0 + Keys.onLeftPressed: value -= (maximumValue - minimumValue)/10.0 + + WheelArea { + id: wheelarea + anchors.fill: parent + horizontalMinimumValue: slider.minimumValue + horizontalMaximumValue: slider.maximumValue + verticalMinimumValue: slider.minimumValue + verticalMaximumValue: slider.maximumValue + property double step: (slider.maximumValue - slider.minimumValue)/100 + + onVerticalWheelMoved: { + value += verticalDelta/4*step + } + + onHorizontalWheelMoved: { + value += horizontalDelta/4*step + } + } + +} diff --git a/share/qtcreator/welcomescreen/components/SpinBox.qml b/share/qtcreator/welcomescreen/components/SpinBox.qml new file mode 100644 index 00000000000..919ac95e6b5 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/SpinBox.qml @@ -0,0 +1,96 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.SpinBox { + id:spinbox + + property variant __upRect; + property variant __downRect; + property int __margin: (height -16)/2 + property string hint + + // Align height with button + topMargin:__margin + bottomMargin:__margin + + leftMargin:6 + rightMargin:6 + + QStyleItem { id:edititem ; elementType:"edit" ; visible:false } + property int buttonHeight: edititem.sizeFromContents(70, 20).height + property int buttonWidth: edititem.sizeFromContents(70, 20).width + + height: buttonHeight + width: buttonWidth + clip:false + + background: Item { + anchors.fill: parent + property variant __editRect + + Rectangle { + id: editBackground + x: __editRect.x - 1 + y: __editRect.y + width: __editRect.width + 1 + height: __editRect.height + } + + Item { + id: focusFrame + anchors.fill: editBackground + visible: frameitem.styleHint("focuswidget") + QStyleItem { + id: frameitem + anchors.margins: -6 + anchors.leftMargin: -6 + anchors.rightMargin: -7 + anchors.fill: parent + visible: spinbox.activeFocus + elementType: "focusframe" + } + } + + function updateRect() { + __upRect = styleitem.subControlRect("up"); + __downRect = styleitem.subControlRect("down"); + __editRect = styleitem.subControlRect("edit"); + spinbox.leftMargin = __editRect.x + 2 + spinbox.rightMargin = spinbox.width -__editRect.width - __editRect.x + } + + Component.onCompleted: updateRect() + onWidthChanged: updateRect() + onHeightChanged: updateRect() + + QStyleItem { + id: styleitem + anchors.fill: parent + elementType: "spinbox" + sunken: (downEnabled && downPressed) | (upEnabled && upPressed) + hover: containsMouse + focus: spinbox.focus + enabled: spinbox.enabled + value: (upPressed ? 1 : 0) | + (downPressed == 1 ? 1<<1 : 0) | + (upEnabled ? (1<<2) : 0) | + (downEnabled == 1 ? (1<<3) : 0) + hint: spinbox.hint + } + } + + up: Item { + x: __upRect.x + y: __upRect.y + width: __upRect.width + height: __upRect.height + } + + down: Item { + x: __downRect.x + y: __downRect.y + width: __downRect.width + height: __downRect.height + } +} diff --git a/share/qtcreator/welcomescreen/components/SplitterRow.qml b/share/qtcreator/welcomescreen/components/SplitterRow.qml new file mode 100644 index 00000000000..adcc535e001 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/SplitterRow.qml @@ -0,0 +1,25 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.SplitterRow { + handleBackground: QStyleItem { + id: styleitem + elementType: "splitter" + width: pixelMetric("splitterwidth") + + MouseArea { + anchors.fill: parent + anchors.leftMargin: (parent.width <= 1) ? -2 : 0 + anchors.rightMargin: (parent.width <= 1) ? -2 : 0 + drag.axis: Qt.YAxis + drag.target: handleDragTarget + onMouseXChanged: handleDragged(handleIndex) + + QStyleItem { + anchors.fill: parent + cursor: "splithcursor" + } + } + } +} diff --git a/share/qtcreator/welcomescreen/components/Switch.qml b/share/qtcreator/welcomescreen/components/Switch.qml new file mode 100644 index 00000000000..5d661ec3d6b --- /dev/null +++ b/share/qtcreator/welcomescreen/components/Switch.qml @@ -0,0 +1,22 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.Switch { + id:widget + minimumWidth:100 + minimumHeight:30 + + groove:QStyleItem { + elementType:"edit" + sunken: true + } + + handle: QStyleItem { + elementType:"button" + width:widget.width/2 + height:widget.height-4 + hover:containsMouse + } +} + diff --git a/share/qtcreator/welcomescreen/components/Tab.qml b/share/qtcreator/welcomescreen/components/Tab.qml new file mode 100644 index 00000000000..b0e223da385 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/Tab.qml @@ -0,0 +1,8 @@ +import Qt 4.7 + +Item { + id:tab + anchors.fill: parent + property string title + property int contentMargin +} diff --git a/share/qtcreator/welcomescreen/components/TabBar.qml b/share/qtcreator/welcomescreen/components/TabBar.qml new file mode 100644 index 00000000000..b5869ebf9d5 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/TabBar.qml @@ -0,0 +1,111 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + + +Item { + id: tabbar + property int tabHeight: tabrow.height + property int tabWidth: tabrow.width + + Keys.onRightPressed: { + if (tabFrame && tabFrame.current < tabFrame.count - 1) + tabFrame.current = tabFrame.current + 1 + } + Keys.onLeftPressed: { + if (tabFrame && tabFrame.current > 0) + tabFrame.current = tabFrame.current - 1 + } + + height: tabHeight + + property Item tabFrame + onTabFrameChanged:parent = tabFrame + visible: tabFrame ? tabFrame.tabsVisible : true + property int __overlap : styleitem.pixelMetric("tabvshift"); + property string position: tabFrame ? tabFrame.position : "North" + property string tabBarAlignment: styleitem.styleHint("tabbaralignment"); + property int tabOverlap: styleitem.pixelMetric("taboverlap"); + property int tabBaseOverlap: styleitem.pixelMetric("tabbaseoverlap"); + property int tabHSpace: styleitem.pixelMetric("tabhspace"); + property int tabVSpace: styleitem.pixelMetric("tabvspace"); + + function tab(index) { + for (var i = 0; i < tabrow.children.length; ++i) { + if (tabrow.children[i].tabindex == index) { + return tabrow.children[i] + } + } + return null; + } + + QStyleItem { + visible:false + id:styleitem + elementType: "tab" + text: "generic" + } + + Row { + id: tabrow + focus: true + property int paintMargins: 1 + states: + State { + when: tabBarAlignment == "center" + name: "centered" + AnchorChanges { + target:tabrow + anchors.horizontalCenter: tabbar.horizontalCenter + } + } + + Repeater { + id:repeater + focus:true + model: tabFrame ? tabFrame.tabs.length : null + delegate: Item { + id:tab + focus:true + property int tabindex: index + property bool selected : tabFrame.current == index + z: selected ? 1 : -1 + function updateRect() { + var rect = style.sizeFromContents(textitem.width + tabHSpace + 2, Math.max(style.fontHeight + tabVSpace + 6, 0)) + width = rect.width + height = rect.height + } + // Component.onCompleted: print("taboverlap" + tabOverlap + " tabbaseoverlap " + tabBaseOverlap + " overlap " +__overlap + " hspace " + tabHSpace) + QStyleItem { + id: style + elementType: "tab" + selected: tab.selected + info: tabbar.position + text: tabFrame.tabs[index].title + hover: mousearea.containsMouse + focus: tabbar.focus && selected + property bool first: index === 0 + paintMargins: tabrow.paintMargins + activeControl: tabFrame.count == 1 ? "only" : index === 0 ? "beginning" : + index == tabFrame.count-1 ? "end" : "middle" + anchors.fill: parent + anchors.margins: -paintMargins + Text { + id: textitem + // Used for size hint + visible: false + onWidthChanged: updateRect() + onHeightChanged: updateRect() + text: tabFrame.tabs[index].title + } + } + MouseArea { + id: mousearea + anchors.fill: parent + hoverEnabled: true + onPressed: tabFrame.current = index + } + } + } + } +} diff --git a/share/qtcreator/welcomescreen/components/TabFrame.qml b/share/qtcreator/welcomescreen/components/TabFrame.qml new file mode 100644 index 00000000000..10d63db3e26 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/TabFrame.qml @@ -0,0 +1,77 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Item { + id: tabWidget + width: 100 + height: 100 + focus: true + property TabBar tabbar + property int current: 0 + property int count: stack.children.length + property bool frame:true + property bool tabsVisible: true + property string position: "North" + default property alias tabs : stack.children + + onCurrentChanged: __setOpacities() + Component.onCompleted: __setOpacities() + onTabbarChanged: { + tabbar.tabFrame = tabWidget + tabbar.anchors.top = tabWidget.top + tabbar.anchors.left = tabWidget.left + tabbar.anchors.right = tabWidget.right + } + + property int __baseOverlap : frameitem.pixelMetric("tabbaseoverlap")// add paintmargins; + function __setOpacities() { + for (var i = 0; i < stack.children.length; ++i) { + stack.children[i].visible = (i == current ? true : false) + } + } + + QStyleItem { + id: frameitem + z: style == "oxygen" ? 1 : 0 + elementType: "tabframe" + info: position + value: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).x : 0 + minimum: tabbar && tabsVisible && tabbar.tab(current) ? tabbar.tab(current).width : 0 + maximum: tabbar && tabsVisible ? tabbar.tabWidth : width + anchors.fill: parent + + property int frameWidth: pixelMetric("defaultframewidth") + + Item { + id: stack + anchors.fill: parent + anchors.margins: (frame ? frameitem.frameWidth : 0) + anchors.topMargin: anchors.margins + (frameitem.style =="mac" ? 6 : 0) + anchors.bottomMargin: anchors.margins + (frameitem.style =="mac" ? 6 : 0) + } + + anchors.topMargin: tabbar && tabsVisible && position == "North" ? tabbar.height - __baseOverlap : 0 + + states: [ + State { + name: "South" + when: position == "South" && tabbar!= undefined + PropertyChanges { + target: frameitem + anchors.topMargin: 0 + anchors.bottomMargin: tabbar ? tabbar.height - __baseOverlap: 0 + } + PropertyChanges { + target: tabbar + anchors.topMargin: -__baseOverlap + } + AnchorChanges { + target: tabbar + anchors.top: frameitem.bottom + anchors.bottom: undefined + } + } + ] + } +} diff --git a/share/qtcreator/welcomescreen/components/TableColumn.qml b/share/qtcreator/welcomescreen/components/TableColumn.qml new file mode 100644 index 00000000000..b40334bbf59 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/TableColumn.qml @@ -0,0 +1,9 @@ +import QtQuick 1.0 + +QtObject { + property string caption + property string property + property int width: 160 + property bool visible: true + property int elideMode: Text.ElideRight +} diff --git a/share/qtcreator/welcomescreen/components/TableView.qml b/share/qtcreator/welcomescreen/components/TableView.qml new file mode 100644 index 00000000000..196a0ed4b6c --- /dev/null +++ b/share/qtcreator/welcomescreen/components/TableView.qml @@ -0,0 +1,574 @@ +import QtQuick 1.0 +import "../components" +import "../components/plugin" + +/* +* +* TableView +* +* This component provides an item-view with resizable +* header sections. +* +* You can style the drawn delegate by overriding the itemDelegate +* property. The following properties are supported for custom +* delegates: +* +* Note: Currently only row selection is available for this component +* +* itemheight - default platform size of item +* itemwidth - default platform width of item +* itemselected - if the row is currently selected +* itemvalue - The text for this item +* itemforeground - The default text color for an item +* +* For example: +* itemDelegate: Item { +* Text { +* anchors.verticalCenter: parent.verticalCenter +* color: itemForeground +* elide: Text.ElideRight +* text: itemValue +* } +* } +* +* Data for each row is provided through a model: +* +* ListModel { +* ListElement{ column1: "value 1"; column2: "value 2"} +* ListElement{ column1: "value 3"; column2: "value 4"} +* } +* +* You provide title and size properties on TableColumns +* by setting the default header property : +* +* TableView { +* TableColumn{ property: "column1" ; caption: "Column 1" ; width:100} +* TableColumn{ property: "column2" ; caption: "Column 2" ; width:200} +* model: datamodel +* } +* +* The header sections are attached to values in the datamodel by defining +* the listmodel property they attach to. Each property in the model, will +* then be shown in each column section. +* +* The view itself does not provide sorting. This has to +* be done on the model itself. However you can provide sorting +* on the model and enable sort indicators on headers. +* +* sortColumn - The index of the currently selected sort header +* sortIndicatorVisible - If sort indicators should be enabled +* sortIndicatorDirection - "up" or "down" depending on state +* +*/ + +FocusScope{ + id: root + property variant model + property int frameWidth: frame ? styleitem.pixelMetric("defaultframewidth") : 0; + property alias contentHeight : tree.contentHeight + property alias contentWidth: tree.contentWidth + property bool frame: true + property bool highlightOnFocus: false + property bool frameAroundContents: styleitem.styleHint("framearoundcontents") + property int sortColumn // Index of currently selected sort column + + property bool sortIndicatorVisible: false // enables or disables sort indicator + property string sortIndicatorDirection: "down" // "up" or "down" depending on current state + + property bool alternateRowColor: true + property alias contentX: tree.contentX + property alias contentY: tree.contentY + + property alias currentIndex: tree.currentIndex // Should this be currentRowIndex? + + property int headerHeight: headerrow.height + + property Component itemDelegate: standardDelegate + property Component rowDelegate: rowDelegate + property Component headerDelegate: headerDelegate + property alias cacheBuffer: tree.cacheBuffer + + property bool headerVisible: true + + default property alias header: tree.header + + signal activated + + Component { + id: standardDelegate + Item { + property int implicitWidth: sizehint.paintedWidth + 4 + Text { + width: parent.width + anchors.margins: 4 + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + elide: itemElideMode + text: itemValue ? itemValue : "" + color: itemForeground + } + Text { + id: sizehint + text: itemValue ? itemValue : "" + visible:false + } + } + } + + Component { + id: nativeDelegate + // This gives more native styling, but might be less performant + QStyleItem { + elementType: "item" + text: itemValue + selected: itemSelected + } + } + + Component { + id: headerDelegate + QStyleItem { + elementType: "header" + activeControl: itemSort + raised: true + sunken: itemPressed + text: itemValue + hover: itemContainsMouse + } + } + + Component { + id: rowDelegate + QStyleItem { + id: rowstyle + elementType: "itemrow" + activeControl: itemAlternateBackground ? "alternate" : "" + selected: itemSelected ? "true" : "false" + } + } + + Rectangle { + id: colorRect + color: "white" + anchors.fill: frameitem + anchors.margins: frameWidth + anchors.rightMargin: (!frameAroundContents && vscrollbar.visible ? vscrollbar.width : 0) + frameWidth + anchors.bottomMargin: (!frameAroundContents && hscrollbar.visible ? hscrollbar.height : 0) +frameWidth + } + + QStyleItem { + id: frameitem + elementType: "frame" + onElementTypeChanged: scrollarea.frameWidth = styleitem.pixelMetric("defaultframewidth"); + sunken: true + visible: frame + anchors.fill: parent + anchors.rightMargin: frame ? (frameAroundContents ? (vscrollbar.visible ? vscrollbar.width + 2 * frameMargins : 0) : -frameWidth) : 0 + anchors.bottomMargin: frame ? (frameAroundContents ? (hscrollbar.visible ? hscrollbar.height + 2 * frameMargins : 0) : -frameWidth) : 0 + anchors.topMargin: frame ? (frameAroundContents ? 0 : -frameWidth) : 0 + property int scrollbarspacing: styleitem.pixelMetric("scrollbarspacing"); + property int frameMargins : frame ? scrollbarspacing : 0 + } + MouseArea { + id: mousearea + + anchors.fill: tree + + property bool autoincrement: false + property bool autodecrement: false + + onReleased: { + autoincrement = false + autodecrement = false + } + + // Handle vertical scrolling whem dragging mouse outside boundraries + + Timer { running: mousearea.autoincrement; repeat: true; interval: 30 ; onTriggered: tree.incrementCurrentIndex()} + Timer { running: mousearea.autodecrement; repeat: true; interval: 30 ; onTriggered: tree.decrementCurrentIndex()} + + onMousePositionChanged: { + if (mouseY > tree.height) { + autodecrement = false + autoincrement = true + } else if (mouseY < 0) { + autoincrement = false + autodecrement = true + } else { + autoincrement = false + autodecrement = false + } + + var y = Math.min(contentY + tree.height - 5, Math.max(mouseY + contentY, contentY)) + + var newIndex = tree.indexAt(0, y) + if (newIndex > 0) + tree.currentIndex = tree.indexAt(0, y) + } + onPressed: { + tree.forceActiveFocus() + var x = Math.min(contentWidth - 5, Math.max(mouseX + contentX, 0)) + var y = Math.min(contentHeight - 5, Math.max(mouseY + contentY, 0)) + tree.currentIndex = tree.indexAt(x, y) + } + + onDoubleClicked: { + parent.activated() + } + } + + ListView { + id: tree + property list header + property bool blockUpdates: false + highlightFollowsCurrentItem: true + model: root.model + + interactive: false + anchors.top: tableColumn.bottom + anchors.topMargin: -frameWidth + anchors.left: frameitem.left + anchors.right: frameitem.right + anchors.bottom: frameitem.bottom + anchors.margins: frameWidth + + anchors.rightMargin: (!frameAroundContents && vscrollbar.visible ? vscrollbar.width: 0) + frameWidth + anchors.bottomMargin: (!frameAroundContents && hscrollbar.visible ? hscrollbar.height : 0) + frameWidth + + focus: true + clip: true + + Keys.onUpPressed: { + blockUpdates = true + if (currentIndex > 0) currentIndex = currentIndex - 1 + wheelarea.verticalValue = contentY/wheelarea.scale + blockUpdates = false + } + Keys.onDownPressed: { + blockUpdates = true + if (currentIndex< count - 1) currentIndex = currentIndex + 1 + wheelarea.verticalValue = contentY/wheelarea.scale + blockUpdates = false + } + Keys.onPressed: { + if (event.key == Qt.Key_PageUp) { + vscrollbar.value = vscrollbar.value - tree.height + } else if (event.key == Qt.Key_PageDown) + vscrollbar.value = vscrollbar.value + tree.height + } + + onContentYChanged: { + // positionViewAtIndex(currentIndex, ListView.Visible) + // highlight follows item + blockUpdates = true + vscrollbar.value = tree.contentY + blockUpdates = false + } + + delegate: Item { + id: rowitem + width: row.width + height: row.height + anchors.margins: frameWidth + property int rowIndex: model.index + property bool itemAlternateBackground: alternateRowColor && rowIndex % 2 == 1 + Loader { + id: rowstyle + // row delegate + sourceComponent: root.rowDelegate + // Row fills the tree width regardless of item size + // But scrollbar should not adjust to it + width: frameitem.width + height: row.height + x: contentX + + property bool itemAlternateBackground: rowitem.itemAlternateBackground + property bool itemSelected: rowitem.ListView.isCurrentItem + } + Row { + id: row + anchors.left: parent.left + + Repeater { + id: repeater + model: root.header.length + Loader { + id: itemDelegateLoader + visible: header[index].visible + sourceComponent: itemDelegate + property variant model: tree.model + property variant itemProperty: header[index].property + + width: header[index].width + height: item ? item.height : Math.max(16, styleitem.sizeFromContents(16, 16).height) + + function getValue() { + if (index < header.length && + root.model.get(rowIndex).hasOwnProperty(header[index].property)) + return root.model.get(rowIndex)[ header[index].property] + } + property variant itemValue: root.model.get(rowIndex)[ header[index].property] + property bool itemSelected: rowitem.ListView.isCurrentItem + property color itemForeground: itemSelected ? rowstyleitem.highlightedTextColor : rowstyleitem.textColor + property int rowIndex: rowitem.rowIndex + property int columnIndex: index + property int itemElideMode: header[index].elideMode + } + } + onWidthChanged: tree.contentWidth = width + } + } + } + Text{ id:text } + + Item { + id: tableColumn + clip: true + anchors.top: frameitem.top + anchors.left: frameitem.left + anchors.right: frameitem.right + anchors.margins: frameWidth + visible: headerVisible + Behavior on height { NumberAnimation{duration:80}} + height: headerVisible ? styleitem.sizeFromContents(text.font.pixelSize, styleitem.fontHeight).height : frameWidth + + Row { + id: headerrow + + anchors.top: parent.top + height:parent.height + x: -tree.contentX + + Repeater { + id: repeater + model: header.length + property int targetIndex: -1 + property int dragIndex: -1 + delegate: Item { + z:-index + width: header[index].width + visible: header[index].visible + height: headerrow.height + + Loader { + sourceComponent: root.headerDelegate + anchors.fill: parent + property string itemValue: header[index].caption + property string itemSort: (sortIndicatorVisible && index == sortColumn) ? (sortIndicatorDirection == "up" ? "up" : "down") : ""; + property bool itemPressed: headerClickArea.pressed + property bool itemContainsMouse: headerClickArea.containsMouse + } + Rectangle{ + id: targetmark + width: parent.width + height:parent.height + opacity: (index == repeater.targetIndex && repeater.targetIndex != repeater.dragIndex) ? 0.5 : 0 + Behavior on opacity { NumberAnimation{duration:160}} + color: palette.highlight + } + + MouseArea{ + id: headerClickArea + drag.axis: Qt.YAxis + hoverEnabled: true + anchors.fill: parent + onClicked: { + if (sortColumn == index) + sortIndicatorDirection = sortIndicatorDirection === "up" ? "down" : "up" + sortColumn = index + } + // Here we handle moving header sections + onMousePositionChanged: { + if (pressed) { // only do this while dragging + for (var h = 0 ; h < header.length ; ++h) { + if (drag.target.x > headerrow.children[h].x - 10) { + repeater.targetIndex = header.length - h - 1 + break + } + } + } + } + + onPressed: { + repeater.dragIndex = index + draghandle.x = parent.x + } + + onReleased: { + if (repeater.targetIndex >= 0 && repeater.targetIndex != index ) { + // Rearrange the header sections + var items = new Array + for (var i = 0 ; i< header.length ; ++i) + items.push(header[i]) + items.splice(index, 1); + items.splice(repeater.targetIndex, 0, header[index]); + header = items + if (sortColumn == index) + sortColumn = repeater.targetIndex + } + repeater.targetIndex = -1 + } + drag.maximumX: 1000 + drag.minimumX: -1000 + drag.target: draghandle + } + + Loader { + id: draghandle + parent: tableColumn + sourceComponent: root.headerDelegate + width: header[index].width + height: parent.height + property string itemValue: header[index].caption + property string itemSort: (sortIndicatorVisible && index == sortColumn) ? (sortIndicatorDirection == "up" ? "up" : "down") : ""; + property bool itemPressed: headerClickArea.pressed + property bool itemContainsMouse: headerClickArea.containsMouse + visible: headerClickArea.pressed + opacity: 0.5 + } + + + MouseArea { + id: headerResizeHandle + property int offset: 0 + property int minimumSize: 20 + anchors.rightMargin: -width/2 + width: 16 ; height: parent.height + anchors.right: parent.right + onPositionChanged: { + var newHeaderWidth = header[index].width + (mouseX - offset) + header[index].width = Math.max(minimumSize, newHeaderWidth) + } + property bool found:false + + onDoubleClicked: { + var row + var minWidth = 0 + var listdata = tree.children[0] + for (row = 0 ; row < listdata.children.length ; ++row){ + var item = listdata.children[row+1] + if (item && item.children[1] && item.children[1].children[index] && + item.children[1].children[index].children[0].hasOwnProperty("implicitWidth")) + minWidth = Math.max(minWidth, item.children[1].children[index].children[0].implicitWidth) + } + if (minWidth) + header[index].width = minWidth + } + onPressedChanged: if(pressed)offset=mouseX + QStyleItem { + anchors.fill: parent + cursor: "splithcursor" + } + } + } + } + } + Loader { + id: loader + z:-1 + sourceComponent: root.headerDelegate + anchors.top: parent.top + anchors.right: parent.right + anchors.bottom: headerrow.bottom + anchors.rightMargin: -2 + width: root.width - headerrow.width + property string itemValue + property string itemSort + property bool itemPressed + property bool itemContainsMouse + } + } + + WheelArea { + id: wheelarea + anchors.fill: parent + property int scale: 5 + horizontalMinimumValue: hscrollbar.minimumValue/scale + horizontalMaximumValue: hscrollbar.maximumValue/scale + verticalMinimumValue: vscrollbar.minimumValue/scale + verticalMaximumValue: vscrollbar.maximumValue/scale + + verticalValue: contentY/scale + horizontalValue: contentX/scale + + onVerticalValueChanged: { + if(!tree.blockUpdates) { + contentY = verticalValue * scale + vscrollbar.value = contentY + } + } + + onHorizontalValueChanged: { + if(!tree.blockUpdates) { + contentX = horizontalValue * scale + hscrollbar.value = contentX + } + } + } + + ScrollBar { + id: hscrollbar + orientation: Qt.Horizontal + property int availableWidth: root.width - vscrollbar.width + visible: contentWidth > availableWidth + maximumValue: contentWidth > availableWidth ? tree.contentWidth - availableWidth : 0 + minimumValue: 0 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: frameWidth + anchors.bottomMargin: styleitem.frameoffset + anchors.rightMargin: vscrollbar.visible ? scrollbarExtent : (frame ? 1 : 0) + onValueChanged: { + if (!tree.blockUpdates) + contentX = value + } + property int scrollbarExtent : styleitem.pixelMetric("scrollbarExtent"); + } + + ScrollBar { + id: vscrollbar + orientation: Qt.Vertical + // We cannot bind directly to tree.height due to binding loops so we have to redo the calculation here + property int availableHeight : root.height - (hscrollbar.visible ? hscrollbar.height : 0) - tableColumn.height + visible: contentHeight > availableHeight + maximumValue: contentHeight > availableHeight ? tree.contentHeight - availableHeight : 0 + minimumValue: 0 + anchors.rightMargin: styleitem.frameoffset + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.topMargin: styleitem.style == "mac" ? tableColumn.height : 0 + onValueChanged: { + if(!tree.blockUpdates) + contentY = value + } + anchors.bottomMargin: hscrollbar.visible ? hscrollbar.height : styleitem.frameoffset + + Keys.onUpPressed: if (tree.currentIndex > 0) tree.currentIndex = tree.currentIndex - 1 + Keys.onDownPressed: if (tree.currentIndex< tree.count - 1) tree.currentIndex = tree.currentIndex + 1 + } + + QStyleItem { + z: 2 + anchors.fill: parent + anchors.margins: -4 + visible: highlightOnFocus && parent.activeFocus && styleitem.styleHint("focuswidget") + elementType: "focusframe" + } + + QStyleItem { + id: styleitem + elementType: "header" + visible:false + property int frameoffset: style === "mac" ? -1 : 0 + } + QStyleItem { + id: rowstyleitem + elementType: "item" + visible:false + property color textColor: styleHint("textColor") + property color highlightedTextColor: styleHint("highlightedTextColor") + } + SystemPalette{id:palette} +} diff --git a/share/qtcreator/welcomescreen/components/TextArea.qml b/share/qtcreator/welcomescreen/components/TextArea.qml new file mode 100644 index 00000000000..440081f829e --- /dev/null +++ b/share/qtcreator/welcomescreen/components/TextArea.qml @@ -0,0 +1,51 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +ScrollArea { + id:area + color: "white" + width: 280 + height: 120 + contentWidth: 200 + + property alias text: edit.text + property alias wrapMode: edit.wrapMode + property alias readOnly: edit.readOnly + + highlightOnFocus: true + property int documentMargins: 4 + frame: true + + Item { + anchors.left: parent.left + anchors.top: parent.top + height: edit.height - 8 + anchors.margins: documentMargins + + TextEdit { + id: edit + text: loremIpsum + loremIpsum; + wrapMode: TextEdit.WordWrap; + width: area.contentWidth + selectByMouse: true + readOnly: false + focus: true + + // keep textcursor within scrollarea + onCursorPositionChanged: { + if (cursorRectangle.y >= area.contentY + area.height - 1.5*cursorRectangle.height) + area.contentY = cursorRectangle.y - area.height + 1.5*cursorRectangle.height + else if (cursorRectangle.y < area.contentY) + area.contentY = cursorRectangle.y + } + } + } + + Keys.onPressed: { + if (event.key == Qt.Key_PageUp) { + verticalValue = verticalValue - area.height + } else if (event.key == Qt.Key_PageDown) + verticalValue = verticalValue + area.height + } +} diff --git a/share/qtcreator/welcomescreen/components/TextField.qml b/share/qtcreator/welcomescreen/components/TextField.qml new file mode 100644 index 00000000000..ccadadf86fc --- /dev/null +++ b/share/qtcreator/welcomescreen/components/TextField.qml @@ -0,0 +1,42 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.TextField { + id: textfield + minimumWidth: 200 + + placeholderText: "" + topMargin: 2 + bottomMargin: 2 + leftMargin: 6 + rightMargin: 6 + + height: backgroundItem.sizeFromContents(200, 25).height + width: 200 + clip: false + + background: QStyleItem { + anchors.fill: parent + elementType: "edit" + sunken: true + focus: textfield.activeFocus + hover: containsMouse + } + + Item{ + id: focusFrame + anchors.fill: textfield + parent: textfield + visible: framestyle.styleHint("focuswidget") + QStyleItem { + id: framestyle + anchors.margins: -2 + anchors.rightMargin:-4 + anchors.bottomMargin:-4 + anchors.fill: parent + visible: textfield.activeFocus + elementType: "focusframe" + } + } +} diff --git a/share/qtcreator/welcomescreen/components/ToolBar.qml b/share/qtcreator/welcomescreen/components/ToolBar.qml new file mode 100644 index 00000000000..98367723c5a --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ToolBar.qml @@ -0,0 +1,11 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +QStyleItem{ + id: toolbar + width: 200 + height: sizeFromContents(32, 32).height + elementType: "toolbar" +} + diff --git a/share/qtcreator/welcomescreen/components/ToolButton.qml b/share/qtcreator/welcomescreen/components/ToolButton.qml new file mode 100644 index 00000000000..7de72fd10c7 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/ToolButton.qml @@ -0,0 +1,34 @@ +import QtQuick 1.0 +import "custom" as Components +import "plugin" + +Components.Button { + id:button + + height: 40; //styleitem.sizeFromContents(32, 32).height + width: 40; //styleitem.sizeFromContents(32, 32).width + + QStyleItem {elementType: "toolbutton"; id:styleitem } + + background: QStyleItem { + anchors.fill: parent + id: styleitem + elementType: "toolbutton" + on: pressed | checked + sunken: pressed + raised: containsMouse + hover: containsMouse + + Text { + text: button.text + anchors.centerIn: parent + visible: button.iconSource == "" + } + + Image { + source: button.iconSource + anchors.centerIn: parent + opacity: enabled ? 1 : 0.5 + } + } +} diff --git a/share/qtcreator/welcomescreen/components/components.pro b/share/qtcreator/welcomescreen/components/components.pro new file mode 100644 index 00000000000..83e0a3d4c0b --- /dev/null +++ b/share/qtcreator/welcomescreen/components/components.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = styleitem diff --git a/share/qtcreator/welcomescreen/components/custom/BasicButton.qml b/share/qtcreator/welcomescreen/components/custom/BasicButton.qml new file mode 100644 index 00000000000..ee591e2026c --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/BasicButton.qml @@ -0,0 +1,51 @@ +import QtQuick 1.0 +import "./behaviors" // ButtonBehavior + +Item { + id: button + + signal clicked + property alias pressed: behavior.pressed + property alias containsMouse: behavior.containsMouse + property alias checkable: behavior.checkable // button toggles between checked and !checked + property alias checked: behavior.checked + + property Component background: null + property Item backgroundItem: backgroundLoader.item + + property color textColor: syspal.text; + property bool activeFocusOnPress: true + property string tooltip + + signal toolTipTriggered + + // implementation + + property string __position: "only" + width: backgroundLoader.item.width + height: backgroundLoader.item.height + + Loader { + id: backgroundLoader + anchors.fill: parent + sourceComponent: background + property alias styledItem: button + property alias position: button.__position + } + + ButtonBehavior { + id: behavior + anchors.fill: parent + onClicked: button.clicked() + onPressedChanged: if (activeFocusOnPress) button.focus = true + onMouseMoved: {tiptimer.restart()} + Timer{ + id: tiptimer + interval:1000 + running:containsMouse && tooltip.length + onTriggered: button.toolTipTriggered() + } + } + + SystemPalette { id: syspal } +} diff --git a/share/qtcreator/welcomescreen/components/custom/Button.qml b/share/qtcreator/welcomescreen/components/custom/Button.qml new file mode 100644 index 00000000000..45abc83f604 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/Button.qml @@ -0,0 +1,21 @@ +import QtQuick 1.0 + +BasicButton { + id: button + + property string text + property url iconSource + property Component label: null + + // implementation + + background: defaultStyle.background + property Item labelItem: labelLoader.item + + Loader { + id: labelLoader + anchors.fill: parent + property alias styledItem: button + sourceComponent: label + } +} diff --git a/share/qtcreator/welcomescreen/components/custom/ButtonColumn.qml b/share/qtcreator/welcomescreen/components/custom/ButtonColumn.qml new file mode 100644 index 00000000000..8d63a855c3b --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/ButtonColumn.qml @@ -0,0 +1,44 @@ +import Qt 4.7 +import "ButtonGroup.js" as Behavior + +/* + Class: ButtonColumn + A ButtonColumn allows you to group Buttons in a column. It provides a selection-behavior as well. + + Note: This component don't support the enabled property. + If you need to disable it you should disable all the buttons inside it. + + + ButtonColumn { + Button { text: "Top" } + Button { text: "Bottom" } + } + +*/ +Column { + id: root + + /* + * Property: exclusive + * [bool=true] Specifies the grouping behavior. If enabled, the checked property on buttons contained + * in the group will be exclusive. + * + * Note that a button in an exclusive group will allways be checkable + */ + property bool exclusive: true + + /* + * Property: checkedButton + * [string] Contains the last checked Button. + */ + property Item checkedButton; + + Component.onCompleted: { + Behavior.create(root, {direction: Qt.Vertical}); + } + + Component.onDestruction: { + Behavior.destroy(); + } + +} diff --git a/share/qtcreator/welcomescreen/components/custom/ButtonGroup.js b/share/qtcreator/welcomescreen/components/custom/ButtonGroup.js new file mode 100644 index 00000000000..19d05fee33d --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/ButtonGroup.js @@ -0,0 +1,137 @@ +var self; +var checkHandlers = []; +var visibleButtons = []; +var nonVisibleButtons = []; +var direction; + +function create(that, options) { + self = that; + direction = options.direction || Qt.Horizontal; + self.childrenChanged.connect(rebuild); +// self.widthChanged.connect(resizeChildren); + build(); +} + +function isButton(item) { + if (item && item.hasOwnProperty("__position")) + return true; + return false; +} + +function hasChecked(item) { + return (item && item.hasOwnProperty("checked")); +} + +function destroy() { + self.childrenChanged.disconnect(rebuild); +// self.widthChanged.disconnect(resizeChildren); + cleanup(); +} + +function build() { + visibleButtons = []; + nonVisibleButtons = []; + + for (var i = 0, item; (item = self.children[i]); i++) { + if (!hasChecked(item)) + continue; + + item.visibleChanged.connect(rebuild); // Not optimal, but hardly a bottleneck in your app + if (!item.visible) { + nonVisibleButtons.push(item); + continue; + } + visibleButtons.push(item); + + if (self.exclusive && item.hasOwnProperty("checkable")) + item.checkable = true; + + if (self.exclusive) { + item.checked = false; + checkHandlers.push(checkExclusive(item)); + item.checkedChanged.connect(checkHandlers[checkHandlers.length - 1]); + } + } + + var nrButtons = visibleButtons.length; + if (nrButtons == 0) + return; + + if (self.checkedButton) + self.checkedButton.checked = true; + else if (self.exclusive) { + self.checkedButton = visibleButtons[0]; + self.checkedButton.checked = true; + } + + if (nrButtons == 1) { + finishButton(visibleButtons[0], "only"); + } else { + finishButton(visibleButtons[0], direction == Qt.Horizontal ? "leftmost" : "top"); + for (var i = 1; i < nrButtons - 1; i++) + finishButton(visibleButtons[i], direction == Qt.Horizontal ? "h_middle": "v_middle"); + finishButton(visibleButtons[nrButtons - 1], direction == Qt.Horizontal ? "rightmost" : "bottom"); + } +} + +function finishButton(button, position) { + if (isButton(button)) { + button.__position = position; + if (direction == Qt.Vertical) { + button.anchors.left = self.left //mm How to make this not cause binding loops? see QTBUG-17162 + button.anchors.right = self.right + } + } +} + +function cleanup() { + visibleButtons.forEach(function(item, i) { + if (checkHandlers[i]) + item.checkedChanged.disconnect(checkHandlers[i]); + item.visibleChanged.disconnect(rebuild); + }); + checkHandlers = []; + + nonVisibleButtons.forEach(function(item, i) { + item.visibleChanged.disconnect(rebuild); + }); +} + +function rebuild() { + if (self == undefined) + return; + + cleanup(); + build(); +} + +function resizeChildren() { + if (direction != Qt.Horizontal) + return; + + var extraPixels = self.width % visibleButtons; + var buttonSize = (self.width - extraPixels) / visibleButtons; + visibleButtons.forEach(function(item, i) { + if (!item || !item.visible) + return; + item.width = buttonSize + (extraPixels > 0 ? 1 : 0); + if (extraPixels > 0) + extraPixels--; + }); +} + +function checkExclusive(item) { + var button = item; + return function() { + for (var i = 0, ref; (ref = visibleButtons[i]); i++) { + if (ref.checked == (button === ref)) + continue; + + // Disconnect the signal to avoid recursive calls + ref.checkedChanged.disconnect(checkHandlers[i]); + ref.checked = !ref.checked; + ref.checkedChanged.connect(checkHandlers[i]); + } + self.checkedButton = button; + } +} diff --git a/share/qtcreator/welcomescreen/components/custom/ButtonRow.qml b/share/qtcreator/welcomescreen/components/custom/ButtonRow.qml new file mode 100644 index 00000000000..7c2d3ea7ad6 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/ButtonRow.qml @@ -0,0 +1,43 @@ +import Qt 4.7 +import "ButtonGroup.js" as Behavior + +/* + Class: ButtonRow + A ButtonRow allows you to group Buttons in a row. It provides a selection-behavior as well. + + Note: This component don't support the enabled property. + If you need to disable it you should disable all the buttons inside it. + + + ButtonRow { + Button { text: "Left" } + Button { text: "Right" } + } + +*/ +Row { + id: root + + /* + * Property: exclusive + * [bool=true] Specifies the grouping behavior. If enabled, the checked property on buttons contained + * in the group will be exclusive. + * + * Note that a button in an exclusive group will allways be checkable + */ + property bool exclusive: true + + /* + * Property: checkedButton + * [string] Contains the last checked Button. + */ + property Item checkedButton; + + Component.onCompleted: { + Behavior.create(root, {direction: Qt.Horizontal}); + } + + Component.onDestruction: { + Behavior.destroy(); + } +} diff --git a/share/qtcreator/welcomescreen/components/custom/CheckBox.qml b/share/qtcreator/welcomescreen/components/custom/CheckBox.qml new file mode 100644 index 00000000000..a49d71d8a53 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/CheckBox.qml @@ -0,0 +1,32 @@ +import QtQuick 1.0 +import "./behaviors" + +Item { + id: checkBox + + signal clicked + property alias pressed: behavior.pressed + property alias checked: behavior.checked + property alias containsMouse: behavior.containsMouse + property bool activeFocusOnPress: true + property Component background: null + property Item backgroundItem: backgroundLoader.item + + // implementation + + Loader { + id: backgroundLoader + anchors.fill: parent + property alias styledItem: checkBox + sourceComponent: background + } + + ButtonBehavior { + id: behavior + anchors.fill: parent + checkable: true + onClicked: {if (activeFocusOnPress)checkBox.focus = true; checkBox.clicked()} + } + + SystemPalette { id: syspal } +} diff --git a/share/qtcreator/welcomescreen/components/custom/ChoiceList.qml b/share/qtcreator/welcomescreen/components/custom/ChoiceList.qml new file mode 100644 index 00000000000..a316f042ed9 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/ChoiceList.qml @@ -0,0 +1,49 @@ +import QtQuick 1.0 +import "./private" as Private + +Item { + id: choiceList + + property alias model: popup.model + property alias currentIndex: popup.currentIndex + property alias currentText: popup.currentText + property alias popupOpen: popup.popupOpen + property alias containsMouse: popup.containsMouse + property alias pressed: popup.buttonPressed + + property Component background: null + property Item backgroundItem: backgroundLoader.item + property Component listItem: null + property Component popupFrame: null + + property int leftMargin: 0 + property int topMargin: 0 + property int rightMargin: 0 + property int bottomMargin: 0 + + property string popupBehavior + width: 0 + height: 0 + + property bool activeFocusOnPress: true + + Loader { + id: backgroundLoader + property alias styledItem: choiceList + sourceComponent: background + anchors.fill: parent + property string currentItemText: model.get(currentIndex).text + } + + Private.ChoiceListPopup { + // NB: This ChoiceListPopup is also the mouse area + // for the component (to enable drag'n'release) + id: popup + listItem: choiceList.listItem + popupFrame: choiceList.popupFrame + } + + Keys.onSpacePressed: { choiceList.popupOpen = !choiceList.popupOpen } + Keys.onUpPressed: { if (currentIndex < model.count - 1) currentIndex++ } + Keys.onDownPressed: {if (currentIndex > 0) currentIndex-- } +} diff --git a/share/qtcreator/welcomescreen/components/custom/GroupBox.qml b/share/qtcreator/welcomescreen/components/custom/GroupBox.qml new file mode 100644 index 00000000000..ab1117e3e8a --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/GroupBox.qml @@ -0,0 +1,54 @@ +import QtQuick 1.0 + +FocusScope { + id: groupbox + + width: Math.max(200, contentWidth + loader.leftMargin + loader.rightMargin) + height: contentHeight + loader.topMargin + loader.bottomMargin + + default property alias children: content.children + + property string title + property bool checkable: false + property int contentWidth: content.childrenRect.width + property int contentHeight: content.childrenRect.height + property double contentOpacity: 1 + + property Component background: null + property Item backgroundItem: loader.item + + property CheckBox checkbox: check + property alias checked: check.checked + + Loader { + id: loader + anchors.fill: parent + property int topMargin: 22 + property int bottomMargin: 4 + property int leftMargin: 4 + property int rightMargin: 4 + + property alias styledItem: groupbox + sourceComponent: background + + Item { + id:content + z: 1 + opacity: contentOpacity + anchors.topMargin: loader.topMargin + anchors.leftMargin: 8 + anchors.top:parent.top + anchors.left:parent.left + enabled: (!checkable || checkbox.checked) + } + + CheckBox { + id: check + checked: true + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: loader.topMargin + } + } +} diff --git a/share/qtcreator/welcomescreen/components/custom/ProgressBar.qml b/share/qtcreator/welcomescreen/components/custom/ProgressBar.qml new file mode 100644 index 00000000000..3ad8bca6c0b --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/ProgressBar.qml @@ -0,0 +1,53 @@ +import QtQuick 1.0 + +Item { + id: progressBar + + property real value: 0 + property real minimumValue: 0 + property real maximumValue: 1 + property bool indeterminate: false + property bool containsMouse: mouseArea.containsMouse + + property int leftMargin: 0 + property int topMargin: 0 + property int rightMargin: 0 + property int bottomMargin: 0 + + property int minimumWidth: 0 + property int minimumHeight: 0 + + width: minimumWidth + height: minimumHeight + + property Component background: null + property Item backgroundItem: groove.item + + property color backgroundColor: syspal.base + property color progressColor: syspal.highlight + + Loader { + id: groove + property alias indeterminate:progressBar.indeterminate + property alias value:progressBar.value + property alias maximumValue:progressBar.maximumValue + property alias minimumValue:progressBar.minimumValue + + sourceComponent: background + anchors.fill: parent + } + + Item { + anchors.fill: parent + anchors.leftMargin: leftMargin + anchors.rightMargin: rightMargin + anchors.topMargin: topMargin + anchors.bottomMargin: bottomMargin + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + } +} diff --git a/share/qtcreator/welcomescreen/components/custom/Slider.qml b/share/qtcreator/welcomescreen/components/custom/Slider.qml new file mode 100644 index 00000000000..f551baa85ad --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/Slider.qml @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** 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 Technology Preview License Agreement accompanying this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +import QtQuick 1.0 +import "../" + +Item { + id: slider + + // COMMON API + property int orientation: Qt.Horizontal + property alias minimumValue: range.minimumValue + property alias maximumValue: range.maximumValue + property alias inverted: range.inverted + property bool updateValueWhileDragging: true + property alias pressed: mouseArea.pressed + property alias stepSize: range.stepSize + property alias hoverEnabled: mouseArea.hoverEnabled + + // NOTE: this property is in/out, the user can set it, create bindings to it, and + // at the same time the slider wants to update. There's no way in QML to do this kind + // of updates AND allow the user bind it (without a Binding object). That's the + // reason this is an alias to a C++ property in range model. + property alias value: range.value + property bool containsMouse: mouseArea.containsMouse + + // CONVENIENCE TO BE USED BY STYLES + + property int leftMargin: 0 + property int rightMargin: 0 + + // EXTENSIONS + // Indicate that we want animations in the Slider, people customizing should + // look at it to decide whether or not active animations. + property bool animated: true + property bool activeFocusOnPress: true + + // Value indicator displays the current value near the slider + property bool valueIndicatorVisible: true + property int valueIndicatorMargin: 10 + property string valueIndicatorPosition: _isVertical ? "Left" : "Top" + + // Reimplement this function to control how the value is shown in the + // indicator. + function formatValue(v) { + return Math.round(v); + } + + // Hooks for customizing the pieces of the slider + property Component groove: null + property Component handle: null + property Component valueIndicator: null + + // PRIVATE/CONVENIENCE + property bool _isVertical: orientation == Qt.Vertical + + // This is a template slider, so every piece can be modified by passing a + // different Component. The main elements in the implementation are + // + // - the 'range' does the calculations to map position to/from value, + // it also serves as a data storage for both properties; + // + // - the 'fakeHandle' is what the mouse area drags on the screen, it feeds + // the 'range' position and also reads it when convenient; + // + // - the real 'handle' it is the visual representation of the handle, that + // just follows the 'fakeHandle' position. + // + // When the 'updateValueWhileDragging' is false and we are dragging, we stop + // feeding the range with position information, delaying until the next + // mouse release. + // + // Everything is encapsulated in a contents Item, so for the + // vertical slider, we just swap the height/width, make it + // horizontal, and then use rotation to make it vertical again. + + Item { + id: contents + + width: _isVertical ? slider.height : slider.width + height: _isVertical ? slider.width : slider.height + rotation: _isVertical ? -90 : 0 + + anchors.centerIn: slider + + RangeModel { + id: range + minimumValue: 0.0 + maximumValue: 1.0 + value: 0 + stepSize: 0.0 + inverted: false + + positionAtMinimum: leftMargin + positionAtMaximum: contents.width - rightMargin + } + + Loader { + id: grooveLoader + anchors.fill: parent + sourceComponent: groove + + property real handlePosition : handleLoader.x + function positionForValue(value) { + return range.positionForValue(value) - leftMargin; + } + } + + Loader { + id: handleLoader + transform: Translate { x: - handleLoader.width / 2 } + + anchors.verticalCenter: grooveLoader.verticalCenter + + sourceComponent: handle + + x: fakeHandle.x + Behavior on x { + id: behavior + enabled: !mouseArea.drag.active && slider.animated + + PropertyAnimation { + duration: behavior.enabled ? 150 : 0 + easing.type: Easing.OutSine + } + } + } + + Item { + id: fakeHandle + width: handleLoader.width + height: handleLoader.height + transform: Translate { x: - handleLoader.width / 2 } + } + + MouseArea { + id: mouseArea + hoverEnabled: true + anchors.centerIn: parent + anchors.horizontalCenterOffset: (slider.leftMargin - slider.rightMargin) / 2 + + width: parent.width + handleLoader.width - slider.rightMargin - slider.leftMargin + height: parent.height + + drag.target: fakeHandle + drag.axis: Drag.XAxis + drag.minimumX: range.positionAtMinimum + drag.maximumX: range.positionAtMaximum + + onPressed: { + + if (activeFocusOnPress) + slider.focus = true; + + // Clamp the value + var newX = Math.max(mouse.x, drag.minimumX); + newX = Math.min(newX, drag.maximumX); + + // Debounce the press: a press event inside the handler will not + // change its position, the user needs to drag it. + + // Note this really messes up things for scrollbar + // if (Math.abs(newX - fakeHandle.x) > handleLoader.width / 2) + range.position = newX; + } + + onReleased: { + // If we don't update while dragging, this is the only + // moment that the range is updated. + if (!slider.updateValueWhileDragging) + range.position = fakeHandle.x; + } + } + + Loader { + id: valueIndicatorLoader + + transform: Translate { x: - handleLoader.width / 2 } + rotation: _isVertical ? 90 : 0 + visible: valueIndicatorVisible + + // Properties available for the delegate component. Note that the indicatorText + // shows the value for the position the handle is, which is not necessarily the + // available as the current slider.value, since updateValueWhileDragging can + // be set to 'false'. + property string indicatorText: slider.formatValue(range.valueForPosition(handleLoader.x)) + property bool dragging: mouseArea.drag.active + + sourceComponent: valueIndicator + + state: { + if (!_isVertical) + return slider.valueIndicatorPosition; + + if (valueIndicatorPosition == "Right") + return "Bottom"; + if (valueIndicatorPosition == "Top") + return "Right"; + if (valueIndicatorPosition == "Bottom") + return "Left"; + + return "Top"; + } + + anchors.margins: valueIndicatorMargin + + states: [ + State { + name: "Top" + AnchorChanges { + target: valueIndicatorLoader + anchors.bottom: handleLoader.top + anchors.horizontalCenter: handleLoader.horizontalCenter + } + }, + State { + name: "Bottom" + AnchorChanges { + target: valueIndicatorLoader + anchors.top: handleLoader.bottom + anchors.horizontalCenter: handleLoader.horizontalCenter + } + }, + State { + name: "Right" + AnchorChanges { + target: valueIndicatorLoader + anchors.left: handleLoader.right + anchors.verticalCenter: handleLoader.verticalCenter + } + }, + State { + name: "Left" + AnchorChanges { + target: valueIndicatorLoader + anchors.right: handleLoader.left + anchors.verticalCenter: handleLoader.verticalCenter + } + } + ] + } + } + + // Range position normally follow fakeHandle, except when + // 'updateValueWhileDragging' is false. In this case it will only follow + // if the user is not pressing the handle. + Binding { + when: updateValueWhileDragging || !mouseArea.pressed + target: range + property: "position" + value: fakeHandle.x + } + + // During the drag, we simply ignore position set from the range, this + // means that setting a value while dragging will not "interrupt" the + // dragging activity. + Binding { + when: !mouseArea.drag.active + target: fakeHandle + property: "x" + value: range.position + } +} diff --git a/share/qtcreator/welcomescreen/components/custom/SpinBox.qml b/share/qtcreator/welcomescreen/components/custom/SpinBox.qml new file mode 100644 index 00000000000..1110ff824e0 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/SpinBox.qml @@ -0,0 +1,164 @@ +import QtQuick 1.0 + +FocusScope { + id: spinbox + SystemPalette{id:syspal} + + property int minimumWidth: 0 + property int minimumHeight: 0 + + property int leftMargin: 0 + property int topMargin: 0 + property int rightMargin: 0 + property int bottomMargin: 0 + + width: Math.max(minimumWidth, + input.width + leftMargin + rightMargin) + + height: Math.max(minimumHeight, + input.height + topMargin + bottomMargin) + + property real value: 0.0 + property real maximumValue: 99 + property real minimumValue: 0 + property real singleStep: 1 + property string postfix + + property bool upEnabled: value != maximumValue; + property bool downEnabled: value != minimumValue; + property alias upPressed: mouseUp.pressed + property alias downPressed: mouseDown.pressed + property alias upHovered: mouseUp.containsMouse + property alias downHovered: mouseDown.containsMouse + property alias containsMouse: mouseArea.containsMouse + property color textColor: syspal.text + property alias font: input.font + + property Component background: null + property Item backgroundItem: backgroundComponent.item + property Component up: null + property Component down: null + + QtObject { + id: componentPrivate + property bool valueUpdate: false + } + + function increment() { + setValue(input.text) + value += singleStep + if (value > maximumValue) + value = maximumValue + input.text = value + } + + function decrement() { + setValue(input.text) + value -= singleStep + if (value < minimumValue) + value = minimumValue + input.text = value + } + + function setValue(v) { + var newval = parseFloat(v) + if (newval > maximumValue) + newval = maximumValue + else if (v < minimumValue) + newval = minimumValue + value = newval + input.text = value + } + + Component.onCompleted: setValue(value) + + onValueChanged: { + componentPrivate.valueUpdate = true + input.text = value + componentPrivate.valueUpdate = false + } + + // background + Loader { + id: backgroundComponent + anchors.fill: parent + sourceComponent: background + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + } + + TextInput { + id: input + + font.pixelSize: 14 + anchors.margins: 5 + anchors.leftMargin: leftMargin + anchors.topMargin: topMargin + anchors.rightMargin: rightMargin + anchors.bottomMargin: bottomMargin + anchors.fill: parent + selectByMouse: true + + // validator: DoubleValidator { bottom: minimumValue; top: maximumValue; } + onAccepted: {setValue(input.text)} + onActiveFocusChanged: setValue(input.text) + color: textColor + opacity: parent.enabled ? 1 : 0.5 + Text { + text: postfix + anchors.rightMargin: 4 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + + Loader { + id: upButton + property alias pressed : spinbox.upPressed + property alias hover : spinbox.upHovered + property alias enabled : spinbox.upEnabled + sourceComponent: up + MouseArea { + id: mouseUp + anchors.fill: upButton.item + onClicked: increment() + + property bool autoincrement: false; + onReleased: autoincrement = false + Timer { running: mouseUp.pressed; interval: 350 ; onTriggered: mouseUp.autoincrement = true } + Timer { running: mouseUp.autoincrement; interval: 60 ; repeat: true ; onTriggered: increment() } + } + onLoaded: { + item.parent = spinbox + mouseUp.parent = item + } + } + + Loader { + id: downButton + property alias pressed : spinbox.downPressed + property alias hover : spinbox.downHovered + property alias enabled : spinbox.downEnabled + sourceComponent: down + MouseArea { + id: mouseDown + anchors.fill: downButton.item + onClicked: decrement() + + property bool autoincrement: false; + onReleased: autoincrement = false + Timer { running: mouseDown.pressed; interval: 350 ; onTriggered: mouseDown.autoincrement = true } + Timer { running: mouseDown.autoincrement; interval: 60 ; repeat: true ; onTriggered: decrement() } + } + onLoaded: { + item.parent = spinbox + mouseDown.parent = item + } + } + Keys.onUpPressed: increment() + Keys.onDownPressed: decrement() +} diff --git a/share/qtcreator/welcomescreen/components/custom/SplitterRow.qml b/share/qtcreator/welcomescreen/components/custom/SplitterRow.qml new file mode 100644 index 00000000000..adf73f317bb --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/SplitterRow.qml @@ -0,0 +1,328 @@ +import QtQuick 1.0 +import "private" + +/* +* +* SplitterRow +* +* SplitterRow is a component that provides a way to layout items horisontally with +* a draggable splitter added in-between each item. +* +* Add items to the SplitterRow by inserting them as child items. The splitter handle +* is outsourced as a delegate (handleBackground). For this delegate to work properly, +* it will need to contain a mouse area that communicates with the SplitterRow by binding +* 'onMouseXChanged: handleDragged(handleIndex)', and 'drag.target: dragTarget'. +* +* The SplitterRow contains the followin API: +* +* Component handleBackground - delegate that will be instanciated between each +* child item. Inside the delegate, the following properties are available: +* int handleIndex - specifies the index of the splitter handle. The handle +* between the first and the second item will get index 0, the next handle index 1 etc. +* Item handleDragTarget - convenience property that tells which drag target any +* inner mouse areas that controls the handle should bind to. +* function handleDragged(handleIndex) - function that should be called whenever +* the handle is dragged to a new position +* +* The following properties can optionally be added for each direct child item of SplitterRow: +* +* real minimumWidth - if present, ensures that the item cannot be resized below the +* given value. A value of -1 will disable it. +* real maximumWidth - if present, ensures that the item cannot be resized above the +* given value. A value of -1 will disable it. +* real percentageWidth - if present, should be a value between 0-100. This value specifies +* a percentage of the width of the SplitterRow width. If the width of the SplitterRow +* change, the width of the item will change as well. 'percentageWidth' have precedence +* over 'width', which means that SplitterRow will ignore any assignments done to 'width'. +* A value of -1 disables it. +* bool expanding - if present, the item will consume all extra space in the SplitterRow, down to +* minimumWidth. This means that that 'width', 'percentageWidth' and 'maximumWidth' will be ignored. +* There will always be one (and only one) item in the SplitterRow that has this behaviour, and by +* default, it will be the last child item of the SplitterRow. Also note that which item that gets +* resized upon dragging a handle depends on whether the expanding item is located towards the left +* or the right of the handle. +* +* Example: +* +* To create a SplitterRow with three items, and let +* the center item be the one that should be expanding, one +* could do the following: +* +* SplitterRow { +* anchors.fill: parent +* +* handleBackground: Rectangle { +* width: 1 +* color: "black" +* +* MouseArea { +* anchors.fill: parent +* anchors.leftMargin: -2 +* anchors.rightMargin: -2 +* drag.axis: Qt.YAxis +* drag.target: handleDragTarget +* onMouseXChanged: handleDragged(handleIndex) +* } +* } +* +* Rectangle { +* color: "gray" +* width: 200 +* } +* Rectangle { +* property real minimumWidth: 50 +* property real maximumWidth: 400 +* property bool expanding: true +* color: "darkgray" +* } +* Rectangle { +* color: "gray" +* width: 200 +* } +* } +*/ + +Item { + id: root + default property alias items: splitterItems.children + property alias handles: splitterHandles.children + property Component handleBackground: Rectangle { width:3; color: "black" } + clip: true + + Component.onCompleted: d.init(); + onWidthChanged: d.updateLayout(); + + QtObject { + id: d + property int expandingIndex: items.length-1 + property bool updateOptimizationBlock: true + property bool bindingRecursionGuard: false + + function init() + { + for (var i=0; i handleIndex) { + // Resize item to the left. + // Ensure that the handle is not crossing other handles: + leftHandle = handles[handleIndex-1] + leftItem = items[handleIndex] + leftEdge = leftHandle ? (leftHandle.x + leftHandle.width) : 0 + handle.x = Math.max(leftEdge, handle.x) + newWidth = handle.x - leftEdge + if (root.width != 0 && leftItem.percentageWidth != undefined && leftItem.percentageWidth !== -1) + leftItem.percentageWidth = newWidth * (100 / root.width) + // The next line will trigger 'updateLayout' inside 'propertyChangeListener': + leftItem.width = newWidth + } else { + // Resize item to the right: + // Since the first item in the splitter always will have x=0, we need + // to ensure that the user cannot drag the handle more left than what + // we got space for: + var min = d.accumulatedWidth(0, handleIndex+1, true) + // Ensure that the handle is not crossing other handles: + rightItem = items[handleIndex+1] + rightHandle = handles[handleIndex+1] + rightEdge = (rightHandle ? rightHandle.x : root.width) + handle.x = Math.max(min, Math.max(Math.min((rightEdge - handle.width), handle.x))) + newWidth = rightEdge - (handle.x + handle.width) + if (root.width != 0 && rightItem.percentageWidth != undefined && rightItem.percentageWidth !== -1) + rightItem.percentageWidth = newWidth * (100 / root.width) + // The next line will trigger 'updateLayout' inside 'propertyChangeListener': + rightItem.width = newWidth + } + } + } + } + + Item { + id: splitterItems + anchors.fill: parent + } + Item { + id: splitterHandles + anchors.fill: parent + } + + Component { + // This dummy item becomes a child of all + // items it the splitter, just to provide a way + // to listed for changes to their width, expanding etc. + id: propertyChangeListener + Item { + id: target + width: parent.width + property bool expanding: (parent.expanding != undefined) ? parent.expanding : false + property real percentageWidth: (parent.percentageWidth != undefined) ? parent.percentageWidth : -1 + property real minimumWidth: (parent.minimumWidth != undefined) ? parent.minimumWidth : -1 + property real maximumWidth: (parent.maximumWidth != undefined) ? parent.maximumWidth : -1 + + onPercentageWidthChanged: d.updateLayout(); + onMinimumWidthChanged: d.updateLayout(); + onMaximumWidthChanged: d.updateLayout(); + + onExpandingChanged: { + // Find out which item that has the expanding flag: + for (var i=0; i 0 + ParentChange { target: popupBehavior; parent: root } + } + } + diff --git a/share/qtcreator/welcomescreen/components/custom/components.pro b/share/qtcreator/welcomescreen/components/custom/components.pro new file mode 100644 index 00000000000..be0663d7094 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/components.pro @@ -0,0 +1,49 @@ +TEMPLATE = subdirs # XXX: Avoid call the linker +TARGETPATH = Qt/labs/components/custom + +symbian { + INSTALL_IMPORTS = /resource/qt/imports +} else { + INSTALL_IMPORTS = $$[QT_INSTALL_IMPORTS] +} + +QML_FILES = \ + qmldir \ + BasicButton.qml \ + BusyIndicator.qml \ + ButtonBlock.qml \ + ButtonColumn.qml \ + ButtonRow.qml \ + ButtonGroup.js \ + Button.qml \ + CheckBox.qml \ + ChoiceList.qml \ + ProgressBar.qml \ + RadioButton.qml \ + ScrollDecorator.qml \ + ScrollIndicator.qml \ + Slider.qml \ + SpinBox.qml \ + Switch.qml \ + TextArea.qml \ + TextField.qml + +QML_DIRS = \ + behaviors \ + private \ + styles \ + visuals + +qmlfiles.files = $$QML_FILES +qmlfiles.sources = $$QML_FILES +qmlfiles.path = $$INSTALL_IMPORTS/$$TARGETPATH + +qmldirs.files = $$QML_DIRS +qmldirs.sources = $$QML_DIRS +qmldirs.path = $$INSTALL_IMPORTS/$$TARGETPATH + +INSTALLS += qmlfiles qmldirs + +symbian { + DEPLOYMENT += qmlfiles qmldirs +} diff --git a/share/qtcreator/welcomescreen/components/custom/private/ChoiceListPopup.qml b/share/qtcreator/welcomescreen/components/custom/private/ChoiceListPopup.qml new file mode 100644 index 00000000000..5ed7f277da2 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/private/ChoiceListPopup.qml @@ -0,0 +1,323 @@ +import QtQuick 1.0 + +MouseArea { + id: popup + + // There is no global z-ordering that can stack this popup in front, so we + // need to reparent it to the root item to fake it upon showing the popup. + // In that case, the popup will also fill the whole window to allow the user to + // close the popup by clicking anywhere in the window. Letting the popup act as the mouse + // area for the button that 'owns' it is also nessesary to support drag'n'release behavior. + + // The 'popupframe' delegate will be told to show or hide by assigning + // opacity to 1 or 0, respectively. + + anchors.fill: parent + hoverEnabled: true + + + + // Set 'popupOpen' to show/hide the popup. The 'state' property is more + // internal, and contains additional states used to protect the popup from + // e.g. receiving mouse clicks while its about to hide etc. + property bool popupOpen: false + + property bool desktopBehavior: true + property int previousCurrentIndex: -1 + property alias model: listView.model + property alias currentIndex: listView.currentIndex + property string currentText: model && currentIndex >= 0 ? model.get(currentIndex).text : "" + + // buttonPressed will be true when the mouse press starts + // while the popup is closed. At that point, this component can be + // seen as a button, and not yet a popup menu: + property bool buttonPressed: false + + property Component listItem + property Component listHighlight + property Component popupFrame + + property Item originalParent: parent + + onPopupOpenChanged: { + if (popupFrameLoader.item === null) + return; + if (popupOpen) { + var oldMouseX = mouseX + + // Reparent to root, so the popup stacks in front: + originalParent = parent; + var p = parent; + while (p.parent != undefined) + p = p.parent + parent = p; + + previousCurrentIndex = currentIndex; + positionPopup(); + popupFrameLoader.item.opacity = 1; + if (oldMouseX === mouseX){ + // Work around bug: mouseX and mouseY does not immidiatly + // update after reparenting and resizing the mouse area: + var pos = originalParent.mapToItem(parent, mouseX, mouseY) + highlightItemAt(pos.x, pos.y); + } else { + highlightItemAt(mouseX, mouseY); + } + listView.forceActiveFocus(); + state = "popupOpen" + } else { + popupFrameLoader.item.opacity = 0; + popup.hideHighlight(); + state = "popupClosed" + } + } + + Component.onCompleted: { + // In case 'popupOpen' was set to 'true' before + // 'popupFrameLoader' was finished, we open the popup now instead: + if (popup.popupOpen){ + popup.popupOpen = false + popup.popupOpen = true + } + } + + function highlightItemAt(posX, posY) + { + var mappedPos = mapToItem(listView.contentItem, posX, posY); + var indexAt = listView.indexAt(mappedPos.x, mappedPos.y); + if (indexAt == listView.highlightedIndex) + return; + if (indexAt >= 0) { + listView.highlightedIndex = indexAt; + } else { + if(posY > listView.y+listView.height && listView.highlightedIndex+1 < listView.count ) { + listView.highlightedIndex++; + } else if(posY < listView.y && listView.highlightedIndex > 0) { + listView.highlightedIndex--; + } else if(posX < popupFrameLoader.x || posX > popupFrameLoader.x+popupFrameLoader.width) { + popup.hideHighlight(); + } + } + } + + function hideHighlight() { + listView.highlightedIndex = -1; + listView.highlightedItem = null; // will trigger positionHighlight() what will hide the highlight + } + + function positionPopup() { + // Set initial values to top left corner of original parent: + var globalPos = mapFromItem(originalParent, 0, 0); + var newX = globalPos.x; + var newY = globalPos.y + var newW = originalParent.width; + var newH = listView.contentHeight + + switch (popupFrameLoader.item.popupLocation) { + case "center": + // Show centered over original parent with respect to selected item: + var itemHeight = Math.max(listView.contentHeight/listView.count, 0); + var currentItemY = Math.max(currentIndex*itemHeight, 0); + currentItemY += Math.floor(itemHeight/2 - choiceList.height/2); // correct for choiceLists that are higher than items in the list + newY -= currentItemY; + break; + case "below": + case "": + // Show below original parent: + newX -= popupFrameLoader.anchors.leftMargin; + newY += originalParent.height - popupFrameLoader.anchors.topMargin; + break; + } + + // Ensure the popup is inside the window: + if (newX < popupFrameLoader.anchors.leftMargin) + newX = popupFrameLoader.anchors.leftMargin; + else if (newX + newW > popup.width - popupFrameLoader.anchors.rightMargin) + newX = popup.width - popupFrameLoader.anchors.rightMargin - newW; + + if (newY < popupFrameLoader.anchors.topMargin) + newY = popupFrameLoader.anchors.topMargin; + else if (newY + newH > popup.height - popupFrameLoader.anchors.bottomMargin) + newY = popup.height - popupFrameLoader.anchors.bottomMargin - newH; + + // Todo: handle case when the list itself is larger than the window... + + listView.x = newX + listView.y = newY + listView.width = newW + listView.height = newH + } + + Loader { + id: popupFrameLoader + property alias styledItem: popup.originalParent + anchors.fill: listView + anchors.leftMargin: -item.anchors.leftMargin + anchors.rightMargin: -item.anchors.rightMargin + anchors.topMargin: -item.anchors.topMargin + anchors.bottomMargin: -item.anchors.bottomMargin + sourceComponent: popupFrame + onItemChanged: item.opacity = 0 + } + + ListView { + id: listView + focus: true + opacity: popupFrameLoader.item.opacity + boundsBehavior: desktopBehavior ? ListView.StopAtBounds : ListView.DragOverBounds + keyNavigationWraps: !desktopBehavior + highlightFollowsCurrentItem: false // explicitly handled below + + interactive: !desktopBehavior // disable flicking. also disables key handling + onCurrentItemChanged: { + if(desktopBehavior) { + positionViewAtIndex(currentIndex, ListView.Contain); + } + } + + property int highlightedIndex: -1 + onHighlightedIndexChanged: positionViewAtIndex(highlightedIndex, ListView.Contain) + + property variant highlightedItem: null + onHighlightedItemChanged: { + if(desktopBehavior) { + positionHighlight(); + } + } + + function positionHighlight() { + if(!Qt.isQtObject(highlightItem)) + return; + + if(!Qt.isQtObject(highlightedItem)) { + highlightItem.opacity = 0; // hide when no item is highlighted + } else { + highlightItem.x = highlightedItem.x; + highlightItem.y = highlightedItem.y; + highlightItem.width = highlightedItem.width; + highlightItem.height = highlightedItem.height; + highlightItem.opacity = 1; // show once positioned + } + } + + delegate: Item { + id: itemDelegate + width: delegateLoader.item.width + height: delegateLoader.item.height + property int theIndex: index // for some reason the loader can't bind directly to 'index' + + Loader { + id: delegateLoader + property variant model: listView.model + property alias index: itemDelegate.theIndex + property Item styledItem: choiceList + property bool highlighted: theIndex == listView.highlightedIndex + property string itemText: popup.model.get(theIndex).text + sourceComponent: listItem + } + + states: State { + name: "highlighted" + when: index == listView.highlightedIndex + StateChangeScript { + script: { + if(Qt.isQtObject(listView.highlightedItem)) { + listView.highlightedItem.yChanged.disconnect(listView.positionHighlight); + } + listView.highlightedItem = itemDelegate; + listView.highlightedItem.yChanged.connect(listView.positionHighlight); + } + } + + } + } + + function firstVisibleItem() { return indexAt(contentX+10,contentY+10); } + function lastVisibleItem() { return indexAt(contentX+width-10,contentY+height-10); } + function itemsPerPage() { return lastVisibleItem() - firstVisibleItem(); } + + Keys.onPressed: { + // with the ListView !interactive (non-flicking) we have to handle arrow keys + if (event.key == Qt.Key_Up) { + if(!highlightedItem) highlightedIndex = lastVisibleItem(); + else if(highlightedIndex > 0) highlightedIndex--; + } else if (event.key == Qt.Key_Down) { + if(!highlightedItem) highlightedIndex = firstVisibleItem(); + else if(highlightedIndex+1 < model.count) highlightedIndex++; + } else if (event.key == Qt.Key_PageUp) { + if(!highlightedItem) highlightedIndex = lastVisibleItem(); + else highlightedIndex = Math.max(highlightedIndex-itemsPerPage(), 0); + } else if (event.key == Qt.Key_PageDown) { + if(!highlightedItem) highlightedIndex = firstVisibleItem(); + else highlightedIndex = Math.min(highlightedIndex+itemsPerPage(), model.count-1); + } else if (event.key == Qt.Key_Home) { + highlightedIndex = 0; + } else if (event.key == Qt.Key_End) { + highlightedIndex = model.count-1; + } else if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + if(highlightedIndex != -1) { + listView.currentIndex = highlightedIndex; + } else { + listView.currentIndex = popup.previousCurrentIndex; + } + + popup.popupOpen = false; + } else if (event.key == Qt.Key_Escape) { + listView.currentIndex = popup.previousCurrentIndex; + popup.popupOpen = false; + } + event.accepted = true; // consume all keys while popout has focus + } + + highlight: popup.listHighlight + } + + Timer { + // This is the time-out value for when we consider the + // user doing a press'n'release, and not just a click to + // open the popup: + id: pressedTimer + interval: 400 // Todo: fetch value from style object + } + + onPressed: { + if (state == "popupClosed") { + // Show the popup: + pressedTimer.running = true + popup.popupOpen = true + popup.buttonPressed = true + } + } + + onReleased: { + if (state == "popupOpen" && pressedTimer.running === false) { + // Either we have a 'new' click on the popup, or the user has + // done a drag'n'release. In either case, the user has done a selection: + var mappedPos = mapToItem(listView.contentItem, mouseX, mouseY); + var indexAt = listView.indexAt(mappedPos.x, mappedPos.y); + if(indexAt != -1) + listView.currentIndex = indexAt; + popup.popupOpen = false + } + popup.buttonPressed = false + } + + onPositionChanged: { + if (state == "popupOpen") + popup.highlightItemAt(mouseX, mouseY) + } + + states: [ + State { + name: "popupClosed" + when: popupFrameLoader.item.opacity === 0; + StateChangeScript { + script: parent = originalParent; + } + } + ] +} + + + + diff --git a/share/qtcreator/welcomescreen/components/custom/qmldir b/share/qtcreator/welcomescreen/components/custom/qmldir new file mode 100644 index 00000000000..8da1fd80f0d --- /dev/null +++ b/share/qtcreator/welcomescreen/components/custom/qmldir @@ -0,0 +1,14 @@ +RangeModel 1.0 RangeModel.qml +BasicButton 1.0 BasicButton.qml +BusyIndicator 1.0 BusyIndicator.qml +ButtonBlock 1.0 ButtonBlock.qml +Button 1.0 Button.qml +ButtonColumn 1.0 ButtonColumn.qml +ButtonRow 1.0 ButtonRow.qml +CheckBox 1.0 CheckBox.qml +ChoiceList 1.0 ChoiceList.qml +ProgressBar 1.0 ProgressBar.qml +Slider 1.0 Slider.qml +SpinBox 1.0 SpinBox.qml +TextField 1.0 TextField.qml +GroupBox 1.0 GroupBox.qml diff --git a/share/qtcreator/welcomescreen/components/images/folder_new.png b/share/qtcreator/welcomescreen/components/images/folder_new.png new file mode 100644 index 00000000000..8d8bb9bd768 Binary files /dev/null and b/share/qtcreator/welcomescreen/components/images/folder_new.png differ diff --git a/share/qtcreator/welcomescreen/components/qmldir b/share/qtcreator/welcomescreen/components/qmldir new file mode 100644 index 00000000000..d33a7971d73 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/qmldir @@ -0,0 +1,27 @@ +Slider 1.0 Slider.qml +SpinBox 1.0 SpinBox.qml +GroupBox 1.0 GroupBox.qml +Button 1.0 Button.qml +ToolBar 1.0 ToolBar.qml +TabFrame 1.0 TabFrame.qml +TabBar 1.0 TabBar.qml +Tab 1.0 Tab.qml +ScrollArea 1.0 ScrollArea.qml +ScrollBar 1.0 ScrollBar.qml +ChoiceList 1.0 ChoiceList.qml +ToolButton 1.0 ToolButton.qml +TextArea 1.0 TextArea.qml +TextField 1.0 TextField.qml +ProgressBar 1.0 ProgressBar.qml +ButtonRow 1.0 ButtonRow.qml +ButtonColumn 1.0 ButtonColumn.qml +SplitterRow 1.0 SplitterRow.qml +Dial 1.0 Dial.qml +TableView 1.0 TableView.qml +CheckBox 1.0 CheckBox.qml +RadioButton 1.0 RadioButton.qml +plugin styleplugin plugin +TableColumn 1.0 TableColumn.qml +ContextMenu 1.0 ContextMenu.qml +Menu 1.0 Menu.qml +MenuItem 1.0 MenuItem.qml diff --git a/share/qtcreator/welcomescreen/components/styleitem/qdeclarativefolderlistmodel.cpp b/share/qtcreator/welcomescreen/components/styleitem/qdeclarativefolderlistmodel.cpp new file mode 100644 index 00000000000..89c072b39f8 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qdeclarativefolderlistmodel.cpp @@ -0,0 +1,488 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![code] +#include "qdeclarativefolderlistmodel.h" +#include +#include +#include + +#ifndef QT_NO_DIRMODEL + +QT_BEGIN_NAMESPACE + +class QDeclarativeFolderListModelPrivate +{ +public: + QDeclarativeFolderListModelPrivate() + : sortField(QDeclarativeFolderListModel::Name), sortReversed(false), count(0) { + nameFilters << QLatin1String("*"); + } + + void updateSorting() { + QDir::SortFlags flags = 0; + switch(sortField) { + case QDeclarativeFolderListModel::Unsorted: + flags |= QDir::Unsorted; + break; + case QDeclarativeFolderListModel::Name: + flags |= QDir::Name; + break; + case QDeclarativeFolderListModel::Time: + flags |= QDir::Time; + break; + case QDeclarativeFolderListModel::Size: + flags |= QDir::Size; + break; + case QDeclarativeFolderListModel::Type: + flags |= QDir::Type; + break; + } + + if (sortReversed) + flags |= QDir::Reversed; + + model.setSorting(flags); + } + + QDirModel model; + QUrl folder; + QStringList nameFilters; + QModelIndex folderIndex; + QDeclarativeFolderListModel::SortField sortField; + bool sortReversed; + int count; +}; + +/*! + \qmlclass FolderListModel QDeclarativeFolderListModel + \ingroup qml-working-with-data + \brief The FolderListModel provides a model of the contents of a file system folder. + + FolderListModel provides access to information about the contents of a folder + in the local file system, exposing a list of files to views and other data components. + + \note This type is made available by importing the \c Qt.labs.folderlistmodel module. + \e{Elements in the Qt.labs module are not guaranteed to remain compatible + in future versions.} + + \bold{import Qt.labs.folderlistmodel 1.0} + + The \l folder property specifies the folder to access. Information about the + files and directories in the folder is supplied via the model's interface. + Components access names and paths via the following roles: + + \list + \o fileName + \o filePath + \endlist + + Additionally a file entry can be differentiated from a folder entry via the + isFolder() method. + + \section1 Filtering + + Various properties can be set to filter the number of files and directories + exposed by the model. + + The \l nameFilters property can be set to contain a list of wildcard filters + that are applied to names of files and directories, causing only those that + match the filters to be exposed. + + Directories can be included or excluded using the \l showDirs property, and + navigation directories can also be excluded by setting the \l showDotAndDotDot + property to false. + + It is sometimes useful to limit the files and directories exposed to those + that the user can access. The \l showOnlyReadable property can be set to + enable this feature. + + \section1 Example Usage + + The following example shows a FolderListModel being used to provide a list + of QML files in a \l ListView: + + \snippet doc/src/snippets/declarative/folderlistmodel.qml 0 + + \section1 Path Separators + + Qt uses "/" as a universal directory separator in the same way that "/" is + used as a path separator in URLs. If you always use "/" as a directory + separator, Qt will translate your paths to conform to the underlying + operating system. + + \sa {QML Data Models} +*/ + +QDeclarativeFolderListModel::QDeclarativeFolderListModel(QObject *parent) + : QAbstractListModel(parent) +{ + QHash roles; + roles[FileNameRole] = "fileName"; + roles[FilePathRole] = "filePath"; + roles[FileSizeRole] = "fileSize"; + setRoleNames(roles); + + d = new QDeclarativeFolderListModelPrivate; + d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); + connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) + , this, SLOT(inserted(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int)) + , this, SLOT(removed(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)) + , this, SLOT(handleDataChanged(const QModelIndex&,const QModelIndex&))); + connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh())); + connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh())); +} + +QDeclarativeFolderListModel::~QDeclarativeFolderListModel() +{ + delete d; +} + +QVariant QDeclarativeFolderListModel::data(const QModelIndex &index, int role) const +{ + QVariant rv; + QModelIndex modelIndex = d->model.index(index.row(), 0, d->folderIndex); + if (modelIndex.isValid()) { + if (role == FileNameRole) + rv = d->model.data(modelIndex, QDirModel::FileNameRole).toString(); + else if (role == FilePathRole) + rv = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); + else if (role == FileSizeRole) + rv = d->model.data(d->model.index(index.row(), 1, d->folderIndex), Qt::DisplayRole).toString(); + } + return rv; +} + +/*! + \qmlproperty int FolderListModel::count + + Returns the number of items in the current folder that match the + filter criteria. +*/ +int QDeclarativeFolderListModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return d->count; +} + +/*! + \qmlproperty string FolderListModel::folder + + The \a folder property holds a URL for the folder that the model is + currently providing. + + The value is a URL expressed as a string, and must be a \c file: or \c qrc: + URL, or a relative URL. + + By default, the value is an invalid URL. +*/ +QUrl QDeclarativeFolderListModel::folder() const +{ + return d->folder; +} + +void QDeclarativeFolderListModel::setFolder(const QUrl &folder) +{ + if (folder == d->folder) + return; + QModelIndex index = d->model.index(folder.toLocalFile()); + if ((index.isValid() && d->model.isDir(index)) || folder.toLocalFile().isEmpty()) { + + d->folder = folder; + QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); + emit folderChanged(); + } +} + +/*! + \qmlproperty url FolderListModel::parentFolder + + Returns the URL of the parent of of the current \l folder. +*/ +QUrl QDeclarativeFolderListModel::parentFolder() const +{ + QString localFile = d->folder.toLocalFile(); + if (!localFile.isEmpty()) { + QDir dir(localFile); +#if defined(Q_OS_SYMBIAN) || defined(Q_OS_WIN) + if (dir.isRoot()) + dir.setPath(""); + else +#endif + dir.cdUp(); + localFile = dir.path(); + } else { + int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); + if (pos == -1) + return QUrl(); + localFile = d->folder.path().left(pos); + } + return QUrl::fromLocalFile(localFile); +} + +/*! + \qmlproperty list FolderListModel::nameFilters + + The \a nameFilters property contains a list of file name filters. + The filters may include the ? and * wildcards. + + The example below filters on PNG and JPEG files: + + \qml + FolderListModel { + nameFilters: [ "*.png", "*.jpg" ] + } + \endqml + + \note Directories are not excluded by filters. +*/ +QStringList QDeclarativeFolderListModel::nameFilters() const +{ + return d->nameFilters; +} + +void QDeclarativeFolderListModel::setNameFilters(const QStringList &filters) +{ + d->nameFilters = filters; + d->model.setNameFilters(d->nameFilters); +} + +void QDeclarativeFolderListModel::classBegin() +{ +} + +void QDeclarativeFolderListModel::componentComplete() +{ + if (!d->folder.isValid() || d->folder.toLocalFile().isEmpty() || !QDir().exists(d->folder.toLocalFile())) + setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); + + if (!d->folderIndex.isValid()) + QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); +} + +/*! + \qmlproperty enumeration FolderListModel::sortField + + The \a sortField property contains field to use for sorting. sortField + may be one of: + \list + \o Unsorted - no sorting is applied. The order is system default. + \o Name - sort by filename + \o Time - sort by time modified + \o Size - sort by file size + \o Type - sort by file type (extension) + \endlist + + \sa sortReversed +*/ +QDeclarativeFolderListModel::SortField QDeclarativeFolderListModel::sortField() const +{ + return d->sortField; +} + +void QDeclarativeFolderListModel::setSortField(SortField field) +{ + if (field != d->sortField) { + d->sortField = field; + d->updateSorting(); + } +} + +/*! + \qmlproperty bool FolderListModel::sortReversed + + If set to true, reverses the sort order. The default is false. + + \sa sortField +*/ +bool QDeclarativeFolderListModel::sortReversed() const +{ + return d->sortReversed; +} + +void QDeclarativeFolderListModel::setSortReversed(bool rev) +{ + if (rev != d->sortReversed) { + d->sortReversed = rev; + d->updateSorting(); + } +} + +/*! + \qmlmethod bool FolderListModel::isFolder(int index) + + Returns true if the entry \a index is a folder; otherwise + returns false. +*/ +bool QDeclarativeFolderListModel::isFolder(int index) const +{ + if (index != -1) { + QModelIndex idx = d->model.index(index, 0, d->folderIndex); + if (idx.isValid()) + return d->model.isDir(idx); + } + return false; +} + +void QDeclarativeFolderListModel::refresh() +{ + d->folderIndex = QModelIndex(); + if (d->count) { + emit beginRemoveRows(QModelIndex(), 0, d->count-1); + d->count = 0; + emit endRemoveRows(); + } + d->folderIndex = d->model.index(d->folder.toLocalFile()); + int newcount = d->model.rowCount(d->folderIndex); + if (newcount) { + emit beginInsertRows(QModelIndex(), 0, newcount-1); + d->count = newcount; + emit endInsertRows(); + } +} + +void QDeclarativeFolderListModel::inserted(const QModelIndex &index, int start, int end) +{ + if (index == d->folderIndex) { + emit beginInsertRows(QModelIndex(), start, end); + d->count = d->model.rowCount(d->folderIndex); + emit endInsertRows(); + } +} + +void QDeclarativeFolderListModel::removed(const QModelIndex &index, int start, int end) +{ + if (index == d->folderIndex) { + emit beginRemoveRows(QModelIndex(), start, end); + d->count = d->model.rowCount(d->folderIndex); + emit endRemoveRows(); + } +} + +void QDeclarativeFolderListModel::handleDataChanged(const QModelIndex &start, const QModelIndex &end) +{ + if (start.parent() == d->folderIndex) + emit dataChanged(index(start.row(),0), index(end.row(),0)); +} + +/*! + \qmlproperty bool FolderListModel::showDirs + + If true, directories are included in the model; otherwise only files + are included. + + By default, this property is true. + + Note that the nameFilters are not applied to directories. + + \sa showDotAndDotDot +*/ +bool QDeclarativeFolderListModel::showDirs() const +{ + return d->model.filter() & QDir::AllDirs; +} + +void QDeclarativeFolderListModel::setShowDirs(bool on) +{ + if (!(d->model.filter() & QDir::AllDirs) == !on) + return; + if (on) + d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives); + else + d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives)); +} + +/*! + \qmlproperty bool FolderListModel::showDotAndDotDot + + If true, the "." and ".." directories are included in the model; otherwise + they are excluded. + + By default, this property is false. + + \sa showDirs +*/ +bool QDeclarativeFolderListModel::showDotAndDotDot() const +{ + return !(d->model.filter() & QDir::NoDotAndDotDot); +} + +void QDeclarativeFolderListModel::setShowDotAndDotDot(bool on) +{ + if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) + return; + if (on) + d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot); + else + d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot); +} + +/*! + \qmlproperty bool FolderListModel::showOnlyReadable + + If true, only readable files and directories are shown; otherwise all files + and directories are shown. + + By default, this property is false. + + \sa showDirs +*/ +bool QDeclarativeFolderListModel::showOnlyReadable() const +{ + return d->model.filter() & QDir::Readable; +} + +void QDeclarativeFolderListModel::setShowOnlyReadable(bool on) +{ + if (!(d->model.filter() & QDir::Readable) == !on) + return; + if (on) + d->model.setFilter(d->model.filter() | QDir::Readable); + else + d->model.setFilter(d->model.filter() & ~QDir::Readable); +} + +//![code] +QT_END_NAMESPACE + +#endif // QT_NO_DIRMODEL diff --git a/share/qtcreator/welcomescreen/components/styleitem/qdeclarativefolderlistmodel.h b/share/qtcreator/welcomescreen/components/styleitem/qdeclarativefolderlistmodel.h new file mode 100644 index 00000000000..f225a04dcd6 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qdeclarativefolderlistmodel.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEFOLDERLISTMODEL_H +#define QDECLARATIVEFOLDERLISTMODEL_H + +#include +#include +#include +#include + +#ifndef QT_NO_DIRMODEL + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QDeclarativeContext; +class QModelIndex; + +class QDeclarativeFolderListModelPrivate; + +//![class begin] +class QDeclarativeFolderListModel : public QAbstractListModel, public QDeclarativeParserStatus +{ + Q_OBJECT + Q_INTERFACES(QDeclarativeParserStatus) +//![class begin] + +//![class props] + Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged) + Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged) + Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters) + Q_PROPERTY(SortField sortField READ sortField WRITE setSortField) + Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed) + Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) + Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) + Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) + Q_PROPERTY(int count READ count NOTIFY countChanged) +//![class props] + +//![abslistmodel] +public: + QDeclarativeFolderListModel(QObject *parent = 0); + ~QDeclarativeFolderListModel(); + + enum Roles { FileNameRole = Qt::UserRole+1, FilePathRole = Qt::UserRole+2, FileSizeRole = Qt::UserRole+3 }; + + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; +//![abslistmodel] + +//![count] + int count() const { return rowCount(QModelIndex()); } +//![count] + +//![prop funcs] + QUrl folder() const; + void setFolder(const QUrl &folder); + + QUrl parentFolder() const; + + QStringList nameFilters() const; + void setNameFilters(const QStringList &filters); + + enum SortField { Unsorted, Name, Time, Size, Type }; + SortField sortField() const; + void setSortField(SortField field); + Q_ENUMS(SortField) + + bool sortReversed() const; + void setSortReversed(bool rev); + + bool showDirs() const; + void setShowDirs(bool); + bool showDotAndDotDot() const; + void setShowDotAndDotDot(bool); + bool showOnlyReadable() const; + void setShowOnlyReadable(bool); +//![prop funcs] + +//![isfolder] + Q_INVOKABLE bool isFolder(int index) const; +//![isfolder] + +//![parserstatus] + virtual void classBegin(); + virtual void componentComplete(); +//![parserstatus] + +//![notifier] +Q_SIGNALS: + void folderChanged(); + void countChanged(); +//![notifier] + +//![class end] +private Q_SLOTS: + void refresh(); + void inserted(const QModelIndex &index, int start, int end); + void removed(const QModelIndex &index, int start, int end); + void handleDataChanged(const QModelIndex &start, const QModelIndex &end); + +private: + Q_DISABLE_COPY(QDeclarativeFolderListModel) + QDeclarativeFolderListModelPrivate *d; +}; +//![class end] + +QT_END_NAMESPACE + +//![qml decl] +QML_DECLARE_TYPE(QDeclarativeFolderListModel) +//![qml decl] + +QT_END_HEADER + +#endif // QT_NO_DIRMODEL + +#endif // QDECLARATIVEFOLDERLISTMODEL_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qrangemodel.cpp b/share/qtcreator/welcomescreen/components/styleitem/qrangemodel.cpp new file mode 100644 index 00000000000..83c106ecd20 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qrangemodel.cpp @@ -0,0 +1,520 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** 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 Technology Preview License Agreement accompanying this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +/*! + \class QRangeModel + \brief The QRangeModel class, helps users to build components that depend + on some value and/or position to be in a certain range previously defined + + With this class, the user sets a value range and a position range, which + represent the valid values/positions the model can assume. It is worth telling + that the value property always has priority over the position property. A nice use + case, would be a Slider implementation with the help of QRangeModel. If the user sets + a value range to [0,100], a position range to [50,100] and sets the value + to 80, the equivalent position would be 90. After that, if the user decides to + resize the slider, the value would be the same, but the knob position would + be updated due to the new position range. + + \ingroup qt-components +*/ + +#include +#include +#include +#include + +#ifndef QT_NO_ACCESSIBILITY +#include +#endif + +#include "qrangemodel.h" +#include "qrangemodel_p.h" + +QRangeModelPrivate::QRangeModelPrivate(QRangeModel *qq) + : q_ptr(qq) +{ +} + +QRangeModelPrivate::~QRangeModelPrivate() +{ +} + +void QRangeModelPrivate::init() +{ + minimum = 0; + maximum = 99; + stepSize = 0; + value = 0; + pos = 0; + posatmin = 0; + posatmax = 0; + inverted = false; +} + +/*! + Calculates the position that is going to be seen outside by the component + that is using QRangeModel. It takes into account the \l stepSize, + \l positionAtMinimum, \l positionAtMaximum properties + and \a position that is passed as parameter. +*/ + +qreal QRangeModelPrivate::publicPosition(qreal position) const +{ + // Calculate the equivalent stepSize for the position property. + const qreal min = effectivePosAtMin(); + const qreal max = effectivePosAtMax(); + const qreal valueRange = maximum - minimum; + const qreal positionValueRatio = valueRange ? (max - min) / valueRange : 0; + const qreal positionStep = stepSize * positionValueRatio; + + if (positionStep == 0) + return (min < max) ? qBound(min, position, max) : qBound(max, position, min); + + const int stepSizeMultiplier = (position - min) / positionStep; + + // Test whether value is below minimum range + if (stepSizeMultiplier < 0) + return min; + + qreal leftEdge = (stepSizeMultiplier * positionStep) + min; + qreal rightEdge = ((stepSizeMultiplier + 1) * positionStep) + min; + + if (min < max) { + leftEdge = qMin(leftEdge, max); + rightEdge = qMin(rightEdge, max); + } else { + leftEdge = qMax(leftEdge, max); + rightEdge = qMax(rightEdge, max); + } + + if (qAbs(leftEdge - position) <= qAbs(rightEdge - position)) + return leftEdge; + return rightEdge; +} + +/*! + Calculates the value that is going to be seen outside by the component + that is using QRangeModel. It takes into account the \l stepSize, + \l minimumValue, \l maximumValue properties + and \a value that is passed as parameter. +*/ + +qreal QRangeModelPrivate::publicValue(qreal value) const +{ + // It is important to do value-within-range check this + // late (as opposed to during setPosition()). The reason is + // QML bindings; a position that is initially invalid because it lays + // outside the range, might become valid later if the range changes. + + if (stepSize == 0) + return qBound(minimum, value, maximum); + + const int stepSizeMultiplier = (value - minimum) / stepSize; + + // Test whether value is below minimum range + if (stepSizeMultiplier < 0) + return minimum; + + const qreal leftEdge = qMin(maximum, (stepSizeMultiplier * stepSize) + minimum); + const qreal rightEdge = qMin(maximum, ((stepSizeMultiplier + 1) * stepSize) + minimum); + const qreal middle = (leftEdge + rightEdge) / 2; + + return (value <= middle) ? leftEdge : rightEdge; +} + +/*! + Checks if the \l value or \l position, that is seen by the user, has changed and emits the changed signal if it + has changed. +*/ + +void QRangeModelPrivate::emitValueAndPositionIfChanged(const qreal oldValue, const qreal oldPosition) +{ + Q_Q(QRangeModel); + + // Effective value and position might have changed even in cases when e.g. d->value is + // unchanged. This will be the case when operating with values outside range: + const qreal newValue = q->value(); + const qreal newPosition = q->position(); + if (!qFuzzyCompare(newValue, oldValue)) + emit q->valueChanged(newValue); + if (!qFuzzyCompare(newPosition, oldPosition)) + emit q->positionChanged(newPosition); +} + +/*! + Constructs a QRangeModel with \a parent +*/ + +QRangeModel::QRangeModel(QObject *parent) + : QObject(parent), d_ptr(new QRangeModelPrivate(this)) +{ + Q_D(QRangeModel); + d->init(); +} + +/*! + \internal + Constructs a QRangeModel with private class pointer \a dd and \a parent +*/ + +QRangeModel::QRangeModel(QRangeModelPrivate &dd, QObject *parent) + : QObject(parent), d_ptr(&dd) +{ + Q_D(QRangeModel); + d->init(); +} + +/*! + Destroys the QRangeModel +*/ + +QRangeModel::~QRangeModel() +{ + delete d_ptr; + d_ptr = 0; +} + +/*! + Sets the range of valid positions, that \l position can assume externally, with + \a min and \a max. + Such range is represented by \l positionAtMinimum and \l positionAtMaximum +*/ + +void QRangeModel::setPositionRange(qreal min, qreal max) +{ + Q_D(QRangeModel); + + bool emitPosAtMinChanged = !qFuzzyCompare(min, d->posatmin); + bool emitPosAtMaxChanged = !qFuzzyCompare(max, d->posatmax); + + if (!(emitPosAtMinChanged || emitPosAtMaxChanged)) + return; + + const qreal oldPosition = position(); + d->posatmin = min; + d->posatmax = max; + + // When a new positionRange is defined, the position property must be updated based on the value property. + // For instance, imagine that you have a valueRange of [0,100] and a position range of [20,100], + // if a user set the value to 50, the position would be 60. If this positionRange is updated to [0,100], then + // the new position, based on the value (50), will be 50. + // If the newPosition is different than the old one, it must be updated, in order to emit + // the positionChanged signal. + d->pos = d->equivalentPosition(d->value); + + if (emitPosAtMinChanged) + emit positionAtMinimumChanged(d->posatmin); + if (emitPosAtMaxChanged) + emit positionAtMaximumChanged(d->posatmax); + + d->emitValueAndPositionIfChanged(value(), oldPosition); +} +/*! + Sets the range of valid values, that \l value can assume externally, with + \a min and \a max. The range has the following constraint: \a min must be less or equal \a max + Such range is represented by \l minimumValue and \l maximumValue +*/ + +void QRangeModel::setRange(qreal min, qreal max) +{ + Q_D(QRangeModel); + + bool emitMinimumChanged = !qFuzzyCompare(min, d->minimum); + bool emitMaximumChanged = !qFuzzyCompare(max, d->maximum); + + if (!(emitMinimumChanged || emitMaximumChanged)) + return; + + const qreal oldValue = value(); + const qreal oldPosition = position(); + + d->minimum = min; + d->maximum = qMax(min, max); + + // Update internal position if it was changed. It can occurs if internal value changes, due to range update + d->pos = d->equivalentPosition(d->value); + + if (emitMinimumChanged) + emit minimumChanged(d->minimum); + if (emitMaximumChanged) + emit maximumChanged(d->maximum); + + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +/*! + \property QRangeModel::minimumValue + \brief the minimum value that \l value can assume + + This property's default value is 0 +*/ + +void QRangeModel::setMinimum(qreal min) +{ + Q_D(const QRangeModel); + setRange(min, d->maximum); +} + +qreal QRangeModel::minimum() const +{ + Q_D(const QRangeModel); + return d->minimum; +} + +/*! + \property QRangeModel::maximumValue + \brief the maximum value that \l value can assume + + This property's default value is 99 +*/ + +void QRangeModel::setMaximum(qreal max) +{ + Q_D(const QRangeModel); + // if the new maximum value is smaller than + // minimum, update minimum too + setRange(qMin(d->minimum, max), max); +} + +qreal QRangeModel::maximum() const +{ + Q_D(const QRangeModel); + return d->maximum; +} + +/*! + \property QRangeModel::stepSize + \brief the value that is added to the \l value and \l position property + + Example: If a user sets a range of [0,100] and stepSize + to 30, the valid values that are going to be seen externally would be: 0, 30, 60, 90, 100. +*/ + +void QRangeModel::setStepSize(qreal stepSize) +{ + Q_D(QRangeModel); + + stepSize = qMax(qreal(0.0), stepSize); + if (qFuzzyCompare(stepSize, d->stepSize)) + return; + + const qreal oldValue = value(); + const qreal oldPosition = position(); + d->stepSize = stepSize; + + emit stepSizeChanged(d->stepSize); + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +qreal QRangeModel::stepSize() const +{ + Q_D(const QRangeModel); + return d->stepSize; +} + +/*! + Returns a valid position, respecting the \l positionAtMinimum, + \l positionAtMaximum and the \l stepSize properties. + Such calculation is based on the parameter \a value (which is valid externally). +*/ + +qreal QRangeModel::positionForValue(qreal value) const +{ + Q_D(const QRangeModel); + + const qreal unconstrainedPosition = d->equivalentPosition(value); + return d->publicPosition(unconstrainedPosition); +} + +/*! + \property QRangeModel::position + \brief the current position of the model + + Represents a valid external position, based on the \l positionAtMinimum, + \l positionAtMaximum and the \l stepSize properties. + The user can set it internally with a position, that is not within the current position range, + since it can become valid if the user changes the position range later. +*/ + +qreal QRangeModel::position() const +{ + Q_D(const QRangeModel); + + // Return the internal position but observe boundaries and + // stepSize restrictions. + return d->publicPosition(d->pos); +} + +void QRangeModel::setPosition(qreal newPosition) +{ + Q_D(QRangeModel); + + if (qFuzzyCompare(newPosition, d->pos)) + return; + + const qreal oldPosition = position(); + const qreal oldValue = value(); + + // Update position and calculate new value + d->pos = newPosition; + d->value = d->equivalentValue(d->pos); + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +/*! + \property QRangeModel::positionAtMinimum + \brief the minimum value that \l position can assume + + This property's default value is 0 +*/ + +void QRangeModel::setPositionAtMinimum(qreal min) +{ + Q_D(QRangeModel); + setPositionRange(min, d->posatmax); +} + +qreal QRangeModel::positionAtMinimum() const +{ + Q_D(const QRangeModel); + return d->posatmin; +} + +/*! + \property QRangeModel::positionAtMaximum + \brief the maximum value that \l position can assume + + This property's default value is 0 +*/ + +void QRangeModel::setPositionAtMaximum(qreal max) +{ + Q_D(QRangeModel); + setPositionRange(d->posatmin, max); +} + +qreal QRangeModel::positionAtMaximum() const +{ + Q_D(const QRangeModel); + return d->posatmax; +} + +/*! + Returns a valid value, respecting the \l minimumValue, + \l maximumValue and the \l stepSize properties. + Such calculation is based on the parameter \a position (which is valid externally). +*/ + +qreal QRangeModel::valueForPosition(qreal position) const +{ + Q_D(const QRangeModel); + + const qreal unconstrainedValue = d->equivalentValue(position); + return d->publicValue(unconstrainedValue); +} + +/*! + \property QRangeModel::value + \brief the current value of the model + + Represents a valid external value, based on the \l minimumValue, + \l maximumValue and the \l stepSize properties. + The user can set it internally with a value, that is not within the current range, + since it can become valid if the user changes the range later. +*/ + +qreal QRangeModel::value() const +{ + Q_D(const QRangeModel); + + // Return internal value but observe boundaries and + // stepSize restrictions + return d->publicValue(d->value); +} + +void QRangeModel::setValue(qreal newValue) +{ + Q_D(QRangeModel); + + if (qFuzzyCompare(newValue, d->value)) + return; + + const qreal oldValue = value(); + const qreal oldPosition = position(); + + // Update relative value and position + d->value = newValue; + d->pos = d->equivalentPosition(d->value); + d->emitValueAndPositionIfChanged(oldValue, oldPosition); +} + +/*! + \property QRangeModel::inverted + \brief the model is inverted or not + + The model can be represented with an inverted behavior, e.g. when \l value assumes + the maximum value (represented by \l maximumValue) the \l position will be at its + minimum (represented by \l positionAtMinimum). +*/ + +void QRangeModel::setInverted(bool inverted) +{ + Q_D(QRangeModel); + if (inverted == d->inverted) + return; + + d->inverted = inverted; + emit invertedChanged(d->inverted); + + // After updating the internal value, the position property can change. + setPosition(d->equivalentPosition(d->value)); +} + +bool QRangeModel::inverted() const +{ + Q_D(const QRangeModel); + return d->inverted; +} + +/*! + Sets the \l value to \l minimumValue. +*/ + +void QRangeModel::toMinimum() +{ + Q_D(const QRangeModel); + setValue(d->minimum); +} + +/*! + Sets the \l value to \l maximumValue. +*/ + +void QRangeModel::toMaximum() +{ + Q_D(const QRangeModel); + setValue(d->maximum); +} diff --git a/share/qtcreator/welcomescreen/components/styleitem/qrangemodel.h b/share/qtcreator/welcomescreen/components/styleitem/qrangemodel.h new file mode 100644 index 00000000000..6144281ed2c --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qrangemodel.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** 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 Technology Preview License Agreement accompanying this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#ifndef QRANGEMODEL_H +#define QRANGEMODEL_H + +#include +#include +#include +#include + +class QRangeModelPrivate; + +class QRangeModel : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged USER true) + Q_PROPERTY(qreal minimumValue READ minimum WRITE setMinimum NOTIFY minimumChanged) + Q_PROPERTY(qreal maximumValue READ maximum WRITE setMaximum NOTIFY maximumChanged) + Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged) + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged) + Q_PROPERTY(qreal positionAtMinimum READ positionAtMinimum WRITE setPositionAtMinimum NOTIFY positionAtMinimumChanged) + Q_PROPERTY(qreal positionAtMaximum READ positionAtMaximum WRITE setPositionAtMaximum NOTIFY positionAtMaximumChanged) + Q_PROPERTY(bool inverted READ inverted WRITE setInverted NOTIFY invertedChanged) + +public: + QRangeModel(QObject *parent = 0); + virtual ~QRangeModel(); + + void setRange(qreal min, qreal max); + void setPositionRange(qreal min, qreal max); + + void setStepSize(qreal stepSize); + qreal stepSize() const; + + void setMinimum(qreal min); + qreal minimum() const; + + void setMaximum(qreal max); + qreal maximum() const; + + void setPositionAtMinimum(qreal posAtMin); + qreal positionAtMinimum() const; + + void setPositionAtMaximum(qreal posAtMax); + qreal positionAtMaximum() const; + + void setInverted(bool inverted); + bool inverted() const; + + qreal value() const; + qreal position() const; + + Q_INVOKABLE qreal valueForPosition(qreal position) const; + Q_INVOKABLE qreal positionForValue(qreal value) const; + +public Q_SLOTS: + void toMinimum(); + void toMaximum(); + void setValue(qreal value); + void setPosition(qreal position); + +Q_SIGNALS: + void valueChanged(qreal value); + void positionChanged(qreal position); + + void stepSizeChanged(qreal stepSize); + + void invertedChanged(bool inverted); + + void minimumChanged(qreal min); + void maximumChanged(qreal max); + void positionAtMinimumChanged(qreal min); + void positionAtMaximumChanged(qreal max); + +protected: + QRangeModel(QRangeModelPrivate &dd, QObject *parent); + QRangeModelPrivate* d_ptr; + +private: + Q_DISABLE_COPY(QRangeModel) + Q_DECLARE_PRIVATE(QRangeModel) + +}; + +QML_DECLARE_TYPE(QRangeModel) + +#endif // QRANGEMODEL_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qrangemodel_p.h b/share/qtcreator/welcomescreen/components/styleitem/qrangemodel_p.h new file mode 100644 index 00000000000..cb72ceff2f6 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qrangemodel_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** 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 Technology Preview License Agreement accompanying this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#ifndef QRANGEMODEL_P_H +#define QRANGEMODEL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt Components 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 "qrangemodel.h" + +class QRangeModelPrivate +{ + Q_DECLARE_PUBLIC(QRangeModel) +public: + QRangeModelPrivate(QRangeModel *qq); + virtual ~QRangeModelPrivate(); + + void init(); + + qreal posatmin, posatmax; + qreal minimum, maximum, stepSize, pos, value; + + uint inverted : 1; + + QRangeModel *q_ptr; + + inline qreal effectivePosAtMin() const { + return inverted ? posatmax : posatmin; + } + + inline qreal effectivePosAtMax() const { + return inverted ? posatmin : posatmax; + } + + inline qreal equivalentPosition(qreal value) const { + // Return absolute position from absolute value + const qreal valueRange = maximum - minimum; + if (valueRange == 0) + return effectivePosAtMin(); + + const qreal scale = (effectivePosAtMax() - effectivePosAtMin()) / valueRange; + return (value - minimum) * scale + effectivePosAtMin(); + } + + inline qreal equivalentValue(qreal pos) const { + // Return absolute value from absolute position + const qreal posRange = effectivePosAtMax() - effectivePosAtMin(); + if (posRange == 0) + return minimum; + + const qreal scale = (maximum - minimum) / posRange; + return (pos - effectivePosAtMin()) * scale + minimum; + } + + qreal publicPosition(qreal position) const; + qreal publicValue(qreal value) const; + void emitValueAndPositionIfChanged(const qreal oldValue, const qreal oldPosition); +}; + +#endif // QRANGEMODEL_P_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qstyleitem.cpp b/share/qtcreator/welcomescreen/components/styleitem/qstyleitem.cpp new file mode 100644 index 00000000000..0e6d942a0ca --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qstyleitem.cpp @@ -0,0 +1,1055 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOTgall +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstyleitem.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +QStyleItem::QStyleItem(QDeclarativeItem *parent) + : QDeclarativeItem(parent), + m_dummywidget(0), + m_styleoption(0), + m_type(Undefined), + m_sunken(false), + m_raised(false), + m_active(true), + m_selected(false), + m_focus(false), + m_on(false), + m_horizontal(true), + m_sharedWidget(false), + m_minimum(0), + m_maximum(100), + m_value(0), + m_paintMargins(0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, false); + setCacheMode(QGraphicsItem::DeviceCoordinateCache); + setSmooth(true); + + connect(this, SIGNAL(infoChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(onChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(selectedChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(textChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(raisedChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(sunkenChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(hoverChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(maximumChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(minimumChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(valueChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(horizontalChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeControlChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(focusChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(activeControlChanged()), this, SLOT(updateItem())); + connect(this, SIGNAL(elementTypeChanged()), this, SLOT(updateItem())); +} + +QStyleItem::~QStyleItem() +{ + delete m_styleoption; + m_styleoption = 0; + + if (!m_sharedWidget) { + delete m_dummywidget; + m_dummywidget = 0; + } +} + +void QStyleItem::initStyleOption() +{ + QString type = elementType(); + if (m_styleoption) + m_styleoption->state = 0; + + switch (m_itemType) { + case Button: { + if (!m_styleoption) + m_styleoption = new QStyleOptionButton(); + + QStyleOptionButton *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->features = (activeControl() == "default") ? + QStyleOptionButton::DefaultButton : + QStyleOptionButton::None; + } + break; + case ItemRow: { + if (!m_styleoption) + m_styleoption = new QStyleOptionViewItemV4(); + + QStyleOptionViewItemV4 *opt = qstyleoption_cast(m_styleoption); + opt->features = 0; + if (activeControl() == "alternate") + opt->features |= QStyleOptionViewItemV2::Alternate; + } + break; + + case Splitter: { + if (!m_styleoption) { + m_styleoption = new QStyleOption; + } + } + break; + + case Item: { + if (!m_styleoption) { + m_styleoption = new QStyleOptionViewItemV4(); + } + QStyleOptionViewItemV4 *opt = qstyleoption_cast(m_styleoption); + opt->features = QStyleOptionViewItemV4::HasDisplay; + opt->text = text(); + opt->textElideMode = Qt::ElideRight; + QPalette pal = m_styleoption->palette; + pal.setBrush(QPalette::Base, Qt::NoBrush); + m_styleoption->palette = pal; + } + break; + case Header: { + if (!m_styleoption) + m_styleoption = new QStyleOptionHeader(); + + QStyleOptionHeader *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->sortIndicator = activeControl() == "down" ? + QStyleOptionHeader::SortDown + : activeControl() == "up" ? + QStyleOptionHeader::SortUp : QStyleOptionHeader::None; + if (activeControl() == QLatin1String("beginning")) + opt->position = QStyleOptionHeader::Beginning; + else if (activeControl() == QLatin1String("end")) + opt->position = QStyleOptionHeader::End; + else if (activeControl() == QLatin1String("only")) + opt->position = QStyleOptionHeader::OnlyOneSection; + else + opt->position = QStyleOptionHeader::Middle; + + } + break; + case ToolButton :{ + if (!m_styleoption) + m_styleoption = new QStyleOptionToolButton(); + + QStyleOptionToolButton *opt = + qstyleoption_cast(m_styleoption); + opt->subControls = QStyle::SC_ToolButton; + opt->state |= QStyle::State_AutoRaise; + opt->activeSubControls = QStyle::SC_ToolButton; + } + break; + case ToolBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionToolBar(); + } + break; + case Tab: { + if (!m_styleoption) + m_styleoption = new QStyleOptionTabV3(); + + QStyleOptionTabV3 *opt = + qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->shape = info() == "South" ? QTabBar::RoundedSouth : QTabBar::RoundedNorth; + if (activeControl() == QLatin1String("beginning")) + opt->position = QStyleOptionTabV3::Beginning; + else if (activeControl() == QLatin1String("end")) + opt->position = QStyleOptionTabV3::End; + else if (activeControl() == QLatin1String("only")) + opt->position = QStyleOptionTabV3::OnlyOneTab; + else + opt->position = QStyleOptionTabV3::Middle; + + } break; + + case Menu: { + if (!m_styleoption) + m_styleoption = new QStyleOptionMenuItem(); + } + break; + case Frame: { + if (!m_styleoption) + m_styleoption = new QStyleOptionFrameV3(); + + QStyleOptionFrameV3 *opt = qstyleoption_cast(m_styleoption); + opt->frameShape = QFrame::StyledPanel; + opt->lineWidth = 1; + opt->midLineWidth = 1; + } + break; + case TabFrame: { + if (!m_styleoption) + m_styleoption = new QStyleOptionTabWidgetFrameV2(); + QStyleOptionTabWidgetFrameV2 *opt = qstyleoption_cast(m_styleoption); + opt->shape = (info() == "South") ? QTabBar::RoundedSouth : QTabBar::RoundedNorth; + if (minimum()) + opt->selectedTabRect = QRect(value(), 0, minimum(), height()); + opt->tabBarSize = QSize(minimum() , height()); + // oxygen style needs this hack + opt->leftCornerWidgetSize = QSize(value(), 0); + } + break; + case MenuItem: + case ComboBoxItem: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionMenuItem(); + + QStyleOptionMenuItem *opt = qstyleoption_cast(m_styleoption); + opt->checked = false; + opt->text = text(); + opt->palette = widget()->palette(); + } + break; + case CheckBox: + case RadioButton: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionButton(); + + QStyleOptionButton *opt = qstyleoption_cast(m_styleoption); + if (!on()) + opt->state |= QStyle::State_Off; + opt->text = text(); + } + break; + case Edit: { + if (!m_styleoption) + m_styleoption = new QStyleOptionFrameV3(); + + QStyleOptionFrameV3 *opt = qstyleoption_cast(m_styleoption); + opt->lineWidth = 1; // this must be non-zero + } + break; + case ComboBox :{ + if (!m_styleoption) + m_styleoption = new QStyleOptionComboBox(); + QStyleOptionComboBox *opt = qstyleoption_cast(m_styleoption); + opt->currentText = text(); + } + break; + case SpinBox: { + if (!m_styleoption) + m_styleoption = new QStyleOptionSpinBox(); + + QStyleOptionSpinBox *opt = qstyleoption_cast(m_styleoption); + opt->frame = true; + if (value() & 0x1) + opt->activeSubControls = QStyle::SC_SpinBoxUp; + else if (value() & (1<<1)) + opt->activeSubControls = QStyle::SC_SpinBoxDown; + opt->subControls = QStyle::SC_All; + opt->stepEnabled = 0; + if (value() & (1<<2)) + opt->stepEnabled |= QAbstractSpinBox::StepUpEnabled; + if (value() & (1<<3)) + opt->stepEnabled |= QAbstractSpinBox::StepDownEnabled; + } + break; + case Slider: + case Dial: + { + if (!m_styleoption) + m_styleoption = new QStyleOptionSlider(); + + QStyleOptionSlider *opt = qstyleoption_cast(m_styleoption); + opt->minimum = minimum(); + opt->maximum = maximum(); + // ### fixme - workaround for KDE inverted dial + opt->sliderPosition = value(); + opt->tickInterval = opt->maximum != opt->minimum ? 1200 / (opt->maximum - opt->minimum) : 0; + if (style() == QLatin1String("oxygen") && type == QLatin1String("dial")) + opt->sliderValue = maximum() - value(); + else + opt->sliderValue = value(); + opt->subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle; + opt->tickPosition = (activeControl() == "below") ? + QSlider::TicksBelow : (activeControl() == "above" ? + QSlider::TicksAbove: + QSlider::NoTicks); + if (opt->tickPosition != QSlider::NoTicks) + opt->subControls |= QStyle::SC_SliderTickmarks; + + opt->activeSubControls = QStyle::SC_None; + } + break; + case ProgressBar: { + if (QProgressBar *bar= qobject_cast(widget())){ + bar->setMaximum(maximum()); + bar->setMinimum(minimum()); + if (maximum() != minimum()) + bar->setValue(1); + } + if (!m_styleoption) + m_styleoption = new QStyleOptionProgressBarV2(); + + QStyleOptionProgressBarV2 *opt = qstyleoption_cast(m_styleoption); + opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; + opt->minimum = minimum(); + opt->maximum = maximum(); + opt->progress = value(); + } + break; + case GroupBox: { + if (!m_styleoption) + m_styleoption = new QStyleOptionGroupBox(); + + QStyleOptionGroupBox *opt = qstyleoption_cast(m_styleoption); + opt->text = text(); + opt->lineWidth = 1; + opt->subControls = QStyle::SC_GroupBoxLabel; + if (sunken()) // Qt draws an ugly line here so I ignore it + opt->subControls |= QStyle::SC_GroupBoxFrame; + else + opt->features |= QStyleOptionFrameV2::Flat; + if (activeControl() == "checkbox") + opt->subControls |= QStyle::SC_GroupBoxCheckBox; + + if (QGroupBox *group= qobject_cast(widget())) { + group->setTitle(text()); + group->setCheckable(opt->subControls & QStyle::SC_GroupBoxCheckBox); + } + } + break; + case ScrollBar: { + if (!m_styleoption) + m_styleoption = new QStyleOptionSlider(); + + QStyleOptionSlider *opt = qstyleoption_cast(m_styleoption); + opt->minimum = minimum(); + opt->maximum = maximum(); + opt->pageStep = horizontal() ? width() : height(); + opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical; + opt->sliderPosition = value(); + opt->sliderValue = value(); + opt->activeSubControls = (activeControl() == QLatin1String("up")) + ? QStyle::SC_ScrollBarSubLine : + (activeControl() == QLatin1String("down")) ? + QStyle::SC_ScrollBarAddLine: + QStyle::SC_ScrollBarSlider; + + opt->sliderValue = value(); + opt->subControls = QStyle::SC_All; + + QScrollBar *bar = qobject_cast(widget()); + bar->setMaximum(maximum()); + bar->setMinimum(minimum()); + bar->setValue(value()); + } + break; + default: + break; + } + + if (!m_styleoption) + m_styleoption = new QStyleOption(); + + m_styleoption->rect = QRect(m_paintMargins, m_paintMargins, width() - 2* m_paintMargins, height() - 2 * m_paintMargins); + + if (isEnabled()) + m_styleoption->state |= QStyle::State_Enabled; + if (m_active) + m_styleoption->state |= QStyle::State_Active; + if (m_sunken) + m_styleoption->state |= QStyle::State_Sunken; + if (m_raised) + m_styleoption->state |= QStyle::State_Raised; + if (m_selected) + m_styleoption->state |= QStyle::State_Selected; + if (m_focus) + m_styleoption->state |= QStyle::State_HasFocus; + if (m_on) + m_styleoption->state |= QStyle::State_On; + if (m_hover) + m_styleoption->state |= QStyle::State_MouseOver; + if (m_horizontal) + m_styleoption->state |= QStyle::State_Horizontal; + + if (widget()) { + widget()->ensurePolished(); + if (type == QLatin1String("tab") && style() != QLatin1String("mac")) { + // Some styles actually check the beginning and end position + // using widget geometry, so we have to trick it + widget()->setGeometry(0, 0, width(), height()); + if (activeControl() != "beginning") + m_styleoption->rect.translate(1, 0); // Don't position at start of widget + if (activeControl() != "end") + widget()->resize(200, height()); + } +#ifdef Q_WS_WIN + else widget()->resize(width(), height()); +#endif + + widget()->setEnabled(isEnabled()); + m_styleoption->fontMetrics = widget()->fontMetrics(); + if (!m_styleoption->palette.resolve()) + m_styleoption->palette = widget()->palette(); + if (m_hint.contains("mac.mini")) { + widget()->setAttribute(Qt::WA_MacMiniSize); + } else if (m_hint.contains("mac.small")) { + widget()->setAttribute(Qt::WA_MacSmallSize); + } + } +} + +/* + * Property style + * + * Returns a simplified style name. + * + * QMacStyle = "mac" + * QWindowsXPStyle = "windowsxp" + * QPlastiqueStyle = "plastique" + */ + +QString QStyleItem::style() const +{ + QString style = qApp->style()->metaObject()->className(); + style = style.toLower(); + if (style.contains(QLatin1String("oxygen"))) + return QLatin1String("oxygen"); + if (style.startsWith(QLatin1Char('q'))) + style = style.right(style.length() - 1); + if (style.endsWith("style")) + style = style.left(style.length() - 5); + return style.toLower(); +} + +QString QStyleItem::hitTest(int px, int py) +{ + QStyle::SubControl subcontrol = QStyle::SC_All; + initStyleOption(); + switch (m_itemType) { + case SpinBox :{ + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_SpinBox, + qstyleoption_cast(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SpinBoxUp) + return "up"; + else if (subcontrol == QStyle::SC_SpinBoxDown) + return "down"; + + } + break; + + case Slider: { + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_Slider, + qstyleoption_cast(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_SliderHandle) + return "handle"; + + } + break; + case ScrollBar: { + subcontrol = qApp->style()->hitTestComplexControl(QStyle::CC_ScrollBar, + qstyleoption_cast(m_styleoption), + QPoint(px,py), 0); + if (subcontrol == QStyle::SC_ScrollBarSlider) + return "handle"; + + if (subcontrol == QStyle::SC_ScrollBarSubLine + || subcontrol == QStyle::SC_ScrollBarSubPage) + return "up"; + + if (subcontrol == QStyle::SC_ScrollBarAddLine + || subcontrol == QStyle::SC_ScrollBarAddPage) + return "down"; + } + break; + default: + break; + } + return "none"; +} + +QSize QStyleItem::sizeFromContents(int width, int height) +{ + initStyleOption(); + + QSize size; + switch (m_itemType) { + case CheckBox: + size = qApp->style()->sizeFromContents(QStyle::CT_CheckBox, m_styleoption, QSize(width,height), widget()); + break; + case ToolButton: + size = qApp->style()->sizeFromContents(QStyle::CT_ToolButton, m_styleoption, QSize(width,height), widget()); + break; + case Button: + size = qApp->style()->sizeFromContents(QStyle::CT_PushButton, m_styleoption, QSize(width,height), widget()); + break; + case Tab: + size = qApp->style()->sizeFromContents(QStyle::CT_TabBarTab, m_styleoption, QSize(width,height), widget()); + break; + case ComboBox: + size = qApp->style()->sizeFromContents(QStyle::CT_ComboBox, m_styleoption, QSize(width,height), widget()); + break; + case SpinBox: + size = qApp->style()->sizeFromContents(QStyle::CT_SpinBox, m_styleoption, QSize(width,height), widget()); + break; + case Slider: + size = qApp->style()->sizeFromContents(QStyle::CT_Slider, m_styleoption, QSize(width,height), widget()); + break; + case ProgressBar: + size = qApp->style()->sizeFromContents(QStyle::CT_ProgressBar, m_styleoption, QSize(width,height), widget()); + break; + case Edit: + size = qApp->style()->sizeFromContents(QStyle::CT_LineEdit, m_styleoption, QSize(width,height), widget()); + break; + case GroupBox: + size = qApp->style()->sizeFromContents(QStyle::CT_GroupBox, m_styleoption, QSize(width,height), widget()); + break; + case Header: + size = qApp->style()->sizeFromContents(QStyle::CT_HeaderSection, m_styleoption, QSize(width,height), widget()); +#ifdef Q_WS_MAC + if (style() =="mac") + size.setHeight(15); +#endif + break; + case ItemRow: + case Item: //fall through + size = qApp->style()->sizeFromContents(QStyle::CT_ItemViewItem, m_styleoption, QSize(width,height), widget()); + break; + default: + break; + } + +#ifdef Q_WS_MAC + // ### hack - With even heights, the text baseline is off on mac + if (size.height() %2 == 0) + size.setHeight(size.height() + 1); +#endif + return size; +} + + +int QStyleItem::pixelMetric(const QString &metric) +{ + + if (metric == "scrollbarExtent") + return qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, widget()); + else if (metric == "defaultframewidth") + return qApp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, widget()); + else if (metric == "taboverlap") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0 , widget()); + else if (metric == "tabbaseoverlap") +#ifdef Q_WS_WIN + // On windows the tabbar paintmargin extends the overlap by one pixels + return 1 + qApp->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, 0 , widget()); +#else + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, 0 , widget()); +#endif + else if (metric == "tabhspace") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabHSpace, 0 , widget()); + else if (metric == "tabvspace") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabVSpace, 0 , widget()); + else if (metric == "tabbaseheight") + return qApp->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, 0 , widget()); + else if (metric == "tabvshift") + return qApp->style()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, 0 , widget()); + else if (metric == "menuhmargin") + return qApp->style()->pixelMetric(QStyle::PM_MenuHMargin, 0 , widget()); + else if (metric == "menuvmargin") + return qApp->style()->pixelMetric(QStyle::PM_MenuVMargin, 0 , widget()); + else if (metric == "menupanelwidth") + return qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0 , widget()); + else if (metric == "splitterwidth") + return qApp->style()->pixelMetric(QStyle::PM_SplitterWidth, 0 , widget()); + // This metric is incorrectly negative on oxygen + else if (metric == "scrollbarspacing") + return abs(qApp->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, 0 , widget())); + return 0; +} + +QVariant QStyleItem::styleHint(const QString &metric) +{ + initStyleOption(); + if (metric == "comboboxpopup") { + return qApp->style()->styleHint(QStyle::SH_ComboBox_Popup, m_styleoption); + } else if (metric == "highlightedTextColor") { + if (widget()) + return widget()->palette().highlightedText().color().name(); + return qApp->palette().highlightedText().color().name(); + } else if (metric == "textColor") { + if (widget()) + return widget()->palette().text().color().name(); + return qApp->palette().text().color().name(); + } else if (metric == "focuswidget") { + return qApp->style()->styleHint(QStyle::SH_FocusFrame_AboveWidget); + + } else if (metric == "tabbaralignment") { + int result = qApp->style()->styleHint(QStyle::SH_TabBar_Alignment); + if (result == Qt::AlignCenter) + return "center"; + return "left"; + + } else if (metric == "framearoundcontents") + return qApp->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents); + return 0; +} + +void QStyleItem::setCursor(const QString &str) +{ + if (m_cursor != str) { + m_cursor = str; + if (m_cursor == "sizehorcursor") + QDeclarativeItem::setCursor(Qt::SizeHorCursor); + else if (m_cursor == "sizevercursor") + QDeclarativeItem::setCursor(Qt::SizeVerCursor); + else if (m_cursor == "sizeallcursor") + QDeclarativeItem::setCursor(Qt::SizeAllCursor); + else if (m_cursor == "splithcursor") + QDeclarativeItem::setCursor(Qt::SplitHCursor); + else if (m_cursor == "splitvcursor") + QDeclarativeItem::setCursor(Qt::SplitVCursor); + else if (m_cursor == "wait") + QDeclarativeItem::setCursor(Qt::WaitCursor); + else if (m_cursor == "pointinghandcursor") + QDeclarativeItem::setCursor(Qt::PointingHandCursor); + emit cursorChanged(); + } +} + +void QStyleItem::setElementType(const QString &str) +{ + if (m_type == str) + return; + + m_type = str; + + emit elementTypeChanged(); + + if (m_dummywidget && !m_sharedWidget) { + delete m_dummywidget; + m_dummywidget = 0; + } + + if (m_styleoption) { + delete m_styleoption; + m_styleoption = 0; + } + + // Only enable visible if the widget can animate + bool visible = false; + if (str == "menu" || str == "menuitem") { + // Since these are used by the delegate, it makes no + // sense to re-create them per item + static QWidget *menu = new QMenu(); + m_sharedWidget = true; + m_dummywidget = menu; + m_itemType = (str == "menu") ? Menu : MenuItem; + } else if (str == "item" || str == "itemrow" || str == "header") { + // Since these are used by the delegate, it makes no + // sense to re-create them per item + static QTreeView *menu = new QTreeView(); + menu->setAttribute(Qt::WA_MacMiniSize); + m_sharedWidget = true; + if (str == "header") { + m_dummywidget = menu->header(); + if (style() == "mac") { // The default qt font seems to big + QFont font = m_dummywidget->font(); + font.setPointSize(11); + m_dummywidget->setFont(font); + } + m_itemType = Header; + } else { + m_dummywidget = menu; + m_itemType = (str == "item") ? Item : ItemRow; + } + } else if (str == "groupbox") { + // Since these are used by the delegate, it makes no + // sense to re-create them per item + static QGroupBox *group = new QGroupBox(); + m_sharedWidget = true; + m_dummywidget = group; + m_itemType = GroupBox; + } else if (str == "tabframe" || str == "tab") { + static QTabWidget *tabframe = new QTabWidget(); + m_sharedWidget = true; + if (str == "tab") { + m_dummywidget = tabframe->findChild(); + m_itemType = Tab; + } else { + m_dummywidget = tabframe; + m_itemType = TabFrame; + } + } else if (str == "comboboxitem") { + // Gtk uses qobject cast, hence we need to separate this from menuitem + // On mac, we temporarily use the menu item because it has more accurate + // palette. +#ifdef Q_WS_MAC + static QMenu *combo = new QMenu(); +#else + static QComboBox *combo = new QComboBox(); +#endif + m_sharedWidget = true; + m_dummywidget = combo; + m_itemType = ComboBoxItem; + } else if (str == "toolbar") { + static QToolBar *tb = 0; + if (!tb) { + QMainWindow *mw = new QMainWindow(); + tb = new QToolBar(mw); + } + m_dummywidget = tb; + m_itemType = ToolBar; + } else if (str == "toolbutton") { + static QToolButton *tb = 0; + static QToolBar *bar = 0; + // KDE animations are too broken with these widgets + if (style() != QLatin1String("oxygen")) { + if (!tb) { + bar = new QToolBar(0); + tb = new QToolButton(bar); + } + } + m_sharedWidget = true; + m_dummywidget = tb; + m_itemType = ToolButton; + } else if (str == "slider") { + static QSlider *slider = new QSlider(); + m_sharedWidget = true; + m_dummywidget = slider; + m_itemType = Slider; + } else if (str == "frame") { + static QFrame *frame = new QFrame(); + m_sharedWidget = true; + m_dummywidget = frame; + m_itemType = Frame; + } else if (str == "combobox") { + m_dummywidget = new QComboBox(); + visible = true; + m_itemType = ComboBox; + } else if (str == "splitter") { + visible = true; + m_itemType = Splitter; + } else if (str == "progressbar") { + m_dummywidget = new QProgressBar(); + visible = true; + m_itemType = ProgressBar; + } else if (str == "button") { + m_dummywidget = new QPushButton(); + visible = true; + m_itemType = Button; + } else if (str == "checkbox") { + m_dummywidget = new QCheckBox(); + visible = true; + m_itemType = CheckBox; + } else if (str == "radiobutton") { + m_dummywidget = new QRadioButton(); + visible = true; + m_itemType = RadioButton; + } else if (str == "edit") { + m_dummywidget = new QLineEdit(); + visible = true; + m_itemType = Edit; + } else if (str == "spinbox") { +#ifndef Q_WS_WIN // Vista spinbox is currently not working due to grabwidget + m_dummywidget = new QSpinBox(); + visible = true; +#endif + m_itemType = SpinBox; + } else if (str == "scrollbar") { + m_dummywidget = new QScrollBar(); + visible = true; + m_itemType = ScrollBar; + } else if (str == "widget") { + m_itemType = Widget; + } else if (str == "focusframe") { + m_itemType = FocusFrame; + } else if (str == "dial") { + m_itemType = Dial; + } + if (m_dummywidget) { + m_dummywidget->installEventFilter(this); + m_dummywidget->setAttribute(Qt::WA_QuitOnClose, false); // dont keep app open + m_dummywidget->setAttribute(Qt::WA_LayoutUsesWidgetRect); + m_dummywidget->winId(); +#ifdef Q_WS_MAC + m_dummywidget->setGeometry(-1000, 0, 10,10); + m_dummywidget->setVisible(visible); // Mac require us to set the visibility before this +#endif + m_dummywidget->setAttribute(Qt::WA_DontShowOnScreen); + m_dummywidget->setVisible(visible); + } +} + +bool QStyleItem::eventFilter(QObject *o, QEvent *e) { + if (e->type() == QEvent::Paint) { + updateItem(); + return true; + } + return QObject::eventFilter(o, e); +} + +void QStyleItem::showToolTip(const QString &str) +{ + QPointF scene = mapToScene(width() - 20, 0); + QPoint global = qApp->focusWidget()->mapToGlobal(scene.toPoint()); + QToolTip::showText(QPoint(global.x(), global.y()), str); +} + +QRect QStyleItem::subControlRect(const QString &subcontrolString) +{ + QStyle::SubControl subcontrol = QStyle::SC_None; + initStyleOption(); + switch (m_itemType) { + case SpinBox: + { + QStyle::ComplexControl control = QStyle::CC_SpinBox; + if (subcontrolString == QLatin1String("down")) + subcontrol = QStyle::SC_SpinBoxDown; + else if (subcontrolString == QLatin1String("up")) + subcontrol = QStyle::SC_SpinBoxUp; + else if (subcontrolString == QLatin1String("edit")){ + subcontrol = QStyle::SC_SpinBoxEditField; + } + return qApp->style()->subControlRect(control, + qstyleoption_cast(m_styleoption), + subcontrol, widget()); + + } + break; + case Slider: + { + QStyle::ComplexControl control = QStyle::CC_Slider; + if (subcontrolString == QLatin1String("handle")) + subcontrol = QStyle::SC_SliderHandle; + else if (subcontrolString == QLatin1String("groove")) + subcontrol = QStyle::SC_SliderGroove; + return qApp->style()->subControlRect(control, + qstyleoption_cast(m_styleoption), + subcontrol, widget()); + + } + break; + case ScrollBar: + { + QStyle::ComplexControl control = QStyle::CC_ScrollBar; + if (subcontrolString == QLatin1String("slider")) + subcontrol = QStyle::SC_ScrollBarSlider; + if (subcontrolString == QLatin1String("groove")) + subcontrol = QStyle::SC_ScrollBarGroove; + else if (subcontrolString == QLatin1String("handle")) + subcontrol = QStyle::SC_ScrollBarSlider; + else if (subcontrolString == QLatin1String("add")) + subcontrol = QStyle::SC_ScrollBarAddPage; + else if (subcontrolString == QLatin1String("sub")) + subcontrol = QStyle::SC_ScrollBarSubPage; + return qApp->style()->subControlRect(control, + qstyleoption_cast(m_styleoption), + subcontrol, widget()); + } + break; + default: + break; + } + return QRect(); +} + +void QStyleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + if (width() < 1 || height() <1) + return; + + initStyleOption(); + + if (widget()) { + painter->save(); + painter->setFont(widget()->font()); + painter->translate(-m_styleoption->rect.left() + m_paintMargins, 0); + } + + switch (m_itemType) { + case Button: + qApp->style()->drawControl(QStyle::CE_PushButton, m_styleoption, painter, widget()); + break; + case ItemRow :{ + QPixmap pixmap; + // Only draw through style once + const QString pmKey = QLatin1Literal("itemrow") % QString::number(m_styleoption->state,16) % activeControl(); + if (!QPixmapCache::find(pmKey, pixmap) || pixmap.width() < width() || height() != pixmap.height()) { + int newSize = width(); + pixmap = QPixmap(newSize, height()); + pixmap.fill(Qt::transparent); + QPainter pixpainter(&pixmap); + qApp->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, m_styleoption, &pixpainter, widget()); + if (!qApp->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected) && selected()) + pixpainter.fillRect(m_styleoption->rect, m_styleoption->palette.highlight()); + QPixmapCache::insert(pmKey, pixmap); + } + painter->drawPixmap(0, 0, pixmap); + } + break; + case Item: + qApp->style()->drawControl(QStyle::CE_ItemViewItem, m_styleoption, painter, widget()); + break; + case Header: + widget()->resize(m_styleoption->rect.size()); // macstyle explicitly uses the widget height + qApp->style()->drawControl(QStyle::CE_Header, m_styleoption, painter, widget()); + break; + case ToolButton: + qApp->style()->drawComplexControl(QStyle::CC_ToolButton, qstyleoption_cast(m_styleoption), painter, widget()); + break; + case Tab: + qApp->style()->drawControl(QStyle::CE_TabBarTab, m_styleoption, painter, widget()); + break; + case Frame: + qApp->style()->drawControl(QStyle::CE_ShapedFrame, m_styleoption, painter, widget()); + break; + case FocusFrame: + qApp->style()->drawControl(QStyle::CE_FocusFrame, m_styleoption, painter, widget()); + break; + case TabFrame: + qApp->style()->drawPrimitive(QStyle::PE_FrameTabWidget, m_styleoption, painter, widget()); + break; + case MenuItem: + case ComboBoxItem: // fall through + qApp->style()->drawControl(QStyle::CE_MenuItem, m_styleoption, painter, widget()); + break; + case CheckBox: + qApp->style()->drawControl(QStyle::CE_CheckBox, m_styleoption, painter, widget()); + break; + case RadioButton: + qApp->style()->drawControl(QStyle::CE_RadioButton, m_styleoption, painter, widget()); + break; + case Edit: + qApp->style()->drawPrimitive(QStyle::PE_PanelLineEdit, m_styleoption, painter, widget()); + break; + case Widget: + qApp->style()->drawPrimitive(QStyle::PE_Widget, m_styleoption, painter, widget()); + break; + case Splitter: + qApp->style()->drawControl(QStyle::CE_Splitter, m_styleoption, painter, widget()); + break; + case ComboBox: + qApp->style()->drawComplexControl(QStyle::CC_ComboBox, + qstyleoption_cast(m_styleoption), + painter, widget()); + qApp->style()->drawControl(QStyle::CE_ComboBoxLabel, m_styleoption, painter, widget()); + break; + case SpinBox: + qApp->style()->drawComplexControl(QStyle::CC_SpinBox, + qstyleoption_cast(m_styleoption), + painter, widget()); + break; + case Slider: + qApp->style()->drawComplexControl(QStyle::CC_Slider, + qstyleoption_cast(m_styleoption), + painter, widget()); + break; + case Dial: + qApp->style()->drawComplexControl(QStyle::CC_Dial, + qstyleoption_cast(m_styleoption), + painter, widget()); + break; + case ProgressBar: + qApp->style()->drawControl(QStyle::CE_ProgressBar, m_styleoption, painter, widget()); + break; + case ToolBar: + qApp->style()->drawControl(QStyle::CE_ToolBar, m_styleoption, painter, widget()); + break; + case GroupBox: + qApp->style()->drawComplexControl(QStyle::CC_GroupBox, qstyleoption_cast(m_styleoption), painter, widget()); + break; + case ScrollBar: + qApp->style()->drawComplexControl(QStyle::CC_ScrollBar, qstyleoption_cast(m_styleoption), painter, widget()); + break; + case Menu: { + if (QMenu *menu = qobject_cast(widget())) { + m_styleoption->palette = menu->palette(); + } + QStyleHintReturnMask val; + qApp->style()->styleHint(QStyle::SH_Menu_Mask, m_styleoption, widget(), &val); + painter->save(); + painter->setClipRegion(val.region); + painter->fillRect(m_styleoption->rect, m_styleoption->palette.window()); + painter->restore(); + qApp->style()->drawPrimitive(QStyle::PE_PanelMenu, m_styleoption, painter, widget()); + + QStyleOptionFrame frame; + frame.lineWidth = qApp->style()->pixelMetric(QStyle::PM_MenuPanelWidth); + frame.midLineWidth = 0; + frame.rect = m_styleoption->rect; + qApp->style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, painter, widget()); + } + break; + default: + break; + } + if (widget()) + painter->restore(); +} + +int QStyleItem::textWidth(const QString &text) +{ + if (widget()) + return widget()->fontMetrics().boundingRect(text).width(); + return qApp->fontMetrics().boundingRect(text).width(); +} + +int QStyleItem::fontHeight() +{ + if (widget()) + return widget()->fontMetrics().height(); + return qApp->fontMetrics().height(); +} + +QString QStyleItem::fontFamily() +{ + if (widget()) + return widget()->font().family(); + return qApp->font().family(); +} + +double QStyleItem::fontPointSize() +{ + if (widget()) + return widget()->font().pointSizeF(); + return qApp->font().pointSizeF(); +} diff --git a/share/qtcreator/welcomescreen/components/styleitem/qstyleitem.h b/share/qtcreator/welcomescreen/components/styleitem/qstyleitem.h new file mode 100644 index 00000000000..1b9f9c875ac --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qstyleitem.h @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STYLEWRAPPER_H +#define STYLEWRAPPER_H + +#include +#include +#include +#include + +class QStyleItem: public QDeclarativeItem +{ + Q_OBJECT + + Q_PROPERTY( bool sunken READ sunken WRITE setSunken NOTIFY sunkenChanged) + Q_PROPERTY( bool raised READ raised WRITE setRaised NOTIFY raisedChanged) + Q_PROPERTY( bool active READ active WRITE setActive NOTIFY activeChanged) + Q_PROPERTY( bool selected READ selected WRITE setSelected NOTIFY selectedChanged) + Q_PROPERTY( bool focus READ focus WRITE setFocus NOTIFY focusChanged) + Q_PROPERTY( bool on READ on WRITE setOn NOTIFY onChanged) + Q_PROPERTY( bool hover READ hover WRITE setHover NOTIFY hoverChanged) + Q_PROPERTY( bool horizontal READ horizontal WRITE setHorizontal NOTIFY horizontalChanged) + + Q_PROPERTY( QString elementType READ elementType WRITE setElementType NOTIFY elementTypeChanged) + Q_PROPERTY( QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY( QString activeControl READ activeControl WRITE setActiveControl NOTIFY activeControlChanged) + Q_PROPERTY( QString info READ info WRITE setInfo NOTIFY infoChanged) + Q_PROPERTY( QString style READ style NOTIFY styleChanged) + Q_PROPERTY( QString hint READ hint WRITE setHint NOTIFY hintChanged) + Q_PROPERTY( QString cursor READ cursor WRITE setCursor NOTIFY cursorChanged) + + // For range controls + Q_PROPERTY( int minimum READ minimum WRITE setMinimum NOTIFY minimumChanged) + Q_PROPERTY( int maximum READ maximum WRITE setMaximum NOTIFY maximumChanged) + Q_PROPERTY( int value READ value WRITE setValue NOTIFY valueChanged) + Q_PROPERTY( int paintMargins READ paintMargins WRITE setPaintMargins NOTIFY paintMarginsChanged) + + Q_PROPERTY( QString fontFamily READ fontFamily) + Q_PROPERTY( double fontPointSize READ fontPointSize) + Q_PROPERTY( int fontHeight READ fontHeight NOTIFY fontHeightChanged) + +public: + enum Type { + Undefined, + Button, + RadioButton, + CheckBox, + ComboBox, + ComboBoxItem, + Dial, + ToolBar, + ToolButton, + Tab, + TabFrame, + Frame, + FocusFrame, + SpinBox, + Slider, + ScrollBar, + ProgressBar, + Edit, + GroupBox, + Header, + Item, + ItemRow, + Splitter, + Menu, + MenuItem, + Widget + }; + + QStyleItem(QDeclarativeItem *parent = 0); + ~QStyleItem(); + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + + bool sunken() const { return m_sunken; } + bool raised() const { return m_raised; } + bool active() const { return m_active; } + bool selected() const { return m_selected; } + bool focus() const { return m_focus; } + bool on() const { return m_on; } + bool hover() const { return m_hover; } + bool horizontal() const { return m_horizontal; } + + int minimum() const { return m_minimum; } + int maximum() const { return m_maximum; } + int value() const { return m_value; } + int paintMargins() const { return m_paintMargins; } + + QString elementType() const { return m_type; } + QString text() const { return m_text; } + QString cursor() const { return m_cursor; } + QString activeControl() const { return m_activeControl; } + QString info() const { return m_info; } + QString hint() const { return m_hint; } + QString style() const; + + void setSunken(bool sunken) { if (m_sunken != sunken) {m_sunken = sunken; emit sunkenChanged();}} + void setRaised(bool raised) { if (m_raised!= raised) {m_raised = raised; emit raisedChanged();}} + void setActive(bool active) { if (m_active!= active) {m_active = active; emit activeChanged();}} + void setSelected(bool selected) { if (m_selected!= selected) {m_selected = selected; emit selectedChanged();}} + void setFocus(bool focus) { if (m_focus != focus) {m_focus = focus; emit focusChanged();}} + void setOn(bool on) { if (m_on != on) {m_on = on ; emit onChanged();}} + void setHover(bool hover) { if (m_hover != hover) {m_hover = hover ; emit hoverChanged();}} + void setHorizontal(bool horizontal) { if (m_horizontal != horizontal) {m_horizontal = horizontal; emit horizontalChanged();}} + void setMinimum(int minimum) { if (m_minimum!= minimum) {m_minimum = minimum; emit minimumChanged();}} + void setMaximum(int maximum) { if (m_maximum != maximum) {m_maximum = maximum; emit maximumChanged();}} + void setValue(int value) { if (m_value!= value) {m_value = value; emit valueChanged();}} + void setPaintMargins(int value) { + Q_UNUSED(value) +#ifdef Q_WS_WIN //only vista style needs this hack + if (m_paintMargins!= value) {m_paintMargins = value;} +#endif + } + void setCursor(const QString &str); + void setElementType(const QString &str); + void setText(const QString &str) { if (m_text != str) {m_text = str; emit textChanged();}} + void setActiveControl(const QString &str) { if (m_activeControl != str) {m_activeControl = str; emit activeControlChanged();}} + void setInfo(const QString &str) { if (m_info != str) {m_info = str; emit infoChanged();}} + void setHint(const QString &str) { if (m_hint != str) {m_hint= str; emit hintChanged();}} + + bool eventFilter(QObject *, QEvent *); + virtual void initStyleOption (); + QWidget *widget(){ return m_dummywidget; } + + int fontHeight(); + QString fontFamily(); + double fontPointSize(); + + +public Q_SLOTS: + int pixelMetric(const QString&); + QVariant styleHint(const QString&); + QSize sizeFromContents(int width, int height); + void updateItem(){update();} + QString hitTest(int x, int y); + QRect subControlRect(const QString &subcontrolString); + void showToolTip(const QString &str); + int textWidth(const QString &); + +Q_SIGNALS: + void elementTypeChanged(); + void textChanged(); + void sunkenChanged(); + void raisedChanged(); + void activeChanged(); + void selectedChanged(); + void focusChanged(); + void onChanged(); + void hoverChanged(); + void horizontalChanged(); + void minimumChanged(); + void maximumChanged(); + void valueChanged(); + void activeControlChanged(); + void infoChanged(); + void styleChanged(); + void paintMarginsChanged(); + void hintChanged(); + void cursorChanged(); + void fontHeightChanged(); + +protected: + QWidget *m_dummywidget; + QStyleOption *m_styleoption; + Type m_itemType; + + QString m_type; + QString m_cursor; + QString m_text; + QString m_activeControl; + QString m_info; + QString m_hint; + + bool m_sunken; + bool m_raised; + bool m_active; + bool m_selected; + bool m_focus; + bool m_hover; + bool m_on; + bool m_horizontal; + bool m_sharedWidget; + + int m_minimum; + int m_maximum; + int m_value; + int m_paintMargins; +}; + +#endif //STYLEWRAPPER_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qstyleplugin.cpp b/share/qtcreator/welcomescreen/components/styleitem/qstyleplugin.cpp new file mode 100644 index 00000000000..2015f0e334e --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qstyleplugin.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qstyleplugin.h" +#include "qstyleitem.h" +#include "qrangemodel.h" +#include "qtmenu.h" +#include "qtmenubar.h" +#include "qtmenuitem.h" +#include "qwheelarea.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +// Load icons from desktop theme +class DesktopIconProvider : public QDeclarativeImageProvider +{ +public: + DesktopIconProvider() + : QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap) + { + } + + QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) + { + Q_UNUSED(requestedSize); + Q_UNUSED(size); + int pos = id.lastIndexOf('/'); + QString iconName = id.right(id.length() - pos); + int width = qApp->style()->pixelMetric(QStyle::PM_ToolBarIconSize); + return QIcon::fromTheme(iconName).pixmap(width); + } +}; + + +void StylePlugin::registerTypes(const char *uri) +{ + qDebug() << "register" << uri; + qmlRegisterType(uri, 1, 0, "QStyleItem"); + qmlRegisterType(uri, 1, 0, "RangeModel"); + qmlRegisterType(uri, 1, 0, "DropShadow"); + qmlRegisterType(uri, 1, 0, "FileSystemModel"); + qmlRegisterType(uri, 1, 0, "WheelArea"); + qmlRegisterType(uri, 1, 0, "MenuBase"); + qmlRegisterType(uri, 1, 0, "MenuBarBase"); + qmlRegisterType(uri, 1, 0, "MenuItemBase"); +} + +void StylePlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) +{ + Q_UNUSED(uri); + engine->addImageProvider("desktoptheme", new DesktopIconProvider); +} + +Q_EXPORT_PLUGIN2(styleplugin, StylePlugin) diff --git a/share/qtcreator/welcomescreen/components/styleitem/qstyleplugin.h b/share/qtcreator/welcomescreen/components/styleitem/qstyleplugin.h new file mode 100644 index 00000000000..648add70c8f --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qstyleplugin.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STYLEPLUGIN_H +#define STYLEPLUGIN_H + +#include +#include +#include +#include +#include "qdeclarativefolderlistmodel.h" + + +class StylePlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + void registerTypes(const char *uri); + void initializeEngine(QDeclarativeEngine *engine, const char *uri); +}; + +#endif // STYLEPLUGIN_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qtmenu.cpp b/share/qtcreator/welcomescreen/components/styleitem/qtmenu.cpp new file mode 100644 index 00000000000..e832f98d930 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qtmenu.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** 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 Technology Preview License Agreement accompanying this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#include "qtmenu.h" +#include "qdebug.h" +#include + +QtMenu::QtMenu(QObject *parent) + : QObject(parent) +{ + m_menu = new QMenu(0); +} + +QtMenu::~QtMenu() +{ + delete m_menu; +} + +void QtMenu::setTitle(const QString &title) +{ + +} + +QString QtMenu::title() const +{ + +} + +QDeclarativeListProperty QtMenu::menuItems() +{ + return QDeclarativeListProperty(this, m_menuItems); +} + +void QtMenu::showPopup(qreal x, qreal y) +{ + m_menu->clear(); + foreach (QtMenuItem *item, m_menuItems) { + QAction *action = new QAction(item->text(), m_menu); + connect(action, SIGNAL(triggered()), item, SIGNAL(selected())); + m_menu->insertAction(0, action); + } + + // x,y are in view coordinates, QMenu expects screen coordinates + // ### activeWindow hack + QPoint screenPosition = QApplication::activeWindow()->mapToGlobal(QPoint(x, y)); + + m_menu->popup(screenPosition); +} + diff --git a/share/qtcreator/welcomescreen/components/styleitem/qtmenu.h b/share/qtcreator/welcomescreen/components/styleitem/qtmenu.h new file mode 100644 index 00000000000..9e17db3028c --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qtmenu.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** 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 Technology Preview License Agreement accompanying this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#ifndef QTMLMENU_H +#define QTMLMENU_H + +#include +#include +#include +#include "qtmenuitem.h" +class QtMenu : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString title READ title WRITE setTitle) + Q_PROPERTY(QDeclarativeListProperty menuItems READ menuItems) + Q_CLASSINFO("DefaultProperty", "menuItems") +public: + QtMenu(QObject *parent = 0); + virtual ~QtMenu(); + + void setTitle(const QString &title); + QString title() const; + QDeclarativeListProperty menuItems(); + Q_INVOKABLE void showPopup(qreal x, qreal y); +Q_SIGNALS: + void selected(); +private: + QString m_title; + QWidget *dummy; + QMenu *m_menu; + QList m_menuItems; +}; + +QML_DECLARE_TYPE(QtMenu) + +#endif // QTMLMENU_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qtmenubar.cpp b/share/qtcreator/welcomescreen/components/styleitem/qtmenubar.cpp new file mode 100644 index 00000000000..7257795a034 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qtmenubar.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOTgall +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtmenubar.h" + +#include + +QtMenuBar::QtMenuBar(QDeclarativeItem *parent) + : QDeclarativeItem(parent) +{ + setFlag(QGraphicsItem::ItemHasNoContents, false); +} + +QtMenuBar::~QtMenuBar() +{ +} + +QDeclarativeListProperty QtMenuBar::menus() +{ + return QDeclarativeListProperty(this, m_menus); +} diff --git a/share/qtcreator/welcomescreen/components/styleitem/qtmenubar.h b/share/qtcreator/welcomescreen/components/styleitem/qtmenubar.h new file mode 100644 index 00000000000..4c402b8501a --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qtmenubar.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMENUBAR_H +#define QTMENUBAR_H + +#include +#include + +#include "qtmenu.h" + +class QtMenuBar: public QDeclarativeItem +{ + Q_OBJECT + + Q_PROPERTY(QDeclarativeListProperty menus READ menus) +public: + QtMenuBar(QDeclarativeItem *parent = 0); + ~QtMenuBar(); + + QDeclarativeListProperty menus(); + + //void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + +private: + QList m_menus; +}; + +#endif //QTMENUBAR_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qtmenuitem.cpp b/share/qtcreator/welcomescreen/components/styleitem/qtmenuitem.cpp new file mode 100644 index 00000000000..8769990133d --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qtmenuitem.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOTgall +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtmenuitem.h" + +QtMenuItem::QtMenuItem(QObject *parent) + : QObject(parent) +{ + +} + +QtMenuItem::~QtMenuItem() +{ +} + +void QtMenuItem::setText(const QString &text) +{ + m_text = text; +} + +QString QtMenuItem::text() +{ + return m_text; +} diff --git a/share/qtcreator/welcomescreen/components/styleitem/qtmenuitem.h b/share/qtcreator/welcomescreen/components/styleitem/qtmenuitem.h new file mode 100644 index 00000000000..7c4a1d4f1d0 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qtmenuitem.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMENUITEM_H +#define QTMENUITEM_H + +#include + +class QtMenuItem: public QObject +{ + Q_PROPERTY(QString text READ text WRITE setText); + + Q_OBJECT +public: + QtMenuItem(QObject *parent = 0); + ~QtMenuItem(); + + void setText(const QString &text); + QString text(); + +Q_SIGNALS: + void selected(); + +private: + QString m_text; +}; + +#endif //QTMENUITEM_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/qwheelarea.cpp b/share/qtcreator/welcomescreen/components/styleitem/qwheelarea.cpp new file mode 100644 index 00000000000..1a7ae9e6cad --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qwheelarea.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOTgall +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qwheelarea.h" + + +QWheelArea::QWheelArea(QDeclarativeItem *parent) + : QDeclarativeItem(parent), + _horizontalMinimumValue(0), + _horizontalMaximumValue(0), + _verticalMinimumValue(0), + _verticalMaximumValue(0), + _horizontalValue(0), + _verticalValue(0), + _verticalDelta(0), + _horizontalDelta(0) +{} + +QWheelArea::~QWheelArea() {} + +bool QWheelArea::event (QEvent * e) { + switch(e->type()) { + case QEvent::GraphicsSceneWheel: { + QGraphicsSceneWheelEvent *we = static_cast(e); + if(we) { + switch(we->orientation()) { + case Qt::Horizontal: + setHorizontalDelta(we->delta()); + break; + case Qt::Vertical: + setVerticalDelta(we->delta()); + } + return true; + } + } + case QEvent::Wheel: { + QWheelEvent *we = static_cast(e); + if(we) { + switch(we->orientation()) { + case Qt::Horizontal: + setHorizontalDelta(we->delta()); + + break; + case Qt::Vertical: + setVerticalDelta(we->delta()); + + } + return true; + } + } + default: break; + } + return QDeclarativeItem::event(e); +} + +void QWheelArea::setHorizontalMinimumValue(qreal min) +{ + _horizontalMinimumValue = min; +} + +qreal QWheelArea::horizontalMinimumValue() const +{ + return _horizontalMinimumValue; +} + +void QWheelArea::setHorizontalMaximumValue(qreal max) +{ + _horizontalMaximumValue = max; +} +qreal QWheelArea::horizontalMaximumValue() const +{ + return _horizontalMaximumValue; +} + +void QWheelArea::setVerticalMinimumValue(qreal min) +{ + _verticalMinimumValue = min; +} + +qreal QWheelArea::verticalMinimumValue() const +{ + return _verticalMinimumValue; +} + +void QWheelArea::setVerticalMaximumValue(qreal max) +{ + _verticalMaximumValue = max; +} + +qreal QWheelArea::verticalMaximumValue() const +{ + return _verticalMaximumValue; +} + +void QWheelArea::setHorizontalValue(qreal val) +{ + if (val > _horizontalMaximumValue) + _horizontalValue = _horizontalMaximumValue; + else if (val < _horizontalMinimumValue) + _horizontalValue = _horizontalMinimumValue; + else + _horizontalValue = val; + emit(horizontalValueChanged()); +} + +qreal QWheelArea::horizontalValue() const +{ + return _horizontalValue; +} + +void QWheelArea::setVerticalValue(qreal val) +{ + if (val > _verticalMaximumValue) + _verticalValue = _verticalMaximumValue; + else if (val < _verticalMinimumValue) + _verticalValue = _verticalMinimumValue; + else + _verticalValue = val; + emit(verticalValueChanged()); +} + +qreal QWheelArea::verticalValue() const +{ + return _verticalValue; +} + +void QWheelArea::setVerticalDelta(qreal d) +{ + _verticalDelta = d/15; + setVerticalValue(_verticalValue - _verticalDelta); + emit(verticalWheelMoved()); +} + +qreal QWheelArea::verticalDelta() const +{ + return _verticalDelta; +} + +void QWheelArea::setHorizontalDelta(qreal d) +{ + _horizontalDelta = d/15; + setHorizontalValue(_horizontalValue - _horizontalDelta); + emit(horizontalWheelMoved()); +} + +qreal QWheelArea::horizontalDelta() const +{ + return _horizontalDelta; +} diff --git a/share/qtcreator/welcomescreen/components/styleitem/qwheelarea.h b/share/qtcreator/welcomescreen/components/styleitem/qwheelarea.h new file mode 100644 index 00000000000..f1d7016a8f8 --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/qwheelarea.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Components project on Qt Labs. +** +** 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 Technology Preview License Agreement accompanying this package. +** +** 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#ifndef QWHEELAREA_H +#define QWHEELAREA_H + + +#include +#include +#include +#include +#include +#include + +class QWheelArea : public QDeclarativeItem +{ + Q_OBJECT + Q_PROPERTY(qreal verticalDelta READ verticalDelta WRITE setVerticalDelta NOTIFY verticalWheelMoved) + Q_PROPERTY(qreal horizontalDelta READ horizontalDelta WRITE setHorizontalDelta NOTIFY horizontalWheelMoved) + Q_PROPERTY(qreal horizontalMinimumValue READ horizontalMinimumValue WRITE setHorizontalMinimumValue) + Q_PROPERTY(qreal horizontalMaximumValue READ horizontalMaximumValue WRITE setHorizontalMaximumValue) + Q_PROPERTY(qreal verticalMinimumValue READ verticalMinimumValue WRITE setVerticalMinimumValue) + Q_PROPERTY(qreal verticalMaximumValue READ verticalMaximumValue WRITE setVerticalMaximumValue) + Q_PROPERTY(qreal horizontalValue READ horizontalValue WRITE setHorizontalValue) + Q_PROPERTY(qreal verticalValue READ verticalValue WRITE setVerticalValue) + + +public: + QWheelArea(QDeclarativeItem *parent = 0); + + virtual ~QWheelArea(); + + virtual bool event (QEvent * e); + + void setHorizontalMinimumValue(qreal min); + qreal horizontalMinimumValue() const; + + void setHorizontalMaximumValue(qreal min); + qreal horizontalMaximumValue() const; + + void setVerticalMinimumValue(qreal min); + qreal verticalMinimumValue() const; + + void setVerticalMaximumValue(qreal min); + qreal verticalMaximumValue() const; + + void setHorizontalValue(qreal val); + qreal horizontalValue() const; + + void setVerticalValue(qreal val); + qreal verticalValue() const; + + void setVerticalDelta(qreal d); + qreal verticalDelta() const; + + void setHorizontalDelta(qreal d); + qreal horizontalDelta() const; + +Q_SIGNALS: + void verticalValueChanged(); + void horizontalValueChanged(); + void verticalWheelMoved(); + void horizontalWheelMoved(); + +private: + qreal _horizontalMinimumValue; + qreal _horizontalMaximumValue; + qreal _verticalMinimumValue; + qreal _verticalMaximumValue; + qreal _horizontalValue; + qreal _verticalValue; + qreal _verticalDelta; + qreal _horizontalDelta; + + Q_DISABLE_COPY(QWheelArea) +}; + +QML_DECLARE_TYPE(QWheelArea) + + +#endif // QWHEELAREA_H diff --git a/share/qtcreator/welcomescreen/components/styleitem/styleitem.pro b/share/qtcreator/welcomescreen/components/styleitem/styleitem.pro new file mode 100644 index 00000000000..25f403a90de --- /dev/null +++ b/share/qtcreator/welcomescreen/components/styleitem/styleitem.pro @@ -0,0 +1,78 @@ +TEMPLATE = lib +CONFIG += qt plugin +QT += declarative +QT += script + +TARGET = styleplugin +include(../../../../../qtcreator.pri) +DESTDIR = $$IDE_DATA_PATH/welcomescreen/components/plugin +OBJECTS_DIR = tmp +MOC_DIR = tmp + +HEADERS += qtmenu.h \ + qtmenubar.h \ + qtmenuitem.h \ + qrangemodel_p.h \ + qrangemodel.h \ + qstyleplugin.h \ + qdeclarativefolderlistmodel.h \ + qstyleitem.h \ + qwheelarea.h + +SOURCES += qtmenu.cpp \ + qtmenubar.cpp \ + qtmenuitem.cpp \ + qrangemodel.cpp \ + qstyleplugin.cpp \ + qdeclarativefolderlistmodel.cpp \ + qstyleitem.cpp \ + qwheelarea.cpp + + +OTHER_FILES += \ + ../gallery.qml \ + ../widgets/Tab.qml \ + ../widgets/TabBar.qml \ + ../widgets/TabFrame.qml \ + ../Button.qml \ + ../ButtonRow.qml \ + ../CheckBox.qml \ + ../ChoiceList.qml \ + ../components.pro \ + ../ContextMenu.qml \ + ../Dial.qml \ + ../Frame.qml \ + ../GroupBox.qml \ + ../Menu.qml \ + ../ProgressBar.qml \ + ../RadioButton.qml \ + ../ScrollArea.qml \ + ../ScrollBar.qml \ + ../Slider.qml \ + ../SpinBox.qml \ + ../Switch.qml \ + ../Tab.qml \ + ../TableView.qml \ + ../TabBar.qml \ + ../TabFrame.qml \ + ../TextArea.qml \ + ../TextField.qml \ + ../TextScrollArea.qml \ + ../ToolBar.qml \ + ../ToolButton.qml \ + ../custom/BasicButton.qml \ + ../custom/BusyIndicator.qml \ + ../custom/Button.qml \ + ../custom/ButtonColumn.qml \ + ../custom/ButtonGroup.js \ + ../custom/ButtonRow.qml \ + ../custom/CheckBox.qml \ + ../custom/ChoiceList.qml \ + ../custom/ProgressBar.qml \ + ../custom/Slider.qml \ + ../custom/SpinBox.qml \ + ../custom/TextField.qml \ + ../../examples/Browser.qml \ + ../../examples/Panel.qml \ + ../../examples/ModelView.qml \ + ../../examples/Gallery.qml diff --git a/share/qtcreator/welcomescreen/develop.qml b/share/qtcreator/welcomescreen/develop.qml new file mode 100644 index 00000000000..7473c789570 --- /dev/null +++ b/share/qtcreator/welcomescreen/develop.qml @@ -0,0 +1,28 @@ +import QtQuick 1.0 +import "widgets" +import "components" as Components + +Item { + id: root + + Components.ScrollArea { + id: scrollArea + anchors.fill: parent + Item { + height: Math.max(recentSessions.height, recentProjects.height) + width: root.width-40 + RecentSessions { + id: recentSessions + x: 10 + width: parent.width / 2 - 10 + } + RecentProjects { + id: recentProjects + x: parent.width / 2 + 10 + width: parent.width / 2 - 10 + } + } + } +} + + diff --git a/share/qtcreator/welcomescreen/examples_fallback.xml b/share/qtcreator/welcomescreen/examples_fallback.xml new file mode 100644 index 00000000000..3a0a8dc2b6a --- /dev/null +++ b/share/qtcreator/welcomescreen/examples_fallback.xml @@ -0,0 +1,858 @@ + + + + + + demo,declarative,samegame,qml,qt quick + + + + demo,declarative,flickr,qml,qt quick + + + + demo,affine + + + + demo,composition + + + + demo,gradients + + + + demo,pathstroke + + + + demo,textedit + + + + demo,chip + + + + demo,embeddeddialogs + + + + demo,interview + + + + demo,declarative,rssnews,qml,qt quick + + + + demo,declarative,twitter,qml,qt quick + + + + demo,browser + + + Phonon can be used in Qt applications to handle audio and video playback.]]> + demo,qmediaplayer,phonon + + + Graphics View Framework.]]> + demo,boxes,graphics view framework + + + the animation framework and the state machine framework to create a game.]]> + demo,sub-attaq,the animation framework,the state machine framework + + + QtMultimedia Module can be used in Qt applications to capture and then play back an audio stream.]]> + demo,spectrum,qtmultimedia module + + + + demo,declarative,minehunt + + + QPainterPath.]]> + demo,deform,qpainterpath + + + + demo,books + + + + demo,mainwindow + + + + demo,spreadsheet + + + + demo,sqlbrowser + + + Qt Designer's custom widget plugin facilities.]]> + demo,arthurplugin + + + + + + example,animatedtiles,animation + + + + example,appchooser,animation + + + + example,easing,animation + + + QGraphicsScene using a QStateMachine with a custom transition.]]> + example,moveblocks,animation,qgraphicsscene,qstatemachine + + + + example,states,animation + + + + example,stickman,animation + + + QtConcurrent Map example shows how to use the synchronous (blocking) QtConcurrent API to scale a collection of images.]]> + example,map,qtconcurrent,qtconcurrent,qtconcurrent + + + QtConcurrent Progress Dialog example shows how to use the QFutureWatcher class to monitor the progress of a long-running operation.]]> + example,progressdialog,qtconcurrent,qtconcurrent,qfuturewatcher + + + QtConcurrent Run Function example shows how to apply concurrency to a standard function, using QFuture instances to retrieve return values at a later time.]]> + example,runfunction,qtconcurrent,qtconcurrent,qfuture + + + QtConcurrent Word Count example demonstrates the use of the map-reduce algorithm when applied to the problem of counting words in a collection of files.]]> + example,wordcount,qtconcurrent,qtconcurrent + + + Dynamic Object Creation support to dynamically create and destroy objects.]]> + example,dynamicscene,declarative,toys,qml,qt quick,dynamic object creation + + + + example,tic-tac-toe,declarative,toys,qml,qt quick + + + Image elements with Rotation transforms and SpringAnimation behaviors.]]> + example,clocks,declarative,toys,qml,qt quick,image,rotation,springanimation + + + ListModel, Repeater and TextEdit together with rotation and scaling transforms, animation and mouse interaction.]]> + example,corkboards,declarative,toys,qml,qt quick,listmodel,repeater,textedit + + + SpringAnimation, SequentialAnimation and PropertyAction to create a game of TV tennis.]]> + example,tvtennis,declarative,toys,qml,qt quick,springanimation,sequentialanimation,propertyaction + + + Qt Designer form at run-time, using the QUiLoader class.]]> + example,calculatorbuilder,designer,quiloader + + + Qt Designer in an application by using the user interface information from a QWidget subclass. We use uic's auto-connection feature to automatically connect signals from widgets on the form to slots in our code.]]> + example,calculatorform,designer,qwidget,uic's auto-connection + + + QDesignerContainerExtension class.]]> + example,containerextension,designer,qdesignercontainerextension + + + Qt Designer.]]> + example,customwidgetplugin,designer + + + Qt Designer, and how to to use the QDesignerTaskMenuExtension class to provide custom task menu entries associated with the plugin.]]> + example,taskmenuextension,designer,<i>qt designer</i>,qdesignertaskmenuextension + + + + example,worldtimeclockbuilder,designer + + + Qt Designer that uses signals and slots.]]> + example,worldtimeclockplugin,designer + + + + example,systray,desktop + + + QApplication and QDesktopWidget. It also shows how to use QTimer to provide a single-shot timer, and how to reimplement the QWidget::resizeEvent() event handler to make sure that an application resizes smoothly and without data loss.]]> + example,screenshot,desktop,qapplication,qdesktopwidget,qtimer,qwidget::resizeevent + + + + example,configdialog,dialogs + + + QDialog using the QAbstractButton::toggled() signal and the QWidget::setVisible() slot.]]> + example,extension,dialogs,qdialog,qabstractbutton::toggled,qwidget::setvisible + + + QProgressDialog to provide feedback on the progress of a slow operation. The example also shows how to use QFileDialog to facilitate browsing, how to use QTextStream's streaming operators to read a file, and how to use QTableWidget to provide standard table display facilities for applications. In addition, files can be opened using the QDesktopServices class.]]> + example,findfiles,dialogs,qprogressdialog,qfiledialog,qtextstream,qtablewidget,qdesktopservices + + + + example,standarddialogs,dialogs + + + QTabWidget class.]]> + example,tabdialog,dialogs,qtabwidget + + + QWizardPage and one instance of QWizard.]]> + example,trivialwizard,dialogs,qwizardpage,qwizard + + + + example,licensewizard,dialogs + + + QWizard.]]> + example,classwizard,dialogs,qwizard + + + + example,draggableicons,draganddrop + + + + example,draggabletext,draganddrop + + + + example,dropsite,draganddrop + + + + example,fridgemagnets,draganddrop + + + + example,puzzle,draganddrop + + + GraphicsView example shows how to implement edges between nodes in a graph, with basic interaction. You can click to drag a node around, and zoom in and out using the mouse wheel or the keyboard. Hitting the space bar will randomize the nodes. The example is also resolution independent; as you zoom in, the graphics remain crisp.]]> + example,elasticnodes,graphicsview,graphicsview + + + + example,collidingmice,graphicsview + + + + example,diagramscene,graphicsview + + + GraphicsView example shows how to implement Drag and Drop in a QGraphicsItem subclass, as well as how to animate items using Qt's Animation Framework.]]> + example,dragdroprobot,graphicsview,graphicsview,qgraphicsitem,animation framework + + + GraphicsView example is a port of the old QCanvas example from Qt 3.]]> + example,portedcanvas,graphicsview,graphicsview,qcanvas + + + GraphicsView example is a port of the Asteroids game, which was based on QCanvas.]]> + example,portedasteroids,graphicsview,graphicsview,qcanvas + + + State Machine Framework to create a simple but useful, dynamic, animated user interface.]]> + example,padnavigator,graphicsview,state machine framework + + + QSharedMemory class to implement inter-process communication using shared memory. To build the example, run make. To run the example, start two instances of the executable. The main() function creates an application and an instance of our example's Dialog class. The dialog is displayed and then control is passed to the application in the standard way.]]> + example,sharedmemory,ipc,qsharedmemory,application + + + QLocalSocket. It is intended to be run alongside the Local Fortune Server example.]]> + example,localfortuneclient,ipc,qlocalsocket,local fortune server + + + Local Fortune Client example]]> + example,localfortuneserver,ipc,local fortune client + + + + example,addressbook,itemviews + + + QSortFilterProxyModel to perform basic sorting and filtering.]]> + example,basicsortfiltermodel,itemviews,qsortfilterproxymodel + + + + example,chart,itemviews + + + QSortFilterProxyModel to perform advanced sorting and filtering.]]> + example,customsortfiltermodel,itemviews,qsortfilterproxymodel + + + QItemDelegate.]]> + example,coloreditorfactory,itemviews,qitemdelegate + + + + example,combowidgetmapper,itemviews + + + QDirModel(obsolete) class to provide supply file and directory information.]]> + example,dirview,itemviews,qdirmodel(obsolete) + + + + example,fetchmore,itemviews + + + QTableView.]]> + example,frozencolumn,itemviews,qtableview + + + + example,pixelator,itemviews + + + + example,puzzle,itemviews + + + + example,simpledommodel,itemviews + + + Model/View Programming overview.]]> + example,simpletreemodel,itemviews,model/view programming + + + + example,simplewidgetmapper,itemviews + + + + example,spinboxdelegate,itemviews + + + + example,stardelegate,itemviews + + + QBoxLayout, QGridLayout and QFormLayout.]]> + example,basiclayouts,layouts,qboxlayout,qgridlayout,qformlayout + + + + example,borderlayout,layouts + + + + example,dynamiclayouts,layouts + + + + example,flowlayout,layouts + + + Qt Linguist concept: "contexts". It also shows how to use two or more languages.]]> + example,arrowpad,linguist + + + + example,hellotr,linguist + + + + example,trollprint,linguist + + + QPlainTextEdit.]]> + example,application,mainwindows,qplaintextedit + + + + example,dockwidgets,mainwindows + + + QMdiArea class.]]> + example,mdi,mainwindows,qmdiarea + + + + example,sdi,mainwindows + + + + example,menus,mainwindows + + + + example,recentfiles,mainwindows + + + Image elements with Rotation transforms and SpringAnimation behaviors to produce an interactive speedometer-type dial.]]> + example,dialcontrol,declarative,ui-components,qml,qt quick,image,rotation,springanimation + + + Flipable element.]]> + example,flipable,declarative,ui-components,qml,qt quick,flipable + + + + example,progressbar,declarative,ui-components,qml,qt quick + + + Flickable element using the Flickable::visibleArea properties.]]> + example,scrollbar,declarative,ui-components,qml,qt quick,flickable,flickable::visiblearea + + + TextInput, FocusScope and BorderImage elements to display multiple text input fields.]]> + example,searchbox,declarative,ui-components,qml,qt quick,textinput,focusscope,borderimage + + + + example,slideswitch,declarative,ui-components,qml,qt quick + + + PathView element.]]> + example,spinner,declarative,ui-components,qml,qt quick,pathview + + + property aliases and default properties can be used to collect and assemble the child items declared within an Item.]]> + example,tabwidget,declarative,ui-components,qml,qt quick,property aliases,default properties,item + + + QTcpSocket's synchronous API in a non-GUI thread.]]> + example,blockingfortuneclient,network,qtcpsocket + + + + example,broadcastreceiver,network + + + + example,broadcastsender,network + + + QUdpSocket and QNetworkInterface to discover its peers.]]> + example,network-chat,network,qudpsocket,qnetworkinterface + + + QTcpSocket. It is intended to be run alongside the Fortune Server example or the Threaded Fortune Server example.]]> + example,fortuneclient,network,qtcpsocket,fortune server,threaded fortune server + + + Fortune Client example or the Blocking Fortune Client example.]]> + example,fortuneserver,network,fortune client,blocking fortune client + + + + example,qftp,network + + + + example,http,network + + + + example,loopback,network + + + + example,threadedfortuneserver,network + + + + example,torrent,network + + + QSslSocket to communicate over an encrypted (SSL) connection. It also demonstrates how to deal with authenticity problems, and how to display security and certificate information.]]> + example,securesocketclient,network,qsslsocket + + + QNetworkAccessManager class to obtain a list of suggestions from the Google search engine as the user types into a QLineEdit.]]> + example,googlesuggest,network,qnetworkaccessmanager,qlineedit + + + QPainter and QGLWidget can be used together to display accelerated 2D graphics on supported hardware.]]> + example,2dpainting,opengl,qpainter,qglwidget + + + QGLFramebufferObject class to render into an off-screen buffer and use the contents as a texture in a QGLWidget.]]> + example,framebufferobject,opengl,qglframebufferobject,qglwidget + + + QGLFramebufferObject class to render into an off-screen buffer and use the contents as a texture in a QGLWidget.]]> + example,framebufferobject2,opengl,qglframebufferobject,qglwidget + + + + example,grabber,opengl + + + + example,hellogl,opengl + + + QPainter can be used to overpaint a scene rendered using OpenGL in a QGLWidget.]]> + example,overpainting,opengl,qpainter,qglwidget + + + QGLPixelBuffer class to render into an off-screen buffer and use the contents as a dynamic texture in a QGLWidget.]]> + example,pbuffers,opengl,qglpixelbuffer,qglwidget + + + QGLPixelBuffer class to render into an off-screen buffer and use the contents as a dynamic texture in a QGLWidget.]]> + example,pbuffers2,opengl,qglpixelbuffer,qglwidget + + + QGLWidget.]]> + example,samplebuffers,opengl,qglwidget + + + + example,textures,opengl + + + QPainter class.]]> + example,basicdrawing,painting,qpainter + + + + example,concentriccircles,painting + + + + example,fontsampler,painting + + + QPainter, described in detail in Composition Modes.]]> + example,imagecomposition,painting,qpainter,composition modes + + + + example,painterpaths,painting + + + + example,svggenerator,painting + + + + example,svgviewer,painting + + + QPainter renders graphics primitives. In particular it shows how the order of transformations affect the result.]]> + example,transformations,painting,qpainter + + + + example,qmusicplayer,phonon + + + QAudioDeviceInfo class provided with Qt.]]> + example,audiodevices,multimedia,qaudiodeviceinfo + + + QAudioOutput class provided with Qt.]]> + example,audiooutput,multimedia,qaudiooutput + + + QAudioInput class provided with Qt.]]> + example,audioinput,multimedia,qaudioinput + + + + example,calendar,richtext + + + DetailsDialog object and displayed on a QTextEdit with a QTextCursor, using various formats. Each form generated is added to a QTabWidget for easy access.]]> + example,orderform,richtext,detailsdialog,qtextedit,qtextcursor,qtabwidget + + + QSyntaxHighlighter class.]]> + example,syntaxhighlighter,richtext,qsyntaxhighlighter + + + QTextDocument.]]> + example,textobject,richtext,qtextdocument + + + QtScript example, we show how to implement the functionality of a calculator widget.]]> + example,calculator,script,qtscript + + + + example,context2d,script + + + QObject-based type scriptable.]]> + example,defaultprototypes,script,qobject + + + + example,helloscript,script + + + + example,qstetrix,script + + + + example,cachedtable,sql + + + QSqlRelationalTableModel and QDataWidgetMapper classes.]]> + example,drilldown,sql,qsqlrelationaltablemodel,qdatawidgetmapper + + + + example,querymodel,sql + + + + example,relationaltablemodel,sql + + + + example,tablemodel,sql + + + + example,masterdetail,sql + + + + example,sqlwidgetmapper,sql + + + The State Machine Framework.]]> + example,eventtransitions,statemachine,the state machine framework + + + + example,rogue,statemachine + + + The State Machine Framework to implement the control flow of a traffic light.]]> + example,trafficlight,statemachine,the state machine framework + + + The State Machine Framework to implement a simple state machine that toggles the current state when a button is clicked.]]> + example,twowaybutton,statemachine,the state machine framework + + + + example,mandelbrot,threads + + + + example,codecs,tools + + + + example,completer,tools + + + TextEdit using QTextCursor.]]> + example,customcompleter,tools,textedit,qtextcursor + + + + example,i18n,tools + + + + example,inputpanel,tools + + + + example,plugandpaint,tools + + + + example,regexp,tools + + + + example,settingseditor,tools + + + + example,treemodelcompleter,tools + + + + example,undoframework,tools + + + + example,analogclock,widgets + + + QGridLayout to place child widgets in a grid.]]> + example,calculator,widgets,qgridlayout + + + QCalendarWidget.]]> + example,calendarwidget,widgets,qcalendarwidget + + + + example,charactermap,widgets + + + + example,codeeditor,widgets + + + QLCDNumber to display a number with LCD-like digits.]]> + example,digitalclock,widgets,qlcdnumber + + + + example,groupbox,widgets + + + QIcon can generate pixmaps reflecting an icon's state, mode and size. These pixmaps are generated from the set of pixmaps made available to the icon, and are used by Qt widgets to show an icon representing a particular action.]]> + example,icons,widgets,qicon + + + QLabel and QScrollArea to display an image. QLabel is typically used for displaying text, but it can also display an image. QScrollArea provides a scrolling view around another widget. If the child widget exceeds the size of the frame, QScrollArea automatically provides scroll bars.]]> + example,imageviewer,widgets,qlabel,qscrollarea,qlabel,qscrollarea,qscrollarea + + + QLineEdit can be used, and shows the effects of various properties and validators on the input and output supplied by the user.]]> + example,lineedits,widgets,qlineedit + + + QMovie and QLabel to display animations. Now that Qt comes with the Phonon multimedia framework, QMovie is mostly useful if one wants to play a simple animation without the added complexity of a multimedia framework to install and deploy.]]> + example,movie,widgets,qmovie,qlabel,phonon multimedia framework,qmovie + + + QWidget's event handlers to receive the events generated for the application's widgets.]]> + example,scribble,widgets,qwidget + + + + example,shapedclock,widgets + + + QSlider, QScrollBar and QDial. They all inherit most of their functionality from QAbstractSlider, and can in theory replace each other in an application since the differences only concern their look and feel. This example shows what they look like, how they work and how their behavior and appearance can be manipulated through their properties.]]> + example,sliders,widgets,qslider,qscrollbar,qdial,qabstractslider + + + QSpinBox widget to more complex editors like the QDateTimeEdit widget.]]> + example,spinboxes,widgets,qspinbox,qdatetimeedit + + + + example,styles,widgets + + + + example,stylesheet,widgets + + + + example,tablet,widgets + + + + example,tetrix,widgets + + + + example,tooltips,widgets + + + QBasicTimer and timerEvent(). In addition, the example demonstrates how to use QFontMetrics to determine the size of text on screen.]]> + example,wiggly,widgets,qbasictimer,timerevent(),qfontmetrics + + + + example,windowflags,widgets + + + QWebFrame with JavaScript to extract form data.]]> + example,formextractor,webkit,qwebframe + + + QtWebKit's QWebView to preview HTML data written in a QPlainTextEdit.]]> + example,previewer,webkit,qtwebkit,qwebview,qplaintextedit + + + QtWebKit to create a web browser with special effects and content manipulation.]]> + example,fancybrowser,webkit,qtwebkit + + + QtWebKit.]]> + example,googlechat,webkit,qtwebkit + + + + example,saxbookmarks,xml + + + + example,dombookmarks,xml + + + + example,rsslisting,xml + + + QXmlStreamReader class for reading, and QXmlStreamWriter class for writing the files.]]> + example,streambookmarks,xml,qxmlstreamreader,qxmlstreamwriter + + + QtXmlPatterns to query XML data loaded from a file.]]> + example,recipes,xmlpatterns,qtxmlpatterns + + + QtXmlPatterns to query QObject trees by modeling the non-XML data structure of a QObject tree to look like XML.]]> + example,qobjectxmlmodel,xmlpatterns,qtxmlpatterns,qobject,qobject + + + QtXmlPatterns for querying non-XML data that is modeled to look like XML.]]> + example,filetree,xmlpatterns,qtxmlpatterns + + + wap.trafikanten.no that is run by the Norwegian governmental agency for public transport in Oslo. The service provides real time information about the departure of busses, trams and undergrounds for every station in the city area.]]> + example,trafficinfo,xmlpatterns + + + QtXmlPatterns to validate XML with a W3C XML Schema.]]> + example,schema,xmlpatterns,qtxmlpatterns + + + + + + + + + + + + + + + tutorial,part1,tutorials,addressbook + + + diff --git a/share/qtcreator/welcomescreen/gettingstarted.qml b/share/qtcreator/welcomescreen/gettingstarted.qml new file mode 100644 index 00000000000..bb712c0c2a0 --- /dev/null +++ b/share/qtcreator/welcomescreen/gettingstarted.qml @@ -0,0 +1,4 @@ +import QtQuick 1.0 +import "widgets" + +ExampleBrowser {} diff --git a/share/qtcreator/welcomescreen/newssupport.qml b/share/qtcreator/welcomescreen/newssupport.qml new file mode 100644 index 00000000000..55e223655f2 --- /dev/null +++ b/share/qtcreator/welcomescreen/newssupport.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 + +Rectangle { + width: 200; height: 200 + color: "blue" +} + diff --git a/share/qtcreator/welcomescreen/qtcreator_tutorials.xml b/share/qtcreator/welcomescreen/qtcreator_tutorials.xml new file mode 100644 index 00000000000..d0e0a2d9e08 --- /dev/null +++ b/share/qtcreator/welcomescreen/qtcreator_tutorials.xml @@ -0,0 +1,25 @@ + + + + + + qt creator,quick tour,ui + + + + qt creator,build,compile + + + + qt,c++,text,qt designer,qt creator + + + + qt,c++,mobile,qt mobility,qt creator + + + + qt quick,qml,states,transitions,visual designer,qt creator + + + diff --git a/share/qtcreator/welcomescreen/welcomescreen.pro b/share/qtcreator/welcomescreen/welcomescreen.pro new file mode 100644 index 00000000000..0e9ebeb25c3 --- /dev/null +++ b/share/qtcreator/welcomescreen/welcomescreen.pro @@ -0,0 +1,22 @@ +TEMPLATE = subdirs +SUBDIRS = components/styleitem + +OTHER_FILES = develop.qml \ + gettingstarted.qml \ + newssupport.qml \ + welcomescreen.qml \ + widgets/Button.qml \ + widgets/Feedback.qml \ + widgets/RatingBar.qml \ + widgets/ExampleBrowser.qml \ + widgets/LineEdit.qml \ + widgets/ExampleDelegate.qml \ + widgets/LinksBar.qml \ + widgets/HeaderItemView.qml \ + widgets/RecentSessions.qml \ + widgets/RecentProjects.qml \ + widgets/FeaturedAndNewsListing.qml \ + widgets/NewsListing.qml \ + widgets/TabWidget.qml \ + examples_fallback.xml \ + qtcreator_tutorials.xml diff --git a/share/qtcreator/welcomescreen/welcomescreen.qml b/share/qtcreator/welcomescreen/welcomescreen.qml new file mode 100644 index 00000000000..67a5a3a980d --- /dev/null +++ b/share/qtcreator/welcomescreen/welcomescreen.qml @@ -0,0 +1,91 @@ +import Qt 4.7 +import "widgets" + +Image { + id: root + source: "qrc:welcome/images/welcomebg.png" + + // work around the fact that we can't use + // a property alias to welcomeMode.activePlugin + property int current: 0 + onCurrentChanged: welcomeMode.activePlugin = current + Component.onCompleted: current = welcomeMode.activePlugin + + BorderImage { + id: headerLine + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + // FIXME: 25 px and get rid of border + height: 24 + border { top: 1; bottom: 1} + source: "qrc:welcome/images/tab_inactive.png" + } + BorderImage { + id: inner_background + Image { + id: header; + source: "qrc:welcome/images/center_frame_header.png"; + anchors.verticalCenter: parent.verticalCenter; + anchors.left: parent.left; + anchors.topMargin: 2 + } + anchors.top: headerLine.bottom + source: "qrc:welcome/images/background_center_frame_v2.png" + width: parent.width + height: 60 + border.right: 2 + border.left: 2 + border.top: 2 + border.bottom: 10 + } + + LinksBar { + id: navigationAndDevLinks + property alias current: root.current + anchors.top: inner_background.bottom + anchors.left: parent.left + anchors.bottomMargin: 4 + anchors.topMargin: -2 + width: parent.width + model: tabs.model + tabBarWidth: width + } + + BorderImage { + id: news + opacity: 0.7 + source: "qrc:welcome/images/rc_combined.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + anchors.top: navigationAndDevLinks.bottom + anchors.bottom: feedback.top + anchors.left: parent.left + anchors.margins: 5 + width: 270 + FeaturedAndNewsListing { + anchors.fill: parent + anchors.margins: 4 + } + + } + + TabWidget { + id: tabs + property int current: root.current + model: pagesModel + anchors.top: navigationAndDevLinks.bottom + anchors.bottom: feedback.top + anchors.left: news.right + anchors.right: parent.right + anchors.leftMargin: 0 + anchors.margins: 4 + } + + Feedback { + id: feedback + anchors.bottom: parent.bottom + width: parent.width + } + +} diff --git a/share/qtcreator/welcomescreen/widgets/Button.qml b/share/qtcreator/welcomescreen/widgets/Button.qml new file mode 100644 index 00000000000..40bd8708b00 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/Button.qml @@ -0,0 +1,45 @@ +import Qt 4.7 + +BorderImage { + property string text + property string image + property int iconSize : innerImg.sourceSize.height + signal clicked; + id: root + source: "qrc:/welcome/images/btn_26.png" + height: innerImg.height + 16 + + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + + Image{ + id: innerImg + height: root.iconSize + width: root.iconSize + anchors.verticalCenter: label.verticalCenter + anchors.right: label.left + anchors.rightMargin: 4 + visible: root.image != "" + source: root.image + } + + Text { + id: label; + anchors.left: innerImg.right + anchors.right: parent.right + text: root.text + } + + MouseArea { id: mouseArea; anchors.fill: parent; hoverEnabled: true; onClicked: root.clicked() } + + states: [ + State { + id: pressedState; when: mouseArea.pressed; + PropertyChanges { target: root; source: "qrc:/welcome/images/btn_26_pressed.png" } + }, + State { + id: hoverState; when: mouseArea.containsMouse + PropertyChanges { target: root; source: "qrc:/welcome/images/btn_26_hover.png" } + } + ] +} diff --git a/share/qtcreator/welcomescreen/widgets/ExampleBrowser.qml b/share/qtcreator/welcomescreen/widgets/ExampleBrowser.qml new file mode 100644 index 00000000000..327af9daa7a --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/ExampleBrowser.qml @@ -0,0 +1,186 @@ +import QtQuick 1.0 +import "../components" as Components + +Item { + id: exampleBrowserRoot + Item { + id : lineEditRoot + width: parent.width + height: lineEdit.height + + Connections { + target: gettingStarted + onTagsUpdated: { + var tagList = gettingStarted.tagList() + for (var tag in tagList) { + tagsTestModel.append({ "text": tagList[tag], "value": tagList[tag] }); + } + } + } + + Components.TextField { + Behavior on width { NumberAnimation{} } + placeholderText: !checkBox.checked ? qsTr("Search in Tutorials") : qsTr("Search in Tutorials, Examples and Demos") + focus: true + id: lineEdit + width: lineEditRoot.width - checkBox.width - 20 - tagFilterButton.width + onTextChanged: examplesModel.filterRegExp = RegExp('.*'+text, "im") + } + + ListModel { + id: tagsTestModel + } + + Components.CheckBox { + id: checkBox + text: qsTr("Show Examples and Demos") + checked: false + anchors.left: lineEdit.right + anchors.verticalCenter: lineEdit.verticalCenter + height: lineEdit.height + onCheckedChanged: examplesModel.showTutorialsOnly = !checked; + } + + Components.Button { + id: tagFilterButton + property string tag + Behavior on width { NumberAnimation{} } + onTagChanged: { examplesModel.filterTag = tag; examplesModel.updateFilter() } + anchors.left: checkBox.right + anchors.verticalCenter: lineEdit.verticalCenter + visible: !examplesModel.showTutorialsOnly + text: tag === "" ? qsTr("Filter by Tag") : qsTr("Tag Filter: ") + tag + onClicked: tagChooser.visible = !tagChooser.visible + } + } + Components.ScrollArea { + id: scrollArea + anchors.topMargin: lineEditRoot.height + anchors.fill: parent + clip: true + frame: false + Column { + Repeater { + id: repeater + model: examplesModel + delegate: ExampleDelegate { width: scrollArea.width-20 } + } + } + } + + + Rectangle { + id: tagChooser + anchors.fill: parent + color: "darkgrey" + visible: false + opacity: 0.95 + radius: 6 + MouseArea { anchors.fill: parent; hoverEnabled: true } // disable mouse on background + Text { + id: descr; + anchors.margins: 6; + color: "white"; + text: qsTr("Please choose a tag to filter for:"); + anchors.top: parent.top; + anchors.left: parent.left + font.bold: true + } + + Item { + width: rect.width + height: rect.height + + anchors.margins: 6; + anchors.top: parent.top; + anchors.right: parent.right + + Rectangle { + color: "red" + id: rect + radius: 4 + opacity: 0.3 + width: closeText.width+4 + height: closeText.height+4 + x: closeText.x-2 + y: closeText.y-2 + } + Text { id: closeText; text: qsTr("Close"); color: "white"; anchors.centerIn: parent } + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: { + tagChooser.visible = false; + tagFilterButton.tag = ""; + } + } + } + + Flickable { + id: flickable + anchors.fill: parent + anchors.margins: 6 + anchors.topMargin: descr.height + anchors.margins*2 + contentHeight: flow.height + contentWidth: flow.width + flickableDirection: Flickable.VerticalFlick + clip: true + Flow { + width: tagChooser.width + id: flow + spacing: 6 + Repeater { + model: tagsTestModel + delegate: Item { + width: btnRect.width + height: btnRect.height + Rectangle { + id: btnRect + radius: 4 + opacity: 0 + width: closeText.width+4 + height: closeText.height+4 + x: closeText.x-2 + y: closeText.y-2 + } + Text { id: closeText; text: model.text; color: "white"; anchors.centerIn: parent } + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + } + + states: [ + State { + name: "selected" + when: mouseArea.pressed + }, + State { + name: "hovered" + when: mouseArea.containsMouse + PropertyChanges { + target: btnRect + color: "darkblue" + opacity: 0.3 + } + } + ] + transitions: [ + Transition { + from: "hovered" + to: "selected" + ParallelAnimation { + PropertyAction { target: tagFilterButton; property: "tag"; value: model.value } + PropertyAction { target: tagChooser; property: "visible"; value: false } + ColorAnimation { to: "#00000000"; duration: 0 } + } + } + ] + } + } + } + + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/ExampleDelegate.qml b/share/qtcreator/welcomescreen/widgets/ExampleDelegate.qml new file mode 100644 index 00000000000..f66a2e410d6 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/ExampleDelegate.qml @@ -0,0 +1,75 @@ +import QtQuick 1.0 + +Rectangle { + id: root + height: 110 + color: "#00ffffff" + radius: 6 + + Text { + id: title + anchors.left: parent.left + anchors.leftMargin: 10 + anchors.top: parent.top + anchors.topMargin: 10 + text: model.name + font.bold: true + font.pixelSize: 16; + + } + + RatingBar { id: rating; anchors.top: parent.top; anchors.topMargin: 10; anchors.right: parent.right; anchors.rightMargin: 10; rating: model.difficulty; visible: model.difficulty !== 0 } + + Image { + property bool hideImage : model.imageUrl === "" || status === Image.Error + id: image + anchors.top: title.bottom + anchors.left: parent.left + anchors.topMargin: 10 + anchors.leftMargin: 10 + width: hideImage ? 0 : 90 + height: hideImage ? 0 : 66 + asynchronous: true + fillMode: Image.PreserveAspectFit + source: model.imageUrl !== "" ? "image://helpimage/" + encodeURI(model.imageUrl) : "" + } + + Text { + id: description + clip: true + anchors.left: image.right + anchors.leftMargin: 10 + anchors.right: parent.right + anchors.rightMargin: 10 + anchors.top: rating.bottom + anchors.topMargin: 6 + wrapMode: Text.WordWrap + text: model.description + } + Text { id: labelText; anchors.top: description.bottom; anchors.topMargin: 10; anchors.left: image.right; text: "Tags: "; font.bold: true; } + Row { id: tagLine; anchors.top: description.bottom; anchors.topMargin: 10; anchors.left: labelText.right; Text { text: model.tags.join(", "); color: "grey" } } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: { + if (model.hasSourceCode) + gettingStarted.openProject(model.projectPath, model.filesToOpen, model.docUrl) + else + gettingStarted.openSplitHelp(model.docUrl); + } + onEntered: parent.state = "hover" + onExited: parent.state = "" + } + + states: [ State { name: "hover"; PropertyChanges { target: root; color: "#eeeeeeee" } } ] + + transitions: + Transition { + from: "" + to: "hover" + reversible: true + ColorAnimation { duration: 100; easing.type: Easing.OutQuad } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/FeaturedAndNewsListing.qml b/share/qtcreator/welcomescreen/widgets/FeaturedAndNewsListing.qml new file mode 100644 index 00000000000..c545b7af910 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/FeaturedAndNewsListing.qml @@ -0,0 +1,39 @@ +import QtQuick 1.0 +import "../components" as Components +Item { + InsetText { + id: text + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.margins: 10 + horizontalAlignment: Text.AlignHCenter + text: "Featured News" +// mainColor: "#44A51C" + mainColor: "#074C1C" + font.bold: true + font.pointSize: 16 + } + + ListModel { + id: tempNewsModel + ListElement { title: "Loading news sources..."; description: "Loading..." ; blogIcon: ""; blogName: ""; link: "" } + } + + NewsListing { + id: newsList + model: { + if (aggregatedFeedsModel.articleCount > 0) + return aggregatedFeedsModel + else + return tempNewsModel + } + anchors.bottom: parent.bottom + anchors.top: text.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: text.height + clip: true + + } + +} diff --git a/share/qtcreator/welcomescreen/widgets/Feedback.qml b/share/qtcreator/welcomescreen/widgets/Feedback.qml new file mode 100644 index 00000000000..71fc1e70dc1 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/Feedback.qml @@ -0,0 +1,56 @@ +import Qt 4.7 +import "../components" as Components + +BorderImage { + id: inner_background + height: openProjectButton.height + 10 + source: "qrc:welcome/images/background_center_frame_v2.png" + border.left: 2 + border.right: 2 + + Rectangle { color: "black"; width: parent.width; height: 1; anchors.top: parent.top; anchors.left: parent.left } + + Components.Button { + + id: openProjectButton + text: "Open Project" + iconSource: "image://desktoptheme/document-open" + onClicked: welcomeMode.openProject(); + height: 32 + anchors.left: parent.left + anchors.margins: 5 + anchors.verticalCenter: parent.verticalCenter + } + + Components.Button { + id: createProjectButton + text: "Create Project" + iconSource: "image://desktoptheme/document-new" + onClicked: welcomeMode.newProject(); + height: 32 + anchors.left: openProjectButton.right + anchors.margins: 5 + anchors.verticalCenter: parent.verticalCenter + } + + + Components.Button { + id: feedbackButton + text: "Feedback" + iconSource: "qrc:welcome/images/feedback_arrow.png" + height: 32 + anchors.verticalCenter: parent.verticalCenter + anchors.right: feedbackText.left + anchors.margins: 5 + onClicked: welcomeMode.sendFeedback() + } + + Text { + id: feedbackText + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.leftMargin: 10 + anchors.margins: 5 + text: "Help us make Qt Creator even better" + } +} diff --git a/share/qtcreator/welcomescreen/widgets/HeaderItemView.qml b/share/qtcreator/welcomescreen/widgets/HeaderItemView.qml new file mode 100644 index 00000000000..1ac0079b113 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/HeaderItemView.qml @@ -0,0 +1,34 @@ +import QtQuick 1.0 +Item { + id: root + height: childrenRect.height + property string header + property QtObject model + property Component delegate + + Text { + id: titleText + text: root.header + font.bold: true + font.pointSize: 14 + color: "#555555" + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.topMargin: 6 + } + + Column { + id: dataSection + spacing: 10 + anchors.topMargin: 10 + anchors.top: titleText.bottom + anchors.left: parent.left + anchors.right: parent.right + + Repeater { + model: root.model + delegate: root.delegate + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/InsetText.qml b/share/qtcreator/welcomescreen/widgets/InsetText.qml new file mode 100644 index 00000000000..0a271bff3da --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/InsetText.qml @@ -0,0 +1,15 @@ +import QtQuick 1.0 + +Text { + property color mainColor: "darkgrey" + Text { + x: 0; y: -1 + text: parent.text + color: parent.mainColor + font.bold: parent.font.bold + font.pointSize: parent.font.pointSize + font.italic: parent.font.italic + } + text: "Featured News" + color: "white" +} diff --git a/share/qtcreator/welcomescreen/widgets/LineEdit.qml b/share/qtcreator/welcomescreen/widgets/LineEdit.qml new file mode 100644 index 00000000000..9d3654d2766 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/LineEdit.qml @@ -0,0 +1,30 @@ +import QtQuick 1.0 + +FocusScope { + id: root + signal textChanged + property alias text : input.text + height:input.font.pixelSize*1.8 + BorderImage { + anchors.fill: parent + source: "img/lineedit.png" + border.left: 5; border.top: 5 + border.right: 5; border.bottom: 5 + TextInput { + id: input + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 4 + anchors.rightMargin: 4 + property string defaultText: "Click here to search the tutorials and howtos" + color: "grey" + text: defaultText + font.pointSize: 12 + clip: true + onActiveFocusChanged: activeFocus ? state = 'active' : state = '' + onTextChanged: if (text != defaultText) root.textChanged(); + states: [ State { name: "active"; PropertyChanges { target: input; color: "black"; text: "" } } ] + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/LinksBar.qml b/share/qtcreator/welcomescreen/widgets/LinksBar.qml new file mode 100644 index 00000000000..a4efb7495c5 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/LinksBar.qml @@ -0,0 +1,59 @@ +import QtQuick 1.0 + + +Row { + id: tabBar + height: 25 + + property alias model: tabs.model + property int tabBarWidth + + Repeater { + id: tabs + height: tabBar.height + model: parent.model + delegate: + Item { + width: tabBarWidth / tabs.count + height: tabBar.height + + Rectangle { + width: parent.width; height: 1 + anchors { bottom: parent.bottom; bottomMargin: 1 } + color: "#acb2c2" + } + BorderImage { + id: tabBackground + anchors.fill: parent + border { top: 1; bottom: 1} + source: "qrc:welcome/images/tab_inactive.png" + } + Text { + id: text + horizontalAlignment: Qt.AlignHCenter; verticalAlignment: Qt.AlignVCenter + anchors.fill: parent + text: model.modelData.title + elide: Text.ElideRight + color: "white" + } + MouseArea { + id: mouseArea + hoverEnabled: true + anchors.fill: parent + onClicked: tabBar.current = index + } + states: [ + State { + id: activeState; when: tabBar.current == index + PropertyChanges { target: tabBackground; source:"qrc:welcome/images/tab_active.png" } + PropertyChanges { target: text; color: "black" } + }, + State { + id: hoverState; when: mouseArea.containsMouse + PropertyChanges { target: tabBackground; source:"qrc:welcome/images/tab_hover.png" } + } + + ] + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/NewsListing.qml b/share/qtcreator/welcomescreen/widgets/NewsListing.qml new file mode 100644 index 00000000000..7ccc33decfa --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/NewsListing.qml @@ -0,0 +1,73 @@ +import Qt 4.7 + +Item { + id: root + + property int currentItem: 0 + property alias model: repeater.model + property alias itemCount: repeater.count + + Timer { + id: timer + repeat: true + interval: 30*1000 + onTriggered: repeater.incrementIndex() + } + + Repeater { + id: repeater + function incrementIndex() { + repeater.itemAt(currentItem).active = false + currentItem = (currentItem+1) % repeater.count + repeater.itemAt(currentItem).active = true + } + + function handleModelChanged() { + if (timer.running) + timer.stop(); + currentItem = 0 + //FIXME: this doesn't work + repeater.itemAt(currentItem).active = true + timer.start() + } + + anchors.fill: parent + onModelChanged: handleModelChanged() + delegate: Item { + property bool active: false + id: delegateItem + opacity: 0 + height: root.height + width: 270 + Column { + spacing: 10 + width: parent.width + id: column + Text { id: heading1; text: title; font.bold: true; wrapMode: Text.WrapAtWordBoundaryOrAnywhere; textFormat: Text.RichText; width: parent.width-icon.width-5 } + Row { + spacing: 5 + width: parent.width + Image { id: icon; source: blogIcon; asynchronous: true } + Text { id: heading2; text: blogName; font.italic: true; wrapMode: Text.WrapAtWordBoundaryOrAnywhere; textFormat: Text.RichText; width: parent.width-icon.width-5 } + } + Text { id: text; text: description; wrapMode: Text.WrapAtWordBoundaryOrAnywhere; textFormat: Text.RichText ; width: parent.width-10 } + Text { visible: link !== ""; id: readmore; text: qsTr("Click to read more..."); font.italic: true; wrapMode: Text.WrapAtWordBoundaryOrAnywhere; textFormat: Text.RichText } + } + MouseArea { anchors.fill: parent; onClicked: Qt.openUrlExternally(link); hoverEnabled: true; id: mouseArea } + + StateGroup { + id: activeState + states: [ State { name: "active"; when: delegateItem.active; PropertyChanges { target: delegateItem; opacity: 1 } } ] + transitions: [ + Transition { from: ""; to: "active"; reversible: true; NumberAnimation { target: delegateItem; property: "opacity"; duration: 200 } } + ] + } + + states: [ + State { name: "clicked"; when: mouseArea.pressed; PropertyChanges { target: text; color: "black" } }, + State { name: "hovered"; when: mouseArea.containsMouse; PropertyChanges { target: text; color: "#074C1C" } } + ] + + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/RatingBar.qml b/share/qtcreator/welcomescreen/widgets/RatingBar.qml new file mode 100644 index 00000000000..f7d5a671bbb --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/RatingBar.qml @@ -0,0 +1,9 @@ +import QtQuick 1.0 + +Row { + property int rating : 2 + property int totalRating: 3 + + Repeater { id: rep1; model: rating; Image { source: "img/face-star.png"; width: 22 } } + Repeater { id: rep2; model: totalRating-rating; Image { source: "img/draw-star.png"; width: 22 } } +} diff --git a/share/qtcreator/welcomescreen/widgets/RecentProjects.qml b/share/qtcreator/welcomescreen/widgets/RecentProjects.qml new file mode 100644 index 00000000000..8a9bab30fcc --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/RecentProjects.qml @@ -0,0 +1,48 @@ +import QtQuick 1.0 +import "../components" as Components + +HeaderItemView { + header: qsTr("Recently Edited Projects") + model: projectList + delegate: Item { + Components.QStyleItem { id: styleItem; cursor: "pointinghandcursor"; anchors.fill: parent } + height: nameText.font.pixelSize*2.5 + width: dataSection.width + Image{ + id: arrowImage; + source: "qrc:welcome/images/list_bullet_arrow.png"; + anchors.verticalCenter: parent.verticalCenter; + anchors.left: parent.left + } + + Text { + id: nameText + text: displayName + font.bold: true + width: parent.width + anchors.top: parent.top + anchors.left: arrowImage.right + anchors.leftMargin: 10 + } + + Text { + text: prettyFilePath + elide: Text.ElideMiddle + color: "grey" + width: parent.width + anchors.top: nameText.bottom + anchors.left: arrowImage.right + anchors.leftMargin: 10 + } + + Timer { id: timer; interval: 500; onTriggered: styleItem.showToolTip(filePath) } + + MouseArea { + anchors.fill: parent + onClicked: projectWelcomePage.requestProject(filePath) + hoverEnabled: true + onEntered:timer.start() + onExited: timer.stop() + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/RecentSessions.qml b/share/qtcreator/welcomescreen/widgets/RecentSessions.qml new file mode 100644 index 00000000000..6956df9df28 --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/RecentSessions.qml @@ -0,0 +1,48 @@ +import QtQuick 1.0 +import "../components" as Components + +HeaderItemView { + header: qsTr("Recently Used Sessions") + model: sessionList + + delegate: Item { + height: arrowImage.height + width: dataSection.width + + function fullSessionName() + { + var newSessionName = sessionName + if (model.currentSession) + newSessionName += qsTr(" (current session)"); + return newSessionName; + } + + Image{ + id: arrowImage; + source: "qrc:welcome/images/list_bullet_arrow.png"; + anchors.verticalCenter: parent.verticalCenter; + anchors.left: parent.left + } + + Text { + Components.QStyleItem { id: styleItem; cursor: "pointinghandcursor"; anchors.fill: parent } + id: fileNameText + text: parent.fullSessionName() + font.italic: model.defaultSession + elide: Text.ElideMiddle + anchors.left: arrowImage.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 10 + } + + Timer { id: timer; interval: 500; onTriggered: { styleItem.showToolTip(sessionName); print("triggered")} } + + MouseArea { + anchors.fill: parent + onClicked: projectWelcomePage.requestSession(sessionName) + hoverEnabled: true + onEntered:timer.start() + onExited: timer.stop() + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/TabWidget.qml b/share/qtcreator/welcomescreen/widgets/TabWidget.qml new file mode 100644 index 00000000000..cf90dfe980d --- /dev/null +++ b/share/qtcreator/welcomescreen/widgets/TabWidget.qml @@ -0,0 +1,30 @@ +import Qt 4.7 + +Item { + id: tabWidget + property alias model: contentRepeater.model + + Item { + id: stack + + anchors.margins: 0 + width: parent.width + height: parent.height + + Repeater { + id: contentRepeater + Loader { + id: pageLoader + clip: true + opacity: index == tabWidget.current + anchors.fill: parent + anchors.margins: 4 + source: model.modelData.pageLocation + + onStatusChanged: { + if (pageLoader.status == Loader.Error) console.debug(source + ' failed to load') + } + } + } + } +} diff --git a/share/qtcreator/welcomescreen/widgets/img/draw-star.png b/share/qtcreator/welcomescreen/widgets/img/draw-star.png new file mode 100644 index 00000000000..bde01565d87 Binary files /dev/null and b/share/qtcreator/welcomescreen/widgets/img/draw-star.png differ diff --git a/share/qtcreator/welcomescreen/widgets/img/face-star.png b/share/qtcreator/welcomescreen/widgets/img/face-star.png new file mode 100644 index 00000000000..7455f9dcc21 Binary files /dev/null and b/share/qtcreator/welcomescreen/widgets/img/face-star.png differ diff --git a/share/qtcreator/welcomescreen/widgets/img/lineedit.png b/share/qtcreator/welcomescreen/widgets/img/lineedit.png new file mode 100644 index 00000000000..1f15c4fcaa6 Binary files /dev/null and b/share/qtcreator/welcomescreen/widgets/img/lineedit.png differ diff --git a/share/share.pro b/share/share.pro index 69509a0098b..df8f06e11ec 100644 --- a/share/share.pro +++ b/share/share.pro @@ -1,3 +1,4 @@ TEMPLATE = subdirs SUBDIRS = qtcreator/static.pro \ - qtcreator/translations + qtcreator/translations \ + qtcreator/welcomescreen diff --git a/src/app/main.cpp b/src/app/main.cpp index 25c8474127c..dc3f22ed49d 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -193,12 +193,16 @@ int main(int argc, char **argv) setrlimit(RLIMIT_NOFILE, &rl); #endif +#ifdef Q_WS_X11 + // QML is unusable with the xlib backend + QApplication::setGraphicsSystem("raster"); +#endif + SharedTools::QtSingleApplication app((QLatin1String(appNameC)), argc, argv); const int threadCount = QThreadPool::globalInstance()->maxThreadCount(); QThreadPool::globalInstance()->setMaxThreadCount(qMax(4, 2 * threadCount)); - #ifdef ENABLE_QT_BREAKPAD QtSystemExceptionHandler systemExceptionHandler; #endif diff --git a/src/libs/utils/iwelcomepage.h b/src/libs/utils/iwelcomepage.h index adfd496799e..d2dd6129a1e 100644 --- a/src/libs/utils/iwelcomepage.h +++ b/src/libs/utils/iwelcomepage.h @@ -34,9 +34,14 @@ #define IWELCOMEPAGE_H +#include +#include + #include "utils_global.h" -#include +QT_BEGIN_NAMESPACE +class QDeclarativeEngine; +QT_END_NAMESPACE namespace Utils { @@ -46,13 +51,18 @@ class QTCREATOR_UTILS_EXPORT IWelcomePage : public QObject { Q_OBJECT + Q_PROPERTY(QString title READ title CONSTANT) + Q_PROPERTY(QString pageLocation READ pageLocation CONSTANT) + Q_PROPERTY(int priority READ priority CONSTANT) + public: IWelcomePage(); virtual ~IWelcomePage(); - virtual QWidget *page() = 0; + virtual QString pageLocation() const = 0; virtual QString title() const = 0; virtual int priority() const { return 0; } + virtual void facilitateQml(QDeclarativeEngine *) {} private: // not used atm diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index ac6ffa5cf21..1eb6b5a8c1d 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -48,7 +48,6 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/checkablemessagebox.cpp \ $$PWD/styledbar.cpp \ $$PWD/stylehelper.cpp \ - $$PWD/welcomemodetreewidget.cpp \ $$PWD/iwelcomepage.cpp \ $$PWD/fancymainwindow.cpp \ $$PWD/detailsbutton.cpp \ @@ -141,7 +140,6 @@ HEADERS += $$PWD/environment.h \ $$PWD/qtcassert.h \ $$PWD/styledbar.h \ $$PWD/stylehelper.h \ - $$PWD/welcomemodetreewidget.h \ $$PWD/iwelcomepage.h \ $$PWD/fancymainwindow.h \ $$PWD/detailsbutton.h \ diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index 0547ad61de1..c1258aa8eea 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -84,14 +84,15 @@ SOURCES += mainwindow.cpp \ outputpanemanager.cpp \ navigationsubwidget.cpp \ sidebarwidget.cpp \ - rssfetcher.cpp \ externaltool.cpp \ dialogs/externaltoolconfig.cpp \ toolsettings.cpp \ variablechooser.cpp \ mimetypemagicdialog.cpp \ mimetypesettings.cpp \ - dialogs/promptoverwritedialog.cpp + dialogs/promptoverwritedialog.cpp \ + multifeedrssmodel.cpp \ + networkaccessmanager.cpp HEADERS += mainwindow.h \ editmode.h \ @@ -177,14 +178,15 @@ HEADERS += mainwindow.h \ outputpanemanager.h \ navigationsubwidget.h \ sidebarwidget.h \ - rssfetcher.h \ externaltool.h \ dialogs/externaltoolconfig.h \ toolsettings.h \ variablechooser.h \ mimetypemagicdialog.h \ mimetypesettings.h \ - dialogs/promptoverwritedialog.h + dialogs/promptoverwritedialog.h \ + multifeedrssmodel.h \ + networkaccessmanager.h FORMS += dialogs/newdialog.ui \ actionmanager/commandmappings.ui \ diff --git a/src/plugins/coreplugin/fancytabwidget.cpp b/src/plugins/coreplugin/fancytabwidget.cpp index e7782b8ded0..234ad7ed88b 100644 --- a/src/plugins/coreplugin/fancytabwidget.cpp +++ b/src/plugins/coreplugin/fancytabwidget.cpp @@ -432,6 +432,10 @@ FancyTabWidget::FancyTabWidget(QWidget *parent) connect(m_tabBar, SIGNAL(currentChanged(int)), this, SLOT(showWidget(int))); } +void FancyTabWidget::setSelectionWidgetHidden(bool hidden) { + m_selectionWidget->setHidden(hidden); +} + void FancyTabWidget::insertTab(int index, QWidget *tab, const QIcon &icon, const QString &label) { m_modesStack->insertWidget(index, tab); diff --git a/src/plugins/coreplugin/fancytabwidget.h b/src/plugins/coreplugin/fancytabwidget.h index 164cf77fa77..cc15e8bdb77 100644 --- a/src/plugins/coreplugin/fancytabwidget.h +++ b/src/plugins/coreplugin/fancytabwidget.h @@ -168,6 +168,7 @@ signals: public slots: void setCurrentIndex(int index); + void setSelectionWidgetHidden(bool hidden); private slots: void showWidget(int index); diff --git a/src/plugins/coreplugin/modemanager.cpp b/src/plugins/coreplugin/modemanager.cpp index 724a938efc2..b89e5c5fe90 100644 --- a/src/plugins/coreplugin/modemanager.cpp +++ b/src/plugins/coreplugin/modemanager.cpp @@ -331,6 +331,11 @@ void ModeManager::setFocusToCurrentMode() } } +void ModeManager::setModeBarHidden(bool hidden) +{ + d->m_modeStack->setSelectionWidgetHidden(hidden); +} + ModeManager *ModeManager::instance() { return ModeManagerPrivate::m_instance; diff --git a/src/plugins/coreplugin/modemanager.h b/src/plugins/coreplugin/modemanager.h index 1bd332fe406..ef9d4a9aa22 100644 --- a/src/plugins/coreplugin/modemanager.h +++ b/src/plugins/coreplugin/modemanager.h @@ -70,6 +70,7 @@ public: void addWidget(QWidget *widget); void activateModeType(const QString &type); + void setModeBarHidden(bool hidden); signals: void currentModeAboutToChange(Core::IMode *mode); diff --git a/src/plugins/coreplugin/multifeedrssmodel.cpp b/src/plugins/coreplugin/multifeedrssmodel.cpp new file mode 100644 index 00000000000..66fe94822c7 --- /dev/null +++ b/src/plugins/coreplugin/multifeedrssmodel.cpp @@ -0,0 +1,190 @@ +#include "multifeedrssmodel.h" + +#include +#include +#include +#include + +#include +#include +#include "networkaccessmanager.h" + +#include + +namespace Core { + +namespace Internal { + +QString shortenHtml(QString html) +{ + html.replace(QLatin1String("")); + uint firstParaEndHtml = (uint) html.indexOf(QLatin1String("

"), html.indexOf(QLatin1String("

"))+1); + uint firstParaEndBr = (uint) html.indexOf(QLatin1String("request().url(); + requestUrl = source.toString(); + streamReader.setDevice(reply); + Internal::RssItemList list; + while (!streamReader.atEnd()) { + switch (streamReader.readNext()) { + case QXmlStreamReader::StartElement: + if (streamReader.name() == QLatin1String("item")) + list.append(parseItem()); + else if (streamReader.name() == QLatin1String("title")) + blogName = streamReader.readElementText(); + else if (streamReader.name() == QLatin1String("link")) { + if (!streamReader.namespaceUri().isEmpty()) + break; + QString favIconString(streamReader.readElementText()); + QUrl favIconUrl(favIconString); + favIconUrl.setPath(QLatin1String("favicon.ico")); + blogIcon = favIconUrl.toString(); + } + break; + default: + break; + } + } + return list; + } + +private: + QXmlStreamReader streamReader; + QString requestUrl; + QString blogIcon; + QString blogName; +}; + +} // namespace Internal + +MultiFeedRssModel::MultiFeedRssModel(QObject *parent) : + QAbstractListModel(parent), + m_networkAccessManager(new NetworkAccessManager), + m_articleCount(0) +{ + //m_namThread = new QThread; + //m_networkAccessManager->moveToThread(m_namThread); + connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), + SLOT(appendFeedData(QNetworkReply*)), Qt::QueuedConnection); + //m_namThread->start(); + //qDebug() << "MainThread" << QThread::currentThread(); + + QHash roleNames; + roleNames[TitleRole] = "title"; + roleNames[DescriptionRole] = "description"; + roleNames[PubDateRole] = "pubDate"; + roleNames[LinkRole] = "link"; + roleNames[BlogNameRole] = "blogName"; + roleNames[BlogIconRole] = "blogIcon"; + setRoleNames(roleNames); +} + +MultiFeedRssModel::~MultiFeedRssModel() +{ + //m_namThread->exit(); + //delete m_namThread; +} + +void MultiFeedRssModel::addFeed(const QString& feed) +{ + QMetaObject::invokeMethod(m_networkAccessManager, "getUrl", + Qt::QueuedConnection, Q_ARG(QUrl, feed)); +} + +bool sortForPubDate(const Internal::RssItem& item1, const Internal::RssItem& item2) +{ + return item1.pubDate > item2.pubDate; +} + +void MultiFeedRssModel::appendFeedData(QNetworkReply *reply) +{ + Internal::RssReader reader; + m_aggregatedFeed.append(reader.parse(reply)); + qSort(m_aggregatedFeed.begin(), m_aggregatedFeed.end(), sortForPubDate); + setArticleCount(m_aggregatedFeed.size()); + reset(); +} + +void MultiFeedRssModel::removeFeed(const QString &feed) +{ + QMutableListIterator it(m_aggregatedFeed); + while (it.hasNext()) { + Internal::RssItem item = it.next(); + if (item.source == feed) + it.remove(); + } + setArticleCount(m_aggregatedFeed.size()); +} + +int MultiFeedRssModel::rowCount(const QModelIndex &) const +{ + return m_aggregatedFeed.size(); +} + +QVariant MultiFeedRssModel::data(const QModelIndex &index, int role) const +{ + + Internal::RssItem item = m_aggregatedFeed.at(index.row()); + + switch (role) { + case Qt::DisplayRole: // fall through + case TitleRole: + return item.title; + case DescriptionRole: + return item.description; + case PubDateRole: + return item.pubDate; + case LinkRole: + return item.link; + case BlogNameRole: + return item.blogName; + case BlogIconRole: + return item.blogIcon; + } + + return QVariant(); +} + +} // namespace Utils diff --git a/src/plugins/coreplugin/multifeedrssmodel.h b/src/plugins/coreplugin/multifeedrssmodel.h new file mode 100644 index 00000000000..1d0d0363a85 --- /dev/null +++ b/src/plugins/coreplugin/multifeedrssmodel.h @@ -0,0 +1,79 @@ +#ifndef MULTIFEEDRSSMODEL_H +#define MULTIFEEDRSSMODEL_H + +#include "core_global.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QThread; +class QNetworkReply; +QT_END_NAMESPACE + +namespace Core { + +namespace Internal { + +struct RssItem { + QString source; + QString title; + QString link; + QString description; + QString blogName; + QString blogIcon; + QDateTime pubDate; + +}; +typedef QList RssItemList; + +} // namespace Internal + +class NetworkAccessManager; + +enum RssRoles { TitleRole = Qt::UserRole+1, DescriptionRole, LinkRole, + PubDateRole, BlogNameRole, BlogIconRole }; + +class CORE_EXPORT MultiFeedRssModel : public QAbstractListModel { + Q_OBJECT + Q_PROPERTY(int articleCount READ articleCount WRITE setArticleCount NOTIFY articleCountChanged) +public: + explicit MultiFeedRssModel(QObject *parent); + ~MultiFeedRssModel(); + void addFeed(const QString& feed); + void removeFeed(const QString& feed); + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + int articleCount() const { return m_articleCount; } + +public slots: + void setArticleCount(int arg) + { + if (m_articleCount != arg) { + m_articleCount = arg; + emit articleCountChanged(arg); + } + } + +signals: + void articleCountChanged(int arg); + +private slots: + void appendFeedData(QNetworkReply *reply); + +private: + QStringList m_sites; + Internal::RssItemList m_aggregatedFeed; + NetworkAccessManager *m_networkAccessManager; + QThread *m_namThread; + int m_articleCount; +}; + +} // namespace Utils + +#endif // MULTIFEEDRSSMODEL_H + + diff --git a/src/plugins/coreplugin/networkaccessmanager.cpp b/src/plugins/coreplugin/networkaccessmanager.cpp new file mode 100644 index 00000000000..8297e94e139 --- /dev/null +++ b/src/plugins/coreplugin/networkaccessmanager.cpp @@ -0,0 +1,113 @@ +#include "networkaccessmanager.h" + +#include +#include + +#ifdef Q_OS_UNIX +#include +#endif + +#include "coreconstants.h" + +/*! + \class Core::NetworkManager + + \brief Network Access Manager for use with Qt Creator. + + Common initialization, Qt Creator User Agent + */ + +namespace Core { + +static const QString getOsString() +{ + QString osString; +#if defined(Q_OS_WIN) + switch (QSysInfo::WindowsVersion) { + case (QSysInfo::WV_4_0): + osString += QLatin1String("WinNT4.0"); + break; + case (QSysInfo::WV_5_0): + osString += QLatin1String("Windows NT 5.0"); + break; + case (QSysInfo::WV_5_1): + osString += QLatin1String("Windows NT 5.1"); + break; + case (QSysInfo::WV_5_2): + osString += QLatin1String("Windows NT 5.2"); + break; + case (QSysInfo::WV_6_0): + osString += QLatin1String("Windows NT 6.0"); + break; + case (QSysInfo::WV_6_1): + osString += QLatin1String("Windows NT 6.1"); + break; + default: + osString += QLatin1String("Windows NT (Unknown)"); + break; + } +#elif defined (Q_OS_MAC) + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) + osString += QLatin1String("PPC "); + else + osString += QLatin1String("Intel "); + osString += QLatin1String("Mac OS X "); + switch (QSysInfo::MacintoshVersion) { + case (QSysInfo::MV_10_3): + osString += QLatin1String("10_3"); + break; + case (QSysInfo::MV_10_4): + osString += QLatin1String("10_4"); + break; + case (QSysInfo::MV_10_5): + osString += QLatin1String("10_5"); + break; + case (QSysInfo::MV_10_6): + osString += QLatin1String("10_6"); + break; + default: + osString += QLatin1String("(Unknown)"); + break; + } +#elif defined (Q_OS_UNIX) + struct utsname uts; + if (uname(&uts) == 0) { + osString += QLatin1String(uts.sysname); + osString += QLatin1Char(' '); + osString += QLatin1String(uts.release); + } else { + osString += QLatin1String("Unix (Unknown)"); + } +#else + ossttring = QLatin1String("Unknown OS"); +#endif + return osString; +} + + +NetworkAccessManager::NetworkAccessManager(QObject *parent) + : QNetworkAccessManager(parent) +{ + +} + +void NetworkAccessManager::getUrl(const QUrl &url) +{ + QNetworkRequest req; + req.setUrl(url); + get(req); +} + +QNetworkReply* NetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) +{ + QString agentStr = QString::fromLatin1("Qt-Creator/%1 (QNetworkAccessManager %2; %3; %4; %5 bit)") + .arg(Core::Constants::IDE_VERSION_LONG).arg(qVersion()) + .arg(getOsString()).arg(QLocale::system().name()) + .arg(QSysInfo::WordSize); + QNetworkRequest req(request); + req.setRawHeader("User-Agent", agentStr.toLatin1()); + return QNetworkAccessManager::createRequest(op, req, outgoingData); +} + + +} // namespace utils diff --git a/src/plugins/coreplugin/networkaccessmanager.h b/src/plugins/coreplugin/networkaccessmanager.h new file mode 100644 index 00000000000..cd4a8aa60e4 --- /dev/null +++ b/src/plugins/coreplugin/networkaccessmanager.h @@ -0,0 +1,22 @@ +#include "core_global.h" + +#include +#include + +namespace Core { + +class CORE_EXPORT NetworkAccessManager : public QNetworkAccessManager +{ + Q_OBJECT +public: + NetworkAccessManager(QObject *parent = 0); + +public slots: + void getUrl(const QUrl &url); + +protected: + virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData); +}; + + +} // namespace utils diff --git a/src/plugins/cpaster/protocol.cpp b/src/plugins/cpaster/protocol.cpp index 95142e88e24..17deae140d0 100644 --- a/src/plugins/cpaster/protocol.cpp +++ b/src/plugins/cpaster/protocol.cpp @@ -34,9 +34,9 @@ #include #include #include +#include #include -#include #include #include @@ -193,7 +193,7 @@ QNetworkReply *NetworkAccessManagerProxy::httpPost(const QString &link, const QB QNetworkAccessManager *NetworkAccessManagerProxy::networkAccessManager() { if (m_networkAccessManager.isNull()) - m_networkAccessManager.reset(new QNetworkAccessManager); + m_networkAccessManager.reset(new Core::NetworkAccessManager); return m_networkAccessManager.data(); } diff --git a/src/plugins/git/gitorious/gitorious.cpp b/src/plugins/git/gitorious/gitorious.cpp index 19324de868c..1a3cdee7571 100644 --- a/src/plugins/git/gitorious/gitorious.cpp +++ b/src/plugins/git/gitorious/gitorious.cpp @@ -37,9 +37,10 @@ #include #include -#include #include +#include + enum { debug = 0 }; enum Protocol { ListCategoriesProtocol, ListProjectsProtocol }; @@ -528,7 +529,7 @@ void Gitorious::slotReplyFinished() QNetworkReply *Gitorious::createRequest(const QUrl &url, int protocol, int hostIndex, int page) { if (!m_networkManager) - m_networkManager = new QNetworkAccessManager(this); + m_networkManager = new Core::NetworkAccessManager(this); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, SIGNAL(finished()), this, SLOT(slotReplyFinished())); reply->setProperty(protocolPropertyC, QVariant(protocol)); diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 611ac2af59f..5ae357652c4 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -256,6 +256,19 @@ bool HelpPlugin::initialize(const QStringList &arguments, QString *error) am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP); #endif + action = new QAction(tr("Technical Support"), this); + cmd = am->registerAction(action, Core::Id("Help.TechSupport"), globalcontext); + am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP); + connect(action, SIGNAL(triggered()), this, SLOT(slotOpenSupportPage())); + +#ifndef Q_WS_MAC + action = new QAction(this); + action->setSeparator(true); + cmd = am->registerAction(action, Core::Id("Help.Separator2"), globalcontext); + am->actionContainer(M_HELP)->addAction(cmd, Core::Constants::G_HELP_HELP); + connect(action, SIGNAL(triggered()), this, SLOT(activateContext())); +#endif + action = new QAction(this); am->registerAction(action, Core::Constants::PRINT, modecontext); connect(action, SIGNAL(triggered()), m_centralWidget, SLOT(print())); @@ -1121,7 +1134,7 @@ void HelpPlugin::handleHelpRequest(const QUrl &url) if (address.startsWith(HelpViewer::NsNokia) || address.startsWith(HelpViewer::NsTrolltech)) { // local help not installed, resort to external web help - QString urlPrefix = QLatin1String("http://doc.trolltech.com/"); + QString urlPrefix = QLatin1String("http://doc.qt.nokia.com/"); if (url.authority() == QLatin1String("com.nokia.qtcreator")) { urlPrefix.append(QString::fromLatin1("qtcreator")); } else { @@ -1192,6 +1205,11 @@ void HelpPlugin::slotOpenActionUrl(QAction *action) #endif } +void HelpPlugin::slotOpenSupportPage() +{ + switchToHelpMode(QUrl("qthelp://com.nokia.qtcreator/doc/technical-support.html")); +} + void HelpPlugin::openFindToolBar() { if (Find::FindPlugin::instance()) diff --git a/src/plugins/help/helpplugin.h b/src/plugins/help/helpplugin.h index 6b6d2b401ff..2700cd6ebfe 100644 --- a/src/plugins/help/helpplugin.h +++ b/src/plugins/help/helpplugin.h @@ -115,6 +115,7 @@ private slots: void slotAboutToShowBackMenu(); void slotAboutToShowNextMenu(); void slotOpenActionUrl(QAction *action); + void slotOpenSupportPage(); void openFindToolBar(); diff --git a/src/plugins/help/helpviewer_qwv.cpp b/src/plugins/help/helpviewer_qwv.cpp index 450f9a24220..d74937472cd 100644 --- a/src/plugins/help/helpviewer_qwv.cpp +++ b/src/plugins/help/helpviewer_qwv.cpp @@ -49,10 +49,11 @@ #include -#include #include #include +#include + using namespace Find; using namespace Help; using namespace Help::Internal; @@ -106,7 +107,7 @@ qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) // -- HelpNetworkAccessManager -class HelpNetworkAccessManager : public QNetworkAccessManager +class HelpNetworkAccessManager : public Core::NetworkAccessManager { public: HelpNetworkAccessManager(QObject *parent); @@ -117,7 +118,7 @@ protected: }; HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent) - : QNetworkAccessManager(parent) + : Core::NetworkAccessManager(parent) { } @@ -125,7 +126,7 @@ QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) { if (!HelpViewer::isLocalUrl(request.url())) - return QNetworkAccessManager::createRequest(op, request, outgoingData); + return Core::NetworkAccessManager::createRequest(op, request, outgoingData); QString url = request.url().toString(); const QHelpEngineCore &engine = LocalHelpManager::helpEngine(); diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index d3c7b067c94..8ef73ff1f27 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -84,6 +84,7 @@ plugin_coreplugin.subdir = coreplugin plugin_welcome.subdir = welcome plugin_welcome.depends = plugin_coreplugin +plugin_welcome.depends += plugin_projectexplorer plugin_find.subdir = find plugin_find.depends += plugin_coreplugin diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 0e39131bc74..315817e164b 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -76,7 +76,6 @@ #include "target.h" #include "projectexplorersettingspage.h" #include "projectwelcomepage.h" -#include "projectwelcomepagewidget.h" #include "corelistenercheckingforrunningbuild.h" #include "buildconfiguration.h" #include "miniprojecttargetselector.h" @@ -1305,7 +1304,7 @@ Project *ProjectExplorerPlugin::startupProject() const void ProjectExplorerPlugin::updateWelcomePage() { - ProjectWelcomePageWidget::WelcomePageData welcomePageData; + WelcomePageData welcomePageData; welcomePageData.sessionList = d->m_session->sessions(); welcomePageData.activeSession = d->m_session->activeSession(); welcomePageData.previousSession = d->m_session->lastSession(); @@ -2202,6 +2201,7 @@ void ProjectExplorerPlugin::addToRecentProjects(const QString &fileName, const Q d->m_recentProjects.prepend(qMakePair(prettyFileName, displayName)); QFileInfo fi(prettyFileName); d->m_lastOpenDirectory = fi.absolutePath(); + emit recentProjectsChanged(); } void ProjectExplorerPlugin::updateRecentProjectMenu() @@ -2236,6 +2236,7 @@ void ProjectExplorerPlugin::updateRecentProjectMenu() "Core", Core::Constants::TR_CLEAR_MENU)); connect(action, SIGNAL(triggered()), this, SLOT(clearRecentProjects())); } + emit recentProjectsChanged(); } void ProjectExplorerPlugin::clearRecentProjects() @@ -2756,4 +2757,9 @@ void ProjectExplorerPlugin::openOpenProjectDialog() Core::ICore::instance()->openFiles(files, Core::ICore::SwitchMode); } +QList > ProjectExplorerPlugin::recentProjects() +{ + return d->m_recentProjects; +} + Q_EXPORT_PLUGIN(ProjectExplorerPlugin) diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 5885db4413d..f383dce33ad 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -33,6 +33,8 @@ #ifndef PROJECTEXPLORER_H #define PROJECTEXPLORER_H +#include + #include "projectexplorer_export.h" #include @@ -116,6 +118,7 @@ public: void renameFile(Node *node, const QString &to); static QStringList projectFilePatterns(); bool coreAboutToClose(); + QList > recentProjects(); bool canRun(Project *pro, const QString &runMode); QString cannotRunReason(Project *project, const QString &runMode); @@ -138,6 +141,7 @@ signals: void currentProjectChanged(ProjectExplorer::Project *project); void currentNodeChanged(ProjectExplorer::Node *node, ProjectExplorer::Project *project); void aboutToExecuteProject(ProjectExplorer::Project *project, const QString &runMode); + void recentProjectsChanged(); void settingsChanged(); diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index 08f372ce152..2f1c57ce920 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -1,6 +1,9 @@ TEMPLATE = lib TARGET = ProjectExplorer -QT += network script +QT += xml \ + script \ + network \ + declarative include(../../qtcreatorplugin.pri) include(projectexplorer_dependencies.pri) include(../../libs/utils/utils.pri) @@ -78,7 +81,6 @@ HEADERS += projectexplorer.h \ debugginghelper.h \ projectexplorersettingspage.h \ projectwelcomepage.h \ - projectwelcomepagewidget.h \ baseprojectwizarddialog.h \ miniprojecttargetselector.h \ targetselector.h \ @@ -169,7 +171,6 @@ SOURCES += projectexplorer.cpp \ debugginghelper.cpp \ projectexplorersettingspage.cpp \ projectwelcomepage.cpp \ - projectwelcomepagewidget.cpp \ corelistenercheckingforrunningbuild.cpp \ baseprojectwizarddialog.cpp \ miniprojecttargetselector.cpp \ @@ -198,7 +199,6 @@ FORMS += processstep.ui \ projectwizardpage.ui \ removefiledialog.ui \ projectexplorersettingspage.ui \ - projectwelcomepagewidget.ui \ targetsettingswidget.ui \ doubletabwidget.ui \ publishing/publishingwizardselectiondialog.ui \ diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 20bb43f4c2c..e1d44c130ba 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -31,37 +31,132 @@ **************************************************************************/ #include "projectwelcomepage.h" -#include "projectwelcomepagewidget.h" + +#include + +#include +#include + +#include + +#include +#include namespace ProjectExplorer { namespace Internal { -ProjectWelcomePage::ProjectWelcomePage() - : m_page(0) +SessionModel::SessionModel(SessionManager *manager, QObject *parent) + : QAbstractListModel(parent), m_manager(manager) { + QHash roleNames; + roleNames[Qt::DisplayRole] = "sessionName"; + roleNames[DefaultSessionRole] = "defaultSession"; + roleNames[CurrentSessionRole] = "currentSession"; + setRoleNames(roleNames); + connect(manager, SIGNAL(sessionLoaded()), SLOT(resetSessions())); } -QWidget *ProjectWelcomePage::page() +int SessionModel::rowCount(const QModelIndex &) const { - if (!m_page) { - m_page = new ProjectWelcomePageWidget; + return qMin(m_manager->sessions().count(), 12); +} - // Forward signals - connect(m_page, SIGNAL(requestProject(QString)), this, SIGNAL(requestProject(QString))); - connect(m_page, SIGNAL(requestSession(QString)), this, SIGNAL(requestSession(QString))); - connect(m_page, SIGNAL(manageSessions()), this, SIGNAL(manageSessions())); +QVariant SessionModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::DisplayRole || role == DefaultSessionRole || role == CurrentSessionRole) { + QString sessionName = m_manager->sessions().at(index.row()); + if (role == Qt::DisplayRole) + return sessionName; + else if (role == DefaultSessionRole) + return m_manager->isDefaultSession(sessionName); + else if (role == CurrentSessionRole) + return sessionName == m_manager->currentSession(); + } else + return QVariant(); +} - m_page->updateWelcomePage(m_welcomePageData); + +void SessionModel::resetSessions() +{ + reset(); +} + + +ProjectModel::ProjectModel(ProjectExplorerPlugin *plugin, QObject *parent) + : QAbstractListModel(parent), m_plugin(plugin) +{ + QHash roleNames; + roleNames[Qt::DisplayRole] = "displayName"; + roleNames[FilePathRole] = "filePath"; + roleNames[PrettyFilePathRole] = "prettyFilePath"; + setRoleNames(roleNames); + connect(plugin, SIGNAL(recentProjectsChanged()), SLOT(resetProjects())); +} + +int ProjectModel::rowCount(const QModelIndex &) const +{ + return qMin(m_plugin->recentProjects().count(), 6); +} + +QVariant ProjectModel::data(const QModelIndex &index, int role) const +{ + QPair data = m_plugin->recentProjects().at(index.row()); + switch (role) { + case Qt::DisplayRole: + return data.second; + break; + case FilePathRole: + return data.first; + case PrettyFilePathRole: + return Utils::withTildeHomePath(data.first); + default: + return QVariant(); } - return m_page; + + return QVariant(); } -void ProjectWelcomePage::setWelcomePageData(const ProjectWelcomePageWidget::WelcomePageData &welcomePageData) +void ProjectModel::resetProjects() +{ + reset(); +} + +/////////////////// + +ProjectWelcomePage::ProjectWelcomePage() +{ +} + +void ProjectWelcomePage::facilitateQml(QDeclarativeEngine *engine) +{ + static const char feedGroupName[] = "Feeds"; + + QDeclarativeContext *ctx = engine->rootContext(); + ProjectExplorerPlugin *pePlugin = ProjectExplorer::ProjectExplorerPlugin::instance(); + ctx->setContextProperty("sessionList", new SessionModel(pePlugin->session(), this)); + ctx->setContextProperty("projectList", new ProjectModel(pePlugin, this)); + Core::MultiFeedRssModel *rssModel = new Core::MultiFeedRssModel(this); + QSettings *settings = Core::ICore::instance()->settings(); + if (settings->childGroups().contains(feedGroupName)) { + int size = settings->beginReadArray(feedGroupName); + for (int i = 0; i < size; ++i) + { + settings->setArrayIndex(i); + rssModel->addFeed(settings->value("url").toString()); + } + settings->endArray(); + } else { + rssModel->addFeed(QLatin1String("http://labs.trolltech.com/blogs/feed")); + rssModel->addFeed(QLatin1String("http://feeds.feedburner.com/TheQtBlog?format=xml")); + } + + ctx->setContextProperty("aggregatedFeedsModel", rssModel); + ctx->setContextProperty("projectWelcomePage", this); +} + +void ProjectWelcomePage::setWelcomePageData(const WelcomePageData &welcomePageData) { m_welcomePageData = welcomePageData; - - if (m_page) - m_page->updateWelcomePage(welcomePageData); } } // namespace Internal diff --git a/src/plugins/projectexplorer/projectwelcomepage.h b/src/plugins/projectexplorer/projectwelcomepage.h index 7c41f0e4392..5b3d2da2cb0 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.h +++ b/src/plugins/projectexplorer/projectwelcomepage.h @@ -33,24 +33,82 @@ #ifndef PROJECTWELCOMEPAGE_H #define PROJECTWELCOMEPAGE_H -#include +#include +#include -#include "projectwelcomepagewidget.h" +#include +#include + +QT_BEGIN_NAMESPACE +class QDeclarativeEngine; +QT_END_NAMESPACE namespace ProjectExplorer { + +class ProjectExplorerPlugin; +class SessionManager; + namespace Internal { +struct WelcomePageData { + bool operator==(const WelcomePageData &rhs) const; + bool operator!=(const WelcomePageData &rhs) const; + + QString previousSession; + QString activeSession; + QStringList sessionList; + QList > projectList; // pair of filename, displayname +}; + + +class SessionModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum { DefaultSessionRole = Qt::UserRole+1, CurrentSessionRole }; + + SessionModel(SessionManager* manager, QObject* parent = 0); + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + +public slots: + void resetSessions(); + +private: + SessionManager *m_manager; +}; + + +class ProjectModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum { FilePathRole = Qt::UserRole+1, PrettyFilePathRole }; + + ProjectModel(ProjectExplorerPlugin* plugin, QObject* parent = 0); + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + +public slots: + void resetProjects(); + +private: + ProjectExplorerPlugin *m_plugin; +}; + class ProjectWelcomePage : public Utils::IWelcomePage { Q_OBJECT public: ProjectWelcomePage(); - QWidget *page(); + void facilitateQml(QDeclarativeEngine *engine); + QString pageLocation() const { return Core::ICore::instance()->resourcePath() + QLatin1String("/welcomescreen/develop.qml"); } + QWidget *page() { return 0; } QString title() const { return tr("Develop"); } int priority() const { return 20; } - void setWelcomePageData(const ProjectWelcomePageWidget::WelcomePageData &welcomePageData); + void setWelcomePageData(const WelcomePageData &welcomePageData); signals: void requestProject(const QString &project); @@ -58,8 +116,7 @@ signals: void manageSessions(); private: - ProjectWelcomePageWidget *m_page; - ProjectWelcomePageWidget::WelcomePageData m_welcomePageData; + WelcomePageData m_welcomePageData; }; } // namespace Internal diff --git a/src/plugins/projectexplorer/projectwelcomepagewidget.h b/src/plugins/projectexplorer/projectwelcomepagewidget.h deleted file mode 100644 index 2b31892d5ed..00000000000 --- a/src/plugins/projectexplorer/projectwelcomepagewidget.h +++ /dev/null @@ -1,86 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#ifndef PROJECTWELCOMEPAGEWIDGET_H -#define PROJECTWELCOMEPAGEWIDGET_H - -#include - - -namespace ProjectExplorer { -namespace Internal { - - -namespace Ui { - class ProjectWelcomePageWidget; -} - -// Documentation inside. -class ProjectWelcomePageWidget : public QWidget -{ - Q_OBJECT -public: - ProjectWelcomePageWidget(QWidget *parent = 0); - ~ProjectWelcomePageWidget(); - - struct WelcomePageData { - bool operator==(const WelcomePageData &rhs) const; - bool operator!=(const WelcomePageData &rhs) const; - - QString previousSession; - QString activeSession; - QStringList sessionList; - QList > projectList; // pair of filename, displayname - }; - - void updateWelcomePage(const WelcomePageData &welcomePageData); - -signals: - void requestProject(const QString &project); - void requestSession(const QString &session); - void manageSessions(); - -private slots: - void slotSessionClicked(const QString &data); - void slotProjectClicked(const QString &data); - void slotCreateNewProject(); - -private: - void activateEditMode(); - Ui::ProjectWelcomePageWidget *ui; - WelcomePageData lastData; -}; - -} // namespace Internal -} // namespace ProjectExplorer - -#endif // PROJECTWELCOMEPAGEWIDGET_H diff --git a/src/plugins/projectexplorer/projectwelcomepagewidget.ui b/src/plugins/projectexplorer/projectwelcomepagewidget.ui deleted file mode 100644 index 0692434fac1..00000000000 --- a/src/plugins/projectexplorer/projectwelcomepagewidget.ui +++ /dev/null @@ -1,177 +0,0 @@ - - - ProjectExplorer::Internal::ProjectWelcomePageWidget - - - - 0 - 0 - 696 - 221 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 2 - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - - - 0 - 0 - - - - Recent Sessions - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - - - - - 0 - 0 - - - - - - - Recent Projects - - - - - - - - - - - - - - - 6 - - - - - - 160 - 36 - - - - Qt::TabFocus - - - Manage Sessions... - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 160 - 36 - - - - Open Project... - - - - - - - - 160 - 36 - - - - Qt::TabFocus - - - Create Project... - - - false - - - - - - - - - - - - - Utils::WelcomeModeTreeWidget - QWidget -

utils/welcomemodetreewidget.h
- 1 - - - Utils::WelcomeModeLabel - QLabel -
utils/welcomemodetreewidget.h
-
- - - - diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepage.cpp b/src/plugins/qt4projectmanager/gettingstartedwelcomepage.cpp deleted file mode 100644 index 86b510efd85..00000000000 --- a/src/plugins/qt4projectmanager/gettingstartedwelcomepage.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (info@qt.nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#include "gettingstartedwelcomepage.h" -#include "gettingstartedwelcomepagewidget.h" - -namespace Qt4ProjectManager { -namespace Internal { - -GettingStartedWelcomePage::GettingStartedWelcomePage() - : m_page(0) -{ -} - -QWidget *GettingStartedWelcomePage::page() -{ - if (!m_page) - m_page = new GettingStartedWelcomePageWidget; - return m_page; -} - -void GettingStartedWelcomePage::updateExamples(const QString &examplePath, - const QString &demosPath, - const QString &sourcePath) -{ - if (m_page) - m_page->updateExamples(examplePath, demosPath, sourcePath); -} - -} // namespace Internal -} // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.ui b/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.ui deleted file mode 100644 index 788470bf477..00000000000 --- a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.ui +++ /dev/null @@ -1,629 +0,0 @@ - - - Qt4ProjectManager::Internal::GettingStartedWelcomePageWidget - - - - 0 - 0 - 749 - 366 - - - - Form - - - - 0 - - - 0 - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 0 - 0 - - - - - 12 - - - - - Tutorials - - - - - - - - 260 - 0 - - - - - 260 - 16777215 - - - - - - - - - - - - 0 - 0 - - - - - 240 - 0 - - - - - 240 - 16777215 - - - - - 0 - - - 0 - - - 12 - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - Did You Know? - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 13 - - - - - - - - QToolButton{ - border-left:solid 0 px; - height:16px; - width:12px; -} - - - - - - - - :/welcome/images/arrow-right.png:/welcome/images/arrow-right.png - - - Qt::NoArrow - - - - - - - QToolButton{ - border-right:solid 0 px; - height:16px; - width:12px; -} - - - - - - - - :/welcome/images/arrow-left.png:/welcome/images/arrow-left.png - - - Qt::NoArrow - - - - - - - Qt::Vertical - - - - 20 - 13 - - - - - - - - - - - 0 - 0 - - - - QFrame::NoFrame - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - true - - - - - - - - - - - 0 - 0 - - - - - 0 - - - - - Examples - - - - - - - Explore Qt C++ examples: - - - - - - - false - - - - 0 - 0 - - - - - 0 - 30 - - - - Examples Not Installed... - - - - - - - Explore Qt Quick examples: - - - - - - - false - - - - 0 - 0 - - - - - 0 - 30 - - - - Examples Not Installed... - - - - - - - - - - 6 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 160 - 36 - - - - Open Project... - - - - - - - - 160 - 36 - - - - Qt::TabFocus - - - Create Project... - - - false - - - - - - - - - - - - - 200 - 0 - - - - - 200 - 16777215 - - - - QFrame#featureFrame { - -background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(245, 245, 245, 255), stop:1 rgba(225,225,225, 255)); - -border-left: 1px solid "#C9C9C9"; -border-bottom: 1px solid "#C9C9C9"; -} - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - Featured - - - - - - - - 128 - 0 - - - - - 16777215 - 128 - - - - - - - Qt::AlignCenter - - - - - - - - - - true - - - - - - - Qt::Vertical - - - - 20 - 6 - - - - - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Vertical - - - - 20 - 239 - - - - - - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 13 - - - - - - - - QToolButton{ - border-left:solid 0 px; - height:16px; - width:12px; -} - - - - - - - - :/welcome/images/arrow-right.png:/welcome/images/arrow-right.png - - - Qt::NoArrow - - - - - - - QToolButton{ - border-right:solid 0 px; - height:16px; - width:12px; -} - - - - - - - - :/welcome/images/arrow-left.png:/welcome/images/arrow-left.png - - - Qt::NoArrow - - - - - - - Qt::Vertical - - - - 20 - 13 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - Utils::WelcomeModeTreeWidget - QWidget -
utils/welcomemodetreewidget.h
- 1 -
- - Utils::WelcomeModeLabel - QLabel -
utils/welcomemodetreewidget.h
-
-
- - - - -
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro index 083fa2996eb..b686b3e7613 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanager.pro +++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro @@ -53,8 +53,6 @@ HEADERS += \ projectloadwizard.h \ qtuicodemodelsupport.h \ externaleditors.h \ - gettingstartedwelcomepagewidget.h \ - gettingstartedwelcomepage.h \ qt4buildconfiguration.h \ qt4target.h \ qmakeparser.h \ @@ -116,8 +114,6 @@ SOURCES += qt4projectmanagerplugin.cpp \ projectloadwizard.cpp \ qtuicodemodelsupport.cpp \ externaleditors.cpp \ - gettingstartedwelcomepagewidget.cpp \ - gettingstartedwelcomepage.cpp \ qt4buildconfiguration.cpp \ qt4target.cpp \ qmakeparser.cpp \ @@ -132,9 +128,9 @@ SOURCES += qt4projectmanagerplugin.cpp \ FORMS += makestep.ui \ qmakestep.ui \ qt4projectconfigwidget.ui \ - gettingstartedwelcomepagewidget.ui \ showbuildlog.ui \ librarydetailswidget.ui \ + showbuildlog.ui \ wizards/testwizardpage.ui \ wizards/targetsetuppage.ui \ wizards/qtquickappwizardsourcespage.ui \ diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp index 83ea47b64c9..7df4512c932 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp +++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp @@ -50,7 +50,6 @@ #include "qt4project.h" #include "profileeditor.h" #include "externaleditors.h" -#include "gettingstartedwelcomepage.h" #include "profilecompletionassist.h" #include "qt-s60/s60manager.h" @@ -99,8 +98,6 @@ Qt4ProjectManagerPlugin::~Qt4ProjectManagerPlugin() delete m_proFileEditorFactory; removeObject(m_qt4ProjectManager); delete m_qt4ProjectManager; - removeObject(m_welcomePage); - delete m_welcomePage; } bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage) @@ -116,12 +113,6 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString * m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance(); Core::ActionManager *am = core->actionManager(); - - m_welcomePage = new GettingStartedWelcomePage; - addObject(m_welcomePage); - connect(QtSupport::QtVersionManager::instance(), SIGNAL(updateExamples(QString,QString,QString)), - m_welcomePage, SLOT(updateExamples(QString,QString,QString))); - //create and register objects m_qt4ProjectManager = new Qt4Manager(this); addObject(m_qt4ProjectManager); diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.h b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.h index af634fc5373..c6c66d35442 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.h +++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.h @@ -53,7 +53,6 @@ class QtVersionManager; namespace Internal { class ProFileEditorFactory; -class GettingStartedWelcomePage; class Qt4ProjectManagerPlugin : public ExtensionSystem::IPlugin { @@ -96,7 +95,6 @@ private: QAction *m_cleanSubProjectContextMenu; QAction *m_addLibraryAction; QAction *m_addLibraryActionContextMenu; - GettingStartedWelcomePage *m_welcomePage; Core::Context m_projectContext; }; diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp new file mode 100644 index 00000000000..cedb825d03b --- /dev/null +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -0,0 +1,346 @@ +#include "exampleslistmodel.h" + +#include +#include +#include + +#include + +#include +#include + +#include + +using QtSupport::QtVersionManager; +using QtSupport::BaseQtVersion; + +namespace QtSupport { + +namespace Internal { + +ExamplesListModel::ExamplesListModel(QObject *parent) : + QAbstractListModel(parent) +{ + QHash roleNames; + roleNames[Name] = "name"; + roleNames[ProjectPath] = "projectPath"; + roleNames[ImageUrl] = "imageUrl"; + roleNames[Description] = "description"; + roleNames[DocUrl] = "docUrl"; + roleNames[FilesToOpen] = "filesToOpen"; + roleNames[Tags] = "tags"; + roleNames[Difficulty] = "difficulty"; + roleNames[Type] = "type"; + roleNames[HasSourceCode] = "hasSourceCode"; + setRoleNames(roleNames); + + connect(QtVersionManager::instance(), SIGNAL(updateExamples(QString,QString,QString)), + SLOT(readNewsItems(QString,QString,QString))); +} + +QList ExamplesListModel::parseExamples(QXmlStreamReader* reader, const QString& projectsOffset) +{ + QList examples; + ExampleItem item; + while (!reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: + if (reader->name() == QLatin1String("example")) { + item = ExampleItem(); + item.type = Example; + QXmlStreamAttributes attributes = reader->attributes(); + item.name = attributes.value(QLatin1String("name")).toString(); + item.projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item.hasSourceCode = !item.projectPath.isEmpty(); + item.projectPath.prepend('/'); + item.projectPath.prepend(projectsOffset); + item.imageUrl = attributes.value(QLatin1String("imagePath")).toString(); + item.docUrl = attributes.value(QLatin1String("docUrl")).toString(); + } else if (reader->name() == QLatin1String("fileToOpen")) { + item.filesToOpen.append(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("description")) { + item.description = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement); + } else if (reader->name() == QLatin1String("tags")) { + item.tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).split(","); + m_tags.append(item.tags); + } + break; + case QXmlStreamReader::EndElement: + if (reader->name() == QLatin1String("example")) + examples.append(item); + else if (reader->name() == QLatin1String("examples")) + return examples; + break; + default: // nothing + break; + } + } + return examples; +} + +QList ExamplesListModel::parseDemos(QXmlStreamReader* reader, const QString& projectsOffset) +{ + QList demos; + ExampleItem item; + while (!reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: + if (reader->name() == QLatin1String("demo")) { + item = ExampleItem(); + item.type = Demo; + QXmlStreamAttributes attributes = reader->attributes(); + item.name = attributes.value(QLatin1String("name")).toString(); + item.projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item.hasSourceCode = !item.projectPath.isEmpty(); + item.projectPath.prepend('/'); + item.projectPath.prepend(projectsOffset); + item.imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); + item.docUrl = attributes.value(QLatin1String("docUrl")).toString(); + } else if (reader->name() == QLatin1String("fileToOpen")) { + item.filesToOpen.append(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("description")) { + item.description = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement); + } else if (reader->name() == QLatin1String("tags")) { + item.tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).split(","); + } + break; + case QXmlStreamReader::EndElement: + if (reader->name() == QLatin1String("demo")) + demos.append(item); + else if (reader->name() == QLatin1String("demos")) + return demos; + break; + default: // nothing + break; + } + } + return demos; +} + +QList ExamplesListModel::parseTutorials(QXmlStreamReader* reader, const QString& projectsOffset) +{ + QList tutorials; + ExampleItem item; + while (!reader->atEnd()) { + switch (reader->readNext()) { + case QXmlStreamReader::StartElement: + if (reader->name() == QLatin1String("tutorial")) { + item = ExampleItem(); + item.type = Tutorial; + QXmlStreamAttributes attributes = reader->attributes(); + item.name = attributes.value(QLatin1String("name")).toString(); + item.projectPath = attributes.value(QLatin1String("projectPath")).toString(); + item.hasSourceCode = !item.projectPath.isEmpty(); + item.projectPath.prepend('/'); + item.projectPath.prepend(projectsOffset); + item.imageUrl = attributes.value(QLatin1String("imageUrl")).toString(); + item.docUrl = attributes.value(QLatin1String("docUrl")).toString(); + } else if (reader->name() == QLatin1String("fileToOpen")) { + item.filesToOpen.append(reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement)); + } else if (reader->name() == QLatin1String("description")) { + item.description = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement); + } else if (reader->name() == QLatin1String("tags")) { + item.tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).split(","); + } + break; + case QXmlStreamReader::EndElement: + if (reader->name() == QLatin1String("tutorial")) + tutorials.append(item); + else if (reader->name() == QLatin1String("tutorials")) + return tutorials; + break; + default: // nothing + break; + } + } + + return tutorials; +} + +void ExamplesListModel::readNewsItems(const QString &examplesPath, const QString &demosPath, const QString &sourcePath) +{ + clear(); + foreach (const QString exampleSource, exampleSources()) { + QFile exampleFile(exampleSource); + if (!exampleFile.open(QIODevice::ReadOnly)) { + qDebug() << Q_FUNC_INFO << "Could not open file" << exampleSource; + return; + } + + QFileInfo fi(exampleSource); + QString offsetPath = fi.path(); + QDir examplesDir(offsetPath); + QDir demosDir(offsetPath); + if (offsetPath.startsWith(Core::ICore::instance()->resourcePath())) { + // Try to get dir from first Qt Version + examplesDir = examplesPath; + demosDir = demosPath; + } + + QXmlStreamReader reader(&exampleFile); + while (!reader.atEnd()) + switch (reader.readNext()) { + case QXmlStreamReader::StartElement: + if (reader.name() == QLatin1String("examples")) + addItems(parseExamples(&reader, examplesDir.path())); + else if (reader.name() == QLatin1String("demos")) + addItems(parseDemos(&reader, demosDir.path())); + else if (reader.name() == QLatin1String("tutorials")) + addItems(parseTutorials(&reader, examplesDir.path())); + break; + default: // nothing + break; + } + + if (reader.hasError()) + qDebug() << "error parsing file" << exampleSource << "as XML document"; + } + + m_tags.sort(); + m_tags.erase(std::unique(m_tags.begin(), m_tags.end()), m_tags.end()); + emit tagsUpdated(); +} + +QStringList ExamplesListModel::exampleSources() const +{ + QFileInfoList sources; + const QStringList pattern(QLatin1String("*.xml")); + + // TODO: Read key from settings + + if (sources.isEmpty()) { + // Try to get dir from first Qt Version + QtVersionManager *versionManager = QtVersionManager::instance(); + foreach (BaseQtVersion *version, versionManager->validVersions()) { + + QDir examplesDir(version->examplesPath()); + if (examplesDir.exists()) + sources << examplesDir.entryInfoList(pattern); + + QDir demosDir(version->demosPath()); + if (demosDir.exists()) + sources << demosDir.entryInfoList(pattern); + + if (!sources.isEmpty()) + break; + } + } + + QString resourceDir = Core::ICore::instance()->resourcePath() + QLatin1String("/welcomescreen/"); + + // Try Creator-provided XML file only + if (sources.isEmpty()) { + qDebug() << Q_FUNC_INFO << "falling through to Creator-provided XML file"; + sources << QString(resourceDir + QLatin1String("/examples_fallback.xml")); + } + + sources << QString(resourceDir + QLatin1String("/qtcreator_tutorials.xml")); + + QStringList ret; + foreach (const QFileInfo& source, sources) + ret.append(source.filePath()); + + return ret; +} + +void ExamplesListModel::clear() +{ + if (exampleItems.count() > 0) { + beginRemoveRows(QModelIndex(), 0, exampleItems.size()-1); + exampleItems.clear(); + endRemoveRows(); + } + m_tags.clear(); +} + +void ExamplesListModel::addItems(const QList &newItems) +{ + beginInsertRows(QModelIndex(), exampleItems.size(), exampleItems.size() - 1 + newItems.size()); + exampleItems.append(newItems); + endInsertRows(); +} + +int ExamplesListModel::rowCount(const QModelIndex &) const +{ + return exampleItems.size(); +} + +QVariant ExamplesListModel::data(const QModelIndex &index, int role) const +{ + + if (!index.isValid() || index.row()+1 > exampleItems.count()) { + qDebug() << Q_FUNC_INFO << "invalid index requested"; + return QVariant(); + } + + ExampleItem item = exampleItems.at(index.row()); + switch (role) + { + case Qt::DisplayRole: // for search only + return QString(item.name + ' ' + item.tags.join(" ")); + case Name: + return item.name; + case ProjectPath: + return item.projectPath; + case Description: + return item.description; + case ImageUrl: + return item.imageUrl; + case DocUrl: + return item.docUrl; + case FilesToOpen: + return item.filesToOpen; + case Tags: + return item.tags; + case Difficulty: + return item.difficulty; + case HasSourceCode: + return item.hasSourceCode; + case Type: + return item.type; + default: + qDebug() << Q_FUNC_INFO << "role type not supported"; + return QVariant(); + } + +} + +ExamplesListModelFilter::ExamplesListModelFilter(QObject *parent) : + QSortFilterProxyModel(parent), m_showTutorialsOnly(true) +{ + connect(this, SIGNAL(showTutorialsOnlyChanged()), SLOT(updateFilter())); +} + +void ExamplesListModelFilter::updateFilter() +{ + invalidateFilter(); +} + +bool ExamplesListModelFilter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + if (m_showTutorialsOnly) { + int type = sourceModel()->index(sourceRow, 0, sourceParent).data(Type).toInt(); + if (type != Tutorial) + return false; + // tag search only active if we are not in tutorial only mode + } else if (!m_filterTag.isEmpty()) { + QStringList tags = sourceModel()->index(sourceRow, 0, sourceParent).data(Tags).toStringList(); + if (!tags.contains(m_filterTag, Qt::CaseInsensitive)) + return false; + } + + bool ok = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); + if (!ok) + return false; + + return true; +} + +void ExamplesListModelFilter::setShowTutorialsOnly(bool showTutorialsOnly) +{ + m_showTutorialsOnly = showTutorialsOnly; + emit showTutorialsOnlyChanged(); +} + +} // namespace Internal +} // namespace QtSupport diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h new file mode 100644 index 00000000000..97811764b3a --- /dev/null +++ b/src/plugins/qtsupport/exampleslistmodel.h @@ -0,0 +1,106 @@ +#ifndef EXAMPLESLISTMODEL_H +#define EXAMPLESLISTMODEL_H + +#include +#include +#include + + +QT_BEGIN_NAMESPACE +class QXmlStreamReader; +QT_END_NAMESPACE + +namespace QtSupport { +namespace Internal { + +enum ExampleRoles { Name=Qt::UserRole, ProjectPath, Description, ImageUrl, + DocUrl, FilesToOpen, Tags, Difficulty, HasSourceCode, Type }; + +enum InstructionalType { Example=0, Demo, Tutorial }; + +struct ExampleItem { + ExampleItem(): difficulty(0) {} + InstructionalType type; + QString name; + QString projectPath; + QString description; + QString imageUrl; + QString docUrl; + QStringList filesToOpen; + QStringList tags; + int difficulty; + bool hasSourceCode; +}; + +class ExamplesListModel : public QAbstractListModel { + Q_OBJECT +public: + explicit ExamplesListModel(QObject *parent); + void addItems(const QList &items); + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + QStringList tags() const { return m_tags; } + +public slots: + void readNewsItems(const QString &examplesPath, const QString &demosPath, const QString &sourcePath); + +signals: + void tagsUpdated(); + +private: + QList parseExamples(QXmlStreamReader* reader, const QString& projectsOffset); + QList parseDemos(QXmlStreamReader* reader, const QString& projectsOffset); + QList parseTutorials(QXmlStreamReader* reader, const QString& projectsOffset); + void clear(); + QStringList exampleSources() const; + QList exampleItems; + QStringList m_tags; +}; + +class ExamplesListModelFilter : public QSortFilterProxyModel { + Q_OBJECT +public: + Q_PROPERTY(bool showTutorialsOnly READ showTutorialsOnly WRITE setShowTutorialsOnly NOTIFY showTutorialsOnlyChanged) + Q_PROPERTY(QString filterTag READ filterTag WRITE setFilterTag NOTIFY filterTagChanged) + + explicit ExamplesListModelFilter(QObject *parent); + + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + bool showTutorialsOnly() {return m_showTutorialsOnly;} + + QString filterTag() const + { + return m_filterTag; + } + +public slots: + void setFilterTag(const QString& arg) + { + if (m_filterTag != arg) { + m_filterTag = arg; + emit filterTagChanged(arg); + } + } + void updateFilter(); + +signals: + void showTutorialsOnlyChanged(); + + void filterTagChanged(const QString& arg); + +private slots: + void setShowTutorialsOnly(bool showTutorialsOnly); + +private: + bool m_showTutorialsOnly; + QString m_filterTag; +}; + +} // namespace Internal +} // namespace QtSupport + +#endif // EXAMPLESLISTMODEL_H + + diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp new file mode 100644 index 00000000000..37f91240e0b --- /dev/null +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -0,0 +1,124 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ + +#include "gettingstartedwelcomepage.h" + +#include "exampleslistmodel.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace QtSupport { +namespace Internal { + +class HelpImageProvider : public QDeclarativeImageProvider +{ +public: + HelpImageProvider() + : QDeclarativeImageProvider(QDeclarativeImageProvider::Image) + { + } + + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) + { + QUrl url = QUrl::fromEncoded(id.toAscii()); + QByteArray imgData = Core::HelpManager::instance()->fileData(url); + QBuffer imgBuffer(&imgData); + imgBuffer.open(QIODevice::ReadOnly); + QImageReader reader(&imgBuffer); + QImage img = reader.read(); + if (size && requestedSize != *size) + img = img.scaled(requestedSize); + return img; + } +}; + +GettingStartedWelcomePage::GettingStartedWelcomePage() + : m_examplesModel(0), m_engine(0) +{ +} + +void GettingStartedWelcomePage::facilitateQml(QDeclarativeEngine *engine) +{ + m_engine = engine; + m_engine->addImageProvider("helpimage", new HelpImageProvider); + m_examplesModel = new ExamplesListModel(this); + connect (m_examplesModel, SIGNAL(tagsUpdated()), SLOT(updateTagsModel())); + ExamplesListModelFilter *proxy = new ExamplesListModelFilter(this); + proxy->setSourceModel(m_examplesModel); + proxy->setDynamicSortFilter(true); + proxy->sort(0); + proxy->setFilterCaseSensitivity(Qt::CaseInsensitive); + + QDeclarativeContext *rootContenxt = m_engine->rootContext(); + rootContenxt->setContextProperty("examplesModel", proxy); + rootContenxt->setContextProperty("gettingStarted", this); +} + +void GettingStartedWelcomePage::openSplitHelp(const QUrl &help) +{ + Core::ICore::instance()->helpManager()->handleHelpRequest(help.toString()+QLatin1String("?view=split")); +} + +QStringList GettingStartedWelcomePage::tagList() const +{ + return m_examplesModel->tags(); +} + +void GettingStartedWelcomePage::openProject(const QString &projectFile, const QStringList &additionalFilesToOpen, const QUrl &help) +{ + qDebug() << projectFile << additionalFilesToOpen << help; + // don't try to load help and files if loading the help request is being cancelled + if (ProjectExplorer::ProjectExplorerPlugin::instance()->openProject(projectFile)) { + Core::ICore::instance()->openFiles(additionalFilesToOpen); + Core::ICore::instance()->helpManager()->handleHelpRequest(help.toString()+QLatin1String("?view=split")); + } +} + +void GettingStartedWelcomePage::updateTagsModel() +{ + m_engine->rootContext()->setContextProperty("tagsList", m_examplesModel->tags()); + emit tagsUpdated(); +} + +} // namespace Internal +} // namespace QtSupport + diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepage.h b/src/plugins/qtsupport/gettingstartedwelcomepage.h similarity index 69% rename from src/plugins/qt4projectmanager/gettingstartedwelcomepage.h rename to src/plugins/qtsupport/gettingstartedwelcomepage.h index 93312a3581c..1c421d024ae 100644 --- a/src/plugins/qt4projectmanager/gettingstartedwelcomepage.h +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.h @@ -34,32 +34,50 @@ #define GETTINGSTARTEDWELCOMEPLUGIN_H #include +#include -namespace Qt4ProjectManager { +#include +#include + +QT_BEGIN_NAMESPACE +class QDeclarativeEngine; +QT_END_NAMESPACE + +namespace QtSupport { namespace Internal { +class ExamplesListModel; class GettingStartedWelcomePageWidget; + class GettingStartedWelcomePage : public Utils::IWelcomePage { Q_OBJECT public: GettingStartedWelcomePage(); - QWidget *page(); + QString pageLocation() const { return Core::ICore::instance()->resourcePath() + QLatin1String("/welcomescreen/gettingstarted.qml"); } QString title() const { return tr("Getting Started");} int priority() const { return 10; } + void facilitateQml(QDeclarativeEngine *); + Q_INVOKABLE QStringList tagList() const; + +signals: + void tagsUpdated(); public slots: - void updateExamples(const QString &examplePath, - const QString &demosPath, - const QString &sourcePath); + void openSplitHelp(const QUrl &help); + void openProject(const QString& projectFile, const QStringList& additionalFilesToOpen, const QUrl& help); + +public slots: + void updateTagsModel(); private: - GettingStartedWelcomePageWidget *m_page; + ExamplesListModel *m_examplesModel; + QDeclarativeEngine *m_engine; }; } // namespace Internal -} // namespace Qt4ProjectManager +} // namespace QtSupport #endif // GETTINGSTARTEDWELCOMEPLUGIN_H diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.cpp b/src/plugins/qtsupport/gettingstartedwelcomepagewidget.cpp similarity index 100% rename from src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.cpp rename to src/plugins/qtsupport/gettingstartedwelcomepagewidget.cpp diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.h b/src/plugins/qtsupport/gettingstartedwelcomepagewidget.h similarity index 100% rename from src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.h rename to src/plugins/qtsupport/gettingstartedwelcomepagewidget.h diff --git a/src/plugins/qtsupport/qtsupport.pro b/src/plugins/qtsupport/qtsupport.pro index eff34bdb7ec..25ffad2f145 100644 --- a/src/plugins/qtsupport/qtsupport.pro +++ b/src/plugins/qtsupport/qtsupport.pro @@ -1,7 +1,7 @@ TEMPLATE = lib TARGET = QtSupport DEFINES += QT_CREATOR QTSUPPORT_LIBRARY -QT += network +QT += network declarative include(../../qtcreatorplugin.pri) include(qtsupport_dependencies.pri) DEFINES += \ @@ -23,7 +23,9 @@ HEADERS += \ debugginghelperbuildtask.h \ qtsupportconstants.h \ profilereader.h \ - qtparser.h + qtparser.h \ + gettingstartedwelcomepage.h \ + exampleslistmodel.h SOURCES += \ qtsupportplugin.cpp \ @@ -37,7 +39,9 @@ SOURCES += \ qtoptionspage.cpp \ debugginghelperbuildtask.cpp \ profilereader.cpp \ - qtparser.cpp + qtparser.cpp \ + gettingstartedwelcomepage.cpp \ + exampleslistmodel.cpp FORMS += \ showbuildlog.ui \ diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 2c2fc4093d4..4b7a1f4100d 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -37,6 +37,8 @@ #include "profilereader.h" +#include "gettingstartedwelcomepage.h" + #include #include @@ -47,6 +49,8 @@ using namespace QtSupport::Internal; QtSupportPlugin::~QtSupportPlugin() { + removeObject(m_welcomePage); + delete m_welcomePage; } bool QtSupportPlugin::initialize(const QStringList &arguments, QString *errorMessage) @@ -60,12 +64,17 @@ bool QtSupportPlugin::initialize(const QStringList &arguments, QString *errorMes QtVersionManager *mgr = new QtVersionManager; addAutoReleasedObject(mgr); addAutoReleasedObject(new QtOptionsPage); + + m_welcomePage = new GettingStartedWelcomePage; + addObject(m_welcomePage); + return true; } void QtSupportPlugin::extensionsInitialized() { QtVersionManager::instance()->extensionsInitialized(); + } Q_EXPORT_PLUGIN(QtSupportPlugin) diff --git a/src/plugins/qtsupport/qtsupportplugin.h b/src/plugins/qtsupport/qtsupportplugin.h index 5423d9125e1..a5d68c31665 100644 --- a/src/plugins/qtsupport/qtsupportplugin.h +++ b/src/plugins/qtsupport/qtsupportplugin.h @@ -38,9 +38,10 @@ namespace QtSupport { - namespace Internal { +class GettingStartedWelcomePage; + class QtSupportPlugin : public ExtensionSystem::IPlugin { Q_OBJECT @@ -55,6 +56,8 @@ private slots: void testQtOutputParser_data(); void testQtOutputParser(); #endif +private: + GettingStartedWelcomePage *m_welcomePage; }; } // namespace Internal diff --git a/src/plugins/texteditor/generichighlighter/definitiondownloader.cpp b/src/plugins/texteditor/generichighlighter/definitiondownloader.cpp index ba878e9901b..c05c15f0935 100644 --- a/src/plugins/texteditor/generichighlighter/definitiondownloader.cpp +++ b/src/plugins/texteditor/generichighlighter/definitiondownloader.cpp @@ -38,10 +38,11 @@ #include #include #include -#include #include #include +#include + using namespace TextEditor; using namespace Internal; @@ -51,7 +52,7 @@ DefinitionDownloader::DefinitionDownloader(const QUrl &url, const QString &local void DefinitionDownloader::run() { - QNetworkAccessManager manager; + Core::NetworkAccessManager manager; int currentAttempt = 0; const int maxAttempts = 5; diff --git a/src/plugins/texteditor/generichighlighter/manager.h b/src/plugins/texteditor/generichighlighter/manager.h index 9de8fdafe02..d157aa623ae 100644 --- a/src/plugins/texteditor/generichighlighter/manager.h +++ b/src/plugins/texteditor/generichighlighter/manager.h @@ -44,7 +44,8 @@ #include #include #include -#include + +#include QT_BEGIN_NAMESPACE class QFileInfo; @@ -114,7 +115,7 @@ private: QSet m_isBuilding; QList m_downloaders; - QNetworkAccessManager m_networkManager; + Core::NetworkAccessManager m_networkManager; QFutureWatcher m_downloadWatcher; QFutureWatcher m_mimeTypeWatcher; diff --git a/src/plugins/welcome/communitywelcomepage.h b/src/plugins/welcome/communitywelcomepage.h index c94a2362a0b..7c5af61fd55 100644 --- a/src/plugins/welcome/communitywelcomepage.h +++ b/src/plugins/welcome/communitywelcomepage.h @@ -36,6 +36,7 @@ #include "welcome_global.h" #include +#include namespace Welcome { namespace Internal { @@ -48,6 +49,7 @@ class CommunityWelcomePage : public Utils::IWelcomePage public: CommunityWelcomePage(); + QString pageLocation() const { return Core::ICore::instance()->resourcePath() + QLatin1String("/welcomescreen/newssupport.qml"); } QWidget *page(); QString title() const { return tr("News && Support"); } int priority() const { return 30; } diff --git a/src/plugins/welcome/communitywelcomepagewidget.ui b/src/plugins/welcome/communitywelcomepagewidget.ui deleted file mode 100644 index 8bb145d18f2..00000000000 --- a/src/plugins/welcome/communitywelcomepagewidget.ui +++ /dev/null @@ -1,132 +0,0 @@ - - - Welcome::Internal::CommunityWelcomePageWidget - - - - 0 - 0 - 667 - 352 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 2 - - - - - #contentframe{ - border: none 0px; - border-bottom: 1px solid #c9c9c9; - margin: 0px; -} - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - News From the Qt Labs - - - - - - - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - Qt Support Sites - - - - - - - - - - Qt Links - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - Utils::WelcomeModeTreeWidget - QWidget -
utils/welcomemodetreewidget.h
- 1 -
- - Utils::WelcomeModeLabel - QLabel -
utils/welcomemodetreewidget.h
-
-
- - -
diff --git a/src/plugins/welcome/images/background_center_frame_v1.png b/src/plugins/welcome/images/background_center_frame_v1.png new file mode 100644 index 00000000000..e77780155e3 Binary files /dev/null and b/src/plugins/welcome/images/background_center_frame_v1.png differ diff --git a/src/plugins/welcome/images/background_center_frame_v2.png b/src/plugins/welcome/images/background_center_frame_v2.png new file mode 100644 index 00000000000..c2de67694dd Binary files /dev/null and b/src/plugins/welcome/images/background_center_frame_v2.png differ diff --git a/src/plugins/welcome/images/tab_active.png b/src/plugins/welcome/images/tab_active.png new file mode 100644 index 00000000000..7bed3d9d899 Binary files /dev/null and b/src/plugins/welcome/images/tab_active.png differ diff --git a/src/plugins/welcome/images/tab_hover.png b/src/plugins/welcome/images/tab_hover.png new file mode 100644 index 00000000000..d11cdd71fec Binary files /dev/null and b/src/plugins/welcome/images/tab_hover.png differ diff --git a/src/plugins/welcome/images/tab_inactive.png b/src/plugins/welcome/images/tab_inactive.png new file mode 100644 index 00000000000..04e804c0fc3 Binary files /dev/null and b/src/plugins/welcome/images/tab_inactive.png differ diff --git a/src/plugins/welcome/welcome.pro b/src/plugins/welcome/welcome.pro index 19a6d8745ea..63ca25a0f18 100644 --- a/src/plugins/welcome/welcome.pro +++ b/src/plugins/welcome/welcome.pro @@ -1,21 +1,14 @@ TEMPLATE = lib TARGET = Welcome -QT += network +QT += network declarative include(../../qtcreatorplugin.pri) include(welcome_dependencies.pri) HEADERS += welcomeplugin.h \ - communitywelcomepagewidget.h \ - communitywelcomepage.h \ welcome_global.h -SOURCES += welcomeplugin.cpp \ - communitywelcomepagewidget.cpp \ - communitywelcomepage.cpp - -FORMS += welcomemode.ui \ - communitywelcomepagewidget.ui +SOURCES += welcomeplugin.cpp RESOURCES += welcome.qrc diff --git a/src/plugins/welcome/welcome.qrc b/src/plugins/welcome/welcome.qrc index 0009b023a17..3c1c211dd73 100644 --- a/src/plugins/welcome/welcome.qrc +++ b/src/plugins/welcome/welcome.qrc @@ -20,5 +20,10 @@ images/arrow-left.png images/arrow-right.png images/welcomebg.png + images/tab_active.png + images/tab_inactive.png + images/background_center_frame_v1.png + images/background_center_frame_v2.png + images/tab_hover.png diff --git a/src/plugins/welcome/welcome_dependencies.pri b/src/plugins/welcome/welcome_dependencies.pri index 7f369f6326a..301ba69b4e4 100644 --- a/src/plugins/welcome/welcome_dependencies.pri +++ b/src/plugins/welcome/welcome_dependencies.pri @@ -1,2 +1,3 @@ +include(../../plugins/projectexplorer/projectexplorer.pri) include(../../plugins/coreplugin/coreplugin.pri) include(../../libs/utils/utils.pri) diff --git a/src/plugins/welcome/welcomemode.ui b/src/plugins/welcome/welcomemode.ui deleted file mode 100644 index c8f6dbf6840..00000000000 --- a/src/plugins/welcome/welcomemode.ui +++ /dev/null @@ -1,470 +0,0 @@ - - - Welcome::WelcomeMode - - - - 0 - 0 - 864 - 690 - - - - #Welcome--WelcomePage { -background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(247, 247, 247, 255), stop:1 rgba(215, 215, 215, 255)); -} - -QToolButton, QPushButton, QComboBox { - border-image: url(:/welcome/images/btn_26.png) 4; - border-width: 4; - padding: 0px 6px; - font-size: 12px; -} - -QToolButton, QPushButton, QComboBox, QLabel { - color: black; -} - - QComboBox QAbstractItemView { - background-color:white; -} - - QComboBox::down-arrow { - image: url(:/welcome/images/combobox_arrow.png); - } -QComboBox:drop-down -{ - subcontrol-origin: padding; - subcontrol-position: top right; - border-left-style: none; - border-top-right-radius: 1px; - border-bottom-right-radius: 1px; -} - -QToolButton:hover, QPushButton:hover, QComboBox:hover { - border-image: url(:/welcome/images/btn_26_hover.png) 4; -} - -QToolButton:disabled, QPushButton:disabled, QComboBox::disabled { - color:gray; -} - -QToolButton:pressed, QPushButton:pressed{ - border-image: url(:/welcome/images/btn_26_pressed.png) 4; -} - - QPushButton::menu-indicator{ - subcontrol-origin: margin; - subcontrol-position: center right; - right: 4px; - } - - QPushButton{ - outline: none; - margin: 2 - } - - - - - 0 - - - 0 - - - - - - 0 - - - 4 - - - 0 - - - 0 - - - 0 - - - - - - 700 - 550 - - - - - 750 - 550 - - - - #mainFrame { - border-image: url(:/welcome/images/background_center_frame.png); - border-width: 2; - padding:-1; - padding-bottom:20 ; -} - -#contentframe{ - border: none 0px; - border-bottom: 1px solid #c9c9c9; - background: #ffffff; - margin: 0px; -} - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 9 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 649 - 50 - - - - - 649 - 50 - - - - #headerFrame { - border-image: url(:/welcome/images/center_frame_header.png) 0; - border-width: 0; -} - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - 0 - 0 - - - - - 0 - 25 - - - - - 50 - false - - - - PointingHandCursor - - - false - - - QToolButton { - border-image:none; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0.0, y2: 1.0, - stop: 0 #838383, - stop: 0.4 #707070, - stop: 0.401 #636363, - stop: 1 #4a4a4a); - border: 0px solid black; - border-top: 1px solid #303030; - border-bottom: 1px solid #202020; - color: white; - height:20px; -} - -QToolButton:hover { - border-image:none; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0.0, y2: 1.0, - stop: 0 #909090, - stop: 0.4 #808080, - stop: 0.401 #707070, - stop: 1 #555555); -} - -QToolButton:checked, QToolButton:checked:pressed { - border-image:none; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0.0, y2: 1.0, - stop: 0 #ffffff, - stop: 0.4 #eeeeee, - stop: 0.401 #e2e2e2, - stop: 1 #dddddd); - color: black; - border-top: 1px solid #606060; - border-bottom: 1px solid #404040; -} - -QToolButton:pressed { - border-image:none; - background-color: qlineargradient(x1: 0, y1: 0, x2: 0.0, y2: 1.0, - stop: 0 #383838, - stop: 0.2 #404040, - stop: 0.201 #484848, - stop: 1 #505050); -} - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - - -1 - - - - - - - 8 - - - 1 - - - 13 - - - 10 - - - - - Qt::TabFocus - - - height:19px; - - - Feedback - - - - :/welcome/images/feedback_arrow.png:/welcome/images/feedback_arrow.png - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 6 - 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 - - - - - - - - Help us make Qt Creator even better - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 0 - 0 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index d028e355f5c..344eb5b11da 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -32,15 +32,17 @@ #include "welcomeplugin.h" -#include "communitywelcomepage.h" -#include "ui_welcomemode.h" - #include #include #include #include #include +#include +#include +#include + +#include #include #include @@ -48,82 +50,84 @@ #include #include -#include #include +#include #include #include #include #include +#include +#include +#include +#include + enum { debug = 0 }; using namespace ExtensionSystem; +static const char currentPageSettingsKeyC[] = "WelcomeTab"; + namespace Welcome { namespace Internal { -// Helper class introduced to cache the scaled background image -// so we avoid re-scaling for every repaint. -class ImageWidget : public QWidget +class NetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory { public: - explicit ImageWidget(QWidget *parent) - : QWidget(parent), - m_bg(":/welcome/images/welcomebg.png") - {} + NetworkAccessManagerFactory(): QDeclarativeNetworkAccessManagerFactory() {} + QNetworkAccessManager* create(QObject *parent) { return new Core::NetworkAccessManager(parent); } +}; - void paintEvent(QPaintEvent *e) - { - if (!m_bg.isNull()) { - QPainter painter(this); - if (m_stretch.size() != size()) - m_stretch = QPixmap::fromImage(m_bg.scaled(size(), - Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - if (!m_stretch.size().isEmpty()) - painter.drawPixmap(rect(), m_stretch); - } - QWidget::paintEvent(e); - } -private: - QImage m_bg; - QPixmap m_stretch; +struct WelcomeModePrivate +{ + }; class WelcomeMode : public Core::IMode { Q_OBJECT - + Q_PROPERTY(int activePlugin READ activePlugin WRITE setActivePlugin NOTIFY activePluginChanged) public: WelcomeMode(); ~WelcomeMode(); void activated(); void initPlugins(); + int activePlugin() const { return m_activePlugin; } + +public slots: + void sendFeedback(); + void newProject(); + void openProject(); + + void setActivePlugin(int pos) + { + if (m_activePlugin != pos) { + m_activePlugin = pos; + emit activePluginChanged(pos); + } + } + +signals: + void activePluginChanged(int pos); private slots: - void slotFeedback(); void welcomePluginAdded(QObject*); - void showClickedPage(); + void modeChanged(Core::IMode*); private: - void addPageToolButton(Utils::IWelcomePage *plugin, int position = -1); - - typedef QMap ToolButtonWidgetMap; - - QScrollArea m_scrollArea; - QWidget m_outerWidget; - ImageWidget *m_welcomePage; - ToolButtonWidgetMap buttonMap; - QHBoxLayout *buttonLayout; - Ui::WelcomeMode ui; + QScrollArea *m_scrollArea; + QDeclarativeView *m_welcomePage; + QHBoxLayout * buttonLayout; + QList m_pluginList; + int m_activePlugin; }; -static const char currentPageSettingsKeyC[] = "General/WelcomeTab"; - // --- WelcomeMode -WelcomeMode::WelcomeMode() +WelcomeMode::WelcomeMode() : + m_activePlugin(0) { setDisplayName(tr("Welcome")); setIcon(QIcon(QLatin1String(Core::Constants::ICON_QTLOGO_32))); @@ -132,119 +136,112 @@ WelcomeMode::WelcomeMode() setType(QLatin1String(Core::Constants::MODE_WELCOME_TYPE)); setContextHelpId(QLatin1String("Qt Creator Manual")); setContext(Core::Context(Core::Constants::C_WELCOME_MODE)); - setWidget(&m_scrollArea); - QVBoxLayout *l = new QVBoxLayout(&m_outerWidget); - l->setMargin(0); - l->setSpacing(0); - l->addWidget(new Utils::StyledBar(&m_outerWidget)); - m_welcomePage = new ImageWidget(&m_outerWidget); - ui.setupUi(m_welcomePage); - ui.helpUsLabel->setAttribute(Qt::WA_LayoutUsesWidgetRect); - ui.feedbackButton->setAttribute(Qt::WA_LayoutUsesWidgetRect); - l->addWidget(m_welcomePage); + m_welcomePage = new QDeclarativeView; + m_welcomePage->setResizeMode(QDeclarativeView::SizeRootObjectToView); - m_scrollArea.setFrameStyle(QFrame::NoFrame); - m_scrollArea.setWidget(&m_outerWidget); - m_scrollArea.setWidgetResizable(true); + m_scrollArea = new QScrollArea; + m_scrollArea->setFrameStyle(QFrame::NoFrame|QFrame::Plain); + m_scrollArea->setWidget(m_welcomePage); + m_scrollArea->setWidgetResizable(true); PluginManager *pluginManager = PluginManager::instance(); connect(pluginManager, SIGNAL(objectAdded(QObject*)), SLOT(welcomePluginAdded(QObject*))); - connect(ui.feedbackButton, SIGNAL(clicked()), SLOT(slotFeedback())); + Core::ModeManager *modeManager = Core::ICore::instance()->modeManager(); + connect(modeManager, SIGNAL(currentModeChanged(Core::IMode*)), SLOT(modeChanged(Core::IMode*))); + + setWidget(m_scrollArea); } WelcomeMode::~WelcomeMode() { QSettings *settings = Core::ICore::instance()->settings(); - settings->setValue(QLatin1String(currentPageSettingsKeyC), ui.stackedWidget->currentIndex()); + settings->setValue(QLatin1String(currentPageSettingsKeyC), activePlugin()); + delete m_scrollArea; } -bool sortFunction(Utils::IWelcomePage *a, Utils::IWelcomePage *b) +bool sortFunction(Utils::IWelcomePage * a, Utils::IWelcomePage *b) { return a->priority() < b->priority(); } -// Create a QToolButton for a page -void WelcomeMode::addPageToolButton(Utils::IWelcomePage *plugin, int position) -{ - QToolButton *btn = new QToolButton; - btn->setCheckable(true); - btn->setText(plugin->title()); - btn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - btn->setAutoExclusive(true); - connect(btn, SIGNAL(clicked()), SLOT(showClickedPage())); - buttonMap.insert(btn, plugin->page()); - if (position >= 0) - buttonLayout->insertWidget(position, btn); - else - buttonLayout->addWidget(btn); -} - void WelcomeMode::initPlugins() { - buttonLayout = new QHBoxLayout(ui.navFrame); - buttonLayout->setMargin(0); - buttonLayout->setSpacing(0); + QSettings *settings = Core::ICore::instance()->settings(); + setActivePlugin(settings->value(QLatin1String(currentPageSettingsKeyC)).toInt()); + + QDeclarativeContext *ctx = m_welcomePage->rootContext(); + ctx->setContextProperty("welcomeMode", this); + QList plugins = PluginManager::instance()->getObjects(); qSort(plugins.begin(), plugins.end(), &sortFunction); - foreach (Utils::IWelcomePage *plugin, plugins) { - ui.stackedWidget->addWidget(plugin->page()); - addPageToolButton(plugin); - if (debug) - qDebug() << "WelcomeMode::initPlugins" << plugin->title(); - } - QSettings *settings = Core::ICore::instance()->settings(); - const int tabId = settings->value(QLatin1String(currentPageSettingsKeyC), 0).toInt(); - const int pluginCount = ui.stackedWidget->count(); - if (tabId >= 0 && tabId < pluginCount) { - ui.stackedWidget->setCurrentIndex(tabId); - if (QToolButton *btn = buttonMap.key(ui.stackedWidget->currentWidget())) - btn->setChecked(true); + QDeclarativeEngine *engine = m_welcomePage->engine(); + engine->setNetworkAccessManagerFactory(new NetworkAccessManagerFactory); + foreach (Utils::IWelcomePage *plugin, plugins) { + plugin->facilitateQml(engine); + m_pluginList.append(plugin); } + + ctx->setContextProperty("pagesModel", QVariant::fromValue(m_pluginList)); + + // finally, load the root page + m_welcomePage->setSource( + QUrl::fromLocalFile(Core::ICore::instance()->resourcePath() + "/welcomescreen/welcomescreen.qml")); } void WelcomeMode::welcomePluginAdded(QObject *obj) { - Utils::IWelcomePage *plugin = qobject_cast(obj); - if (!plugin) - return; - - int insertPos = 0; - QList pages - = PluginManager::instance()->getObjects(); - foreach (Utils::IWelcomePage *p, pages) { - if (plugin->priority() >= p->priority()) - break; - insertPos++; + if (Utils::IWelcomePage *plugin = qobject_cast(obj)) { + int insertPos = 0; + foreach (Utils::IWelcomePage* p, PluginManager::instance()->getObjects()) { + if (plugin->priority() < p->priority()) + insertPos++; + else + break; + } + m_pluginList.insert(insertPos, plugin); + // update model through reset + QDeclarativeContext *ctx = m_welcomePage->rootContext(); + ctx->setContextProperty("pagesModel", QVariant::fromValue(m_pluginList)); } - ui.stackedWidget->insertWidget(insertPos, plugin->page()); - addPageToolButton(plugin, insertPos); - if (debug) - qDebug() << "welcomePluginAdded" << plugin->title() << "at" << insertPos - << " of " << buttonMap.size(); } -void WelcomeMode::showClickedPage() -{ - QToolButton *btn = qobject_cast(sender()); - const ToolButtonWidgetMap::const_iterator it = buttonMap.constFind(btn); - if (it != buttonMap.constEnd()) - ui.stackedWidget->setCurrentWidget(it.value()); -} - -void WelcomeMode::slotFeedback() +void WelcomeMode::sendFeedback() { QDesktopServices::openUrl(QUrl(QLatin1String( "http://qt.nokia.com/forms/feedback-forms/qt-creator-user-feedback/view"))); } +void WelcomeMode::newProject() +{ + Core::ICore::instance()->showNewItemDialog(tr("New Project"), + Core::IWizard::wizardsOfKind(Core::IWizard::ProjectWizard)); +} + +void WelcomeMode::openProject() +{ + ProjectExplorer::ProjectExplorerPlugin::instance()->openOpenProjectDialog(); +} + +void WelcomeMode::modeChanged(Core::IMode *mode) +{ + Q_UNUSED(mode) + +// Eike doesn't like this, but I do... + +// ProjectExplorer::ProjectExplorerPlugin *projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance(); +// Core::ModeManager *modeManager = Core::ICore::instance()->modeManager(); +// Core::EditorManager *editorManager = Core::ICore::instance()->editorManager(); +// if (mode->id() == id() && (!projectExplorer->currentProject() && editorManager->openedEditors().isEmpty())) +// modeManager->setModeBarHidden(true); +// else +// modeManager->setModeBarHidden(false); +} // - - WelcomePlugin::WelcomePlugin() : m_welcomeMode(0) { @@ -258,8 +255,6 @@ WelcomePlugin::WelcomePlugin() */ bool WelcomePlugin::initialize(const QStringList & /* arguments */, QString * /* error_message */) { - addAutoReleasedObject(new Internal::CommunityWelcomePage); - m_welcomeMode = new WelcomeMode; addAutoReleasedObject(m_welcomeMode); @@ -283,8 +278,8 @@ void WelcomePlugin::extensionsInitialized() Core::ModeManager::instance()->activateMode(m_welcomeMode->id()); } -} // namespace Welcome } // namespace Internal +} // namespace Welcome Q_EXPORT_PLUGIN(Welcome::Internal::WelcomePlugin) diff --git a/src/tools/examplesscanner/examplesscanner.pro b/src/tools/examplesscanner/examplesscanner.pro new file mode 100644 index 00000000000..531a4aabfbf --- /dev/null +++ b/src/tools/examplesscanner/examplesscanner.pro @@ -0,0 +1,9 @@ +QT += declarative xml network +CONFIG += help + +SOURCES += \ + main.cpp \ + helpextractor.cpp + +HEADERS += \ + helpextractor.h diff --git a/src/tools/examplesscanner/helpextractor.cpp b/src/tools/examplesscanner/helpextractor.cpp new file mode 100644 index 00000000000..7fad8551976 --- /dev/null +++ b/src/tools/examplesscanner/helpextractor.cpp @@ -0,0 +1,372 @@ +#include "helpextractor.h" + +#include +#include + +HelpExtractor::HelpExtractor() +{ + initHelpEngine(); +} + +void HelpExtractor::initHelpEngine() +{ + helpRootUrl = QString("qthelp://com.trolltech.qt/qdoc/"); + // .arg(QT_VERSION >> 16).arg((QT_VERSION >> 8) & 0xFF) + // .arg(QT_VERSION & 0xFF); + + // Store help collection file in cache dir of assistant + QString cacheDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation) + + QLatin1String("/Trolltech/Assistant/"); + QString helpDataFile = QString(QLatin1String("qtdemo_%1.qhc")).arg(QLatin1String(QT_VERSION_STR)); + + QDir dir; + if (!dir.exists(cacheDir)) + dir.mkpath(cacheDir); + + // Create help engine (and new + // helpDataFile if it does not exist): + helpEngine = new QHelpEngineCore(cacheDir + helpDataFile); + helpEngine->setupData(); + + QString qtDocRoot = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/qch"); + qtDocRoot = QDir(qtDocRoot).absolutePath(); + + QStringList qchFiles; + qchFiles << QLatin1String("/qt.qch") + << QLatin1String("/designer.qch") + << QLatin1String("/linguist.qch"); + + QString oldDir = helpEngine->customValue(QLatin1String("docDir"), QString()).toString(); + if (oldDir != qtDocRoot) { + foreach (const QString &qchFile, qchFiles) + helpEngine->unregisterDocumentation(QHelpEngineCore::namespaceName(qtDocRoot + qchFile)); + } + + // If the data that the engine will work + // on is not yet registered, do it now: + foreach (const QString &qchFile, qchFiles) + helpEngine->registerDocumentation(qtDocRoot + qchFile); + + helpEngine->setCustomValue(QLatin1String("docDir"), qtDocRoot); +} + +void HelpExtractor::readXmlDocument() +{ + contentsDoc = new QDomDocument(); + QString errorStr; + int errorLine; + int errorColumn; + + QString qtDemoPath = QLibraryInfo::location(QLibraryInfo::DemosPath) + QLatin1String("/qtdemo"); + QFile file(qtDemoPath + "/xml/examples.xml"); + bool statusOK = contentsDoc->setContent(&file, true, &errorStr, &errorLine, &errorColumn); + if (!statusOK) { + qDebug() << QString::fromLatin1("DOM Parser: Could not read or find the contents document. Error at line %1, column %2:\n%3") + .arg(errorLine).arg(errorColumn).arg(errorStr); + exit(-1); + } + //convertToSql(contentsDoc->documentElement()); + convertToAggregatableXml(contentsDoc->documentElement()); +} + + +void HelpExtractor::convertToAggregatableXml(const QDomElement &documentElement) +{ + QDomDocument outDocument; + QDomElement root = outDocument.createElement("instructionals"); + QDomElement demos = outDocument.createElement("demos"); + QDomElement examples = outDocument.createElement("examples"); + QDomElement tutorials = outDocument.createElement("tutorials"); + root.setAttribute("module", "Qt"); + root.appendChild(demos); + root.appendChild(examples); + root.appendChild(tutorials); + outDocument.appendChild(root); + + QDomNode currentNode = documentElement.firstChild(); + QDomElement step, steps, instructional; + int id = 0; + while (!currentNode.isNull()){ + //qDebug() << '\t' << label; + QDomNode sub = currentNode.firstChild(); + while (!sub.isNull()) { + QDomElement element = sub.toElement(); + readInfoAboutExample(element); + QString exampleName = element.attribute("name"); + StringHash exampleInfo = info[exampleName]; + + // type = category - last char + QString category = exampleInfo["category"]; + QString categoryName = sub.parentNode().toElement().attribute("name"); + QString type = category; + type.chop(1); + + QString dirName = exampleInfo["dirname"]; + + if (category != "tutorial" || (category == "tutorial" && category != lastCategory)) { + instructional = outDocument.createElement(type); + if (category == "tutorial" && category != lastCategory) + instructional.setAttribute("name", categoryName); + else + instructional.setAttribute("name", exampleName); + } + + QString projectPath = dirName + '/' + exampleInfo["filename"] + '/' + exampleInfo["filename"]; + + bool qml = (exampleInfo["qml"] == "true"); + if (qml) + projectPath += ".qmlproject"; + else + projectPath += ".pro"; + + + if (category == "tutorials") + { + if (category != lastCategory) { + steps = outDocument.createElement("steps"); + instructional.appendChild(steps); + } + + step = outDocument.createElement("step"); + step.setAttribute("projectPath", projectPath); + step.setAttribute("imageUrl", getImageUrl(exampleName)); + step.setAttribute("docUrl", resolveDocUrl(exampleName)); + steps.appendChild(step); + } + + instructional.setAttribute("projectPath", projectPath); + instructional.setAttribute("imageUrl", getImageUrl(exampleName)); + instructional.setAttribute("docUrl", resolveDocUrl(exampleName)); + instructional.setAttribute("difficulty", "?"); + QDomElement description = outDocument.createElement("description"); + QString descriptionText = loadDescription(exampleName); + description.appendChild(outDocument.createCDATASection(descriptionText)); + QDomElement tags = outDocument.createElement("tags"); + // TODO + QStringList tagList; + tagList << type << exampleInfo["filename"].split('/'); + if (dirName != ".") + tagList << dirName.split('/'); + if (qml) + tagList << "qml" << "qt quick"; + QRegExp ttText("(.*)"); + ttText.setMinimal(true); // non-greedy + int index = 0; + QStringList keywords; + while ((index = ttText.indexIn(descriptionText, index)) != -1) { + keywords << descriptionText.mid(index+4, ttText.matchedLength()-9); + index = index + ttText.matchedLength(); + } + + // Blacklist Checking... + QStringList blackList; + blackList << "license" << "trafikanten"; + foreach (const QString& keyword, keywords) + if (!keyword.isEmpty()) { + bool skip = false; + foreach (const QString& blackListItem, blackList) + if (keyword.contains(blackListItem, Qt::CaseInsensitive)) { + skip = true; + break; + } + if (!skip) + tagList << keyword.simplified().toLower(); + } + + tags.appendChild(outDocument.createTextNode(tagList.join(","))); + instructional.appendChild(description); + instructional.appendChild(tags); + + if (category != "tutorials") { + if (category == "demos") + demos.appendChild(instructional); + else + examples.appendChild(instructional); + } else if (lastCategory != "tutorials") + tutorials.appendChild(instructional); + + id++; + sub = sub.nextSibling(); + lastCategory = category; + + } + currentNode = currentNode.nextSibling(); + } + + + QFile outFile("../../../share/qtcreator/welcomescreen/examples_fallback.xml"); + + QByteArray xml = "\n"; + xml += outDocument.toByteArray(); + if (!outFile.open(QIODevice::WriteOnly)) + return; + outFile.write(xml); + //qDebug() << xml; + outFile.close(); + +} + +QString HelpExtractor::loadDescription(const QString &name) +{ + QByteArray ba = getHtml(name); + QString errorMsg; + int errorLine, errorColumn; + + QDomDocument exampleDoc; + if (ba.isEmpty()) { + qDebug() << "No documentation found for" << name << "Is the documentation built?"; + } else if (!exampleDoc.setContent(ba, false, &errorMsg, &errorLine, &errorColumn)) { + qDebug() << "Error loading documentation for " << name << ": " << errorMsg << errorLine << errorColumn; + } + + QDomNodeList paragraphs = exampleDoc.elementsByTagName("p"); + if (paragraphs.length() < 1) + qDebug() << "- ExampleContent::loadDescription(): Could not load description:" + << info[name]["docfile"]; + QString description = QLatin1String(""); + for (int p = 0; p < int(paragraphs.length()); ++p) { + description = extractTextFromParagraph(paragraphs.item(p)); + if (isSummaryOf(description, name)) { + break; + } + } + return description; +} + +void HelpExtractor::readInfoAboutExample(const QDomElement &example) +{ + QString name = example.attribute("name"); + if (info.contains(name)) + qWarning() << "__WARNING: HelpExtractor::readInfoAboutExample: Demo/example with name" + << name << "appears twice in the xml-file!__"; + + info[name]["filename"] = example.attribute("filename"); + QString dirName = example.parentNode().toElement().attribute("dirname"); + info[name]["dirname"] = dirName; + QString category; + if (dirName.startsWith("tutorials")) + category = "tutorials"; + else + category = example.parentNode().toElement().tagName(); + + if (category == "category") + category = "examples"; + + info[name]["category"] = category; + info[name]["changedirectory"] = example.attribute("changedirectory"); + info[name]["image"] = example.attribute("image"); + info[name]["qml"] = example.attribute("qml"); +} + +QString HelpExtractor::resolveDocUrl(const QString &name) +{ + QString dirName = info[name]["dirname"]; + QString category = info[name]["category"]; + QString fileName = info[name]["filename"]; + + if (category == "demos") + return helpRootUrl + "demos-" + fileName.replace("/", "-") + ".html"; + else + return helpRootUrl + dirName.replace("/", "-") + "-" + fileName + ".html"; +} + + +QString HelpExtractor::resolveImageUrl(const QString &name) +{ + return helpRootUrl + "images/" + name; +} + +QByteArray HelpExtractor::getResource(const QString &name) +{ + return helpEngine->fileData(name); +} + +QByteArray HelpExtractor::getHtml(const QString &name) +{ + return getResource(resolveDocUrl(name)); +} + +QByteArray HelpExtractor::getImage(const QString &name) +{ + QString imageName = this->info[name]["image"]; + QString category = this->info[name]["category"]; + QString fileName = this->info[name]["filename"]; + bool qml = (this->info[name]["qml"] == QLatin1String("true")); + if (qml) + fileName = QLatin1String("qml-") + fileName.split('/').last(); + + if (imageName.isEmpty()){ + if (category == "demos") + imageName = fileName + "-demo.png"; + else + imageName = fileName + "-example.png"; + if ((getResource(resolveImageUrl(imageName))).isEmpty()) + imageName = fileName + ".png"; + if ((getResource(resolveImageUrl(imageName))).isEmpty()) + imageName = fileName + "example.png"; + } + return getResource(resolveImageUrl(imageName)); +} + +QString HelpExtractor::getImageUrl(const QString &name) +{ + QString imageName = this->info[name]["image"]; + QString category = this->info[name]["category"]; + QString fileName = this->info[name]["filename"]; + bool qml = (this->info[name]["qml"] == QLatin1String("true")); + if (qml) + fileName = QLatin1String("qml-") + fileName.split('/').last(); + + if (imageName.isEmpty()){ + if (category == "demos") + imageName = fileName + "-demo.png"; + else + imageName = fileName + "-example.png"; + if ((getResource(resolveImageUrl(imageName))).isEmpty()) + imageName = fileName + ".png"; + if ((getResource(resolveImageUrl(imageName))).isEmpty()) + imageName = fileName + "example.png"; + if ((getResource(resolveImageUrl(imageName))).isEmpty()) + return ""; + } + return resolveImageUrl(imageName); +} + +QString HelpExtractor::extractTextFromParagraph(const QDomNode &parentNode) +{ + QString description; + QDomNode node = parentNode.firstChild(); + + while (!node.isNull()) { + QString beginTag; + QString endTag; + if (node.isText()) + description += node.nodeValue(); + else if (node.hasChildNodes()) { + if (node.nodeName() == "b") { + beginTag = ""; + endTag = ""; + } else if (node.nodeName() == "a") { + beginTag = ""; + endTag = ""; + } else if (node.nodeName() == "i") { + beginTag = ""; + endTag = ""; + } else if (node.nodeName() == "tt") { + beginTag = ""; + endTag = ""; + } + description += beginTag + extractTextFromParagraph(node) + endTag; + } + node = node.nextSibling(); + } + + return description; +} + +bool HelpExtractor::isSummaryOf(const QString &text, const QString &example) +{ + return (!text.contains("[") && + text.indexOf(QRegExp(QString("(In )?((The|This) )?(%1 )?.*(tutorial|example|demo|application)").arg(example), + Qt::CaseInsensitive)) != -1); +} diff --git a/src/tools/examplesscanner/helpextractor.h b/src/tools/examplesscanner/helpextractor.h new file mode 100644 index 00000000000..4210a6635db --- /dev/null +++ b/src/tools/examplesscanner/helpextractor.h @@ -0,0 +1,41 @@ +#ifndef HELPEXTRACTOR_H +#define HELPEXTRACTOR_H + +#include +#include +#include + +typedef QHash StringHash; +typedef QHash HashHash; + +class HelpExtractor +{ +public: + HelpExtractor(); + void readXmlDocument(); + +private: + void initHelpEngine(); + void convertToAggregatableXml(const QDomElement &documentElement); + QByteArray getResource(const QString &name); + QByteArray getHtml(const QString &name); + QByteArray getImage(const QString &name); + QString getImageUrl(const QString &name); + QString resolveDocUrl(const QString &name); + QString resolveImageUrl(const QString &name); + QString loadDescription(const QString &name); + void readInfoAboutExample(const QDomElement &example); + QString extractTextFromParagraph(const QDomNode &parentNode); + bool isSummaryOf(const QString &text, const QString &example); + + HashHash info; + QHelpEngineCore *helpEngine; + QDomDocument *contentsDoc; + QString helpRootUrl; + QDir docDir; + QDir imgDir; + QString lastCategory; + +}; + +#endif // HELPEXTRACTOR_H diff --git a/src/tools/examplesscanner/main.cpp b/src/tools/examplesscanner/main.cpp new file mode 100644 index 00000000000..5c47a9788b0 --- /dev/null +++ b/src/tools/examplesscanner/main.cpp @@ -0,0 +1,9 @@ +#include + +#include "helpextractor.h" + +int main(int argc, char *argv[]) +{ + HelpExtractor extractor; + extractor.readXmlDocument(); +}