/*
-@version: 0.1
+@version: 0.2
@author: Sudheer K. <scifi1947 at gmail.com>
@license: GNU General Public License
*/
import Qt 4.7
+import "Library" as Library
Item {
width: 800
height: 380
- id: stockDetailsComponent
+ id: stockDetailsScreen
+ property int componentWidth: width - 120
property int itemHeight: 50
property string symbol: "YHOO"
- property string stockName: "Yahoo"
+ property string stockName: ""
property string lastTradedPrice: ""
- property string lastTradedTime: ""
+ property string lastTradedDateTime: ""
property string change: ""
property string changePercentage: ""
- property string dayLow: ""
- property string dayHigh: ""
- property string fiftyTwoWeekLow: ""
- property string fiftyTwoWeekHigh: ""
+ property string daysRange: ""
+ property string yearRange: ""
property string marketVolume: ""
property string prevClose: ""
property string marketCap: ""
+ property string baseChartURL: "http://chart.finance.yahoo.com/z?q=&l=&z=m&p=s&a=v&p=s&lang=en-US®ion=US"
property string chartURL: ""
+ property string rssURL: ""
+
+ property int currentScreenIndex: 1
signal logRequest(string strMessage)
+ signal loadChart(string duration)
Rectangle {
anchors.fill: parent
color:"#343434"
- Component.onCompleted: {
- loadDetails();
+ Component.onCompleted: {
if (symbol !== "") {
- chartURL = "http://chart.finance.yahoo.com/z?t=1d&q=&l=&z=m&p=s&a=v&p=s&lang=en-US®ion=US&s="+symbol;
- stockDetailsLoader.sourceComponent = stockChartComponent;
- console.log(stockDetailsLoader.width + " x "+ stockDetailsLoader.height);
+ loadDetails();
+ loadNews();
+ chartURL = baseChartURL+"&t=1d&s="+symbol;
}
}
function loadDetails(){
- if (symbol === "") return;
+ var queryURL = 'http://query.yahooapis.com/v1/public/yql?q=select Symbol,Name,LastTradePriceOnly,LastTradeDate,LastTradeTime,Change,ChangeinPercent,DaysRange,YearRange,Volume,PreviousClose,MarketCapitalization from yahoo.finance.quotes where symbol in ("'+symbol+'")&env=store://datatables.org/alltableswithkeys';
+ logRequest("Loading stock details from "+queryURL);
+ var response = new XMLHttpRequest();
+ response.onreadystatechange = function() {
+ if (response.readyState == XMLHttpRequest.DONE) {
+ refreshDetails(response.responseXML);
+ }
+ }
+ response.open("GET", queryURL);
+ response.send();
}
- Text {
- id: stockNameLabel
- anchors.top: parent.top
- width: parent.width
- anchors.horizontalCenter: parent.horizontalCenter
- height: 30
- horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
- font.pixelSize: 18; font.bold: true; elide: Text.ElideMiddle; color: "#B8B8B8"; style: Text.Raised; styleColor: "black"
- text: (stockName != "")? (stockName +" ("+symbol+")"):symbol
+ function loadNews(){
+ rssURL = "http://feeds.finance.yahoo.com/rss/2.0/headline?region=US&lang=en-US&s="+symbol;
+ logRequest("Loading news from "+rssURL);
+ var response = new XMLHttpRequest();
+ response.onreadystatechange = function() {
+ if (response.readyState == XMLHttpRequest.DONE) {
+ refreshNewsModel(response.responseXML);
+ }
+ }
+
+ response.open("GET", rssURL);
+ response.send();
}
- Rectangle {
- id: stockDetailsSection
- border.width: 1
- border.color: "#BFBFBF"
- color:"#2E2E2E"
- anchors {top: stockNameLabel.bottom;left: parent.left;leftMargin: 40;right: parent.right;rightMargin: 40}
- height: 125
- radius: 15
-
- Column{
- id: stockDetailsColumn
- anchors {top: parent.top; left: parent.left; leftMargin: 10}
- width: (parent.width - 10)
-
- StockDetailsRow{
- label1: "Last Traded"
- value1: lastTradedPrice
- cell1Width: stockDetailsColumn.width/2
-
- label2: "Day's Range"
- value2: ((dayHigh != "" && dayLow != "")? (dayLow + " - " + dayHigh) : "")
- cell2Width: stockDetailsColumn.width/2
+ function refreshDetails(responseXML){
+ if (!responseXML) return;
+ var xmlDoc = responseXML.documentElement;
+ var results = xmlDoc.firstChild;
+
+ if (results) {
+ var quoteNodes = results.childNodes;
+ if (quoteNodes){
+ if (quoteNodes.length === 0) {
+ logRequest("No results for stock quote details");
+ }
+ else{
+ //We are only expecting one quote node per symbol.
+ var quoteElements = quoteNodes[0].childNodes;
+ var j = 0;
+ var lastTradedDate = "", lastTradedTime ="";
+ for (j = 0; j < quoteElements.length; j++){
+
+ if (quoteElements[j].childNodes[0]) {
+ switch (quoteElements[j].nodeName){
+ case 'Name':
+ stockName = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'LastTradePriceOnly':
+ lastTradedPrice = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'LastTradeDate':
+ lastTradedDate = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'LastTradeTime':
+ lastTradedTime = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'Change':
+ change = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'ChangeinPercent':
+ changePercentage = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'DaysRange':
+ daysRange = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'YearRange':
+ yearRange = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'Volume':
+ marketVolume = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'PreviousClose':
+ prevClose = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ case 'MarketCapitalization':
+ marketCap = quoteElements[j].childNodes[0].nodeValue;
+ break;
+ default:
+ }
+ }
+ }
+ if (lastTradedDate !== "") lastTradedDateTime = lastTradedDate + " " + lastTradedTime;
+ }
}
+ }
+ }
+
+ function refreshNewsModel(responseXML){
+ if (!(responseXML && stockNewsDataModel)) return;
+
+ var xmlDoc = responseXML.documentElement;
+ var channel = xmlDoc.firstChild;
+
+ //Not the best code I ever wrote, but got no choice
+ //Refer to Memory leak issue with XMLListModel --> http://bugreports.qt.nokia.com/browse/QTBUG-15191
+
+ if (channel) {
+ var itemNodes = channel.childNodes;
+ if (itemNodes){
+
+ logRequest("Clearing News Model");
+ stockNewsDataModel.clear();
+
+ var i = 0;
+ for (i = 0; i < itemNodes.length; i++) {
- StockDetailsRow{
- label1: "Last Trade Time"
- value1: lastTradedTime
- cell1Width: stockDetailsColumn.width/2
+ if (itemNodes[i].nodeName === 'item'){
+ var newsElements = itemNodes[i].childNodes;
+ var j = 0;
+ var newsTitle,newsLink
+ for (j = 0; j < newsElements.length; j++){
- label2: "52w Range"
- value2: ((fiftyTwoWeekHigh != "" && fiftyTwoWeekLow != "")? (fiftyTwoWeekLow + " - " + fiftyTwoWeekHigh) : "")
- cell2Width: stockDetailsColumn.width/2
+ switch (newsElements[j].nodeName){
+ case 'title':
+ newsTitle = newsElements[j].childNodes[0].nodeValue;
+ break;
+ case 'link':
+ newsLink = newsElements[j].childNodes[0].nodeValue;
+ break;
+ default:
+ }
+ }
+ stockNewsDataModel.append({"title":newsTitle,"link":newsLink});
+ }
+ }
}
+ }
+ }
+
+ ListModel{
+ id: stockNewsDataModel
+ }
- StockDetailsRow{
- label1: "Change"
- value1: ((change != "" && changePercentage != "")? change + " ("+changePercentage+")":"")
- cell1Width: stockDetailsColumn.width/2
+ Component {
+ id: stockNewsDelegate
- label2: "Volume"
- value2: marketVolume
- cell2Width: stockDetailsColumn.width/2
+ Item {
+ id: newsWrapper; width: componentWidth; height: itemHeight
+ Item {
+ anchors.fill: parent
+ Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: newsWrapper.height - 2; width: newsWrapper.width; y: 1 }
+ Text {
+ anchors {verticalCenter: parent.verticalCenter;left: parent.left;leftMargin: 10;right: parent.right}
+ text: title; font.pixelSize: 14
+ font.bold: false;
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignLeft
+ elide: Text.ElideRight;
+ color: "white";
+ style: Text.Raised;
+ styleColor: "black"
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: {
+ logRequest("Opening news article: "+link);
+ Qt.openUrlExternally(link);
+ }
+ }
}
+ }
+ }
+
+ Component {
+ id: stockDetailsComponent
- StockDetailsRow{
- label1: "Prev. Close"
- value1: prevClose
- cell1Width: stockDetailsColumn.width/2
+ Item {
+ anchors.fill: parent
- label2: "Market Cap"
- value2: marketCap
- cell2Width: stockDetailsColumn.width/2
+ Text {
+ id: stockNameLabel
+ anchors.top: parent.top
+ width: parent.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: 30
+ horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
+ font.pixelSize: 18; font.bold: true; elide: Text.ElideMiddle; color: "#B8B8B8"; style: Text.Raised; styleColor: "black"
+ text: (stockName != "")? (stockName +" ("+symbol+")"):symbol
+ }
+
+
+ Rectangle {
+ id: stockDetailsSection
+ border.width: 1
+ border.color: "#BFBFBF"
+ color:"#2E2E2E"
+ anchors {top: stockNameLabel.bottom;left: parent.left;right: parent.right}
+ height: 125
+ radius: 15
+
+ Column{
+ id: stockDetailsColumn
+ anchors {top: parent.top; left: parent.left; leftMargin: 10}
+ width: (parent.width - 10)
+
+ StockDetailsRow{
+ label1: "Last Traded"
+ value1: lastTradedPrice
+ cell1Width: stockDetailsColumn.width/2
+
+ label2: "Day's Range"
+ value2: daysRange
+ cell2Width: stockDetailsColumn.width/2
+ }
+
+ StockDetailsRow{
+ label1: "Last Trade Time"
+ value1: lastTradedDateTime
+ cell1Width: stockDetailsColumn.width/2
+
+ label2: "52w Range"
+ value2: yearRange
+ cell2Width: stockDetailsColumn.width/2
+ }
+
+ StockDetailsRow{
+ label1: "Change"
+ value1: ((change != "" && changePercentage != "")? change + " ("+changePercentage+")":"")
+ cell1Width: stockDetailsColumn.width/2
+
+ label2: "Volume"
+ value2: marketVolume
+ cell2Width: stockDetailsColumn.width/2
+ }
+
+ StockDetailsRow{
+ label1: "Prev. Close"
+ value1: prevClose
+ cell1Width: stockDetailsColumn.width/2
+
+ label2: "Market Cap"
+ value2: marketCap
+ cell2Width: stockDetailsColumn.width/2
+ }
+ }
+ }
+
+ Rectangle{
+ border.width: 1
+ border.color: "#BFBFBF"
+ color:"#2E2E2E"
+ width: parent.width
+ anchors {top: stockDetailsSection.bottom;topMargin: 5;
+ bottom: parent.bottom;bottomMargin: 20;
+ left: parent.left;
+ right: parent.right}
+ ListView {
+ flickDeceleration: 500
+ anchors.fill: parent
+ model: stockNewsDataModel
+ delegate: stockNewsDelegate
+ focus:true
+ snapMode: ListView.SnapToItem
+ }
+ }
+
+ }
+ }
+
+ Rectangle{
+ id: arrowLeftArea
+ color: "#343434"
+ width:40; height: 40
+ visible: (currentScreenIndex > 1)
+ anchors {verticalCenter: parent.verticalCenter; left: parent.left; leftMargin: 10}
+ Image {
+ width: 32
+ height: 32
+ smooth: true
+ source: "Library/images/arrow_left.png"
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: {
+ switch (currentScreenIndex){
+ case 1:
+ //Do Nothing
+ break;
+ case 2:
+ stockDetailsLoader.sourceComponent = stockDetailsComponent;
+ currentScreenIndex = currentScreenIndex - 1;
+ break;
+ default:
+ //Do Nothing
+ }
+ logRequest("currentScreenIndex = "+currentScreenIndex);
}
}
}
Loader {
id: stockDetailsLoader
- anchors {top: stockDetailsSection.bottom;bottom: parent.bottom; horizontalCenter: parent.horizontalCenter}
- //width: parent.width
- width: 480
+ anchors{top: parent.top; bottom: parent.bottom
+ left: parent.left; leftMargin: 60
+ right: parent.right; rightMargin: 60}
+ sourceComponent: stockDetailsComponent
+ }
+
+ Rectangle{
+ id: arrowRightArea
+ color: "#343434"
+ width:40; height: 40
+ visible: (currentScreenIndex < 2)
+ anchors {verticalCenter: parent.verticalCenter; right: parent.right; rightMargin: 10}
+ Image {
+ width: 32
+ height: 32
+ smooth: true
+ source: "Library/images/arrow_right.png"
+ }
+ MouseArea{
+ anchors.fill: parent
+ onClicked: {
+ switch (currentScreenIndex){
+ case 1:
+ stockDetailsLoader.sourceComponent = stockChartComponent;
+ currentScreenIndex = currentScreenIndex + 1;
+ break;
+ case 2:
+ //Do Nothing
+ break;
+ default:
+ //Do Nothing
+ }
+ logRequest("currentScreenIndex = "+currentScreenIndex);
+ }
+ }
}
Component{
id: stockChartComponent
- Rectangle {
- id: rectangleChart
- border.width: 1
- border.color: "#BFBFBF"
- color:"#2E2E2E"
- anchors {top: parent.top;topMargin: 5;bottom: parent.bottom; left: parent.left;leftMargin: 40;right: parent.right;rightMargin: 40}
- radius: 15
- Image {
- anchors.fill: parent
- id: name
- source: chartURL
- fillMode: Image.PreserveAspectFit
+
+ Item {
+ id: chartAreaWrapper
+ anchors.fill: parent
+
+ Rectangle {
+ id: chartArea
+ border.width: 1
+ border.color: "#BFBFBF"
+ //color:"#2E2E2E"
+ color:"white"
+ anchors { top: parent.top;topMargin: 40;
+ bottom: parent.bottom; bottomMargin: 40;
+ left: parent.left; right: parent.right}
+ radius: 10
+
+ Library.Loading { anchors.centerIn: parent; visible: chartImg.status == Image.Loading}
+
+ Image {
+ id: chartImg
+ anchors {left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter}
+ source: chartURL
+ sourceSize.width: 512
+ sourceSize.height: 288
+ smooth: true
+ fillMode: Image.PreserveAspectFit
+ onStatusChanged: {
+ switch(status){
+ case Image.Ready:
+ logRequest("Image is ready");
+ break;
+ case Image.Loading:
+ logRequest("Image is loading");
+ break;
+ case Image.Error:
+ logRequest("Image loading failed");
+ break;
+ default:
+ logRequest("No image specified");
+ break;
+ }
+
+ }
+
+ Connections{
+ target: stockDetailsScreen
+ onLoadChart: {
+ chartURL = baseChartURL+"&t="+duration+"&s="+symbol;
+ logRequest(chartURL);
+ }
+ }
+ }
+
+ Column {
+ width: 130
+ spacing: 20
+ anchors {top: parent.top; topMargin: 40; bottom: parent.bottom;
+ right: chartArea.right;rightMargin: 10}
+
+ Row {
+ height: 40
+ spacing: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ Library.Button {
+ id: oneDayButton
+ text: "1d"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("1d");
+ }
+
+ Library.Button {
+ id: fiveDayButton
+ text: "5d"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("5d");
+ }
+ }
+
+ Row {
+ height: 40
+ spacing: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ Library.Button {
+ id: threeMonthButton
+ text: "3m"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("3m");
+ }
+
+ Library.Button {
+ id: sixMonthButton
+ text: "6m"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("6m");
+ }
+ }
+ Row {
+ height: 40
+ spacing: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ Library.Button {
+ id: oneYearButton
+ text: "1y"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("1y");
+ }
+
+ Library.Button {
+ id: twoYearButton
+ text: "2y"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("2y");
+ }
+ }
+ Row {
+ height: 40
+ spacing: 20
+ anchors.horizontalCenter: parent.horizontalCenter
+ Library.Button {
+ id: fiveYearButton
+ text: "5y"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("5y");
+ }
+
+ Library.Button {
+ id: maxButton
+ text: "max"
+ anchors { verticalCenter: parent.verticalCenter}
+ width: 50; height: 32
+ onClicked: loadChart("my");
+ }
+ }
+ }
}
}
}