--- ../../drupal/modules/system/system.module	2006-08-04 08:10:31.000000000 +0200
+++ system.module	2006-08-03 11:30:42.000000000 +0200
@@ -176,7 +176,21 @@
       'description' => t('Enable or disable add-on modules for your site.'),
       'weight' => -10,
       'callback' => 'system_modules',
+      'callback arguments' => array('enabled'),
       'access' => $access);
+    $items[] = array('path' => 'admin/settings/modules/enabled', 
+      'title' => t('enabled'),
+      'callback' => 'system_modules', 
+      'callback arguments' => array('enabled'), 
+      'access' => $access, 
+      'type' => MENU_DEFAULT_LOCAL_TASK, 
+      'weight' => -10);
+    $items[] = array('path' => 'admin/settings/modules/disabled',
+      'title' => t('disabled'),
+      'callback' => 'system_modules', 
+      'callback arguments' => array('disabled'), 
+      'access' => $access, 
+      'type' => MENU_LOCAL_TASK);
 
     // Settings:
     $items[] = array(
@@ -1150,112 +1164,385 @@
 }
 
 /**
+ * Parse drupal meta file format.
+ *
+ * @param $filename 
+ *   The path to the filename
+ * @return 
+ *   The meta data array
+ */
+function system_parse_meta_file($filename) {
+  $handle = fopen($filename, "r");
+  $meta = fread($handle, filesize($filename));
+  fclose($handle);
+  $metadata = array();    
+  $pattern = '@^\s*((?:[^:/]|/(?!/))+?)\s*:\s*(?:("(?:[^"]|(?<=\\\\)")*")|(\'(?:[^\']|(?<=\\\\)\')*\')|([^\n]*?))\s*($|//)@ms';    
+  if (preg_match_all($pattern, $meta, $matches, PREG_SET_ORDER)) {
+    foreach ($matches as $match) {
+      list(, $key, $value1, $value2, $value3) = $match;
+      $value = stripslashes(trim($value1, '"')) . stripslashes(trim($value2, "'")) . $value3;
+      $metadata[$key] = $value;
+    }
+  } 
+  return $metadata;
+}
+
+/**
+ * Load the metadata associated with a module.
+ *
+ * @param $module
+ *   The name of the module
+ * @param $path
+ *   The path the module lives in, not including the module name.
+ */
+function system_get_meta_info($module, $path) {
+  $filename = $path .'/'. $module .'.meta';
+  $metadata = array();
+
+  if (file_exists($filename)) {
+    $metadata = system_parse_meta_file($filename);
+  }
+  if (!$metadata['package']) {
+    $metadata['package'] = t('uncategorized');
+  }
+  if (!$metadata['version']) {
+    $metadata['version'] = t('unknown');
+  }
+  if (!$metadata['drupal']) {
+    $metadata['drupal'] = t('undefined');
+  }
+  if (!$metadata['name']) {
+    $metadata['name'] = $module;
+  }
+  if (!$metadata['links']) {
+    $metadata['links'] = array();
+  }
+  else {
+    $metadata['links'] = explode(",", $metadata['links']);
+    $links = array();
+    foreach ($metadata['links'] as $link) {
+      list($link, $destination) = explode("=", $link,2);
+      $links[] = array('title' => trim($link), 'href' => trim($destination));
+    }
+    $metadata['links'] = $links;
+  }
+  if ($metadata['dependencies']) {
+    $metadata['dependencies'] = explode(',', $metadata['dependencies']);
+  }
+  else {
+    $metadata['dependencies'] = array();
+  }
+  return $metadata;
+}
+
+/**
+ * Helper function to reduce code. Provides a form that is a button or two
+ * keyed to the module.
+ */
+function system_module_form($module, $metadata, $type, $type2 = NULL) {
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => $type,
+    '#attributes' => array('class' => 'modules-button')
+  );
+  
+  $form['metadata'] = array(
+    '#type' => 'value',
+    '#value' => $metadata,
+    '#attributes' => array('class' => 'modules-button')
+  );
+  
+  if ($type2) {
+    $form['submit2'] = array(
+      '#type' => 'submit',
+      '#value' => $type2,
+      '#attributes' => array('class' => 'modules-button')
+    );
+  }
+  return drupal_get_form("system_module_form_$module", $form, 'system_module_form');
+}
+
+/**
  * Menu callback; displays a listing of all modules.
  */
