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	9 May 2008 19:13:43 -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	9 May 2008 20:13:02 -0000
@@ -1,6 +1,52 @@
 <?php
 // $Id: admin_menu.install,v 1.4 2008/02/24 17:32:47 sun Exp $
 
+// @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.
+// @todo Schema API
+function admin_menu_install() {
+  db_query("CREATE TABLE {admin_menu} (
+    load_functions varchar(255) default '',
+    to_arg_functions varchar(255) default '',
+    access_callback varchar(255) default '',
+    access_arguments text,
+    page_callback varchar(255) default '',
+    page_arguments text,
+    title varchar(255) default '',
+    title_callback varchar(255) default '',
+    title_arguments varchar(255) default '',
+    type int(11) default 0,
+    menu_name varchar(32) NOT NULL default '',
+    mlid int(10) unsigned NOT NULL default 0,
+    plid int(10) unsigned NOT NULL default 0,
+    link_path varchar(255) NOT NULL default '',
+    router_path varchar(255) NOT NULL default '',
+    link_title varchar(255) NOT NULL default '',
+    options text,
+    module varchar(255) NOT NULL default 'system',
+    hidden smallint(6) NOT NULL default 0,
+    external smallint(6) NOT NULL default 0,
+    has_children smallint(6) NOT NULL default 0,
+    expanded smallint(6) NOT NULL default 0,
+    weight int(11) NOT NULL default 0,
+    depth smallint(6) NOT NULL default 0,
+    customized smallint(6) NOT NULL default 0,
+    p1 int(10) unsigned NOT NULL default 0,
+    p2 int(10) unsigned NOT NULL default 0,
+    p3 int(10) unsigned NOT NULL default 0,
+    p4 int(10) unsigned NOT NULL default 0,
+    p5 int(10) unsigned NOT NULL default 0,
+    p6 int(10) unsigned NOT NULL default 0,
+    p7 int(10) unsigned NOT NULL default 0,
+    p8 int(10) unsigned NOT NULL default 0,
+    p9 int(10) unsigned NOT NULL default 0,
+    updated smallint(6) NOT NULL default 0,
+    UNIQUE mlid (mlid),
+    KEY path (link_path)
+  )");
+}
+
 /**
  * #224605: Rebuild cached menu for users.
  */
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	9 May 2008 17:01:16 -0000
@@ -151,15 +151,16 @@ function &admin_menu_get_menu($mid_admin
   }
   global $user, $language;
   
+  // @todo links:admin_menu:$user->uid:$language->language should be sufficient
   $cid = 'links:admin_menu:all:admin:'. $user->uid .':'. $language->language;
-  $cache = 0; // cache_get($cid, 'cache_menu');
+  $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 +182,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 +357,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(
