diff options
author | Caroline Chao <caroline.chao@digia.com> | 2013-12-10 14:42:22 +0100 |
---|---|---|
committer | Caroline Chao <caroline.chao@digia.com> | 2013-12-10 14:42:22 +0100 |
commit | 9e2a27f41ab4b76851440fe0d5a11e1ae7ca9dde (patch) | |
tree | 234b14b90e9627939e2f99087c84e2ce5c1c72bb |
Initial commitv1.1
94 files changed, 4692 insertions, 0 deletions
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 @@ +<?xml version='1.0' encoding='utf-8'?> +<manifest android:versionCode="3" android:installLocation="auto" xmlns:android="http://schemas.android.com/apk/res/android" package="org.qtproject.quickforecast" android:versionName="1.1"> + <application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="@string/app_name" android:icon="@drawable/icon"> + <activity android:screenOrientation="unspecified" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="@string/app_name" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + <meta-data android:value="QuickForecast" android:name="android.app.lib_name"/> + <meta-data android:resource="@array/qt_sources" android:name="android.app.qt_sources_resource_id"/> + <meta-data android:value="default" android:name="android.app.repository"/> + <meta-data android:resource="@array/qt_libs" android:name="android.app.qt_libs_resource_id"/> + <meta-data android:resource="@array/bundled_libs" android:name="android.app.bundled_libs_resource_id"/> + <!-- Deploy Qt libs as part of package --> + <meta-data android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --" android:name="android.app.bundle_local_qt_libs"/> + <meta-data android:resource="@array/bundled_in_lib" android:name="android.app.bundled_in_lib_resource_id"/> + <meta-data android:resource="@array/bundled_in_assets" android:name="android.app.bundled_in_assets_resource_id"/> + <!-- Run with local libs --> + <meta-data android:value="-- %%USE_LOCAL_QT_LIBS%% --" android:name="android.app.use_local_qt_libs"/> + <meta-data android:value="/data/local/tmp/qt/" android:name="android.app.libs_prefix"/> + <meta-data android:value="-- %%INSERT_LOCAL_LIBS%% --" android:name="android.app.load_local_libs"/> + <meta-data android:value="-- %%INSERT_LOCAL_JARS%% --" android:name="android.app.load_local_jars"/> + <meta-data android:value="-- %%INSERT_INIT_CLASSES%% --" android:name="android.app.static_init_classes"/> + <!-- Messages maps --> + <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/> + <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/> + <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/> + <!-- Messages maps --> + <!-- Splash screen --> + <meta-data android:resource="@layout/splash" android:name="android.app.splash_screen"/> + <!-- Splash screen --> + </activity> + </application> + <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="18"/> + <supports-screens android:normalScreens="true" android:smallScreens="true" android:largeScreens="true" android:anyDensity="true"/> + <!-- %%INSERT_PERMISSIONS --> + <!-- %%INSERT_FEATURES --> + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> +</manifest> diff --git a/android/res/drawable-hdpi/icon.png b/android/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 0000000..4e95fc2 --- /dev/null +++ b/android/res/drawable-hdpi/icon.png diff --git a/android/res/drawable-ldpi/icon.png b/android/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 0000000..17eb470 --- /dev/null +++ b/android/res/drawable-ldpi/icon.png diff --git a/android/res/drawable-mdpi/icon.png b/android/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 0000000..ba69e8f --- /dev/null +++ b/android/res/drawable-mdpi/icon.png diff --git a/app-icons/AppIcon_100px.png b/app-icons/AppIcon_100px.png Binary files differnew file mode 100644 index 0000000..7ab56c9 --- /dev/null +++ b/app-icons/AppIcon_100px.png diff --git a/app-icons/AppIcon_1024px.png b/app-icons/AppIcon_1024px.png Binary files differnew file mode 100644 index 0000000..462c68c --- /dev/null +++ b/app-icons/AppIcon_1024px.png diff --git a/app-icons/AppIcon_114px.png b/app-icons/AppIcon_114px.png Binary files differnew file mode 100644 index 0000000..0fe60cb --- /dev/null +++ b/app-icons/AppIcon_114px.png diff --git a/app-icons/AppIcon_120px.png b/app-icons/AppIcon_120px.png Binary files differnew file mode 100644 index 0000000..0525a69 --- /dev/null +++ b/app-icons/AppIcon_120px.png diff --git a/app-icons/AppIcon_144px.png b/app-icons/AppIcon_144px.png Binary files differnew file mode 100644 index 0000000..ad5e348 --- /dev/null +++ b/app-icons/AppIcon_144px.png diff --git a/app-icons/AppIcon_152px.png b/app-icons/AppIcon_152px.png Binary files differnew file mode 100644 index 0000000..ad63eb3 --- /dev/null +++ b/app-icons/AppIcon_152px.png diff --git a/app-icons/AppIcon_29px.png b/app-icons/AppIcon_29px.png Binary files differnew file mode 100644 index 0000000..718b00e --- /dev/null +++ b/app-icons/AppIcon_29px.png diff --git a/app-icons/AppIcon_36px.png b/app-icons/AppIcon_36px.png Binary files differnew file mode 100644 index 0000000..2592625 --- /dev/null +++ b/app-icons/AppIcon_36px.png diff --git a/app-icons/AppIcon_40px.png b/app-icons/AppIcon_40px.png Binary files differnew file mode 100644 index 0000000..9a6aeda --- /dev/null +++ b/app-icons/AppIcon_40px.png diff --git a/app-icons/AppIcon_48px.png b/app-icons/AppIcon_48px.png Binary files differnew file mode 100644 index 0000000..2e4b199 --- /dev/null +++ b/app-icons/AppIcon_48px.png diff --git a/app-icons/AppIcon_50px.png b/app-icons/AppIcon_50px.png Binary files differnew file mode 100644 index 0000000..f2c3520 --- /dev/null +++ b/app-icons/AppIcon_50px.png diff --git a/app-icons/AppIcon_512px.png b/app-icons/AppIcon_512px.png Binary files differnew file mode 100644 index 0000000..74eb30a --- /dev/null +++ b/app-icons/AppIcon_512px.png diff --git a/app-icons/AppIcon_57px.png b/app-icons/AppIcon_57px.png Binary files differnew file mode 100644 index 0000000..2874aa9 --- /dev/null +++ b/app-icons/AppIcon_57px.png diff --git a/app-icons/AppIcon_58px.png b/app-icons/AppIcon_58px.png Binary files differnew file mode 100644 index 0000000..4b56cb7 --- /dev/null +++ b/app-icons/AppIcon_58px.png diff --git a/app-icons/AppIcon_72px.png b/app-icons/AppIcon_72px.png Binary files differnew file mode 100644 index 0000000..49a8bf4 --- /dev/null +++ b/app-icons/AppIcon_72px.png diff --git a/app-icons/AppIcon_76px.png b/app-icons/AppIcon_76px.png Binary files differnew file mode 100644 index 0000000..6a3ba5e --- /dev/null +++ b/app-icons/AppIcon_76px.png diff --git a/app-icons/AppIcon_80px.png b/app-icons/AppIcon_80px.png Binary files differnew file mode 100644 index 0000000..bf56b81 --- /dev/null +++ b/app-icons/AppIcon_80px.png 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 Binary files differnew file mode 100644 index 0000000..fd79d43 --- /dev/null +++ b/fonts/OpenSans-Bold.ttf diff --git a/fonts/OpenSans-Regular.ttf b/fonts/OpenSans-Regular.ttf Binary files differnew file mode 100644 index 0000000..db43334 --- /dev/null +++ b/fonts/OpenSans-Regular.ttf diff --git a/fonts/OpenSans-Semibold.ttf b/fonts/OpenSans-Semibold.ttf Binary files differnew file mode 100644 index 0000000..1a7679e --- /dev/null +++ b/fonts/OpenSans-Semibold.ttf diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_100px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_100px.png Binary files differnew file mode 100644 index 0000000..7ab56c9 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_100px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_114px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_114px.png Binary files differnew file mode 100644 index 0000000..0fe60cb --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_114px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_120px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_120px.png Binary files differnew file mode 100644 index 0000000..0525a69 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_120px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_144px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_144px.png Binary files differnew file mode 100644 index 0000000..ad5e348 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_144px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_152px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_152px.png Binary files differnew file mode 100644 index 0000000..ad63eb3 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_152px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_29px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_29px.png Binary files differnew file mode 100644 index 0000000..718b00e --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_29px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_40px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_40px.png Binary files differnew file mode 100644 index 0000000..9a6aeda --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_40px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_50px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_50px.png Binary files differnew file mode 100644 index 0000000..f2c3520 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_50px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_57px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_57px.png Binary files differnew file mode 100644 index 0000000..2874aa9 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_57px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_58px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_58px.png Binary files differnew file mode 100644 index 0000000..4b56cb7 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_58px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_72px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_72px.png Binary files differnew file mode 100644 index 0000000..49a8bf4 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_72px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_76px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_76px.png Binary files differnew file mode 100644 index 0000000..6a3ba5e --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_76px.png diff --git a/ios/Images.xcassets/AppIcon.appiconset/AppIcon_80px.png b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_80px.png Binary files differnew file mode 100644 index 0000000..bf56b81 --- /dev/null +++ b/ios/Images.xcassets/AppIcon.appiconset/AppIcon_80px.png 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 Binary files differnew file mode 100644 index 0000000..f5c1011 --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Land.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Port.png b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Port.png Binary files differnew file mode 100644 index 0000000..0cd0c65 --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_Port.png 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 Binary files differnew file mode 100644 index 0000000..10e007d --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Land.png 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 Binary files differnew file mode 100644 index 0000000..8e90fd3 --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/NoSB_ipad_7_R_Port.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Land.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Land.png Binary files differnew file mode 100644 index 0000000..055975e --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Land.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Port.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Port.png Binary files differnew file mode 100644 index 0000000..b1b02da --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_Port.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Land.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Land.png Binary files differnew file mode 100644 index 0000000..b149b62 --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Land.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Port.png b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Port.png Binary files differnew file mode 100644 index 0000000..3a660bf --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/ipad_7_R_Port.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/iphone_6.1.png b/ios/Images.xcassets/LaunchImage.launchimage/iphone_6.1.png Binary files differnew file mode 100644 index 0000000..51fab95 --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/iphone_6.1.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R3.5.png b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R3.5.png Binary files differnew file mode 100644 index 0000000..c4130ac --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R3.5.png diff --git a/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R4.png b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R4.png Binary files differnew file mode 100644 index 0000000..fe97bdf --- /dev/null +++ b/ios/Images.xcassets/LaunchImage.launchimage/iphone_7_R4.png 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDisplayName</key> + <string>QuickForecast</string> + <key>CFBundleExecutable</key> + <string>QuickForecast</string> + <key>CFBundleGetInfoString</key> + <string>Created by Qt/QMake</string> + <key>CFBundleIcons</key> + <dict/> + <key>CFBundleIcons~ipad</key> + <dict/> + <key>CFBundleIdentifier</key> + <string>com.digia.qt.iosteam.WeatherApp</string> + <key>CFBundleName</key> + <string>Quick Forecast</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.1</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.1</string> + <key>NOTE</key> + <string>This file was generated by Qt/QMake.</string> + <key>UIAppFonts</key> + <array> + <string>fonts/OpenSans-Bold.ttf</string> + <string>fonts/OpenSans-Semibold.ttf</string> + <string>fonts/OpenSans-Regular.ttf</string> + </array> + <key>UIStatusBarHidden</key> + <true/> + <key>UIStatusBarHidden~ipad</key> + <true/> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> +</dict> +</plist> 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<count; i++) { + var item = get(i) + var date = Utils.getItemDate(item) + var dayModel = loadedCityModel.getDayModel(date) + if (dayModel === null) { + // add a dayModel to cityModel + dayModel = Qt.createQmlObject('import org.qtproject.demo.weather 1.0; DayModel {}', loadedCityModel, "") + dayModel.date = date + loadedCityModel.addDayModel(dayModel) + } + if (item.period === "2") + dayModel.afternoonIndex = dayModel.periodCount() + Utils.updateDayModel(dayModel, item) + } + modelitem.showLongTerm() + } else if ( status === XmlListModel.Error) { + error(errorString()) + } else if (status === XmlListModel.Ready && count == 0) { + error(qsTr("Can't parse the xml file")) + } + } + } +} diff --git a/qml/pages/BasicPage.qml b/qml/pages/BasicPage.qml new file mode 100644 index 0000000..874df94 --- /dev/null +++ b/qml/pages/BasicPage.qml @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** 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 QtQuick.Controls.Styles 1.0 +import org.qtproject.demo.weather 1.0 + +Item { + id: page + signal updateStatusBar(string message) + signal nextPage + signal previousPage + signal clearSearchBox + + property Component pageComponent + property bool isLocked: true + property string title1 + property string title2 + property string title3 + + property alias searchText: searchField.text + property alias hasNoSearchText: searchField.isEmpty + signal searchBoxReturn + property string statusBarMessageDefault + + property alias blueRect: blueRect + + Binding { + target: ApplicationInfo + property: "isPortraitMode" + value: page.height > 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 + " <a href=" + ApplicationInfo.currentCityModel.sourceXml + "\>(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 Binary files differnew file mode 100644 index 0000000..9070d0f --- /dev/null +++ b/qml/touch/images/BackArrow.png diff --git a/qml/touch/images/Circle.png b/qml/touch/images/Circle.png Binary files differnew file mode 100644 index 0000000..7b229ec --- /dev/null +++ b/qml/touch/images/Circle.png diff --git a/qml/touch/images/Clear.png b/qml/touch/images/Clear.png Binary files differnew file mode 100644 index 0000000..883dffd --- /dev/null +++ b/qml/touch/images/Clear.png diff --git a/qml/touch/images/Pointer.png b/qml/touch/images/Pointer.png Binary files differnew file mode 100644 index 0000000..45b075e --- /dev/null +++ b/qml/touch/images/Pointer.png diff --git a/qml/touch/images/Pointer_pressed.png b/qml/touch/images/Pointer_pressed.png Binary files differnew file mode 100644 index 0000000..776e0d1 --- /dev/null +++ b/qml/touch/images/Pointer_pressed.png diff --git a/qml/touch/images/darkclose.png b/qml/touch/images/darkclose.png Binary files differnew file mode 100644 index 0000000..2f90820 --- /dev/null +++ b/qml/touch/images/darkclose.png diff --git a/qml/touch/images/magnifier.png b/qml/touch/images/magnifier.png Binary files differnew file mode 100644 index 0000000..42033b5 --- /dev/null +++ b/qml/touch/images/magnifier.png 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 <QtCore/QFile> +#include <QtCore/qmath.h> +#include <QtCore/QRegExp> +#include <QtCore/QUrl> +#include <QtCore/QUrlQuery> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkRequest> + +#include "applicationinfo.h" +#include "weatherimageprovider.h" +#include <QDebug> + +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 <QtCore/QObject> +#include <QtQml/QQmlPropertyMap> + +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 <QtCore/QDir> +#include <QtCore/QStandardPaths> +#include <QtCore/QStringList> +#include <QDebug> + +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 <QtCore/QCoreApplication> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QIODevice> +#include <QtCore/QTextStream> +#include <QtGlobal> + +#include "cities.h" +#include "citymodel.h" +#include "applicationpaths.h" +#include <QDebug> + +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 <m_cityMap.count(); i++) { + if (m_cityMap.at(i).first == sourceXml) + return i; + } + CityModel *model = new CityModel(this); + if (model->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<int, QByteArray> Cities::roleNames() const +{ + QHash<int, QByteArray> 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 <QtCore/QAbstractListModel> +#include <QtCore/QList> +#include <QtCore/QPair> +#include <QtQml/qqml.h> + +class CityModel; + +typedef QPair<QString, CityModel*> 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<int, QByteArray> 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<CityModelPair> 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 <QDebug> + +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<CityXmlPair> 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<int, QByteArray> CitiesListModel::roleNames() const +{ + QHash<int, QByteArray> 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 <QtCore/QAbstractListModel> +#include <QtCore/QList> +#include <QtCore/QPair> +#include <QtCore/QStringList> +#include <QtQml/qqml.h> + +typedef QPair<QString, QString> 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<int, QByteArray> roleNames() const; + +signals: + void isEmptyChanged(); + +private: + QList<CityXmlPair> 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 <QtCore/QDateTime> +#include <QtCore/QFile> +#include <QtCore/QIODevice> +#include <QtCore/QRegExp> +#include <QtCore/QStringList> +#include <QtNetwork/QNetworkRequest> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkAccessManager> + +#include "citymodel.h" +#include "applicationpaths.h" +#include <QDebug> + +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<int, QByteArray> CityModel::roleNames() const +{ + QHash<int, QByteArray> 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 <QtCore/QModelIndex> +#include <QtCore/QObject> +#include <QtQml/qqml.h> +#include <QDebug> + +#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<int, QByteArray> 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<DayModel*> 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 <QtCore/QDir> +#include <QtCore/QCoreApplication> +#include <QtNetwork/QNetworkRequest> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkAccessManager> + +#include "daymodel.h" +#include "applicationpaths.h" +#include <QDebug> + +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<int, QByteArray> DayModel::roleNames() const +{ + QHash<int, QByteArray> 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 <QtCore/QModelIndex> + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtQml/qqml.h> + +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<int, QByteArray> 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<DayModelStructure> 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 <QtCore/QString> +#include <QtGui/QFont> +#include <QtGui/QFontDatabase> +#include <QtGui/QGuiApplication> +#include <QtQuick/QQuickWindow> +#include <QtQml> + +#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<DayModel>(uri, 1, 0, "DayModel"); + qmlRegisterType<CityModel>(uri, 1, 0, "CityModel"); + qmlRegisterType<Cities>(uri, 1, 0, "Cities"); + qmlRegisterType<CitiesListModel>(uri, 1, 0, "CitiesListModel"); + qmlRegisterSingletonType<ApplicationInfo>(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<QQuickWindow *>(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 <QtQuick/QQuickImageProvider> +#include <QtGui/QImage> +#include <QtCore/QSize> + +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 = \ + "<RCC>" \ + "<qresource>" + +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 += "<file alias=\"weatherapp/$$relativepath_in\">$$relativepath_out</file>" +} + +RESOURCE_CONTENT += \ + "</qresource>" \ + "</RCC>" + +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 |