[gnome-weather] Improve split between the model and view for the world module
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-weather] Improve split between the model and view for the world module
- Date: Sun, 3 Aug 2014 13:39:18 +0000 (UTC)
commit 69ba00ac225efee9a4d4e29722d51b14d2d102ff
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sun Aug 3 15:05:51 2014 +0200
Improve split between the model and view for the world module
Split world.js into shared/world.js, which contains the model
(a simple array of GWeatherInfos backed by GSettings), and app/world.js,
which contains the view (a GtkPopover holding a GtkListBox).
This will allow restoring the functionality of the search provider.
data/places-popover.ui | 75 +----
data/window.ui | 75 ++++-
src/app/main.js | 70 +---
src/app/window.js | 43 ++-
src/app/world.js | 213 +++++++++++
...org.gnome.Weather.Application.src.gresource.xml | 1 +
src/shared/world.js | 389 ++++----------------
7 files changed, 411 insertions(+), 455 deletions(-)
---
diff --git a/data/places-popover.ui b/data/places-popover.ui
index 3a80f68..885ab40 100644
--- a/data/places-popover.ui
+++ b/data/places-popover.ui
@@ -198,6 +198,7 @@
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">False</property>
+ <property name="selection-mode">none</property>
</object>
</child>
</object>
@@ -222,78 +223,4 @@
</packing>
</child>
</object>
- <object class="GtkGrid" id="initial-grid">
- <property name="visible">True</property>
- <property name="name">initial-grid</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="margin_top">25</property>
- <property name="margin_bottom">25</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="row_homogeneous">True</property>
- <property name="vexpand">False</property>
- <child>
- <object class="GtkImage" id="mark-location-image">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">mark-location-symbolic</property>
- <property name="icon_size">6</property>
- <property name="use_fallback">True</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="vexpand">False</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="search-location-label">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label">Search for a location</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="vexpand">False</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="search-nereby-location-label">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label">To see weather information, enter the name of a city.</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="vexpand">False</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GWeatherLocationEntry" id="initial-grid-location-entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">3</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- </object>
</interface>
diff --git a/data/window.ui b/data/window.ui
index e48d9b3..6cb5e7f 100644
--- a/data/window.ui
+++ b/data/window.ui
@@ -56,7 +56,80 @@
<object class="GtkStack" id="main-stack">
<property name="transition-type">crossfade</property>
<child>
- <placeholder/> <!-- world view -->
+ <object class="GtkGrid" id="initial-grid">
+ <property name="visible">True</property>
+ <property name="name">initial-grid</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="margin_top">25</property>
+ <property name="margin_bottom">25</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="row_homogeneous">True</property>
+ <property name="vexpand">False</property>
+ <child>
+ <object class="GtkImage" id="mark-location-image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">mark-location-symbolic</property>
+ <property name="icon_size">6</property>
+ <property name="use_fallback">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="search-location-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">Search for a location</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="search-nereby-location-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label">To see weather information, enter the name of a city.</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="vexpand">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GWeatherLocationEntry" id="initial-grid-location-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
</child>
<child>
<placeholder/> <!-- city view -->
diff --git a/src/app/main.js b/src/app/main.js
index 0a87ca8..30bd6d7 100644
--- a/src/app/main.js
+++ b/src/app/main.js
@@ -60,21 +60,7 @@ const Application = new Lang.Class({
let location = this.world.deserialize(parameter.deep_unpack());
let win = this._createWindow();
- let info = this.model.getLocationInfo(location);
- if (!info) {
- this.model.addLocation(location, false);
- info = this.model.getLocationInfo(location);
- }
-
- win.showInfo(info);
- },
-
- _onNewLocation: function(action, parameter) {
- let win = this.get_active_window();
- if (!win)
- win = this._createWindow();
-
- win.activate_action('new-location', null);
+ this.model.addNewLocation(location, false);
},
_initAppMenu: function() {
@@ -111,9 +97,7 @@ const Application = new Lang.Class({
activate: this._onQuit },
{ name: 'show-location',
activate: this._onShowLocation,
- parameter_type: new GLib.VariantType('v') },
- { name: 'new-location',
- activate: this._onNewLocation }]);
+ parameter_type: new GLib.VariantType('v') }]);
let gwSettings = new Gio.Settings({ schema_id: 'org.gnome.GWeather' });
this.add_action(gwSettings.create_action('temperature-unit'));
@@ -128,40 +112,26 @@ const Application = new Lang.Class({
let win = new Window.MainWindow({ application: this });
let notifyId;
- if (!this.currentLocationController.autoLocation) {
- if (this.model.loading) {
- let timeoutId;
- let model = this.model;
-
- timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, function() {
- log('Timeout during model load, perhaps the network is not available?');
- model.disconnect(notifyId);
- win.show();
- return false;
- });
- notifyId = this.model.connect('notify::loading', function(model) {
- if (model.loading)
- return;
-
- model.disconnect(notifyId);
- GLib.source_remove(timeoutId);
- win.show();
- });
- } else {
+ if (this.model.loading) {
+ let timeoutId;
+ let model = this.model;
+
+ timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, function() {
+ log('Timeout during model load, perhaps the network is not available?');
+ model.disconnect(notifyId);
win.show();
- }
- } else {
- if (this.model.loading) {
- notifyId = this.model.connect('notify::loading', Lang.bind(this, function(model) {
- if (model.loading)
- return;
-
- model.disconnect(notifyId);
- win.show();
- }));
- } else {
+ return false;
+ });
+ notifyId = this.model.connect('notify::loading', function(model) {
+ if (model.loading)
+ return;
+
+ model.disconnect(notifyId);
+ GLib.source_remove(timeoutId);
win.show();
- }
+ });
+ } else {
+ win.show();
}
return win;
diff --git a/src/app/window.js b/src/app/window.js
index 444635c..19b82d7 100644
--- a/src/app/window.js
+++ b/src/app/window.js
@@ -23,10 +23,11 @@ const Lang = imports.lang;
const City = imports.app.city;
const Params = imports.misc.params;
const World = imports.shared.world;
+const WorldView = imports.app.world;
const Util = imports.misc.util;
const Page = {
- WORLD: 0,
+ SEARCH: 0,
CITY: 1
};
@@ -41,7 +42,7 @@ const MainWindow = new Lang.Class({
this._world = this.application.world;
this._currentInfo = null;
- this._currentPage = Page.WORLD;
+ this._currentPage = Page.SEARCH;
this._pageWidgets = [[],[]];
Util.initActions(this,
@@ -62,20 +63,21 @@ const MainWindow = new Lang.Class({
this._header.title = title;
this._header.subtitle = subtitle;
- this._worldView = new World.WorldContentView(this.application, { visible: true });
+ this._worldView = new WorldView.WorldContentView(this.application, { visible: true });
this._worldView.hide();
this._model = this._worldView.model;
this._model.connect('show-info', Lang.bind(this, function(model, info) {
- this.showInfo(info);
- }));
- this._model.connect('no-cityview', Lang.bind(this, function() {
- for (let i = 0; i < this._pageWidgets[Page.WORLD].length; i++)
- this._pageWidgets[Page.WORLD][i].show_all();
+ if (info)
+ this.showInfo(info);
+ else
+ this.showSearch(info);
}));
- this._initialGrid = this._worldView.initialGrid;
- this._pageWidgets[Page.WORLD].push(this._initialGrid);
+ let initialGrid = builder.get_object('initial-grid');
+
+ let initialGridLocEntry = builder.get_object('initial-grid-location-entry');
+ initialGridLocEntry.connect('notify::location', Lang.bind(this, this._initialLocationChanged));
let placesButton = builder.get_object('places-button');
this._pageWidgets[Page.CITY].push(placesButton);
@@ -91,9 +93,7 @@ const MainWindow = new Lang.Class({
vexpand: true });
this._stack.add(this._cityView);
- this._stack.add(this._initialGrid);
-
- this._stack.set_visible_child(this._initialGrid);
+ this._stack.set_visible_child(initialGrid);
this.add(grid);
grid.show_all();
@@ -101,15 +101,22 @@ const MainWindow = new Lang.Class({
for (let i = 0; i < this._pageWidgets[Page.CITY].length; i++)
this._pageWidgets[Page.CITY][i].hide();
- this._model.fillCityView(this.application.currentLocationController.autoLocation);
+ let autoLocation = this.application.currentLocationController.autoLocation;
+ if (!autoLocation)
+ this._model.showRecent();
},
update: function() {
this._cityView.update();
},
+ _initialLocationChanged: function(entry) {
+ if (entry.location)
+ this._model.addNewLocation(entry.location, false);
+ },
+
_getTitle: function() {
- if (this._currentPage == Page.WORLD)
+ if (this._currentPage == Page.SEARCH)
return [_("Select Location"), null];
let location = this._cityView.info.location;
@@ -145,9 +152,14 @@ const MainWindow = new Lang.Class({
this._header.subtitle = subtitle;
},
+ showSearch: function() {
+ this._goToPage(Page.SEARCH);
+ },
+
showInfo: function(info) {
this._cityView.info = info;
this._cityView.disconnectClock();
+
let isCurrentLocation = false;
let currentLocation = this.application.currentLocationController.currentLocation;
if (currentLocation) {
@@ -159,6 +171,7 @@ const MainWindow = new Lang.Class({
this._cityView.connectClock();
this._cityView.infoPage.timeGrid.show();
}
+
this._stack.set_visible_child(this._cityView);
this._goToPage(Page.CITY);
},
diff --git a/src/app/world.js b/src/app/world.js
new file mode 100644
index 0000000..32edaff
--- /dev/null
+++ b/src/app/world.js
@@ -0,0 +1,213 @@
+// -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
+//
+// Copyright (c) 2012 Giovanni Campagna <scampa giovanni gmail com>
+// 2014 Saurabh Patel <srp201201051 gmail com>
+//
+// Gnome Weather 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 Weather 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 Weather; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
+const Gtk = imports.gi.Gtk;
+const GWeather = imports.gi.GWeather;
+const Lang = imports.lang;
+
+const Params = imports.misc.params;
+const Util = imports.misc.util;
+
+
+const WorldContentView = new Lang.Class({
+ Name: 'WorldContentView',
+ Extends: Gtk.Popover,
+
+ _init: function(application, params) {
+ params = Params.fill(params, { hexpand: false, vexpand: false });
+ this.parent(params);
+
+ this.get_accessible().accessible_name = _("World view");
+
+ let builder = new Gtk.Builder();
+ builder.add_from_resource('/org/gnome/Weather/Application/places-popover.ui');
+
+ let grid = builder.get_object('popover-grid');
+ this.add(grid);
+
+ this.model = application.model;
+
+ this._listbox = builder.get_object('locations-list-box');
+ this._listbox.set_header_func(function (row, previous) {
+ let hasHeader = row.get_header() != null;
+ let shouldHaveHeader = previous != null;
+ if (hasHeader != shouldHaveHeader) {
+ if (shouldHaveHeader)
+ row.set_header(new Gtk.Separator());
+ else
+ row.set_header(null);
+ }
+ });
+
+ let locationEntry = builder.get_object('location-entry');
+ locationEntry.connect('notify::location', Lang.bind(this, this._locationChanged));
+
+ this.connect('show', Lang.bind(this, function() {
+ locationEntry.grab_focus();
+ }));
+
+ let autoLocStack = builder.get_object('auto-location-stack');
+ let autoLocSwitch = builder.get_object('auto-location-switch');
+ let currentLocationController = application.currentLocationController;
+
+ if(currentLocationController.autoLocation) {
+ autoLocStack.visible_child_name = 'locating-label';
+ } else {
+ autoLocStack.visible_child_name = 'auto-location-switch-grid';
+ autoLocSwitch.active = false;
+ }
+
+ let handlerId = autoLocSwitch.connect('notify::active', Lang.bind(this, function() {
+ currentLocationController.setAutoLocation(autoLocSwitch.active);
+
+ if (autoLocSwitch.active && !this.model.addedCurrentLocation)
+ autoLocStack.visible_child_name = 'locating-label';
+
+ this.hide();
+ }));
+
+ this._listbox.connect('row-activated', Lang.bind(this, function(listbox, row) {
+ this.hide();
+ this.model.showInfo(row._info);
+ }));
+
+ this.model.connect('current-location-changed', Lang.bind(this, function(model, location) {
+ autoLocStack.visible_child_name = 'auto-location-switch-grid';
+ if (location) {
+ GObject.signal_handler_block(autoLocSwitch, handlerId);
+ autoLocSwitch.active = true;
+ GObject.signal_handler_unblock(autoLocSwitch, handlerId);
+ } else {
+ GObject.signal_handler_block(autoLocSwitch, handlerId);
+ autoLocSwitch.active = false;
+ GObject.signal_handler_unblock(autoLocSwitch, handlerId);
+
+ autoLocSwitch.sensitive = false;
+ }
+ }));
+
+ let stackPopover = builder.get_object('popover-stack');
+ this.model.connect('revalidate', Lang.bind(this, function() {
+ this._listbox.invalidate_filter();
+
+ let children = this._listbox.get_children();
+ if (children.length == 1)
+ stackPopover.set_visible_child_name("search-grid");
+ else
+ stackPopover.set_visible_child_name("locations-grid");
+ }));
+
+ this._listbox.set_filter_func(Lang.bind(this, this._filterListbox, this.model));
+ this.model.connect('location-added', Lang.bind(this, this._onLocationAdded));
+ this.model.connect('location-removed', Lang.bind(this, this._onLocationRemoved));
+
+ this.model.load();
+ },
+
+ _filterListbox: function(row, model) {
+ return model.currentlyLoadedInfo == null ||
+ row._info != model.currentlyLoadedInfo;
+ },
+
+ _locationChanged: function(entry) {
+ if (entry.location) {
+ this.model.addNewLocation(entry.location, false);
+ this.hide();
+ entry.location = null;
+ }
+ },
+
+ _onLocationAdded: function(model, info, isCurrentLocation) {
+ let location = info.location;
+
+ let grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
+ column_spacing: 12,
+ margin: 12,
+ visible: true });
+
+ let name = location.get_city_name();
+ let locationGrid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
+ column_spacing: 12,
+ halign: Gtk.Align.START,
+ hexpand: true,
+ visible: true });
+ let locationLabel = new Gtk.Label({ label: name,
+ use_markup: true,
+ halign: Gtk.Align.START,
+ visible: true });
+ locationGrid.attach(locationLabel, 0, 0, 1, 1);
+ grid.attach(locationGrid, 0, 0, 1, 1);
+
+ let tempLabel = new Gtk.Label({ use_markup: true,
+ halign: Gtk.Align.END,
+ margin_start: 12,
+ visible: true });
+ grid.attach(tempLabel, 1, 0, 1, 1);
+
+ if (isCurrentLocation) {
+ let image = new Gtk.Image({ icon_size: Gtk.IconSize.LARGE_TOOLBAR,
+ icon_name: 'mark-location-symbolic',
+ use_fallback: true,
+ halign: Gtk.Align.START,
+ visible: true });
+ locationGrid.attach(image, 1, 0, 1, 1);
+ }
+
+ let image = new Gtk.Image({ icon_size: Gtk.IconSize.LARGE_TOOLBAR,
+ use_fallback: true,
+ halign: Gtk.Align.END,
+ visible: true });
+ grid.attach(image, 2, 0, 1, 1);
+
+ let row = new Gtk.ListBoxRow({ visible: true });
+ row.add(grid);
+ row._info = info;
+
+ if (isCurrentLocation) {
+ if (model.addedCurrentLocation) {
+ this._listbox.get_row_at_index(0).destroy();
+ }
+
+ this._listbox.insert(row, 0);
+ } else {
+ if (model.addedCurrentLocation)
+ this._listbox.insert(row, 1);
+ else
+ this._listbox.insert(row, 0);
+ }
+
+ info.connect('updated', Lang.bind(this, function(info) {
+ tempLabel.label = info.get_temp_summary();
+ image.icon_name = info.get_symbolic_icon_name();
+ }));
+ },
+
+ _onLocationRemoved: function(model, info) {
+ let rows = this._listbox.get_children();
+
+ for (let row of rows) {
+ if (row._info == info) {
+ row.destroy();
+ break;
+ }
+ }
+ },
+});
diff --git a/src/org.gnome.Weather.Application.src.gresource.xml
b/src/org.gnome.Weather.Application.src.gresource.xml
index 33a1ebe..0d91f1c 100644
--- a/src/org.gnome.Weather.Application.src.gresource.xml
+++ b/src/org.gnome.Weather.Application.src.gresource.xml
@@ -7,6 +7,7 @@
<file>app/weeklyForecast.js</file>
<file>app/main.js</file>
<file>app/window.js</file>
+ <file>app/world.js</file>
<file>misc/params.js</file>
<file>misc/util.js</file>
<file>shared/strings.js</file>
diff --git a/src/shared/world.js b/src/shared/world.js
index 461c0f8..2ce4ee0 100644
--- a/src/shared/world.js
+++ b/src/shared/world.js
@@ -18,30 +18,21 @@
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
const GWeather = imports.gi.GWeather;
const Lang = imports.lang;
const Params = imports.misc.params;
const Util = imports.misc.util;
-function getLabelFromRow(row) {
- let grid = row.get_child();
- let cityGrid = grid.get_child_at(0, 0);
- let label = cityGrid.get_child_at(0, 0);
- return label.get_text();
-}
-
const WorldModel = new Lang.Class({
Name: 'WorldModel',
Extends: GObject.Object,
Signals: {
- 'updated': { param_types: [ GWeather.Info ] },
- 'no-cityview': { param_types: [] },
'show-info': { param_types: [ GWeather.Info ] },
'current-location-changed': { param_types: [ GWeather.Location ] },
- 'validate-listbox': { param_types: [ GWeather.Location ] },
- 'update-listbox': { param_types: [ GWeather.Location, GWeather.Info, GObject.Boolean ] }
+ 'revalidate': { param_types: [ GWeather.Location ] },
+ 'location-added': { param_types: [ GWeather.Info, GObject.Boolean ] },
+ 'location-removed': { param_types: [ GWeather.Info ] }
},
Properties: {
'loading': GObject.ParamSpec.boolean('loading', '', '', GObject.ParamFlags.READABLE, false)
@@ -53,108 +44,62 @@ const WorldModel = new Lang.Class({
this._world = world;
this._settings = Util.getSettings('org.gnome.Weather.Application');
-
this._providers = Util.getEnabledProviders();
this._loadingCount = 0;
this._infoList = [];
- this._enableGtk = enableGtk;
-
- this._currentLocationInfo = null;
-
this.currentlyLoadedInfo = null;
-
this.addedCurrentLocation = false;
+ },
- this.numberOfLocations = 0;
+ get length() {
+ return this._infoList.length;
+ },
+
+ getAll: function() {
+ return [].concat(this._infoList);
},
currentLocationChanged: function(location) {
if (location) {
- this._newCurrentLocationInfo = new GWeather.Info({ location: location,
- enabled_providers: this._providers });
- if (this._currentLocationInfo) {
- if (!this._currentLocationInfo.location.equal(location)) {
- this._newCurrentLocationInfo.connect('updated', Lang.bind(this, function(info) {
- this._updateLoadingCount(-1);
- this.emit('updated', this._newCurrentLocationInfo);
- }));
- this.updateInfo(this._newCurrentLocationInfo);
- this._currentLocationInfo = this._newCurrentLocationInfo;
- }
- } else {
- this._newCurrentLocationInfo.connect('updated', Lang.bind(this, function(info) {
- this._updateLoadingCount(-1);
- this.emit('updated', this._newCurrentLocationInfo);
- }));
- this.updateInfo(this._newCurrentLocationInfo);
- this._currentLocationInfo = this._newCurrentLocationInfo;
- }
+ this.addNewLocation(location, true);
+ } else {
+ if (!this.addedCurrentLocation)
+ this.showRecent();
}
this.emit('current-location-changed', location);
},
- rowActivated: function(listbox, row) {
- let cityName = getLabelFromRow(row);
- this.emit('show-info', this._infoList[cityName]);
- this.currentlyLoadedInfo = this._infoList[cityName];
- this.emit('validate-listbox', this.currentlyLoadedInfo.location);
+ showInfo: function(info) {
+ this.currentlyLoadedInfo = info;
+ this.emit('show-info', info);
+ if (info != null)
+ this.emit('revalidate', info.location);
},
showRecent: function(listbox) {
- let row = listbox.get_row_at_index(0);
- if (row) {
- this.rowActivated(null, row);
- return;
- } else
- this.emit('no-cityview');
- },
-
- _showCurrentLocation: function() {
- if (this._currentLocationInfo) {
- this.emit('show-info', this._currentLocationInfo);
- this.currentlyLoadedInfo = this._currentLocationInfo;
- }
+ if (this._infoList.length > 0)
+ this.showInfo(this._infoList[0]);
+ else
+ this.showInfo(null);
},
- fillListbox: function () {
+ load: function () {
let locations = this._settings.get_value('locations').deep_unpack();
- this.numberOfLocations = locations.length;
- if (locations.length != 0) {
- for (let i = 0; i < locations.length && i < 5; i++) {
- let variant = locations[i];
- let location = this._world.deserialize(variant);
- let info = new GWeather.Info({ location: location,
- enabled_providers: this._providers });
-
- this._infoList[location.get_city_name()] = info;
-
- info.connect('updated', Lang.bind(this, function(info) {
- this._updateLoadingCount(-1);
- this.emit('updated', info);
- }));
- this.updateInfo(info);
- this.emit('update-listbox', location, info, false);
- }
+
+ if (locations.length > 5) {
+ locations = locations.slice(0, 5);
+ this._settings.set_value('locations', new GLib.Variant('av', locations));
}
- },
- fillCityView: function(autoLocation) {
- let locations = this._settings.get_value('locations').deep_unpack();
+ for (let i = 0; i < locations.length; i++) {
+ let variant = locations[i];
+ let location = this._world.deserialize(variant);
- if (!autoLocation) {
- if (locations.length > 0) {
- let variant = locations[locations.length-1];
- let location = this._world.deserialize(variant);
- this.emit('show-info', this._infoList[location.get_city_name()]);
- this.currentlyLoadedInfo = this._infoList[location.get_city_name()];
- this.emit('validate-listbox', this.currentlyLoadedInfo.location);
- } else {
- this.emit('no-cityview');
- }
+ this._addLocationInternal(location, false);
}
},
@@ -168,6 +113,16 @@ const WorldModel = new Lang.Class({
},
updateInfo: function(info) {
+ if (info._loadingId)
+ return;
+
+ info._loadingId = info.connect('updated', Lang.bind(this, function(info) {
+ info.disconnect(info._loadingId);
+ info._loadingId = 0;
+
+ this._updateLoadingCount(-1);
+ }));
+
info.update();
this._updateLoadingCount(+1);
},
@@ -177,249 +132,53 @@ const WorldModel = new Lang.Class({
},
addNewLocation: function(newLocation, isCurrentLocation) {
- if (newLocation) {
- let locations = this._settings.get_value('locations').deep_unpack();
-
- if (!isCurrentLocation) {
- for (let i = 0; i < locations.length; i++) {
- let location = this._world.deserialize(locations[i]);
- if (location.equal(newLocation)) {
- this.emit('show-info', this._infoList[location.get_city_name()]);
- this.currentlyLoadedInfo = this._infoList[location.get_city_name()];
- this.emit('validate-listbox', this.currentlyLoadedInfo.location);
- return;
- }
+ if (!isCurrentLocation) {
+ for (let info of this._infoList) {
+ let location = info.location;
+ if (location.equal(newLocation)) {
+ this.showInfo(info);
+ return;
}
-
- locations.push(newLocation.serialize());
-
- this.numberOfLocations = locations.length;
-
- this._settings.set_value('locations', new GLib.Variant('av', locations));
}
- let info = new GWeather.Info({ location: newLocation,
- enabled_providers: this._providers });
-
- this._infoList[newLocation.get_city_name()] = info;
-
- info.connect('updated', Lang.bind(this, function(info) {
- this._updateLoadingCount(-1);
- this.emit('updated', info);
- }));
- this.updateInfo(info);
-
- this.emit('update-listbox', newLocation, info, isCurrentLocation);
- if (!isCurrentLocation) {
- this.emit('show-info', this._infoList[newLocation.get_city_name()]);
- this.currentlyLoadedInfo = this._infoList[newLocation.get_city_name()];
- this.emit('validate-listbox', this.currentlyLoadedInfo.location);
- }
- else {
- if(!this.addedCurrentLocation) {
- this.emit('show-info', this._currentLocationInfo);
- this.currentlyLoadedInfo = this._currentLocationInfo;
- this.emit('validate-listbox', this.currentlyLoadedInfo.location);
- }
- this.addedCurrentLocation = true;
- }
+ let locations = this._settings.get_value('locations').deep_unpack();
+ locations.push(newLocation.serialize());
+ this._settings.set_value('locations', new GLib.Variant('av', locations));
}
- }
-});
-
-const WorldContentView = new Lang.Class({
- Name: 'WorldContentView',
- Extends: Gtk.Popover,
-
- _init: function(application, params) {
- params = Params.fill(params, { hexpand: false, vexpand: false });
- this.parent(params);
-
- this.get_accessible().accessible_name = _("World view");
-
- let builder = new Gtk.Builder();
- builder.add_from_resource('/org/gnome/Weather/Application/places-popover.ui');
-
- let grid = builder.get_object('popover-grid');
- this.add(grid);
- this.initialGrid = builder.get_object('initial-grid');
-
- let stackPopover = builder.get_object('popover-stack');
-
- this.model = application.model;
-
- this._listbox = builder.get_object('locations-list-box');
- this._listbox.set_header_func(function (row, previous) {
- let hasHeader = row.get_header() != null;
- let shouldHaveHeader = previous != null;
- if (hasHeader != shouldHaveHeader) {
- if (shouldHaveHeader)
- row.set_header(new Gtk.Separator());
- else
- row.set_header(null);
- }
- });
-
- let initialGridLocEntry = builder.get_object('initial-grid-location-entry');
- initialGridLocEntry.connect('notify::location', Lang.bind(this, function(entry) {
- this._locationChanged(entry);
- }));
-
- let locationEntry = builder.get_object('location-entry');
- locationEntry.connect('notify::location', Lang.bind(this, function(entry) {
- this._locationChanged(entry)
- }));
-
- this.connect('notify::visible', Lang.bind(this, function() {
- this._listbox.set_selection_mode(0);
- locationEntry.grab_focus();
- this._listbox.set_selection_mode(1);
- }));
-
- let autoLocStack = builder.get_object('auto-location-stack');
-
- let autoLocSwitch = builder.get_object('auto-location-switch');
-
- let currentLocationController = application.currentLocationController;
-
- let handlerId = autoLocSwitch.connect('notify::active', Lang.bind(this, function() {
- currentLocationController.setAutoLocation(autoLocSwitch.get_active());
-
- if (autoLocSwitch.get_active() && !this.model.addedCurrentLocation)
- autoLocStack.set_visible_child_name('locating-label');
-
- this.hide();
- }));
+ this._addLocationInternal(newLocation, isCurrentLocation);
+ },
- if(currentLocationController.autoLocation)
- autoLocStack.set_visible_child_name('locating-label');
- else {
- autoLocStack.set_visible_child_name('auto-location-switch-grid');
- GObject.signal_handler_block(autoLocSwitch, handlerId);
- autoLocSwitch.set_active(false);
- GObject.signal_handler_unblock(autoLocSwitch, handlerId);
+ _removeLocationInternal: function(oldInfo) {
+ if (oldInfo._loadingId) {
+ oldInfo.disconnect(oldInfo._loadingId);
+ oldInfo._loadingId = 0;
+ this._updateLoadingCount(-1);
}
- this._listbox.connect('row-activated', Lang.bind(this, function(listbox, row) {
- this.hide();
- this.model.rowActivated(listbox, row);
- }));
-
- this.model.connect('current-location-changed', Lang.bind(this, function(model, location) {
- autoLocStack.set_visible_child_name('auto-location-switch-grid');
- if (location) {
- this.model.addNewLocation(location, true);
-
- GObject.signal_handler_block(autoLocSwitch, handlerId);
- autoLocSwitch.set_active(true);
- GObject.signal_handler_unblock(autoLocSwitch, handlerId);
- } else {
- if (!this.model.addedCurrentLocation)
- this.model.showRecent(this._listbox);
-
- GObject.signal_handler_block(autoLocSwitch, handlerId);
- autoLocSwitch.set_active(false);
- GObject.signal_handler_unblock(autoLocSwitch, handlerId);
-
- autoLocSwitch.set_sensitive(false);
- }
- }));
-
- this.model.connect('validate-listbox', Lang.bind(this, function() {
- this._listbox.invalidate_filter();
- let children = this._listbox.get_children();
- if (children.length == 1) {
- stackPopover.set_visible_child_name("search-grid");
- return;
- }
- stackPopover.set_visible_child_name("locations-grid");
- }));
-
- this._listbox.set_filter_func(Lang.bind(this, this._filterListbox, this.model));
-
- this.model.connect('update-listbox', Lang.bind(this, this._addLocationInternal));
-
- this.model.fillListbox();
+ this.emit('location-removed', oldInfo);
},
- _filterListbox: function(row, model) {
- if(model.currentlyLoadedInfo) {
- let cityName = getLabelFromRow(row);
- let loadedCity = model.currentlyLoadedInfo.location.get_city_name();
- return (cityName != loadedCity);
- }
- return true;
- },
+ _addLocationInternal: function(newLocation, isCurrentLocation) {
+ let info = new GWeather.Info({ location: newLocation,
+ enabled_providers: this._providers });
+ this._infoList.push(info);
+ this.updateInfo(info);
- _locationChanged: function(entry) {
- if (entry.location) {
- this.model.addNewLocation(entry.location, false);
- this.hide();
- entry.location = null;
- }
- },
+ this.emit('location-added', info, isCurrentLocation);
- _addLocationInternal: function(model, location, info, isCurrentLocation) {
- let grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
- column_spacing: 12,
- margin: 12 });
-
- let name = location.get_city_name();
- let locationGrid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
- column_spacing: 12,
- halign: Gtk.Align.START,
- hexpand: true,
- visible: true });
- let locationLabel = new Gtk.Label({ label: name,
- use_markup: true,
- halign: Gtk.Align.START,
- visible: true });
- locationGrid.attach(locationLabel, 0, 0, 1, 1);
- grid.attach(locationGrid, 0, 0, 1, 1);
-
- let tempLabel = new Gtk.Label({ use_markup: true,
- halign: Gtk.Align.END,
- margin_start: 12,
- visible: true });
- grid.attach(tempLabel, 1, 0, 1, 1);
+ if (this._infoList.length > 5) {
+ let oldInfo = this._infoList.pop();
+ this._removeLocationInternal(oldInfo);
+ }
if (isCurrentLocation) {
- let image = new Gtk.Image({ icon_size: Gtk.IconSize.LARGE_TOOLBAR,
- icon_name: 'mark-location-symbolic',
- use_fallback: true,
- halign: Gtk.Align.START,
- visible: true });
- locationGrid.attach(image, 1, 0, 1, 1);
- }
+ if(!this.addedCurrentLocation)
+ this.showInfo(info);
- let image = new Gtk.Image({ icon_size: Gtk.IconSize.LARGE_TOOLBAR,
- use_fallback: true,
- halign: Gtk.Align.END,
- visible: true });
- grid.attach(image, 2, 0, 1, 1);
-
- grid.show();
- if(isCurrentLocation) {
- if (model.addedCurrentLocation) {
- let children = this._listbox.get_children();
- children[0].destroy();
- }
- this._listbox.insert(grid, 0);
+ this.addedCurrentLocation = true;
} else {
- if (model.addedCurrentLocation)
- this._listbox.insert(grid, 1);
- else
- this._listbox.insert(grid, 0);
+ this.showInfo(info);
}
- if (model.numberOfLocations > 5) {
- let children = this._listbox.get_children();
- children[children.length-1].destroy();
- }
-
- info.connect('updated', Lang.bind(this, function(info) {
- tempLabel.label = info.get_temp_summary();
- image.icon_name = info.get_symbolic_icon_name();
- }));
- },
+ }
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]