From e47063b1bcd9ca67f9905278b4fe5fd2764cfbc3 Mon Sep 17 00:00:00 2001
From: Sascha Grossenbacher <saschagros@gmail.com>
Date: Mon, 18 Apr 2011 18:07:32 +0200
Subject: [PATCH] Issue #1022404 by Berdir, te-brian: Added drag and drop sorting for list display fields and replaced header theme functions with a hook.

---
 privatemsg.admin.inc                       |   36 ++++-
 privatemsg.api.php                         |   47 +++++++
 privatemsg.install                         |    1 +
 privatemsg.module                          |  191 ++++++++++++++++++++-------
 privatemsg.pages.inc                       |    7 +-
 privatemsg.theme.inc                       |  197 ++++++++-------------------
 privatemsg_filter/privatemsg_filter.module |   24 ++--
 7 files changed, 289 insertions(+), 214 deletions(-)

diff --git a/privatemsg.admin.inc b/privatemsg.admin.inc
index 3a6ef68..34f10d9 100644
--- a/privatemsg.admin.inc
+++ b/privatemsg.admin.inc
@@ -111,18 +111,38 @@ function privatemsg_admin_settings() {
     '#description' => t('Choose the number of conversations that should be listed per page.'),
   );
 
-  $form['privatemsg_listing']['privatemsg_display_fields'] = array(
-    '#type' => 'checkboxes',
+  $form['privatemsg_listing']['privatemsg_fields'] = array(
+    '#type' => 'fieldset',
     '#title' => t('Configure fields'),
-    '#description' => t('Select which columns/fields should be displayed in the message listings. Subject and Last updated cannot be disabled.'),
-    '#options' => array(
-      'participants'    => t('Participants'),
-      'thread_started'  => t('Started'),
-      'count'           => t('Messages'),
+    '#description' => t('Select which columns/fields should be displayed in the message listings.'),
+    '#collapsible' => FALSE,
+    '#theme' => 'privatemsg_admin_settings_display_fields',
+    'privatemsg_display_fields' => array(
+      '#tree' => TRUE,
+    ),
+    'privatemsg_display_fields_weights' => array(
+      '#tree' => TRUE,
     ),
-    '#default_value' => variable_get('privatemsg_display_fields', array('participants')),
   );
 
+  foreach (privatemsg_get_headers() as $key => $header) {
+    $form['privatemsg_listing']['privatemsg_fields']['privatemsg_display_fields'][$key] = array(
+      '#type' => 'checkbox',
+      '#title' => $header['#title'],
+      '#return_value' => $key,
+      '#default_value' => $header['#enabled'],
+      '#disabled' => $header['#locked'],
+      '#weight' => $header['#weight'],
+    );
+
+    $form['privatemsg_listing']['privatemsg_fields']['privatemsg_display_fields_weights'][$key] = array(
+      '#type' => 'weight',
+      '#title' => t('!field weight', array('!field' => $header['#title'])),
+      '#default_value' => $header['#weight'],
+      '#delta' => 20,
+    );
+  }
+
   $amounts = drupal_map_assoc(array(5, 10, 20, 30, 50, 70, 90, 150, 200, 250, 300));
   $form['privatemsg_listing']['privatemsg_view_max_amount'] = array(
     '#type'          => 'select',
diff --git a/privatemsg.api.php b/privatemsg.api.php
index 72461c7..a7f26af 100644
--- a/privatemsg.api.php
+++ b/privatemsg.api.php
@@ -577,3 +577,50 @@ function hook_privatemsg_operation_executed($operation, $threads, $account = NUL
 /**
  * @}
  */
+
+/**
+ * Declare headers for message listings.
+ *
+ * @return
+ *   An array keyed by an identifier. All header definition keys for theme_table
+ *   and tablesortort_sql() and the following additional keys:
+ *     - #enabled: TRUE if the header should be enabled by default. FALSE by
+ *                 default.
+ *     - #locked: TRUE if it the header should be locked and can not be
+ *                enabled or disabled in the user interface.
+ *     - #weight: The default weight which can be changed in the user interface.
+ *     - #title: A title used in the administrative user interface. Defaults to
+ *               data.
+ *     - #access: Control if the header is accessible, TRUE or FALSE.
+ *     - #theme: Optionally define a theme function for the field. Defaults to
+ *               'privatemsg_list_field_$key'.
+ *
+ * @see theme_table()
+ * @ingroup theming
+ */
+function hook_privatemsg_header_info() {
+  return array(
+    'subject' => array(
+      'data'    => t('Subject'),
+      'field'   => 'subject',
+      'class'   => 'privatemsg-header-subject',
+      '#enabled' => TRUE,
+      '#locked'  => TRUE,
+      '#weight'  => -20,
+    ),
+  );
+}
+
+/**
+ * Alter the defined header structure.
+ *
+ * @param $headers
+ *   All headers returned by hook_privatemsg_header_info().
+ *
+ *
+ * @see hook_privatemsg_header_info()
+ * @ingroup theming
+ */
+function hook_privatemsg_header_info_alter(&$headers) {
+
+}
diff --git a/privatemsg.install b/privatemsg.install
index 7754c88..ed83c20 100644
--- a/privatemsg.install
+++ b/privatemsg.install
@@ -146,6 +146,7 @@ function privatemsg_uninstall() {
   variable_del('privatemsg_per_page');
   variable_del('privatemsg_display_loginmessage');
   variable_del('privatemsg_display_fields');
+  variable_del('privatemsg_display_fields_weights');
   variable_del('privatemsg_display_link_self');
   variable_del('privatemsg_view_default_amount');
   variable_del('privatemsg_view_max_amount');
diff --git a/privatemsg.module b/privatemsg.module
index 9c591dc..edcb822 100644
--- a/privatemsg.module
+++ b/privatemsg.module
@@ -656,14 +656,8 @@ function privatemsg_theme() {
       'variables'        => array('recipients' => NULL),
       'template'         => 'privatemsg-between',
     ),
-    // Define pattern for header/field templates. The theme system will register all
+    // Define pattern for field templates. The theme system will register all
     // theme functions that start with the defined pattern.
-    'privatemsg_list_header'  => array(
-      'file'                  => 'privatemsg.theme.inc',
-      'path'                  => drupal_get_path('module', 'privatemsg'),
-      'pattern'               => 'privatemsg_list_header__',
-      'variables'             => array(),
-    ),
     'privatemsg_list_field'   => array(
       'file'                  => 'privatemsg.theme.inc',
       'path'                  => drupal_get_path('module', 'privatemsg'),
@@ -680,6 +674,12 @@ function privatemsg_theme() {
       'path'                  => drupal_get_path('module', 'privatemsg'),
       'variables'             => array('recipient' => NULL, 'options' => array()),
     ),
+    // Admin settings theme callbacks.
+    'privatemsg_admin_settings_display_fields' => array(
+      'file'                  => 'privatemsg.theme.inc',
+      'path'                  => drupal_get_path('module', 'privatemsg'),
+      'render element'        => 'element',
+    ),
   );
   // Include the theme file to load the theme suggestions.
   module_load_include('inc', 'privatemsg', 'privatemsg.theme');
@@ -1006,7 +1006,7 @@ function privatemsg_sql_list($account, $argument = 'list') {
   $query->addExpression('SUM(pmi.is_new)', 'is_new');
 
   // Load enabled columns
-  $fields = array_filter(variable_get('privatemsg_display_fields', array('participants')));
+  $fields = privatemsg_get_enabled_headers();
 
   if (in_array('count', $fields)) {
     // We only want the distinct number of messages in this thread.
@@ -1033,7 +1033,7 @@ function privatemsg_sql_list($account, $argument = 'list') {
     ->condition('pmi.type', array('hidden', 'user'))
     ->condition('pmi.deleted', 0)
     ->groupBy('pmi.thread_id')
-    ->orderByHeader(_privatemsg_list_headers(array_merge(array('subject', 'last_updated'), $fields)))
+    ->orderByHeader(privatemsg_get_headers())
     ->limit(variable_get('privatemsg_per_page', 25));
 }
 
@@ -2043,40 +2043,6 @@ function privatemsg_thread_change_status($threads, $status, $account = NULL) {
     drupal_set_message(format_plural(count($threads), 'Marked 1 thread as read.', 'Marked @count threads as read.'));
   }
 }
-/**
- * Returns a table header definition based on the submitted keys.
- *
- * Uses @link theming theme patterns @endlink to theme single headers.
- *
- * @param $has_posts
- *   TRUE when there is at least one row. Decides if the select all checkbox should be displayed.
- * @param $keys
- *   Array with the keys which are present in the query/should be displayed.
- * @return
- *   Array with header defintions for tablesort_sql and theme('table').
- */
-function _privatemsg_list_headers($keys) {
-
-  // theme() doesn't include the theme file for patterns, we need to do it manually.
-  include_once drupal_get_path('module', 'privatemsg') . '/privatemsg.theme.inc';
-
-  $header = array();
-  foreach ($keys as $key) {
-    // First, try to load a specific theme for that header, if not present, use the default.
-    if ($return = theme('privatemsg_list_header__' . $key)) {
-      // The default theme returns nothing, only store the value if we have something.
-      $header[$key] = $return;
-    }
-  }
-  uasort($header, 'element_sort');
-  // Remove weight column or it will show up in the markup.
-  foreach ($header as $key => $element) {
-    if (isset($header[$key]['#weight'])) {
-      unset($header[$key]['#weight']);
-    }
-  }
-  return $header;
-}
 
 /**
  * Formats all rows (#options) in the privatemsg tableselect thread list.
@@ -2089,18 +2055,23 @@ function _privatemsg_list_headers($keys) {
  *   Row definition for use with theme('table')
  */
 function _privatemsg_list_thread($tableselect) {
+  $enabled_headers = privatemsg_get_enabled_headers();
+  $headers = privatemsg_get_headers();
+
+  // theme() doesn't include the theme file for patterns, we need to do it
+  // manually.
+  include_once drupal_get_path('module', 'privatemsg') . '/privatemsg.theme.inc';
+
   foreach ($tableselect['#options'] as $id => $thread) {
     $row = array();
     if (!empty($thread['is_new'])) {
       // Set the css class in the tr tag.
       $row['#attributes']['class'][] = 'privatemsg-unread';
     }
-    foreach ($thread as $key => $data) {
-      // First, try to load a specific theme for that field, if not present, use the default.
-      if ($return = theme('privatemsg_list_field__' . $key, array('thread' => $thread))) {
-        // The default theme returns nothing, only store the value if we have something.
-        $row[$key] = $return;
-      }
+
+    foreach ($enabled_headers as $key) {
+      // Theme each enabled field.
+      $row[$key] = theme($headers[$key]['#theme'], array('thread' => $thread));
     }
     $tableselect['#options'][$id] = $row;
   }
@@ -2409,6 +2380,7 @@ function privatemsg_recipient_get_types() {
   }
   return $types;
 }
+
 /**
  * Return a single recipient type information.
  * @param $type
@@ -3092,3 +3064,124 @@ function privatemsg_format_date($timestamp) {
   return format_date($timestamp, 'privatemsg_years');
 
 }
+
+/**
+ * Returns an array of defined column headers for message listings.
+ *
+ * @param $visible_only
+ *   Disabled and denied headers and properties starting with # are removed.
+ *
+ * @return
+ *   Array of headers.
+ *
+ * @see hook_privatemsg_header_info()
+ *
+ * @ingroup theming
+ */
+function privatemsg_get_headers($visible_only = FALSE) {
+  $headers = drupal_static(__FUNCTION__, NULL);
+
+  if ($headers === NULL) {
+    $headers = module_invoke_all('privatemsg_header_info');
+    if (!is_array($headers)) {
+      $headers = array();
+    }
+
+    $weights = variable_get('privatemsg_display_fields_weights', array());
+    $enabled = variable_get('privatemsg_display_fields', array('subject', 'participants', 'last_updated'));
+
+    // Apply defaults and configurations.
+    foreach ($headers as $key => &$header) {
+      // Apply defaults.
+      $header += array(
+        '#enabled' => FALSE,
+        '#weight' => 0,
+        '#title' => $header['data'],
+        '#access' => TRUE,
+        '#locked' => FALSE,
+        '#theme' => 'privatemsg_list_field__' . $key,
+      );
+      if (empty($header['#locked']) && isset($enabled[$key])) {
+        $header['#enabled'] = (bool)$enabled[$key];
+      }
+      if (isset($weights[$key])) {
+        $header['#weight'] =  $weights[$key];
+      }
+    }
+
+    drupal_alter('privatemsg_header_info', $headers);
+    uasort($headers, 'element_sort');
+  }
+  if ($visible_only) {
+    // Remove all attributes prefixed with a # and disabled headers.
+    $headers_visible = $headers;
+    foreach ($headers_visible as $header_key => &$header) {
+      if (!$header['#enabled'] || !$header['#access']) {
+        unset($headers_visible[$header_key]);
+      }
+      else {
+        foreach ($header as $key => $value) {
+          if ($key[0] == '#') {
+            unset($header[$key]);
+          }
+        }
+      }
+    }
+    return $headers_visible;
+  }
+  else {
+    return $headers;
+  }
+}
+
+/**
+ * Returns an array of enabled header keys.
+ *
+ * @return
+ *   A indexed array with the header keys as value, ordered by their weight.
+ */
+function privatemsg_get_enabled_headers() {
+  return array_keys(privatemsg_get_headers(TRUE));
+}
+
+/**
+ * Implements hook_privatemsg_header_info().
+ */
+function privatemsg_privatemsg_header_info() {
+  return array(
+    'subject' => array(
+      'data'    => t('Subject'),
+      'field'   => 'subject',
+      'class'   => array('privatemsg-header-subject'),
+      '#enabled' => TRUE,
+      '#locked'  => TRUE,
+      '#weight'  => -20,
+    ),
+    'count' => array(
+      'data'    => t('Messages'),
+      'class'   => array('privatemsg-header-count'),
+      '#weight'  => -5,
+    ),
+    'participants' => array(
+      'data'    => t('Participants'),
+      'class'   => array('privatemsg-header-participants'),
+      '#weight'  => -15,
+      '#enabled' => TRUE,
+    ),
+    'last_updated' => array(
+      'data'    => t('Last Updated'),
+      'field'   => 'last_updated',
+      'sort'    => 'desc',
+      'class'   => array('privatemsg-header-lastupdated'),
+      '#enabled' => TRUE,
+      '#locked'  => TRUE,
+      '#weight'  => 20,
+    ),
+    'thread_started' => array(
+      'data'    => t('Started'),
+      'field'   => 'thread_started',
+      'class'   => array('privatemsg-header-threadstarted'),
+      '#weight'  => -10,
+    ),
+  );
+}
diff --git a/privatemsg.pages.inc b/privatemsg.pages.inc
index 882ce9a..d637bbe 100644
--- a/privatemsg.pages.inc
+++ b/privatemsg.pages.inc
@@ -167,11 +167,8 @@ function privatemsg_list($form, &$form_state, $argument, $account) {
     $_GET['q'] = $q;
   }
 
-  // Load the table columns.
-  $columns = array_merge(array('subject', 'last_updated'), array_filter(variable_get('privatemsg_display_fields', array('participants'))));
-
   // Load the themed list headers based on the available data.
-  $headers = _privatemsg_list_headers($columns);
+  $headers = privatemsg_get_headers(TRUE);
 
   $form = array(
     '#list_argument' => $argument,
@@ -302,7 +299,7 @@ function privatemsg_new($form, &$form_state, $recipients = '', $subject = '') {
   }
 
   if (!empty($recipients_title)) {
-    drupal_set_title(t('Write new message to %recipient', array('%recipient' => $recipients_title)));
+    drupal_set_title(t('Write new message to %recipient', array('%recipient' => $recipients_title)), PASS_THROUGH);
   }
   else {
     drupal_set_title(t('Write new message'));
diff --git a/privatemsg.theme.inc b/privatemsg.theme.inc
index 6841b76..33706ef 100644
--- a/privatemsg.theme.inc
+++ b/privatemsg.theme.inc
@@ -8,45 +8,33 @@
 /**
  * @defgroup theming Theming documentation
  *
- * It is possible to theme every aspect of privatemsg with theme functions.
+ * It is possible to theme many aspect of privatemsg with theme functions.
  *
  * For the thread list, so called theme patterns are used to allow flexible
  * theming of the table and its columns (including columns added by other
  * modules).
  *
- * Three requirements have to be fulfilled so a new column, with data, is
- * displayed in the private message list:
- *  - A field needs to be returned by the list query, see @link sql Query Builder @endlink.
- *  - A header theme pattern needs to exist for the field.
- *  - A field theme pattern needs to exist for the field.
+ * Columns are defined with hook_privatemsg_header_info(). The default weight
+ * and if they are enabled or not can by set by default but can be overriden in
+ * the admin user interface.
  *
- * For each field in the query, Privatemsg will try to call a theme pattern for
- * the header. That theme function can return a table header definition and
- * has the following structure: theme_privatemsg_list_header_fieldname.
- * @see theme_privatemsg_list_header()
+ * Additionally, a theme function needs to be defined that defaults to the name
+ * 'privatemsg_list_field__$key', where $key is the name of the header/column.
  *
- * Privatemsg will then do the same for each row, with the field theme pattern.
- * That theme function should return a table field compatible structure, either
- * just a string or an array. The theme function has to have the following
- * name: theme_privatemsg_list_field_fieldname.
- * @see theme_privatemsg_list_field()
+ * Every theme function will receive the $thread array as single argument, which
+ * is everything that has been returned by the query built in
+ * privatemsg_sql_list(). The theme function should return either a string or a
+ * theme_table() compatible array.
  *
- * To override an already existing theme function, use the following structure:
- * themename_privatemsg_list_field_fieldname. It is not necessary to
- * overwrite the header theme function unless that information needs to be
- * changed too.
- *
- * Modules can use the hook_form_alter() hook to alter the data. The form with
- * id "privatemsg_list" will contain the header, raw and themed field data in
- * the following form:
- * @code
- * $form['#headers']['field_name'] = $header // Array with the header defintion;
- * $form['#data']['thread_id'] = $data // Raw data of that thread
- * $form['#rows']['thread_id'] = $row // Themed fields of that thread
- * @endcode
+ * To change what information is available in that array, it is possible to
+ * either implement hook_privatemsg_sql_list_alter() or alter $form['#data'] of
+ * privatemsg_list(). See privatemsg_filter_form_privatemsg_list_alter() for an
+ * example.
  *
- * Note that the information in #data can be used to populate #rows, but it will
- * not be used by the default theme function theme_privatemsg_list().
+ * To override an already existing theme function, use the following structure:
+ * themename_privatemsg_list_field_fieldname. It is possible to change the
+ * header definition with hook_privatemsg_header_info_alter() but that is often
+ * not necessary.
  *
  */
 
@@ -56,24 +44,7 @@
  */
 
 /**
- * Default theme function for field theme.
- *
- * To hide all fields that don't have an explicit theme pattern defined, this
- * theme doesn't return anything.
- *
- * @param $thread
- *   Thread row returned by the list query.
- *
- * @return
- *   A theme_table() compatible field definition.
- */
-function theme_privatemsg_list_field($thread) {
-}
-
-/**
  * Theme the participants field.
- *
- * @see theme_privatemsg_list_field()
  */
 function theme_privatemsg_list_field__participants($variables) {
   $thread = $variables['thread'];
@@ -86,8 +57,6 @@ function theme_privatemsg_list_field__participants($variables) {
 
 /**
  * Theme the subject of the thread.
- *
- * @see theme_privatemsg_list_field()
  */
 function theme_privatemsg_list_field__subject($variables) {
   $thread = $variables['thread'];
@@ -110,8 +79,6 @@ function theme_privatemsg_list_field__subject($variables) {
 
 /**
  * Theme the replies field.
- *
- * @see theme_privatemsg_list_field()
  */
 function theme_privatemsg_list_field__count($variables) {
   $thread = $variables['thread'];
@@ -128,8 +95,6 @@ function theme_privatemsg_list_field__count($variables) {
 
 /**
  * Theme the last updated column.
- *
- * @see theme_privatemsg_list_field()
  */
 function theme_privatemsg_list_field__last_updated($variables) {
   $thread = $variables['thread'];
@@ -140,8 +105,6 @@ function theme_privatemsg_list_field__last_updated($variables) {
 
 /**
  * Theme the thread started column.
- *
- * @see theme_privatemsg_list_field()
  */
 function theme_privatemsg_list_field__thread_started($variables) {
   $thread = $variables['thread'];
@@ -152,89 +115,6 @@ function theme_privatemsg_list_field__thread_started($variables) {
 }
 
 /**
- * Define the table header for a specific column.
- *
- * This default theme function is used to ignore columns that should not be
- * displayed. Only columns with a specific theme pattern function are displayed.
- *
- * @return
- *   A theme_table() compatible table header definition. Additionally, the key
- *   "key" should be used to specify which row column should be displayed in
- *   this column.
- */
-function theme_privatemsg_list_header() {
-}
-
-/**
- * Define the subject header.
- *
- * @see theme_privatemsg_list_header()
- */
-function theme_privatemsg_list_header__subject() {
-  return array(
-    'data'    => t('Subject'),
-    'field'   => 'subject',
-    'class'   => array('privatemsg-header-subject'),
-    '#weight' => -40,
-  );
-}
-
-/**
- * Define the answers column.
- *
- * @see theme_privatemsg_list_header()
- */
-function theme_privatemsg_list_header__count() {
-  return array(
-    'data'    => t('Messages'),
-    'class'   => array('privatemsg-header-count'),
-    '#weight' => -25,
-  );
-}
-
-/**
- * Define the participants column.
- *
- * @see theme_privatemsg_list_header()
- */
-function theme_privatemsg_list_header__participants() {
-  return array(
-    'data'    => t('Participants'),
-    'class'   => array('privatemsg-header-participants'),
-    '#weight' => -30,
-  );
-}
-
-/**
- * Define the last updated column.
- *
- * @see theme_privatemsg_list_header()
- */
-function theme_privatemsg_list_header__last_updated() {
-  return array(
-    'data'    => t('Last Updated'),
-    'field'   => 'last_updated',
-    'sort'    => 'desc',
-    'class'   => array('privatemsg-header-lastupdated'),
-    '#weight' => -20,
-  );
-}
-
-/**
- * Define the thread started column.
- *
- * @see theme_privatemsg_list_header()
- */
-function theme_privatemsg_list_header__thread_started() {
-  return array(
-    'data'    => t('Started'),
-    'field'   => 'thread_started',
-    'class'   => array('privatemsg-header-threadstarted'),
-    '#weight' => -15,
-  );
-}
-
-/**
  * Theme a block which displays the number of new messages a user has.
  */
 function theme_privatemsg_new_block($count) {
@@ -274,5 +154,46 @@ function theme_privatemsg_username($variables) {
 }
 
 /**
+ * Output the admin settings display fields and weight settings as a
+ * drag and drop sortable table.
+ */
+function theme_privatemsg_admin_settings_display_fields($variables) {
+  $element = $variables['element'];
+  $header = array(
+    array('data' => t('Field'), 'class' => array('field')),
+    array('data' => t('Enable'), 'class' => array('enable')),
+    array('data' => t('Weight'), 'class' => array('weight')),
+  );
+  $rows = array();
+  foreach (element_children($element['privatemsg_display_fields']) as $child) {
+    $row = array();
+
+    // Title.
+    $row[] = array('data' => $element['privatemsg_display_fields'][$child]['#title'], 'class' => array('field'));
+    unset($element['privatemsg_display_fields'][$child]['#title']);
+
+    // Enable checkbox.
+    $row[] = array('data' => drupal_render($element['privatemsg_display_fields'][$child]), 'class' => array('enable'));
+
+    // Weight selector.
+    unset($element['privatemsg_display_fields_weights'][$child]['#title']);
+    $element['privatemsg_display_fields_weights'][$child]['#attributes']['class'] = array('privatemsg-display-fields-weight');
+    $row[] = array(
+      'data' => drupal_render($element['privatemsg_display_fields_weights'][$child]),
+      'class' => array('weight'),
+    );
+
+    $rows[] = array('data' => $row, 'class' => array('draggable'));
+  }
+  if (!empty($rows)) {
+    drupal_add_tabledrag('privatemsg-list-display-fields', 'order', 'sibling', 'privatemsg-display-fields-weight');
+    return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'privatemsg-list-display-fields'))) . drupal_render_children($element);
+  }
+  else {
+    return drupal_render_children($element);
+  }
+}
+
+/**
  * @}
  */
diff --git a/privatemsg_filter/privatemsg_filter.module b/privatemsg_filter/privatemsg_filter.module
index 0c7455d..9b30339 100644
--- a/privatemsg_filter/privatemsg_filter.module
+++ b/privatemsg_filter/privatemsg_filter.module
@@ -157,9 +157,6 @@ function privatemsg_filter_form_privatemsg_admin_settings_alter(&$form, $form_st
     '#default_value' => variable_get('privatemsg_filter_searchbody', FALSE),
   );
 
-  // Add tags to the list of possible columns.
-  $form['privatemsg_listing']['privatemsg_display_fields']['#options']['tags'] = t('Tags');
-
   $form['#submit'][] = 'privatemsg_filter_settings_submit';
 }
 
@@ -507,7 +504,7 @@ function privatemsg_filter_form_privatemsg_list_alter(&$form, $form_state) {
     $form += privatemsg_filter_dropdown($form_state, $form['account']['#value']);
   }
 
-  $fields = array_filter(variable_get('privatemsg_display_fields', array('participants')));
+  $fields = privatemsg_get_enabled_headers();
   if (privatemsg_user_access('tag private messages') && in_array('tags', $fields) && !empty($form['updated']['list']['#options'])) {
     // Load thread id's of the current list.
     $threads = array_keys($form['updated']['list']['#options']);
@@ -595,18 +592,17 @@ function privatemsg_filter_privatemsg_thread_operations($type) {
 }
 
 /**
- * Define the header for the tags column.
- *
- * @see theme_privatemsg_list_header()
+ * Implements hook_privatemsg_header_info().
  */
-function theme_privatemsg_list_header__tags() {
-  if (privatemsg_user_access('tag private messages')) {
-    return array(
+function privatemsg_filter_privatemsg_header_info() {
+  return array(
+    'tags' => array(
       'data' => t('Tags'),
-      'class' => 'privatemsg-header-tags',
-      '#weight' => -42,
-    );
-  }
+      'class' => array('privatemsg-header-tags'),
+      '#weight' => -23,
+      '#access' => privatemsg_user_access('tag private messages'),
+    ),
+  );
 }
 
 
-- 
1.7.4.1

