Bug 488846, use a custom controller finding method which checks for open context menus for places, r=mak (CLOSED TREE)
authorNeil Deakin <neil@mozilla.com>
Wed, 10 Jun 2009 14:00:30 -0400
changeset 29017 771509552a2ed09a31a27b3983bbe68df1393296
parent 29016 1057ca8f2a91a2c4fb6f2d6f8f721be13c9bbd12
child 29018 cabb8925dcd3d831a244b01e0a37c29b8793c77b
push id7376
push userneil@mozilla.com
push dateWed, 10 Jun 2009 18:01:37 +0000
treeherderautoland@cabb8925dcd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak
bugs488846
milestone1.9.2a1pre
Bug 488846, use a custom controller finding method which checks for open context menus for places, r=mak (CLOSED TREE)
browser/components/places/content/controller.js
browser/components/places/content/menu.xml
browser/components/places/content/placesOverlay.xul
browser/components/places/content/toolbar.xml
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -122,33 +122,37 @@ PlacesController.prototype = {
 
   isCommandEnabled: function PC_isCommandEnabled(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
       return PlacesUIUtils.ptm.numberOfUndoItems > 0;
     case "cmd_redo":
       return PlacesUIUtils.ptm.numberOfRedoItems > 0;
     case "cmd_cut":
+    case "placesCmd_cut":
       var nodes = this._view.getSelectionNodes();
       // If selection includes history nodes there's no reason to allow cut.
       for (var i = 0; i < nodes.length; i++) {
         if (nodes[i].itemId == -1)
           return false;
       }
       // Otherwise fallback to cmd_delete check.
     case "cmd_delete":
+    case "placesCmd_delete":
       return this._hasRemovableSelection(false);
     case "placesCmd_deleteDataHost":
       return this._hasRemovableSelection(false) &&
         !PlacesUIUtils.privateBrowsing.privateBrowsingEnabled;
     case "placesCmd_moveBookmarks":
       return this._hasRemovableSelection(true);
     case "cmd_copy":
+    case "placesCmd_copy":
       return this._view.hasSelection;
     case "cmd_paste":
+    case "placesCmd_paste":
       return this._canInsert(true) && this._isClipboardDataPasteable();
     case "cmd_selectAll":
       if (this._view.selType != "single") {
         var result = this._view.getResult();
         if (result) {
           var container = asContainer(result.root);
           if (container.childCount > 0);
             return true;
@@ -224,25 +228,29 @@ PlacesController.prototype = {
     switch (aCommand) {
     case "cmd_undo":
       PlacesUIUtils.ptm.undoTransaction();
       break;
     case "cmd_redo":
       PlacesUIUtils.ptm.redoTransaction();
       break;
     case "cmd_cut":
+    case "placesCmd_cut":
       this.cut();
       break;
     case "cmd_copy":
+    case "placesCmd_copy":
       this.copy();
       break;
     case "cmd_paste":
+    case "placesCmd_paste":
       this.paste();
       break;
     case "cmd_delete":
+    case "placesCmd_delete":
       this.remove("Remove Selection");
       break;
     case "placesCmd_deleteDataHost":
       var host;
       if (PlacesUtils.nodeIsHost(this._view.selectedNode)) {
         var queries = this._view.selectedNode.getQueries({});
         host = queries[0].domain;
       }
@@ -1599,36 +1607,65 @@ var PlacesControllerDragHelper = {
     var flavourSet = new FlavourSet();
     var acceptedDropFlavours = this.GENERIC_VIEW_DROP_TYPES;
     acceptedDropFlavours.forEach(flavourSet.appendFlavour, flavourSet);
     return this.flavourSet = flavourSet;
   }
 };
 
 function goUpdatePlacesCommands() {
-  var placesController;
-  try {
-    // Or any other command...
-    placesController = top.document.commandDispatcher
-                          .getControllerForCommand("placesCmd_open");
-  }
-  catch(ex) { return; }
+  // Get the controller for one of the places commands.
+  var placesController = doGetPlacesControllerForCommand("placesCmd_open");
+  if (!placesController)
+    return;
 
   function updatePlacesCommand(aCommand) {
-    var enabled = false;
-    if (placesController)
-      enabled = placesController.isCommandEnabled(aCommand);
-    goSetCommandEnabled(aCommand, enabled);
+    goSetCommandEnabled(aCommand, placesController.isCommandEnabled(aCommand));
   }
 
   updatePlacesCommand("placesCmd_open");
   updatePlacesCommand("placesCmd_open:window");
   updatePlacesCommand("placesCmd_open:tab");
   updatePlacesCommand("placesCmd_new:folder");
   updatePlacesCommand("placesCmd_new:bookmark");
   updatePlacesCommand("placesCmd_new:livemark");
   updatePlacesCommand("placesCmd_new:separator");
   updatePlacesCommand("placesCmd_show:info");
   updatePlacesCommand("placesCmd_moveBookmarks");
   updatePlacesCommand("placesCmd_reload");
   updatePlacesCommand("placesCmd_reloadMicrosummary");
   updatePlacesCommand("placesCmd_sortBy:name");
+  updatePlacesCommand("placesCmd_cut");
+  updatePlacesCommand("placesCmd_copy");
+  updatePlacesCommand("placesCmd_paste");
+  updatePlacesCommand("placesCmd_delete");
 }
+
+function doGetPlacesControllerForCommand(aCommand)
+{
+  var placesController = top.document.commandDispatcher
+                            .getControllerForCommand(aCommand);
+  if (!placesController) {
+    // If building commands for a context menu, look for an element in the
+    // current popup.
+    var element = document.popupNode;
+    while (element) {
+      var isContextMenuShown = ("_contextMenuShown" in element) && element._contextMenuShown;
+      // Check for the parent menupopup or the hbox used for toolbars
+      if ((element.localName == "menupopup" || element.localName == "hbox") &&
+          isContextMenuShown) {
+        placesController = element.controllers.getControllerForCommand(aCommand);
+        break;
+      }
+      element = element.parentNode;
+    }
+  }
+
+  return placesController;
+}
+
+function goDoPlacesCommand(aCommand)
+{
+  var controller = doGetPlacesControllerForCommand(aCommand);
+  if (controller && controller.isCommandEnabled(aCommand))
+    controller.doCommand(aCommand);
+}
+
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -1019,21 +1019,17 @@
 
       <property name="selType" readonly="true" onget="return 'single';"/>
 
       <method name="buildContextMenu">
         <parameter name="aPopup"/>
         <body><![CDATA[
           this._ensureInitialized();
           this._contextMenuShown = true;
-          // Activate the controller
-          this.focus();
-          // The above call may not always fire a consumable event for
-          // commandUpdater, so we force a command update.
-          window.updateCommands("focus");
+          window.updateCommands("places");
           return this.controller.buildContextMenu(aPopup);
         ]]></body>
       </method>
 
       <method name="destroyContextMenu">
         <parameter name="aPopup"/>
         <body>
           <![CDATA[
--- a/browser/components/places/content/placesOverlay.xul
+++ b/browser/components/places/content/placesOverlay.xul
@@ -57,50 +57,60 @@
           src="chrome://browser/content/places/controller.js"/>
   <script type="application/x-javascript"
           src="chrome://browser/content/places/treeView.js"/>
   <script type="application/x-javascript"
           src="chrome://global/content/nsDragAndDrop.js"/>
 
   <commandset id="placesCommands"
               commandupdater="true"
-              events="focus,sort"
+              events="focus,sort,places"
               oncommandupdate="goUpdatePlacesCommands();">
     <command id="placesCmd_open"
-             oncommand="goDoCommand('placesCmd_open');"/>
+             oncommand="goDoPlacesCommand('placesCmd_open');"/>
     <command id="placesCmd_open:window"
-             oncommand="goDoCommand('placesCmd_open:window');"/>
+             oncommand="goDoPlacesCommand('placesCmd_open:window');"/>
     <command id="placesCmd_open:tab"
-             oncommand="goDoCommand('placesCmd_open:tab');"/>
+             oncommand="goDoPlacesCommand('placesCmd_open:tab');"/>
 
     <command id="placesCmd_new:bookmark"
-             oncommand="goDoCommand('placesCmd_new:bookmark');"/>
+             oncommand="goDoPlacesCommand('placesCmd_new:bookmark');"/>
     <command id="placesCmd_new:livemark"
-             oncommand="goDoCommand('placesCmd_new:livemark');"/>
+             oncommand="goDoPlacesCommand('placesCmd_new:livemark');"/>
     <command id="placesCmd_new:folder"
-             oncommand="goDoCommand('placesCmd_new:folder');"/>
+             oncommand="goDoPlacesCommand('placesCmd_new:folder');"/>
     <command id="placesCmd_new:separator"
-             oncommand="goDoCommand('placesCmd_new:separator');"/>
+             oncommand="goDoPlacesCommand('placesCmd_new:separator');"/>
     <command id="placesCmd_show:info" 
-             oncommand="goDoCommand('placesCmd_show:info');"/>
+             oncommand="goDoPlacesCommand('placesCmd_show:info');"/>
     <command id="placesCmd_rename"
-             oncommand="goDoCommand('placesCmd_show:info');"
+             oncommand="goDoPlacesCommand('placesCmd_show:info');"
              observes="placesCmd_show:info"/>
     <command id="placesCmd_reload"
-             oncommand="goDoCommand('placesCmd_reload');"/>
+             oncommand="goDoPlacesCommand('placesCmd_reload');"/>
     <command id="placesCmd_reloadMicrosummary"
-             oncommand="goDoCommand('placesCmd_reloadMicrosummary');"/>
+             oncommand="goDoPlacesCommand('placesCmd_reloadMicrosummary');"/>
     <command id="placesCmd_sortBy:name"
-             oncommand="goDoCommand('placesCmd_sortBy:name');"/>
+             oncommand="goDoPlacesCommand('placesCmd_sortBy:name');"/>
     <command id="placesCmd_moveBookmarks"
-             oncommand="goDoCommand('placesCmd_moveBookmarks');"/>
+             oncommand="goDoPlacesCommand('placesCmd_moveBookmarks');"/>
     <command id="placesCmd_deleteDataHost"
-             oncommand="goDoCommand('placesCmd_deleteDataHost');"/>
+             oncommand="goDoPlacesCommand('placesCmd_deleteDataHost');"/>
     <command id="placesCmd_createBookmark"
-             oncommand="goDoCommand('placesCmd_createBookmark');"/>
+             oncommand="goDoPlacesCommand('placesCmd_createBookmark');"/>
+
+    <!-- Special versions of cut/copy/paste/delete which check for an open context menu. -->
+    <command id="placesCmd_cut"
+             oncommand="goDoPlacesCommand('placesCmd_cut');"/>
+    <command id="placesCmd_copy"
+             oncommand="goDoPlacesCommand('placesCmd_copy');"/>
+    <command id="placesCmd_paste"
+             oncommand="goDoPlacesCommand('placesCmd_paste');"/>
+    <command id="placesCmd_delete"
+             oncommand="goDoPlacesCommand('placesCmd_delete');"/>
   </commandset>
 
   <popup id="placesContext"
          onpopupshowing="this._view = PlacesUIUtils.getViewForNode(document.popupNode);
                          return this._view.buildContextMenu(this);"
          onpopuphiding="this._view.destroyContextMenu();">
     <menuitem id="placesContext_open"
               command="placesCmd_open"
@@ -160,44 +170,44 @@
     <menuseparator id="placesContext_newSeparator"/>
     <menuitem id="placesContext_createBookmark"
               command="placesCmd_createBookmark"
               label="&cmd.bookmarkLink.label;"
               accesskey="&cmd.bookmarkLink.accesskey;"
               selection="link"
               forcehideselection="bookmark|tagChild"/>
     <menuitem id="placesContext_cut"
-              command="cmd_cut"
+              command="placesCmd_cut"
               label="&cutCmd.label;"
               accesskey="&cutCmd.accesskey;" 
               closemenu="single"
               selection="bookmark|folder|separator|query"
               forcehideselection="tagChild|livemarkChild"/>
     <menuitem id="placesContext_copy"
-              command="cmd_copy"
+              command="placesCmd_copy"
               label="&copyCmd.label;"
               closemenu="single"
               accesskey="&copyCmd.accesskey;" 
               selection="any"/>
     <menuitem id="placesContext_paste"
-              command="cmd_paste"
+              command="placesCmd_paste"
               label="&pasteCmd.label;"
               closemenu="single"
               accesskey="&pasteCmd.accesskey;"
               selection="any"
               hideifnoinsertionpoint="true"/>
     <menuseparator id="placesContext_editSeparator"/>
     <menuitem id="placesContext_delete"
-              command="cmd_delete"
+              command="placesCmd_delete"
               label="&deleteCmd.label;"
               accesskey="&deleteCmd.accesskey;"
               closemenu="single"
               selection="bookmark|tagChild|folder|query|dynamiccontainer|separator|host"/>
     <menuitem id="placesContext_delete_history"
-              command="cmd_delete"
+              command="placesCmd_delete"
               label="&cmd.delete.label;"
               accesskey="&cmd.delete.accesskey;"
               closemenu="single"
               selection="link"
               forcehideselection="bookmark"/>
     <menuitem id="placesContext_deleteHost"
               command="placesCmd_deleteDataHost"
               label="&cmd.deleteDomainData.label;"
--- a/browser/components/places/content/toolbar.xml
+++ b/browser/components/places/content/toolbar.xml
@@ -720,21 +720,17 @@
       })]]></field>
 
       <property name="selType" onget="return 'single';"/>
 
       <method name="buildContextMenu">
         <parameter name="aPopup"/>
         <body><![CDATA[
           this._contextMenuShown = true;
-          // Activate the controller
-          this.focus();
-          // The above call may not always fire a consumable event for
-          // commandUpdater, so we force a command update.
-          window.updateCommands("focus");
+          window.updateCommands("places");
           return this.controller.buildContextMenu(aPopup);
         ]]></body>
       </method>
 
       <method name="destroyContextMenu">
         <parameter name="aPopup"/>
         <body><![CDATA[
           this._contextMenuShown = false;