[gnome-maps/wip/jonasdn/osm-edit-address: 6/6] osmEditDialog: Add ability to add and edit addresses



commit cbdadc381126179b2dc2a888891cdf0092d2a28b
Author: Jonas Danielsson <jonas threetimestwo org>
Date:   Mon Feb 22 19:49:30 2016 +0100

    osmEditDialog: Add ability to add and edit addresses
    
    Supports editing street, house number, postal code, and city.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=762591

 data/org.gnome.Maps.data.gresource.xml |    1 +
 data/ui/osm-edit-address.ui            |   59 ++++++++++++
 po/POTFILES.in                         |    1 +
 src/osmConnection.js                   |    1 +
 src/osmEditDialog.js                   |  152 ++++++++++++++++++++++++++++----
 5 files changed, 196 insertions(+), 18 deletions(-)
---
diff --git a/data/org.gnome.Maps.data.gresource.xml b/data/org.gnome.Maps.data.gresource.xml
index 70a43d9..2c9c82d 100644
--- a/data/org.gnome.Maps.data.gresource.xml
+++ b/data/org.gnome.Maps.data.gresource.xml
@@ -17,6 +17,7 @@
     <file preprocess="xml-stripblanks">ui/map-bubble.ui</file>
     <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-address.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>
diff --git a/data/ui/osm-edit-address.ui b/data/ui/osm-edit-address.ui
new file mode 100644
index 0000000..1a36f87
--- /dev/null
+++ b/data/ui/osm-edit-address.ui
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.12"/>
+  <template class="Gjs_OSMEditAddress" parent="GtkGrid">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <style>
+      <class name="linked"/>
+    </style>
+    <child>
+      <object class="GtkEntry" id="street">
+        <property name="visible">True</property>
+        <property name="hexpand">True</property>
+        <property name="placeholder_text" translatable="yes">Street</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="number">
+        <property name="visible">True</property>
+        <property name="hexpand">False</property>
+        <property name="placeholder_text" translatable="yes">House number</property>
+        <property name="width_chars">3</property>
+      </object>
+      <packing>
+        <property name="left_attach">2</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="post">
+        <property name="visible">True</property>
+        <property name="hexpand">False</property>
+        <property name="placeholder_text" translatable="yes">Postal code</property>
+        <property name="width_chars">5</property>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="city">
+        <property name="visible">True</property>
+        <property name="hexpand">True</property>
+        <property name="placeholder_text" translatable="yes" comments="This is the place name as it would be 
written in a postal address (typically coming after the postal code)">City</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">1</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index df436e1..cc0b8ca 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,6 +12,7 @@ data/org.gnome.Maps.gschema.xml
 [type: gettext/glade]data/ui/main-window.ui
 [type: gettext/glade]data/ui/map-bubble.ui
 [type: gettext/glade]data/ui/osm-account-dialog.ui
+[type: gettext/glade]data/ui/osm-edit-address.ui
 [type: gettext/glade]data/ui/osm-edit-dialog.ui
 [type: gettext/glade]data/ui/place-bubble.ui
 [type: gettext/glade]data/ui/place-popover.ui
diff --git a/src/osmConnection.js b/src/osmConnection.js
index cbddeea..39d4e17 100644
--- a/src/osmConnection.js
+++ b/src/osmConnection.js
@@ -78,6 +78,7 @@ const OSMConnection = new Lang.Class({
                                              message.response_body.length);
                 callback(true, message.status_code, object, type, null);
             } catch (e) {
+                Utils.debug(e);
                 callback(false, message.status_code, null, type, e);
             }
         }).bind(this));
