some changes to support saved queries for new TKO
-migration to add saved_queries table.  this is different from the existing query_history table.  this feature is incompatible with the old one and I didn't want to interfere with the old one.
-various modifications to history handling across the board to allow better support for saved queries (the url will show up as just "saved_query=123", without all the extra crap)
-refactoring of apache_auth.py to allow new TKO to use it without using all the Django auth crap


git-svn-id: http://test.kernel.org/svn/autotest/trunk@1810 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/frontend/apache_auth.py b/frontend/apache_auth.py
index a74dda3..1c63f9e 100644
--- a/frontend/apache_auth.py
+++ b/frontend/apache_auth.py
@@ -42,12 +42,13 @@
             return None
 
 
-class ApacheAuthMiddleware(object):
+class GetApacheUserMiddleware(object):
     """
     Middleware for use when Apache is doing authentication.  Looks for
-    REQUEST_USER in requests and logs that user in.  If no such header is
-    found, looks for HTTP_AUTHORIZATION header with username to login (this
-    allows CLI to authenticate).
+    REMOTE_USER in headers and passed the username found to
+    thread_local.set_user().  If no such header is found, looks for
+    HTTP_AUTHORIZATION header with username (this allows CLI to authenticate).
+    If neither of those are found, DEBUG_USER is used.
     """
 
     def process_request(self, request):
@@ -60,8 +61,20 @@
         if user is None:
             # no user info - assume we're in development mode
             user = DEBUG_USER
-        user_object = auth.authenticate(username=user,
+        thread_local.set_user(user)
+
+
+class ApacheAuthMiddleware(GetApacheUserMiddleware):
+    """
+    Like GetApacheUserMiddleware, but also logs the user into Django's auth
+    system, and replaces the username in thread_local with the actual User model
+    object.
+    """
+
+    def process_request(self, request):
+        super(ApacheAuthMiddleware, self).process_request(request)
+        username = thread_local.get_user()
+        user_object = auth.authenticate(username=username,
                                         password='')
         auth.login(request, user_object)
-        thread_local.set_user(models.User.objects.get(login=user))
-        return None
+        thread_local.set_user(models.User.objects.get(login=username))
diff --git a/frontend/client/src/autotest/afe/AfeClient.java b/frontend/client/src/autotest/afe/AfeClient.java
index 424dadc..ce50977 100644
--- a/frontend/client/src/autotest/afe/AfeClient.java
+++ b/frontend/client/src/autotest/afe/AfeClient.java
@@ -5,6 +5,7 @@
 import autotest.afe.HostListView.HostListListener;
 import autotest.afe.JobDetailView.JobDetailListener;
 import autotest.afe.JobListView.JobSelectListener;
+import autotest.common.CustomHistory;
 import autotest.common.JsonRpcProxy;
 import autotest.common.StaticDataRepository;
 import autotest.common.ui.CustomTabPanel;
@@ -82,6 +83,7 @@
         
         final RootPanel tabsRoot = RootPanel.get("tabs");
         tabsRoot.add(mainTabPanel);
+        CustomHistory.processInitialToken();
         mainTabPanel.initialize();
         tabsRoot.setStyleName("");
     }
