Release 0.4-0
[marketstoday] / src / qml / MarketsTodayWidget.qml
1 /*
2 @version: 0.4
3 @author: Sudheer K. <scifi1947 at gmail.com>
4 @license: GNU General Public License
5 */
6
7 import Qt 4.7
8
9 import "Library" as Library
10 import "Library/js/ISODate.js" as DateLib
11 import "Library/js/DBUtility.js" as DBUtility
12 import "Library/js/Common.js" as Common
13 import "Library/js/CoreLogic.js" as CoreLib
14
15 Item {
16     id: mainPage
17
18     signal showConfigInNewWindow
19     signal showStockDetails(string strSymbol)
20     signal quoteRefreshStarted
21     signal quoteRefreshCompleted(bool success, string strMessage)
22     signal newsReloadCompleted(bool success, string strMessage)
23     signal checkNetworkStatus
24
25     property int itemHeight: 50
26     property int titleBarHeight: 60
27     property int toolBarHeight: 40
28     property int componentWidth: mainPage.width
29     property int autoUpdateInterval: 300000
30     property bool updateWeekDaysOnly: false
31     property bool updateOnSavedNetworksOnly: false
32     property bool isDesktopWidget: true
33     property string rssURL: "http://finance.yahoo.com/rss/topfinstories"
34     property string lastUpdatedTimeStamp
35     property string selectedSymbol:""
36
37     function reloadData(){
38         CoreLib.reloadQuotes();
39         CoreLib.reloadNews();
40     }
41
42     function initialize(){
43         DBUtility.initialize();
44         CoreLib.initialize();
45     }
46
47     Component.onCompleted: {
48         initialize();
49     }
50
51     Timer {
52         id: autoUpdateTimer
53         interval: autoUpdateInterval
54         //running: (autoUpdateInterval == 0? false:true)
55         repeat: true
56         onTriggered: {
57             if (!updateWeekDaysOnly){
58                 logUtility.logMessage("Allowed to update all days of the week");
59                 mainPage.reloadData();
60                 //checkNetworkStatus();
61             }
62             else if (Common.isTodayAWeekDay()){
63                 logUtility.logMessage("Today is a weekday");
64                 mainPage.reloadData();
65                 //checkNetworkStatus();
66             }
67             else{
68                 logUtility.logMessage("Update not triggered: Today is not a weekday");
69             }
70         }
71     }
72
73     ListModel{
74         id: stockQuoteDataModel
75     }
76
77     ListModel {
78         id: newsDataModel
79     }
80
81     Rectangle {
82         id: background
83         anchors.fill: parent;
84         color: "#343434"
85         clip: true
86
87         Component.onCompleted: {
88             console.log("Rectangle Height = "+background.height);
89         }
90
91         Component {
92             id: stockQuotesDelegate
93
94             Item {
95                 id: wrapper; width: parent.width; height: itemHeight
96                 Item {
97                     anchors.fill: parent
98                     Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: wrapper.height - 2; width: wrapper.width; y: 1
99                         Image{
100                             id: informationIcon
101                             width: 32
102                             height: 32
103                             z: 10
104                             anchors {right: parent.right; rightMargin: 10; verticalCenter: parent.verticalCenter}
105                             visible: false
106                             source: "Library/images/information.png"
107                             MouseArea{
108                                 anchors.fill: parent;
109                                 onPressed: {
110                                     logUtility.logMessage("Image clicked");
111                                     showStockDetails(symbol);
112                                 }
113                             }
114                         }
115
116                         MouseArea {
117                             anchors.fill: parent
118                             onPressed:{
119                                 informationIcon.visible = true;
120                                 //console.log("Rectangle clicked");
121                             }
122                         }
123                     }
124                     Row {
125                         y: 15;//x: 30;
126                         anchors {left: parent.left;leftMargin: 10;right: parent.right;rightMargin: 10}
127                         //width: componentWidth;
128                         height: parent.height
129                         spacing: 5
130
131                         Text { text: symbol; width: parent.width * 25/100; font.pixelSize: 18; font.bold: true; verticalAlignment:Text.AlignVCenter; elide: Text.ElideRight; color: "white"; style: Text.Raised; styleColor: "black" }
132                         Text { text: lastTradedPrice; width: parent.width * 25/100; font.pixelSize: 18; verticalAlignment:Text.AlignVCenter; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
133                         Column {
134                             y: -15;
135                             width: parent.width * 20/100; height: parent.height
136                             spacing: 2
137                             Text { text: change; font.pixelSize: 16; elide: Text.ElideRight
138                                 color: if(change >= 0){"green";} else {"red";}
139                                     style: Text.Raised; styleColor: "black" }
140                             Text { text: changePercentage; font.pixelSize: 16; elide: Text.ElideRight;
141                                 color: if(change >= 0){"green";} else {"red";}
142                                     style: Text.Raised; styleColor: "black" }
143                         }
144                         Text { text: volume; width: parent.width * 30/100; font.pixelSize: 18; verticalAlignment:Text.AlignVCenter; elide: Text.ElideLeft; color: "#cccccc"; style: Text.Raised; styleColor: "black" }
145                     }
146                 }
147             }
148         }
149
150         Component {
151             id: newsDelegate
152
153             Item {
154                 id: newsWrapper; width: componentWidth; height: itemHeight
155                 Item {
156                     anchors.fill: parent
157                     Rectangle { color: "black"; opacity: index % 2 ? 0.2 : 0.4; height: newsWrapper.height - 2; width: newsWrapper.width; y: 1 }
158                     Text {
159                         anchors.verticalCenter: parent.verticalCenter
160                         anchors.left: parent.left
161                         anchors.leftMargin: 10
162                         anchors.right: parent.right
163                         text: title; font.pixelSize: 14
164                         font.bold: false;
165                         verticalAlignment: Text.AlignVCenter
166                         horizontalAlignment: Text.AlignLeft
167                         elide: Text.ElideRight;
168                         color: "white";
169                         style: Text.Raised;
170                         styleColor: "black"
171                     }
172                     MouseArea{
173                         anchors.fill: parent
174                         onClicked: Qt.openUrlExternally(link);
175                     }
176                 }
177             }
178         }
179
180         Library.TitleBar {
181             id: titleBar
182             width: parent.width; height: mainPage.titleBarHeight
183             anchors.top: parent.top
184             title: "Markets Today"
185             buttonType: ""
186             displayMenuIcon: false
187
188             onBackClicked: {
189                 uiLoader.sourceComponent = stockQuotesUIComponent;
190                 titleBar.buttonType = "";
191                 titleBar.displayMenu = false;
192                 toolBar.displayIcons = true;
193             }
194         }
195
196         Loader {
197             id: uiLoader
198             width: parent.width
199             anchors.top: titleBar.bottom
200             anchors.bottom: toolBar.top
201             sourceComponent: stockQuotesUIComponent
202         }
203
204         Library.ToolBar {
205             id:toolBar
206             width: parent.width; height: mainPage.toolBarHeight
207             anchors.bottom: parent.bottom
208             opacity: 0.9
209             displayNavigation: true
210             onReloadButtonClicked: mainPage.reloadData();
211             onNewsButtonClicked: {
212                 uiLoader.sourceComponent = newsComponent;
213                 toolBar.displayIcons = true;
214                 toolBar.targetContentType = "Stocks";
215             }
216
217             onStocksButtonClicked: {
218                 uiLoader.sourceComponent = stockQuotesUIComponent;
219                 toolBar.displayIcons = true;
220                 toolBar.targetContentType = "News";
221             }
222
223
224             Connections {
225                 target: mainPage
226                 onQuoteRefreshStarted:{
227                     if (!toolBar.updatePending) toolBar.updatePending = true;
228                 }
229                 onQuoteRefreshCompleted:{
230                     toolBar.updatePending = false;
231                 }
232             }
233         }
234
235         Component {
236             id: stockQuotesUIComponent
237             Item {
238                 Rectangle{
239                     id: pathViewWrapper
240                     width: parent.width
241                     anchors.top: parent.top
242                     anchors.bottom: footerText.top
243                     color: "#343434"
244
245                     PathView {
246                         id: stockQuotesView
247                         anchors.fill: parent
248                         flickDeceleration: 500
249                         //preferredHighlightBegin: 1/stockQuotesView.count
250                         //preferredHighlightEnd: 1/stockQuotesView.count
251                         //pathItemCount: count
252                         focus: true
253                         interactive: true
254                         model: stockQuoteDataModel
255                         delegate:  stockQuotesDelegate
256                         path: Path {
257                             startX: width / 2
258                             startY: itemHeight/2
259                             PathLine {
260                                 x: width / 2
261                                 y: stockQuotesView.count * itemHeight  + itemHeight/2
262                             }
263                         }
264                         Keys.onDownPressed: if (!moving && interactive) incrementCurrentIndex()
265                         Keys.onUpPressed: if (!moving && interactive) decrementCurrentIndex()
266
267                         Connections {
268                             target:  mainPage
269                             onQuoteRefreshCompleted:{
270                                 stockQuotesView.currentIndex = 0;
271                             }
272                         }
273
274                         Connections {
275                             target: toolBar
276                             onDownButtonClicked: {
277                                 if (!stockQuotesView.moving && stockQuotesView.interactive)
278                                     stockQuotesView.currentIndex = stockQuotesView.currentIndex + 1
279                             }
280                             onUpButtonClicked: {
281                                 if (!stockQuotesView.moving && stockQuotesView.interactive)
282                                     stockQuotesView.currentIndex = stockQuotesView.currentIndex - 1
283                             }
284                        }
285                     }
286                 }
287
288                 Rectangle {
289                     id: stockStatusMsgArea
290                     height: 100
291                     color: "#343434"
292                     anchors {left: parent.left; leftMargin: 15; right: parent.right; rightMargin: 15;
293                             verticalCenter: parent.verticalCenter}
294                     visible: false
295
296                     Text {
297                         id: stockStatusText
298                         anchors.fill: parent
299                         text: "Loading quotes.."
300                         horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
301                         width: parent.width; font.pixelSize: 16; elide: Text.ElideNone;
302                         color: "#cccccc"
303                         wrapMode: Text.WrapAtWordBoundaryOrAnywhere
304                         style: Text.Raised; styleColor: "black"
305
306                         Connections {
307                             target: mainPage
308                             onQuoteRefreshCompleted: {
309                                 if (success){                                    
310                                     stockStatusMsgArea.visible = false;
311                                     pathViewWrapper.visible = true;
312                                 }
313                                 else{
314                                     stockStatusText.text = strMessage;
315                                     pathViewWrapper.visible = false;
316                                     stockStatusMsgArea.visible = true;
317                                 }
318                             }
319                         }
320                     }
321                 }
322
323                 Rectangle{
324                     id: footerText
325                     width: parent.width
326                     height: 25
327                     color: "#343434"
328                     anchors.bottom: parent.bottom
329                     Text {
330                         id: timeStamp
331                         anchors.fill: parent
332                         text: mainPage.lastUpdatedTimeStamp
333                         horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignVCenter
334                         width: parent.width; font.pixelSize: 12; elide: Text.ElideRight;
335                         color: "#cccccc"
336                         style: Text.Raised; styleColor: "black"
337
338                         Connections {
339                             target: mainPage
340                             onQuoteRefreshCompleted:{
341                                 timeStamp.text = mainPage.lastUpdatedTimeStamp;
342                             }
343                         }
344                     }
345                 }
346             }
347         }
348
349         Component {
350             id: newsComponent
351             Item {
352                 Rectangle{
353                     id: newsViewArea
354                     width: parent.width
355                     anchors.top: parent.top
356                     anchors.bottom: parent.bottom
357                     color: "#343434"
358
359                     PathView {
360                         id: newsView
361                         anchors.fill: parent
362                         flickDeceleration: 500
363                         focus: true
364                         interactive: true
365                         model: newsDataModel
366                         delegate:  newsDelegate
367                         path: Path {
368                             startX: width / 2
369                             startY: itemHeight/2
370                             PathLine {
371                                 x: width / 2
372                                 y: newsView.count * itemHeight  + itemHeight/2
373                             }
374                         }
375                         Keys.onDownPressed: if (!moving && interactive) incrementCurrentIndex()
376                         Keys.onUpPressed: if (!moving && interactive) decrementCurrentIndex()
377
378                         Connections {
379                             target:  mainPage
380                             onQuoteRefreshCompleted:{
381                                 newsView.currentIndex = 0;
382                             }
383                         }
384
385                         Connections {
386                             target: toolBar
387                             onDownButtonClicked: {
388                                 if (!newsView.moving && newsView.interactive)
389                                     newsView.currentIndex = newsView.currentIndex + 1
390                             }
391                             onUpButtonClicked: {
392                                 if (!newsView.moving && newsView.interactive)
393                                     newsView.currentIndex = newsView.currentIndex - 1
394                             }
395                        }
396                     }
397                 }
398
399                 Rectangle {
400                     id: newsStatusMsgArea
401                     height: 100
402                     color: "#343434"
403                     anchors {left: parent.left; leftMargin: 15; right: parent.right; rightMargin: 15;
404                             verticalCenter: parent.verticalCenter}
405                     visible: false
406
407                     Text {
408                         id: newsStatusText
409                         anchors.fill: parent
410                         text: "Loading news.."
411                         horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
412                         width: parent.width; font.pixelSize: 16; elide: Text.ElideNone;
413                         color: "#cccccc"
414                         wrapMode: Text.WrapAtWordBoundaryOrAnywhere
415                         style: Text.Raised; styleColor: "black"
416
417                         Connections {
418                             target: mainPage
419                             onNewsReloadCompleted: {
420                                 if (success){
421                                     newsStatusMsgArea.visible = false;
422                                     newsViewArea.visible = true;
423                                 }
424                                 else{
425                                     newsStatusText.text = strMessage;
426                                     newsViewArea.visible = false;
427                                     newsStatusMsgArea.visible = true;
428                                 }
429                             }
430                         }
431                     }
432                 }
433             }
434         }
435     }
436 }