[gnome-maps] Add search popup and use it to show search results



commit 3cd8ce0e317c2d8c5012b94d380263853286ac39
Author: Jonas Danielsson <jonas threetimestwo org>
Date:   Tue Aug 20 11:18:47 2013 +0200

    Add search popup and use it to show search results
    
    https://bugzilla.gnome.org/show_bug.cgi?id=706300

 data/gnome-maps.css          |    7 +++
 src/Makefile-js.am           |    3 +-
 src/gnome-maps.gresource.xml |    1 +
 src/main-window.ui           |    3 +-
 src/mainWindow.js            |   67 ++++++++++++++---------------
 src/mapView.js               |    1 +
 src/search-popup.ui          |   22 ++++++++++
 src/searchPopup.js           |   95 ++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 162 insertions(+), 37 deletions(-)
---
diff --git a/data/gnome-maps.css b/data/gnome-maps.css
index c68f822..187f442 100644
--- a/data/gnome-maps.css
+++ b/data/gnome-maps.css
@@ -6,6 +6,13 @@
     border-width: 0 1px 0 0;
 }
 
+.search-popup {
+       border-style: solid;
+       border-width: 5px;
+       border-color: black;
+       border-radius: 6px 6px 6px 6px;
+}
+
 .zoom-control {
     background-color: transparent;
 }
diff --git a/src/Makefile-js.am b/src/Makefile-js.am
index 53296db..90365a3 100644
--- a/src/Makefile-js.am
+++ b/src/Makefile-js.am
@@ -10,7 +10,8 @@ dist_js_DATA = \
     utils.js \
     userLocation.js \
     geoclue.js \
-    zoomControl.js
+    zoomControl.js \
+    searchPopup.js
 
 BUILT_SOURCES += \
     path.js \
diff --git a/src/gnome-maps.gresource.xml b/src/gnome-maps.gresource.xml
index ded3871..0265ec2 100644
--- a/src/gnome-maps.gresource.xml
+++ b/src/gnome-maps.gresource.xml
@@ -4,6 +4,7 @@
     <file preprocess="xml-stripblanks">app-menu.ui</file>
     <file preprocess="xml-stripblanks">main-window.ui</file>
     <file preprocess="xml-stripblanks">zoom-control.ui</file>
+    <file preprocess="xml-stripblanks">search-popup.ui</file>
     <file alias="application.css">../data/gnome-maps.css</file>
     <file alias="zoom-in.png">../data/media/zoom-in.png</file>
     <file alias="zoom-out.png">../data/media/zoom-out.png</file>
diff --git a/src/main-window.ui b/src/main-window.ui
index 3216a93..b7d833b 100644
--- a/src/main-window.ui
+++ b/src/main-window.ui
@@ -29,10 +29,9 @@
           <class name="titlebar"/>
         </style>
         <child type="title">
-          <object class="GtkComboBox" id="search-box">
+          <object class="GtkSearchEntry" id="search-entry">
             <property name="visible">True</property>
             <property name="width_request">500</property>
-            <property name="has_entry">True</property>
           </object>
         </child>
         <child>
diff --git a/src/mainWindow.js b/src/mainWindow.js
index 44376b2..1cd92f9 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -32,6 +32,7 @@ const Mainloop = imports.mainloop;
 
 const Application = imports.application;
 const MapView = imports.mapView;
+const SearchPopup = imports.searchPopup;
 const Utils = imports.utils;
 const Config = imports.config;
 
