From 9e2a27f41ab4b76851440fe0d5a11e1ae7ca9dde Mon Sep 17 00:00:00 2001 From: Caroline Chao Date: Tue, 10 Dec 2013 14:42:22 +0100 Subject: Initial commit --- .gitignore | 15 + android/AndroidManifest.xml | 40 +++ android/res/drawable-hdpi/icon.png | Bin 0 -> 7414 bytes android/res/drawable-ldpi/icon.png | Bin 0 -> 3404 bytes android/res/drawable-mdpi/icon.png | Bin 0 -> 4621 bytes app-icons/AppIcon_100px.png | Bin 0 -> 11228 bytes app-icons/AppIcon_1024px.png | Bin 0 -> 293694 bytes app-icons/AppIcon_114px.png | Bin 0 -> 13680 bytes app-icons/AppIcon_120px.png | Bin 0 -> 14423 bytes app-icons/AppIcon_144px.png | Bin 0 -> 18424 bytes app-icons/AppIcon_152px.png | Bin 0 -> 15072 bytes app-icons/AppIcon_29px.png | Bin 0 -> 2569 bytes app-icons/AppIcon_36px.png | Bin 0 -> 3240 bytes app-icons/AppIcon_40px.png | Bin 0 -> 3515 bytes app-icons/AppIcon_48px.png | Bin 0 -> 4423 bytes app-icons/AppIcon_50px.png | Bin 0 -> 4570 bytes app-icons/AppIcon_512px.png | Bin 0 -> 109605 bytes app-icons/AppIcon_57px.png | Bin 0 -> 5380 bytes app-icons/AppIcon_58px.png | Bin 0 -> 5597 bytes app-icons/AppIcon_72px.png | Bin 0 -> 7127 bytes app-icons/AppIcon_76px.png | Bin 0 -> 7822 bytes app-icons/AppIcon_80px.png | Bin 0 -> 8166 bytes fonts/LICENSE.txt | 202 ++++++++++++++ fonts/OpenSans-Bold.ttf | Bin 0 -> 224592 bytes fonts/OpenSans-Regular.ttf | Bin 0 -> 217360 bytes fonts/OpenSans-Semibold.ttf | Bin 0 -> 221328 bytes .../AppIcon.appiconset/AppIcon_100px.png | Bin 0 -> 11228 bytes .../AppIcon.appiconset/AppIcon_114px.png | Bin 0 -> 13680 bytes .../AppIcon.appiconset/AppIcon_120px.png | Bin 0 -> 14423 bytes .../AppIcon.appiconset/AppIcon_144px.png | Bin 0 -> 18424 bytes .../AppIcon.appiconset/AppIcon_152px.png | Bin 0 -> 15072 bytes .../AppIcon.appiconset/AppIcon_29px.png | Bin 0 -> 2569 bytes .../AppIcon.appiconset/AppIcon_40px.png | Bin 0 -> 3515 bytes .../AppIcon.appiconset/AppIcon_50px.png | Bin 0 -> 4570 bytes .../AppIcon.appiconset/AppIcon_57px.png | Bin 0 -> 5380 bytes .../AppIcon.appiconset/AppIcon_58px.png | Bin 0 -> 5597 bytes .../AppIcon.appiconset/AppIcon_72px.png | Bin 0 -> 7127 bytes .../AppIcon.appiconset/AppIcon_76px.png | Bin 0 -> 7822 bytes .../AppIcon.appiconset/AppIcon_80px.png | Bin 0 -> 8166 bytes .../AppIcon.appiconset/Contents.json | 104 +++++++ .../LaunchImage.launchimage/Contents.json | 107 ++++++++ .../LaunchImage.launchimage/NoSB_ipad_7_Land.png | Bin 0 -> 96322 bytes .../LaunchImage.launchimage/NoSB_ipad_7_Port.png | Bin 0 -> 116434 bytes .../LaunchImage.launchimage/NoSB_ipad_7_R_Land.png | Bin 0 -> 234465 bytes .../LaunchImage.launchimage/NoSB_ipad_7_R_Port.png | Bin 0 -> 282805 bytes .../LaunchImage.launchimage/ipad_7_Land.png | Bin 0 -> 110632 bytes .../LaunchImage.launchimage/ipad_7_Port.png | Bin 0 -> 130586 bytes .../LaunchImage.launchimage/ipad_7_R_Land.png | Bin 0 -> 287682 bytes .../LaunchImage.launchimage/ipad_7_R_Port.png | Bin 0 -> 337781 bytes .../LaunchImage.launchimage/iphone_6.1.png | Bin 0 -> 48664 bytes .../LaunchImage.launchimage/iphone_7_R3.5.png | Bin 0 -> 116742 bytes .../LaunchImage.launchimage/iphone_7_R4.png | Bin 0 -> 144780 bytes ios/iosInfo.plist | 51 ++++ ios/readme.txt | 15 + qml/js/utils.js | 277 +++++++++++++++++++ qml/main.qml | 178 ++++++++++++ qml/models/SearchResultModel.qml | 32 +++ qml/models/WeatherModel.qml | 134 +++++++++ qml/pages/BasicPage.qml | 205 ++++++++++++++ qml/pages/CitiesPage.qml | 148 ++++++++++ qml/pages/LongTermDayItem.qml | 156 +++++++++++ qml/pages/LongTermPage.qml | 135 +++++++++ qml/pages/OneDayPage.qml | 100 +++++++ qml/pages/OneDaySliderItem.qml | 172 ++++++++++++ qml/pages/OneDayZoomItem.qml | 171 ++++++++++++ qml/pages/Separator.qml | 52 ++++ qml/touch/ListViewDelegate.qml | 158 +++++++++++ qml/touch/Separator.qml | 29 ++ qml/touch/TouchLabel.qml | 79 ++++++ qml/touch/TouchScrollView.qml | 59 ++++ qml/touch/TouchSlider.qml | 81 ++++++ qml/touch/TouchTextField.qml | 115 ++++++++ qml/touch/images/BackArrow.png | Bin 0 -> 376 bytes qml/touch/images/Circle.png | Bin 0 -> 1219 bytes qml/touch/images/Clear.png | Bin 0 -> 1783 bytes qml/touch/images/Pointer.png | Bin 0 -> 5674 bytes qml/touch/images/Pointer_pressed.png | Bin 0 -> 5690 bytes qml/touch/images/darkclose.png | Bin 0 -> 3328 bytes qml/touch/images/magnifier.png | Bin 0 -> 3422 bytes src/applicationinfo.cpp | 193 +++++++++++++ src/applicationinfo.h | 139 ++++++++++ src/applicationpaths.h | 75 +++++ src/cities.cpp | 164 +++++++++++ src/cities.h | 92 +++++++ src/citieslistmodel.cpp | 125 +++++++++ src/citieslistmodel.h | 84 ++++++ src/citymodel.cpp | 302 +++++++++++++++++++++ src/citymodel.h | 138 ++++++++++ src/daymodel.cpp | 149 ++++++++++ src/daymodel.h | 116 ++++++++ src/main.cpp | 138 ++++++++++ src/src.pri | 16 ++ src/weatherimageprovider.h | 72 +++++ weatherapp.pro | 74 +++++ 94 files changed, 4692 insertions(+) create mode 100644 .gitignore create mode 100644 android/AndroidManifest.xml create mode 100644 android/res/drawable-hdpi/icon.png create mode 100644 android/res/drawable-ldpi/icon.png create mode 100644 android/res/drawable-mdpi/icon.png create mode 100644 app-icons/AppIcon_100px.png create mode 100644 app-icons/AppIcon_1024px.png create mode 100644 app-icons/AppIcon_114px.png create mode 100644 app-icons/AppIcon_120px.png create mode 100644 app-icons/AppIcon_144px.png create mode 100644 app-icons/AppIcon_152px.png create mode 100644 app-icons/AppIcon_29px.png create mode 100644 app-icons/AppIcon_36px.png create mode 100644 app-icons/AppIcon_40px.png create mode 100644 app-icons/AppIcon_48px.png create mode 100644 app-icons/AppIcon_50px.png create mode 100644 app-icons/AppIcon_512px.png create mode 100644 app-icons/AppIcon_57px.png create mode 100644 app-icons/AppIcon_58px.png create mode 100644 app-icons/AppIcon_72px.png create mode 100644 app-icons/AppIcon_76px.png create mode 100644 app-icons/AppIcon_80px.png create mode 100644 fonts/LICENSE.txt create mode 100644 fonts/OpenSans-Bold.ttf create mode 100644 fonts/OpenSans-Regular.ttf create mode 100644 fonts/OpenSans-Semibold.ttf create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_100px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_114px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_120px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_144px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_152px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_29px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_40px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_50px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_57px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_58px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_72px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_76px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/AppIcon_80px.png create mode 100644 ios/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Land.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Port.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Land.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Port.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Land.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Port.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Land.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Port.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/iphone_6.1.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R3.5.png create mode 100644 ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R4.png create mode 100644 ios/iosInfo.plist create mode 100644 ios/readme.txt create mode 100644 qml/js/utils.js create mode 100644 qml/main.qml create mode 100644 qml/models/SearchResultModel.qml create mode 100644 qml/models/WeatherModel.qml create mode 100644 qml/pages/BasicPage.qml create mode 100644 qml/pages/CitiesPage.qml create mode 100644 qml/pages/LongTermDayItem.qml create mode 100644 qml/pages/LongTermPage.qml create mode 100644 qml/pages/OneDayPage.qml create mode 100644 qml/pages/OneDaySliderItem.qml create mode 100644 qml/pages/OneDayZoomItem.qml create mode 100644 qml/pages/Separator.qml create mode 100644 qml/touch/ListViewDelegate.qml create mode 100644 qml/touch/Separator.qml create mode 100644 qml/touch/TouchLabel.qml create mode 100644 qml/touch/TouchScrollView.qml create mode 100644 qml/touch/TouchSlider.qml create mode 100644 qml/touch/TouchTextField.qml create mode 100644 qml/touch/images/BackArrow.png create mode 100644 qml/touch/images/Circle.png create mode 100644 qml/touch/images/Clear.png create mode 100644 qml/touch/images/Pointer.png create mode 100644 qml/touch/images/Pointer_pressed.png create mode 100644 qml/touch/images/darkclose.png create mode 100644 qml/touch/images/magnifier.png create mode 100644 src/applicationinfo.cpp create mode 100644 src/applicationinfo.h create mode 100644 src/applicationpaths.h create mode 100644 src/cities.cpp create mode 100644 src/cities.h create mode 100644 src/citieslistmodel.cpp create mode 100644 src/citieslistmodel.h create mode 100644 src/citymodel.cpp create mode 100644 src/citymodel.h create mode 100644 src/daymodel.cpp create mode 100644 src/daymodel.h create mode 100644 src/main.cpp create mode 100644 src/src.pri create mode 100644 src/weatherimageprovider.h create mode 100644 weatherapp.pro diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3a8700 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +Makefile +WeatherApp + +*.dll +*.exe +*.o +*.so +*.pro.user +*.qrc +*.wa +*.settings + +moc_*.cpp +qrc_*.cpp + diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000..7e189fd --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/res/drawable-hdpi/icon.png b/android/res/drawable-hdpi/icon.png new file mode 100644 index 0000000..4e95fc2 Binary files /dev/null and b/android/res/drawable-hdpi/icon.png differ diff --git a/android/res/drawable-ldpi/icon.png b/android/res/drawable-ldpi/icon.png new file mode 100644 index 0000000..17eb470 Binary files /dev/null and b/android/res/drawable-ldpi/icon.png differ diff --git a/android/res/drawable-mdpi/icon.png b/android/res/drawable-mdpi/icon.png new file mode 100644 index 0000000..ba69e8f Binary files /dev/null and b/android/res/drawable-mdpi/icon.png differ diff --git a/app-icons/AppIcon_100px.png b/app-icons/AppIcon_100px.png new file mode 100644 index 0000000..7ab56c9 Binary files /dev/null and b/app-icons/AppIcon_100px.png differ diff --git a/app-icons/AppIcon_1024px.png b/app-icons/AppIcon_1024px.png new file mode 100644 index 0000000..462c68c Binary files /dev/null and b/app-icons/AppIcon_1024px.png differ diff --git a/app-icons/AppIcon_114px.png b/app-icons/AppIcon_114px.png new file mode 100644 index 0000000..0fe60cb Binary files /dev/null and b/app-icons/AppIcon_114px.png differ diff --git a/app-icons/AppIcon_120px.png b/app-icons/AppIcon_120px.png new file mode 100644 index 0000000..0525a69 Binary files /dev/null and b/app-icons/AppIcon_120px.png differ diff --git a/app-icons/AppIcon_144px.png b/app-icons/AppIcon_144px.png new file mode 100644 index 0000000..ad5e348 Binary files /dev/null and b/app-icons/AppIcon_144px.png differ diff --git a/app-icons/AppIcon_152px.png b/app-icons/AppIcon_152px.png new file mode 100644 index 0000000..ad63eb3 Binary files /dev/null and b/app-icons/AppIcon_152px.png differ diff --git a/app-icons/AppIcon_29px.png b/app-icons/AppIcon_29px.png new file mode 100644 index 0000000..718b00e Binary files /dev/null and b/app-icons/AppIcon_29px.png differ diff --git a/app-icons/AppIcon_36px.png b/app-icons/AppIcon_36px.png new file mode 100644 index 0000000..2592625 Binary files /dev/null and b/app-icons/AppIcon_36px.png differ diff --git a/app-icons/AppIcon_40px.png b/app-icons/AppIcon_40px.png new file mode 100644 index 0000000..9a6aeda Binary files /dev/null and b/app-icons/AppIcon_40px.png differ diff --git a/app-icons/AppIcon_48px.png b/app-icons/AppIcon_48px.png new file mode 100644 index 0000000..2e4b199 Binary files /dev/null and b/app-icons/AppIcon_48px.png differ diff --git a/app-icons/AppIcon_50px.png b/app-icons/AppIcon_50px.png new file mode 100644 index 0000000..f2c3520 Binary files /dev/null and b/app-icons/AppIcon_50px.png differ diff --git a/app-icons/AppIcon_512px.png b/app-icons/AppIcon_512px.png new file mode 100644 index 0000000..74eb30a Binary files /dev/null and b/app-icons/AppIcon_512px.png differ diff --git a/app-icons/AppIcon_57px.png b/app-icons/AppIcon_57px.png new file mode 100644 index 0000000..2874aa9 Binary files /dev/null and b/app-icons/AppIcon_57px.png differ diff --git a/app-icons/AppIcon_58px.png b/app-icons/AppIcon_58px.png new file mode 100644 index 0000000..4b56cb7 Binary files /dev/null and b/app-icons/AppIcon_58px.png differ diff --git a/app-icons/AppIcon_72px.png b/app-icons/AppIcon_72px.png new file mode 100644 index 0000000..49a8bf4 Binary files /dev/null and b/app-icons/AppIcon_72px.png differ diff --git a/app-icons/AppIcon_76px.png b/app-icons/AppIcon_76px.png new file mode 100644 index 0000000..6a3ba5e Binary files /dev/null and b/app-icons/AppIcon_76px.png differ diff --git a/app-icons/AppIcon_80px.png b/app-icons/AppIcon_80px.png new file mode 100644 index 0000000..bf56b81 Binary files /dev/null and b/app-icons/AppIcon_80px.png differ diff --git a/fonts/LICENSE.txt b/fonts/LICENSE.txt new file mode 100644 index 0000000..75b5248 --- /dev/null +++ b/fonts/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/fonts/OpenSans-Bold.ttf b/fonts/OpenSans-Bold.ttf new file mode 100644 index 0000000..fd79d43 Binary files /dev/null and b/fonts/OpenSans-Bold.ttf differ diff --git a/fonts/OpenSans-Regular.ttf b/fonts/OpenSans-Regular.ttf new file mode 100644 index 0000000..db43334 Binary files /dev/null and b/fonts/OpenSans-Regular.ttf differ diff --git a/fonts/OpenSans-Semibold.ttf b/fonts/OpenSans-Semibold.ttf new file mode 100644 index 0000000..1a7679e Binary files /dev/null and b/fonts/OpenSans-Semibold.ttf differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_100px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_100px.png new file mode 100644 index 0000000..7ab56c9 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_100px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_114px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_114px.png new file mode 100644 index 0000000..0fe60cb Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_114px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_120px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_120px.png new file mode 100644 index 0000000..0525a69 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_120px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_144px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_144px.png new file mode 100644 index 0000000..ad5e348 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_144px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_152px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_152px.png new file mode 100644 index 0000000..ad63eb3 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_152px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_29px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_29px.png new file mode 100644 index 0000000..718b00e Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_29px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_40px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_40px.png new file mode 100644 index 0000000..9a6aeda Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_40px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_50px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_50px.png new file mode 100644 index 0000000..f2c3520 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_50px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_57px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_57px.png new file mode 100644 index 0000000..2874aa9 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_57px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_58px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_58px.png new file mode 100644 index 0000000..4b56cb7 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_58px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_72px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_72px.png new file mode 100644 index 0000000..49a8bf4 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_72px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_76px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_76px.png new file mode 100644 index 0000000..6a3ba5e Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_76px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_80px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_80px.png new file mode 100644 index 0000000..bf56b81 Binary files /dev/null and b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_80px.png differ diff --git a/ios/Images.xcassets/AppIcon.appiconset/Contents.json b/ios/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..afa67cd --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,104 @@ +{ + "images" : [ + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon_29px.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon_58px.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "AppIcon_80px.png", + "scale" : "2x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "AppIcon_57px.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "AppIcon_114px.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "AppIcon_120px.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon_29px.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon_58px.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon_40px.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon_80px.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "AppIcon_50px.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "AppIcon_100px.png", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "AppIcon_72px.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "AppIcon_144px.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon_76px.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon_152px.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Images.xcassets/LaunchImage.launchimage/Contents.json b/ios/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000..a685873 --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,107 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "iphone_7_R3.5.png", + "scale" : "2x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "retina4", + "filename" : "iphone_7_R4.png", + "minimum-system-version" : "7.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "ipad_7_Port.png", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "ipad_7_Land.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "ipad_7_R_Port.png", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "ipad_7_R_Land.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "iphone_6.1.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "iphone_7_R3.5.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "iphone_7_R4.png", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "NoSB_ipad_7_Port.png", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "NoSB_ipad_7_Land.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "NoSB_ipad_7_R_Port.png", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "to-status-bar", + "filename" : "NoSB_ipad_7_R_Land.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Land.png b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Land.png new file mode 100644 index 0000000..f5c1011 Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Land.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Port.png b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Port.png new file mode 100644 index 0000000..0cd0c65 Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Port.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Land.png b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Land.png new file mode 100644 index 0000000..10e007d Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Land.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Port.png b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Port.png new file mode 100644 index 0000000..8e90fd3 Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Port.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Land.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Land.png new file mode 100644 index 0000000..055975e Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Land.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Port.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Port.png new file mode 100644 index 0000000..b1b02da Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Port.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Land.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Land.png new file mode 100644 index 0000000..b149b62 Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Land.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Port.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Port.png new file mode 100644 index 0000000..3a660bf Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Port.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/iphone_6.1.png b/ios/Images.xcassets/LaunchImage.launchimage/iphone_6.1.png new file mode 100644 index 0000000..51fab95 Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/iphone_6.1.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R3.5.png b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R3.5.png new file mode 100644 index 0000000..c4130ac Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R3.5.png differ diff --git a/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R4.png b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R4.png new file mode 100644 index 0000000..fe97bdf Binary files /dev/null and b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R4.png differ diff --git a/ios/iosInfo.plist b/ios/iosInfo.plist new file mode 100644 index 0000000..6a26fee --- /dev/null +++ b/ios/iosInfo.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDisplayName + QuickForecast + CFBundleExecutable + QuickForecast + CFBundleGetInfoString + Created by Qt/QMake + CFBundleIcons + + CFBundleIcons~ipad + + CFBundleIdentifier + com.digia.qt.iosteam.WeatherApp + CFBundleName + Quick Forecast + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.1 + CFBundleSignature + ???? + CFBundleVersion + 1.1 + NOTE + This file was generated by Qt/QMake. + UIAppFonts + + fonts/OpenSans-Bold.ttf + fonts/OpenSans-Semibold.ttf + fonts/OpenSans-Regular.ttf + + UIStatusBarHidden + + UIStatusBarHidden~ipad + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ios/readme.txt b/ios/readme.txt new file mode 100644 index 0000000..a59fa72 --- /dev/null +++ b/ios/readme.txt @@ -0,0 +1,15 @@ +* In order to use the images assets: + +- After running qmake, open the Xcode project +- In the General tab of the project, go down to App Icons section +- Click for Source "use Asset Catalog" +- Validate by selecting Migrate +- In the pro file directory, replace Images.xcassets under QuickForecast +by the one under ios. + +=> The icons and launch images are ready to be used + +* Default image + +In Xcode, in the "Bundle Resources" section, remove the default launch +image. It is not needed. diff --git a/qml/js/utils.js b/qml/js/utils.js new file mode 100644 index 0000000..caa21ea --- /dev/null +++ b/qml/js/utils.js @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +.pragma library + +// LongTermPage utils + +function getAfternoonIndex(dayModel) +{ + var index = 0 + var count = intervalCount + if (count > 1) + index = count - 1 + return index +} + +function getTemp(isMax, dayModel) { + var temp = getTemperature(0, dayModel) + var count = dayModel.periodCount() + for (var i = 0; i < count; i++) { + var currentTemp = getTemperature(i, dayModel) + if (isMax) + temp = Math.max(temp, currentTemp) + else + temp = Math.min(temp, currentTemp) + } + return temp +} + +function getMinTemp(dayModel) +{ + return getTemp(false, dayModel) +} + +function getMaxTemp(dayModel) +{ + return getTemp(true, dayModel) +} + +function getTempFormat(temp) +{ + return temp + "°C" +} + +function isNegative(val) +{ + return val < 0 +} + +// OneDayPage utils + +function getFromTime(index, dayModel) { + var timerange = dayModel.getDayDetails(index, 'timeRange') + var pattern_time = /(.*) - .*/ + var time = timerange.replace(pattern_time, "$1") + return time +} + +function getToTime(index, dayModel) { + var timerange = dayModel.getDayDetails(index, 'timeRange') + var pattern_time = /.* - (.*)/ + var time = timerange.replace(pattern_time, "$1") + return time +} + +function getMaxMinTemp(dayModel) { + // at least 1 data per day + var minTemp = dayModel.getDayDetails(0, 'temperature') + var maxTemp = dayModel.getDayDetails(0, 'temperature') + for (var i = 1; i < dayModel.periodCount(); i++) + { + var tempTemp = dayModel.getDayDetails(i, 'temperature') + maxTemp = Math.max(tempTemp, maxTemp) + minTemp = Math.min(tempTemp, minTemp) + } + + return [minTemp, maxTemp] +} + +function getMaxTempLenght(cityModel) { + var maxLength = 1 + for (var indexDay = 0; indexDay < cityModel.daysCount(); indexDay++) { + var day = cityModel.getDayModel(indexDay) + var range = getMaxMinTemp(day) + maxLength = Math.max(range[0].toString().length, maxLength) + maxLength = Math.max(range[1].toString().length, maxLength) + } + var stringTemp = "555" // temperatures estimated between -55 and +55 + if (maxLength === 3) + stringTemp = "-" + stringTemp + return stringTemp.substring(0, maxLength) + "°C." +} + +// WeatherModel utils + +function getWindType(windspeed) +{ + var speed = parseFloat(windspeed) + if (speed <= 0.2) + return "Calm" // Calm + if (speed <= 1.5) + return "0000" // Light air + if (speed <= 3.3) + return "0025" // Light breeze + if (speed <= 5.4) + return "0050" // Glentle breeze + if (speed <= 7.9) + return "0075" // Moderate breeze + if (speed <= 10.7) + return "0100" // Fresh breeze + if (speed <= 13.8) + return "0125" // Strong breeze + if (speed <= 17.1) + return "0150" // Near gale + if (speed <= 18.0) + return "0175" // Near gale / Gale + if (speed <= 20.7) + return "0200" // Gale + if (speed <= 24.4) + return "0225" // Strong storm + if (speed <= 28.4) + return "0250" // Whole storm + if (speed <= 32.6) + return "0300" // Storm + return "0350" // Hurricane +} + +function updateDayModel(dayModel, item) +{ + var windIconUrl = getWindSymbolUrl(item.windSpeed, item.windDirectionDeg) + var weatherUrl = extractSymbolUrl(item.symbolcode) + var day = Qt.formatDate(new Date(dayModel.date), "dddd") + var timeRange = getTimeRange(item) + + dayModel.addRow(day, weatherUrl, timeRange, item.temperature, item.windSpeed, windIconUrl, item.rain, item.period) +} + +function getItemDate(item) +{ + var fromDateTime = parseDateTime(item.from) + var toDateTime = parseDateTime(item.to) + var date = (item.period === "0") ? toDateTime[0] : fromDateTime[0] + return date +} + +function getTimeRange(item) +{ + var fromDateTime = parseDateTime(item.from) + var toDateTime = parseDateTime(item.to) + var timeRange = fromDateTime[1] + " - " + toDateTime[1] + return timeRange +} + +function parseDateTime(dt) +{ + var pattern_date = /(.*)T.*/ + var pattern_time = /.*T([0-9][0-9]:[0-9][0-9]).*/ + var time = dt.replace(pattern_time, "$1") + var date = dt.replace(pattern_date, "$1") + return [date, time] +} + +function getWindSymbolUrl(windspeed, winddir) +{ + var windtype = getWindType(windspeed) + if (windtype === "Calm") + return "http://fil.nrk.no/yr/grafikk/vindpiler/32/vindstille.png" + + var iconurl = "http://fil.nrk.no/yr/grafikk/vindpiler/32/vindpil.TYPE.WINDDIRCODE.png" + var windcode = Math.round((parseFloat(winddir).toFixed(0)) / 5) * 5 + var codeLenght = windcode.toString().length; + for (var i = codeLenght; i < 3; i++) + windcode = "0" + windcode + + if (windcode === 360) + windcode = "000" + + iconurl = iconurl.replace("TYPE", windtype) + iconurl = iconurl.replace("WINDDIRCODE", windcode) + return iconurl +} + +function extractSymbolUrl(code) +{ + // In order to use yr.no weather data service, refer to their terms + // and conditions of use. http://om.yr.no/verdata/free-weather-data/ + var iconUrl = "http://symbol.yr.no/grafikk/sym/b100/__CODE__.png" + return iconUrl.replace("__CODE__", code) +} + +// Global + +function getDay(index, dayModel) +{ + var day = dayModel.getDayDetails(index, "day") + return day +} + +function getShortDate(date) +{ + return date.substr(8, 2) + "." + date.substr(5, 2) // dd.MM +} + +function getLongDate(date) +{ + return date.substr(8, 2) + "." + date.substr(5, 2) + "." + date.substr(0, 4) // dd.MM.yyyy +} + +function getRain(index, dayModel) +{ + return dayModel.getDayDetails(index, "rain") +} + +function getTemperature(index, dayModel) +{ + return dayModel.getDayDetails(index, "temperature") +} + +function getWindSpeed(index, dayModel) +{ + return dayModel.getDayDetails(index, "windSpeed") +} + +function getWindUrl(index, dayModel) +{ + var url = dayModel.getDayDetails(index, "windUrl") + return dayModel.getCachedImageFile(url) +} + +function getWeatherUrl(index, dayModel, size) +{ + var smallUrl = dayModel.getDayDetails(index, "weatherUrl") + if (size === "large") + smallUrl = smallUrl.replace("b100", "b200") + else + smallUrl = smallUrl + return dayModel.getCachedImageFile(smallUrl) +} + diff --git a/qml/main.qml b/qml/main.qml new file mode 100644 index 0000000..49720f7 --- /dev/null +++ b/qml/main.qml @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import org.qtproject.demo.weather 1.0 + +ApplicationWindow { + id: root + height: 700 + width: 1200 + title: qsTr("Quick Forecast") + + property string statusBarMessage + + property Component citiesPage: CitiesPage { + onUpdateStatusBar: statusBarMessage = message + onNextPage: if (!isLocked) { + isLocked = true + pageView.push(longTermPage) + clearSearchBox() + } + } + property Component longTermPage: LongTermPage { + onUpdateStatusBar: statusBarMessage = message + onNextPage: if (!isLocked) { + isLocked = true + pageView.push(oneDayPage) + } + onPreviousPage: { + ApplicationInfo.currentIndexDay = -1 + pageView.pop() + } + } + property Component oneDayPage: OneDayPage { + onUpdateStatusBar: statusBarMessage = message + onPreviousPage: if (!isLocked) { + isLocked = true + pageView.pop() + } + } + + StackView { + id: pageView + anchors.fill: parent + initialItem: citiesPage + delegate: StackViewDelegate { + pushTransition: StackViewTransition { + function transitionFinished(properties) + { + properties.exitItem.opacity = 1 + } + PropertyAnimation { + target: enterItem + property: "x" + from: target.width + to: 0 + duration: 500 + easing.type: Easing.OutSine + } + PropertyAnimation { + target: exitItem + property: "x" + from: 0 + to: -target.width + duration: 500 + easing.type: Easing.OutSine + } + } + popTransition: StackViewTransition { + function transitionFinished(properties) + { + properties.exitItem.opacity = 1 + } + PropertyAnimation { + target: enterItem + property: "x" + from: -target.width + to: 0 + duration: 500 + easing.type: Easing.OutSine + } + PropertyAnimation { + target: exitItem + property: "x" + from: 0 + to: target.width + duration: 500 + easing.type: Easing.OutSine + + } + } + property Component replaceTransition: pushTransition + } + } + + statusBar: StatusBar { + width: parent.width + opacity: label.text !== "" ? 1 : 0 + height: label.text !== "" ? 65 * ApplicationInfo.ratio : 0 + + Behavior on height { NumberAnimation {easing.type: Easing.OutSine}} + Behavior on opacity { NumberAnimation {}} + + style: StatusBarStyle { + padding { left: 0; right: 0 ; top: 0 ; bottom: 0} + property Component background: Rectangle { + implicitHeight: 65 * ApplicationInfo.ratio + implicitWidth: root.width + color: ApplicationInfo.colors.smokeGray + Rectangle { + width: parent.width + height: 1 + color: Qt.darker(parent.color, 1.5) + } + Rectangle { + y: 1 + width: parent.width + height: 1 + color: "white" + } + } + } + TouchLabel { + id: label + y: 32 * ApplicationInfo.ratio - height/2 + width: parent.width // The text will only wrap if an explicit width has been set + text: statusBarMessage + textFormat: Text.RichText + onLinkActivated: Qt.openUrlExternally(link) + wrapMode: Text.Wrap + pixelSize: 18 + letterSpacing: -0.15 + color: ApplicationInfo.colors.mediumGray + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + } + } +} diff --git a/qml/models/SearchResultModel.qml b/qml/models/SearchResultModel.qml new file mode 100644 index 0000000..95a871e --- /dev/null +++ b/qml/models/SearchResultModel.qml @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtQuick Enterprise Controls Demos. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 + +ListModel { + ListElement { sourceXml: "http://www.yr.no/place/Norway/Oslo/Oslo/Oslo/forecast.xml"; name: "Oslo"; country: "Norway"} + ListElement { sourceXml: "http://www.yr.no/place/France/Île-de-France/Paris/forecast.xml"; name: "Paris"; country: "France"} + ListElement { sourceXml: "http://www.yr.no/place/United_Kingdom/England/London/forecast.xml"; name: "London"; country: "United Kingdom"} + ListElement { sourceXml: "http://www.yr.no/place/Germany/Berlin/Berlin/forecast.xml"; name: "Berlin"; country: "Germany"} + ListElement { sourceXml: "http://www.yr.no/place/United_States/California/San_Francisco/forecast.xml"; name: "San Francisco"; country: "United States"} + ListElement { sourceXml: "http://www.yr.no/place/Italy/Lazio/Rome/forecast.xml"; name: "Rome"; country: "Italia"} + ListElement { sourceXml: "http://www.yr.no/place/Antarctica/Other/Vostok_Station/forecast.xml"; name: "Vostok Station"; country: "Antarctica"} + ListElement { sourceXml: "http://www.yr.no/place/Mali/Tombouctou/Timbuktu/forecast.xml"; name: "Timbuktu"; country: "Mali"} +} diff --git a/qml/models/WeatherModel.qml b/qml/models/WeatherModel.qml new file mode 100644 index 0000000..4ef3530 --- /dev/null +++ b/qml/models/WeatherModel.qml @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.XmlListModel 2.0 +import org.qtproject.demo.weather 1.0 +import "../js/utils.js" as Utils + +Item { + id: modelitem + signal error(string errorMessage) + signal showLongTerm() + + property var loadedCityModel + property string lastLoadedCity + + function getLongTermModel(model) + { + if (model.sourceXml !== lastLoadedCity || + standardmodel.xml !== model.contentXml || + model.daysCount() === 0) { + if (!!model) model.clear() + if (standardmodel.xml !== model.contentXml) { + standardmodel.xml = model.contentXml + } else { + if (!!standardmodel.get(0)) { + // no error on last loading + model.copyright = standardmodel.get(0).copyright + currentCityForecastModel.reload() + } else { + error("The saved xml file cannot be parsed") + } + } + loadedCityModel = model + } else { + showLongTerm() + } + lastLoadedCity = model.sourceXml + } + + XmlListModel { + id: standardmodel + property var city + query: "/weatherdata" + XmlRole { name: "copyright"; query: "credit/link/@text/string()"} + onStatusChanged : { + if (status === XmlListModel.Ready && count > 0) { + var item = get(0) + loadedCityModel.copyright = item.copyright + currentCityForecastModel.xml = xml + } else if ( status === XmlListModel.Error) { + error(errorString()) + } else if (status === XmlListModel.Ready && count == 0) { + error(qsTr("Can't parse the xml file")) + } + } + } + + XmlListModel { + id: currentCityForecastModel + query: "/weatherdata/forecast/tabular/time" + XmlRole { name: "from"; query: "@from/string()" } + XmlRole { name: "to"; query: "@to/string()" } + XmlRole { name: "period"; query: "@period/string()" } + XmlRole { name: "symbolcode"; query: "symbol/@var/string()" } + XmlRole { name: "windType"; query: "windSpeed/@name/string()" } + XmlRole { name: "windDirectionDeg"; query: "windDirection/@deg/string()" } + XmlRole { name: "windSpeed"; query: "windSpeed/@mps/string()" } + XmlRole { name: "temperature"; query: "temperature/@value/string()" } + XmlRole { name: "rain"; query: "precipitation/@value/string()" } + + onStatusChanged: { + if (status === XmlListModel.Ready && count > 0) { + for (var i=0; i page.width + when: !ApplicationInfo.isMobile + } + + Binding { + target: ApplicationInfo + property: "applicationWidth" + value: page.width + } + + Rectangle { + id: blueRect + z: 2 // so flickable doesn't draw on top + anchors.top: parent.top + height: 80 * ApplicationInfo.ratio + width: parent.width + color: page.Stack.index !== 0 && mouseBack.pressed ? + Qt.lighter(ApplicationInfo.colors.blue, 1.2) : ApplicationInfo.colors.blue + Rectangle { + color: Qt.lighter(parent.color, 1.2) + height: 1 + anchors.bottom: parent.bottom + anchors.bottomMargin: 1 + width: parent.width + } + Rectangle { + z: 2 // so flickable doesn't draw on top + height: 1 + width: parent.width + color: Qt.darker(ApplicationInfo.colors.blue, 1.6) + anchors.bottom: parent.bottom + } + + RowLayout { + id: titleRow + anchors.left: parent.left + anchors.right: parent.right + spacing: 0 + anchors.verticalCenter: parent.verticalCenter + Separator {} + Image { + source: ApplicationInfo.getImagePath("BackArrow.png") + Layout.preferredWidth: 22 * ApplicationInfo.ratio + Layout.preferredHeight: 35 * ApplicationInfo.ratio + visible: page.Stack.index > 0 + } + Rectangle { + opacity: 0 + Layout.preferredWidth: 20 * ApplicationInfo.ratio + Layout.fillHeight: true + visible: page.Stack.index > 0 + } + TouchLabel { + id: t1 + text: title1 + " " + color: ApplicationInfo.colors.white + pixelSize: 30 + font.weight: Font.Bold + Layout.maximumWidth: ApplicationInfo.applicationWidth - t3.implicitWidth - 2 * ApplicationInfo.hMargin - 5 * ApplicationInfo.ratio - 42 * ApplicationInfo.ratio + Layout.alignment: Qt.AlignBaseline + } + TouchLabel { + text: "- " + title2 + color: ApplicationInfo.colors.white + visible: title2 !== "" + pixelSize: 22 + letterSpacing: -0.15 + Layout.alignment: Qt.AlignBaseline + Layout.maximumWidth: freeSpace > implicitWidth ? freeSpace : 0 + property real freeSpace: ApplicationInfo.applicationWidth - t1.width - t3.implicitWidth - 2 * ApplicationInfo.hMargin - 5 * ApplicationInfo.ratio - 42 * ApplicationInfo.ratio + } + Item { + Layout.fillWidth: true + height: 0 + } + TouchLabel { + id: t3 + text: title3 + color: ApplicationInfo.colors.white + visible: title3 !== "" + pixelSize: 22 + letterSpacing: -0.15 + Layout.alignment: Qt.AlignBaseline + } + Separator {} + } + Rectangle { + width: parent.width + height: 5 + anchors.top: parent.bottom + gradient: Gradient { + GradientStop {position: 0 ; color: "#40000000"} + GradientStop {position: 1 ; color: "#00000000"} + } + } + MouseArea { + id: mouseBack + anchors.fill: parent + onClicked: if (!isLocked) page.previousPage() + } + } + + TouchTextField { + id: searchField + z: 2 + visible: page.Stack.index === 0 ? 1 : 0 + anchors.right: blueRect.right + anchors.top: blueRect.top + anchors.bottom: blueRect.bottom + width: ApplicationInfo.isPortraitMode ? + parent.width - t1.implicitWidth - ApplicationInfo.ratio * 50 : + parent.width/2.5 + anchors.leftMargin: blueRect.width/2 + anchors.rightMargin: 20 * ApplicationInfo.ratio + anchors.margins: 12 * ApplicationInfo.ratio + + placeholderText: qsTr("Find City") + Layout.fillWidth: true + Keys.onReturnPressed: page.searchBoxReturn() + Keys.onEnterPressed: page.searchBoxReturn() + onClearButtonClicked: page.clearSearchBox() + } + + Loader { + sourceComponent: pageComponent + anchors.top: blueRect.bottom + anchors.bottom: parent.bottom + width: parent.width + Rectangle { + z: -1 + anchors.fill: parent + color: ApplicationInfo.colors.white + } + } +} diff --git a/qml/pages/CitiesPage.qml b/qml/pages/CitiesPage.qml new file mode 100644 index 0000000..e5caec8 --- /dev/null +++ b/qml/pages/CitiesPage.qml @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import org.qtproject.demo.weather 1.0 + +BasicPage { + id: page1 + title1: qsTr("Cities") + + signal cityDeleted(string city) + property int selected: -1 + + Binding { + target: page1 + property: "pageComponent" + value: listViewComponent + when: hasNoSearchText + } + Binding { + target: page1 + property: "pageComponent" + value: searchViewComponent + when: !hasNoSearchText + } + + onSearchTextChanged : ApplicationInfo.queryCities(searchText) + + property Component searchViewComponent: TouchScrollView { + flickableItem.interactive: true + flickableItem.flickableDirection: Flickable.VerticalFlick + ListView { + interactive: true + flickableDirection: Flickable.VerticalFlick + model: ApplicationInfo.foundCities + delegate: ListViewDelegate { + isSearchView: true + onClicked: validateSearchIndex(index) + } + } + } + property Component listViewComponent: TouchScrollView { + flickableItem.interactive: true + flickableItem.flickableDirection: Flickable.VerticalFlick + ListView { + id: listview + model: availableCities + interactive: true + flickableDirection: Flickable.VerticalFlick + delegate: ListViewDelegate { + onClicked: page1.processCity(index) + onDeleteCity: availableCities.removeCityModel(index) + } + currentIndex: page1.selected + TouchLabel { + z: 1 + anchors.centerIn: parent + visible: listview.count === 0 + text: "No Cities" + color: ApplicationInfo.colors.lightGray + } + } + } + + Connections { + target: ApplicationInfo + onWaitForCitiesQueryReply: if (ApplicationInfo.isMobile) updateStatusBar(message) + onErrorOnQueryCities: updateStatusBar(errorMessage) + } + + onSearchBoxReturn: validateSearchIndex(0) + onClearSearchBox: { + searchText = "" + blueRect.forceActiveFocus() // attempt to clear focus in TextField + Qt.inputMethod.hide() + } + function validateSearchIndex(index) { + + if (!ApplicationInfo.foundCities.isEmpty) { + // get sourcexml at index + var foundIndex = availableCities.processSourceXml(ApplicationInfo.foundCities.getCitySourceXml(index)) + if (foundIndex > -1) + processCity(foundIndex) + } + clearSearchBox() + } + function processCity(index) + { + if (!isLocked) { + page1.selected = index + ApplicationInfo.currentCityModel = availableCities.getCityModel(index) + nextPage() + } + } + + Cities { id: availableCities } + + Connections { + target: Qt.application + onStateChanged: if (ApplicationInfo.constants.isMobile && Qt.application.state === Qt.ApplicationSuspended) availableCities.saveCities() + } + + Stack.onStatusChanged: { + isLocked = !(Stack.status === Stack.Active) + if (Stack.status === Stack.Activating) + updateStatusBar("") + } +} diff --git a/qml/pages/LongTermDayItem.qml b/qml/pages/LongTermDayItem.qml new file mode 100644 index 0000000..6053cca --- /dev/null +++ b/qml/pages/LongTermDayItem.qml @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import "../js/utils.js" as Utils +import org.qtproject.demo.weather 1.0 + +Rectangle { + id: day + Layout.preferredHeight: 118 * ApplicationInfo.ratio + Layout.preferredWidth: scrollview.viewport.width - 5 + + signal next + property bool last + property var dayModel: ApplicationInfo.currentCityModel.getDayModel(index) + + color: mouse.pressed ? ApplicationInfo.colors.smokeGray : ApplicationInfo.colors.white + + MouseArea { + id: mouse + anchors.fill: parent + onClicked: { + ApplicationInfo.currentIndexDay = index + next() + } + } + RowLayout { + anchors.fill: parent + spacing: 0 + Separator {} + TouchLabel { + id: shortDay + Layout.preferredWidth: expectedTextWidth("Wed.") + text: Utils.getDay(0, dayModel).substr(0, 3) + font.weight: Font.DemiBold + Layout.alignment: Qt.AlignBaseline + } + TouchLabel { + Layout.preferredWidth: expectedTextWidth("00.00") + text: Utils.getShortDate(dayModel.date) + pixelSize: 20 + letterSpacing: -0.15 + Layout.alignment: Qt.AlignBaseline + } + Separator { + Layout.fillHeight: true + Layout.fillWidth: true + Layout.minimumHeight: 5 + Layout.minimumWidth: 5 + } + Image { + source: Utils.getWeatherUrl(dayModel.afternoonIndex, dayModel) + property int weatherIconSize: 80 * ApplicationInfo.ratio + Layout.preferredHeight: weatherIconSize + Layout.preferredWidth: weatherIconSize + onStatusChanged: if (status === Image.Error) updateStatusBar(ApplicationInfo.constants.errorLoadingImage + ": " + source) + } + Separator { + Layout.fillHeight: true + Layout.fillWidth: true + Layout.minimumHeight: 5 + Layout.minimumWidth: 5 + } + TouchLabel { + Layout.preferredWidth: expectedTextWidth(Utils.getMaxTempLenght(ApplicationInfo.currentCityModel)) + property string temp: Utils.getMinTemp(dayModel) + text: Utils.getTempFormat(temp) + color: temp < 0 ? ApplicationInfo.colors.blue : ApplicationInfo.colors.doubleDarkGray + Layout.alignment: Qt.AlignBaseline + } + Rectangle { + id: separator2 + Layout.preferredWidth: 1 + Layout.preferredHeight: day.height/5 + color: ApplicationInfo.colors.lightGray + } + TouchLabel { + Layout.preferredWidth: expectedTextWidth(Utils.getMaxTempLenght(ApplicationInfo.currentCityModel)) + property int temp: Utils.getMaxTemp(dayModel) + text: Utils.getTempFormat(temp) + horizontalAlignment: Qt.AlignRight + color: temp < 0 ? ApplicationInfo.colors.blue : ApplicationInfo.colors.doubleDarkGray + Layout.alignment: Qt.AlignBaseline + } + Separator { + Layout.fillHeight: true + Layout.fillWidth: true + Layout.minimumHeight: 5 + Layout.minimumWidth: 5 + } + Image { + property int windIconSize: 32 * ApplicationInfo.ratio + source: Utils.getWindUrl(dayModel.afternoonIndex, dayModel) + Layout.preferredHeight: windIconSize + Layout.preferredWidth: windIconSize + onStatusChanged: if (status === Image.Error) updateStatusBar(ApplicationInfo.constants.errorLoadingImage + ": " + source) + } + TouchLabel { + Layout.preferredWidth: expectedTextWidth("10.0") + text: Utils.getWindSpeed(dayModel.afternoonIndex, dayModel) + pixelSize: 24 + Layout.alignment: Qt.AlignBaseline + } + TouchLabel { + text: qsTr("m/s") + pixelSize: 18 + Layout.alignment: Qt.AlignBaseline + } + Separator {} + } + Rectangle { + width: parent.width + height: 1 + visible: !last + color: ApplicationInfo.colors.paleGray + } +} diff --git a/qml/pages/LongTermPage.qml b/qml/pages/LongTermPage.qml new file mode 100644 index 0000000..938b78d --- /dev/null +++ b/qml/pages/LongTermPage.qml @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import org.qtproject.demo.weather 1.0 + +BasicPage { + id: page2 + title1: ApplicationInfo.currentCityModel.cityNameDisplay + title2: ApplicationInfo.currentCityModel.countryName + title3: qsTr("10 Days Forecast") + + property bool cityLoaded: false + + onCityLoadedChanged: updateStatusBar(ApplicationInfo.currentCityModel.copyright + " (source)") + + isLocked: true + + pageComponent: Item { + TouchScrollView { + id: scrollview + anchors.fill: parent + flickableItem.interactive: true + flickableItem.flickableDirection: Flickable.VerticalFlick + ColumnLayout { + id: layout + spacing: 0 + Repeater { + id: repeat + model: cityLoaded ? ApplicationInfo.currentCityModel.daysCount() : null + LongTermDayItem { + Layout.fillWidth: true + last: index === repeat.count + onNext: nextPage() + } + } + } + } + + Rectangle { + anchors.fill: parent + opacity: cityLoaded ? 0 : 1 + Behavior on opacity { NumberAnimation{}} + TouchLabel { + id: label + opacity: cityLoaded ? 0 : 1 + Behavior on opacity { NumberAnimation{} } + anchors.centerIn: parent + text: qsTr("Loading data...") + horizontalAlignment: Text.AlignCenter + verticalAlignment: Text.AlignTop + pixelSize: 28 + color: ApplicationInfo.colors.mediumGray + height: label.implicitHeight + 80 * ApplicationInfo.ratio + BusyIndicator { + opacity: 0.8 + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + height: implicitHeight * ApplicationInfo.ratio + width: implicitWidth * ApplicationInfo.ratio + } + } + } + } + + Connections { + id: cityModelConnection + target: ApplicationInfo.currentCityModel + onError: { + cityLoaded = false + isLocked = false + previousPage() + updateStatusBar(errorMessage) + } + onContentXmlChanged: weathermodel.getLongTermModel(ApplicationInfo.currentCityModel) + } + + WeatherModel { + id: weathermodel + onShowLongTerm: { + isLocked = false + cityLoaded = true + } + onError: { + cityLoaded = false + lastLoadedCity = "" + isLocked = false + previousPage() + updateStatusBar(qsTr("Problem loading the data: ") + errorMessage) + } + } + + Stack.onStatusChanged: if (Stack.status === Stack.Active) + ApplicationInfo.currentCityModel.loadData() +} diff --git a/qml/pages/OneDayPage.qml b/qml/pages/OneDayPage.qml new file mode 100644 index 0000000..8264899 --- /dev/null +++ b/qml/pages/OneDayPage.qml @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.0 +import org.qtproject.demo.weather 1.0 +import "../js/utils.js" as Utils + +BasicPage { + id : page3 + title1: ApplicationInfo.currentCityModel.cityNameDisplay + title2: ApplicationInfo.currentCityModel.countryName + + property QtObject dayModel: ApplicationInfo.currentCityModel.getDayModel(ApplicationInfo.currentIndexDay) + + onDayModelChanged: if (!!dayModel) { + if (ApplicationInfo.currentIndexDay === 0) + title3 = qsTr("Today") + else if (ApplicationInfo.currentIndexDay === 1) + title3 = qsTr("Tomorrow") + else + title3 = Utils.getDay(0, dayModel) + " " + Utils.getLongDate(dayModel.date) + } + + pageComponent: GridLayout { + id: splitview + flow: !ApplicationInfo.isPortraitMode ? GridLayout.LeftToRight : GridLayout.TopToBottom + property bool singleItem: sliderItem.slider.minimumValue === sliderItem.slider.maximumValue + Separator { + Layout.fillHeight: true + Layout.fillWidth: true + } + OneDayZoomItem { + id: zoom + slider: sliderItem.slider + model: page3.dayModel + singleItem: splitview.singleItem + } + Separator { + Layout.fillHeight: true + Layout.fillWidth: true + implicitHeight: 10 * ApplicationInfo.ratio + implicitWidth: 10 * ApplicationInfo.ratio + Layout.minimumWidth: 0 + Layout.minimumHeight: 0 + visible: !singleItem + } + OneDaySliderItem { + id: sliderItem + visible: !singleItem + model: page3.dayModel + } + Separator { + Layout.fillHeight: true + Layout.fillWidth: true + } + } + + Stack.onStatusChanged: isLocked = !(Stack.status === Stack.Active) + +} diff --git a/qml/pages/OneDaySliderItem.qml b/qml/pages/OneDaySliderItem.qml new file mode 100644 index 0000000..dfd51db --- /dev/null +++ b/qml/pages/OneDaySliderItem.qml @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import "../js/utils.js" as Utils +import org.qtproject.demo.weather 1.0 + +GridLayout { + id: root + flow: ApplicationInfo.isPortraitMode ? GridLayout.LeftToRight : GridLayout.TopToBottom + + property alias slider: touchSlider + property QtObject model + + Separator { + Layout.fillHeight: true + Layout.fillWidth: ApplicationInfo.isPortraitMode ? true : false + Layout.minimumHeight: 10 + } + Canvas { + id: canvasSlider + Layout.alignment: Qt.AlignHCenter + + property int drawingOffset: ApplicationInfo.sliderGapWidth + property var rangeTemp: Utils.getMaxMinTemp(model) + + implicitWidth: touchSlider.width + 2 * drawingOffset + implicitHeight: 3.8*drawingOffset + + property int marginsTemperaturesDrawing: calibrate(rangeTemp[1]) + 10 * ApplicationInfo.ratio + property real circleIconWidth: 20 * ApplicationInfo.ratio + property real weatherIconWidth: 80 * ApplicationInfo.ratio + + function calibrate(temperature) { + return 2 * ApplicationInfo.ratio * temperature + } + + antialiasing: true + smooth: true + onPaint: { + var ctx = getContext('2d') + var count = model.periodCount() + ctx.save() + ctx.beginPath(); + ctx.fillStyle = ApplicationInfo.colors.doubleDarkGray + ctx.lineWidth = 1 + ctx.translate(touchSlider.x, marginsTemperaturesDrawing + weatherIconWidth + 15 * ApplicationInfo.ratio + circleIconWidth/2) + ctx.moveTo(drawingOffset/2, 0) + for (var i = 0; i < count; i++) { + ctx.moveTo((i + .5 )* drawingOffset, 0) + var temperatureStart = canvasSlider.calibrate(Utils.getTemperature(i, model)) + var temperatureEnd = canvasSlider.calibrate(Utils.getTemperature(i + 1, model)) + ctx.moveTo((i + 1 )* drawingOffset, -temperatureStart) + if ( (i+1) < count) + ctx.lineTo((i + 2) * drawingOffset, -temperatureEnd) + } + ctx.stroke() + ctx.closePath() + ctx.restore(); + } + Repeater { + id: repeater + model: root.model.periodCount() + Column { + x: (index + 1.5) * ApplicationInfo.sliderGapWidth - canvasSlider.weatherIconWidth/2 - canvasSlider.circleIconWidth/2 + y: -canvasSlider.calibrate(temperature) + canvasSlider.marginsTemperaturesDrawing + property int temperature: Utils.getTemperature(index, root.model) + height: parent.height + id: col + Image { + source: Utils.getWeatherUrl(index, root.model) + width: canvasSlider.weatherIconWidth + height: width + anchors.horizontalCenter: col.horizontalCenter + } + Item { + height: 15 * ApplicationInfo.ratio + width: height + } + Image { + id: circle + source: ApplicationInfo.getImagePath("Circle.png") + width: canvasSlider.circleIconWidth + height: width + anchors.horizontalCenter: col.horizontalCenter + } + Item { + height: 15 * ApplicationInfo.ratio + width: height + } + TouchLabel { + text: Utils.getTempFormat(temperature) + pixelSize: 24 + color: temperature > 0 ? ApplicationInfo.colors.doubleDarkGray : ApplicationInfo.colors.blue + anchors.horizontalCenter: col.horizontalCenter + } + } + } + ColumnLayout { + id: column + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + TouchSlider { + id: touchSlider + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.preferredWidth: (model.periodCount() - 1) * canvasSlider.drawingOffset + ApplicationInfo.sliderHandleWidth + minimumValue: 0 + maximumValue: model.periodCount() - 1 + } + RowLayout { + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + Layout.preferredWidth: model.periodCount() * canvasSlider.drawingOffset + ApplicationInfo.sliderHandleWidth + spacing: 0 + Repeater { + model: root.model.periodCount() + 1 + TouchLabel { + pixelSize: 24 + Layout.fillWidth: true + horizontalAlignment: Qt.AlignHCenter + Layout.alignment: Qt.AlignBaseline + text: (!!root.model && index !== root.model.periodCount()) ? Utils.getFromTime(index, root.model) : Utils.getToTime(index-1, root.model) + } + } + } + } + + } + Separator { + Layout.fillHeight: true + Layout.fillWidth: ApplicationInfo.isPortraitMode ? true : false + Layout.minimumHeight: 10 + } +} diff --git a/qml/pages/OneDayZoomItem.qml b/qml/pages/OneDayZoomItem.qml new file mode 100644 index 0000000..5e2af42 --- /dev/null +++ b/qml/pages/OneDayZoomItem.qml @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import "../js/utils.js" as Utils +import org.qtproject.demo.weather 1.0 + +GridLayout { + id: root + flow: ApplicationInfo.isPortraitMode ? GridLayout.LeftToRight : GridLayout.TopToBottom + + property QtObject slider + property QtObject model + property bool singleItem + property string singleTimeString: "(" + Utils.getFromTime(0, dayModel) + " - " + Utils.getToTime(0, dayModel) + ")" + + Separator { + Layout.fillHeight: true + Layout.fillWidth: ApplicationInfo.isPortraitMode ? true : false + } + GridLayout { + id: grid + rowSpacing: 0 + columnSpacing: 15 * ApplicationInfo.ratio + columns: 3 + TouchLabel { + id: longDay + text : Utils.getDay(root.slider.value, root.model) + font.weight: Font.Bold + Layout.alignment: Qt.AlignBaseline + } + TouchLabel { + text: Utils.getLongDate(root.model.date) + pixelSize: 30 + Layout.alignment: Qt.AlignBaseline | Qt.AlignLeft + color: ApplicationInfo.colors.darkGray + } + TouchLabel { + text: root.singleItem ? root.singleTimeString : "" + pixelSize: 20 + horizontalAlignment: Text.AlignRight + Layout.alignment: Qt.AlignBaseline + color: ApplicationInfo.colors.darkGray + } + Item { + Image { + id: mainIcon + source: Utils.getWeatherUrl(Math.round(root.slider.value), root.model, "large") + onStatusChanged: if (status === Image.Error) updateStatusBar(ApplicationInfo.constants.errorLoadingImage + ": " + source) + anchors.centerIn: parent + width: parent.width + height: parent.height + onSourceChanged: anim.running = true + anchors.verticalCenterOffset: offset + property real offset: 0 + ParallelAnimation { + id: anim + alwaysRunToEnd: true + NumberAnimation { + target: mainIcon + property: "offset" + from: -30 + to: 0 + duration: 500 + easing.type: Easing.OutCubic + } + NumberAnimation { + target: mainIcon + property: "opacity" + from: 0 + to: 1 + duration: 300 + } + } + } + + Layout.rowSpan: 1 + Layout.preferredHeight: 200 * ApplicationInfo.ratio + Layout.preferredWidth: 200 * ApplicationInfo.ratio + Layout.alignment: Qt.AlignCenter + } + TouchLabel { + Layout.preferredWidth: expectedTextWidth(Utils.getMaxTempLenght(ApplicationInfo.currentCityModel)) + property int temp: Utils.getTemperature(root.slider.value, root.model) + text : temp + qsTr("°C") + color: temp < 0 ? ApplicationInfo.colors.blue : ApplicationInfo.colors.doubleDarkGray + pixelSize: 72 + letterSpacing: -0.5 + Layout.alignment: Qt.AlignLeft + } + RowLayout { + Layout.columnSpan: 3 + TouchLabel { + id: rainLabel + text : qsTr("Rain: ") + Utils.getRain(root.slider.value, root.model) + Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline + pixelSize: 30 + } + TouchLabel { + text : qsTr("mm") + pixelSize: 24 + Layout.alignment: Qt.AlignBaseline | Qt.AlignLeft + } + } + RowLayout { + Layout.columnSpan: 3 + TouchLabel { + id: windLabel + text : qsTr("Wind: ") + Utils.getWindSpeed(root.slider.value, root.model) + " " + Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline + pixelSize: 30 + } + TouchLabel { + text : qsTr("m/s") + pixelSize: 24 + Layout.alignment: Qt.AlignLeft | Qt.AlignBaseline + } + Image { + source: Utils.getWindUrl(root.slider.value, root.model) + property int windIconSize: 45 * ApplicationInfo.ratio + Layout.preferredHeight: windIconSize + Layout.preferredWidth: windIconSize + onStatusChanged: if (status === Image.Error) updateStatusBar(ApplicationInfo.constants.errorLoadingImage + ": " + source) + Layout.alignment: Qt.AlignLeft + } + } + } + Separator { + Layout.fillHeight: true + Layout.fillWidth: ApplicationInfo.isPortraitMode ? true : false + } +} diff --git a/qml/pages/Separator.qml b/qml/pages/Separator.qml new file mode 100644 index 0000000..78c1f9f --- /dev/null +++ b/qml/pages/Separator.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import org.qtproject.demo.weather 1.0 + +Rectangle { + implicitHeight: ApplicationInfo.hMargin + implicitWidth: ApplicationInfo.hMargin + Layout.minimumHeight: implicitHeight + Layout.minimumWidth: implicitWidth + opacity: 0 +} diff --git a/qml/touch/ListViewDelegate.qml b/qml/touch/ListViewDelegate.qml new file mode 100644 index 0000000..eecce49 --- /dev/null +++ b/qml/touch/ListViewDelegate.qml @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import org.qtproject.demo.weather 1.0 + +Rectangle { + id: rect + height: 118 * ApplicationInfo.ratio + width: parent.width + signal clicked + signal deleteCity + + property bool isSearchView: false + + color: mouseNext.pressed ? ApplicationInfo.colors.smokeGray : ApplicationInfo.colors.white + + GridLayout { + id: _grid + anchors.fill: parent + flow: Qt.LeftToRight + rowSpacing: 4 * ApplicationInfo.ratio + columnSpacing: 0 + columns: 2 + Rectangle { + Layout.preferredWidth: ApplicationInfo.hMargin + Layout.fillHeight: true + opacity: 0 + } + Loader { + sourceComponent: isSearchView ? searchViewRow : cityViewRow + Layout.fillHeight: true + Layout.fillWidth: true + } + Rectangle { + id: separator + Layout.fillWidth: true + Layout.fillHeight: true + Layout.columnSpan: 2 + } + } + Rectangle { + z: 1 + height: 1 + anchors.bottom: parent.bottom + width: parent.width + color: ApplicationInfo.colors.paleGray + } + MouseArea { + id: mouseNext + anchors.left: parent.left + width: parent.width - 80 * ApplicationInfo.ratio - ApplicationInfo.hMargin + height: parent.height + onClicked: rect.clicked() + } + + property Component searchViewRow: RowLayout { + spacing: 0 + TouchLabel { + color: ApplicationInfo.colors.mediumGray + id: countryLabel + text: country + pixelSize: 28 + Layout.alignment: Qt.AlignBaseline + Layout.fillWidth: true + Layout.maximumWidth: rect.width - 2 * ApplicationInfo.hMargin + } + Rectangle { + Layout.preferredWidth: ApplicationInfo.hMargin + Layout.fillHeight: true + opacity: 0 + } + } + + property Component cityViewRow: RowLayout { + spacing: 0 + TouchLabel { + id: city + text: name + font.weight: Font.DemiBold + Layout.maximumWidth: maximumWidth * 2 + Layout.alignment: Qt.AlignBaseline + } + Item { + implicitWidth: 12 * ApplicationInfo.ratio + Layout.minimumWidth: implicitWidth + } + TouchLabel { + color: ApplicationInfo.colors.mediumGray + id: countryLabel + text: country + pixelSize: 28 + Layout.alignment: Qt.AlignBaseline | Qt.AlignLeft + Layout.fillWidth: true + Layout.minimumWidth: 0 + } + MouseArea { + id: deleteMouse + implicitWidth: 110 * ApplicationInfo.ratio + implicitHeight: 110 * ApplicationInfo.ratio + Layout.minimumWidth: implicitWidth + onClicked: if (!isSearchView) rect.deleteCity() + Image { + id: imageRemove + anchors.centerIn: parent + source: ApplicationInfo.getImagePath("darkclose.png") + width: 31 * ApplicationInfo.ratio + height: 31 * ApplicationInfo.ratio + } + Rectangle { + anchors.fill: parent + color: ApplicationInfo.colors.smokeGray + opacity: deleteMouse.pressed ? 1 : 0 + z: -1 + radius: 8 + } + } + } +} diff --git a/qml/touch/Separator.qml b/qml/touch/Separator.qml new file mode 100644 index 0000000..dd7516e --- /dev/null +++ b/qml/touch/Separator.qml @@ -0,0 +1,29 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the QtQuick Enterprise Controls Demos. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Layouts 1.0 +import org.qtproject.demo.weather 1.0 + +Rectangle { + Layout.minimumWidth: SystemInfo.hMargin + Layout.minimumHeight: SystemInfo.hMargin + opacity: 0 +} diff --git a/qml/touch/TouchLabel.qml b/qml/touch/TouchLabel.qml new file mode 100644 index 0000000..bea6b3b --- /dev/null +++ b/qml/touch/TouchLabel.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import org.qtproject.demo.weather 1.0 + +Label { + id: label + property int pixelSize: 34 + property real letterSpacing: -0.25 + + font.family: "Open Sans" + font.pixelSize: pixelSize * ApplicationInfo.ratio * 1.1 // increasing fonts + font.letterSpacing: letterSpacing * ApplicationInfo.ratio + color: ApplicationInfo.colors.doubleDarkGray + verticalAlignment: Text.AlignBottom + horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + linkColor: ApplicationInfo.colors.blue + + function expectedTextWidth(value) + { + dayText.text = value + return dayText.width + } + + property int maximumWidth: (ApplicationInfo.constants.isMobile ? ApplicationInfo.applicationWidth : 1120) / 4 + Layout.minimumWidth: Math.min(Layout.maximumWidth, implicitWidth + 1) + + Text { + id: dayText + visible: false + font.family: label.font.family + font.pixelSize: label.font.pixelSize + font.letterSpacing: label.font.letterSpacing + wrapMode: label.wrapMode + elide: label.elide + } +} diff --git a/qml/touch/TouchScrollView.qml b/qml/touch/TouchScrollView.qml new file mode 100644 index 0000000..5d2c211 --- /dev/null +++ b/qml/touch/TouchScrollView.qml @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import org.qtproject.demo.weather 1.0 + +ScrollView { + frameVisible: false + style: ScrollViewStyle { + property int handleWidth: 20 * ApplicationInfo.ratio + transientScrollBars: true + padding{ top: 4 ; bottom: 4 ; right: 4} + property bool hovered: false + } + Rectangle { + anchors.fill: parent + color: ApplicationInfo.colors.white + } +} diff --git a/qml/touch/TouchSlider.qml b/qml/touch/TouchSlider.qml new file mode 100644 index 0000000..6969239 --- /dev/null +++ b/qml/touch/TouchSlider.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import org.qtproject.demo.weather 1.0 + +Slider { + id: slider + implicitHeight: ApplicationInfo.sliderHandleHeight + ApplicationInfo.ratio * 25 + style: SliderStyle { + groove: Rectangle { + Rectangle { + id: beforeHandle + width: control.value * ApplicationInfo.sliderGapWidth + ApplicationInfo.sliderHandleWidth/2 + height: 20 * ApplicationInfo.ratio + color: ApplicationInfo.colors.blue + radius: 90 + z: -1 + } + Rectangle { + id: afterHandle + anchors.left: beforeHandle.right + anchors.right: parent.right + height: 20 * ApplicationInfo.ratio + color: ApplicationInfo.colors.darkGray + radius: 90 + z: -1 + } + } + handle: Item { + width: ApplicationInfo.sliderHandleWidth + height: ApplicationInfo.sliderHandleHeight + Image { + anchors.centerIn: parent + source: ApplicationInfo.getImagePath(control.pressed ? "Pointer_pressed.png" : "Pointer.png") + width: ApplicationInfo.sliderHandleWidth + 16 * ApplicationInfo.ratio + height: ApplicationInfo.sliderHandleHeight + 16 * ApplicationInfo.ratio + } + } + } +} diff --git a/qml/touch/TouchTextField.qml b/qml/touch/TouchTextField.qml new file mode 100644 index 0000000..9e0ffb0 --- /dev/null +++ b/qml/touch/TouchTextField.qml @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import org.qtproject.demo.weather 1.0 + +TextField { + id: textfield + signal clearButtonClicked + implicitWidth: parent.width + property bool isEmpty: true + style: TextFieldStyle { + background : + Rectangle { + radius: 8 + border.width: 1 + border.color: Qt.darker(ApplicationInfo.colors.blue, 1.6) + color: ApplicationInfo.colors.white + gradient: Gradient { + GradientStop { position: 0 ; color: "#ddd"} + GradientStop { position: 0.05 ; color: "#fff"} + } + + implicitHeight: 60 * ApplicationInfo.ratio + opacity: 1 + } + padding.left : (12 + 50) * ApplicationInfo.ratio + padding.right: (12 + 50) * ApplicationInfo.ratio + font.pixelSize: 28 * ApplicationInfo.ratio + font.family: "Open Sans" + font.letterSpacing: -0.25 * ApplicationInfo.ratio + selectedTextColor : ApplicationInfo.colors.lightGray + selectionColor : ApplicationInfo.colors.darkBlue + textColor : ApplicationInfo.colors.mediumGray + } + + Item { + id: item + anchors.left: parent.left + anchors.top: parent.top + height: parent.height + width: parent.height + Image { + opacity: 0.9 + anchors.centerIn: item + height: iconSize + width: iconSize + source: ApplicationInfo.getImagePath("magnifier.png") + property int iconSize: 50 * ApplicationInfo.ratio + } + } + + onTextChanged: isEmpty = (text === "") + inputMethodHints: Qt.ImhNoPredictiveText + MouseArea { + z: 2 + opacity: !textfield.isEmpty ? 1 : 0 + Behavior on opacity {NumberAnimation{}} + anchors.right: parent.right + anchors.rightMargin: 4 * ApplicationInfo.ratio + anchors.top: parent.top + height: parent.height + width: parent.height + Image { + anchors.centerIn: parent + source: ApplicationInfo.getImagePath("Clear.png") + property int iconSize: 40 * ApplicationInfo.ratio + opacity: parent.pressed ? 1 : 0.9 + width: iconSize + height: iconSize + } + onClicked: textfield.clearButtonClicked() + } +} + diff --git a/qml/touch/images/BackArrow.png b/qml/touch/images/BackArrow.png new file mode 100644 index 0000000..9070d0f Binary files /dev/null and b/qml/touch/images/BackArrow.png differ diff --git a/qml/touch/images/Circle.png b/qml/touch/images/Circle.png new file mode 100644 index 0000000..7b229ec Binary files /dev/null and b/qml/touch/images/Circle.png differ diff --git a/qml/touch/images/Clear.png b/qml/touch/images/Clear.png new file mode 100644 index 0000000..883dffd Binary files /dev/null and b/qml/touch/images/Clear.png differ diff --git a/qml/touch/images/Pointer.png b/qml/touch/images/Pointer.png new file mode 100644 index 0000000..45b075e Binary files /dev/null and b/qml/touch/images/Pointer.png differ diff --git a/qml/touch/images/Pointer_pressed.png b/qml/touch/images/Pointer_pressed.png new file mode 100644 index 0000000..776e0d1 Binary files /dev/null and b/qml/touch/images/Pointer_pressed.png differ diff --git a/qml/touch/images/darkclose.png b/qml/touch/images/darkclose.png new file mode 100644 index 0000000..2f90820 Binary files /dev/null and b/qml/touch/images/darkclose.png differ diff --git a/qml/touch/images/magnifier.png b/qml/touch/images/magnifier.png new file mode 100644 index 0000000..42033b5 Binary files /dev/null and b/qml/touch/images/magnifier.png differ diff --git a/src/applicationinfo.cpp b/src/applicationinfo.cpp new file mode 100644 index 0000000..dcbc54f --- /dev/null +++ b/src/applicationinfo.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "applicationinfo.h" +#include "weatherimageprovider.h" +#include + +ApplicationInfo::ApplicationInfo(WeatherImageProvider *provider) + : imageProvider(provider) +{ + + m_isMobile = false; +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_BLACKBERRY) + m_isMobile = true; +#endif + + m_colors = new QQmlPropertyMap(this); + m_colors->insert(QLatin1String("white"), QVariant("#ffffff")); + m_colors->insert(QLatin1String("smokeGray"), QVariant("#eeeeee")); + m_colors->insert(QLatin1String("paleGray"), QVariant("#d7d6d5")); + m_colors->insert(QLatin1String("lightGray"), QVariant("#aeadac")); + m_colors->insert(QLatin1String("darkGray"), QVariant("#35322f")); + m_colors->insert(QLatin1String("mediumGray"), QVariant("#5d5b59")); + m_colors->insert(QLatin1String("doubleDarkGray"), QVariant("#1e1b18")); + m_colors->insert(QLatin1String("blue"), QVariant("#14aaff")); + m_colors->insert(QLatin1String("darkBlue"), QVariant("#14148c")); + + m_constants = new QQmlPropertyMap(this); + m_constants->insert(QLatin1String("isMobile"), QVariant(m_isMobile)); + m_constants->insert(QLatin1String("errorLoadingImage"), QVariant(tr("Error loading image - Host not found or unreachable"))); + + manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); + m_citiesFound = new CitiesListModel(this); + + QRect rect = qApp->primaryScreen()->geometry(); + m_ratio = m_isMobile ? qMin(qMax(rect.width(), rect.height())/1136. , qMin(rect.width(), rect.height())/640.) : 1; + m_sliderHandleWidth = getSizeWithRatio(70); + m_sliderHandleHeight = getSizeWithRatio(87); + m_sliderGapWidth = getSizeWithRatio(100); + m_isPortraitMode = m_isMobile ? rect.height() > rect.width() : false; + m_hMargin = m_isPortraitMode ? 20 * ratio() : 50 * ratio(); + m_applicationWidth = m_isMobile ? rect.width() : 1120; + + m_currentIndexDay = -1; + + if (m_isMobile) + connect(qApp->primaryScreen(), SIGNAL(physicalSizeChanged(QSizeF)), this, SLOT(notifyPortraitMode())); + + // Search in English + // In order to use yr.no weather data service, refer to their terms + // and conditions of use. http://om.yr.no/verdata/free-weather-data/ + QUrl searchUrl2("http://www.yr.no/_/settspr.aspx"); + QUrlQuery query2; + query2.addQueryItem("spr", "eng"); + query2.addQueryItem("redir", "/"); + searchUrl2.setQuery(query2); + manager->get(QNetworkRequest(searchUrl2)); +} + +void ApplicationInfo::setCurrentCityModel(CityModel *model) +{ + if (model != m_currentCityModel) + { + m_currentCityModel = model; + emit currentCityModelChanged(); + } +} + +void ApplicationInfo::setCurrentIndexDay(const int index) +{ + if (index != m_currentIndexDay) { + m_currentIndexDay = index; + emit currentIndexDayChanged(); + } +} + +void ApplicationInfo::setApplicationWidth(const int newWidth) +{ + if (newWidth != m_applicationWidth) { + m_applicationWidth = newWidth; + emit applicationWidthChanged(); + } +} + +QString ApplicationInfo::getImagePath(const QString image) +{ + return QString("qrc:/weatherapp/qml/touch/images/%1").arg(image); +} + +void ApplicationInfo::notifyPortraitMode() +{ + int width = qApp->primaryScreen()->geometry().width(); + int height = qApp->primaryScreen()->geometry().height(); + setIsPortraitMode(height > width); +} + +void ApplicationInfo::setIsPortraitMode(const bool newMode) +{ + if (m_isPortraitMode != newMode) { + m_isPortraitMode = newMode; + m_hMargin = m_isPortraitMode ? 20 * ratio() : 50 * ratio(); + emit portraitModeChanged(); + emit hMarginChanged(); + } +} + +void ApplicationInfo::queryCities(const QString input) +{ + if (input.isEmpty()) + return; + // In order to use yr.no weather data service, refer to their terms + // and conditions of use. http://om.yr.no/verdata/free-weather-data/ + QUrl searchUrl("http://www.yr.no/_/websvc/jsonforslagsboks.aspx"); + QUrlQuery query; + query.addQueryItem("s", input); + searchUrl.setQuery(query); + manager->get(QNetworkRequest(searchUrl)); + m_citiesFound->clear(); + waitForCitiesQueryReply(tr("Waiting for cities, network may be slow...")); +} + +void ApplicationInfo::replyFinished(QNetworkReply *reply) +{ + waitForCitiesQueryReply(""); + if (reply->request().url().query() != "spr=eng&redir=/" ) { + if (reply->error() != QNetworkReply::NoError) { + emit(errorOnQueryCities(tr("Network error: %1").arg(reply->errorString()))); + m_citiesFound->addCities(); + } else { + QString data = reply->readAll(); + QRegExp regExp; + regExp.setPattern("^\\[\\[.*\\],\\[\\[(.*)\\]\\]\\]$"); + regExp.exactMatch(data); + QString foundCities = regExp.capturedTexts().at(1); + QStringList citiesFound = foundCities.split(QRegExp("\\],\\["), QString::SkipEmptyParts); + m_citiesFound->addCities(citiesFound); + } + } + if (reply) { + reply->deleteLater(); + reply = 0; + } +} + diff --git a/src/applicationinfo.h b/src/applicationinfo.h new file mode 100644 index 0000000..4e001dd --- /dev/null +++ b/src/applicationinfo.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef APPLICATIONINFO_H +#define APPLICATIONINFO_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QNetworkAccessManager; +class QNetworkReply; +QT_END_NAMESPACE + +class WeatherImageProvider; + +#include "citymodel.h" +#include "citieslistmodel.h" + +class ApplicationInfo : public QObject +{ + Q_OBJECT + Q_PROPERTY(int applicationWidth READ applicationWidth WRITE setApplicationWidth NOTIFY applicationWidthChanged) + Q_PROPERTY(QObject *colors READ colors CONSTANT) + Q_PROPERTY(QObject *constants READ constants CONSTANT) + Q_PROPERTY(bool isPortraitMode READ isPortraitMode WRITE setIsPortraitMode NOTIFY portraitModeChanged) + Q_PROPERTY(int currentIndexDay READ currentIndexDay WRITE setCurrentIndexDay NOTIFY currentIndexDayChanged) + Q_PROPERTY(CityModel *currentCityModel READ currentCityModel WRITE setCurrentCityModel NOTIFY currentCityModelChanged) + Q_PROPERTY(CitiesListModel *foundCities READ foundCities NOTIFY foundCitiesChanged) + Q_PROPERTY(qreal ratio READ ratio NOTIFY ratioChanged) + Q_PROPERTY(qreal hMargin READ hMargin NOTIFY hMarginChanged) + Q_PROPERTY(qreal sliderHandleWidth READ sliderHandleWidth NOTIFY ratioChanged) + Q_PROPERTY(qreal sliderHandleHeight READ sliderHandleHeight NOTIFY ratioChanged) + Q_PROPERTY(qreal sliderGapWidth READ sliderGapWidth NOTIFY ratioChanged) + +public: + ApplicationInfo(WeatherImageProvider *provider); + + QQmlPropertyMap *colors() const { return m_colors; } + QQmlPropertyMap *constants() const { return m_constants; } + + CityModel *currentCityModel() const { return m_currentCityModel; } + void setCurrentCityModel(CityModel *model); + + int applicationWidth() const { return m_applicationWidth; } + void setApplicationWidth(const int newWidth); + + int currentIndexDay() const { return m_currentIndexDay; } + void setCurrentIndexDay(const int index); + + bool isPortraitMode() const { return m_isPortraitMode; } + void setIsPortraitMode(const bool newMode); + + CitiesListModel *foundCities() { return m_citiesFound; } + + qreal hMargin() const { return m_hMargin; } + qreal ratio() const { return m_ratio; } + qreal sliderHandleHeight() { return m_sliderHandleHeight; } + qreal sliderGapWidth() { return m_sliderGapWidth; } + qreal sliderHandleWidth() { return m_sliderHandleWidth; } + + Q_INVOKABLE QString getImagePath(const QString image); + Q_INVOKABLE void queryCities(const QString input); + +protected slots: + void notifyPortraitMode(); + +private slots: + void replyFinished(QNetworkReply *reply); + +protected: + qreal getSizeWithRatio(const qreal height) { return ratio() * height; } + +signals: + void applicationWidthChanged(); + void portraitModeChanged(); + void hMarginChanged(); + void currentCityModelChanged(); + void currentIndexDayChanged(); + void foundCitiesChanged(); + void ratioChanged(); + void waitForCitiesQueryReply(const QString message); + void errorOnQueryCities(const QString errorMessage); + +private: + int m_applicationWidth; + QQmlPropertyMap *m_colors; + QQmlPropertyMap *m_constants; + CityModel *m_currentCityModel; + bool m_isPortraitMode; + int m_currentIndexDay; + QNetworkAccessManager *manager; + CitiesListModel *m_citiesFound; + bool m_isMobile; + qreal m_ratio; + qreal m_hMargin; + qreal m_sliderHandleHeight, m_sliderHandleWidth, m_sliderGapWidth; + WeatherImageProvider *imageProvider; +}; + +#endif // APPLICATIONINFO_H diff --git a/src/applicationpaths.h b/src/applicationpaths.h new file mode 100644 index 0000000..efce270 --- /dev/null +++ b/src/applicationpaths.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef APPLICATIONPATHS_H +#define APPLICATIONPATHS_H + +#include +#include +#include +#include + +class ApplicationPaths +{ +public: + inline static QString settingsPath() + { + return getPath(QStandardPaths::DataLocation); + } + inline static QString dowloadedFilesPath() + { + return getPath(QStandardPaths::CacheLocation); + } +protected: + + inline static QString getPath(QStandardPaths::StandardLocation location) + { + QString path = QStandardPaths::standardLocations(location).value(0); + QDir dir(path); + if (!dir.exists()) + dir.mkpath(path); + if (!path.isEmpty() && !path.endsWith("/")) + path += "/"; + return path; + } +}; + +#endif // APPLICATIONPATHS_H diff --git a/src/cities.cpp b/src/cities.cpp new file mode 100644 index 0000000..b91c276 --- /dev/null +++ b/src/cities.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "cities.h" +#include "citymodel.h" +#include "applicationpaths.h" +#include + +Cities::Cities(QObject *parent) : + QAbstractListModel(parent) +{ + m_citiesFileName = QString("%1cities.settings").arg(ApplicationPaths::settingsPath()); + readCities(); +} + +Cities::~Cities() +{ + saveCities(); +} + +CityModel* Cities::getCityModel(int index) +{ + Q_ASSERT(index > -1); + Q_ASSERT(index < m_cityMap.count()); + return m_cityMap.at(index).second; +} + +void Cities::removeCityModel(int index) +{ + if (index < m_cityMap.count() && index >=0 ) + { + beginRemoveRows(QModelIndex(), index, index); + CityModel *modelToDelete = m_cityMap.at(index).second; + modelToDelete->cleanAll(); + modelToDelete->deleteLater(); + m_cityMap.removeAt(index); + endRemoveRows(); + } +} + +int Cities::addCityModel(CityModel *model) +{ + CityModelPair pair = qMakePair(model->sourceXml(), model); + int modelIndex = m_cityMap.indexOf(pair); + if (modelIndex == -1) { + m_cityMap.prepend(pair); + connect(model, SIGNAL(contentXmlChanged()), this, SIGNAL(cityModelReady())); + if (m_cityMap.count() > 15) + removeCityModel(m_cityMap.count() - 1); + return 0; + } + return modelIndex; +} + +void Cities::readCities() +{ + QFile file(m_citiesFileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + return; + QTextStream in(&file); + while (!in.atEnd()) { + QString sourceXml = in.readLine().trimmed(); + processSourceXml(sourceXml); + } + file.close(); +} + +int Cities::processSourceXml(const QString sourceXml) +{ + // Dont add save town/identical sourceXml twice + for (int i = 0; i setSourceXml(sourceXml)) + return addCityModel(model); + + model->deleteLater(); + return -1; +} + +void Cities::saveCities() +{ + QFile file(m_citiesFileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + QTextStream out(&file); + for (int index = m_cityMap.count()-1; index >= 0; index--) + out << m_cityMap.at(index).first << endl; + file.close(); +} + +QVariant Cities::data(const QModelIndex & index, int role) const +{ + CityModel *model = m_cityMap.at(index.row()).second; + if (model) { + switch (role) { + case CityNameRole: + return model->cityNameDisplay().replace("_", " "); + case CountryRole: + return model->countryName().replace("_", " "); + } + } + return QVariant(); +} + +int Cities::rowCount(const QModelIndex & /*parent*/) const +{ + return m_cityMap.count(); +} + +QHash Cities::roleNames() const +{ + QHash rn; + rn[CityNameRole] = "name"; + rn[CountryRole] = "country"; + return rn; +} diff --git a/src/cities.h b/src/cities.h new file mode 100644 index 0000000..6839074 --- /dev/null +++ b/src/cities.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CITIES_H +#define CITIES_H + +#include +#include +#include +#include + +class CityModel; + +typedef QPair CityModelPair; + +class Cities : public QAbstractListModel +{ + Q_OBJECT +public: + enum { + CityNameRole = Qt::UserRole + 1, + CountryRole = Qt::UserRole + 2 + }; + + Cities(QObject *parent = 0); + ~Cities(); + + Q_INVOKABLE CityModel* getCityModel(const int index); + Q_INVOKABLE void removeCityModel(const int index); + int addCityModel(CityModel *model); + Q_INVOKABLE int processSourceXml(const QString sourceXml); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QHash roleNames() const; + int rowCount(const QModelIndex & parent = QModelIndex()) const; + Q_INVOKABLE void saveCities(); + +protected: + void readCities(); + +signals: + void cityModelReady(); + void modelChanged(const int index); + +private: + QString m_wantedCity; + QString m_citiesFileName; + QString m_cachePath; + QList m_cityMap; +}; + +QML_DECLARE_TYPE(Cities) + +#endif // CITIES_H diff --git a/src/citieslistmodel.cpp b/src/citieslistmodel.cpp new file mode 100644 index 0000000..e86bd0d --- /dev/null +++ b/src/citieslistmodel.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "citieslistmodel.h" +#include + +CitiesListModel::CitiesListModel(QObject *parent) : + QAbstractListModel(parent), m_isEmpty(true) +{ +} + +QVariant CitiesListModel::data(const QModelIndex & index, int role) const +{ + Q_ASSERT(index.row() < m_foundCities.count()); + if (role == CountryRole) + return QString(m_foundCities.at(index.row()).first).replace("_", " "); + else + return QVariant(""); +} + +int CitiesListModel::rowCount(const QModelIndex & /*parent*/) const +{ + return m_foundCities.count(); +} + +QString CitiesListModel::getCitySourceXml(const int index) +{ + Q_ASSERT(index > -1); + Q_ASSERT(index < m_foundCities.count()); + CityXmlPair pair = m_foundCities.at(index); + // In order to use yr.no weather data service, refer to their terms + // and conditions of use. http://om.yr.no/verdata/free-weather-data/ + return QString("http://www.yr.no%1forecast.xml").arg(pair.second); +} + +void CitiesListModel::addCities(QStringList listCities) +{ + clear(); + QList temp; + if (!listCities.empty()) { + for (int i = 0; i < listCities.count(); i++) + { + QRegExp regExp2; + regExp2.setPattern("^\"(.*)\",\"(.*)\",\"(.*)\",\"(.*)\"$"); + regExp2.exactMatch(listCities.at(i)); + QString cityName = regExp2.capturedTexts().at(1); + QString countryName = regExp2.capturedTexts().at(3); + QString xml = regExp2.capturedTexts().at(2); + QRegExp regExp3; + regExp3.setPattern("^/place/.*/.*/.*/$"); + if (countryName.isEmpty() || countryName.contains("Municipality") || !regExp3.exactMatch(xml)) + continue; // We want cities forecast only + QString name = cityName + " - " + countryName; + temp.append(qMakePair(name, xml)); + } + } + + if (!temp.isEmpty()) { + beginInsertRows(QModelIndex(), 0, temp.count() - 1); + m_foundCities.append(temp); + m_isEmpty = false; + } else { + beginInsertRows(QModelIndex(), 0, 0); + m_foundCities.append(qMakePair(tr("no city found"), QString(""))); + } + + endInsertRows(); +} + +void CitiesListModel::clear() +{ + m_isEmpty = true; + if (m_foundCities.count() > 0) { + beginRemoveRows(QModelIndex(), 0, m_foundCities.count() - 1); + m_foundCities.clear(); + endRemoveRows(); + } +} + +QHash CitiesListModel::roleNames() const +{ + QHash rn; + rn[CountryRole] = "country"; + rn[NameRole] = "name"; // needed to use in delegate that read both roles (country and name) + return rn; +} + diff --git a/src/citieslistmodel.h b/src/citieslistmodel.h new file mode 100644 index 0000000..7120620 --- /dev/null +++ b/src/citieslistmodel.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CITIESLISTMODEL_H +#define CITIESLISTMODEL_H + +#include +#include +#include +#include +#include + +typedef QPair CityXmlPair; + +class CitiesListModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged) +public: + enum { + NameRole = Qt::UserRole + 1, + CountryRole = Qt::UserRole + 2 + }; + CitiesListModel(QObject *parent = 0); + + Q_INVOKABLE QString getCitySourceXml(const int index); + void addCities(QStringList listCities = QStringList()); + + bool isEmpty() const { return m_isEmpty; } + + void clear(); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + Q_INVOKABLE int rowCount(const QModelIndex & parent = QModelIndex()) const; + QHash roleNames() const; + +signals: + void isEmptyChanged(); + +private: + QList m_foundCities; + bool m_isEmpty; +}; + +QML_DECLARE_TYPE(CitiesListModel) + +#endif // CITIESLISTMODEL_H diff --git a/src/citymodel.cpp b/src/citymodel.cpp new file mode 100644 index 0000000..9056398 --- /dev/null +++ b/src/citymodel.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "citymodel.h" +#include "applicationpaths.h" +#include + +CityModel::CityModel(QObject *parent) : + QObject(parent), m_timeStamp(0) +{ + manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(replyFinished(QNetworkReply*))); + connect(this, SIGNAL(ready()), this, SLOT(readXml())); +} + +void CityModel::setCopyright(const QString copyright) +{ + if (copyright != m_copyright) { + m_copyright = copyright; + emit copyrightChanged(); + } +} + +bool CityModel::setSourceXml(const QString xml) +{ + if (xml != m_sourceXml) { + QRegExp regExp; + // will reject invalid xml string + regExp.setPattern("^http://www\\.yr\\.no/place/(([^/]*)/.*/([^/]*))/forecast\\.xml$"); + if (!regExp.exactMatch(xml)) + return false; + m_sourceXml = xml; + + // get city name, country and filename from sourceXml + QStringList list = regExp.capturedTexts(); + setCityNameDisplay(list.at(3)); + setCountryName(list.at(2)); + QString tempFileName = regExp.capturedTexts().at(1); + tempFileName = tempFileName.replace(QString("/"), QString("_")); + m_filename = QString("%1%2.wa").arg(ApplicationPaths::dowloadedFilesPath()).arg(tempFileName); + emit sourceXmlChanged(); + } + return true; +} + +void CityModel::setCityNameDisplay(QString name) +{ + int pos = name.indexOf("~"); + if ( pos > 0) + name.truncate(pos); + + if (name != m_cityNameDisplay) { + m_cityNameDisplay = name; + emit cityNameDisplayChanged(); + } +} + +QString CityModel::cityNameDisplay() const +{ + QString cityName = m_cityNameDisplay; + return cityName.replace("_", " "); +} + +void CityModel::setCountryName(const QString name) +{ + if (name != m_countryName) { + m_countryName = name; + emit countryNameChanged(); + } +} + +QString CityModel::countryName() const +{ + QString countryName = m_countryName; + return countryName.replace("_", " "); +} + +void CityModel::setError(const QString errorMessage) +{ + // Always emit error message + emit error(tr("Network error: ") + errorMessage); +} + +QVariant CityModel::data(const QModelIndex & /*index*/, int role) const +{ + if (role == CityNameDisplayRole) + return m_cityNameDisplay; + return QVariant(); +} + +QHash CityModel::roleNames() const +{ + QHash rn; + rn[CityNameDisplayRole] = "name"; + return rn; +} + +void CityModel::clear() +{ + m_copyright = QString(); + m_timeStamp = 0; + for (int i = 0; i < m_citydata.count(); i++) { + DayModel *temp = m_citydata.takeAt(i); + temp->clear(); + temp->deleteLater(); + } + m_citydata.clear(); +} + +void CityModel::cleanAll() +{ + clear(); + // Clear eventual cached file + QFile file(m_filename); + if (file.exists()) + file.remove(); +} + +void CityModel::addDayModel(DayModel *newDayModel) +{ + m_citydata.append(newDayModel); + connect(newDayModel, SIGNAL(addedImages(QStringList)), this, SLOT(addImages(QStringList))); +} + +void CityModel::addImages(const QStringList images) +{ + for (int i = 0; i < images.count(); i++) + downloadImage(images.at(i)); +} + +DayModel* CityModel::getDayModel(QString date) +{ + for (int i = 0; i < m_citydata.count(); i++) { + if ( m_citydata.at(i)->getDate() == date ) + return m_citydata.at(i); + } + return 0; +} + +DayModel* CityModel::getDayModel(int indexDay) +{ + Q_ASSERT(indexDay > -1); + Q_ASSERT(indexDay < m_citydata.count()); + return m_citydata.at(indexDay); +} + +void CityModel::refreshData() +{ + if (sourceXml() == QString()) { + qWarning("Warning: source xml not set"); + return; + } + QNetworkRequest request; + request.setUrl(QUrl(sourceXml())); + request.setRawHeader("Accept", "application/xml,*/*"); + manager->get(request); +} + +void CityModel::loadData() +{ + Q_ASSERT(!m_filename.isEmpty()); + QFile file(m_filename); + m_timeStamp = 0; + if (file.exists() && file.open(QIODevice::ReadOnly)) { + m_timeStamp = QString(file.readLine().trimmed()).toLongLong(); + file.close(); + } + if (dataExpired(m_timeStamp)) + refreshData(); + else + emit ready(); +} + +bool CityModel::dataExpired(qint64 timeStamp) { + // 10 minutes caching + qint64 tenMinutesMSecs = 10 * 60 * 1000; + qint64 timeElapsed = QDateTime::currentMSecsSinceEpoch() - timeStamp; + return timeStamp == 0 || timeElapsed > tenMinutesMSecs; +} + +void CityModel::replyFinished(QNetworkReply *reply) +{ + if (reply->error() != QNetworkReply::NoError) { + setError(reply->errorString()); + } else { + QString requestUrl = reply->request().url().toString(); + if (requestUrl.endsWith(".xml")) { + QByteArray data = reply->readAll(); + if (!data.isEmpty()) { + data.prepend("\n"); + data.prepend(QByteArray::number(QDateTime::currentMSecsSinceEpoch(), 'f', 0)); + QFile file(m_filename); + if (file.open(QIODevice::WriteOnly)) { + file.write(data); + file.close(); + emit ready(); + } else { + setError(file.errorString()); + } + } else { + setError(tr("No data at given url")); + } + } else { // download image + QString filename = getImageFileName(reply->url().toString()); + QByteArray data = reply->readAll(); + if (!data.isEmpty()) { + QFile file(filename); + if (!file.exists() && file.open(QIODevice::WriteOnly)) { + file.write(data); + file.close(); + } + } + } + } + if (reply) { + reply->deleteLater(); + reply = 0; + } +} + +void CityModel::downloadImage(const QString imageUrl) +{ + QString filename = getImageFileName(imageUrl); + QFile file(filename); + if (!file.exists()) { + QNetworkRequest request; + request.setUrl(QUrl(imageUrl)); + manager->get(request); + } +} + +QString CityModel::getImageFileName(const QString url) +{ + bool isLargeImage = url.contains("b200"); + QString filename = url.right(url.length() - url.lastIndexOf("/") - 1); + if (isLargeImage) + filename.prepend("large_"); + filename = QString("%1%2").arg(ApplicationPaths::dowloadedFilesPath()).arg(filename); + return filename; +} + +void CityModel::readXml() +{ + QFile file(m_filename); + QString content; + if (file.open(QIODevice::ReadOnly)) { + m_timeStamp = QString(file.readLine().trimmed()).toLongLong(); + m_contentXml = QString(file.readAll()); + emit contentXmlChanged(); // always emit this signal + file.close(); + } else { + setError(file.errorString()); + } +} diff --git a/src/citymodel.h b/src/citymodel.h new file mode 100644 index 0000000..34d40ec --- /dev/null +++ b/src/citymodel.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CITYMODEL_H +#define CITYMODEL_H + +#include +#include +#include +#include + +#include "daymodel.h" + +QT_BEGIN_NAMESPACE +class QNetworkAccessManager; +class QNetworkReply; +QT_END_NAMESPACE + +class CityModel : public QObject +{ + Q_OBJECT + Q_ENUMS(Status) + Q_PROPERTY(QString copyright READ copyright WRITE setCopyright NOTIFY copyrightChanged) + Q_PROPERTY(QString cityNameDisplay READ cityNameDisplay NOTIFY cityNameDisplayChanged) + Q_PROPERTY(QString countryName READ countryName NOTIFY countryNameChanged) + Q_PROPERTY(QString sourceXml READ sourceXml NOTIFY sourceXmlChanged) + Q_PROPERTY(QString contentXml READ contentXml NOTIFY contentXmlChanged) + +public: + enum { + CityNameDisplayRole = Qt::UserRole + 1 + }; + + CityModel(QObject *parent = 0); + + void setError(const QString msg); + + QString copyright() const { return m_copyright;} + void setCopyright(const QString copyright); + + QString cityNameDisplay() const; + void setCityNameDisplay(QString name); + + QString countryName() const; + void setCountryName(const QString name); + + QString sourceXml() const { return m_sourceXml; } + bool setSourceXml(const QString xml); + + QString contentXml() const { return m_contentXml; } + + QVariant data(const QModelIndex &index, int role) const; + QHash roleNames() const; + + Q_INVOKABLE int daysCount() const { return m_citydata.count(); } + Q_INVOKABLE void loadData(); + Q_INVOKABLE void clear(); + Q_INVOKABLE void addDayModel(DayModel *newDayModel); + Q_INVOKABLE DayModel* getDayModel(QString dayName); + Q_INVOKABLE DayModel* getDayModel(int indexDay); + + void cleanAll(); + + void downloadImage(const QString imageUrl); + +private: + void refreshData(); + bool dataExpired(qint64 timeStamp); + QString getImageFileName(const QString url); + +private Q_SLOTS: + void replyFinished(QNetworkReply*); + void readXml(); + void addImages(const QStringList images); + +Q_SIGNALS: + void copyrightChanged(); + void countryNameChanged(); + void error(const QString errorMessage); + void sourceXmlChanged(); + void contentXmlChanged(); + void cityNameDisplayChanged(); + void fileNameChanged(); + void ready(); + +private: + QString m_copyright; + QString m_countryName, m_contentXml; + qreal m_timeStamp; + QList m_citydata; + QNetworkAccessManager *manager; + QString m_filename; + QString m_url; + QString m_sourceXml; + QString m_cityNameDisplay; +}; + +QML_DECLARE_TYPE(CityModel) + +#endif // CITYMODEL_H diff --git a/src/daymodel.cpp b/src/daymodel.cpp new file mode 100644 index 0000000..a0ae9ac --- /dev/null +++ b/src/daymodel.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "daymodel.h" +#include "applicationpaths.h" +#include + +DayModel::DayModel() + : QObject(), m_afternoonindex(0) { +} + +QVariant DayModel::data(const QModelIndex &index, int role) const +{ + if (role == DayRole) + return m_data.at(index.row()).day; + if (role == WeatherUrlRole) + return m_data.at(index.row()).weatherUrl; + if (role == TimeRangeRole) + return m_data.at(index.row()).timeRange; + if (role == TemperatureRole) + return m_data.at(index.row()).temperature; + if (role == WindSpeedRole) + return m_data.at(index.row()).windSpeed; + if (role == WindUrlRole) + return m_data.at(index.row()).windUrl; + if (role == RainRole) + return m_data.at(index.row()).rain; + return QVariant(); +} + +QHash DayModel::roleNames() const +{ + QHash rn; + rn[DayRole] = "day"; + rn[WeatherUrlRole] = "weatherUrl"; + rn[TimeRangeRole] = "timeRange"; + rn[TemperatureRole] = "temperature"; + rn[WindSpeedRole] = "windSpeed"; + rn[WindUrlRole] = "windUrl"; + rn[RainRole] = "rain"; + return rn; +} + +void DayModel::clear() +{ + m_date = QString(); + m_afternoonindex = 0; + m_data.clear(); +} + +void DayModel::addRow(QString day, QString weatherUrl, QString timeRange, QString temperature, QString windSpeed, QString windUrl, QString rain) { + QStringList m_images; + DayModelStructure temp; + temp.day = day; + temp.weatherUrl = weatherUrl; + m_images.append(weatherUrl); + QString largeWeatherIconUrl = weatherUrl; + m_images.append(largeWeatherIconUrl.replace("b100", "b200")); + temp.timeRange = timeRange; + temp.temperature = temperature; + temp.windSpeed = windSpeed; + temp.windUrl = windUrl; + m_images.append(windUrl); + temp.rain = rain; + m_data.append(temp); + emit addedImages(m_images); +} + +QUrl DayModel::getCachedImageFile(const QString url) +{ + bool isLargeImage = url.contains("b200"); + QString filename = url.right(url.length() - url.lastIndexOf("/") - 1); + if (isLargeImage) + filename.prepend("large_"); + filename = QString("%1%2").arg(ApplicationPaths::dowloadedFilesPath()).arg(filename); + QFile file(filename); + if (file.exists()) + return QUrl(QString("image://weatherImages/%1").arg(filename)); + else + return QUrl(url); +} + +QString DayModel::getDayDetails(int index, QString prop) const +{ + if (index == -1) + index = 0; + if (index < m_data.count()) { + DayModelStructure temp = m_data.at(index); + if (prop == "day") + return temp.day; + if (prop == "weatherUrl") + return temp.weatherUrl; + if (prop == "timeRange") + return temp.timeRange; + if (prop == "temperature") + return temp.temperature; + if (prop == "windSpeed") + return temp.windSpeed; + if (prop == "windUrl") + return temp.windUrl; + if (prop == "rain") + return temp.rain; + } + return QString(); +} diff --git a/src/daymodel.h b/src/daymodel.h new file mode 100644 index 0000000..d93e905 --- /dev/null +++ b/src/daymodel.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DAYMODEL_H +#define DAYMODEL_H + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QNetworkAccessManager; +class QNetworkReply; +QT_END_NAMESPACE + +class DayModel : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString date READ getDate WRITE setDate NOTIFY dateChanged) + Q_PROPERTY(int afternoonIndex READ getAfternoonIndex WRITE setAfternoonIndex NOTIFY afternoonIndexChanged) + +public: + + struct DayModelStructure { + QString day; + QString weatherUrl; + QString timeRange; + QString temperature; + QString windSpeed; + QString windUrl; + QString rain; + }; + + enum { + DayRole = Qt::UserRole + 1, + WeatherUrlRole = Qt::UserRole + 2, + TimeRangeRole = Qt::UserRole + 3, + TemperatureRole = Qt::UserRole + 4, + WindSpeedRole = Qt::UserRole + 5, + WindUrlRole = Qt::UserRole + 6, + RainRole = Qt::UserRole + 7 + }; + + DayModel(); + + QString getDate() const { return m_date;} + void setDate(QString date) { m_date = date; } + + int getAfternoonIndex() const { return m_afternoonindex;} + void setAfternoonIndex(int index) { m_afternoonindex = index; } + + void clear(); + + QVariant data(const QModelIndex &index, int role) const; + QHash roleNames() const; + + Q_INVOKABLE void addRow(QString day, QString weatherUrl, QString timeRange, QString temperature, QString windSpeed, QString windUrl, QString rain); + Q_INVOKABLE QString getDayDetails(int index, QString prop) const; + Q_INVOKABLE int periodCount() const { return m_data.count(); } + + Q_INVOKABLE QUrl getCachedImageFile(const QString url); + +Q_SIGNALS: + void dateChanged(); + void afternoonIndexChanged(); + void addedImages(const QStringList images); + +private: + QString m_date; + int m_afternoonindex; + QList m_data; +}; + +QML_DECLARE_TYPE(DayModel) + +#endif // DAYMODEL_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..1704fe2 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "daymodel.h" +#include "citymodel.h" +#include "cities.h" +#include "applicationinfo.h" +#include "weatherimageprovider.h" + +static const struct { + const char *type; + int major, minor; +} qmldir_touch [] = { + { "TouchSlider", 1, 0 }, + { "TouchScrollView", 1, 0 }, + { "TouchLabel", 1, 0 }, + { "TouchTextField", 1, 0 }, + { "ListViewDelegate", 1, 0 }, + { "ListViewDelegateLoading", 1, 0 }, +}; + +static const struct { + const char *type; + int major, minor; +} qmldir_models [] = { + { "CitiesModel", 1, 0 }, + { "WeatherModel", 1, 0 }, +}; + +static const struct { + const char *type; + int major, minor; +} qmldir_pages [] = { + { "CitiesPage", 1, 0 }, + { "LongTermPage", 1, 0 }, + { "OneDayPage", 1, 0 }, +}; + +static QObject *systeminfo_provider(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + WeatherImageProvider *provider = new WeatherImageProvider(); + engine->addImageProvider(QLatin1String("weatherImages"), provider); + return new ApplicationInfo(provider); +} + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + app.setOrganizationName("Digia"); + app.setApplicationName("QuickForecast"); + +#ifndef Q_OS_IOS //QTBUG-34490 + QFontDatabase::addApplicationFont(":/weatherapp/fonts/OpenSans-Bold.ttf"); + QFontDatabase::addApplicationFont(":/weatherapp/fonts/OpenSans-Semibold.ttf"); + int openSansID = QFontDatabase::addApplicationFont(":/weatherapp/fonts/OpenSans-Regular.ttf"); + QStringList loadedFontFamilies = QFontDatabase::applicationFontFamilies(openSansID); + if (!loadedFontFamilies.empty()) { + QString fontName = loadedFontFamilies.at(0); + QGuiApplication::setFont(QFont(fontName)); + } else { + qWarning("Error: fail to load Open Sans font"); + } +#endif + + const char *uri = "org.qtproject.demo.weather"; + qmlRegisterType(uri, 1, 0, "DayModel"); + qmlRegisterType(uri, 1, 0, "CityModel"); + qmlRegisterType(uri, 1, 0, "Cities"); + qmlRegisterType(uri, 1, 0, "CitiesListModel"); + qmlRegisterSingletonType(uri, 1, 0, "ApplicationInfo", systeminfo_provider); + + for (int i = 0; i < int(sizeof(qmldir_touch)/sizeof(qmldir_touch[0])); i++) + qmlRegisterType(QUrl(QString("qrc:/weatherapp/qml/touch/%1.qml").arg(qmldir_touch[i].type)), uri, qmldir_touch[i].major, qmldir_touch[i].minor, qmldir_touch[i].type); + + for (int i = 0; i < int(sizeof(qmldir_models)/sizeof(qmldir_models[0])); i++) + qmlRegisterType(QUrl(QString("qrc:/weatherapp/qml/models/%1.qml").arg(qmldir_models[i].type)), uri, qmldir_models[i].major, qmldir_models[i].minor, qmldir_models[i].type); + + for (int i = 0; i < int(sizeof(qmldir_pages)/sizeof(qmldir_pages[0])); i++) + qmlRegisterType(QUrl(QString("qrc:/weatherapp/qml/pages/%1.qml").arg(qmldir_pages[i].type)), uri, qmldir_pages[i].major, qmldir_pages[i].minor, qmldir_pages[i].type); + + QQmlApplicationEngine engine(QUrl("qrc:/weatherapp/qml/main.qml")); + QObject *topLevel = engine.rootObjects().value(0); + + QQuickWindow *window = qobject_cast(topLevel); + if ( !window ) { + qWarning("Error: Your root item has to be a Window."); + return -1; + } + window->show(); + return app.exec(); +} diff --git a/src/src.pri b/src/src.pri new file mode 100644 index 0000000..5a3bbdf --- /dev/null +++ b/src/src.pri @@ -0,0 +1,16 @@ +SOURCES += \ + $$PWD/main.cpp \ + $$PWD/citymodel.cpp \ + $$PWD/daymodel.cpp \ + $$PWD/cities.cpp \ + $$PWD/applicationinfo.cpp \ + $$PWD/citieslistmodel.cpp + +HEADERS += \ + $$PWD/citymodel.h \ + $$PWD/daymodel.h \ + $$PWD/cities.h \ + $$PWD/applicationinfo.h \ + $$PWD/citieslistmodel.h \ + $$PWD/weatherimageprovider.h \ + $$PWD/applicationpaths.h diff --git a/src/weatherimageprovider.h b/src/weatherimageprovider.h new file mode 100644 index 0000000..59fcbcc --- /dev/null +++ b/src/weatherimageprovider.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the FOO module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WEATHERIMAGEPROVIDER_H +#define WEATHERIMAGEPROVIDER_H + +#include +#include +#include + +class WeatherImageProvider : public QQuickImageProvider +{ +public: + WeatherImageProvider() + : QQuickImageProvider(QQuickImageProvider::Image) + { + } + + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) + { + int width = 50; + int height = 50; + + if (size) + *size = QSize(width, height); + QImage image(requestedSize.width() > 0 ? requestedSize.width() : width, + requestedSize.height() > 0 ? requestedSize.height() : height, + QImage::Format_ARGB32); + image.load(id); + return image; + } +}; + +#endif // WEATHERIMAGEPROVIDER_H diff --git a/weatherapp.pro b/weatherapp.pro new file mode 100644 index 0000000..a386a5d --- /dev/null +++ b/weatherapp.pro @@ -0,0 +1,74 @@ +cache() + +TEMPLATE = app +QT += qml quick gui network xmlpatterns +TARGET = QuickForecast + +include(src/src.pri) + +APP_FILES = \ + $$PWD/qml/main.qml \ + $$PWD/qml/pages/BasicPage.qml \ + $$PWD/qml/pages/CitiesPage.qml \ + $$PWD/qml/pages/OneDayPage.qml \ + $$PWD/qml/pages/LongTermPage.qml \ + $$PWD/qml/pages/LongTermDayItem.qml \ + $$PWD/qml/pages/OneDayZoomItem.qml \ + $$PWD/qml/pages/OneDaySliderItem.qml \ + $$PWD/qml/pages/Separator.qml \ + $$PWD/qml/models/WeatherModel.qml \ + $$PWD/qml/js/utils.js + +# Touch Styled Controls +APP_FILES += \ + $$PWD/qml/touch/TouchLabel.qml \ + $$PWD/qml/touch/TouchScrollView.qml \ + $$PWD/qml/touch/TouchSlider.qml \ + $$PWD/qml/touch/TouchTextField.qml \ + $$PWD/qml/touch/ListViewDelegate.qml \ + $$PWD/qml/touch/images/BackArrow.png \ + $$PWD/qml/touch/images/Pointer.png \ + $$PWD/qml/touch/images/Pointer_pressed.png \ + $$PWD/qml/touch/images/Circle.png \ + $$PWD/qml/touch/images/darkclose.png \ + $$PWD/qml/touch/images/magnifier.png \ + $$PWD/qml/touch/images/Clear.png + +# Fonts +APP_FILES += \ + $$PWD/fonts/OpenSans-Bold.ttf \ + $$PWD/fonts/OpenSans-Semibold.ttf \ + $$PWD/fonts/OpenSans-Regular.ttf + +OTHER_FILES += $$APP_FILES + +# Create the resource file +GENERATED_RESOURCE_FILE = $$OUT_PWD/weatherapp.qrc + +RESOURCE_CONTENT = \ + "" \ + "" + +for(resourcefile, APP_FILES) { + resourcefileabsolutepath = $$absolute_path($$resourcefile) + relativepath_in = $$relative_path($$resourcefileabsolutepath, $$_PRO_FILE_PWD_) + relativepath_out = $$relative_path($$resourcefileabsolutepath, $$OUT_PWD) + RESOURCE_CONTENT += "$$relativepath_out" +} + +RESOURCE_CONTENT += \ + "" \ + "" + +write_file($$GENERATED_RESOURCE_FILE, RESOURCE_CONTENT)|error("Aborting.") + +RESOURCES += $$GENERATED_RESOURCE_FILE + +ios { + FONTS.files = $$PWD/fonts/OpenSans-Bold.ttf $$PWD/fonts/OpenSans-Semibold.ttf $$PWD/fonts/OpenSans-Regular.ttf + FONTS.path = fonts + QMAKE_BUNDLE_DATA += FONTS + QMAKE_INFO_PLIST = ios/iosInfo.plist +} + +android: ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android -- cgit v1.2.3