? tests
? includes/geo_geometry.inc
? includes/handlers/funcs
? includes/handlers/geo_geometry.inc.save
? includes/handlers/geo_simple.inc.save
Index: geo.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/geo.inc,v
retrieving revision 1.17
diff -r1.17 geo.inc
73,151d72
< function geo_query_operators($geo_type) {
<   return array(
<     'Equals' => t('Equals'),
<     'NOT Equals' => t('Does not equal'),
<     'Intersects' => t('Intersects'),
<     'NOT Intersects' => t('Does not intersect'),
<     'Within' => t('Within'),
<     'NOT Within' => t('Not within'),
<   );
< }
< 
< function geo_query_functions($geo_type) {
<   $geo_type = strtolower($geo_type);
<   $functions = array( 'wkt' => 'wkt', 'wkb' => 'wkb' );
< 
<   if ($geo_type == 'point') {
<     $functions['lat'] = 'lat';
<     $functions['lon'] = 'lon';
<   }
< 
<   if ($geo_type == 'polygon' || $geo_type == 'linestring') {
<     $functions['area'] = 'area';
<     $functions['bbox'] = 'bbox';
<     $functions['perimeter'] = 'perimeter';
<   }
< 
<   if ($geo_type == 'linestring') {
<     $functions['start'] = 'start';
<     $functions['end'] = 'end';
<   }
< 
<   // TODO distance? given that we have a starting point?
< 
<   return $functions;
< }
< 
< function geo_query_handlers($geo_type) {
<   // TODO are these all supported by default?  (and through which functions?)
<   return array(
<     'wkt' => t('Well Known Text'),
<     'wkb' => t('Well Known Binary'),
<     'svg' => t('SVG'),
<     'kml' => t('KML'),
<     'gml' => t('GML'),
<   );
< }
< 
< function geo_query_area($field, $srid = null) {
<   return 'Area('. $field .')';
< }
< 
< function geo_query_bbox($field, $srid = null) {
<   return 'Envelope('. $field .')';
< }
< 
< function geo_query_centroid($field, $srid = null) {
<   return 'Centroid('. $field .')';
< }
< 
< function geo_query_geo_type($field, $srid = null) {
<   return 'GeometryType('. $field .')';
< }
< 
< function geo_query_end($field, $srid = null) {
<   return 'EndPoint('. $field .')';
< }
< 
< function geo_query_lat($field, $srid = null) {
<   return 'Y('. $field .')';
< }
< 
< function geo_query_lon($field, $srid = null) {
<   return 'X('. $field .')';
< }
< 
< function geo_query_length($field, $srid = null) {
<   return 'Length('. $field .')';
< }
< 
156,167d76
< function geo_query_start($field, $srid = null) {
<   return 'StartPoint('. $field .')';
< }
< 
< function geo_query_wkt($field, $srid = null) {
<   return 'asText('. $field .')';
< }
< 
< function geo_query_wkb($field, $srid = null) {
<   return 'asBinary('. $field .')';
< }
< 
174,185d82
< function geo_query_within($field, $srid = null, $target) {
<   return "Within($field, GeomFromText('". $target['wkt'] ."', $srid))";
< }
< 
< function geo_query_contains($field, $srid = null, $target) {
<   return "Contains(GeomFromText('". $target['wkt'] ."', $srid), $field)";
< }
< 
< function geo_query_extent($field) {
<   return "ST_Extent($field)";
< }
< 
248,263d144
< function geo_gis_input_selector($default_value) {
<   // Provide a selection of input handlers.
<   $input_types = array();
<   foreach (module_invoke_all('gis_input_info') as $name => $info) {
<     $input_types[$name] = $info['label'];
<   }
< 
<   $form = array(
<     '#type' => 'select',
<     '#title' => 'Widget',
<     '#options' => $input_types,
<     '#default_value' => $default_value,
<   );
<   return $form;
< }
< 
Index: geo.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/geo.module,v
retrieving revision 1.36
diff -r1.36 geo.module
193c193
<    
---
> 
Index: db/mysql_spatial.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/db/mysql_spatial.inc,v
retrieving revision 1.14
diff -r1.14 mysql_spatial.inc
16,67d15
< /**
<  * Calculate the distance using the Pythagorean theorem.  It's cheaper than
<  * the spherical versions, but less accurate.
<  * TODO only works for points - the X() and Y() functions should be supplanted
<  *      by something that's cognizant of other geometries.
<  */
< function geo_mysql_spatial_query_distance($field, $srid, $point) {
<   // Point data.
<   $x = $point['lon'];
<   $y = $point['lat'];
< 
<   // Offsets, in meters.
<   $mod_x = GEO_DEGREE_M * cos($y / 57.2958);
<   $mod_y = GEO_DEGREE_M;
< 
<   return "SQRT(POW(($mod_x * (X($field) - $x)), 2) + POW(($mod_y * (Y($field) - $y)), 2))";
< }
< 
< /**
<  * Calculate the distance using the Great Circle Distance Formula.
<  * TODO only works for points - the X() and Y() functions should be supplanted
<  *      by something that's cognizant of other geometries.
<  */
< function geo_mysql_spatial_query_distance_sphere($field, $srid, $point) {
<   // Radius of the earth in meters.
<   $r = 6370986;
< 
<   // Degree offset.
<   $d = 57.2958;
< 
<   // Point data.
<   $x = $point['lon'];
<   $y = $point['lat'];
< 
<   // Offsets, in meters.
<   $ysin = sin($y / $d);
<   $ycos = cos($y / $d);
<   $xd   = $x/$d;
< 
<   return "($r * ACOS($ysin * SIN(Y($field)/$d) + $ycos * COS(Y($field)/$d) * COS(X($field)/$d - $xd)))";
< }
< 
< /**
<  * Aggregate function that returns the total boundary of a result set.
<  */
< function mysql_spatial_geo_query_extent($field) {
<   return "MIN(X(PointN(ExteriorRing(envelope($field)), 1))) AS minx,
<     MAX(X(PointN(ExteriorRing(envelope($field)), 3))) AS maxx,
<     MIN(Y(PointN(ExteriorRing(Envelope($field)), 1))) AS miny,
<     MAX(Y(PointN(ExteriorRing(Envelope($field)), 3))) AS maxy";
< }
< 
Index: includes/geo.api.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/geo.api.inc,v
retrieving revision 1.2
diff -r1.2 geo.api.inc
356,361c356,372
< function geo_value_convert($value, $in = 'array', $out = 'wkt') {
<   // TODO We are taking the element's requested input and output formats, and
<   // making the necessary adjustments.  This needs to be refactored and set up
<   // in some kind of a handler model.  For now it's a proof-of-concept that
<   // gets the UI & existing inputs up and running.
<   switch ($in) {
---
> // TODO We are taking the element's requested input and output formats, and
> // making the necessary adjustments.  This needs to be refactored and set up
> // in some kind of a handler model.  For now it's a proof-of-concept that
> // gets the UI & existing inputs up and running.
> function geo_value($input, $output_format, $input_format = 'wkb') {
> 
>   // Nothing to do here.
>   if ($output_format == $input_format) return $input;
> 
>   switch ($input_format) {
>     case 'wkb':
>       $value = geo_wkb_get_data($input, $output_format);
>       return $value['value'];
> 
>     case 'wkt':
>       break;
> 
363,364c374,375
<       if ($out == 'wkt') {
<         $value = geo('wkt_from_point', $value['lat'], $value['lon']);
---
>       if ($output_format == 'wkt') {
>         return geo('wkt_from_point', $input['lat'], $input['lon']);
367a379,421
> }
> 
> /**
>  * Determine which gis input formats are supported by a theme function.
>  */
> function geo_theme_input($theme) {
>   static $registry;
>   if (!isset($registry)) {
>     init_theme();
>     $registry = theme_get_registry();
>   }
>   return $registry[$theme]['gis input'];
> }
> 
> /**
>  * Determine which gis input formats are supported by a formatter.
>  */
> function geo_formatter_input($name, $field_type) {
>   $formatter = _content_get_formatter($name, $field_type);
>   return geo_theme_input($formatter['module'] .'_formatter_'. $name);
> }
> 
> /**
>  * Return a list of possible inputs.
>  */
> function geo_inputs() {
>   static $inputs;
>   if (!isset($inputs)) {
>     $inputs = module_invoke_all('gis_input_info') ;
>     foreach ($inputs as $name => $info) {
>       // Ignore nonexistent element types.
>       if (!$element = _element_info($info['element']['#type'])) continue;
> 
>       // Build out the element from its system defaults and from the hook.
>       $element = array_merge($element, $info['element']);
>       $element['#gis_input'] = $info['gis input'];
>       unset($element['#parents']);
> 
>       $inputs[$name]['element'] = $element;
>     }
>   }
>   return $inputs;
> }
369c423,425
<   return $value;
---
> function geo_input_element_info($name) {
>   $inputs = geo_inputs();
>   return $inputs[$name]['element'];
Index: includes/geo.input.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/geo.input.inc,v
retrieving revision 1.2
diff -r1.2 geo.input.inc
42a43
>       $format = geo_theme_input($theme);
45c46
<           $element[$key]['field']['items'][$i]['#item'] = geo_set_value($item['#item'], $theme);
---
>           $element[$key]['field']['items'][$i]['#item'][$format] = geo_value($item['#item']['wkb'], $format);
52,68d52
< 
< function geo_set_value($item, $theme) {
<   init_theme();
<   $registry = theme_get_registry();
< 
<   if ($format = $registry[$theme]['gis input']) {
<     if (isset($item['wkb']) && !isset($item[$format])) {
<       if (!isset($item['wkb'])) $item['wkb'] = $item['geo'];
<       $value = geo_wkb_get_data($item['wkb'], $format);
<       $item['geo'] = $item[$format] = $value['value'];
<     }
<     else {
<       $item['geo'] = $item[$format] = '';
<     }
<   }
<   return $item;
< }
Index: includes/handlers/geo_simple.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/handlers/geo_simple.inc,v
retrieving revision 1.3
diff -r1.3 geo_simple.inc
22c22
<   private function geometryTypes() {
---
>   public function geometryTypes() {
222c222
<     return $types[$g->geo_type];
---
>     return $types[$g->geoType()];
Index: includes/handlers/geo_sql.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/handlers/geo_sql.inc,v
retrieving revision 1.4
diff -r1.4 geo_sql.inc
59a60
>         $wkt = NULL;
70d70
<             $sql = preg_replace('/\%g/', "GeomFromText('". $wkt ."')", $sql, 1);
72a73,78
>         elseif(is_string($g)) {
>           $wkt = $g;
>         }
>         if (isset($wkt)) {
>           $sql = preg_replace('/\%g/', "GeomFromText('". $wkt ."')", $sql, 1);
>         }
84a91,188
>   /**
>    * Return a list of functions supported by this backend.
>    *
>    * These are used in a user interface (e.g. Views administration)
>    */
>   function supportedFunctions() {
>     return array(
>     );
>   }
> 
>   /**
>    * Returns information about a specific function.
>    */
>   function functionInfo($function) {
>     $functions = $this->supportedFunctions();
>     return $functions[$function];
>   }
> 
>   /**
>    * Return a list of supported functions in a name => value array.
>    */
>   function functionNames($callback) {
>     $return = array();
> 
>     $callback .= 'Functions';
>     foreach ($this->$callback() as $name => $info) {
>       $return[$name] = $info['label'];
>     }
> 
>     return $return;
>   }
> 
>   /**
>    * Return a list of functions that can be used for sorting values.  This
>    * is based on a flag set in the supportedFunctions elements.
>    */
>   function displayFunctions() {
>     static $functions;
>     if (!isset($functions)) {
>       $functions = $this->supportedFunctions();
>       foreach ($functions as $key => $info) {
>         if (!isset($info['display']) || !$info['display']) {
>           unset($functions[$key]);
>         }
>         if (isset($info['geo types'])) {
>           if (!in_array($this->geo_type, $info['geo types'])) {
>             unset($functions[$key]);
>           }
>         }
>       }
>     }
>     return $functions;
>   }
> 
>   /**
>    * Return a list of functions that can be used for filtering values.  This
>    * is based on a flag set in the supportedFunctions elements.
>    */
>   function filterFunctions() {
>     static $functions;
>     if (!isset($functions)) {
>       $functions = $this->supportedFunctions();
>       foreach ($functions as $key => $info) {
>         if (!isset($info['filter']) || !$info['filter']) {
>           unset($functions[$key]);
>         }
>         if (isset($info['geo types'])) {
>           if (!in_array($this->geo_type, $info['geo types'])) {
>             unset($functions[$key]);
>           }
>         }
>       }
>     }
>     return $functions;
>   }
> 
>   /**
>    * Return a list of functions that can be used for sorting values.  This
>    * is based on a flag set in the supportedFunctions elements.
>    */
>   function sortFunctions() {
>     static $functions;
>     if (!isset($functions)) {
>       $functions = $this->supportedFunctions();
>       foreach ($functions as $key => $info) {
>         if (!isset($info['sort']) || !$info['sort']) {
>           unset($functions[$key]);
>         }
>         if (isset($info['geo types'])) {
>           if (!in_array($this->geo_type, $info['geo types'])) {
>             unset($functions[$key]);
>           }
>         }
>       }
>     }
>     return $functions;
>   }
> 
Index: includes/handlers/geo_sql_mysql.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/handlers/geo_sql_mysql.inc,v
retrieving revision 1.3
diff -r1.3 geo_sql_mysql.inc
18a19,111
>   /**
>    * Return a list of functions supported by this backend.
>    *
>    * These are used in a user interface (e.g. Views administration)
>    */
>   function supportedFunctions() {
>     return array(
>       'AsBinary' => array(
>         'label' => t('Well-known binary'),
>       ),
>       'AsText' => array(
>         'label' => t('Well-known text'),
>         'display' => TRUE,
>       ),
>       'x' => array(
>         'label' => t('Longitude'),
>         'returns' => 'float',
>         'geo types' => array(GEO_TYPE_POINT),
>         'sort' => TRUE,
>         'display' => TRUE,
>       ),
>       'y' => array(
>         'label' => t('Latitude'),
>         'returns' => 'float',
>         'geo types' => array(GEO_TYPE_POINT),
>         'sort' => TRUE,
>         'display' => TRUE,
>       ),
>       'length' => array(
>         'label' => t('Length'),
>         'returns' => 'float',
>         'geo types' => array(GEO_TYPE_LINESTRING),
>         'sort' => TRUE,
>         'display' => TRUE,
>         'filter' => TRUE,
>       ),
>       'area' => array(
>         'label' => t('Area'),
>         'returns' => 'float',
>         'geo types' => array(GEO_TYPE_POLYGON),
>         'sort' => TRUE,
>         'display' => TRUE,
>         'filter' => TRUE,
>       ),
>       'distance' => array(
>         'label' => t('Distance'),
>         'returns' => 'float',
>         'requires target' => TRUE,
>         'sort' => TRUE,
>         'display' => TRUE,
>         'filter' => TRUE,
>       ),
>       'distanceSpheroid' => array(
>         'label' => t('Distance (Spherical)'),
>         'returns' => 'float',
>         'requires target' => TRUE,
>         'sort' => TRUE,
>         'display' => TRUE,
>         'filter' => TRUE,
>       ),
>       'equals' => array(
>         'label' => t('Equals'),
>         'returns' => 'boolean',
>         'requires target' => TRUE,
>         'filter' => TRUE,
>       ),
>       'touches' => array(
>         'label' => t('Touches'),
>         'returns' => 'boolean',
>         'requires target' => TRUE,
>         'filter' => TRUE,
>       ),
>       'within' => array(
>         'label' => t('Within'),
>         'returns' => 'boolean',
>         'requires target' => TRUE,
>         'filter' => TRUE,
>       ),
>       'intersects' => array(
>         'label' => t('Intersects'),
>         'returns' => 'boolean',
>         'requires target' => TRUE,
>         'filter' => TRUE,
>       ),
>       'contains' => array(
>         'label' => t('Contains'),
>         'returns' => 'boolean',
>         'requires target' => TRUE,
>         'filter' => TRUE,
>       ),
>     );
>   }
> 
180c273,274
<     return GeoSimple::geometryType($this);
---
>     $types = GeoSimple::geometryTypes();
>     return $types[$this->geo_type];
285a380,471
> 
>   /**
>    * MySQL has no native support for the extent function.
>    * Construct one manually.
>    */
>   public function extent($g) {
>     // TODO this is incorrect!  It's returning coordinates rather than an
>     // actual geometry (box)
>     return $this->sql("MIN(X(PointN(ExteriorRing(Envelope(%g)), 1))) AS minx,
>       MAX(X(PointN(ExteriorRing(Envelope(%g)), 3))) AS maxx,
>       MIN(Y(PointN(ExteriorRing(Envelope(%g)), 1))) AS miny,
>       MAX(Y(PointN(ExteriorRing(Envelope(%g)), 3))) AS maxy",
>       array($g, $g, $g, $g));
>   }
> 
>   /**
>    * MySQL has no native support for distance calculations between geometries
>    * Approximate this using the Pythagorean function.
>    *
>    * NOTE: As we can only support points, the distance measured will be from
>    * Centroid to centroid.  This means that geometries such as Polygons and
>    * Linestrings will have an artificially-high distance result.
>    *
>    * Imagine two 10x10 squares that are adjacent to each other.  In reality,
>    * The distance between these objects is 0.  But this calculation would
>    * return 10. (radius of 5 + radius of 5)
>    *
>    * Still, it's better than nothing.
>    */
>   public function distance($g1, $g2) {
>     // Convert $g2 to a point and get its x and y coordinates.
>     list($x, $y) = array_values(db_fetch_array(db_query("SELECT ".
>       $this->sql("X(%g), Y(%g)", array($g2, $g2)))));
> 
>     // Perhaps it wasn't a point.  Try with a centroid.
>     if (!$x && !$y) {
>       list ($x, $y) = array_values(db_fetch_array(db_query("SELECT ".
>         $this->sql("X(Centroid(%g)), Y(Centroid(%g))", array($g2, $g2)))));
>     }
> 
>     // Offsets, in meters.
>     $mod_x = GEO_DEGREE_M * cos($y / 57.2958);
>     $mod_y = GEO_DEGREE_M;
> 
>     $g = ($g1->geoType() == GEO_TYPE_POINT ) ? '%g' : 'Centroid(%g)';
> 
>     // Let MySQL take it from here with the pythagorean function.
>     $sql = "SQRT(POW(($mod_x * (X($g) - $x)), 2)
>       + POW(($mod_y * (Y($g) - $y)), 2))";
> 
>     return $this->sql($sql, array($g1, $g1));
>   }
> 
>   /**
>    * Calculate distance using the Great Circle Distance Formula.
>    * This is more accurate than the distance() function over large distances,
>    * but less efficient.
>    *
>    * NOTE: As we can only support points, the distance measured will be from
>    * Centroid to centroid.  This means that geometries such as Polygons and
>    * Linestrings will have an artificially-high distance result.
>    */
>   public function distanceSpheroid($g1, $g2) {
>     // Convert $g2 to a point and get its x and y coordinates.
>     list($x, $y) = array_values(db_fetch_array(db_query("SELECT ".
>       $this->sql("X(%g), Y(%g)", array($g2, $g2)))));
> 
>     // Perhaps it wasn't a point.  Try with a centroid.
>     if (!$x && !$y) {
>       list ($x, $y) = array_values(db_fetch_array(db_query("SELECT ".
>         $this->sql("X(Centroid(%g)), Y(Centroid(%g))", array($g2, $g2)))));
>     }
> 
>     // Radius of the earth in meters.
>     $r = 6370986;
> 
>     // Degree offset.
>     $d = 57.2958;
> 
>     // Offsets, in meters.
>     $ysin = sin($y / $d);
>     $ycos = cos($y / $d);
>     $xd   = $x/$d;
> 
>     $g = ($g1->geoType() == GEO_TYPE_POINT ) ? '%g' : 'Centroid(%g)';
> 
>     $sql = "($r * ACOS($ysin * SIN(Y($g)/$d) + $ycos
>       * COS(Y($g)/$d)
>       * COS(X($g)/$d - $xd)))";
> 
>     return $this->sql($sql, array($g1, $g1, $g1));
>   }
Index: includes/views/geo.views.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/views/geo.views.inc,v
retrieving revision 1.6
diff -r1.6 geo.views.inc
8a9,10
> require_once dirname(__FILE__) . '/views_join_geo.inc';
> 
14a17,18
>   $geo_fields = geo_field_names();
> 
17a22,36
>     // Do not process Geo CCK fields, these will be handled separately.
>     if (in_array($geo->name(), $geo_fields)) continue;
> 
>     // Create an all-purpose Geo base table.
>     if (!isset($data['geo'])) {
> 
>       $data['geo_data']['table']['base'] = array(
>         'title' => t('Geospatial data'),
>         'description' => t(''),
>       );
> 
>       // Add to 'geo' group.
>       $data['geo_data']['table']['group']  = t('Geo');
>     }
> 
29c48
<     // There's a geometry column,
---
>     // There's a geometry column. Set up fields relationships between geo data.
31c50,66
<       $data['geo'][$table] = array(
---
> 
>       // Add to 'geo' group.
>       $data[$table]['table']['group']  = t('Geo');
> 
>       // Establish a relationship to the geo_data base table.
>       $data[$table]['table']['join']  = array(
>         'geo_data' => array(
>           'handler' => 'views_join_geo',
>           'left_field' => 'geo',
>           'field' => $column,
>           'geo_gid' => $geo->gid(),
>         ),
>       );
> 
>       // Establish a relationship to the geo_data "base table".
>       $data[$table][$column] = array(
>         'title' => $geo->title(),
33,35c68,69
<           'handler' => 'views_handler_field_numeric',
<           'float' => $float,
<           'click sortable' => TRUE,
---
>           'handler' => 'views_handler_field_geo',
>           'geo_gid' => $geo->gid(),
37,38c71,73
<         'sort' => array(
<           'handler' => 'views_handler_sort',
---
>         'argument' => array(
>           'handler' => 'views_handler_argument_geo',
>           'geo_gid' => $geo->gid(),
41c76,77
<           'handler' => 'views_handler_filter_numeric',
---
>           'handler' => 'views_handler_filter_geo',
>           'geo_gid' => $geo->gid(),
43,45c79,81
<         'argument' => array(
<           'handler' => 'views_handler_argument_numeric',
<           'click sortable' => TRUE,
---
>         'sort' => array(
>           'handler' => 'views_handler_sort_geo',
>           'geo_gid' => $geo->gid(),
48d83
<     }
50,61c85,86
<     // This dataset has additional metadata in a schema definition.
<     if (isset($schema)) {
<       foreach ($schema as $geo_table => $info) {
< 
<         // Field information
<         foreach ($info['fields'] as $field_name => $field_info) {
<           $views_field = array();
< 
<           // Use the field's predefined views stuff.
<           if (isset($field['views'])) {
<             $views_field = $field['views'];
<           }
---
>       // This dataset has additional metadata in a schema definition.
>       if (isset($schema)) {
63,129c88
<           // Make our best guess at what kind of views support to use.
<           else {
<             switch ($field_info['type']) {
<               case 'serial':
<               case 'int':
<               case 'float':
<               case 'numeric':
<                 $float = in_array($field_info['type'], array('float', 'numeric'));
<                 $views_field = array(
<                   'field' => array(
<                     'handler' => 'views_handler_field_numeric',
<                     'float' => $float,
<                     'click sortable' => TRUE,
<                   ),
<                   'sort' => array(
<                     'handler' => 'views_handler_sort',
<                   ),
<                   'filter' => array(
<                     'handler' => 'views_handler_filter_numeric',
<                   ),
<                   'argument' => array(
<                     'handler' => 'views_handler_argument_numeric',
<                     'click sortable' => TRUE,
<                   ),
<                 );
<                 break;
< 
<               case 'varchar':
<               case 'char':
<                 $views_field = array(
<                   'field' => array(
<                     'handler' => 'views_handler_field',
<                   ),
<                   'sort' => array(
<                     'handler' => 'views_handler_sort',
<                   ),
<                   'filter' => array(
<                     'handler' => 'views_handler_filter_string',
<                   ),
<                   'argument' => array(
<                     'handler' => 'views_handler_argument_string',
<                   ),
<                 );
<                 break;
< 
<               case 'text':
<                 $views_field = array(
<                   'field' => array(
<                     'handler' => 'views_handler_field',
<                     'click sortable' => TRUE,
<                   ),
<                   'sort' => array(
<                     'handler' => 'views_handler_sort',
<                   ),
<                   'filter' => array(
<                     'handler' => 'views_handler_filter_string',
<                   ),
<                   'argument' => array(
<                     'handler' => 'views_handler_argument_string',
<                     'click sortable' => TRUE,
<                   ),
<                 );
<                 break;
< 
<               case 'blob':
<                 // Don't deal with these.
<                 break;
---
>         foreach ($schema as $geo_table => $info) {
131c90,181
<               case 'datetime':
---
>           // Field information
>           foreach ($info['fields'] as $field_name => $field_info) {
>             $views_field = array();
> 
>             // Use the field's predefined views stuff.
>             if (isset($field['views'])) {
>               $views_field = $field['views'];
>             }
> 
>             // Make our best guess at what kind of views support to use.
>             else {
>               switch ($field_info['type']) {
>                 case 'serial':
>                 case 'int':
>                 case 'float':
>                 case 'numeric':
>                   $float = in_array($field_info['type'], array('float', 'numeric'));
>                   $views_field = array(
>                     'field' => array(
>                       'handler' => 'views_handler_field_numeric',
>                       'float' => $float,
>                       'click sortable' => TRUE,
>                     ),
>                     'sort' => array(
>                       'handler' => 'views_handler_sort',
>                     ),
>                     'filter' => array(
>                       'handler' => 'views_handler_filter_numeric',
>                     ),
>                     'argument' => array(
>                       'handler' => 'views_handler_argument_numeric',
>                       'click sortable' => TRUE,
>                     ),
>                   );
>                   break;
> 
>                 case 'varchar':
>                 case 'char':
>                   $views_field = array(
>                     'field' => array(
>                       'handler' => 'views_handler_field',
>                     ),
>                     'sort' => array(
>                       'handler' => 'views_handler_sort',
>                     ),
>                     'filter' => array(
>                       'handler' => 'views_handler_filter_string',
>                     ),
>                     'argument' => array(
>                       'handler' => 'views_handler_argument_string',
>                     ),
>                   );
>                   break;
> 
>                 case 'text':
>                   $views_field = array(
>                     'field' => array(
>                       'handler' => 'views_handler_field',
>                       'click sortable' => TRUE,
>                     ),
>                     'sort' => array(
>                       'handler' => 'views_handler_sort',
>                     ),
>                     'filter' => array(
>                       'handler' => 'views_handler_filter_string',
>                     ),
>                     'argument' => array(
>                       'handler' => 'views_handler_argument_string',
>                       'click sortable' => TRUE,
>                     ),
>                   );
>                   break;
> 
>                 case 'blob':
>                   // Don't bother with these.
>                   break;
> 
>                 case 'datetime':
>               }
>             }
> 
>             if ($views_field) {
>               // Set some common values.
>               $views_field['title'] = $geo->title() .' - '. $field_name;
>               $views_field['help'] = '';
> 
>               // Specify the table and field names in the Views field definition,
>               // because we're using generic name of 'geo' to group these.
>               $views_field['table'] = $geo_table;
> 
>               // Add it to the geo base table.
>               $data[$geo_table][$field_name] = $views_field;
133a184,190
>         }
>       }
>     }
>   }
> 
>   return $data;
> }
135,137c192,227
<           if ($views_field) {
<             $views_field['title'] = '';
<             $views_field['help'] = '';
---
> /**
>  * Implementation of CCK's hook_field_settings_alter().
>  */
> function geo_field_settings_alter(&$data, $op, $field) {
>   if ($op == 'views data') {
>     if (in_array($field['field_name'], geo_field_names())) {
> 
>       // No views data from the field module.  Start with CCK defaults
>       if (!$data) $data = content_views_field_views_data($field);
> 
>       // Load the geo handler that controls this dataset.
>       if ($geo = geo_load(array('name' => $field['field_name']))) {
>         $geo->setTableName(content_views_tablename($field));
> 
>         $db_info = content_database_info($field);
>         foreach ($db_info['columns'] as $column => $info) {
>           $table = $geo->tableName();
>           $field = $info['column'];
> 
>           if ($info['gis type']) {
>             // Add a relationship to the Geo join handler.
>             $data[$table][$field]['relationship'] = array(
>               'handler' => 'views_handler_relationship_geo',
>               'join_handler' => 'views_join_geo',
>               'base' => 'geo_data',
>               'field' => 'geo',
>               'label' => t('Geo'),
>               'geo_gid' => $geo->gid(),
>             );
> 
>             // Set all field handlers to Geo's built-in versions.
>             foreach (array('field', 'filter', 'argument', 'sort') as $item) {
>               $handler = 'views_handler_'. $item .'_geo';
>               $data[$table][$field][$item]['handler'] = $handler;
>               $data[$table][$field][$item]['geo_gid'] = $geo->gid();
>             }
140a231
>       // TODO this isn't picking up any of geo_data's fields!
153a245,251
>       'views_join_geo' => array(
>         'parent' => 'views_join',
>       ),
>       'views_handler_relationship_geo' => array(
>         'parent' => 'views_handler_relationship',
>         'join_handler' => 'views_join_geo',
>       ),
155,156c253,254
<       'views_handler_field_geo_field' => array(
<         'parent' => 'content_handler_field',
---
>       'views_handler_field_geo_field' => array( // TODO deprecate?
>         'parent' => 'content_handler_field_multiple',
166c264
<       'views_handler_field_geo_distance' => array(
---
>       'views_handler_field_geo_distance' => array( // TODO deprecate?
170c268
<       'views_handler_filter_geo_distance' => array(
---
>       'views_handler_filter_geo_distance' => array( // TODO deprecate?
174c272
<       'views_handler_sort_geo_distance' => array(
---
>       'views_handler_sort_geo' => array(
237a336,409
> 
> /**
>  * A helper function used across views handlers to select a target geometry.
>  */
> function geo_views_target_form(&$form, &$form_state, &$handler, $group) {
> 
>   if (!isset($handler->geo)) {
>     $handler->geo = geo_load(array('gid' => $handler->definition['geo_gid']));
>   }
> 
>   $functions = $handler->geo->functionNames($group);
> 
>   // Select which function to use.
>   $form['function'] = array(
>     '#type' => 'radios',
>     '#title' => t($group .' function to use'),
>     '#default_value' => $handler->options['function'],
>     '#options' => $functions,
>   );
> 
>   // Some of these functions require a relationship to another value.
>   // If so, show the target handling functionality here.
>   $deps = array();
>   foreach ($functions as $function => $label) {
>     $info = $handler->geo->functionInfo($function);
>     if ($info['requires target']) $deps[] = $function;
>   }
> 
>   $form['target_div_prefix'] = array(
>     '#type' => 'hidden',
>     '#id' => 'geo-target-options',
>     '#prefix' => '<div><fieldset id="geo-target-options"><legend>' . t('Provide a target for this function') . '</legend>',
>     '#process' => array('views_process_dependency'),
>     '#dependency' => array('radio:options[function]' => $deps),
>   );
> 
>   // Add a distance handler to ensure it gets the proper weight.
>   $form['distance'] = array();
> 
>   $form['target'] = array('#tree' => TRUE);
> 
>   $form['target']['input'] = array(
>     '#type' => 'select',
>     '#title' => 'Widget',
>     '#default_value' => $handler->options['target']['input'],
>   );
> 
>   $input_options = array();
>   foreach (geo_inputs() as $name => $info) {
>     $element = $info['element'];
> 
>     $input_options[$name] = $info['label'];
> 
>     $element = array_merge($element, array(
>       '#title' => $handler->options['label'],
>       '#default_value' => $handler->options['target']['value'][$name],
>       '#gis_type' => $handler->geo->geometryType(),
>       '#gis_output' => 'wkt', // The format expected by this handler.
>       '#tree' => TRUE,
>     ));
> 
>     $element['#process'][] = 'views_process_dependency';
>     $element['#dependency'] = array('edit-options-target-input' => array($name));
> 
>     $form['target']['value'][$name] = $element;
>   }
> 
>   // Set the list of elements back to the target options.
>   $form['target']['input']['#options'] = $input_options;
> 
>   $form['target_div_suffix'] = array(
>     '#value' => '</fieldset></div>',
>   );
> }
Index: includes/views/views_handler_field_geo.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/views/views_handler_field_geo.inc,v
retrieving revision 1.4
diff -r1.4 views_handler_field_geo.inc
3a4,14
> 
>   function options_definition() {
>     $options = parent::option_definition();
>     $options['function'] = array('default' => 'AsText');
>     $options['target'] = array(
>       'input' => array('default' => 'geo_latlon'),
>       'value' => array('default' => array()),
>     );
>     return $options;
>   }
> 
5,10c16,29
<     // TODO Implement settings for AsKML, AsSVG, AsText, etc.
<     // By the way, those would only apply to postgis for now.
<     $form['geo_format'] = array(
<       '#type' => 'select',
<       '#options' => geo('query_functions', ($this->definition['geo_type'])),
<       '#default_value' => $this->options['geo_format'],
---
>     parent::options_form($form, $form_state);
> 
>     $geo = geo_load(array('gid' => $this->definition['geo_gid']));
> 
>     // Select which function to use for display.
>     $options = $geo->functionNames('display');
> 
>     // TODO add functions that are formatters for geo fields (e.g maps!)
> 
>     $form['function'] = array(
>       '#type' => 'radios',
>       '#title' => t('Display format'),
>       '#default_value' => $this->options['function'],
>       '#options' => $options,
11a31,32
> 
>     // TODO some of these might have a target (e.g. distance) add target stuff here.
15,16c36
<     $format = $this->options['geo_format'];
<     if (!$format) $format = 'wkt';
---
>     $this->geo = geo_load(array('gid' => $this->definition['geo_gid']));
18,24d37
<     // Add the geo formula as a field.
<     if ($format) {
<       $func = geo('query_'. $format, $this->real_field, array('aggregate' => TRUE));
<     }
<     else {
<       $func = geo('query_'. $format, $this->real_field, array('aggregate' => TRUE));
<     }
26c39,50
<     $this->query->add_field(NULL, $func, $table, array('aggregate' => TRUE));
---
>     $this->geo->setTableName($table);
>     $this->geo->setColumnName($this->field);
> 
>     // For now, we fetch the result as text data.
>     $function = $this->options['function'];
>     if (!$function) return;
> 
>     $this->field_alias .= '_'. strtolower($function);
> 
>     // Add the field, using the Geo API method for getting it.
>     $field = $this->geo->$function($this->geo);
>     $this->query->add_field(NULL, $field, $this->field_alias);
Index: includes/views/views_handler_field_geo_field.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/views/views_handler_field_geo_field.inc,v
retrieving revision 1.2
diff -r1.2 views_handler_field_geo_field.inc
3c3
< class views_handler_field_geo_field extends content_handler_field {
---
> class views_handler_field_geo_field extends content_handler_field_multiple {
10c10,18
<     $this->field_alias = $table .'_'. $this->field;
---
> 
>     // If this field has been added more than once, make its alias unique.
>     $alias = $this->field_alias = $table .'_'. $this->field;
>     for($i = 0; $i <100; $i++) {
>       if (isset($this->query->fields[$this->field_alias])) {
>         $this->field_alias = $alias . $i;
>       }
>       else break;
>     }
21c29,30
<     $this->query->add_field(NULL, $field, $this->field_alias, array('aggregate' => TRUE));
---
>     //$this->query->add_field(NULL, $field, $this->field_alias, array('aggregate' => TRUE));
>     $this->query->add_field(NULL, $field, $this->field_alias);
28,30c37,38
<     $name = $this->options['format'];
<     $formatter = _content_get_formatter($name, $this->content_field['type']);
<     $theme = $formatter['module'] .'_formatter_'. $name;
---
>     $format = geo_formatter_input($this->options['format'], $this->content_field['type']);
>     $alias  = '_'. $this->field_alias;
33,43c41,56
<       // For some reason, this gets called repeatedly.  Don't double-process.
<       if (is_array($row->{$this->field_alias})) return;
< 
<       $field = array(
<         'srid' => $this->geo->srid(),
<         'wkb' => db_decode_blob($row->{$this->field_alias}),
<       );
< 
<       // Convert the output to a format recognized by the theme function
<       if ($value = geo_set_value($field, $theme));
<       $values[$i]->{$this->field_alias} = $value['geo'];
---
>       if (!is_array($values[$i]->$alias)) {
>         $values[$i]->$alias = array(
>           'srid' => $this->geo->srid(),
>           'wkb' => db_decode_blob($row->{$this->field_alias}),
>         );
>       }
> 
>       // The derivative value has already been processed.
>       if (!isset($values[$i]->{$alias}[$format])) {
>         $values[$i]->{$alias}[$format] = geo_value($values[$i]->{$alias}['wkb'], $format);
>       }
> 
>       // Return the field in a format recognized by its formatter.
>       if ($value = $values[$i]->{$alias}[$format]) {
>         $values[$i]->{$this->field_alias} = $values[$i]->{$alias}[$format];
>       }
Index: includes/views/views_handler_filter_geo.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/views/views_handler_filter_geo.inc,v
retrieving revision 1.6
diff -r1.6 views_handler_filter_geo.inc
9c9,17
<     $options['expose']['contains']['gis_input'] = array('default' => '');
---
>     $options['function'] = array('default' => 'distance');
>     $options['target'] = array(
>       'input' => array('default' => 'geo_latlon'),
>       'value' => array('default' => array()),
>     );
>     $options['distance'] = array(
>       'distance' => array('default' => '50'),
>       'units' => array('default' => 'mi'),
>     );
13,20c21,22
<   function construct() {
<     parent::construct();
<     // If this was a CCK field, set the content_field definition.
<       if (function_exists('content_fields')) {
<         $this->content_field = content_fields($this->definition['content_field_name']);
<         $this->additional_fields = $this->definition['additional fields'];
<       }
<   }
---
>   function options_form(&$form, &$form_state) {
>    parent::options_form($form, $form_state);
22,24c24,25
<   function operator_options() {
<     return geo('query_operators', $this->definition['geo_type']);
<   }
---
>     // This helper function provides a function chooser and sets up targets.
>     geo_views_target_form($form, $form_state, $this, 'filter');
26,28c27,33
<   function expose_form_left(&$form, &$form_state) {
<     // Get initial form from the views_handler_filter class.
<     parent::expose_form_left($form, $form_state);
---
>     // Special-case distance filters, which have additional inputs.
>     $dst_functions = array();
>     foreach ($this->geo->functionNames('filter') as $name => $info) {
>       if (substr($name, 0, 8) == 'distance') {
>         $dst_functions[] = $name;
>       }
>     }
30,31c35,52
<     // TODO this is proof of concept and not actually working.
<     $form['expose']['gis_input'] = geo('gis_input_selector', $this->options['expose']['gis_input']);
---
>     $form['distance']['distance'] = array(
>       '#type' => 'textfield',
>       '#title' => t('Distance'),
>       '#default_value' => $this->options['distance']['distance'],
>       '#size' => 5,
>       '#process' => array('views_process_dependency'),
>       '#dependency' => array('edit-options-function' => $dst_functions),
>       '#prefix' => '<div class="container-inline">',
>     );
>     $form['distance']['units'] = array(
>       '#type' => 'select',
>       '#title' => t('Units'),
>       '#options' => geo_units(),
>       '#default_value' => $this->options['distance']['units'],
>       '#process' => array('views_process_dependency'),
>       '#dependency' => array('edit-options-functions' => $dst_functions ),
>       '#suffix' => '</div>',
>     );
35,36c56,57
<     $info = module_invoke_all('gis_input_info');
<     $info = $info[$this->options['expose']['geo_widget']];
---
>     parent::exposed_form($form, $form_state);
> 
38,42c59,69
<     $form[$key] = array_merge($info['element'], array(
<       '#title' => $info['label'],
<       '#default_value' => $this->value,
<       '#gis_type' => 'point', // TODO derived.
<     ));
---
> 
>     // Get the selected input element (e.g. latlon, geocoded textbox, etc.)
>     $input = geo_input_element_info($this->options['target']['input']);
> 
>     if(substr($this->options['function'], 0, 8) == 'distance') {
>       // TODO add distancy stuff here.
>       $form[$key] = $input;
>     }
>     else {
>       $form[$key] = $input;
>     }
46,48c73,76
<     $table = $this->ensure_my_table();
<     $func = $this->operator;
<     $srid = GEO_SRID_DEFAULT;
---
>     $this->geo = geo_load(array('gid' => $this->definition['geo_gid']));
> 
>     // The GIS function we'll be filtering on.
>     $function = $this->options['function'];
50c78,89
<     $value = geo('wkt', $this->value);
---
>     // Figure out whether or not we need a target value to compare against.
>     $target = NULL;
> 
>     $info = $this->geo->functionInfo($function);
>     if ($info['requires target']) {
>       $input = $this->options['target']['input'];
>       $value = $this->options['target']['value'][$input];
>       $target = geo_value($value, 'wkt', 'array'); // TODO assumption of array
>     }
> 
>     $table = $this->ensure_my_table();
>     $this->field_alias = $this->field .'_'. $function;
52,54c91,102
<     if ($geo_table = $this->definition['geo_table']) {
<       $geo_table = $this->query->ensure_table($geo_table, $this->relationship);
<       $field = $geo_table . '.geo';
---
>     // Ensure that the query acts on the table and column aliases defined here.
>     $this->geo->setTableName($table);
>     $this->geo->setColumnName($this->field);
> 
>  		// TODO If there's not already a field with this calculation, add one.
>  		// TODO Add a bounding box filter to leverage the geo index for performance
>  		// TODO Add a distance filter to limit on a circular radius
> 
>     // Add the field, using the Geo API method for getting it.
>     if ($info['return'] == 'boolean') {
>       $where = $this->geo->$function($this->geo, $target);
>       $this->query->add_where(0, $where);
56c104
<     $field = $this->field_name;
---
>     elseif {
58,59d105
<     foreach (geo('query_function', $func, $field, $value, $srid) as $sql) {
<       $this->query->add_where(0, $sql);
Index: includes/views/views_handler_filter_geo_distance.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/includes/views/views_handler_filter_geo_distance.inc,v
retrieving revision 1.7
diff -r1.7 views_handler_filter_geo_distance.inc
46c46
<   
---
> 
140c140
<         $target = geo_value_convert($target, $info['gis input'], 'array');
---
>         $target = geo_value($target, 'array', $info['gis input']);
Index: modules/geo_field/geo_field.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/modules/geo_field/geo_field.module,v
retrieving revision 1.29
diff -r1.29 geo_field.module
52,89d51
< 
<     case 'views data':
<       // Start with default views data, as constructed by CCK.
<       $data = content_views_field_views_data($field);
<       $table = content_views_tablename($field);
< 
<       // Copy the wkt item to geo, and add handlers for the geospatial field.
<       $geo = $field['field_name'] .'_geo';
<       $dst = $field['field_name'] .'_dst';
< 
<       $data[$table][$dst] = $data[$table][$geo];
< 
<       // Set field handler to our own.
<       $data[$table][$geo]['field']['field'] = $geo;
<       $data[$table][$geo]['field']['handler'] = 'views_handler_field_geo_field';
<       $data[$table][$geo]['field']['geo_type'] = $field['geo_type'];
< 
<       // Add a field handler for distance.
<       $data[$table][$dst]['field']['title'] .= ' - '. t('Distance');
<       $data[$table][$dst]['field']['field'] = $geo;
<       $data[$table][$dst]['field']['handler'] = 'views_handler_field_geo_distance';
<       $data[$table][$dst]['field']['float'] = TRUE;
<       $data[$table][$dst]['field']['click sortable'] = TRUE;
<       $data[$table][$dst]['filter']['title'] = $data[$table][$dst]['field']['title'];
<       $data[$table][$dst]['filter']['handler'] = 'views_handler_filter_geo_distance';
<       $data[$table][$dst]['filter']['field'] = $geo;
< 
<       $data[$table][$dst]['sort']['handler'] = 'views_handler_sort_geo_distance';
<       $data[$table][$dst]['sort']['field'] = $geo;
< 
<       $data[$table][$dst]['field']['geo_type'] = $field['geo_type'];
< 
<       // Set filter handler to Geo's built-in geo filters.
<       $data[$table][$geo]['filter']['field'] = $geo;
<       $data[$table][$geo]['filter']['handler'] = 'views_handler_filter_geo';
<       $data[$table][$geo]['filter']['geo_type'] = $field['geo_type'];
< 
<       return $data;
141c103,106
<         $wkt = geo_value_convert($item['geo'], $gis_input, 'wkt');
---
>         $wkt = $item['geo'];
>         if ($gis_input) {
>           $wkt = geo_value($wkt, 'wkt', $gis_input);
>         }
155c120,123
<           $wkt = geo_value_convert($item['geo'], $gis_input, 'wkt');
---
>           if ($gis_input) {
>             $wkt = geo_value($item['geo'], 'wkt', $gis_input);
>           }
>           else $wkt = $item['geo'];
179c147
<   foreach (module_invoke_all('gis_input_info') as $name => $info) {
---
>   foreach (geo_inputs() as $name => $info) {
218,227d185
< 
< /**
<  * Implementation of hook_views_api().
<  */
< function geo_field_views_api() {
<   return array(
<     'api' => 2,
<     'path' => drupal_get_path('module', 'geo_field') .'/includes/views',
<   );
< }
Index: theme/geo.theme.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/geo/theme/geo.theme.inc,v
retrieving revision 1.3
diff -r1.3 geo.theme.inc
53c53
<   return $element['#item'];
---
>   return $element['#item']['geo'];
