import QtQuick 2.0
import QtLocation 5.0
import QtLocation.examples 5.0
import "content/places"
Item {
id: page
width: (parent && parent.width > 0) ? parent.width : 360
height: (parent && parent.height > 0) ? parent.height : 640
property bool mobileUi: true
property variant map
property variant searchRegion : startLocation
property variant searchRegionItem
property Plugin favoritesPlugin
onMapChanged: editPlaceDialog.prepareDialog()
Rectangle {
id: backgroundRect
anchors.fill: parent
color: "lightgrey"
z: 2
}
Menu {
id:mainMenu
anchors.bottom: parent.bottom
z: backgroundRect.z + 3
Component.onCompleted: {
addItem("Provider");
addItem("New");
addItem("Search");
}
onClicked: page.state = page.state == "" ? button : "";
}
Menu {
id: providerMenu
z: backgroundRect.z + 2
y: page.height
horizontalOrientation: false
exclusive: true
Component.onCompleted: {
var plugins = getPlacesPlugins()
for (var i = 0; i<plugins.length; i++) {
addItem(plugins[i]);
if (plugins[i] === "nokia")
exclusiveButton = plugins[i];
}
if (exclusiveButton === "")
exclusiveButton = plugins[0];
}
onClicked: page.state = ""
onExclusiveButtonChanged: placesPlugin.name = exclusiveButton;
}
Menu {
id: newMenu
z: backgroundRect.z + 2
y: page.height
horizontalOrientation: false
Component.onCompleted: {
var item = addItem("Place");
item.enabled = Qt.binding(function() { return placesPlugin.name != "" ? placesPlugin.supportsPlaces(Plugin.SavePlaceFeature) : false })
item = addItem("Category");
item.enabled = Qt.binding(function() { return placesPlugin.name != "" ? placesPlugin.supportsPlaces(Plugin.SaveCategoryFeature) : false })
}
onClicked: {
switch (button) {
case "Place": {
editPlaceDialog.prepareDialog();
page.state = "NewPlace";
break;
}
case "Category": {
editCategoryDialog.category = null;
editCategoryDialog.prepareDialog();
page.state = "NewCategory";
break;
}
}
}
}
Menu {
id: searchMenu
z: backgroundRect.z + 2
y: page.height
horizontalOrientation: false
Component.onCompleted: {
addItem("Search Center");
addItem("Search Bounding Box");
addItem("Search Bounding Circle");
addItem("Search Options");
}
onClicked: page.state = button
}
PlaceDialog {
id: editPlaceDialog
z: backgroundRect.z + 4
onCancelButtonClicked: page.state = ""
onCompleted: page.state = "";
}
CategoryDialog {
id: editCategoryDialog
z: backgroundRect.z + 4
onCancelButtonClicked: page.state = ""
Connections {
target: editCategoryDialog.category
onStatusChanged: {
switch (editCategoryDialog.category.status) {
case Category.Saving: {
console.log("Saving...");
break;
}
case Category.Ready: {
page.state = "";
break;
}
case Category.Error: {
console.log("Error while saving!");
break;
}
}
}
}
}
InputDialog {
id: searchCenterDialog
z: backgroundRect.z + 4
title: "Search center"
Behavior on opacity { NumberAnimation { duration: 500 } }
Component.onCompleted: prepareDialog()
function prepareDialog() {
setModel([
["Latitude", searchRegion.center ? String(searchRegion.center.latitude) : ""],
["Longitude", searchRegion.center ? String(searchRegion.center.longitude) : ""]
]);
}
onCancelButtonClicked: page.state = ""
onGoButtonClicked: {
startLocation.center.latitude = dialogModel.get(0).inputText;
startLocation.center.longitude = dialogModel.get(1).inputText;
searchRegion = startLocation;
if (searchRegionItem) {
map.removeMapItem(searchRegionItem);
searchRegionItem.destroy();
}
page.state = "";
}
}
InputDialog {
id: searchBoxDialog
z: backgroundRect.z + 4
title: "Search Bounding Box"
Behavior on opacity { NumberAnimation { duration: 500 } }
Component.onCompleted: prepareDialog()
function prepareDialog() {
setModel([
["Latitude", searchRegion.center ? String(searchRegion.center.latitude) : ""],
["Longitude", searchRegion.center ? String(searchRegion.center.longitude) : ""],
["Width(deg)", searchRegion.width ? String(searchRegion.width) : "" ],
["Height(deg)", searchRegion.height ? String(searchRegion.height) : "" ]
]);
}
onCancelButtonClicked: page.state = ""
onGoButtonClicked: {
var newRegion = Qt.createQmlObject('import QtLocation 5.0; BoundingBox {}', page, "BoundingCircle");
newRegion.center.latitude = dialogModel.get(0).inputText;
newRegion.center.longitude = dialogModel.get(1).inputText;
newRegion.width = dialogModel.get(2).inputText;
newRegion.height = dialogModel.get(3).inputText;
startLocation.center.latitude = dialogModel.get(0).inputText;
startLocation.center.longitude = dialogModel.get(1).inputText;
searchRegion = newRegion;
if (searchRegionItem) {
map.removeMapItem(searchRegionItem);
searchRegionItem.destroy();
}
searchRegionItem = Qt.createQmlObject('import QtLocation 5.0; MapRectangle { color: "red"; opacity: 0.4 }', page, "MapRectangle");
searchRegionItem.topLeft = newRegion.topLeft;
searchRegionItem.bottomRight = newRegion.bottomRight;
map.addMapItem(searchRegionItem);
page.state = "";
}
}
InputDialog {
id: searchCircleDialog
z: backgroundRect.z + 4
title: "Search Bounding Circle"
Behavior on opacity { NumberAnimation { duration: 500 } }
Component.onCompleted: prepareDialog()
function prepareDialog() {
setModel([
["Latitude", searchRegion.center ? String(searchRegion.center.latitude) : ""],
["Longitude", searchRegion.center ? String(searchRegion.center.longitude) : ""],
["Radius(m)", searchRegion.radius ? String(searchRegion.radius) : "" ]
]);
}
onCancelButtonClicked: page.state = ""
onGoButtonClicked: {
var newRegion = Qt.createQmlObject('import QtLocation 5.0; BoundingCircle {}', page, "BoundingCircle");
newRegion.center.latitude = dialogModel.get(0).inputText;
newRegion.center.longitude = dialogModel.get(1).inputText;
newRegion.radius = dialogModel.get(2).inputText;
startLocation.center.latitude = dialogModel.get(0).inputText;
startLocation.center.longitude = dialogModel.get(1).inputText;
searchRegion = newRegion;
if (searchRegionItem) {
map.removeMapItem(searchRegionItem);
searchRegionItem.destroy();
}
searchRegionItem = Qt.createQmlObject('import QtLocation 5.0; MapCircle { color: "red"; opacity: 0.4 }', page, "MapRectangle");
searchRegionItem.center = newRegion.center;
searchRegionItem.radius = newRegion.radius;
map.addMapItem(searchRegionItem);
page.state = "";
}
}
OptionsDialog {
id: optionsDialog
z: backgroundRect.z + 4
Behavior on opacity { NumberAnimation { duration: 500 } }
Component.onCompleted: prepareDialog()
function prepareDialog() {
if (placeSearchModel.favoritesPlugin !== null)
isFavoritesEnabled = true;
else
isFavoritesEnabled = false;
locales = placesPlugin.locales.join(Qt.locale().groupSeparator);
}
onCancelButtonClicked: page.state = ""
onGoButtonClicked: {
if (isFavoritesEnabled) {
if (favoritesPlugin == null)
favoritesPlugin = Qt.createQmlObject('import QtLocation 5.0; Plugin { name: "nokia_places_jsondb" }', page);
placeSearchModel.favoritesPlugin = favoritesPlugin;
recommendationModel.favoritesPlugin = favoritesPlugin;
} else {
placeSearchModel.favoritesPlugin = null;
recommendationModel.favoritesPlugin = null;
}
placesPlugin.locales = locales.split(Qt.locale().groupSeparator);
categoryModel.update();
page.state = "";
}
}
BoundingCircle {
id: startLocation
}
Binding {
target: startLocation
property: "center"
value: map ? map.center : null
}
PlaceSearchModel {
id: placeSearchModel
plugin: placesPlugin
maximumCorrections: 5
searchArea: searchRegion
function searchForCategory(category) {
searchTerm = "";
categories = category;
limit = -1;
offset = 0;
update();
}
function searchForText(text) {
searchTerm = text;
categories = null;
limit = -1;
offset = 0;
update();
}
function previousPage() {
if (limit === -1)
limit = count;
offset = Math.max(0, offset - limit);
update();
}
function nextPage() {
if (limit === -1)
limit = count;
offset += limit;
update();
}
onStatusChanged: {
if (status === PlaceSearchModel.Ready)
searchResultView.showSearchResults();
}
}
PlaceRecommendationModel {
id: recommendationModel
plugin: placesPlugin
searchArea: searchRegion
}
CategoryModel {
id: categoryModel
plugin: placesPlugin
hierarchical: true
}
SearchBox {
id: searchBox
anchors.top: page.top
anchors.topMargin: page.mobileUi ? 20 : 0
width: parent.width
expandedHeight: parent.height
z: backgroundRect.z + 3
}
Plugin {
id: placesPlugin
parameters: pluginParametersFromMap(pluginParameters)
onNameChanged: {
createMap(placesPlugin);
categoryModel.update();
}
}
Item {
id: searchResultTab
z: backgroundRect.z + 2
height: parent.height - searchBox.baseHeight - mainMenu.height
width: parent.width
x: 0
y: mainMenu.height - height + catchImage.width
opacity: 0
property bool open: false
Behavior on y { PropertyAnimation { duration: 300; easing.type: Easing.InOutQuad } }
Behavior on opacity { PropertyAnimation { duration: 300 } }
Image {
id: catchImage
source: "resources/catch.png"
rotation: 90
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: (width - height) / 2
MouseArea {
anchors.fill: parent
onClicked: searchResultTab.open = !searchResultTab.open;
}
}
Rectangle {
id: searchResultTabPage
width: parent.width
height: parent.height - catchImage.width
color: "#ECECEC"
radius: 5
SearchResultView {
id: searchResultView
anchors.fill: parent
anchors.margins: 10
}
}
states: [
State {
name: ""
when: placeSearchModel.count == 0 && recommendationModel.count == 0
PropertyChanges { target: searchResultTab; open: false }
},
State {
name: "Close"
when: (placeSearchModel.count > 0 || recommendationModel.count > 0) && !searchResultTab.open
PropertyChanges { target: searchResultTab; opacity: 1 }
},
State {
name: "Open"
when: (placeSearchModel.count > 0 || recommendationModel.count > 0) && searchResultTab.open
PropertyChanges { target: searchResultTab; y: mainMenu.height; opacity: 1 }
}
]
}
Component {
id: mapComponent
MapComponent {
z: backgroundRect.z + 1
width: page.width
height: page.height - mainMenu.height
onMapPressed: page.state = ""
MapItemView {
model: placeSearchModel
delegate: MapQuickItem {
coordinate: place.location.coordinate
anchorPoint.x: image.width * 0.28
anchorPoint.y: image.height
sourceItem: Image {
id: image
source: "resources/marker.png"
MouseArea {
anchors.fill: parent
onClicked: {
searchResultView.showPlaceDetails({
distance: model.distance,
place: model.place,
});
searchResultTab.state = "Open";
}
}
}
}
}
}
}
function createMap(placesPlugin) {
var mapPlugin;
if (placesPlugin.supportsMapping()) {
mapPlugin = placesPlugin;
} else {
mapPlugin = Qt.createQmlObject('import QtLocation 5.0; Plugin { required.mapping: Plugin.AnyMappingFeatures }', page);
}
if (map)
map.destroy();
map = mapComponent.createObject(page);
map.plugin = mapPlugin;
}
function getPlacesPlugins() {
var plugin = Qt.createQmlObject('import QtLocation 5.0; Plugin {}', page);
var myArray = new Array;
for (var i = 0; i < plugin.availableServiceProviders.length; i++) {
var tempPlugin = Qt.createQmlObject ('import QtLocation 5.0; Plugin {name: "' + plugin.availableServiceProviders[i]+ '"}', page)
if (tempPlugin.supportsPlaces())
myArray.push(tempPlugin.name)
}
return myArray;
}
function pluginParametersFromMap(pluginParameters) {
var parameters = new Array()
for (var prop in pluginParameters){
var parameter = Qt.createQmlObject('import QtLocation 5.0; PluginParameter{ name: "'+ prop + '"; value: "' + pluginParameters[prop]+'"}',page)
parameters.push(parameter)
}
return parameters
}
states: [
State {
name: "Provider"
PropertyChanges { target: providerMenu; y: page.height - providerMenu.height - mainMenu.height }
},
State {
name: "New"
PropertyChanges { target: newMenu; y: page.height - newMenu.height - mainMenu.height }
},
State {
name: "Search"
PropertyChanges { target: searchMenu; y: page.height - searchMenu.height - mainMenu.height }
},
State {
name: "NewPlace"
PropertyChanges { target: editPlaceDialog; title: "New Place"; opacity: 1 }
},
State {
name: "NewCategory"
PropertyChanges { target: editCategoryDialog; title: "New Category"; opacity: 1 }
},
State {
name: "EditPlace"
PropertyChanges { target: editPlaceDialog; title: "Edit Place"; opacity: 1 }
},
State {
name: "EditCategory"
PropertyChanges { target: editCategoryDialog; opacity: 1 }
},
State {
name: "Search Center"
PropertyChanges { target: searchCenterDialog; opacity: 1 }
StateChangeScript { script: searchCenterDialog.prepareDialog() }
},
State {
name: "Search Bounding Box"
PropertyChanges { target: searchBoxDialog; opacity: 1 }
StateChangeScript { script: searchBoxDialog.prepareDialog() }
},
State {
name: "Search Bounding Circle"
PropertyChanges { target: searchCircleDialog; opacity: 1 }
StateChangeScript { script: searchCircleDialog.prepareDialog() }
},
State {
name: "Search Options"
PropertyChanges { target: optionsDialog; opacity: 1 }
StateChangeScript { script: optionsDialog.prepareDialog() }
}
]
transitions: [
Transition {
to: ""
NumberAnimation { properties: "opacity,y,x,rotation" ; duration: 500; easing.type: Easing.Linear }
},
Transition {
to: "Provider"
NumberAnimation { properties: "y" ; duration: 300; easing.type: Easing.Linear }
},
Transition {
to: "New"
NumberAnimation { properties: "y" ; duration: 300; easing.type: Easing.Linear }
},
Transition {
to: "Search"
NumberAnimation { properties: "y" ; duration: 300; easing.type: Easing.Linear }
}
]
}