diff --git a/src/osmEditDialog.js b/src/osmEditDialog.js
index 31cf210..7195101 100644
--- a/src/osmEditDialog.js
+++ b/src/osmEditDialog.js
@@ -50,7 +50,8 @@ const Response = {
 const EditFieldType = {
     TEXT: 0,
     INTEGER: 1,
-    COMBO: 2
+    COMBO: 2,
+    ADDRESS: 3
 };
 
 const _WIKI_BASE = 'http://wiki.openstreetmap.org/wiki/Key:';
@@ -94,6 +95,8 @@ let _osmPhoneRewriteFunc = function(text) {
  * options: The options for the combo box (only used for COMBO fields)
  * hint: a hint text to show in a popover displayed by a hint button
  * (for TEXT and INTEGER fields)
+ * subtags: Used by a complex composite OSM tag.
+ * rows: Number of rows neded if != 1.
  */
 const OSM_FIELDS = [
     {
@@ -103,6 +106,14 @@ const OSM_FIELDS = [
         hint: _("The official name. This is typically what appears on signs.")
     },
     {
+        name: _("Address"),
+        tag: 'addr',
+        subtags: ['addr:street', 'addr:housenumber',
+                  'addr:postcode', 'addr:city'],
+        type: EditFieldType.ADDRESS,
+        rows: 2
+    },
+    {
         name: _("Website"),
         tag: 'website',
         type: EditFieldType.TEXT,
@@ -167,6 +178,44 @@ const OSM_FIELDS = [
                   ['service', _("Service")]]
     }];
 
+const OSMEditAddress = new Lang.Class({
+    Name: 'OSMEditAddress',
+    Extends: Gtk.Grid,
+    Template: 'resource:///org/gnome/Maps/ui/osm-edit-address.ui',
+    Children: [ 'street',
+                'number',
+                'post',
+                'city' ],
+
+    _init: function(params) {
+        let street = params.street;
+        delete params.street;
+
+        let number = params.number;
+        delete params.number;
+
+        let postCode = params.postCode;
+        delete params.postCode;
+
+        let city = params.city;
+        delete params.city;
+
+        this.parent(params);
+
+        if (street)
+            this.street.text = street;
+
+        if (number)
+            this.number.text = number;
+
+        if (postCode)
+            this.post.text = postCode;
+
+        if (city)
+            this.city.text = city;
+    }
+});
+
 
 const OSMEditDialog = new Lang.Class({
     Name: 'OSMEditDialog',
@@ -465,38 +514,49 @@ const OSMEditDialog = new Lang.Class({
 
     /* GtkContainer.child_get_property doesn't seem to be usable from GJS */
     _getRowOfDeleteButton: function(button) {
-        for (let row = 1;; row++) {
+        for (let row = 1; row < this._currentRow; row++) {
             let label = this._editorGrid.get_child_at(0, row);
             let deleteButton = this._editorGrid.get_child_at(2, row);
 
             if (deleteButton === button)
                 return row;
-
-            /* if we reached the end of the table */
-            if (label == null)
-                return -1;
         }
 
         return -1;
     },
 
-    _addOSMEditDeleteButton: function(tag) {
+    _addOSMEditDeleteButton: function(fieldSpec) {
         let deleteButton = Gtk.Button.new_from_icon_name('user-trash-symbolic',
                                                          Gtk.IconSize.BUTTON);
         let styleContext = deleteButton.get_style_context();
+        let rows = fieldSpec.rows || 1;
 
         styleContext.add_class('flat');
         this._editorGrid.attach(deleteButton, 2, this._currentRow, 1, 1);
 
         deleteButton.connect('clicked', (function() {
-            this._osmObject.delete_tag(tag);
+            if (fieldSpec.subtstags) {
+                fieldSpec.subtags.forEach((function(key) {
+                    this._osmObject.delete_tag(key);
+                }).bind(this));
+            } else {
+                this._osmObject.delete_tag(fieldSpec.tag);
+            }
 
             let row = this._getRowOfDeleteButton(deleteButton);
             this._editorGrid.remove_row(row);
+            if (rows  === 2) {
+                /* 
+                 * if we should delete the following row (for a widget spanning
+                 * two rows) delete next row (which now has moved up one row)
+                 */
+                this._editorGrid.remove_row(row);
+                this._currentRow--;
+            }
             this._nextButton.sensitive = true;
             this._currentRow--;
             this._updateAddFieldMenu();
-        }).bind(this, tag));
+        }).bind(this));
 
         deleteButton.show();
     },
@@ -551,7 +611,7 @@ const OSMEditDialog = new Lang.Class({
         entry.show();
 
         /* TODO: should we allow deleting the name field? */
-        this._addOSMEditDeleteButton(fieldSpec.tag);
+        this._addOSMEditDeleteButton(fieldSpec);
 
         this._currentRow++;
     },
@@ -578,7 +638,7 @@ const OSMEditDialog = new Lang.Class({
         this._editorGrid.attach(spinbutton, 1, this._currentRow, 1, 1);
         spinbutton.show();
 
-        this._addOSMEditDeleteButton(fieldSpec.tag);
+        this._addOSMEditDeleteButton(fieldSpec);
         this._currentRow++;
     },
 
@@ -600,10 +660,32 @@ const OSMEditDialog = new Lang.Class({
         this._editorGrid.attach(combobox, 1, this._currentRow, 1, 1);
         combobox.show();
 
-        this._addOSMEditDeleteButton(fieldSpec.tag);
+        this._addOSMEditDeleteButton(fieldSpec);
         this._currentRow++;
     },
 
+    _addOSMEditAddressEntry: function(fieldSpec, value) {
+        this._addOSMEditLabel(fieldSpec);
+
+        let addr = new OSMEditAddress({ street: value[0],
+                                        number: value[1],
+                                        postCode: value[2],
+                                        city: value[3] });
+        let changedFunc = (function(entry, index) {
+            this._osmObject.set_tag(fieldSpec.subtags[index], entry.text);
+            this._nextButton.sensitive = true;
+        }).bind(this);
+
+        addr.street.connect('changed', changedFunc.bind(this, addr.street, 0));
+        addr.number.connect('changed', changedFunc.bind(this, addr.number, 1));
+        addr.post.connect('changed', changedFunc.bind(this, addr.post, 2));
+        addr.city.connect('changed', changedFunc.bind(this, addr.city, 3));
+
+        this._editorGrid.attach(addr, 1, this._currentRow, 1, 2);
+        this._addOSMEditDeleteButton(fieldSpec);
+        this._currentRow += 2;
+    },
+
     /* update visible items in the "Add Field" popover */
     _updateAddFieldMenu: function() {
         /* clear old items */
@@ -618,9 +700,18 @@ const OSMEditDialog = new Lang.Class({
         /* add selectable items */
         for (let i = 0; i < OSM_FIELDS.length; i++) {
             let fieldSpec = OSM_FIELDS[i];
-            let value = this._osmObject.get_tag(fieldSpec.tag);
+            let hasValue = false;
+
+            if (fieldSpec.subtags) {
+                fieldSpec.subtags.forEach((function(tag) {
+                    if (this._osmObject.get_tag(tag))
+                        hasValue = true;
+                }).bind(this));
+            } else {
+                hasValue = this._osmObject.get_tag(fieldSpec.tag) !== null;
+            }
 
-            if (value === null) {
+            if (!hasValue) {
                 let button = new Gtk.Button({
                     visible: true, sensitive: true,
                     label: fieldSpec.name
@@ -636,7 +727,13 @@ const OSMEditDialog = new Lang.Class({
                     /* add a "placeholder" empty OSM tag to keep the add field
                      * menu updated, these tags will be filtered out if nothing
                      * is entered */
-                    this._osmObject.set_tag(fieldSpec.tag, '');
+                    if (fieldSpec.subtags) {
+                        fieldSpec.subtags.forEach((function(tag) {
+                            this._osmObject.set_tag(tag, '');
+                        }).bind(this));
+                    } else {
+                        this._osmObject.set_tag(fieldSpec.tag, '');
+                    }
                     this._updateAddFieldMenu();
                 }).bind(this));
 
@@ -659,6 +756,9 @@ const OSMEditDialog = new Lang.Class({
         case EditFieldType.COMBO:
             this._addOSMEditComboEntry(fieldSpec, value);
             break;
+        case EditFieldType.ADDRESS:
+            this._addOSMEditAddressEntry(fieldSpec, value);
+            break;
         }
     },
 
@@ -671,10 +771,26 @@ const OSMEditDialog = new Lang.Class({
 
         for (let i = 0; i < OSM_FIELDS.length; i++) {
             let fieldSpec = OSM_FIELDS[i];
-            let value = osmObject.get_tag(fieldSpec.tag);
+            let value;
+
+            if (fieldSpec.subtags) {
+                let hasAny = false;
+                fieldSpec.subtags.forEach(function(tag) {
+                    if (osmObject.get_tag(tag) != null)
+                        hasAny = true;
+                });
 
-            if (value != null)
-                this._addOSMField(fieldSpec, value);
+                if (hasAny) {
+                    value = fieldSpec.subtags.map(function(tag) {
+                        return osmObject.get_tag(tag);
+                    });
+                    this._addOSMField(fieldSpec, value);
+                }
+            } else {
+                value = osmObject.get_tag(fieldSpec.tag);
+                if (value != null)
+                    this._addOSMField(fieldSpec, value);
+            }
         }
 
         this._updateAddFieldMenu();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]