Index: flag.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.module,v
retrieving revision 1.11.2.52
diff -u -r1.11.2.52 flag.module
--- flag.module	14 Nov 2008 17:18:02 -0000	1.11.2.52
+++ flag.module	14 Nov 2008 23:28:00 -0000
@@ -410,7 +410,32 @@
     );
   }
 
-  $output .= theme('table', array(t('Flag'), t('Flag type'), t('Roles'), t('Node types'), t('Global?'), t('Operations')), $rows);
+  $header = array(t('Flag'), t('Flag type'), t('Roles'), t('Node types'), t('Global?'), t('Operations'));
+  $output .= theme('table', $header, $rows);
+
+  // Build a list of disabled, module-based flags.
+  $default_flags = flag_get_default_flags(TRUE);
+  $rows = array();
+  foreach ($default_flags as $name => $flag) {
+    if (!isset($flags[$name])) {
+      $ops = theme('links', array(
+        'flags_enable' =>  array('title' => t('enable'), 'href' => "admin/build/flags/edit/". $flag->name),
+      ));
+
+      $roles = array_flip(array_intersect(array_flip(user_roles()), $flag->roles));
+      $rows[] = array(
+        $flag->name,
+        node_get_types('name', $flag->module),
+        $flag->content_type,
+        $ops,
+      );
+    }
+  }
+
+  if (!empty($rows)) {
+    $header = array(t('Disabled Flags'), t('Module'), t('Flag type'), t('Operations'));
+    $output .= theme('table', $header, $rows);
+  }
 
   if (!module_exists('views')) {
     $output .= '<p>' . t('The <a href="@views-url">Views</a> module is not installed, or not enabled. It is recommended that you install the Views module to be able to easily produce lists of flagged content.', array('@views-url' => url('http://drupal.org/project/views'))) . '</p>';
@@ -508,7 +533,14 @@
     // Editing an existing flag.
     $flag = flag_get_flag($name);
     if (empty($flag)) {
-      drupal_goto('admin/build/flags');
+      // Check if we're overriding a default flag.
+      $default_flags = flag_get_default_flags(TRUE);
+      if (isset($default_flags[$name])) {
+        $flag = $default_flags[$name];
+      }
+      else {
+        drupal_goto('admin/build/flags');
+      }
     }
     drupal_set_title(t('Edit @title flag', array('@title' => $flag->get_title())));
   }
@@ -522,6 +554,7 @@
     '#description' => t('The machine-name for this flag. It may be up to 32 characters long and my only contain lowercase letters, underscores, and numbers. It will be used in URLs and in all API calls.'),
     '#maxlength' => 32,
     '#required' => TRUE,
