Index: install.php
===================================================================
RCS file: /cvs/drupal/drupal/install.php,v
retrieving revision 1.37
diff -u -F^f -r1.37 install.php
--- install.php	27 Feb 2007 12:29:22 -0000	1.37
+++ install.php	2 Mar 2007 08:25:59 -0000
@@ -151,6 +151,7 @@ function install_change_settings($profil
   // We always need this because we want to run form_get_errors.
   include_once './includes/form.inc';
   drupal_maintenance_theme();
+  install_task_list('database');
 
   // The existing database settings are not working, so we need write access
   // to settings.php to change them.
@@ -375,7 +376,14 @@ function install_settings_form_submit($f
 }
 
 /**
- * Find all .profile files and allow admin to select which to install.
+ * Find all .profile files.
+ */
+function install_find_profiles() {
+  return file_scan_directory('./profiles', '\.profile$', array('.', '..', 'CVS'), 0, TRUE, 'name', 0);  
+}
+
+/**
+ * Allow admin to select which profile to install.
  *
  * @return
  *   The selected profile.
@@ -383,7 +391,7 @@ function install_settings_form_submit($f
 function install_select_profile() {
   include_once './includes/form.inc';
 
-  $profiles = file_scan_directory('./profiles', '\.profile$', array('.', '..', 'CVS'), 0, TRUE, 'name', 0);
+  $profiles = install_find_profiles();
   // Don't need to choose profile if only one available.
   if (sizeof($profiles) == 1) {
     $profile = array_pop($profiles);
@@ -398,6 +406,7 @@ function install_select_profile() {
     }
 
     drupal_maintenance_theme();
+    install_task_list('profile');
 
     drupal_set_title(st('Select an installation profile'));
     print theme('install_page', drupal_get_form('install_select_profile_form', $profiles));
@@ -432,7 +441,16 @@ function install_select_profile_form($pr
 }
 
 /**
- * Find all .po files for the current profile and allow admin to select which to use.
+ * Find all .po files for the current profile..
+ */
+function install_find_locales($profilename) {
+  $locales = file_scan_directory('./profiles/'. $profilename, '\.po$', array('.', '..', 'CVS'), 0, FALSE);
+  array_unshift($locales, (object) array('name' => 'en'));
+  return $locales;
+}
+
+/**
+ * Allow admin to select which locale to use for the current profile.
  *
  * @return
  *   The selected language.
@@ -441,9 +459,8 @@ function install_select_locale($profilen
   include_once './includes/file.inc';
   include_once './includes/form.inc';
 
-  // Collect possible locales, add default
-  $locales = file_scan_directory('./profiles/' . $profilename, '\.po$', array('.', '..', 'CVS'), 0, FALSE);
-  array_unshift($locales, (object) array('name' => 'en'));
+  // Find all available locales.
+  $locales = install_find_locales($profilename);
 
   // Don't need to choose locale if only one (English) is available.
   if (sizeof($locales) == 1) {
@@ -456,6 +473,7 @@ function install_select_locale($profilen
     }
 
     drupal_maintenance_theme();
+    install_task_list('locale');
 
     drupal_set_title(st('Choose your preferred language'));
     print theme('install_page', drupal_get_form('install_select_locale_form', $locales));
@@ -492,6 +510,7 @@ function install_select_locale_form($loc
  */
 function install_no_profile_error() {
   drupal_maintenance_theme();
+  install_task_list('profile');
   drupal_set_title(st('No profiles available'));
   print theme('install_page', '<p>'. st('We were unable to find any installer profiles. Installer profiles tell us what modules to enable and what schema to install in the database. A profile is necessary to continue with the installation process.') .'</p>');
   exit;
@@ -517,6 +536,7 @@ function install_missing_modules_error($
   global $base_url;
 
   drupal_maintenance_theme();
+  install_task_list('install');
   drupal_set_title(st('Modules missing'));
   print theme('install_page', '<p>'. st('One or more required modules are missing. Please check the error messages and <a href="!url">try again</a>.', array('!url' => "install.php?profile=$profile")) .'</p>');
   exit;
@@ -537,6 +557,7 @@ function install_complete($profile) {
 
   // Build final page.
   drupal_maintenance_theme();
+  install_task_list();
   drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
   $output .= '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
 
@@ -570,6 +591,7 @@ function install_check_requirements($pro
   // If there are issues, report them.
   if ($severity == REQUIREMENT_ERROR) {
     drupal_maintenance_theme();
+    install_task_list('requirements');
 
     foreach ($requirements as $requirement) {
       if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
@@ -583,4 +605,30 @@ function install_check_requirements($pro
   }
 }
 
+/**
+ * Add the installation task list to the current page.
+ */
+function install_task_list($active = NULL) {
+  // Default list of tasks.
+  $tasks = array(
+    'profile' => st('Choose profile'),
+    'locale' => st('Choose language'),
+    'requirements' => st('Verify requirements'),
+    'database' => st('Database setup'),
+    'install' => st('Installation'),
+  );
+  
+  // Remove profiles if only one profile exists.
+  if (count(install_find_profiles()) == 1) {
+    unset($tasks['profile']);
+  }
+
+  // Remove locale if no install profiles use them.
+  if (count(install_find_locales('.')) == 1) {
+    unset($tasks['locale']);
+  }
+
+  drupal_set_content('left', theme_task_list($tasks, $active));
+}
+
 install_main();
Index: update.php
===================================================================
RCS file: /cvs/drupal/drupal/update.php,v
retrieving revision 1.211
diff -u -F^f -r1.211 update.php
--- update.php	25 Dec 2006 21:22:03 -0000	1.211
+++ update.php	2 Mar 2007 08:25:59 -0000
@@ -325,6 +325,8 @@ function update_selection_page() {
   drupal_add_js('misc/update.js', 'core', 'header', FALSE, TRUE);
   $output .= drupal_get_form('update_script_selection_form');
 
+  update_task_list('select');
+
   return $output;
 }
 
@@ -393,6 +395,7 @@ function update_update_page() {
   // Keep track of total number of updates
   $_SESSION['update_total'] = count($_SESSION['update_remaining']);
 
+  update_task_list('run');
   if ($_POST['has_js']) {
     return update_progress_page();
   }
@@ -513,6 +516,7 @@ function update_finished_page($success) 
   $links[] = '<a href="'. base_path() .'">main page</a>';
   $links[] = '<a href="'. base_path() .'?q=admin">administration pages</a>';
 
+  update_task_list();
   // Report end result
   if ($success) {
     $output = '<p>Updates were attempted. If you see no failures below, you may proceed happily to the <a href="index.php?q=admin">administration pages</a>. Otherwise, you may need to update your database manually. All errors have been <a href="index.php?q=admin/logs/watchdog">logged</a>.</p>';
@@ -559,6 +563,7 @@ function update_finished_page($success) 
 }
 
 function update_info_page() {
+  update_task_list('info');
   drupal_set_title('Drupal database update');
   $output = "<ol>\n";
   $output .= "<li>Use this script to <strong>upgrade an existing Drupal installation</strong>. You don't need this script when installing Drupal from scratch.</li>";
@@ -759,6 +764,21 @@ function update_create_cache_tables() {
   return $ret;
 }
 
+/**
+ * Add the update task list to the current page.
+ */
+function update_task_list($active = NULL) {
+  // Default list of tasks.
+  $tasks = array(
+    'info' => 'Overview',
+    'select' => 'Select updates',
+    'run' => 'Run updates',
+    'finished' => 'Review log',
+  );
+
+  drupal_set_content('left', theme_task_list($tasks, $active));
+}
+
 // Some unavoidable errors happen because the database is not yet up-to-date.
 // Our custom error handler is not yet installed, so we just suppress them.
 ini_set('display_errors', FALSE);
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.342
diff -u -F^f -r1.342 theme.inc
--- includes/theme.inc	15 Feb 2007 11:40:17 -0000	1.342
+++ includes/theme.inc	2 Mar 2007 08:25:59 -0000
@@ -423,72 +423,125 @@ function theme_page($content) {
   return $output;
 }
 
+/**
+ * Generate a themed maintenance page.
+ *
+ * Note: this function is not themable.
+ *
+ * @param $content
+ *   The page content to show.
+ * @param $messages
+ *   Whether to output status and error messages.
+ * @param $partial
+ *   Whether to output an unclosed HTML page. Useful for doing output buffering
+ *   tricks, e.g. in update.php.
+ */
 function theme_maintenance_page($content, $messages = TRUE, $partial = FALSE) {
+  // Set required headers.
   drupal_set_header('Content-Type: text/html; charset=utf-8');
   drupal_set_html_head('<style type="text/css" media="all">@import "'. base_path() .'misc/maintenance.css";</style>');
   drupal_set_html_head('<style type="text/css" media="all">@import "'. base_path() . drupal_get_path('module', 'system') .'/defaults.css";</style>');
   drupal_set_html_head('<style type="text/css" media="all">@import "'. base_path() . drupal_get_path('module', 'system') .'/system.css";</style>');
   drupal_set_html_head('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />');
 
-  $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
-  $output .= '<html xmlns="http://www.w3.org/1999/xhtml">';
-  $output .= '<head>';
-  $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>';
-  $output .= drupal_get_html_head();
-  $output .= drupal_get_js();
-  $output .= '</head>';
-  $output .= '<body>';
-  $output .= '<h1>' . drupal_get_title() . '</h1>';
-
-  if ($messages) {
-    $output .= theme('status_messages');
-  }
-
-  $output .= "\n<!-- begin content -->\n";
-  $output .= $content;
-  $output .= "\n<!-- end content -->\n";
-
-  if (!$partial) {
-    $output .= '</body></html>';
+  // Prepare variables.
+  $variables = array(
+    'head_title' => strip_tags(drupal_get_title()),
+    'head' => drupal_get_html_head(),
+    'styles' => '',
+    'scripts' => drupal_get_js(),
+    'sidebar_left' => drupal_get_content('left'),
+    'sidebar_right' => drupal_get_content('right'),
+    'base_path' => base_path(),
+    'path_to_theme' => base_path() .'themes/garland/minnelli',
+    'logo' => base_path() .'themes/garland/minnelli/logo.png',
+    'site_title' => t('Drupal'),
+    'title' => drupal_get_title(),
+    'messages' => theme('status_messages'),
+    'content' => $content,
+  );
+  //  'logo' => '/themes/garland/logo.png',
+
+  // Render simplified PHPTemplate.
+  include_once './themes/engines/phptemplate/phptemplate.engine';
+  $output = _phptemplate_render('misc/maintenance.tpl.php', $variables);
+  
+  // If a partial page was requested, remove body and html closing tags.
+  if ($partial) {
+    $output = preg_replace('@</(body|html)>@i', '', $output);
   }
 
   return $output;
 }
 
+/**
+ * Generate a themed installation page.
+ *
+ * Note: this function is not themable.
+ *
+ * @param $content
+ *   The page content to show.
+ */
 function theme_install_page($content) {
   drupal_set_header('Content-Type: text/html; charset=utf-8');
   drupal_add_css('misc/maintenance.css', 'module', 'all', FALSE);
   drupal_set_html_head('<link rel="shortcut icon" href="'. base_path() .'misc/favicon.ico" type="image/x-icon" />');
-  $output = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
-  $output .= '<html xmlns="http://www.w3.org/1999/xhtml">';
-  $output .= '<head>';
-  $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>';
-  $output .= drupal_get_html_head();
-  $output .= drupal_get_css();
-  $output .= drupal_get_js();
-  $output .= '</head>';
-  $output .= '<body>';
-  $output .= '<h1>' . drupal_get_title() . '</h1>';
 
+  $variables = array(
+    'head_title' => strip_tags(drupal_get_title()),
+    'head' => drupal_get_html_head(),
+    'styles' => drupal_get_css(),
+    'scripts' => drupal_get_js(),
+    'sidebar_left' => drupal_get_content('left'),
+    'sidebar_right' => drupal_get_content('right'),
+    'base_path' => base_path(),
+    'path_to_theme' => base_path() .'themes/garland/minnelli',
+    'logo' => base_path() .'themes/garland/minnelli/logo.png',
+    'site_title' => st('Drupal Installation'),
+    'title' => drupal_get_title(),
+    'messages' => '',
+    'content' => $content,
+  );
+
+  // Special handling of error messages
   $messages = drupal_set_message();
   if (isset($messages['error'])) {
     $title = count($messages['error']) > 1 ? st('The following errors must be resolved before you can continue the installation process') : st('The following error must be resolved before you can continue the installation process');
-    $output .= '<h3>' .$title. ':</h3>';
-    $output .= theme('status_messages', 'error');
+    $variables['messages'] .= '<h3>' .$title. ':</h3>';
+    $variables['messages'] .= theme('status_messages', 'error');
   }
 
+  // Special handling of status messages
   if (isset($messages['status'])) {
     $warnings = count($messages['status']) > 1 ? st('The following installation warnings should be carefully reviewed, but in most cases may be safely ignored') : st('The following installation warning should be carefully reviewed, but in most cases may be safely ignored');
-    $output .= '<h4>' .$title. ':</h4>';
-    $output .= theme('status_messages', 'status');
+    $variables['messages'] .= '<h4>' .$title. ':</h4>';
+    $variables['messages'] .= theme('status_messages', 'status');
   }
 
-  $output .= "\n<!-- begin content -->\n";
-  $output .= $content;
-  $output .= "\n<!-- end content -->\n";
-
-  $output .= '</body></html>';
+  // Render simplified PHPTemplate.
+  include_once './themes/engines/phptemplate/phptemplate.engine';
+  return _phptemplate_render('misc/maintenance.tpl.php', $variables);
+}
 
+/**
+ * Return a themed list of maintenance tasks to perform.
+ *
+ * Note: this function is not themable.
+ */
+function theme_task_list($items, $active = NULL) {
+  $done = isset($items[$active]) || $active == NULL;
+  $output = '<ol class="task-list">';
+  foreach ($items as $k => $item) {
+    if ($active == $k) {
+      $class = 'active';
+      $done = false;
+    }
+    else {
+      $class = $done ? 'done' : '';
+    }
+    $output .= '<li class="'. $class .'">'. $item .'</li>';
+  }
+  $output .= '</ol>';
   return $output;
 }
 
Index: misc/maintenance.css
===================================================================
RCS file: /cvs/drupal/drupal/misc/maintenance.css,v
retrieving revision 1.6
diff -u -F^f -r1.6 maintenance.css
--- misc/maintenance.css	13 Jul 2006 13:11:36 -0000	1.6
+++ misc/maintenance.css	2 Mar 2007 08:25:59 -0000
@@ -1,45 +1,5 @@
 /* $Id: maintenance.css,v 1.6 2006/07/13 13:11:36 dries Exp $ */
 
-body {
-  background: url(druplicon.png) 4.2em 4em no-repeat #fff;
-  color: #000;
-  border: 1px solid #bbb;
-  margin: 3em;
-  padding: 1em 1em 1em 128px;
-  line-height: 1.2;
-}
-h1 {
-  margin: 1.6em 0 1.1em 0;
-}
-h1, h2, h3, h4, h5, h6 {
-  font-family: sans-serif;
-}
-:link {
-  color: #0073ba;
-  font-weight: bold;
-}
-:visited {
-  color: #004975;
-  font-weight: bold;
-}
-
-div.messages {
-  border: 1px solid #ddd;
-  padding: 0.4em;
-  margin-top: 1em;
-}
-
-div.messages li {
-  margin-top: 0.5em;
-  margin-bottom: 0.5em;
-}
-
-div.error {
-  background: #fdd;
-  border: 1px solid #daa;
-  color: #400;
-}
-
 /* Update styles */
 #update-results {
   margin-top: 3em;
Index: misc/maintenance.tpl.php
===================================================================
RCS file: misc/maintenance.tpl.php
diff -N misc/maintenance.tpl.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/maintenance.tpl.php	2 Mar 2007 08:25:59 -0000
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title><?php print $head_title ?></title>
+    <?php print $head ?>
+    <?php print $styles ?>
+    <?php print $scripts ?>
+    <style type="text/css" media="all">@import "<?php print $path_to_theme ?>/style.css";</style>
+    <!--[if lt IE 7]>
+    <style type="text/css" media="all">@import "<?php print $path_to_theme ?>/fix-ie.css";</style>
+    <![endif]-->
+  </head>
+  <body class="<?php
+  $classes = array('', 'sidebar-left', 'sidebar-right', 'sidebar-both');
+  print $classes[((bool)$sidebar_left) + 2 * ((bool)$sidebar_right)];
+  ?>">
+
+<!-- Layout -->
+  <div id="header-region" class="clear-block"></div>
+
+    <div id="wrapper">
+    <div id="container" class="clear-block">
+
+      <div id="header">
+        <div id="logo-floater">
+          <h1><a href="<?php print check_url($base_path) ?>"><img src="<?php print check_url($logo) ?>" alt="Drupal" id="logo" /><span><?php print $site_title ?></span></a></h1>
+        </div>
+      </div> <!-- /header -->
+
+      <?php if ($sidebar_left): ?>
+        <div id="sidebar-left" class="sidebar">
+          <?php print $sidebar_left ?>
+        </div>
+      <?php endif; ?>
+
+      <div id="center"><div id="squeeze"><div class="right-corner"><div class="left-corner">
+          <?php if ($title): print '<h2>'. $title .'</h2>'; endif; ?>
+
+          <?php if ($messages): print $messages; endif; ?>
+          <?php print $content ?>
+          <span class="clear"></span>
+      </div></div></div></div> <!-- /.left-corner, /.right-corner, /#squeeze, /#center -->
+
+      <?php if ($sidebar_right): ?>
+        <div id="sidebar-right" class="sidebar">
+          <?php print $sidebar_right ?>
+        </div>
+      <?php endif; ?>
+
+    </div> <!-- /container -->
+  </div>
+<!-- /layout -->
+
+  </body>
+</html>
Index: modules/system/system.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.css,v
retrieving revision 1.22
diff -u -F^f -r1.22 system.css
--- modules/system/system.css	6 Feb 2007 08:35:13 -0000	1.22
+++ modules/system/system.css	2 Mar 2007 08:25:59 -0000
@@ -66,6 +66,9 @@
   padding: 0;
   list-style: disc;
 }
+ol.task-list li.active {
+  font-weight: bold;
+}
 .form-item {
   margin-top: 1em;
   margin-bottom: 1em;
Index: themes/garland/style.css
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/style.css,v
retrieving revision 1.16
diff -u -F^f -r1.16 style.css
--- themes/garland/style.css	6 Feb 2007 08:35:13 -0000	1.16
+++ themes/garland/style.css	2 Mar 2007 08:25:59 -0000
@@ -96,7 +96,12 @@
   padding: 0;
 }
 
-ul li {
+ol {
+  margin: 0.75em 0 1.25em;
+  padding: 0;
+}
+
+ol li, ul li {
   margin: 0.4em 0 0.4em .5em;
 }
 
@@ -109,7 +114,7 @@
   margin-left: 0em;
 }
 
-ul li, ul.menu li, .item-list ul li, li.leaf {
+ol li, ul li, ul.menu li, .item-list ul li, li.leaf {
   margin: 0.15em 0 0.15em .5em;
 }
 
@@ -120,6 +125,11 @@
   background: transparent url(images/menu-leaf.gif) no-repeat 1px .35em;
 }
 
+ol li {
+  padding: 0 0 .3em;
+  margin-left: 2em;
+}
+
 ul li.expanded {
   background: transparent url(images/menu-expanded.gif) no-repeat 1px .35em;
 }
@@ -138,6 +148,25 @@
   padding: 0 1em 0 0;
 }
 
+ol.task-list {
+  margin-left: 0;
+  list-style-type: none;
+  list-style-image: none;
+}
+ol.task-list li {
+  padding: 0.5em 1em 0.5em 2em;
+}
+ol.task-list li.active {
+  background: transparent url(images/task-list.png) no-repeat 3px 50%;
+}
+ol.task-list li.done {
+  color: #393;
+  background: transparent url(../../misc/watchdog-ok.png) no-repeat 0px 50%;
+}
+ol.task-list li.active {
+  margin-right: 1em;
+}
+
 fieldset ul.clear-block li {
   margin: 0;
   padding: 0;
