? location_cck.patch
Index: location_cck.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/location/contrib/location_cck/location_cck.module,v
retrieving revision 1.5.2.11
diff -u -p -r1.5.2.11 location_cck.module
--- location_cck.module	3 Apr 2009 18:59:21 -0000	1.5.2.11
+++ location_cck.module	6 Jul 2009 10:55:05 -0000
@@ -12,7 +12,19 @@
 function location_cck_theme() {
   return array(
     'location_cck_formatter_default' => array(
-      'arguments' => array('element'),
+      'arguments' => array('element' => NULL),
+    ),
+    'location_cck_formatter_all' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'location_cck_formatter_map' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'location_cck_field_map' => array(
+      'arguments' => array('locations' => NULL, 'field' => NULL),
+    ),
+    'location_cck_field_popup' => array(
+      'arguments' => array('location' => NULL, 'field' => NULL),
     ),
   );
 }
@@ -38,7 +50,7 @@ function location_cck_field_settings($op
       $form = array();
       $settings = isset($field['location_settings']) ? $field['location_settings'] : FALSE;
       $form['location_settings'] = location_settings($settings);
-
+      
       // Multiple is handled by CCK.
       unset ($form['location_settings']['multiple']);
       // CCK handles weight, and collapsibility is not changeable.
@@ -46,10 +58,46 @@ function location_cck_field_settings($op
       unset ($form['location_settings']['form']['collapsible']);
       unset ($form['location_settings']['form']['collapsed']);
       unset ($form['location_settings']['display']['weight']);
+      
+      // We want to see the settings, so uncollapse them.
+      $form['location_settings']['#collapsible'] = FALSE;
+      $form['location_settings']['form']['#collapsed'] = FALSE;
+      $form['location_settings']['display']['#collapsed'] = FALSE;
+      
+      // Add some GMap settings, if GMap is enabled.
+      if (module_exists('gmap')) {
+        $gmap = variable_get("gmap_node_map", _gmap_location_node_map_defaults());
+        $default_macro = $gmap['macro'];
+        $form['gmap_macro'] = array(
+          '#type' => 'textarea',
+          '#title' => t('GMap Macro'),
+          '#rows' => 2,
+          '#maxlength' => 500,
+          '#description' => t('A macro to be used as a base map for this field.  This map will be recentered on the location, so the center is not that important.'),
+          '#default_value' => !empty($field['gmap_macro']) ? $field['gmap_macro'] : $default_macro,
+        );
+        $options = gmap_get_marker_titles();
+        $form['gmap_marker'] = array(
+          '#type' => 'select',
+          '#title' => t('GMap marker'),
+          '#options' => $options,
+          '#default_value' => !empty($field['gmap_marker']) ? $field['gmap_marker'] : 'drupal',
+        );
+      }
+      else {
+        $form['gmap_macro'] = array(
+          '#type' => 'hidden',
+          '#value' => '',
+          );
+        $form['gmap_marker'] = array(
+          '#type' => 'hidden',
+          '#value' => '',
+        );  
+      }
       return $form;
 
     case 'save':
-      return array('location_settings');
+      return array('location_settings', 'gmap_macro', 'gmap_marker');
 
     case 'database columns':
       return array(
@@ -60,40 +108,6 @@ function location_cck_field_settings($op
         ),
       );
 
-    case 'arguments':
-/*      $arguments = content_views_field_arguments($field);
-      $alias = "content: $field[field_name]";
-      $argument = array(
-        'handler' => 'text_views_argument_handler',
-        'option' => 'string',
-        'help' => t('Set the option to the number of initial characters to filter by. Leave empty for full term; use 1 for an A/B/C style glossary.'),
-      );
-      $arguments[$alias] = array_merge($arguments[$alias], $argument);
-      return $arguments;*/return;
-
-    case 'filters':
-      /*
-      $allowed_values = text_allowed_values($field);
-       if (count($allowed_values)) {
-         return array(
-           'default' => array(
-            'list' => $allowed_values,
-             'list-type' => 'list',
-             'operator' => 'views_handler_operator_andor',
-             'value-type' => 'array',
-            ),
-          );
-        }
-      else {
-        return array(
-          'like' => array(
-            'operator' => 'views_handler_operator_like',
-            'handler' => 'views_handler_filter_like',
-          ),
-        );
-      }*/
-      break;
-
     case 'views data':
       // We want to for the most part use the CCK stuff, but we also want to
       // patch in a relationship so location's views support can target
@@ -112,66 +126,11 @@ function location_cck_field_settings($op
   }
 }
 
-/*
-
-function location_cck_views_argument_handler($op, &$query, $argtype, $arg = '') {
-  $name = explode(':', is_array($argtype) ? $argtype['type'] : $argtype);
-  $field_name = trim($name[1]);
-  $field      = content_fields($field_name);
-  $db_info    = content_database_info($field);
-  $value      = $db_info['columns']['value']['column'];
-  $table      = 'node_data_'. $field['field_name'];
-
-  switch($op) {
-    case 'summary':
-      $query->ensure_table($table);
-      $query->add_field($value, $table);
-
-      $length = intval($arg);
-      $fieldinfo['field'] = $length <= 0 ? "$table.$value" : "LEFT($table.$value, $length)";
-      $fieldinfo['fieldname'] = 'letter';
-      return $fieldinfo;
-
-    case 'sort':
-      break;
-
-    case 'filter':
-      $query->ensure_table($table);
-      $query->add_field($value, $table);
-
-      $length = intval($argtype['options']);
-      $where = $length <= 0 ? "$table.$value = '%s'" : "LEFT($table.$value, $length) = '%s'";
-      $query->add_where($where, $arg);
-      break;
-
-    case 'link':
-      return l(strtoupper($query->letter), "$arg/$query->letter");
-
-    case 'title':
-      return check_plain(strtoupper($query));
-  }
-}
-*/
-
 /**
  * Implementation of hook_field().
  */
 function location_cck_field($op, &$node, $field, &$items, $teaser, $page) {
   switch ($op) {
-    case 'validate':
-      /*
-      if (is_array($items)) {
-        foreach ($items as $delta => $item) {
-          $error_field = $field['field_name'] .']['. $delta .'][value';
-          if ($item['value'] != '') {
-            if (count($allowed_values) && !array_key_exists($item['value'], $allowed_values)) {
-              form_set_error($error_field, t('Illegal value for %name.', array('%name' => t($field['widget']['label']))));
-            }
-          }
-        }
-      }
-      */
-      break;
 
     case 'insert':
     case 'update':
@@ -211,29 +170,30 @@ function location_cck_field($op, &$node,
  * Implementation of hook_field_formatter_info().
  */
 function location_cck_field_formatter_info() {
-  return array(
+  $info = array(
     'default' => array(
-      'label' => t('Default'),
+      'label' => t('Default (address)'),
       'field types' => array('location'),
     ),
   );
-}
-
-/**
- * Implementation of hook_field_formatter().
- *
- * The $node argument is necessary so that filter access can be checked on
- * node preview.
- */
-function location_cck_field_formatter($field, $item, $formatter, $node) {
-  if (empty($item)) {
-    return '';
+  if (module_exists('gmap')) {
+    $info['all'] = array(
+      'label' => t('Address with map'),
+      'field types' => array('location'),
+    );
+    $info['map'] = array(
+      'label' => t('Map only'),
+      'field types' => array('location'),
+    );
+    $info['multiple'] = array(
+      'label' => t('Multiple field values on a single map'),
+      'field types' => array('location'),
+      'multiple values' => CONTENT_HANDLE_MODULE,
+    );
   }
-  $item = location_load_location($item['lid']);
-  return theme('location', $item);
+  return $info;
 }
 
-
 /**
  * Implementation of hook_widget_info().
  */
@@ -242,30 +202,21 @@ function location_cck_widget_info() {
     'location' => array(
       'label' => t('Location Field'),
       'field types' => array('location'),
+      // Location will set its own custom values.
       'callbacks' => array(
-//        'default value' => CONTENT_CALLBACK_CUSTOM,
+        //'default value' => CONTENT_CALLBACK_MODULE,
       ),
     ),
   );
 }
 
 /**
- * Implementation of hook_widget_settings().
- */
-function location_cck_widget_settings($op, $widget) {
-
-}
-
-/**
  * Implementation of hook_widget().
  */
 function location_cck_widget(&$form, &$form_state, $field, $items, $delta = 0) {
   if ($field['widget']['type'] == 'location') {
     $settings = $field['location_settings'];
 
-    // Initialize empty location.
-    $location = location_empty_location($settings);
-
     // Load location data for existing locations.
     if (isset($items[$delta]['lid']) && $items[$delta]['lid']) {
       // Are we in a node preview?
@@ -283,11 +234,12 @@ function location_cck_widget(&$form, &$f
     }
     // Load location data passed by cck.
     else if (isset($items[$delta]) && is_array($items[$delta]) && !empty($items[$delta])) {
-
+      
+      // Initialize empty location.
+      $location = location_empty_location($settings);
       foreach ($items[$delta] as $k => $v) {
         $location[$k] = $v;
       }
-
       // We can't trust that CCK is giving us the right information.
       // It can't tell us whether $items is defaults or multistep values.
       // Location *needs* the defaults to match the initial field values,
@@ -314,6 +266,7 @@ function location_cck_widget(&$form, &$f
       '#required' => $field['required'],
       '#location_settings' => $settings,
       '#default_value' => $location,
+      '#element_validate' => array('location_cck_validate'),
     );
     // This is used to determine whether we are in a preview or not, because
     // several pieces of code work differently when previewing.
@@ -326,16 +279,29 @@ function location_cck_widget(&$form, &$f
 }
 
 /**
+ * Add validation when a location is chosen on a map
+ * but is given no name to warn it will not be
+ * saved (won't make it through location_is_empty()).
+ */
+function location_cck_validate($element, &$form_state) {
+  $location = $element['#value'];
+  $fields = $location;
+  if (location_is_empty($location, $fields)) {
+    if (!empty($location['locpick']['user_latitude']) && !empty($location['locpick']['user_longitude'])) {
+      // We don't exactly which location fields are available
+      // so just pick the first one for our error message.
+      $field_key = array_shift(array_keys($fields));
+      $labels = location_locationapi($fields, 'fields');
+      $error_field = implode('][', $element['#parents']) .']['. $field_key;
+      form_set_error($error_field, t('Location coordinates will not be stored unless they have %field_key or some other value set.', array('%field_key' => $labels[$field_key])));
+    }
+  }
+}
+
+/**
  * CCK Emptiness check.
  */
 function location_cck_content_is_empty($item, $field) {
-  // @@@ Bug:
-  // There is a suspect check here from content_set_empty().
-  // It's calling this function with raw cck defaults.
-  // I think it's causing a minimum of two fieldsets to be shown when using
-  // cck default values.
-
-  // Empty check
   $fields = array();
   if (location_is_empty($item, $fields)) {
     return TRUE;
@@ -343,6 +309,9 @@ function location_cck_content_is_empty($
   return FALSE;
 }
 
+/**
+ * Return an address for an individual item.
+ */
 function theme_location_cck_formatter_default($element) {
   $field = content_fields($element['#field_name'], $element['#type_name']);
   $hide = array_keys(array_filter($field['location_settings']['display']['hide']));
@@ -363,6 +332,109 @@ function theme_location_cck_formatter_de
   }
 }
 
+/**
+ * Return both an address and a map for an individual item.
+ */
+function theme_location_cck_formatter_all($element) {
+  $content = '';
+  $field = content_fields($element['#field_name'], $element['#type_name']);
+  $hide = array_keys(array_filter($field['location_settings']['display']['hide']));
+  $location = $element['#item'];
+  if (!empty($location['cck_preview_in_progress'])) {
+    // Our canary field is in place, we are in a node preview.
+    $fields = array();
+    // If the delete location checkbox isn't checked, and the location isn't
+    // "empty", then theme it based on the current state of the item.
+    if (!location_is_empty($location, $fields) && empty($location['delete_location'])) {
+      $content = theme('location', $location, $hide);
+    }
+  }
+  else if (isset($location['lid']) && $location['lid']) {
+    // "normal" viewing.
+    // Location is already cached by CCK, so no need to load it.
+    $content = theme('location', $location, $hide);
+  }
+  $content .= theme_location_cck_field_map(array($location), $field);
+  return $content;
+}
+
+/**
+ * Returns a map for an individual field value.
+ */
+function theme_location_cck_formatter_map($element) {
+  $field = content_fields($element['#field_name'], $element['#type_name']);
+  $location = $element['#item'];
+  return theme_location_cck_field_map(array($location), $field);  
+}
+
+/**
+ * Alternate function to return a map with all
+ * multiple values in the same map.
+ */
+function theme_location_cck_formatter_combined($element) {
+  $field = content_fields($element['#field_name'], $element['#type_name']);
+  $locations = $element['#items'];
+  return theme_location_cck_field_map($locations, $field);
+}
+
+/**
+ * Generate a GMap map for one or more location field values.
+ * 
+ * Mostly just cut and paste from gmap_location 
+ * block view.
+ */
+function theme_location_cck_field_map($locations, $field) {
+  $content = '';
+  foreach ($locations as $location) {
+    if (location_has_coordinates($location)) {
+      $count++;
+      $markername = isset($field['gmap_marker']) ? $field['gmap_marker'] : 'drupal';
+      $markers[] = array(
+        'latitude' => $location['latitude'],
+        'longitude' => $location['longitude'],
+        'markername' => $markername,
+        'offset' => $count-1,
+        'text' => theme('location_cck_field_popup', $location, $field),
+      );
+    }
+  }
+  if (!empty($markers)) {
+    $macro = $field['gmap_macro'];
+    if (empty($macro)) {
+      $gmap = variable_get("gmap_node_map", _gmap_location_node_map_defaults());
+      $macro = $gmap['macro'];
+    }
+    $map = gmap_parse_macro($macro);
+    $map['latitude'] = $markers[0]['latitude'];
+    $map['longitude'] = $markers[0]['longitude'];
+    $map['markers'] = $markers;
+    $map['zoom'] = $map['gmap zoom'];
+    $map['id'] = gmap_get_auto_mapid();
+    $content = theme('gmap', array('#settings' => $map));
+  }
+  return $content;
+}
+
+/**
+ * Theme the GMap popup text for the field.
+ */
+function theme_location_cck_field_popup($location, $field) {
+  $hide = array_keys(array_filter($field['location_settings']['display']['hide']));
+  // Don't use a map link in a popup!
+  // We're making the name into a title.
+  $hide[] = 'map_link';
+  $hide[] = 'name';
+  
+  $markertitle = $field['widget']['label'];
+  if (!empty($location['name'])) {
+    $markertitle = $location['name'];
+  }
+  return '<h4>'. $markertitle .'</h4>'. theme('location', $location, $hide);
+}
+
+/**
+ * Implementation of hook_token_list().
+ */
 function location_cck_token_list($type = 'all') {
   if ($type == 'field') {
     $tokens = array();
@@ -378,6 +450,9 @@ function location_cck_token_list($type =
   }
 }
 
+/**
+ * Implementation of hook_token_values().
+ */
 function location_cck_token_values($type, $object = NULL) {
   if ($type == 'field') {
     $tokens = array();
