[gnome-maps/wip/mlundblad/osm-add-location: 4/5] osmEdit: WIP: Add support for creating new locations in the edit dialog
- From: Marcus Lundblad <mlundblad src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-maps/wip/mlundblad/osm-add-location: 4/5] osmEdit: WIP: Add support for creating new locations in the edit dialog
- Date: Mon, 4 Jan 2016 21:24:32 +0000 (UTC)
commit 50e84d7209695ab2260577b71fad412fb541fb98
Author: Marcus Lundblad <ml update uu se>
Date: Sun Dec 20 23:22:50 2015 +0100
osmEdit: WIP: Add support for creating new locations in the edit dialog
data/org.gnome.Maps.data.gresource.xml | 3 +
data/ui/osm-edit-dialog.ui | 104 ++++++++++++++++++++++++++++++++
data/ui/osm-type-list-row.ui | 29 +++++++++
data/ui/osm-type-search-entry.ui | 10 +++
data/ui/osm-type-search-popover.ui | 16 +++++
src/org.gnome.Maps.src.gresource.xml | 1 +
src/osmEditDialog.js | 102 ++++++++++++++++++++++++++++---
src/osmTypeListRow.js | 52 ++++++++++++++++
src/osmTypeSearchEntry.js | 74 ++++++++++++++++++++++
src/osmTypeSearchPopover.js | 68 +++++++++++++++++++++
10 files changed, 450 insertions(+), 9 deletions(-)
---
diff --git a/data/org.gnome.Maps.data.gresource.xml b/data/org.gnome.Maps.data.gresource.xml
index 3e579f1..4d9a6f5 100644
--- a/data/org.gnome.Maps.data.gresource.xml
+++ b/data/org.gnome.Maps.data.gresource.xml
@@ -16,6 +16,9 @@
<file preprocess="xml-stripblanks">ui/notification.ui</file>
<file preprocess="xml-stripblanks">ui/osm-account-dialog.ui</file>
<file preprocess="xml-stripblanks">ui/osm-edit-dialog.ui</file>
+ <file preprocess="xml-stripblanks">ui/osm-type-list-row.ui</file>
+ <file preprocess="xml-stripblanks">ui/osm-type-search-entry.ui</file>
+ <file preprocess="xml-stripblanks">ui/osm-type-search-popover.ui</file>
<file preprocess="xml-stripblanks">ui/place-bubble.ui</file>
<file preprocess="xml-stripblanks">ui/place-entry.ui</file>
<file preprocess="xml-stripblanks">ui/place-list-row.ui</file>
diff --git a/data/ui/osm-edit-dialog.ui b/data/ui/osm-edit-dialog.ui
index 3f2623d..d1a593b 100644
--- a/data/ui/osm-edit-dialog.ui
+++ b/data/ui/osm-edit-dialog.ui
@@ -51,6 +51,55 @@
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<property name="margin-bottom">12</property>
+ <child>
+ <object class="GtkLabel" id="typeLabel">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="true">Type</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="typeButton">
+ <property name="visible">False</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row-spacing">5</property>
+ <property name="column-spacing">5</property>
+ <child>
+ <object class="GtkLabel" id="typeValueLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">None</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">GTK_ALIGN_END</property>
+ <property name="hexpand">True</property>
+ <property name="icon-name">go-next-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
</object>
</child>
<child>
@@ -159,6 +208,61 @@
<property name="name">upload</property>
</packing>
</child>
+ <child>
+ <object class="GtkGrid" id="typeSearchGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_start">60</property>
+ <property name="margin_end">60</property>
+ <property name="margin_top">15</property>
+ <property name="margin_bottom">30</property>
+ <property name="row-spacing">5</property>
+ <!--
+ <child>
+ <object class="Gjs_OSMTypeSearchEntry" id="typeSearchEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="margin_start">10</property>
+ <property name="margin_end">10</property>
+ <property name="margin_bottom">10</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ -->
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Recently Used</property>
+ <property name="halign">GTK_ALIGN_START</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkListBox" id="recentTypesListBox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">select-type</property>
+ </packing>
+ </child>
</object>
</child>
</object>
diff --git a/data/ui/osm-type-list-row.ui b/data/ui/osm-type-list-row.ui
new file mode 100644
index 0000000..4dda238
--- /dev/null
+++ b/data/ui/osm-type-list-row.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <template class="Gjs_OSMTypeListRow" parent="GtkListBoxRow">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkGrid" id="grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row-homogeneous">True</property>
+ <property name="margin">5</property>
+ <child>
+ <object class="GtkLabel" id="name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">end</property>
+ <property name="hexpand">True</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/osm-type-search-entry.ui b/data/ui/osm-type-search-entry.ui
new file mode 100644
index 0000000..db292a7
--- /dev/null
+++ b/data/ui/osm-type-search-entry.ui
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <template class="Gjs_OSMTypeSearchEntry" parent="GtkSearchEntry">
+ <property name="hexpand">True</property>
+ <property name="margin_start">10</property>
+ <property name="margin_end">10</property>
+ <property name="margin_bottom">10</property>
+ </template>
+</interface>
diff --git a/data/ui/osm-type-search-popover.ui b/data/ui/osm-type-search-popover.ui
new file mode 100644
index 0000000..81e6c35
--- /dev/null
+++ b/data/ui/osm-type-search-popover.ui
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <template class="Gjs_OSMTypeSearchPopover" parent="Gjs_PropagatingSearchPopover">
+ <property name="position">GTK_POS_BOTTOM</property>
+ <property name="modal">False</property>
+ <child>
+ <object class="GtkListBox" id="list">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="expand">True</property>
+ <property name="activate_on_single_click">True</property>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/org.gnome.Maps.src.gresource.xml b/src/org.gnome.Maps.src.gresource.xml
index ec6d5d6..a2b2f8f 100644
--- a/src/org.gnome.Maps.src.gresource.xml
+++ b/src/org.gnome.Maps.src.gresource.xml
@@ -35,6 +35,7 @@
<file>osmEdit.js</file>
<file>osmEditDialog.js</file>
<file>osmTypeSearchEntry.js</file>
+ <file>osmTypeListRow.js</file>
<file>osmTypeLookup.js</file>
<file>osmTypeSearchPopover.js</file>
<file>osmUtils.js</file>
diff --git a/src/osmEditDialog.js b/src/osmEditDialog.js
index 599e98f..4270274 100644
--- a/src/osmEditDialog.js
+++ b/src/osmEditDialog.js
@@ -23,12 +23,16 @@
const _ = imports.gettext.gettext;
const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Application = imports.application;
+const Maps = imports.gi.GnomeMaps;
const OSMConnection = imports.osmConnection;
+const OSMTypeSearchEntry = imports.osmTypeSearchEntry;
const OSMUtils = imports.osmUtils;
+const Utils = imports.utils;
const Response = {
UPLOADED: 0,
@@ -88,17 +92,41 @@ const OSMEditDialog = new Lang.Class({
'editorGrid',
'commentTextView',
'addFieldPopoverGrid',
- 'addFieldButton'],
+ 'addFieldButton',
+ 'typeSearchGrid',
+ 'typeLabel',
+ 'typeButton',
+ 'typeValueLabel',
+ 'headerBar'],
_init: function(params) {
this._place = params.place;
delete params.place;
+ this._addLocation = params.addLocation;
+ delete params.addLocation;
+
+ this._latitude = params.latitude;
+ delete params.latitude;
+
+ this._longitude = params.longitude;
+ delete params.longitude;
+
/* This is a construct-only property and cannot be set by GtkBuilder */
params.use_header_bar = true;
this.parent(params);
+ /* It seems it's not possible to use a custom widget implemented in GJS
+ from within a widget template */
+ let typeSearch = new OSMTypeSearchEntry.OSMTypeSearchEntry();
+ this._typeSearchGrid.attach(typeSearch, 0, 0, 1, 1);
+ typeSearch.visible = true;
+ typeSearch.can_focus = true;
+
+ let typeSearchPopover = typeSearch.popover;
+ typeSearchPopover.connect('selected', this._onTypeSelected.bind(this));
+
this._cancellable = new Gio.Cancellable();
this._cancellable.connect((function() {
this.response(Response.CANCELLED);
@@ -108,14 +136,40 @@ const OSMEditDialog = new Lang.Class({
this._cancellable.cancel();
}).bind(this));
+ if (this._addLocation) {
+ this._headerBar.title = _("Add Location");
+ this._typeLabel.visible = true;
+ this._typeButton.visible = true;
+ }
+
this._isEditing = false;
this._nextButton.connect('clicked', this._onNextClicked.bind(this));
this._cancelButton.connect('clicked', this._onCancelClicked.bind(this));
this._backButton.connect('clicked', this._onBackClicked.bind(this));
+ this._typeButton.connect('clicked', this._onTypeClicked.bind(this));
+
+ if (this._addLocation) {
+ this._headerBar.title = _("Add Location");
+ this._typeLabel.visible = true;
+ this._typeButton.visible = true;
+ /* the OSMObject ID, version, and changeset ID is unknown for now */
+ let newNode =
+ Maps.OSMNode.new(0, 0, 0, this._longitude, this._latitude);
+ /* set a placeholder name tag to always get a name entry for new
+ locations */
+ newNode.set_tag('name', '');
+ this._loadOSMData(newNode);
+ this._isEditing = true;
+ } else {
+ this._osmType = this._place.osmType;
+ Application.osmEdit.fetchObject(this._place,
+ this._onObjectFetched.bind(this),
+ this._cancellable);
+ }
- Application.osmEdit.fetchObject(this._place,
- this._onObjectFetched.bind(this),
- this._cancellable);
+ /* store original title of the dialog to be able to restore it when
+ coming back from type selection */
+ this._originalTitle = this._headerBar.title;
},
_onNextClicked: function() {
@@ -130,11 +184,41 @@ const OSMEditDialog = new Lang.Class({
// upload data to OSM
let comment = this._commentTextView.buffer.text;
Application.osmEdit.uploadObject(this._osmObject,
- this._place.osmType, comment,
+ this._osmType, comment,
this._onObjectUploaded.bind(this));
}
},
+ _onTypeClicked: function() {
+ this._cancelButton.visible = false;
+ this._backButton.visible = true;
+ this._headerBar.title = _("Select Type");
+ this._stack.visible_child_name = 'select-type';
+ },
+
+ _onTypeSelected: function(popover, key, value, title) {
+ this._typeValueLabel.label = title;
+ this._updateType(key, value);
+ popover.hide();
+
+ /* go back to the editing stack page */
+ this._backButton.visible = false;
+ this._cancelButton.visible = true;
+ this._stack.visible_child_name = 'editor';
+ this._headerBar.title = this._originalTitle;
+ },
+
+ _updateType: function(key, value) {
+ /* clear out any previous type-related OSM tags */
+ this._osmObject.delete_tag('amenity');
+ this._osmObject.delete_tag('shop');
+ this._osmObject.delete_tag('tourism');
+ this._osmObject.delete_tag('place');
+ this._osmObject.delete_tag('leasure');
+
+ this._osmObject.set_tag(key, value);
+ },
+
_switchToUpload: function() {
this._stack.set_visible_child_name('upload');
this._nextButton.label = _("Done");
@@ -155,6 +239,7 @@ const OSMEditDialog = new Lang.Class({
this._stack.set_visible_child_name('editor');
this._isEditing = true;
this._commentTextView.buffer.text = '';
+ this._headerBar.title = this._originalTitle;
},
_onObjectFetched: function(success, status, osmObject, osmType, error) {
@@ -196,7 +281,7 @@ const OSMEditDialog = new Lang.Class({
/* GtkContainer.child_get_property doesn't seem to be usable from GJS */
_getRowOfDeleteButton: function(button) {
- for (let row = 0;; row++) {
+ for (let row = 1;; row++) {
let label = this._editorGrid.get_child_at(0, row);
let deleteButton = this._editorGrid.get_child_at(2, row);
@@ -369,13 +454,12 @@ const OSMEditDialog = new Lang.Class({
}
},
- _loadOSMData: function(osmObject, osmType) {
+ _loadOSMData: function(osmObject) {
this._osmObject = osmObject;
- this._osmType = osmType;
/* keeps track of the current insertion row in the grid for editing
widgets */
- this._currentRow = 0;
+ this._currentRow = 1;
/* create edit widgets */
for (let i = 0; i < OSM_FIELDS.length; i++) {
diff --git a/src/osmTypeListRow.js b/src/osmTypeListRow.js
new file mode 100644
index 0000000..00c7577
--- /dev/null
+++ b/src/osmTypeListRow.js
@@ -0,0 +1,52 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * Copyright (c) 2015 Marcus Lundblad.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author: Marcus Lundblad <ml update uu se>
+ */
+
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+
+const OSMTypeListRow = new Lang.Class({
+ Name: 'OSMTypeListRow',
+ Extends: Gtk.ListBoxRow,
+ Template: 'resource:///org/gnome/Maps/ui/osm-type-list-row.ui',
+ InternalChildren: [ 'name' ],
+
+ _init: function(props) {
+ this._type = props.type;
+ delete props.type;
+
+ this.parent(props);
+
+ this._name.label = this._type.title;
+ },
+
+ get key() {
+ return this._type.key;
+ },
+
+ get value() {
+ return this._type.value;
+ },
+
+ get title() {
+ return this._type.title;
+ }
+});
+
diff --git a/src/osmTypeSearchEntry.js b/src/osmTypeSearchEntry.js
new file mode 100644
index 0000000..41e52df
--- /dev/null
+++ b/src/osmTypeSearchEntry.js
@@ -0,0 +1,74 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * Copyright (c) 2015 Marcus Lundblad.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author: Marcus Lundblad <ml update uu se>
+ */
+
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+
+const OSMTypeSearchPopover = imports.osmTypeSearchPopover;
+const OSMTypeLookup = imports.osmTypeLookup;
+const Utils = imports.utils;
+
+const MAX_MATCHES = 10;
+
+const OSMTypeSearchEntry = new Lang.Class({
+ Name: 'OSMTypeSearchEntry',
+ Extends: Gtk.SearchEntry,
+ Template: 'resource:///org/gnome/Maps/ui/osm-type-search-entry.ui',
+
+ _init: function(props) {
+ this.parent(props);
+
+ this._popover =
+ new OSMTypeSearchPopover.OSMTypeSearchPopover({relative_to: this});
+
+ this.connect('size-allocate', (function(widget, allocation) {
+ // Magic number to make the alignment pixel perfect.
+ let width_request = allocation.width + 20;
+ this._popover.width_request = width_request;
+ }).bind(this));
+
+ this.connect('search-changed', this._onSearchChanged.bind(this));
+ this.connect('activate', this._onSearchChanged.bind(this));
+ },
+
+ get popover() {
+ return this._popover;
+ },
+
+ _onSearchChanged: function() {
+ if (this.text.length === 0) {
+ this._popover.hide();
+ return;
+ }
+
+ /* Note: Not sure if searching already on one character might be a bit
+ too much, but unsure about languages such as Chinese and Japanese
+ using ideographs. */
+ if (this.text.length >= 1) {
+ let matches = OSMTypeLookup.findMatches(this.text, MAX_MATCHES);
+
+ if (matches.length > 0) {
+ /* show search results */
+ this._popover.showMatches(matches);
+ }
+ }
+ }
+});
diff --git a/src/osmTypeSearchPopover.js b/src/osmTypeSearchPopover.js
new file mode 100644
index 0000000..9416022
--- /dev/null
+++ b/src/osmTypeSearchPopover.js
@@ -0,0 +1,68 @@
+/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
+/* vim: set et ts=4 sw=4: */
+/*
+ * Copyright (c) 2015 Marcus Lundblad.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Author: Marcus Lundblad <ml update uu se>
+ */
+
+const GObject = imports.gi.GObject;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+
+const OSMTypeListRow = imports.osmTypeListRow;
+const PropagatingSearchPopover = imports.propagatingSearchPopover;
+
+const OSMTypeSearchPopover = new Lang.Class({
+ Name: 'OSMTypeSearchPopover',
+ Extends: PropagatingSearchPopover.PropagatingSearchPopover,
+ Template: 'resource:///org/gnome/Maps/ui/osm-type-search-popover.ui',
+ Signals : {
+ /* signal emitted when selecting a type, indicates OSM key and value
+ and display title */
+ 'selected' : { param_types: [ GObject.TYPE_STRING,
+ GObject.TYPE_STRING,
+ GObject.TYPE_STRING ] }
+ },
+ InternalChildren: ['list'],
+
+ _init: function(props) {
+ this.parent(props);
+
+ this._list.connect('row-activated', (function(list, row) {
+ if (row)
+ this.emit('selected', row.key, row.value, row.title);
+ }).bind(this));
+ },
+
+ showMatches: function(matches) {
+ this._list.forall(function(row) {
+ row.destroy();
+ });
+
+ matches.forEach((function(type) {
+ this._addRow(type);
+ }).bind(this));
+ this.show();
+ },
+
+ _addRow: function(type) {
+ let row = new OSMTypeListRow.OSMTypeListRow({ type: type,
+ can_focus: true });
+ this._list.add(row);
+ }
+ });
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]