### Eclipse Workspace Patch 1.0
#P drupal7-cvs
Index: modules/filter/filter.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.install,v
retrieving revision 1.16
diff -u -r1.16 filter.install
--- modules/filter/filter.install	27 May 2009 18:33:57 -0000	1.16
+++ modules/filter/filter.install	24 Jul 2009 23:34:27 -0000
@@ -10,90 +10,83 @@
  * Implement hook_schema().
  */
 function filter_schema() {
-  $schema['filter'] = array(
-    'description' => 'Table that maps filters (HTML corrector) to text formats (Filtered HTML).',
+  $schema['filter_format'] = array(
+    'description' => 'Stores text formats: custom groupings of filters, such as Filtered HTML.',
     'fields' => array(
-      'fid' => array(
+      'format_id' => array(
         'type' => 'serial',
         'not null' => TRUE,
-        'description' => 'Primary Key: Auto-incrementing filter ID.',
+        'description' => 'Primary Key: Unique ID for format.',
       ),
-      'format' => array(
-        'type' => 'int',
+      'name' => array(
+        'type' => 'varchar',
+        'length' => 255,
         'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Foreign key: The {filter_format}.format to which this filter is assigned.',
+        'default' => '',
+        'description' => 'Name of the text format (Filtered HTML).',
       ),
-      'module' => array(
+      'roles' => array(
         'type' => 'varchar',
-        'length' => 64,
+        'length' => 255,
         'not null' => TRUE,
         'default' => '',
-        'description' => 'The origin module of the filter.',
+        'description' => 'A comma-separated string of roles; references {role}.rid.', // This is bad since you can't use joins, nor index.
       ),
-      'delta' => array(
+      'cache' => array(
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
         'size' => 'tiny',
-        'description' => 'ID to identify which filter within module is being referenced.',
+        'description' => 'Flag to indicate whether format is cacheable. (1 = cacheable, 0 = not cacheable)',
       ),
       'weight' => array(
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
         'size' => 'tiny',
-        'description' => 'Weight of filter within format.',
+        'description' => 'Weight of text format to use when listing.',
       )
     ),
-    'primary key' => array('fid'),
+    'primary key' => array('format_id'),
     'unique keys' => array(
-      'fmd' => array('format', 'module', 'delta'),
-    ),
-    'indexes' => array(
-      'list' => array('format', 'weight', 'module', 'delta'),
+      'name' => array('name'),
     ),
   );
-  $schema['filter_format'] = array(
-    'description' => 'Stores text formats: custom groupings of filters, such as Filtered HTML.',
+
+  $schema['filter_format_filter'] = array(
+    'description' => 'Table that maps text formats (Filtered HTML) to text formats (HTML corrector).',
     'fields' => array(
-      'format' => array(
-        'type' => 'serial',
+      'format_id' => array(
+        'type' => 'int',
         'not null' => TRUE,
-        'description' => 'Primary Key: Unique ID for format.',
+        'default' => 0,
+        'description' => 'Foreign key: The {filter_format}.format_id',
       ),
-      'name' => array(
+      'module' => array(
         'type' => 'varchar',
-        'length' => 255,
+        'length' => 64,
         'not null' => TRUE,
         'default' => '',
-        'description' => 'Name of the text format (Filtered HTML).',
+        'description' => 'The origin module of the filter.',
       ),
-      'roles' => array(
+      'filter_id' => array(
         'type' => 'varchar',
-        'length' => 255,
+        'length' => 64,
         'not null' => TRUE,
         'default' => '',
-        'description' => 'A comma-separated string of roles; references {role}.rid.', // This is bad since you can't use joins, nor index.
-      ),
-      'cache' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'size' => 'tiny',
-        'description' => 'Flag to indicate whether format is cacheable. (1 = cacheable, 0 = not cacheable)',
-      ),
+        'description' => 'The filter referenced unique ID as defined in hook_filter_info().',
+      ),      
       'weight' => array(
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
         'size' => 'tiny',
-        'description' => 'Weight of text format to use when listing.',
+        'description' => 'Weight of filter within format.',
       )
     ),
-    'primary key' => array('format'),
-    'unique keys' => array(
-      'name' => array('name'),
+    'primary key' => array('format_id', 'module', 'filter_id'),
+    'foreign keys' => array(
+      'format_id' => array('filter_format' => 'format_id'),
     ),
   );
 
Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.263
diff -u -r1.263 filter.module
--- modules/filter/filter.module	19 Jul 2009 05:34:52 -0000	1.263
+++ modules/filter/filter.module	24 Jul 2009 23:34:37 -0000
@@ -88,10 +88,10 @@
     'type' => MENU_LOCAL_TASK,
     'weight' => 1,
   );
-  $items['admin/settings/formats/delete'] = array(
+  $items['admin/settings/formats/delete/%filter_format'] = array(
     'title' => 'Delete text format',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('filter_admin_delete'),
+    'page arguments' => array('filter_admin_delete', 4),
     'access arguments' => array('administer filters'),
     'type' => MENU_CALLBACK,
   );
@@ -299,7 +299,7 @@
     $formats = array();
 
     $query = db_select('filter_format', 'f');
-    $query->addField('f', 'format', 'format');
+    $query->addField('f', 'format_id', 'format_id');
     $query->addField('f', 'name', 'name');
     $query->addField('f', 'roles', 'roles');
     $query->addField('f', 'cache', 'cache');
@@ -308,15 +308,16 @@
 
     // Build query for selecting the format(s) based on the user's roles.
     if (!$all) {
-      $or = db_or()->condition('format', variable_get('filter_default_format', 1));
+      $or = db_or()->condition('format_id', variable_get('filter_default_format', 1));
       foreach ($user->roles as $rid => $role) {
         $or->condition('roles', '%' . (int)$rid . '%', 'LIKE');
       }
       $query->condition($or);
     }
 
-    $formats = $query->execute()->fetchAllAssoc('format');
+    $formats = $query->execute()->fetchAllAssoc('format_id');
   }
+  
   if (isset($index)) {
     return isset($formats[$index]) ? $formats[$index] : FALSE;
   }
@@ -324,24 +325,45 @@
 }
 
 /**
+ * Collect the filter definitions from modules that implement hook_filter_info().
+ */
+function filter_build() {
+	static $filter_info;
+	
+	if (!isset($filter_info)) {
+	  // We need to manually call each module so that we can know which module
+	  // a given item came from.
+	  $filter_info = array();
+	  foreach (module_implements('filter_info') as $module) {
+	    $info = call_user_func($module . '_filter_info');
+	    if (isset($info) && is_array($info)) {
+	      foreach ($info as $filter_id => $filter) {
+	      	$filter += array(
+	      	  'process callback' => '',
+	      	  'settings callback' => '',
+	      	  'tips callback' => '',
+	      	  'cache' => TRUE,
+	      	);
+	      	$item = (object)$filter;
+	      	$item->process_callback = $filter['process callback'];
+	      	$item->settings_callback = $filter['settings callback'];
+	      	$item->tips_callback = $filter['tips callback'];
+	      	$item->module = $module;
+	        $filter_info[$filter_id] = $item;
+	      }
+	    }
+	  }
+	  drupal_alter('filter_info', $filter_info);
+	  uasort($filter_info, '_filter_list_cmp');
+	}
+  return $filter_info;
+}
+
+/**
  * Build a list of all filters.
  */
 function filter_list_all() {
-  $filters = array();
-
-  foreach (module_implements('filter') as $module) {
-    $function = $module . '_filter';
-    $list = $function('list');
-    if (isset($list) && is_array($list)) {
-      foreach ($list as $delta => $name) {
-        $filters[$module . '/' . $delta] = (object)array('module' => $module, 'delta' => $delta, 'name' => $name);
-      }
-    }
-  }
-
-  uasort($filters, '_filter_list_cmp');
-
-  return $filters;
+  return filter_build();
 }
 
 /**
@@ -357,37 +379,48 @@
 function filter_resolve_format($format) {
   return $format == FILTER_FORMAT_DEFAULT ? variable_get('filter_default_format', 1) : $format;
 }
+
+/**
+ * Check is the given format object is configured as the deafult format.
+ *
+ * @param $format
+ *   The format object.
+ * @return 
+ *   TRUE if the given format is the default format, FALSE otherwise.
+ */
+function filter_is_default_format($format) {
+	return  $format->format_id == variable_get('filter_default_format', 1);
+}
+
 /**
  * Check if text in a certain text format is allowed to be cached.
  */
-function filter_format_allowcache($format) {
+function filter_format_allowcache($format_id) {
   static $cache = array();
-  $format = filter_resolve_format($format);
-  if (!isset($cache[$format])) {
-    $cache[$format] = db_query('SELECT cache FROM {filter_format} WHERE format = :format', array(':format' => $format))->fetchField();
+  $format_id = filter_resolve_format($format_id);
+  if (!isset($cache[$format_id])) {
+    $cache[$format_id] = db_query('SELECT cache FROM {filter_format} WHERE format_id = :format_id', array(':format_id' => $format_id))->fetchField();
   }
-  return $cache[$format];
+  return $cache[$format_id];
 }
 
 /**
  * Retrieve a list of filters for a certain format.
  */
-function filter_list_format($format) {
-  static $filters = array();
-
-  if (!isset($filters[$format])) {
-    $filters[$format] = array();
-    $result = db_query("SELECT * FROM {filter} WHERE format = :format ORDER BY weight, module, delta", array(':format' => (int) $format));
+function filter_list_format($format_id) {
+  $filters = &drupal_static(__FUNCTION__);
+  $filter_info = filter_list_all();
+  
+  if (!isset($filters[$format_id])) {
+    $filters[$format_id] = array();
+    $result = db_query("SELECT filter_id, ff.weight FROM {filter_format} f INNER JOIN {filter_format_filter} ff ON f.format_id = ff.format_id WHERE f.format_id = :format_id ORDER BY ff.weight", array(':format_id' => $format_id));
     foreach ($result as $filter) {
-      $list = module_invoke($filter->module, 'filter', 'list');
-      if (isset($list) && is_array($list) && isset($list[$filter->delta])) {
-        $filter->name = $list[$filter->delta];
-        $filters[$format][$filter->module . '/' . $filter->delta] = $filter;
-      }
+      $filters[$format_id][$filter->filter_id] = $filter_info[$filter->filter_id];
+      $filters[$format_id][$filter->filter_id]->weight = $filter->weight;
     }
   }
 
-  return $filters[$format];
+  return $filters[$format_id];
 }
 
 /**
@@ -448,12 +481,16 @@
 
     // Give filters the chance to escape HTML-like data such as code or formulas.
     foreach ($filters as $filter) {
-      $text = module_invoke($filter->module, 'filter', 'prepare', $filter->delta, $format, $text, $langcode, $cache_id);
+      if (isset($filter->prepare) && drupal_function_exists($filter->prepare)) {
+        $text = call_user_func($filter->prepare, $text, $format, $langcode, $cache_id);
+      }    	
     }
 
     // Perform filtering.
     foreach ($filters as $filter) {
-      $text = module_invoke($filter->module, 'filter', 'process', $filter->delta, $format, $text, $langcode, $cache_id);
+      if (isset($filter->process_callback) && drupal_function_exists($filter->process_callback)) {
+        $text = call_user_func($filter->process_callback, $text, $format, $langcode, $cache_id);
+      }     
     }
 
     // Store in cache with a minimum expiration time of 1 day.
@@ -500,8 +537,8 @@
     '#weight' => 2,
   );
   foreach ($formats as $format) {
-    $options[$format->format] = $format->name;
-    $form['format_guidelines'][$format->format] = array(
+    $options[$format->format_id] = $format->name;
+    $form['format_guidelines'][$format->format_id] = array(
       '#markup' => theme('filter_guidelines', $format),
     );
   }
@@ -548,22 +585,22 @@
  * Helper function for fetching filter tips.
  */
 function _filter_tips($format, $long = FALSE) {
-  if ($format == -1) {
+  if (empty($format)) {
     $formats = filter_formats();
   }
   else {
-    $formats = array(db_query("SELECT * FROM {filter_format} WHERE format = :format", array(':format' => $format))->fetchObject());
+    $formats = array($format);
   }
 
   $tips = array();
 
   foreach ($formats as $format) {
-    $filters = filter_list_format($format->format);
+    $filters = filter_list_format($format->format_id);
 
     $tips[$format->name] = array();
-    foreach ($filters as $id => $filter) {
-      if ($tip = module_invoke($filter->module, 'filter_tips', $filter->delta, $format->format, $long)) {
-        $tips[$format->name][] = array('tip' => $tip, 'id' => $id);
+    foreach ($filters as $filter_id => $filter) {
+      if ($tip = module_invoke($filter->module, 'filter_tips', $filter_id, $format->format_id, $long)) {
+        $tips[$format->name][] = array('tip' => $tip, 'id' => $filter_id);
       }
     }
   }
@@ -588,7 +625,7 @@
  */
 function theme_filter_guidelines($format) {
   $name = isset($format->name) ? '<label>' . $format->name . ':</label>' : '';
-  return '<div id="filter-guidelines-' . $format->format . '" class="filter-guidelines-item">' . $name . theme('filter_tips', _filter_tips($format->format, FALSE)) . '</div>';
+  return '<div id="filter-guidelines-' . $format->format_id . '" class="filter-guidelines-item">' . $name . theme('filter_tips', _filter_tips($format, FALSE)) . '</div>';
 }
 
 /**
@@ -598,9 +635,9 @@
  */
 
 /**
- * Implement hook_filter().
+ * Implement hook_filter_info().
  *  
- * Set up a basic set of essential filters:
+ * Define a basic set of essential filters:
  * - Limit allowed HTML tags:
  *     Restricts user-supplied HTML to certain tags, and removes dangerous
  *     components in allowed tags.
@@ -613,56 +650,39 @@
  * - Escape all HTML:
  *     Converts all HTML tags into visible text.
  */
-function filter_filter($op, $delta = 0, $format = -1, $text = '') {
-  switch ($op) {
-    case 'list':
-      return array(0 => t('Limit allowed HTML tags'), 1 => t('Convert line breaks'), 2 => t('Convert URLs into links'), 3 => t('Correct broken HTML'), 4 => t('Escape all HTML'));
-
-    case 'description':
-      switch ($delta) {
-        case 0:
-          return t('Allows you to restrict the HTML tags the user can use. It will also remove harmful content such as JavaScript events, JavaScript URLs and CSS styles from those tags that are not removed.');
-        case 1:
-          return t('Converts line breaks into HTML (i.e. &lt;br&gt; and &lt;p&gt;) tags.');
-        case 2:
-          return t('Turns web and e-mail addresses into clickable links.');
-        case 3:
-          return t('Corrects faulty and chopped off HTML in postings.');
-        case 4:
-          return t('Escapes all HTML tags, so they will be visible instead of being effective.');
-        default:
-          return;
-      }
-
-    case 'process':
-      switch ($delta) {
-        case 0:
-          return _filter_html($text, $format);
-        case 1:
-          return _filter_autop($text);
-        case 2:
-          return _filter_url($text, $format);
-        case 3:
-          return _filter_htmlcorrector($text);
-        case 4:
-          return trim(check_plain($text));
-        default:
-          return $text;
-      }
-
-    case 'settings':
-      switch ($delta) {
-        case 0:
-          return _filter_html_settings($format);
-        case 2:
-          return _filter_url_settings($format);
-        default:
-          return;
-      }
-
-    default:
-      return $text;
-  }
+function filter_filter_info() {
+  $filters['filter_html'] = array(
+    'name' => t('Limit allowed HTML tags'),
+    'description' => t('Allows you to restrict the HTML tags the user can use. It will also remove harmful content such as JavaScript events, JavaScript URLs and CSS styles from those tags that are not removed.'),
+    'process callback' => '_filter_html',
+    'settings callback' => '_filter_html_settings',
+    'tips callback'  => '_filter_html_tips'
+  );
+  $filters['filter_autop'] = array(
+    'name' => t('Convert line breaks'),
+    'description' => t('Converts line breaks into HTML (i.e. &lt;br&gt; and &lt;p&gt;) tags.'),
+    'process callback' => '_filter_autop',
+    'tips callback' => '_filter_autop_tips'
+  );
+  $filters['filter_url'] = array(
+    'name' => t('Convert URLs into links'),
+    'description' => t('Turns web and e-mail addresses into clickable links.'),
+    'process callback' => '_filter_url',
+    'settings callback' => '_filter_url_settings',
+    'tips callback' => '_filter_url_tips'
+  ); 
+  $filters['filter_htmlcorrector'] = array(
+    'name' =>  t('Correct broken HTML'),
+    'description' => t('Corrects faulty and chopped off HTML in postings.'),
+    'process callback' => '_filter_htmlcorrector',
+    'tips callback' => 'filter_htmlcorrector_tips' 
+  );  
+  $filters['filter_html_escape'] = array(
+    'name' => t('Escape all HTML'),
+    'description' => t('Escapes all HTML tags, so they will be visible instead of being effective.'),
+    'process callback' => '_filter_html_escape',
+  ); 
+  return $filters;
 }
 
 /**
@@ -674,24 +694,24 @@
     '#title' => t('HTML filter'),
     '#collapsible' => TRUE,
   );
-  $form['filter_html']["allowed_html_$format"] = array(
+  $form['filter_html']["allowed_html_$format->format_id"] = array(
     '#type' => 'textfield',
     '#title' => t('Allowed HTML tags'),
-    '#default_value' => variable_get("allowed_html_$format", '<a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>'),
+    '#default_value' => variable_get("allowed_html_$format->format_id", '<a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>'),
     '#size' => 64,
     '#maxlength' => 1024,
     '#description' => t('Specify a list of tags which should not be stripped. (Note that JavaScript event attributes are always stripped.)'),
   );
-  $form['filter_html']["filter_html_help_$format"] = array(
+  $form['filter_html']["filter_html_help_$format->format_id"] = array(
     '#type' => 'checkbox',
     '#title' => t('Display HTML help'),
-    '#default_value' => variable_get("filter_html_help_$format", 1),
+    '#default_value' => variable_get("filter_html_help_$format->format_id", 1),
     '#description' => t('If enabled, Drupal will display some basic HTML help in the long filter tips.'),
   );
-  $form['filter_html']["filter_html_nofollow_$format"] = array(
+  $form['filter_html']["filter_html_nofollow_$format->format_id"] = array(
     '#type' => 'checkbox',
     '#title' => t('Spam link deterrent'),
-    '#default_value' => variable_get("filter_html_nofollow_$format", FALSE),
+    '#default_value' => variable_get("filter_html_nofollow_$format->format_id", FALSE),
     '#description' => t('If enabled, Drupal will add rel="nofollow" to all links, as a measure to reduce the effectiveness of spam links. Note: this will also prevent valid links from being followed by search engines, therefore it is likely most effective when enabled for anonymous users.'),
   );
   return $form;
@@ -720,10 +740,10 @@
     '#title' => t('URL filter'),
     '#collapsible' => TRUE,
   );
-  $form['filter_urlfilter']['filter_url_length_' . $format] = array(
+  $form['filter_urlfilter']['filter_url_length_' . $format->format_id] = array(
     '#type' => 'textfield',
     '#title' => t('Maximum link text length'),
-    '#default_value' => variable_get('filter_url_length_' . $format, 72),
+    '#default_value' => variable_get('filter_url_length_' . $format->format_id, 72),
     '#maxlength' => 4,
     '#description' => t('URLs longer than this number of characters will be truncated to prevent long strings that break formatting. The link itself will be retained; just the text portion of the link will be truncated.'),
   );
Index: modules/filter/filter.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.admin.inc,v
retrieving revision 1.30
diff -u -r1.30 filter.admin.inc
--- modules/filter/filter.admin.inc	12 Jun 2009 08:39:37 -0000	1.30
+++ modules/filter/filter.admin.inc	24 Jul 2009 23:34:27 -0000
@@ -98,7 +98,7 @@
 function filter_admin_format_page($format = NULL) {
   if (!isset($format->name)) {
     drupal_set_title(t('Add text format'), PASS_THROUGH);
-    $format = (object)array('name' => '', 'roles' => '', 'format' => '');
+    $format = (object)array('name' => '', 'roles' => '', 'format_id' => 0);
   }
   return drupal_get_form('filter_admin_format_form', $format);
 }
@@ -111,8 +111,8 @@
  * @see filter_admin_format_form_submit()
  */
 function filter_admin_format_form(&$form_state, $format) {
-  $default = ($format->format == variable_get('filter_default_format', 1));
-  if ($default) {
+	$is_default = filter_is_default_format($format);
+  if ($is_default) {
     $help = t('All roles for the default format must be enabled and cannot be changed.');
     $form['default_format'] = array('#type' => 'hidden', '#value' => 1);
   }
@@ -127,7 +127,7 @@
   // Add a row of checkboxes for form group.
   $form['roles'] = array('#type' => 'fieldset',
     '#title' => t('Roles'),
-    '#description' => $default ? $help : t('Choose which roles may use this text format. Note that roles with the "administer filters" permission can always use all text formats.'),
+    '#description' => $is_default ? $help : t('Choose which roles may use this text format. Note that roles with the "administer filters" permission can always use all text formats.'),
     '#tree' => TRUE,
   );
 
@@ -135,33 +135,33 @@
     $checked = strpos($format->roles, ",$rid,") !== FALSE;
     $form['roles'][$rid] = array('#type' => 'checkbox',
       '#title' => $name,
-      '#default_value' => ($default || $checked),
+      '#default_value' => ($is_default || $checked),
     );
-    if ($default) {
+    if ($is_default) {
       $form['roles'][$rid]['#disabled'] = TRUE;
     }
   }
   // Table with filters
   $all = filter_list_all();
-  $enabled = filter_list_format($format->format);
+  $enabled = filter_list_format($format->format_id);
 
   $form['filters'] = array('#type' => 'fieldset',
     '#title' => t('Filters'),
     '#description' => t('Choose the filters that will be used in this text format.'),
     '#tree' => TRUE,
   );
-  foreach ($all as $id => $filter) {
-    $form['filters'][$id] = array('#type' => 'checkbox',
+  foreach ($all as $filter_id => $filter) {
+    $form['filters'][$filter_id] = array('#type' => 'checkbox',
       '#title' => $filter->name,
-      '#default_value' => isset($enabled[$id]),
-      '#description' => module_invoke($filter->module, 'filter', 'description', $filter->delta),
+      '#default_value' => isset($enabled[$filter_id]),
+      '#description' => $filter->description,
     );
   }
-  if (!empty($format->format)) {
-    $form['format'] = array('#type' => 'hidden', '#value' => $format->format);
+  if (!empty($format->format_id)) {
+    $form['format_id'] = array('#type' => 'hidden', '#value' => $format->format_id);
 
     // Composition tips (guidelines)
-    $tips = _filter_tips($format->format, FALSE);
+    $tips = _filter_tips($format, FALSE);
     $tiplist = theme('filter_tips', $tips, FALSE);
     if (!$tiplist) {
       $tiplist = '<p>' . t('No guidelines available.') . '</p>';
@@ -182,9 +182,9 @@
  * Validate text format form submissions.
  */
 function filter_admin_format_form_validate($form, &$form_state) {
-  if (!isset($form_state['values']['format'])) {
+  if (!isset($form_state['values']['format_id'])) {
     $name = trim($form_state['values']['name']);
-    $result = db_query("SELECT format FROM {filter_format} WHERE name = :name", array(':name' => $name))->fetchField();
+    $result = db_query("SELECT format_id FROM {filter_format} WHERE name = :name", array(':name' => $name))->fetchField();
     if ($result) {
       form_set_error('name', t('Text format names must be unique. A format named %name already exists.', array('%name' => $name)));
     }
@@ -195,77 +195,80 @@
  * Process text format form submissions.
  */
 function filter_admin_format_form_submit($form, &$form_state) {
-  $format = isset($form_state['values']['format']) ? $form_state['values']['format'] : NULL;
-  $current = filter_list_format($format);
-  $name = trim($form_state['values']['name']);
-  $cache = TRUE;
-
-  // Add a new text format.
-  if (!$format) {
-    $new = TRUE;
-    db_insert('filter_format')
-      ->fields(array('name' => $name))
-      ->execute();
-    $format = db_query("SELECT MAX(format) AS format FROM {filter_format}")->fetchField();
-    drupal_set_message(t('Added text format %format.', array('%format' => $name)));
-  }
-  else {
-    drupal_set_message(t('The text format settings have been updated.'));
-  }
-  db_delete('filter')
-    ->condition('format', $format)
-    ->execute();
-  $query = db_insert('filter')->fields(array('format', 'module', 'delta', 'weight'));
-  foreach ($form_state['values']['filters'] as $id => $checked) {
-    if ($checked) {
-      list($module, $delta) = explode('/', $id);
-      // Add new filters to the bottom.
-      $weight = isset($current[$id]->weight) ? $current[$id]->weight : 10;
-      $query->values(array(
-        'format' => $format,
-        'module' => $module,
-        'delta'  => $delta,
-        'weight' => $weight,
-      ));
-      // Check if there are any 'no cache' filters.
-      $cache &= !module_invoke($module, 'filter', 'no cache', $delta);
-    }
-    $query->execute();
-  }
-
+  $format_id = isset($form_state['values']['format_id']) ? $form_state['values']['format_id'] : NULL;
+  $current = filter_list_format($format_id);
+  $form_state['values']['name'] = trim($form_state['values']['name']);
+  
+  $format = (object)$form_state['values'];
+  
   // We store the roles as a string for ease of use.
   // We should always set all roles to TRUE when saving a default role.
   // We use leading and trailing comma's to allow easy substring matching.
-  $roles = array();
+  $format->roles = array();
   if (isset($form_state['values']['roles'])) {
     foreach ($form_state['values']['roles'] as $id => $checked) {
       if ($checked) {
-        $roles[] = $id;
+        $format->roles[] = $id;
       }
     }
   }
   if (!empty($form_state['values']['default_format'])) {
-    $roles = ',' . implode(',', array_keys(user_roles())) . ',';
+    $format->roles = ',' . implode(',', array_keys(user_roles())) . ',';
   }
   else {
-    $roles = ',' . implode(',', $roles) . ',';
+    $format->roles = ',' . implode(',', $format->roles) . ',';
   }
 
-  db_update('filter_format')
-    ->fields(array(
-      'cache' => $cache,
-      'name'  => $name,
-      'roles' => $roles,
-    ))
-    ->condition('format', $format)
-    ->execute();
+  $filter_info = filter_list_all();
+  $format->cache = TRUE;
+  $enabled_filters = array();
+  foreach ($form_state['values']['filters'] as $filter_id => $checked) {
+    if ($checked) {
+      $filter  = $filter_info[$filter_id];       
+      // Add new filters to the bottom.
+      $filter->weight = isset($current[$filter_id]->weight) ? $current[$filter_id]->weight : 10;
+      // Check if there are any 'no cache' filters.
+      $format->cache &= empty($filter->cache) || $filter->cache; // cache by default.
+      $enabled_filters[$filter_id] = $filter;
+    }
+  }
+  
+  // Add a new text format.
+  if (!$format_id) {
+    $new = TRUE;
+    drupal_write_record('filter_format', $format);
+    
+    drupal_set_message(t('Added text format %format_name.', array('%format_name' => $format->name)));
+  }
+  else {
+	  // Remove all filters associated to the format.
+	  db_delete('filter_format_filter')
+	    ->condition('format_id', $format->format_id)
+	    ->execute();
+    drupal_write_record('filter_format', $format, 'format_id');
+   
+    drupal_set_message(t('The text format settings have been updated.'));
+  }
 
-  cache_clear_all($format . ':', 'cache_filter', TRUE);
+  $query = db_insert('filter_format_filter')->fields(array('format_id', 'module', 'filter_id', 'weight'));
+  foreach ($enabled_filters as $filter_id => $filter) {
+  	$query->values(array(
+      'format_id' => $format->format_id,
+  	  'module' => $filter->module,
+  	  'filter_id' => $filter_id,
+  	  'weight' => $filter->weight,
+  	));
+  }
+  $query->execute();
+  
+  cache_clear_all($format->format_id . ':', 'cache_filter', TRUE);
 
-  // If a new filter was added, return to the main list of filters. Otherwise, stay on edit filter page to show new changes.
+  // If a new format was added, return to the main list of formats. 
+  // Otherwise, stay on edit format page to show new changes.
   $return = 'admin/settings/formats';
   if (!empty($new)) {
-    $return .= '/' . $format;
+    $return .= '/' . $format->format_id;
+    module_invoke_all('filter_format_update', $format);
   }
   $form_state['redirect'] = $return;
   return;
@@ -277,24 +280,14 @@
  * @ingroup forms
  * @see filter_admin_delete_submit()
  */
-function filter_admin_delete() {
-  $format = arg(4);
-  $format = db_query('SELECT * FROM {filter_format} WHERE format = :format', array(':format' => $format))->fetchObject();
-
-  if ($format) {
-    if ($format->format != variable_get('filter_default_format', 1)) {
-      $form['format'] = array('#type' => 'hidden', '#value' => $format->format);
-      $form['name'] = array('#type' => 'hidden', '#value' => $format->name);
-
-      return confirm_form($form, t('Are you sure you want to delete the text format %format?', array('%format' => $format->name)), 'admin/settings/formats', t('If you have any content left in this text format, it will be switched to the default text format. This action cannot be undone.'), t('Delete'), t('Cancel'));
-    }
-    else {
-      drupal_set_message(t('The default format cannot be deleted.'));
-      drupal_goto('admin/settings/formats');
-    }
+function filter_admin_delete($form_state, $format) {
+  if (!filter_is_default_format($format)) {
+    $form['format'] = array('#type' => 'value', '#value' => $format);
+    return confirm_form($form, t('Are you sure you want to delete the text format %format?', array('%format' => $format->name)), 'admin/settings/formats', t('If you have any content left in this text format, it will be switched to the default text format. This action cannot be undone.'), t('Delete'), t('Cancel'));
   }
   else {
-    drupal_not_found();
+    drupal_set_message(t('The default format cannot be deleted.'));
+    drupal_goto('admin/settings/formats');
   }
 }
 
@@ -302,30 +295,20 @@
  * Process filter delete form submission.
  */
 function filter_admin_delete_submit($form, &$form_state) {
+	$format = $form_state['values']['format'];
+	
   db_delete('filter_format')
-    ->condition('format', $form_state['values']['format'])
-    ->execute();
-  db_delete('filter')
-    ->condition('format', $form_state['values']['format'])
+    ->condition('format_id', $format->format_id)
     ->execute();
-
-  $default = variable_get('filter_default_format', 1);
-  // Replace existing instances of the deleted format with the default format.
-  if (db_table_exists('comment')) {
-    db_update('comment')
-      ->fields(array('format' => $default))
-      ->condition('format', $form_state['values']['format'])
+    
+  db_delete('filter_format_filter')
+    ->condition('format_id', $format->format_id)
       ->execute();
-  }
-  if (db_table_exists('box')) {
-    db_update('box')
-      ->fields(array('format' => $default))
-      ->condition('format', $form_state['values']['format'])
-      ->execute();
-  }
 
-  cache_clear_all($form_state['values']['format'] . ':', 'cache_filter', TRUE);
-  drupal_set_message(t('Deleted text format %format.', array('%format' => $form_state['values']['name'])));
+  module_invoke_all('filter_format_delete', $format);
+  cache_clear_all($format->format_id . ':', 'cache_filter', TRUE);
+
+  drupal_set_message(t('Deleted text format %format_name.', array('%format_name' => $format->name)));
 
   $form_state['redirect'] = 'admin/settings/formats';
   return;
@@ -346,12 +329,14 @@
  * @ingroup forms
  */
 function filter_admin_configure(&$form_state, $format) {
-  $list = filter_list_format($format->format);
+  $filters = filter_list_format($format->format_id);
   $form = array();
-  foreach ($list as $filter) {
-    $form_module = module_invoke($filter->module, 'filter', 'settings', $filter->delta, $format->format);
-    if (isset($form_module) && is_array($form_module)) {
-      $form = array_merge($form, $form_module);
+  foreach ($filters as $filter) {
+    if (isset($filter->settings_callback) && drupal_function_exists($filter->settings_callback)) {
+      $settings_form = call_user_func($filter->settings_callback, $format);
+      if (isset($settings_form) && is_array($settings_form)) {
+        $form = array_merge($form, $settings_form);
+      }
     }
   }
 
@@ -361,7 +346,7 @@
   else {
     $form['error'] = array('#markup' => t('No settings are available.'));
   }
-  $form['format'] = array('#type' => 'hidden', '#value' => $format->format);
+  $form['format'] = array('#type' => 'value', '#value' => $format);
   $form['#submit'][] = 'filter_admin_configure_submit';
   return $form;
 }
@@ -390,14 +375,14 @@
  */
 function filter_admin_order(&$form_state, $format = NULL) {
   // Get list (with forced refresh).
-  $filters = filter_list_format($format->format);
+  $filters = filter_list_format($format->format_id);
 
   $form['weights'] = array('#tree' => TRUE);
-  foreach ($filters as $id => $filter) {
-    $form['names'][$id] = array('#markup' => $filter->name);
-    $form['weights'][$id] = array('#type' => 'weight', '#default_value' => $filter->weight);
+  foreach ($filters as $filter_id => $filter) {
+    $form['names'][$filter_id] = array('#markup' => $filter->name);
+    $form['weights'][$filter_id] = array('#type' => 'weight', '#default_value' => $filter->weight);
   }
-  $form['format'] = array('#type' => 'hidden', '#value' => $format->format);
+  $form['format'] = array('#type' => 'value', '#value' => $format);
   $form['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
 
   return $form;
@@ -434,16 +419,28 @@
  * Process filter order configuration form submission.
  */
 function filter_admin_order_submit($form, &$form_state) {
-  foreach ($form_state['values']['weights'] as $id => $weight) {
-    list($module, $delta) = explode('/', $id);
-    db_update('filter')
+	$format = $form_state['values']['format'];
+  foreach ($form_state['values']['weights'] as $filter_id => $weight) {
+    db_update('filter_format_filter')
       ->fields(array('weight' => $weight))
-      ->condition('format', $form_state['values']['format'])
-      ->condition('module', $module)
-      ->condition('delta', $delta)
+      ->condition('format_id', $format->format_id)
+      ->condition('filter_id', $filter_id)
       ->execute();
   }
   drupal_set_message(t('The filter ordering has been saved.'));
 
-  cache_clear_all($form_state['values']['format'] . ':', 'cache_filter', TRUE);
+  module_invoke_all('filter_format_update', $format);
+  cache_clear_all($format->format_id . ':', 'cache_filter', TRUE);
 }
+
+/**
+ * Implement hook_modules_uninstalled().
+ */
+function filter_modules_uninstalled($modules) {
+	// Remove filters from unistalled modules.
+  foreach ($modules as $module) {
+    db_delete('filter_format_filter')
+      ->condition('module', $module)
+      ->execute();
+  }
+}
\ No newline at end of file
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.356
diff -u -r1.356 system.install
--- modules/system/system.install	21 Jul 2009 07:27:00 -0000	1.356
+++ modules/system/system.install	24 Jul 2009 23:34:57 -0000
@@ -435,14 +435,14 @@
     ->execute();
 
   // Add text formats.
-  $filtered_html_format = db_insert('filter_format')
+  $filtered_html_format_id = db_insert('filter_format')
     ->fields(array(
       'name' => 'Filtered HTML',
       'roles' => ',' . DRUPAL_ANONYMOUS_RID . ',' . DRUPAL_AUTHENTICATED_RID . ',',
       'cache' => 1,
     ))
     ->execute();
-  $full_html_format = db_insert('filter_format')
+  $full_html_format_id = db_insert('filter_format')
     ->fields(array(
       'name' => 'Full HTML',
       'roles' => '',
@@ -453,62 +453,62 @@
   // Enable filters for each text format.
 
   // Filtered HTML:
-  db_insert('filter')
-    ->fields(array('format', 'module', 'delta', 'weight'))
+  db_insert('filter_format_filter')
+    ->fields(array('format_id', 'module', 'filter_id', 'weight'))
     // URL filter.
     ->values(array(
-      'format' => $filtered_html_format,
+      'format_id' => $filtered_html_format_id,
       'module' => 'filter',
-      'delta' => 2,
+      'filter_id' => 'filter_url',
       'weight' => 0,
     ))
     // HTML filter.
     ->values(array(
-      'format' => $filtered_html_format,
+      'format_id' => $filtered_html_format_id,
       'module' => 'filter',
-      'delta' => 0,
+      'filter_id' => 'filter_html',
       'weight' => 1,
     ))
     // Line break filter.
     ->values(array(
-      'format' => $filtered_html_format,
+      'format_id' => $filtered_html_format_id,
       'module' => 'filter',
-      'delta' => 1,
+      'filter_id' => 'filter_autop',
       'weight' => 2,
     ))
     // HTML corrector filter.
     ->values(array(
-      'format' => $filtered_html_format,
+      'format_id' => $filtered_html_format_id,
       'module' => 'filter',
-      'delta' => 3,
+      'filter_id' => 'filter_htmlcorrector',
       'weight' => 10,
     ))
   // Full HTML:
     // URL filter.
     ->values(array(
-      'format' => $full_html_format,
+      'format_id' => $full_html_format_id,
       'module' => 'filter',
-      'delta' => 2,
+      'filter_id' => 'filter_url',
       'weight' => 0,
     ))
     // Line break filter.
     ->values(array(
-      'format' => $full_html_format,
+      'format_id' => $full_html_format_id,
       'module' => 'filter',
-      'delta' => 1,
+      'filter_id' => 'filter_autop',
       'weight' => 1,
     ))
     // HTML corrector filter.
     ->values(array(
-      'format' => $full_html_format,
+      'format_id' => $full_html_format_id,
       'module' => 'filter',
-      'delta' => 3,
+      'filter_id' => 'filter_htmlcorrector',
       'weight' => 10,
     ))
     ->execute();
 
   // Set the default input format to Filtered HTML.
-  variable_set('filter_default_format', $filtered_html_format);
+  variable_set('filter_default_format', $filtered_html_format_id);
 
   variable_set('node_options_forum', array(0 => 'status'));
 