+    '#access' => empty($flag->locked['name']),
   );
 
   if (!empty($flag->fid)) {
@@ -535,6 +568,7 @@
     '#description' => t('A short, descriptive title for this flag. It will be used in administrative interfaces to refer to this flag, and in page titles and menu items of some <a href="@insite-views-url">views</a> this module provides (theses are customizable, though). Some examples could be <em>Bookmarks</em>, <em>Favorites</em>, or <em>Offensive</em>.', array('@insite-views-url' => url('admin/build/views'))),
     '#maxlength' => 255,
     '#required' => TRUE,
+    '#access' => empty($flag->locked['title']),
   );
 
   $form['flag_short'] = array(
@@ -543,6 +577,7 @@
     '#default_value' => $flag->flag_short,
     '#description' => t('The text for the "flag this" link for this flag.'),
     '#required' => TRUE,
+    '#access' => empty($flag->locked['flag_short']),
   );
 
   $form['flag_long'] = array(
@@ -550,6 +585,7 @@
     '#title' => t('Flag link description'),
     '#default_value' => $flag->flag_long,
     '#description' => t('The description of the "flag this" link. Usually displayed on mouseover.'),
+    '#access' => empty($flag->locked['flag_long']),
   );
 
   $form['flag_confirmation'] = array(
@@ -557,6 +593,7 @@
     '#title' => t('Flag confirmation message'),
     '#default_value' => $flag->flag_confirmation,
     '#description' => t('Message displayed if the user has clicked the "flag this" link and confirmation is required. Usually presented in the form of a question such as, "Are you sure you want to flag this content?"'),
+    '#access' => empty($flag->locked['flag_confirmation']),
   );
 
   $form['flag_message'] = array(
@@ -564,6 +601,7 @@
     '#title' => t('Flagged message'),
     '#default_value' => $flag->flag_message,
     '#description' => t('Message displayed after flagging content. If JavaScript is enabled, it will be displayed below the link. If not, it will be displayed in the message area.'),
+    '#access' => empty($flag->locked['flag_message']),
   );
 
   $form['unflag_short'] = array(
@@ -572,6 +610,7 @@
     '#default_value' => $flag->unflag_short,
     '#description' => t('The text for the "unflag this" link for this flag.'),
     '#required' => TRUE,
+    '#access' => empty($flag->locked['unflag_short']),
   );
 
   $form['unflag_long'] = array(
@@ -579,6 +618,7 @@
     '#title' => t('Unflag link description'),
     '#default_value' => $flag->unflag_long,
     '#description' => t('The description of the "unflag this" link. Usually displayed on mouseover.'),
+    '#access' => empty($flag->locked['unflag_long']),
   );
 
   $form['unflag_confirmation'] = array(
@@ -586,6 +626,7 @@
     '#title' => t('Unflag confirmation message'),
     '#default_value' => $flag->unflag_confirmation,
     '#description' => t('Message displayed if the user has clicked the "unflag this" link and confirmation is required. Usually presented in the form of a question such as, "Are you sure you want to unflag this content?"'),
+    '#access' => empty($flag->locked['unflag_confirmation']),
   );
 
   $form['unflag_message'] = array(
@@ -593,6 +634,7 @@
     '#title' => t('Unflagged message'),
     '#default_value' => $flag->unflag_message,
     '#description' => t('Message displayed after content has been unflagged. If JavaScript is enabled, it will be displayed below the link. If not, it will be displayed in the message area.'),
+    '#access' => empty($flag->locked['unflag_message']),
   );
 
   if (module_exists('token')) {
@@ -616,6 +658,7 @@
     '#default_value' => $flag->global,
     '#description' => t('If checked, flag is considered "global" and each node is either flagged or not. If unchecked, each user has individual flags on content.'),
     '#weight' => 1,
+    '#access' => empty($flag->locked['global']),
   );
 
   $form['roles'] = array(
@@ -626,6 +669,7 @@
     '#required' => TRUE,
     '#description' => t('Checking <em>authenticated user</em> will allow all logged-in users to flag content with this flag. Anonymous users may not flag content.'),
     '#weight' => 5,
+    '#access' => empty($flag->locked['roles']),
   );
 
   $form['types'] = array(
@@ -636,6 +680,7 @@
     '#description' => t('Check any node types that this flag may be used on. You must check at least one node type.'),
     '#required' => TRUE,
     '#weight' => 10,
+    '#access' => empty($flag->locked['types']),
   );
 
   $form['display'] = array(
@@ -652,6 +697,7 @@
     '#options' => _flag_link_type_options(),
     '#default_value' => $flag->link_type,
     '#weight' => 2,
+    '#access' => isset($flag->locked['link_type']),
   );
 
   $form['submit'] = array(
@@ -695,6 +741,7 @@
   $flag = $form['#flag'];
   $flag->form_input($form_state['values']);
   $flag->save();
+  $flag->enable();
   drupal_set_message(t('Flag @name has been saved.', array('@name' => $flag->get_title())));
   _flag_clear_cache();
   $form_state['redirect'] = 'admin/build/flags';
@@ -714,7 +761,7 @@
   return confirm_form($form,
     t('Are you sure you want to delete %title?', array('%title' => $flag->get_title())),
     !empty($_GET['destination']) ? $_GET['destination'] : 'admin/build/flags',
-    t('This action cannot be undone.'),
+    isset($flag->module) ? t('This flag is provided by the @module module. It will loose any customizations and be disabled.', array('@module' => node_get_types('name', $flag->module))) : t('This action cannot be undone.'),
     t('Delete'), t('Cancel')
   );
 }
@@ -723,6 +770,7 @@
   $flag = flag_get_flag(NULL, $form_state['values']['fid']);
   if ($form_state['values']['confirm']) {
     $flag->delete();
+    $flag->disable();
     _flag_clear_cache();
   }
   drupal_set_message(t('Flag @name has been deleted.', array('@name' => $flag->get_title())));
