Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.196
diff -u -p -r1.196 locale.module
--- modules/locale/locale.module	21 Oct 2007 18:59:02 -0000	1.196
+++ modules/locale/locale.module	23 Oct 2007 11:53:47 -0000
@@ -227,9 +227,8 @@ function locale_user($type, $edit, &$use
  */
 function locale_form_alter(&$form, $form_state, $form_id) {
   switch ($form_id) {
-
     // Language field for paths
-    case 'path_admin_edit':
+    case 'path_admin_form':
       $form['language'] = array(
         '#type' => 'select',
         '#title' => t('Language'),
Index: modules/path/path.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.admin.inc,v
retrieving revision 1.4
diff -u -p -r1.4 path.admin.inc
--- modules/path/path.admin.inc	12 Aug 2007 16:34:56 -0000	1.4
+++ modules/path/path.admin.inc	23 Oct 2007 11:53:47 -0000
@@ -6,16 +6,36 @@
  * Administrative page callbacks for the path module.
  */
 
+function path_admin_overview($callback_arg = '') {
+  $op = isset($_POST['op']) ? $_POST['op'] : $callback_arg;
+
+  switch ($op) {
+    default:
+      if (!empty($_POST['paths']) && isset($_POST['operation']) && ($_POST['operation'] == 'delete')) {
+        $output = drupal_get_form('path_multiple_delete_confirm');
+      } 
+      else {
+        $output = drupal_get_form('path_admin_filter_form');
+        $output .= drupal_get_form('path_admin_overview_form');
+      } 
+  } // switch
+  return $output;
+}
+
 /**
  * Return a listing of all defined URL aliases.
  * When filter key passed, perform a standard search on the given key,
  * and return the list of matching URL aliases.
  */
-function path_admin_overview($keys = NULL) {
-  // Add the filter form above the overview table.
-  $output = drupal_get_form('path_admin_filter_form', $keys);
+function path_admin_overview_form(&$form_state) {
+  if (arg(3) == 'list' && arg(4)) {
+    $form_state['values']['filter'] = arg(4);
+  }
+  $keys = isset($form_state['values']['filter']) ? $form_state['values']['filter'] : NULL;
+
   // Enable language column if locale is enabled or if we have any alias with language
   $count = db_result(db_query("SELECT COUNT(*) FROM {url_alias} WHERE language != ''"));
+
   $multilanguage = (module_exists('locale') || $count);
 
   if ($keys) {
@@ -26,39 +46,48 @@ function path_admin_overview($keys = NUL
   else {
     $sql = 'SELECT * FROM {url_alias}';
   }
+
   $header = array(
+    array(),
     array('data' => t('Alias'), 'field' => 'dst', 'sort' => 'asc'),
-    array('data' => t('System'), 'field' => 'src'),
-    array('data' => t('Operations'), 'colspan' => '2')
+    array('data' => t('System'), 'field' => 'src')
   );
   if ($multilanguage) {
-    $header[3] = $header[2];
-    $header[2] = array('data' => t('Language'), 'field' => 'language');
+    $header[] = array('data' => t('Language'), 'field' => 'language');
   }
+  $header[] = array('data' => t('Operations'));
+  
   $sql .= tablesort_sql($header);
   $result = pager_query($sql, 50, 0 , NULL, $keys);
 
   $rows = array();
+  $paths = array();
   $destination = drupal_get_destination();
   while ($data = db_fetch_object($result)) {
-    $row = array(check_plain($data->dst), check_plain($data->src), l(t('edit'), "admin/build/path/edit/$data->pid", array('query' => $destination)), l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination)));
+    $paths[$data->pid] = '';
+    $form['dst'][$data->pid] = array('#value' => check_plain($data->dst));
+    $form['src'][$data->pid] = array('#value' => check_plain($data->src));
+    
+    $form['operations'][$data->pid] = array('#value' => l(t('edit'), "admin/build/path/edit/$data->pid", array('query' => $destination)));
+
     if ($multilanguage) {
-      $row[4] = $row[3];
-      $row[3] = $row[2];
-      $row[2] = module_invoke('locale', 'language_name', $data->language);
+      $form['language'][$data->pid] = array('#value' => module_invoke('locale', 'language_name', $data->language));
     }
-    $rows[] = $row;
   }
+  $form['paths'] = array(
+    '#type' => 'checkboxes',
+    '#options' => $paths
+  );
+  $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
 
-  if (empty($rows)) {
-    $empty_message = $keys ? t('No URL aliases found.') : t('No URL aliases available.') ;
-    $rows[] = array(array('data' => $empty_message, 'colspan' => ($multilanguage ? 5 : 4)));
-  }
+  $form['delete'] = array('#type' => 'submit', '#value' => t('Delete selected'));
+  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
 
-  $output .= theme('table', $header, $rows);
-  $output .= theme('pager', NULL, 50, 0);
+  return $form;
+}
 
-  return $output;
+function path_admin_overview_form_submit($form, &$form_state) {
+  
 }
 
 /**
@@ -95,7 +124,8 @@ function path_admin_form(&$form_state, $
     '#maxlength' => 64,
     '#size' => 45,
     '#description' => t('Specify the existing path you wish to alias. For example: node/28, forum/1, taxonomy/term/1+2.'),
-    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
+    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
+    '#required' => TRUE,
   );
   $form['dst'] = array(
     '#type' => 'textfield',
@@ -104,7 +134,8 @@ function path_admin_form(&$form_state, $
     '#maxlength' => 64,
     '#size' => 45,
     '#description' => t('Specify an alternative path by which this data can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
-    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
+    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
+    '#required' => TRUE,
   );
   // This will be a hidden value unless locale module is enabled
   $form['language'] = array(
@@ -118,7 +149,6 @@ function path_admin_form(&$form_state, $
   else {
     $form['submit'] = array('#type' => 'submit', '#value' => t('Create new alias'));
   }
-
   return $form;
 }
 
@@ -136,6 +166,10 @@ function path_admin_form_validate($form,
   if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE pid != %d AND dst = '%s' AND language = '%s'", $pid, $dst, $language))) {
     form_set_error('dst', t('The alias %alias is already in use in this language.', array('%alias' => $dst)));
   }
+  $item = menu_get_item($src);
+  if (!$item || !$item['access']) {
+    form_set_error('src', t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $src)));
+  }
 }
 
 /**
@@ -182,7 +216,16 @@ function path_admin_delete_confirm_submi
  * @ingroup forms
  * @see path_admin_filter_form_submit().
  */
-function path_admin_filter_form(&$form_state, $keys = '') {
+function path_admin_filter_form(&$form_state) {
+  if (isset($form_state['post']['filter'])) {
+    $form_state['values']['filter'] = $form_state['post']['filter'];
+  }
+  if (arg(3) == 'list' && arg(4)) {
+    $form_state['values']['filter'] = arg(4);
+  }
+  $keys = isset($form_state['values']['filter']) ? $form_state['values']['filter'] : NULL;
+  
+  
   $form['#attributes'] = array('class' => 'search-form');
   $form['basic'] = array('#type' => 'fieldset',
     '#title' => t('Filter aliases')
@@ -195,16 +238,33 @@ function path_admin_filter_form(&$form_s
     '#maxlength' => 64,
     '#size' => 25,
   );
-  $form['basic']['inline']['submit'] = array('#type' => 'submit', '#value' => t('Filter'));
-
+  $form['basic']['inline']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Filter'),
+    '#submit' => array('path_admin_filter_form_submit_filter'),
+    );
+  if ($keys) {
+    $form['basic']['inline']['reset'] = array(
+      '#type' => 'submit',
+      '#value' => t('Reset'),
+      '#submit' => array('path_admin_filter_form_submit_reset'),
+    );
+  }
   return $form;
 }
 
 /**
- * Process filter form submission.
+ * Process filter form submission when the Filter button is pressed.
  */
-function path_admin_filter_form_submit($form, &$form_state) {
-  return 'admin/build/path/list/'. trim($form_state['values']['filter']);
+function path_admin_filter_form_submit_filter($form, &$form_state) {
+  $form_state['redirect'] = 'admin/build/path/list/'. trim($form_state['values']['filter']);
+}
+
+/**
+ * Process filter form submission when the Reset button is pressed.
+ */
+function path_admin_filter_form_submit_reset($form, &$form_state) {
+  $form_state['redirect'] = 'admin/build/path/list';
 }
 
 /**
@@ -215,3 +275,52 @@ function path_admin_filter_get_keys() {
   $path = explode('/', $_GET['q'], 5);
   return count($path) == 5 ? $path[4] : '';
 }
+
+/**
+ * Theme the path alias overview.
+ * 
+ * @ingroup themeable
+ **/
+function theme_path_admin_overview_form($form) {
+  if (arg(3) == 'list' && arg(4)) {
+    $form_state['values']['filter'] = arg(4);
+  }
+  $keys = isset($form_state['values']['filter']) ? $form_state['values']['filter'] : NULL;
+  // Overview table:
+  $header = array(
+    theme('table_select_header_cell'),
+    array('data' => t('Alias'), 'field' => 'dst', 'sort' => 'asc'),
+    array('data' => t('System'), 'field' => 'src'),
+    t('Operations')
+  );
+
+  $rows = array();
+  $colspan = 5;
+  if (isset($form['dst']) && is_array($form['dst'])) {
+    foreach (element_children($form['dst']) as $key) {
+      $row = array(
+        drupal_render($form['paths'][$key]),
+        drupal_render($form['dst'][$key]),
+        drupal_render($form['src'][$key]),
+      );
+      if (isset($form['language'][$key])) {
+        $row[] = drupal_render($form['operations'][$key]);
+        $colspan = 6;
+      }
+      $row[] = drupal_render($form['operations'][$key]);
+      $rows[] = $row;
+    }
+  }
+  else  {
+    $rows[] = array(array('data' => ($keys ? t('No URL aliases found.') : t('No URL aliases available.')), 'colspan' => $colspan));
+  }
+
+  $output = theme('table', $header, $rows, array('summary' => t('URL aliases')));
+  if ($form['pager']['#value']) {
+    $output .= drupal_render($form['pager']);
+  }
+
+  $output .= drupal_render($form);
+
+  return $output;
+}
Index: modules/path/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.module,v
retrieving revision 1.131
diff -u -p -r1.131 path.module
--- modules/path/path.module	12 Aug 2007 16:34:56 -0000	1.131
+++ modules/path/path.module	23 Oct 2007 11:53:49 -0000
@@ -77,7 +77,6 @@ function path_menu() {
  */
 function path_admin_delete($pid = 0) {
   db_query('DELETE FROM {url_alias} WHERE pid = %d', $pid);
-  drupal_set_message(t('The alias has been deleted.'));
 }
 
 /**
@@ -85,8 +84,8 @@ function path_admin_delete($pid = 0) {
  */
 function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = '') {
   if ($path && !$alias) {
-    // Delete based on path
-    db_query("DELETE FROM {url_alias} WHERE src = '%s' AND language = '%s'", $path, $language);
+    // Delete the most fitting result based on path falling back on path without language.
+    db_query("DELETE FROM {url_alias} WHERE src = '%s' AND language IN('%s', '')", $path, $language);
     drupal_clear_path_cache();
   }
   else if (!$path && $alias) {
@@ -111,19 +110,9 @@ function path_set_alias($path = NULL, $a
         db_query("INSERT INTO {url_alias} (src, dst, language) VALUES ('%s', '%s', '%s')", $path, $alias, $language);
       }
     }
-    // The alias exists.
+    // The alias exist, update the path.
     else {
-      // This path has no alias yet, so we redirect the alias here.
-      if ($path_count == 0) {
-        db_query("UPDATE {url_alias} SET src = '%s' WHERE dst = '%s' AND language = '%s'", $path, $alias, $language);
-      }
-      else {
-        // This will delete the path that alias was originally pointing to.
-        path_set_alias(NULL, $alias, NULL, $language);
-        // This will remove the current aliases of the path.
-        path_set_alias($path, NULL, NULL, $language);
-        path_set_alias($path, $alias, NULL, $language);
-      }
+      db_query("UPDATE {url_alias} SET src = '%s' WHERE dst = '%s' AND language = '%s'", $path, $alias, $language);
     }
     if ($alias_count == 0 || $path_count == 0) {
       drupal_clear_path_cache();
@@ -139,10 +128,10 @@ function path_set_alias($path = NULL, $a
  */
 function path_nodeapi(&$node, $op, $arg) {
   if (user_access('create url aliases') || user_access('administer url aliases')) {
+    $language = isset($node->language) ? $node->language : '';
     switch ($op) {
       case 'validate':
         $node->path = trim($node->path);
-        $language = isset($node->language) ? $node->language : '';
         if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE dst = '%s' AND src != '%s' AND language = '%s'", $node->path, "node/$node->nid", $language))) {
           form_set_error('path', t('The path is already in use.'));
         }
@@ -150,7 +139,6 @@ function path_nodeapi(&$node, $op, $arg)
 
       case 'load':
         $path = "node/$node->nid";
-        $language = isset($node->language) ? $node->language : '';
         $alias = drupal_get_path_alias($path, $language);
         if ($path != $alias) {
           $node->path = $alias;
@@ -161,17 +149,17 @@ function path_nodeapi(&$node, $op, $arg)
         // Don't try to insert if path is NULL. We may have already set
         // the alias ahead of time.
         if (isset($node->path)) {
-          path_set_alias("node/$node->nid", $node->path);
+          path_set_alias("node/$node->nid", $node->path, NULL, $language);
         }
         break;
 
       case 'update':
-        path_set_alias("node/$node->nid", isset($node->path) ? $node->path : NULL, isset($node->pid) ? $node->pid : NULL);
+        path_set_alias("node/$node->nid", isset($node->path) ? $node->path : NULL, isset($node->pid) ? $node->pid : NULL, $language);
         break;
 
       case 'delete':
         $path = "node/$node->nid";
-        if (drupal_get_path_alias($path) != $path) {
+        if (drupal_get_path_alias($path, $language) != $path) {
           path_set_alias($path);
         }
         break;
@@ -223,3 +211,43 @@ function path_perm() {
 function path_load($pid) {
   return db_fetch_array(db_query('SELECT * FROM {url_alias} WHERE pid = %d', $pid));
 }
+
+function path_multiple_delete_confirm(&$form_state) {
+  $edit = $form_state['post'];
+
+  $form['paths'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
+  // array_filter returns only elements with TRUE values
+  foreach (array_filter($edit['paths']) as $pid => $value) {
+    $alias = path_load($pid);
+    $form['paths'][$pid] = array('#type' => 'hidden', '#value' => $pid, '#prefix' => '<li>', '#suffix' => check_plain($alias['dst']) ."</li>\n");
+   }
+  $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
+
+  return confirm_form($form,
+                      t('Are you sure you want to delete these URL aliases?'),
+                      'admin/build/path', t('This action cannot be undone.'),
+                      t('Delete all'), t('Cancel'));
+}
+
+function path_multiple_delete_confirm_submit($form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    foreach ($form_state['values']['paths'] as $pid => $value) {
+      path_admin_delete($pid);
+    }
+    drupal_set_message(t('The URL aliases have been deleted.'));
+  }
+  $form_state['redirect'] = 'admin/build/path';
+  return;
+}
+
+/**
+ * Implementation of hook_theme() 
+ **/
+function path_theme() {
+  return array(
+    'path_admin_overview_form' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'path.admin.inc',
+    ),
+  );
+}
