[gnome-maps/wip/places: 3/6] Add store for recent and favorite places
- From: Jonas Danielsson <jonasdn src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-maps/wip/places: 3/6] Add store for recent and favorite places
- Date: Tue, 14 Jan 2014 20:50:23 +0000 (UTC)
commit b47ce23506908213f4afdb8daa89ee9e2c4be731
Author: Jonas Danielsson <jonas threetimestwo org>
Date: Mon Jan 13 13:27:32 2014 +0100
Add store for recent and favorite places
This patch adds the PlaceStore object that extends GtkListStore.
Recent places can be added to the store and be written to file using
the JSON format.
If adding a recent place exceeds the limit for recent places the
oldest recent place will be removed.
https://bugzilla.gnome.org/show_bug.cgi?id=722102
src/Makefile-js.am | 3 +-
src/placeStore.js | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/utils.js | 25 +++++++
3 files changed, 221 insertions(+), 1 deletions(-)
---
diff --git a/src/Makefile-js.am b/src/Makefile-js.am
index 134fbd1..a7055f5 100644
--- a/src/Makefile-js.am
+++ b/src/Makefile-js.am
@@ -13,7 +13,8 @@ dist_js_DATA = \
geoclue.js \
zoomControl.js \
searchPopup.js \
- contextMenu.js
+ contextMenu.js \
+ placeStore.js
BUILT_SOURCES += \
path.js \
diff --git a/src/placeStore.js b/src/placeStore.js
new file mode 100644
index 0000000..cdbbfeb
--- /dev/null
+++ b/src/placeStore.js
@@ -0,0 +1,194 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Jonas Danielsson <jonas threetimestwo org>
+ */
+
+const Geocode = imports.gi.GeocodeGlib;
+const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
+const Gio = imports.gi.Gio;
+const GdkPixbuf = imports.gi.GdkPixbuf;
+const Gtk = imports.gi.Gtk;
+
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+
+const Utils = imports.utils;
+const Application = imports.application;
+
+const _PLACES_STORE_FILE = 'maps-places.json';
+const _ICON_SIZE = 20;
+
+const PlaceType = {
+ ANY: -1,
+ RECENT: 0,
+};
+
+const Columns = {
+ PLACE_ICON: 0,
+ PLACE: 1,
+ NAME: 2,
+ TYPE: 3,
+ ADDED: 4
+};
+
+const PlaceStore = new Lang.Class({
+ Name: 'PlaceStore',
+ Extends: Gtk.ListStore,
+
+ _init: function() {
+ this._dirty = false;
+ this.recentLimit = Application.settings.get('recent-places-limit');
+ this._numRecent = 0;
+ this.filename = GLib.build_filenamev([GLib.get_user_data_dir(),
+ _PLACES_STORE_FILE]);
+ this._typeTable = {};
+
+ this.parent();
+ this.set_column_types([GdkPixbuf.Pixbuf,
+ GObject.TYPE_OBJECT,
+ GObject.TYPE_STRING,
+ GObject.TYPE_INT,
+ GObject.TYPE_DOUBLE]);
+ },
+
+ addRecent: function(place) {
+ if (this._exists(place, PlaceType.RECENT))
+ return;
+
+ if (this._numRecent === this.recentLimit) {
+ // Since all we do is append, the oldest recent will be
+ // the first one we encounter.
+ this._removeIf((function(model, iter) {
+ let type = model.get_value(iter, Columns.TYPE);
+ return type === PlaceType.RECENT;
+ }), true);
+ }
+ this._addPlace(place, PlaceType.RECENT, new Date().getTime());
+ this._numRecent++;
+ },
+
+ load: function() {
+ if (!GLib.file_test(this.filename, GLib.FileTest.EXISTS))
+ return;
+
+ let buffer = Utils.readFile(this.filename);
+ if (buffer === null)
+ return;
+
+ try {
+ let jsonArray = JSON.parse(buffer);
+ jsonArray.forEach((function(jsonObject) {
+ let name = jsonObject.name;
+ let location = new Geocode.Location({
+ latitude: jsonObject.latitude,
+ longitude: jsonObject.longitude,
+ altitude: jsonObject.altitude,
+ accuracy: jsonObject.accuracy,
+ description: name
+ });
+ let place_type = jsonObject.poi_type;
+ let place = Geocode.Place.new_with_location(name,
+ place_type,
+ location);
+ let type = jsonObject.type;
+ let added = jsonObject.added;
+
+ this._addPlace(place, type, added);
+ if (type === PlaceType.RECENT)
+ this._numRecent++;
+ }).bind(this));
+ } catch (e) {
+ throw new Error('failed to parse places file');
+ }
+ },
+
+ store: function() {
+ if (!this._dirty)
+ return;
+
+ let jsonArray = [];
+ this.foreach(function(model, path, iter) {
+ let place = model.get_value(iter, Columns.PLACE);
+ let location = place.location;
+ let type = model.get_value(iter, Columns.TYPE);
+ let added = model.get_value(iter, Columns.ADDED);
+
+ let jsonObject = {};
+ jsonObject.poi_type = place.place_type;
+ jsonObject.name = place.name;
+ jsonObject.latitude = location.latitude;
+ jsonObject.longitude = location.longitude;
+ jsonObject.altitude = location.altitude;
+ jsonObject.accuracy = location.accuracy;
+ jsonObject.type = type;
+ jsonObject.added = added;
+
+ jsonArray.push(jsonObject);
+ });
+
+ let buffer = JSON.stringify(jsonArray);
+ if (!Utils.writeFile(this.filename, buffer))
+ throw new Error('failed to write file');
+ else
+ this.dirty = false;
+ },
+
+ _addPlace: function(place, type, added) {
+ let iter = this.append();
+
+ this.set(iter,
+ [Columns.PLACE,
+ Columns.NAME,
+ Columns.TYPE,
+ Columns.ADDED],
+ [place,
+ place.name,
+ type,
+ added]);
+
+ if (place.icon !== null) {
+ Utils.load_icon(place.icon, _ICON_SIZE, (function(pixbuf) {
+ this.set(iter, [Columns.ICON], [pixbuf]);
+ }).bind(this));
+ }
+ this._typeTable[place.name] = type;
+ this._dirty = true;
+
+ try {
+ this.store();
+ } catch (e) {
+ Utils.debug(e);
+ }
+ },
+
+ _exists: function(place, type) {
+ return this._typeTable[place.name] === type;
+ },
+
+ _removeIf: function(evalFunc, stop) {
+ this.foreach((function(model, path, iter) {
+ if (evalFunc(model, iter)) {
+ this.remove(iter);
+ if (stop)
+ return true;
+ }
+ return false;
+ }).bind(this));
+ },
+});
diff --git a/src/utils.js b/src/utils.js
index d7d17b4..631ca12 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -134,6 +134,31 @@ function getUIObject(res, ids) {
return ret;
}
+function readFile(filename) {
+ let status, buffer;
+ let file = Gio.File.new_for_path(filename);
+ try {
+ [status, buffer] = file.load_contents(null);
+ } catch (e) {
+ return null;
+ }
+ if (status)
+ return buffer;
+ else
+ return null;
+}
+
+function writeFile(filename, buffer) {
+ let file = Gio.File.new_for_path(filename);
+ let status;
+ try {
+ status = file.replace_contents(buffer, null, false, 0, null)[0];
+ return status;
+ } catch (e) {
+ return false;
+ }
+}
+
function load_icon(icon, size, loadCompleteCallback) {
if (icon instanceof Gio.FileIcon) {
_load_file_icon(icon, loadCompleteCallback);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]