@@ -53,11 +54,11 @@ const MainWindow = new Lang.Class({
         this._configureId = 0;
         let ui = Utils.getUIObject('main-window', [ 'app-window',
                                                     'window-content',
-                                                    'search-box',
+                                                    'search-entry',
                                                     'track-user-button']);
         let grid = ui.windowContent,
             toggle = ui.trackUserButton;
-        this._searchBox = ui.searchBox;
+        this._searchEntry = ui.searchEntry;
         this.window = ui.appWindow;
         this.window.application = app;
 
@@ -70,23 +71,26 @@ const MainWindow = new Lang.Class({
         this._initSignals();
         this._restoreWindowGeometry();
 
-        grid.add(this.mapView);
+        this._mapOverlay = new Gtk.Overlay({ visible: true });
+        this._mapOverlay.add(this.mapView);
+        this._mapOverlay.add_overlay(this._searchPopup);
+
+        grid.add(this._mapOverlay);
 
         grid.show_all();
     },
 
     _initSearchWidgets: function() {
-        this._searchEntry = new Gtk.SearchEntry();
-        this._searchBox.add(this._searchEntry);
+        this._searchPopup = new SearchPopup.SearchPopup(this.window);
 
         let model = new Gtk.ListStore();
         model.set_column_types([GObject.TYPE_STRING,
                                 GObject.TYPE_OBJECT]);
-        this._searchBox.model = model;
-        this._searchBox.entry_text_column = SearchResults.COL_DESCRIPTION;
-        this._searchBox.connect('changed',
-                                this._onSearchBoxChanged.bind(this));
-        this._searchBox.show_all();
+        this._searchPopup.setModel(model);
+        this._searchPopup.connect('selected',
+                                  this._onSearchPopupSelected.bind(this));
+        this.mapView.view.connect('button-press-event',
+                             this._searchPopup.hide.bind(this._searchPopup));
     },
 
     _initActions: function() {
@@ -210,19 +214,12 @@ const MainWindow = new Lang.Class({
         return false;
     },
 
-    _onSearchBoxChanged: function() {
-        let ret = this._searchBox.get_active_iter();
-        let is_set = ret[0];
-        let iter = ret[1];
-
-        if (is_set) {
-            let location =
-                this._searchBox.model.get_value(iter,
-                                                SearchResults.COL_LOCATION);
-            this.mapView.showLocation(location);
-        } else {
-            this._searchBox.model.clear();
-        }
+    _onSearchPopupSelected: function(widget, iter) {
+        let model = this._searchPopup.getModel();
+        let location = model.get_value(iter, SearchResults.COL_LOCATION);
+
+        this.mapView.showLocation(location);
+        this._searchPopup.hide();
     },
 
     _onSearchActivate: function() {
@@ -235,23 +232,25 @@ const MainWindow = new Lang.Class({
     },
 
     _showSearchResults: function(places) {
-        this._searchBox.model.clear();
+        let model = this._searchPopup.getModel();
 
-        places.forEach((function(place) {
-            let iter = this._searchBox.model.append();
+        model.clear();
+        places.forEach(function(place) {
+            let iter = model.append();
             let location = place.get_location();
 
             if (location == null)
                 return;
 
-            this._searchBox.model.set(iter,
-                                      [SearchResults.COL_DESCRIPTION,
-                                       SearchResults.COL_LOCATION],
-                                      [location.description,
-                                       location]);
-        }).bind(this));
-
-        this._searchBox.popup();
+            let description_markup = '<b>' + location.description + '</b>';
+            model.set(iter,
+                      [SearchResults.COL_DESCRIPTION,
+                       SearchResults.COL_LOCATION],
+                      [description_markup,
+                       location]);
+        });
+        this._searchPopup.setModel(model);
+        this._searchPopup.show();
     },
 
     _quit: function() {
diff --git a/src/mapView.js b/src/mapView.js
index 2137eaf..cd59c14 100644
--- a/src/mapView.js
+++ b/src/mapView.js
@@ -59,6 +59,7 @@ const MapView = new Lang.Class({
         this.actor = this.get_view();
         this.view = this.actor;
         this.view.set_zoom_level(3);
+        this.view.set_reactive(true);
 
         this.view.connect('notify::latitude', this._onViewMoved.bind(this));
         this.view.connect('notify::longitude', this._onViewMoved.bind(this));
diff --git a/src/search-popup.ui b/src/search-popup.ui
new file mode 100644
index 0000000..780ffc5
--- /dev/null
+++ b/src/search-popup.ui
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.10 -->
+  <object class="GtkFrame" id="frame">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <style>
+      <class name="search-popup" />
+    </style>
+    <child>
+      <object class="GtkTreeView" id="treeview">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="expand">True</property>
+        <property name="headers-visible">False</property>
+        <child internal-child="selection">
+          <object class="GtkTreeSelection" id="treeview-selection"/>
+        </child>
+          </object>
+    </child>
+  </object>
+</interface>
diff --git a/src/searchPopup.js b/src/searchPopup.js
new file mode 100644
index 0000000..d8731fb
--- /dev/null
+++ b/src/searchPopup.js
@@ -0,0 +1,95 @@
+/* -*- 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 Gtk = imports.gi.Gtk;
+
+const Lang = imports.lang;
+const Utils = imports.utils;
+
+const Columns = {
+    TEXT: 0
+};
+
+const SearchPopup = new Lang.Class({
+    Name: 'SearchPopup',
+    Extends: Gtk.Bin,
+
+    _init: function (window) {
+        this.parent({ width_request: 500,
+                      halign: Gtk.Align.CENTER,
+                      valign: Gtk.Align.START,
+                      margin_top: 10,
+                      no_show_all: true,
+                      visible: true });
+
+        let ui = Utils.getUIObject('search-popup', ['frame',
+                                                    'treeview',
+                                                    'treeview-selection']);
+        this._treeView = ui.treeview;
+        this._treeViewSelection = ui.treeviewSelection;
+        this._treeView.connect('button-press-event',
+                               this._onListButtonPress.bind(this));
+        this._initList();
+
+        this.add(ui.frame);
+        this.hide();
+    },
+
+    _initList: function() {
+        let cell = new Gtk.CellRendererText({ xpad: 16,
+                                              ypad: 8 });
+        let column = new Gtk.TreeViewColumn();
+
+        this._treeView.append_column(column);
+        column.pack_start(cell, true);
+        column.add_attribute(cell, 'markup', Columns.TEXT);
+    },
+
+    _onListButtonPress: function(widget, event) {
+        let path_valid, path;
+        let bool, coordX, coordY;
+
+        [bool, coordX, coordY] = event.get_coords();
+        [path_valid, path] = this._treeView.get_path_at_pos(coordX, coordY,
+                                                            null, null, null);
+        if (path_valid) {
+            let model = this.getModel();
+            let iter_valid, iter;
+
+            if (model === null)
+                return;
+
+            [iter_valid, iter] = model.get_iter(path);
+            if (!iter_valid)
+                return;
+
+            this.emit('selected', iter);
+        }
+    },
+
+    setModel: function(model) {
+        this._treeView.set_model(model);
+    },
+
+    getModel: function() {
+        return this._treeView.get_model();
+    },
+});
+Utils.addSignalMethods(SearchPopup.prototype);


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