diff --git a/frontend/client/src/autotest/common/CustomHistory.java b/frontend/client/src/autotest/common/CustomHistory.java
index 7321b87..b34d6a8 100644
--- a/frontend/client/src/autotest/common/CustomHistory.java
+++ b/frontend/client/src/autotest/common/CustomHistory.java
@@ -5,6 +5,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Wrapper around gwt.user.client.History that won't call onHistoryChanged for
@@ -14,29 +15,61 @@
 public class CustomHistory implements HistoryListener {
     protected static final CustomHistory theInstance = new CustomHistory();
     
-    protected List<HistoryListener> listeners = new ArrayList<HistoryListener>();
-    protected boolean ignoreNextChange = false;
+    private List<CustomHistoryListener> listeners = new ArrayList<CustomHistoryListener>();
+    private boolean ignoreNextChange = false;
+    private String lastHistoryToken = "";
     
-    protected CustomHistory() {
+    public static interface CustomHistoryListener {
+        public void onHistoryChanged(Map<String, String> arguments);
+    }
+    
+    private CustomHistory() {
         History.addHistoryListener(this);
     }
     
+    /**
+     * Allows programmatic simulation of history changes, without actually changing history or the 
+     * URL.
+     */
+    public static void simulateHistoryToken(String token) {
+        theInstance.onHistoryChanged(token);
+    }
+    
+    public static void processInitialToken() {
+        String initialToken = History.getToken();
+        if (!initialToken.equals("")) {
+            theInstance.onHistoryChanged(initialToken);
+        }
+    }
+    
     public void onHistoryChanged(String historyToken) {
+        lastHistoryToken = historyToken;
         if (ignoreNextChange) {
             ignoreNextChange = false;
             return;
         }
+        
+        Map<String, String> arguments;
+        try {
+            arguments = Utils.decodeUrlArguments(historyToken);
+        } catch (IllegalArgumentException exc) {
+            return;
+        }
 
-        for (HistoryListener listener : listeners) {
-            listener.onHistoryChanged(historyToken);
+        for (CustomHistoryListener listener : listeners) {
+            listener.onHistoryChanged(arguments);
         }
     }
+    
+    public static String getLastHistoryToken() {
+        return theInstance.lastHistoryToken;
+    }
 
-    public static void addHistoryListener(HistoryListener listener) {
+    public static void addHistoryListener(CustomHistoryListener listener) {
         theInstance.listeners.add(listener);
     }
     
-    public static void removeHistoryListener(HistoryListener listener) {
+    public static void removeHistoryListener(CustomHistoryListener listener) {
         theInstance.listeners.remove(listener);
     }
     
diff --git a/frontend/client/src/autotest/common/ui/CustomTabPanel.java b/frontend/client/src/autotest/common/ui/CustomTabPanel.java
index 11d647d..86907fd 100644
--- a/frontend/client/src/autotest/common/ui/CustomTabPanel.java
+++ b/frontend/client/src/autotest/common/ui/CustomTabPanel.java
@@ -1,10 +1,8 @@
 package autotest.common.ui;
 
 import autotest.common.CustomHistory;
-import autotest.common.Utils;
+import autotest.common.CustomHistory.CustomHistoryListener;
 
-import com.google.gwt.user.client.History;
-import com.google.gwt.user.client.HistoryListener;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.ClickListener;
 import com.google.gwt.user.client.ui.Composite;
@@ -22,13 +20,14 @@
 import java.util.List;
 import java.util.Map;
 
-public class CustomTabPanel extends Composite implements HistoryListener {
+public class CustomTabPanel extends Composite implements CustomHistoryListener, TabListener {
     protected TabPanel tabPanel = new TabPanel();
     protected Panel otherWidgetsPanel = new HorizontalPanel();
     private Panel commonAreaPanel = new VerticalPanel();
     protected Button refreshButton = new Button("Refresh");
     protected int topBarHeight = 0;
     protected List<TabView> tabViews = new ArrayList<TabView>();
+    private boolean doUpdateHistory = true;
     
     public CustomTabPanel() {
         VerticalPanel container = new VerticalPanel();
@@ -53,20 +52,7 @@
         bottom.add(tabDeck);
         bottom.setCellHeight(tabDeck, "100%");
         
-        tabPanel.addTabListener(new TabListener() {
-            public boolean onBeforeTabSelected(SourcesTabEvents sender,
-                                               int tabIndex) {
-                // do nothing if the user clicks the selected tab
-                if (tabPanel.getTabBar().getSelectedTab() == tabIndex)
-                    return false;
-                tabViews.get(tabIndex).ensureInitialized();
-                tabViews.get(tabIndex).display();
-                return true;
-            }
-            public void onTabSelected(SourcesTabEvents sender, int tabIndex) {
-                tabViews.get(tabIndex).updateHistory();
-            }
-        });
+        tabPanel.addTabListener(this);
         
         // transfer the DeckPanel's class to the entire bottom panel
         String tabDeckClass = tabDeck.getStyleName();
@@ -90,11 +76,6 @@
      * This must be called after this widget has been added to the page.
      */
     public void initialize() {
-        String initialToken = History.getToken();
-        if (!initialToken.equals("")) {
-            onHistoryChanged(initialToken);
-        }
-        
         // if the history token didn't provide a selected tab, default to the 
         // first tab
         if (getSelectedTabView() == null)
@@ -140,14 +121,7 @@
         return commonAreaPanel;
     }
 
-    public void onHistoryChanged(String historyToken) {
-        Map<String, String> arguments;
-        try {
-            arguments = Utils.decodeUrlArguments(historyToken);
-        } catch (IllegalArgumentException exc) {
-            return;
-        }
-        
+    public void onHistoryChanged(Map<String, String> arguments) {
         String tabId = arguments.get("tab_id");
         if (tabId == null) {
             return;
@@ -158,13 +132,30 @@
                 tabView.ensureInitialized();
                 tabView.handleHistoryArguments(arguments);
                 
-                if (getSelectedTabView() != tabView)
+                if (getSelectedTabView() != tabView) {
+                    doUpdateHistory = false;
                     selectTabView(tabView);
-                else
+                    doUpdateHistory = true;
+                } else {
                     tabView.refresh();
+                }
                 
                 return;
             }
         }
     }
+
+    public boolean onBeforeTabSelected(SourcesTabEvents sender, int tabIndex) {
+        // do nothing if the user clicks the selected tab
+        if (tabPanel.getTabBar().getSelectedTab() == tabIndex)
+            return false;
+        tabViews.get(tabIndex).ensureInitialized();
+        tabViews.get(tabIndex).display();
+        return true;
+    }
+
+    public void onTabSelected(SourcesTabEvents sender, int tabIndex) {
+        if (doUpdateHistory)
+            tabViews.get(tabIndex).updateHistory();
+    }
 }