[gnome-maps/wip/mlundblad/osm-add-location: 5/5] osmEdit: WIP: Add support for creating new locations in the edit dialog



commit 0661a501d77310a655c562ddf93ebeaed11cbabe
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/ui/osm-edit-dialog.ui  |  104 +++++++++++++++++++++++++++++++++++++++++++
 src/osmEditDialog.js        |   75 +++++++++++++++++++++++++++----
 src/osmTypeSearchEntry.js   |   66 +++++++++++++++++++++++++++
 src/osmTypeSearchPopover.js |   33 ++++++++++++++
 4 files changed, 269 insertions(+), 9 deletions(-)
---
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/src/osmEditDialog.js b/src/osmEditDialog.js
index 599e98f..2e6d2db 100644
--- a/src/osmEditDialog.js
+++ b/src/osmEditDialog.js
@@ -23,11 +23,14 @@
 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 Response = {
@@ -88,17 +91,38 @@ 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;
+
         this._cancellable = new Gio.Cancellable();
         this._cancellable.connect((function() {
             this.response(Response.CANCELLED);
@@ -108,14 +132,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._latitude, this._longitude);
+            /* 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 +180,18 @@ 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';
+    },
+
     _switchToUpload: function() {
         this._stack.set_visible_child_name('upload');
         this._nextButton.label = _("Done");
@@ -155,6 +212,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 +254,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 +427,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/osmTypeSearchEntry.js b/src/osmTypeSearchEntry.js
new file mode 100644
index 0000000..8720e25
--- /dev/null
+++ b/src/osmTypeSearchEntry.js
@@ -0,0 +1,66 @@
+/* -*- 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,
+
+    _init: function(props) {
+        this.parent(props);
+
+        /* couldn't get this widget working from a .ui template */
+        this.hexpand = true;
+        this.margin_bottom = 10;
+        this.margin_start = 10;
+        this.margin_end = 10;
+
+        this._popover =
+            new OSMTypeSearchPopover.OSMTypeSearchPopover({relative_to: this});
+
+        this.connect('search-changed', this._onSearchChanged.bind(this));
+    },
+
+    get popover() {
+        return this._popover;
+    },
+
+    _onSearchChanged: function() {
+        if (this.text.length === 0) {
+            this._popover.hide();
+            return;
+        }
+
+        if (this.text.length >= 3) {
+            let matches = OSMTypeLookup.findMatches(this.text, MAX_MATCHES);
+
+            Utils.debug('Matches: ' + matches);
+        }
+    }
+});
diff --git a/src/osmTypeSearchPopover.js b/src/osmTypeSearchPopover.js
new file mode 100644
index 0000000..da99335
--- /dev/null
+++ b/src/osmTypeSearchPopover.js
@@ -0,0 +1,33 @@
+/* -*- 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 = new Lang.Class({
+    Name: 'OSMTypeSearchPopover',
+    Extends: Gtk.Popover,
+
+    _init: function(props) {
+        this.parent(props);
+    }
+ });
+ 


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