/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */ /* vim: set et ts=4 sw=4: */ /* * Copyright (c) 2013,2014 Jonas Danielsson, Mattias Bengtsson. * * GNOME Maps is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * GNOME Maps is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with GNOME Maps; if not, see . * * Author: Jonas Danielsson * Mattias Bengtsson */ const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const Geocode = imports.gi.GeocodeGlib; const Gio = imports.gi.Gio; const Gtk = imports.gi.Gtk; const Lang = imports.lang; const Application = imports.application; const Location = imports.location; const Place = imports.place; const PlaceStore = imports.placeStore; const PlacePopover = imports.placePopover; const Utils = imports.utils; const PlaceEntry = new Lang.Class({ Name: 'PlaceEntry', Extends: Gtk.SearchEntry, Properties: { 'place': GObject.ParamSpec.object('place', 'Place', 'The selected place', GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, Geocode.Place) }, set place(p) { if (!this._place && !p) return; if (this._place && p && this._locEquals(this._place, p)) return; if (p) { if (p.name) { this.text = p.name; } else this.text = p.location.latitude + ', ' + p.location.longitude; } else this.text = ''; this._place = p; this.notify('place'); }, get place() { return this._place; }, get popover() { return this._popover; }, _init: function(props) { let numVisible = props.num_visible || 6; delete props.num_visible; this._mapView = props.mapView; delete props.mapView; if (!props.loupe) props.primary_icon_name = null; delete props.loupe; let maxChars = props.maxChars; delete props.maxChars; let parseOnFocusOut = props.parseOnFocusOut; delete props.parseOnFocusOut; this._matchRoute = props.matchRoute || false; delete props.matchRoute; this.parent(props); this._filter = new Gtk.TreeModelFilter({ child_model: Application.placeStore }); this._filter.set_visible_func(this._completionVisibleFunc.bind(this), null, null); this._popover = this._createPopover(numVisible, maxChars); this.connect('activate', this._onActivate.bind(this)); this.connect('search-changed', (function() { if (this._cancellable) this._cancellable.cancel(); this._refreshFilter(); if (this.text.length === 0) { this._popover.hide(); this.place = null; return; } if (this._filter.iter_n_children(null) > 0) this._popover.showCompletion(); else this._popover.hide(); }).bind(this)); if (parseOnFocusOut) { this.connect('focus-out-event', (function() { this._parse(); return false; }).bind(this)); } }, _locEquals: function(placeA, placeB) { if (!placeA.location || !placeB.location) return false; return (placeA.location.latitude === placeB.location.latitude && placeA.location.longitude === placeB.location.longitude); }, _createPopover: function(numVisible, maxChars) { let popover = new PlacePopover.PlacePopover({ num_visible: numVisible, relative_to: this, maxChars: maxChars}); this.connect('size-allocate', (function(widget, allocation) { // Magic number to make the alignment pixel perfect. let width_request = allocation.width + 20; popover.width_request = width_request; }).bind(this)); popover.connect('selected', (function(widget, place) { this.place = place; popover.hide(); }).bind(this)); return popover; }, _refreshFilter: function() { /* Filter model based on input text */ this._filter.refilter(); this._popover.updateCompletion(this._filter, this.text); }, _completionVisibleFunc: function(model, iter) { let place = model.get_value(iter, PlaceStore.Columns.PLACE); let type = model.get_value(iter, PlaceStore.Columns.TYPE); if (!this._matchRoute && type === PlaceStore.PlaceType.RECENT_ROUTE) return false; if (place !== null) return place.match(this.text); else return false; }, _parse: function() { if (this.text.length === 0) { this.place = null; return true; } if (this.text.startsWith('geo:')) { let location = new Geocode.Location(); try { location.set_from_uri(this.text); this.place = new Place.Place({ location: location }); } catch(e) { let msg = _("Failed to parse Geo URI"); Application.notificationManager.showMessage(msg); } return true; } let parsedLocation = Place.Place.parseCoordinates(this.text); if (parsedLocation) { this.place = new Place.Place({ location: parsedLocation }); return true; } return false; }, _onActivate: function() { if (this._parse()) return; let bbox = this._mapView.view.get_bounding_box(); this._popover.showSpinner(); this._cancellable = new Gio.Cancellable(); Application.geocodeService.search(this.text, bbox, this._cancellable, (function(places) { if (!places) { this.place = null; this._popover.hide(); return; } this._popover.updateResult(places, this.text); this._popover.showResult(); }).bind(this)); } });