@@ -1127,7 +1175,7 @@
  */
 function flag_get_flag($name = NULL, $fid = NULL) {
   $flags = flag_get_flags();
-  if (isset($name)) {
+  if (isset($name) && isset($flags[$name])) {
     return $flags[$name];
   }
   elseif (isset($fid)) {
@@ -1164,6 +1212,8 @@
   // Retrieve a list of all flags, regardless of the parameters.
   if (!isset($flags) || $reset) {
     $flags = array();
+
+    // Database flags.
     $result = db_query("SELECT f.*, fn.type FROM {flags} f LEFT JOIN {flag_types} fn ON fn.fid = f.fid");
     while ($row = db_fetch_object($result)) {
       if (!isset($flags[$row->name])) {
@@ -1173,6 +1223,29 @@
         $flags[$row->name]->types[] = $row->type;
       }
     }
+
+    // Add code-based flags provided by modules.
+    $default_flags = flag_get_default_flags();
+    foreach ($default_flags as $name => $default_flag) {
+      // Insert new enabled flags into the database to give them an FID.
+      if ($default_flag->status && !isset($flags[$name])) {
+        $default_flag->save();
+        $flags[$name] = $default_flag;
+      }
+
+      if (isset($flags[$name])) {
+        // Ensure overridden flags are associated with their parent module.
+        $flags[$name]->module = $default_flag->module;
+
+        // Update the flag with any properties that are "locked" by the code version.
+        if (isset($default_flag->locked)) {
+          $flags[$name]->locked = $default_flag->locked;
+          foreach ($default_flag->locked as $property) {
+            $flags[$name]->$property = $default_flag->$property;
+          }
+        }
+      }
+    }
   }
 
   // Make a variable copy to filter types and account.
@@ -1200,6 +1273,39 @@
 }
 
 /**
+ * Retrieve a list of flags defined by modules.
+ *
+ * @param $include_disabled
+ *   Unless specified, only enabled flags will be returned.
+ * @return
+ *   An array of flag prototypes, not usable for flagging. Use flag_get_flags()
+ *   if needing to perform a flagging with any enabled flag.
+ */
+function flag_get_default_flags($include_disabled = FALSE) {
+  $default_flags = array();
+  $flag_status = variable_get('flag_default_flag_status', array());
+
+  foreach (module_implements('flag_default_flags') as $module) {
+    $function = $module . '_flag_default_flags';
+    foreach ($function() as $config) {
+      $flag = flag_flag::factory_by_array($config);
+      $flag->module = $module;
+      // Add flags that have been enabled.
+      if ((!isset($flag_status[$flag->name]) && (!isset($flag->status) || $flag->status)) || !empty($flag_status[$flag->name])) {
+        $flag->status = TRUE;
+        $default_flags[$flag->name] = $flag;
+      }
+      elseif ($include_disabled) {
+        $flag->status = FALSE;
+        $default_flags[$flag->name] = $flag;
+      }
+    }
+  }
+
+  return $default_flags;
+}
+
+/**
  * Find what a user has flagged, either a single node or on the entire site.
  *
  * @param $content_type
Index: flag.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/flag/Attic/flag.inc,v
retrieving revision 1.1.2.23
diff -u -r1.1.2.23 flag.inc
--- flag.inc	14 Nov 2008 17:18:02 -0000	1.1.2.23
+++ flag.inc	14 Nov 2008 23:28:00 -0000
@@ -150,7 +150,24 @@
 
     return $flag;
   }
-  
+
+  /**
+   * Create a complete flag (except an FID) from an array definition.
+   */
+  function factory_by_array($config) {
+    $flag = flag_create_handler($config['content_type']);
+
+    foreach ($config as $option => $value) {
+      $flag->$option = $value;
+    }
+
+    if (is_array($config['locked'])) {
+      $flag->locked = drupal_map_assoc($config['locked']);
+    }
+
+    return $flag;
+  }
+
   /**
    * Another factory method. Returns a new, "empty" flag; e.g., one suitable for
    * the "Add new flag" page.
@@ -706,6 +723,28 @@
   }
 
   /**
+   * Disable a flag provided by a module.
+   */
+  function disable() {
+    if (isset($this->module)) {
+      $flag_status = variable_get('flag_default_flag_status', array());
+      $flag_status[$this->name] = FALSE;
+      variable_set('flag_default_flag_status', $flag_status);
+    }
+  }
+
+  /**
+   * Enable a flag provided by a module.
+   */
+  function enable() {
+    if (isset($this->module)) {
+      $flag_status = variable_get('flag_default_flag_status', array());
+      $flag_status[$this->name] = TRUE;
+      variable_set('flag_default_flag_status', $flag_status);
+    }
+  }
+
+  /**
    * Renders a flag/unflag link. This is a wrapper around theme('flag') that,
    * in Drupal 6, easily channels the call to the right template file.
    *
@@ -770,17 +809,20 @@
       '#type' => 'checkbox',
       '#title' => t('Display link on node teaser'),
       '#default_value' => $this->show_on_teaser,
+      '#access' => empty($this->locked['show_on_teaser']),
     );
     $form['display']['show_on_page'] = array(
       '#type' => 'checkbox',
       '#title' => t('Display link on node page'),
       '#default_value' => $this->show_on_page,
+      '#access' => empty($this->locked['show_on_page']),
     );
     $form['display']['show_on_form'] = array(
       '#type' => 'checkbox',
       '#title' => t('Display checkbox on node edit form'),
       '#default_value' => $this->show_on_form,
       '#description' => t('If you elect to have a checkbox on the node edit form, you may specify its initial state in the settings form <a href="@content-types-url">for each content type</a>.', array('@content-types-url' => url('admin/content/types'))),
+      '#access' => empty($this->locked['show_on_form']),
     );
   }
 
@@ -913,6 +955,7 @@
       '#type' => 'checkbox',
       '#title' => t('Display link under comment'),
       '#default_value' => $this->show_on_comment,
+      '#access' => empty($this->locked['show_on_comment']),
     );
   }
 
@@ -1012,6 +1055,7 @@
       '#type' => 'checkbox',
       '#title' => t('Display link on user profile page'),
       '#default_value' => $this->show_on_profile,
+      '#access' => empty($this->locked['show_on_profile']),
     );
   }
 
