Index: admin_menu.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.inc,v
retrieving revision 1.11
diff -u -p -r1.11 admin_menu.inc
--- admin_menu.inc	26 Apr 2008 16:10:09 -0000	1.11
+++ admin_menu.inc	4 Jun 2008 12:04:06 -0000
@@ -40,57 +40,86 @@ function admin_menu_build($mid_admin) {
  * @see menu_tree_all_data()
  */
 function admin_menu_tree_all_data() {
-  // chx way. 13/03/2008 sun
-  // $item_admin = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE link_path = 'admin' AND menu_name = 'navigation'"));
   $item_admin = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE router_path = 'admin'"));
   $item_admin = array_merge_recursive($item_admin, menu_get_item('admin'));
-
-  // chx way. 13/03/2008 sun
-  // $data['tree'] = menu_tree_all_data('navigation', $item_admin);
-  // return $data['tree'];
-
-  $args = $parents = array($item_admin['mlid']);
-  $placeholders = implode(', ', array_fill(0, count($args), '%d'));
-  
-  // Collect all links as well as all of their children.
+  $args = $where = array();
+  $p = 1;
   do {
-    $result = db_query("SELECT mlid FROM {menu_links} WHERE menu_name = '%s' AND has_children = 1 AND plid IN (". $placeholders .') AND mlid NOT IN ('. $placeholders .')', array_merge(array($item_admin['menu_name']), $args, $args));
-    $num_rows = FALSE;
-    while ($item = db_fetch_array($result)) {
-      $args[] = $item['mlid'];
-      $num_rows = TRUE;
-    }
-    $placeholders = implode(', ', array_fill(0, count($args), '%d'));
-  } while ($num_rows);
-
-  // Build db_query arguments array.
-  array_unshift($args, $item_admin['menu_name']);
+    $where[] = "ml.p$p = %d";
+    $args[] = $item_admin["p$p"];
+    $p++;
+  } while ($p < 9 && $item_admin["p$p"] != 0);
+  $where[] = "ml.p$p != 0";
+  $where = implode(' AND ', $where);
   
   // Until now, everything seems to be a wanted behaviour of the new menu system
   // in Drupal 6.  However, {menu_links} does not contain any local tasks, and
   // because of that, it's getting crude now.
-  
-  // Select the links from the table, and recursively build the tree. We
-  // LEFT JOIN since there is no match in {menu_router} for an external
-  // link.
-  // Union select all local tasks from {menu_router}
-  // - that start with 'admin/',
-  // - using the mlid of the corresponding tab_parent path in {menu_links} as plid,
-  // - using the depth of the tab_parent path in {menu_links} + 1 as depth.
-  $types = array(MENU_LOCAL_TASK, MENU_DEFAULT_LOCAL_TASK);
-  $args = array_merge($args, $types);
-  $data['tree'] = menu_tree_data(db_query("(
-    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type, ml.*
+
+  // Poor man's locking.
+  if ($lock = variable_get('admin_menu_lock', 0)) {
+    while ($lock < time() + 10) {
+      sleep(1);
+    }
+  }
+  variable_set('admin_menu_lock', time());
+
+  // Clear old data.
+  db_query('DELETE FROM {admin_menu}');
+
+  // Fetch the regular, visible menu tree below 'admin/'.
+  // @todo Figure out which fields are actually needed for menu building and/or
+  //  theming. Everything else can probably be ignored (doesn't need to be queried).
+  db_query("INSERT INTO {admin_menu} SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type,
+      ml.menu_name, ml.mlid, ml.plid, ml.link_path, ml.router_path, ml.link_title, ml.options, ml.module, ml.hidden, ml.external, ml.has_children, ml.expanded, ml.weight, ml.depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated
     FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
-    WHERE ml.menu_name = '%s' AND ml.plid IN (". $placeholders .")
-  ) UNION (
-    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type,
-      ml.menu_name, ml.mlid + 100000 as mlid, ml.plid, ml.link_path, ml.router_path, m.title as link_title, ml.options, ml.module, ml.hidden, ml.external, ml.has_children, ml.expanded, ml.weight, ml.depth + 1 as depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated
-    FROM {menu_router} m LEFT JOIN {menu_links} ml ON ml.router_path = m.tab_parent
-    WHERE ml.router_path REGEXP '[^%%]*' AND m.path LIKE 'admin/%%' AND m.type IN (". db_placeholders($types) .")
-  )
-  ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC", $args), $parents);
-  
+    WHERE $where", $args);
+
+  // Fetch all local tasks from all administrative menu items using the depth
+  // of the tab_parent path in {menu_links} + 1 as depth.
+  $types = array(MENU_LOCAL_TASK, MENU_DEFAULT_LOCAL_TASK);
+  $result = db_query("SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type,
+      ml.menu_name, 0 AS mlid, ml.mlid AS plid, m.path as link_path, m.path as router_path, m.title as link_title, ml.options, ml.module, ml.hidden, ml.external, 0 as has_children, ml.expanded, m.weight, ml.depth + 1 as depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated
+    FROM {menu_router} m
+    INNER JOIN {menu_links} ml ON ml.router_path = m.tab_parent
+    WHERE ml.hidden <> -1 AND m.type IN (". db_placeholders($types) .") AND $where", array_merge($types, $args));
+  // Assign unique mlids to local tasks, and add them to the previously queried
+  // menu tree.
+  $mlid = 100000;
+  while ($item = db_fetch_array($result)) {
+    $item['mlid'] = $mlid++;
+    // Adjust parent id.
+    $item['p'. $item['depth']] = $item['mlid'];
+    db_query("INSERT INTO {admin_menu} VALUES ('". implode("','", array_fill(0, count($item), '%s')) ."')", $item);
+  }
+
+  // Fetch secondary level local tasks. These have its parent in the
+  // {menu_router} table, which means we have to join the table with itself.
+  // The parent of the parent item is the link item from the {menu_links} table.
+  // The item's parent id (plid) needs to be looked up from the {admin_menu} table.
+  $result = db_query("SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.title, m.title_callback, m.title_arguments, m.type,
+      ml.menu_name, 0 AS mlid, am.mlid AS plid, m.path as link_path, m.path as router_path, m.title as link_title, ml.options, ml.module, ml.hidden, ml.external, 0 as has_children, ml.expanded, m.weight, am.depth + 1 as depth, ml.customized, ml.p1, ml.p2, ml.p3, ml.p4, ml.p5, ml.p6, ml.p7, ml.p8, ml.p9, ml.updated
+    FROM {menu_router} m
+    INNER JOIN {menu_router} mp ON (mp.path = m.tab_parent)
+    INNER JOIN {menu_links} ml ON (ml.router_path = mp.tab_parent)
+    INNER JOIN {admin_menu} am ON (am.link_path = m.tab_parent)
+    WHERE ml.hidden <> -1 AND m.type IN (". db_placeholders($types) .") AND $where", array_merge($types, $args));
+  while ($item = db_fetch_array($result)) {
+    $item['mlid'] = $mlid++;
+    // Adjust parent id of the local task and its parent item.
+    $item['p'. ($item['depth'] - 1)] = $item['plid'];
+    $item['p'. $item['depth']] = $item['mlid'];
+    db_query("INSERT INTO {admin_menu} VALUES ('". implode("','", array_fill(0, count($item), '%s')) ."')", $item);
+  }
+
+  // @todo Make adjustments to the menu tree here....
+
+  // Fetch all items, ordered by parent items.
+  $result = db_query("SELECT * FROM {admin_menu} ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC");
+  $data['tree'] = menu_tree_data($result);
+
+  variable_del('admin_menu_lock');
+
   $data['node_links'] = array();
   menu_tree_collect_node_links($data['tree'], $data['node_links']);
   
Index: admin_menu.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.install,v
retrieving revision 1.4
diff -u -p -r1.4 admin_menu.install
--- admin_menu.install	24 Feb 2008 17:32:47 -0000	1.4
+++ admin_menu.install	4 Jun 2008 12:04:06 -0000
@@ -2,6 +2,243 @@
 // $Id: admin_menu.install,v 1.4 2008/02/24 17:32:47 sun Exp $
 
 /**
+ * Implementation of hook_install().
+ */
+function admin_menu_install() {
+  drupal_install_schema('admin_menu');
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function admin_menu_uninstall() {
+  // Remove tables.
+  drupal_uninstall_schema('admin_menu');
+  menu_rebuild();
+}
+
+// @todo Create a valid scheme.
+// @todo Columns that are not needed for menu building and/or theming can
+//   probably be given a fake definition (CHAR(0)) or even left out.
+function admin_menu_schema() {
+  $schema['admin_menu'] = array(
+    'description' => t('Maintains a copy of the menu items for admin menu use.'),
+    'fields' => array(
+
+      // Items from table menu_router.
+      'load_functions' => array(
+        'description' => t('A serialized array of function names (like node_load) to be called to load an object corresponding to a part of the current path.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'to_arg_functions' => array(
+        'description' => t('A serialized array of function names (like user_current_to_arg) to be called to replace a part of the router path with another string.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'access_callback' => array(
+        'description' => t('The callback which determines the access to this router path. Defaults to user_access.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'access_arguments' => array(
+        'description' => t('A serialized array of arguments for the access callback.'),
+        'type' => 'text',
+        'not null' => FALSE),
+      'page_callback' => array(
+        'description' => t('The name of the function that renders the page.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'page_arguments' => array(
+        'description' => t('A serialized array of arguments for the page callback.'),
+        'type' => 'text',
+        'not null' => FALSE),
+      'title' => array(
+        'description' => t('The title for the current page, or the title for the tab if this is a local task.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'title_callback' => array(
+        'description' => t('A function which will alter the title. Defaults to t()'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'title_arguments' => array(
+        'description' => t('A serialized array of arguments for the title callback. If empty, the title will be used as the sole argument for the title callback.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'type' => array(
+        'description' => t('Numeric representation of the type of the menu item, like MENU_LOCAL_TASK.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0),
+      
+      // Items from table menu_links.
+      'menu_name' => array(
+        'description' => t("The menu name. All links with the same menu name (such as 'navigation') are part of the same menu."),
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => ''),
+      'mlid' => array(
+        'description' => t('The menu link ID (mlid) is the integer primary key.'),
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE),
+      'plid' => array(
+        'description' => t('The parent link ID (plid) is the mlid of the link above in the hierarchy, or zero if the link is at the top level in its menu.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'link_path' => array(
+        'description' => t('The Drupal path or external path this link points to.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'router_path' => array(
+        'description' => t('For links corresponding to a Drupal path (external = 0), this connects the link to a {menu_router}.path for joins.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'link_title' => array(
+      'description' => t('The text displayed for the link, which may be modified by a title callback stored in {menu_router}.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''),
+      'options' => array(
+        'description' => t('A serialized array of options to be passed to the url() or l() function, such as a query string or HTML attributes.'),
+        'type' => 'text',
+        'not null' => FALSE),
+      'module' => array(
+        'description' => t('The name of the module that generated this link.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => 'system'),
+      'hidden' => array(
+        'description' => t('A flag for whether the link should be rendered in menus. (1 = a disabled menu item that may be shown on admin screens, -1 = a menu callback, 0 = a normal, visible link)'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small'),
+      'external' => array(
+        'description' => t('A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small'),
+      'has_children' => array(
+        'description' => t('Flag indicating whether any links have this link as a parent (1 = children exist, 0 = no children).'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small'),
+      'expanded' => array(
+        'description' => t('Flag for whether this link should be rendered as expanded in menus - expanded links always have their child links displayed, instead of only when the link is in the active trail (1 = expanded, 0 = not expanded)'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small'),
+      'weight' => array(
+        'description' => t('Link weight among links in the same menu at the same depth.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0),
+      'depth' => array(
+        'description' => t('The depth relative to the top level. A link with plid == 0 will have depth == 1.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small'),
+      'customized' => array(
+        'description' => t('A flag to indicate that the user has manually created or edited the link (1 = customized, 0 = not customized).'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small'),
+      'p1' => array(
+        'description' => t('The first mlid in the materialized path. If N = depth, then pN must equal the mlid. If depth > 1 then p(N-1) must equal the plid. All pX where X > depth must equal zero. The columns p1 .. p9 are also called the parents.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p2' => array(
+        'description' => t('The second mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p3' => array(
+        'description' => t('The third mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p4' => array(
+        'description' => t('The fourth mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p5' => array(
+        'description' => t('The fifth mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p6' => array(
+        'description' => t('The sixth mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p7' => array(
+        'description' => t('The seventh mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p8' => array(
+        'description' => t('The eighth mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'p9' => array(
+        'description' => t('The ninth mlid in the materialized path. See p1.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      'updated' => array(
+        'description' => t('Flag that indicates that this link was generated during the update from Drupal 5.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'small'),
+    ),
+    'unique keys' => array('mlid' => array('mlid')),
+    'indexes' => array(
+      'path' => array('link_path'),
+    ),
+  );
+  return $schema;
+}
+
+/**
  * #224605: Rebuild cached menu for users.
  */
 function admin_menu_update_5202() {
Index: admin_menu.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.module,v
retrieving revision 1.43
diff -u -p -r1.43 admin_menu.module
--- admin_menu.module	26 Apr 2008 16:10:09 -0000	1.43
+++ admin_menu.module	4 Jun 2008 12:04:06 -0000
@@ -151,15 +151,15 @@ function &admin_menu_get_menu($mid_admin
   }
   global $user, $language;
   
-  $cid = 'links:admin_menu:all:admin:'. $user->uid .':'. $language->language;
-  $cache = 0; // cache_get($cid, 'cache_menu');
+  $cid = 'links:admin_menu:'. $user->uid .':'. $language->language;
+  $cache = cache_get($cid, 'cache_menu');
   if ($cache && isset($cache->data)) {
     $_admin_menu = $cache->data;
   }
   else {
     require_once drupal_get_path('module', 'admin_menu') .'/admin_menu.inc';
     $_admin_menu = admin_menu_build($mid_admin);
-    // cache_set($cid, $_admin_menu, 'cache_menu', 0);
+    cache_set($cid, $_admin_menu, 'cache_menu', 0);
   }
   
   return $_admin_menu;
@@ -181,7 +181,7 @@ function admin_menu_tree_output($tree) {
   // Pull out just the menu items we are going to render so that we
   // get an accurate count for the first/last classes.
   foreach ($tree as $data) {
-    if (!$data['link']['hidden']) {
+    if ($data['link']['hidden'] != -1) {
       $items[] = $data;
     }
   }
@@ -356,7 +356,7 @@ function admin_menu_admin_menu(&$admin_m
 function admin_menu_form_alter(&$form, $form_state, $form_id) {
   if ($form_id == 'devel_admin_settings') {
     // Shift system_settings_form buttons.
-    $weight = $form['buttons']['#weight'];
+    $weight = isset($form['buttons']['#weight']) ? $form['buttons']['#weight'] : 0;
     $form['buttons']['#weight'] = $weight + 1;
     
     $form['admin_menu'] = array(