-function system_modules() {
+function system_modules($type) {
   // Get current list of modules
   $files = module_rebuild_cache();
+  // Extract current files from database.
+  system_get_files_database($files, 'module');
 
-  foreach ($files as $filename => $file) {
-    drupal_get_filename('module', $file->name, $file->filename);
-    drupal_load('module', $file->name);
+  ksort($files);
 
-    $file->description = module_invoke($file->name, 'help', 'admin/settings/modules#description');
+  $required = array('block', 'filter', 'node', 'system', 'user', 'watchdog');
+  foreach ($files as $filename => $file) {
+    $metadata = system_get_meta_info($file->name, dirname($file->filename));
+    if (($type == 'enabled' && $file->status) || ($type == 'disabled' && !$file->status)) {
+      $packages[$metadata['package']][] = $file->name;
+      $options[$file->name] = '';
+    }
+    $file->description = $metadata['description'];
 
-    $form['name'][$file->name] = array('#value' => $file->name);
-    $form['description'][$file->name] = array('#value' => $file->description);
-    $options[$file->name] = '';
+    // for later dependency checking.
     if ($file->status) {
-      $status[] = $file->name;
+      $metadata['enabled'] = true;
     }
-    if ($file->throttle) {
-      $throttle[] = $file->name;
+    else if ($file->schema_version != -1) {
+      $metadata['uninstalled'] = true;
     }
+    $metadata['filename'] = $file->filename;
+    $modules[$filename] = $metadata;
   }
-
-  // Handle status checkboxes, including overriding the generated
-  // checkboxes for required modules.
-  $form['status'] = array('#type' => 'checkboxes', '#default_value' => $status, '#options' => $options);
-  $required = array('block', 'filter', 'node', 'system', 'user', 'watchdog');
-  foreach ($required as $require) {
-    $form['status'][$require] = array('#type' => 'hidden', '#value' => 1, '#suffix' => t('required'));
-  }
-
-  /**
-   * Handle throttle checkboxes, including overriding the generated checkboxes for required modules.
-   */
-  if (module_exist('throttle')) {
-    $form['throttle'] = array('#type' => 'checkboxes', '#default_value' => $throttle, '#options' => $options);
-    $throttle_required = array_merge($required, array('throttle'));
-    foreach ($throttle_required as $require) {
-      $form['throttle'][$require] = array('#type' => 'hidden', '#value' => 0, '#suffix' => t('required'));
-    }
+  // Re-order packages to force core modules to the top.
+  ksort($packages);
+  $packages = array_merge(
+    array(
+      t('required modules') => $packages[t('required modules')],
+      t('drupal core modules') => $packages[t('drupal core modules')]
+    ),
+    $packages
+  );
+
+  if (!is_array($packages[t('required modules')])) { // this is only on enabled page
+    array_splice($packages,0,1); 
   }
 
-  $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
 
-  return drupal_get_form('system_modules', $form);
-}
+  $header = array(
+    array(
+      'data' => t('Name'),
+      'header' => TRUE, 
+      'class' => 'modules-heading'
+    ),
+    array(
+      'data' => t('Version'),
+      'header' => TRUE, 
+      'class' => 'modules-heading'
+    ),
+    array(
+      'data' => t('Description'),
+      'header' => TRUE, 
+      'class' => 'modules-heading'
+    ),
+    array(
+      'data' => t('Operations'),
+      'header' => TRUE, 
+      'class' => 'modules-heading'
+    )
+  );
+       
+  $rows = array();
+  foreach ($packages as $group => $package) {
+    $rows[] = array(
+      array(
+        'colspan' => 4,
+        'header'  => TRUE,
+        'data' => $group,
+        'class' => 'modules-header', 
+      )
+    );
+    $rows[] = $header;
+    foreach ($package as $module) {
+      $modules[$module]['buttons'] = array();
+    
+      // Check for dependencies.
+      $depends = '';
+      $can_change = TRUE;
+      $compatible = strpos(VERSION, $modules[$module]['drupal']) === 0;
+          
+      if (!$modules[$module]['enabled']) {
+        // disabled modules and don't get their links
+        $modules[$module]['links'] = array();
+        foreach ($modules[$module]['dependencies'] as $dependency) {
+          $depends .= (!$depends ? t('Depends on: ') : ', ') ."<em>$dependency</em>";
+          if (!$modules[$dependency]['enabled']) {
+            $depends .= t(' (not present)');
+            $can_change = FALSE;
+          }
+        }
+        if ($can_change&&$compatible) {
+          if ($modules[$module]['uninstalled']) {
+            $modules[$module]['buttons'][] = system_module_form($module, $modules[$module], t('Enable'), t('Uninstall'));
+          } 
+          else {
+            $modules[$module]['buttons'][] = system_module_form($module, $modules[$module], t('Install'));  
+          }
+        }
+        else {
+          if ($modules[$module]['uninstalled']) {
+            $modules[$module]['buttons'][] = system_module_form($module, $modules[$module], t('Uninstall'));
+          } 
+        }
+      }
+      else {
+        // Check for modules that depend on this module.
+        foreach ($modules as $dependency => $module_data) {
+          if (in_array($module, $module_data['dependencies']) && $module_data['enabled']) {
+            $depends .= (!$depends ? t('Required by: ') : ', ') ."<em>$dependency</em>";
+            $can_change = FALSE;
+          }
+        }
+        if ($can_change && !in_array($module, $required)) {
+          $modules[$module]['buttons'][] = system_module_form($module, $modules[$module], t('Disable'));
+        }
+      }
 
-function theme_system_modules($form) {
-  foreach (element_children($form['name']) as $key) {
-    $row = array();
-    $row[] = form_render($form['name'][$key]);
-    $row[] = form_render($form['description'][$key]);
-    $row[] = array('data' => form_render($form['status'][$key]), 'align' => 'center');
+      $cells = array();
+      $cells[] = $modules[$module]['name'];
+      $cells[] = $modules[$module]['version'];
+      $cells[] = $modules[$module]['description'];
+      $cells[] = array(
+        'data' => theme('operations_links',
+          $modules[$module]['links'],
+          $modules[$module]['buttons']
+        ),
+        'nowrap' => TRUE
+      );
 
-    if (module_exist('throttle')) {
-      $row[] = array('data' => form_render($form['throttle'][$key]), 'align' => 'center');
+      $rows[] = $cells;
+      if ($depends) {
+        $rows[] = array('', array(
+          'data' => $depends, 
+          'colspan' => 3)
+        );
+      }
+      if (!$compatible) {
+        $rows[] = array('', array(
+          'data' => t('(This module is not compatible with your current Drupal version)'), 
+          'colspan' => 3)
+        );
+      }
     }
-    $rows[] = $row;
   }
-
-  $header = array(t('Name'), t('Description'), t('Enabled'));
-  if (module_exist('throttle')) {
-    $header[] = t('Throttle');
+  if ($rows) {
+    $output .= theme('system_modules_table', array(), $rows, array('width' => '100%'));
   }
 
-  $output = theme('table', $header, $rows);
   $output .= form_render($form);
   return $output;
 }
 
 
-function system_modules_submit($form_id, $edit) {
-  include_once './includes/install.inc';
-  $new_modules = array();
-  foreach ($edit['status'] as $key => $choice) {
-    if ($choice) {
-      if (drupal_get_installed_schema_version($key) == SCHEMA_UNINSTALLED) {
-        $new_modules[] = $key;
+/**
+ * This is only for a proof of concept to get theme.inc patched to allow for cells to 
+ * be able to identify that they are <th> and not <td>
+ * Thus the call to the private method in theme.inc _theme_table_cell
+ */
+function theme_system_modules_table($header, $rows, $attributes = array()) {
+  $output = '<table'. drupal_attributes($attributes) .">\n";
+  // Format the table header:
+  if (count($header)) {
+    $ts = tablesort_init($header);
+    $output .= ' <thead><tr>';
+    foreach ($header as $cell) {
+      $cell = tablesort_header($cell, $header, $ts);
+      $output .= _theme_table_cell($cell, 1); // private method call for proof of concept
+    }
+    $output .= " </tr></thead>\n";
+  }
+
+  // Format the table rows:
+  $output .= "<tbody>\n";
+  if (count($rows)) {
+    foreach ($rows as $number => $row) {
+      $attributes = array();
+
+      // Check if we're dealing with a simple or complex row
+      if (isset($row['data'])) {
+        foreach ($row as $key => $value) {
+          if ($key == 'data') {
+            $cells = $value;
+          }
+          else {
+            $attributes[$key] = $value;
+          }
+        }
       }
       else {
-        module_enable($key);
+        $cells = $row;
       }
-    }
-    else {
-      module_disable($key);
+
+      // Add odd/even class
+      $class = ($number % 2 == 1) ? 'even': 'odd';
+      if (isset($attributes['class'])) {
+        $attributes['class'] .= ' '. $class;
+      }
+      else {
+        $attributes['class'] = $class;
+      }
+
+      // Build row
+      $output .= ' <tr'. drupal_attributes($attributes) .'>';
+      $i = 0;
+      foreach ($cells as $cell) {
+        $cell = tablesort_cell($cell, $header, $ts, $i++);
+        $is_header = 0; // default cell not a th
+        if (isset($cell['header']) && $cell['header'] === TRUE) { // only boolean true will succeed
+          $is_header = 1;         
+          unset($cell['header']);  // remove header to not end up in attributes
+        }
+        $output .= _theme_table_cell($cell, $is_header); // call to hidden function for proof of concept
+      }
+      $output .= " </tr>\n";
     }
   }
 
-  module_list(TRUE, FALSE);
+  $output .= "</tbody></table>\n";
+  return $output;
+}
 
-  foreach ($new_modules as $module) {
-    drupal_install_module($module);
-  }
+/**
+ * Theme call back for module action buttons and links.
+ * @param $links
+ *  List of links.
+ * @param $buttons
+ *  List of buttons.
+ */
+function theme_operations_links($links, $buttons){
+  $output  =  '<div class="module-links">';
+  $output .=  theme('links', $links, '|');
+  $output .=  ' ';
+  $output .=  implode(' ', $buttons); 
+  $output .=  '</div>'; 
+  return $output;               
+}
 
-  if (is_array($edit['throttle'])) {
-    foreach ($edit['throttle'] as $key => $choice) {
-      if ($choice) {
-        db_query("UPDATE {system} SET throttle = 1 WHERE type = 'module' and name = '%s'", $key);
-      }
+/**
+ * Implementation of the module form hook_submit().
+ * @param $form_id
+ *  The id of the form.
+ * @param $form_values
+ *  The values passed back from the client.
+ */
+function system_module_form_submit($form_id, $form_values) {
+  include_once './includes/install.inc';
+  $module = str_replace('system_module_form_', '', $form_id);
+  $metadata = $form_values['metadata'];
+
+
+  $op = $_POST['op'];
+  if ($op == t('Install') || $op == t('Enable')) {
+    $status = 1;
+    if ($op == t('Install')) {
+      drupal_install_module($module);
+      drupal_set_message(t('%module installed.', array('%module' => $metadata['name'])));
+    } 
+    else {
+      module_enable($module);
+      drupal_set_message(t('%module enabled.', array('%module' => $metadata['name'])));
+    }
+  }
+  else {
+    $status = 0;
+    if ($op == t('Uninstall')) {
+      drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED);
+      drupal_set_message(t('%module uninstalled.', array('%module' => $metadata['name'])));
+    }
+    else {
+      module_disable($module);
+      drupal_set_message(t('%module disabled.', array('%module' => $metadata['name'])));
     }
   }
-
   menu_rebuild();
-
-  drupal_set_message(t('The configuration options have been saved.'));
-  return 'admin/settings/modules';
 }
 
 
