home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / firefox-3.0.14 / chrome / browser.jar / content / browser / places / tree.xml < prev    next >
Encoding:
Extensible Markup Language  |  2008-04-28  |  27.1 KB  |  750 lines

  1. <?xml version="1.0"?>
  2.  
  3.  
  4. <bindings id="placesTreeBindings"
  5.           xmlns="http://www.mozilla.org/xbl"
  6.           xmlns:xbl="http://www.mozilla.org/xbl"
  7.           xmlns:html="http://www.w3.org/1999/xhtml"
  8.           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  9.   
  10.   <binding id="places-tree" extends="chrome://global/content/bindings/tree.xml#tree">
  11.     <implementation>
  12.       <constructor><![CDATA[
  13.         // Force an initial build.
  14.         if (this.place)
  15.           this.place = this.place;
  16.       ]]></constructor>
  17.  
  18.       <destructor><![CDATA[
  19.         // Break the treeviewer->result->treeviewer cycle.
  20.         // Note: unsetting the result's viewer also unsets
  21.         // the viewer's reference to our treeBoxObject.
  22.         var result = this.getResult();
  23.         if (result)
  24.           result.viewer = null;
  25.         this.view = null;
  26.       ]]></destructor>
  27.  
  28.       <property name="controller"
  29.                 readonly="true"
  30.                 onget="return this._controller;"/>
  31.  
  32.       <!-- overriding -->
  33.       <property name="view">
  34.         <getter><![CDATA[
  35.           return this.treeBoxObject.view.QueryInterface(Ci.nsINavHistoryResultTreeViewer);
  36.         ]]></getter>
  37.         <setter><![CDATA[ 
  38.           return this.treeBoxObject.view = val;
  39.         ]]></setter>
  40.       </property>
  41.  
  42.       <method name="getBestOptions">
  43.         <body><![CDATA[
  44.           // Get the best set of grouping options to use, either reuse the 
  45.           // existing ones or create new ones. 
  46.           var options = this.getResult().queryOptions;
  47.           if (!options)
  48.             options = PlacesUtils.history.getNewQueryOptions();
  49.           return options;
  50.         ]]></body>
  51.       </method>
  52.  
  53.       <method name="applyFilter">
  54.         <parameter name="filterString"/>
  55.         <parameter name="folderRestrict"/>
  56.         <body><![CDATA[
  57.           // preserve grouping
  58.           var queryNode = asQuery(this.getResultNode());
  59.           var options = queryNode.queryOptions.clone();
  60.  
  61.           var query = PlacesUtils.history.getNewQuery();
  62.           query.searchTerms = filterString;
  63.  
  64.           if (folderRestrict) {
  65.             query.setFolders(folderRestrict, folderRestrict.length);
  66.             options.queryType = options.QUERY_TYPE_BOOKMARKS;
  67.           }
  68.  
  69.           this.load([query], options);
  70.         ]]></body>
  71.       </method>
  72.       
  73.       <method name="load">
  74.         <parameter name="queries"/>
  75.         <parameter name="options"/>
  76.         <body><![CDATA[
  77.           var result = PlacesUtils.history.executeQueries(queries, queries.length, 
  78.                                                           options);
  79.           var callback;
  80.           if (this.flatList) {
  81.             var onOpenFlatContainer = this.onOpenFlatContainer;
  82.             if (onOpenFlatContainer)
  83.               callback = new Function("aContainer", onOpenFlatContainer);
  84.           }
  85.  
  86.           var treeView = new PlacesTreeView(this.showRoot, this.flatList, callback);
  87.           result.viewer = treeView;
  88.           this.view = treeView;
  89.           if (!this._controller) {
  90.             this._controller = new PlacesController(this);
  91.             this.controllers.appendController(this._controller);
  92.           }
  93.           this._cachedInsertionPoint = undefined;
  94.         ]]></body>
  95.       </method>
  96.  
  97.       <property name="showRoot">
  98.         <getter><![CDATA[
  99.           return this.getAttribute("showRoot") == "true";
  100.         ]]></getter>
  101.         <setter><![CDATA[
  102.           if (this.showRoot != val) {
  103.             this.setAttribute("showRoot", val);
  104.             // reload with the last place set
  105.             if (this.place)
  106.               this.place = this.place;
  107.           }
  108.           return val;
  109.         ]]></setter>
  110.       </property>
  111.  
  112.       <property name="flatList">
  113.         <getter><![CDATA[
  114.           return this.getAttribute("flatList") == "true";
  115.         ]]></getter>
  116.         <setter><![CDATA[
  117.           if (this.flatList != val) {
  118.             this.setAttribute("flatList", val);
  119.             // reload with the last place set
  120.             if (this.place)
  121.               this.place = this.place;
  122.           }
  123.           return val;
  124.         ]]></setter>
  125.       </property>
  126.  
  127.       <property name="onOpenFlatContainer">
  128.         <getter><![CDATA[
  129.           return this.getAttribute("onopenflatcontainer");
  130.         ]]></getter>
  131.         <setter><![CDATA[
  132.           if (this.onOpenFlatContainer != val) {
  133.             this.setAttribute("onopenflatcontainer", val);
  134.             // reload with the last place set
  135.             if (this.place)
  136.               this.place = this.place;
  137.           }
  138.           return val;
  139.         ]]></setter>
  140.       </property>
  141.  
  142.       <!-- 
  143.         Causes a particular node represented by the specified placeURI to be
  144.         selected in the tree. All containers above the node in the hierarchy
  145.         will be opened, so that the node is visible. 
  146.         -->
  147.       <method name="selectPlaceURI">
  148.         <parameter name="placeURI"/>
  149.         <body><![CDATA[
  150.           // Do nothing if a node matching the given uri is already selected
  151.           if (this.hasSelection && this.selectedNode.uri == placeURI)
  152.             return;
  153.  
  154.           function findNode(container, placeURI, nodesURIChecked) {
  155.             var containerURI = container.uri;
  156.             if (containerURI == placeURI)
  157.               return container;
  158.             if (nodesURIChecked.indexOf(containerURI) != -1)
  159.               return null;
  160.  
  161.             // never check the contents of the same query
  162.             nodesURIChecked.push(containerURI);
  163.  
  164.             var wasOpen = container.containerOpen;
  165.             if (!wasOpen)
  166.               container.containerOpen = true;
  167.             for (var i = 0; i < container.childCount; ++i) {
  168.               var child = container.getChild(i);
  169.               var childURI = child.uri;
  170.               if (childURI == placeURI)
  171.                 return child;
  172.               else if (PlacesUtils.nodeIsContainer(child)) {
  173.                 var nested = findNode(asContainer(child), placeURI, nodesURIChecked);
  174.                 if (nested)
  175.                   return nested;
  176.               }
  177.             }
  178.  
  179.             if (!wasOpen)
  180.               container.containerOpen = false;
  181.  
  182.             return null;
  183.           }
  184.  
  185.           var container = this.getResultNode();
  186.           NS_ASSERT(container, "No result, cannot select place URI!");
  187.           if (!container)
  188.             return;
  189.  
  190.           var child = findNode(container, placeURI, []);
  191.           if (child)
  192.             this.selectNode(child);
  193.           else {
  194.             // If the specified child could not be located, clear the selection
  195.             var selection = this.view.selection;
  196.             selection.clearSelection();
  197.           }
  198.         ]]></body>
  199.       </method>
  200.  
  201.       <!-- 
  202.         Causes a particular node to be selected in the tree, resulting in all 
  203.         containers above the node in the hierarchy to be opened, so that the
  204.         node is visible. 
  205.         -->
  206.       <method name="selectNode">
  207.         <parameter name="node"/>
  208.         <body><![CDATA[ 
  209.           var view = this.getResultView();
  210.  
  211.           var parent = node.parent;
  212.           if (parent && !parent.containerOpen) {
  213.             // Build a list of all of the nodes that are the parent of this one 
  214.             // in the result. 
  215.             var parents = [];
  216.             var root = this.getResultNode();
  217.             while (parent && parent != root) {
  218.               parents.push(parent);
  219.               parent = parent.parent;
  220.             }
  221.  
  222.             // Walk the list backwards (opening from the root of the hierarchy)
  223.             // opening each folder as we go.
  224.             for (var i = parents.length - 1; i >= 0; --i) {
  225.               var index = view.treeIndexForNode(parents[i]);
  226.               if (view.isContainer(index) && !view.isContainerOpen(index)) 
  227.                 view.toggleOpenState(index);
  228.             }
  229.             // Select the specified node...
  230.           }
  231.  
  232.           var index = view.treeIndexForNode(node);
  233.           view.selection.select(index);
  234.           // ... and ensure it's visible, not scrolled off somewhere. 
  235.           this.treeBoxObject.ensureRowIsVisible(index);
  236.         ]]></body>
  237.       </method>
  238.  
  239.       <!-- nsIPlacesView -->
  240.       <method name="getResult">
  241.         <body><![CDATA[
  242.           try {
  243.             return this.view.QueryInterface(Ci.nsINavHistoryResultViewer).result;
  244.           }
  245.           catch (e) {
  246.             return null;
  247.           }
  248.         ]]></body>
  249.       </method>
  250.  
  251.       <!-- nsIPlacesView -->
  252.       <method name="getResultNode">
  253.         <body><![CDATA[
  254.           return this.getResult().root;
  255.         ]]></body>
  256.       </method>
  257.  
  258.       <method name="getResultView">
  259.         <body><![CDATA[
  260.           try {
  261.             return this.view.QueryInterface(Ci.nsINavHistoryResultTreeViewer);
  262.           }
  263.           catch (e) {
  264.           }
  265.           return null;
  266.         ]]></body>
  267.       </method>
  268.  
  269.       <!-- nsIPlacesView -->
  270.       <property name="place">
  271.         <getter><![CDATA[
  272.           return this.getAttribute("place");
  273.         ]]></getter>
  274.         <setter><![CDATA[
  275.           this.setAttribute("place", val);
  276.  
  277.           var queriesRef = { };
  278.           var queryCountRef = { };
  279.           var optionsRef = { };
  280.           PlacesUtils.history.queryStringToQueries(val, queriesRef, queryCountRef, optionsRef);
  281.           if (queryCountRef.value == 0)
  282.             queriesRef.value = [PlacesUtils.history.getNewQuery()];
  283.           if (!optionsRef.value)
  284.             optionsRef.value = PlacesUtils.history.getNewQueryOptions();
  285.  
  286.           this.load(queriesRef.value, optionsRef.value);
  287.  
  288.           return val;
  289.         ]]></setter>
  290.       </property>
  291.  
  292.       <!-- nsIPlacesView -->
  293.       <property name="hasSelection">
  294.         <getter><![CDATA[
  295.           return this.view.selection.count >= 1;
  296.         ]]></getter>
  297.       </property>
  298.       
  299.       <!-- nsIPlacesView -->
  300.       <method name="getSelectionNodes">
  301.         <body><![CDATA[ 
  302.           var selection = this.view.selection;
  303.           var rc = selection.getRangeCount();
  304.           var nodes = [];
  305.           var resultview = this.getResultView();
  306.           for (var i = 0; i < rc; ++i) {
  307.             var min = { }, max = { };
  308.             selection.getRangeAt(i, min, max);
  309.  
  310.             for (var j = min.value; j <= max.value; ++j)
  311.               nodes.push(resultview.nodeForTreeIndex(j));
  312.           }
  313.           return nodes;
  314.         ]]></body>
  315.       </method>
  316.  
  317.       <!-- nsIPlacesView -->
  318.       <method name="getRemovableSelectionRanges">
  319.         <body><![CDATA[ 
  320.           // This function exists in addition to getSelectionNodes because it
  321.           // encodes selection ranges (which only occur in list views) into
  322.           // the return value. For each removed range, the index at which items
  323.           // will be re-inserted upon the remove transaction being performed is
  324.           // the first index of the range, so that the view updates correctly. 
  325.           //
  326.           // For example, if we remove rows 2,3,4 and 7,8 from a list, when we
  327.           // undo that operation, if we insert what was at row 3 at row 3 again,
  328.           // it will show up _after_ the item that was at row 5. So we need to 
  329.           // insert all items at row 2, and the tree view will update correctly. 
  330.           //
  331.           // Also, this function collapses the selection to remove redundant
  332.           // data, e.g. when deleting this selection:
  333.           //
  334.           //      http://www.foo.com/
  335.           //  (-) Some Folder
  336.           //        http://www.bar.com/
  337.           //
  338.           // ... returning http://www.bar.com/ as part of the selection is 
  339.           // redundant because it is implied by removing "Some Folder". We 
  340.           // filter out all such redundancies since some partial amount of
  341.           // the folder's children may be selected.          
  342.           //
  343.           var selection = this.view.selection;
  344.           var rc = selection.getRangeCount();
  345.           var nodes = [];
  346.           var resultview = this.getResultView();
  347.           // This list is kept independently of the range selected (i.e. OUTSIDE
  348.           // the for loop) since the row index of a container is unique for the
  349.           // entire view, and we could have some really wacky selection and we
  350.           // don't want to blow up.
  351.           var containers = { };
  352.           for (var i = 0; i < rc; ++i) {
  353.             var range = [];
  354.             var min = { }, max = { };
  355.             selection.getRangeAt(i, min, max);
  356.             
  357.             for (var j = min.value; j <= max.value; ++j) {
  358.               if (this.view.isContainer(j))
  359.                 containers[j] = true;
  360.               if (!(this.view.getParentIndex(j) in containers))
  361.                 range.push(resultview.nodeForTreeIndex(j));
  362.             }
  363.             nodes.push(range);
  364.           }
  365.           return nodes;
  366.         ]]></body>
  367.       </method>
  368.       
  369.       <!-- nsIPlacesView -->
  370.       <method name="getDragableSelection">
  371.         <body><![CDATA[
  372.           return this.getSelectionNodes();
  373.         ]]></body>
  374.       </method>
  375.       
  376.       <!-- nsIPlacesView -->
  377.       <property name="selectedNode">
  378.         <getter><![CDATA[
  379.           var view = this.view;
  380.           if (view.selection.count != 1)
  381.             return null;
  382.  
  383.           var selection = view.selection;
  384.           var min = { }, max = { };
  385.           selection.getRangeAt(0, min, max);
  386.  
  387.           return this.getResultView().nodeForTreeIndex(min.value);
  388.         ]]></getter>
  389.       </property>
  390.  
  391.       <!-- nsIPlacesView -->
  392.       <property name="insertionPoint">
  393.         <getter><![CDATA[
  394.           // invalidated on selection and focus changes
  395.           if (this._cachedInsertionPoint !== undefined)
  396.             return this._cachedInsertionPoint;
  397.  
  398.           // there is no insertion point for history queries
  399.           // so bail out now and save a lot of work when updating commands
  400.           var resultNode = this.getResultNode();
  401.           if (PlacesUtils.nodeIsQuery(resultNode)) {
  402.             var options = asQuery(resultNode).queryOptions;
  403.             if (options.queryType == options.QUERY_TYPE_HISTORY)
  404.               return this._cachedInsertionPoint = null;
  405.           }
  406.  
  407.           var orientation = Ci.nsITreeView.DROP_BEFORE;
  408.           // If there is no selection, insert at the end of the container. 
  409.           if (!this.hasSelection) {
  410.             var index = this.view.rowCount - 1;
  411.             this._cachedInsertionPoint =
  412.               this._getInsertionPoint(index, orientation);
  413.             return this._cachedInsertionPoint;
  414.           }
  415.  
  416.           // This is a two-part process. The first part is determining the drop
  417.           // orientation.
  418.           // * The default orientation is to drop _before_ the selected item.
  419.           // * If the selected item is a container, the default orientation
  420.           //   is to drop _into_ that container.
  421.           //
  422.           // Warning: It may be tempting to use tree indexes in this code, but
  423.           //          you must not, since the tree is nested and as your tree 
  424.           //          index may change when folders before you are opened and
  425.           //          closed. You must convert your tree index to a node, and
  426.           //          then use getIndexOfNode to find your absolute index in
  427.           //          the parent container instead. 
  428.           //
  429.           var resultView = this.getResultView();
  430.           var selection = resultView.selection;
  431.           var rc = selection.getRangeCount();
  432.           var min = { }, max = { };
  433.           selection.getRangeAt(rc - 1, min, max);
  434.           
  435.           // If the sole selection is a container, and we are not in
  436.           // a flatlist, insert into it.
  437.           // Note that this only applies to _single_ selections,
  438.           // if the last element within a multi-selection is a
  439.           // container, insert _adjacent_ to the selection.
  440.           //
  441.           // If the sole selection is the bookmarks toolbar folder, we insert
  442.           // into it even if it is not opened
  443.           var itemId =
  444.             PlacesUtils.getConcreteItemId(resultView.nodeForTreeIndex(max.value));
  445.           if (selection.count == 1 && resultView.isContainer(max.value) &&
  446.               !this.flatList)
  447.             orientation = Ci.nsITreeView.DROP_ON;
  448.  
  449.           this._cachedInsertionPoint =
  450.             this._getInsertionPoint(max.value, orientation);
  451.           return this._cachedInsertionPoint;
  452.         ]]></getter>
  453.       </property>
  454.       
  455.       <method name="_disallowInsertion">
  456.         <parameter name="aContainer"/>
  457.         <body><![CDATA[
  458.           // allow dropping into Tag containers
  459.           if (PlacesUtils.nodeIsTagQuery(aContainer))
  460.             return false;
  461.           // Disallow insertion of items under readonly folders
  462.           return (!PlacesUtils.nodeIsFolder(aContainer) ||
  463.                    PlacesUtils.nodeIsReadOnly(aContainer));
  464.         ]]></body>
  465.       </method>
  466.  
  467.       <method name="_getInsertionPoint">
  468.         <parameter name="index"/>
  469.         <parameter name="orientation"/>
  470.         <body><![CDATA[ 
  471.           var result = this.getResult();
  472.           var resultview = this.getResultView();
  473.           var container = result.root;
  474.           var dropNearItemId = -1;
  475.           NS_ASSERT(container, "null container");
  476.           // When there's no selection, assume the container is the container
  477.           // the view is populated from (i.e. the result's itemId).
  478.           if (index != -1) {
  479.             var lastSelected = resultview.nodeForTreeIndex(index);
  480.             if (resultview.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
  481.               // If the last selected item is an open container, append _into_
  482.               // it, rather than insert adjacent to it. 
  483.               container = lastSelected;
  484.               index = -1;
  485.             }
  486.             else if (!this._disallowInsertion(lastSelected) &&
  487.                      lastSelected.containerOpen &&
  488.                      orientation == Ci.nsITreeView.DROP_AFTER &&
  489.                      lastSelected.hasChildren) {
  490.              // If the last selected item is an open container and the user is
  491.              // trying to drag into it as a first item, really insert into it.
  492.              container = lastSelected;
  493.              orientation = Ci.nsITreeView.DROP_BEFORE;
  494.              index = 0;
  495.             }
  496.             else {
  497.               // Use the last-selected node's container unless the root node
  498.               // is selected, in which case we use the root node itself as the
  499.               // insertion point.
  500.               container = lastSelected.parent || container;
  501.  
  502.               // avoid the potentially expensive call to getIndexOfNode() 
  503.               // if we know this container doesn't allow insertion
  504.               if (this._disallowInsertion(container))
  505.                 return null;
  506.  
  507.               var queryOptions = asQuery(result.root).queryOptions;
  508.               if (queryOptions.sortingMode !=
  509.                     Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
  510.                 // If we are within a sorted view, insert at the end
  511.                 index = -1;
  512.               }
  513.               else if (queryOptions.excludeItems ||
  514.                        queryOptions.excludeQueries ||
  515.                        queryOptions.excludeReadOnlyFolders) {
  516.                 // Some item may be invisible, insert near last selected one.
  517.                 // We don't replace index here to avoid requests to the db,
  518.                 // instead it will be calculated later by the controller.
  519.                 index = -1;
  520.                 dropNearItemId = lastSelected.itemId;
  521.               }
  522.               else {
  523.                 var lsi = PlacesUtils.getIndexOfNode(lastSelected);
  524.                 index = orientation == Ci.nsITreeView.DROP_BEFORE ? lsi : lsi + 1;
  525.               }
  526.             }
  527.           }
  528.  
  529.           if (this._disallowInsertion(container))
  530.             return null;
  531.  
  532.           return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
  533.                                     index, orientation,
  534.                                     PlacesUtils.nodeIsTagQuery(container),
  535.                                     dropNearItemId);
  536.         ]]></body>
  537.       </method>
  538.  
  539.       <!-- nsIPlacesView -->
  540.       <method name="selectAll">
  541.         <body><![CDATA[ 
  542.           this.view.selection.selectAll();
  543.         ]]></body>
  544.       </method>
  545.  
  546.       <!-- This method will select the first node in the tree that matches
  547.            each given item id. It will open any parent nodes that it needs
  548.            to in order to show the selected items.
  549.       -->
  550.       <method name="selectItems">
  551.         <parameter name="aIDs"/>
  552.         <body><![CDATA[
  553.           var ids = aIDs; // don't manipulate the caller's array
  554.  
  555.           // Array of nodes found by findNodes which are to be selected
  556.           var nodes = [];
  557.  
  558.           // A set of URIs of container-nodes that were previously searched,
  559.           // and thus shouldn't be searched again. This is empty at the initial
  560.           // start of the recursion and gets filled in as the recursion
  561.           // progresses.
  562.           var nodesURIChecked = [];
  563.  
  564.           /**
  565.            * Recursively search through a node's children for items
  566.            * with the given IDs. When a matching item is found, remove its ID
  567.            * from the IDs array, and add the found node to the nodes dictionary.
  568.            *
  569.            * NOTE: This method will leave open any node that had matching items
  570.            * in its subtree.
  571.            */
  572.           function findNodes(node) {
  573.             var foundOne = false;
  574.             // See if node matches an ID we wanted; add to results.
  575.             // For simple folder queries, check both itemId and the concrete
  576.             // item id.
  577.             var index = ids.indexOf(node.itemId);
  578.             if (index == -1 &&
  579.                 node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT)
  580.               index = ids.indexOf(asQuery(node).folderItemId);
  581.  
  582.             if (index != -1) {
  583.               nodes.push(node);
  584.               foundOne = true;
  585.               ids.splice(index, 1);
  586.             }
  587.  
  588.             if (ids.length == 0 || !PlacesUtils.nodeIsContainer(node) ||
  589.                 nodesURIChecked.indexOf(node.uri) != -1)
  590.               return foundOne;
  591.  
  592.             nodesURIChecked.push(node.uri);
  593.             asContainer(node);
  594.  
  595.             // Remember the beginning state so that we can re-close
  596.             // this node if we don't find any additional results here.
  597.             var previousOpenness = node.containerOpen;
  598.             node.containerOpen = true;
  599.             for (var child = 0;  child < node.childCount && ids.length > 0;
  600.                  child++) {
  601.               var childNode = node.getChild(child);
  602.               var found = findNodes(childNode);
  603.               if (!foundOne)
  604.                 foundOne = found;
  605.             }
  606.  
  607.             // If we didn't find any additional matches in this node's
  608.             // subtree, revert the node to its previous openness.
  609.             if (!foundOne)
  610.               node.containerOpen = previousOpenness;
  611.             return foundOne;
  612.           }
  613.  
  614.           findNodes(this.getResultNode());
  615.  
  616.           // For all the nodes we've found, highlight the corresponding
  617.           // index in the tree.
  618.           var resultview = this.getResultView();
  619.           var selection = this.view.selection;
  620.           selection.clearSelection();
  621.           for (var i=0; i < nodes.length; i++) {
  622.             var index = resultview.treeIndexForNode(nodes[i]);
  623.             selection.rangedSelect(index, index, true);
  624.           }
  625.         ]]></body>
  626.       </method>
  627.  
  628.       <!-- nsDragAndDrop -->
  629.       <method name="onDragStart">
  630.         <parameter name="event"/>
  631.         <parameter name="xferData"/>
  632.         <parameter name="dragAction"/>
  633.         <body><![CDATA[ 
  634.           // Drag and Drop does not work while a tree view is sorted.
  635.           if (this.getAttribute("sortActive") == "true")
  636.             throw Cr.NS_OK;
  637.  
  638.           var nodes = this.getSelectionNodes();
  639.           for (var i = 0; i < nodes.length; ++i) {
  640.             var node = nodes[i];
  641.  
  642.             // Disallow dragging the root node of a tree
  643.             var parent = node.parent;
  644.             if (!parent)
  645.               throw Cr.NS_OK;
  646.  
  647.             // If this node is part of a readonly container (e.g. a livemark) it 
  648.             // cannot be moved, only copied, so we must change the action used
  649.             // by the drag session.
  650.             if (PlacesUtils.nodeIsTagQuery(parent) ||
  651.                 !PlacesControllerDragHelper.canMoveContainerNode(node)) {
  652.               // XXX DOES NOTHING! dragAction doesn't persist
  653.               dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
  654.               break;
  655.             }
  656.           }
  657.  
  658.           // XXXben - the drag wrapper should do this automatically.
  659.           if (event.ctrlKey)
  660.             dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
  661.           // Stuff the encoded selection into the transferable data object
  662.           xferData.data = this._controller.getTransferData(dragAction.action);
  663.         ]]></body>
  664.       </method>
  665.       
  666.       <!-- nsDragAndDrop -->
  667.       <method name="canDrop">
  668.         <parameter name="event"/>
  669.         <parameter name="session"/>
  670.         <body><![CDATA[ 
  671.           var row = { }, col = { }, child = { };
  672.           this.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, 
  673.                                        child);
  674.           return this.view.canDrop(row.value, -1);
  675.         ]]></body>
  676.       </method>
  677.       
  678.       <!-- nsDragAndDrop -->
  679.       <method name="onDragOver">
  680.         <parameter name="event"/>
  681.         <parameter name="flavor"/>
  682.         <parameter name="session"/>
  683.         <body><![CDATA[ 
  684.           var dragService = 
  685.               Cc["@mozilla.org/widget/dragservice;1"].
  686.               getService(Ci.nsIDragService);
  687.           var dragSession = dragService.getCurrentSession();
  688.           dragSession.canDrop = this.canDrop(event, session);
  689.         ]]></body>
  690.       </method>
  691.  
  692.       <!-- nsDragAndDrop -->
  693.       <method name="getSupportedFlavours">
  694.         <body><![CDATA[
  695.           var flavorSet = new FlavourSet();
  696.           var types = PlacesUIUtils.GENERIC_VIEW_DROP_TYPES;
  697.           for (var i = 0; i < types.length; ++i)
  698.             flavorSet.appendFlavour(types[i]);
  699.           return flavorSet;
  700.         ]]></body>
  701.       </method>
  702.  
  703.       <method name="buildContextMenu">
  704.         <parameter name="aPopup"/>
  705.         <body><![CDATA[
  706.           return this.controller.buildContextMenu(aPopup);
  707.         ]]></body>
  708.       </method>
  709.  
  710.       <method name="destroyContextMenu">
  711.         <parameter name="aPopup"/>
  712.         <body/>
  713.       </method>
  714.     </implementation>
  715.     <handlers>
  716.       <handler event="focus"><![CDATA[
  717.         this._cachedInsertionPoint = undefined;
  718.  
  719.         // See select handler. We need the sidebar's places commandset to be
  720.         // updated as well
  721.         document.commandDispatcher.updateCommands("focus");
  722.       ]]></handler>
  723.       <handler event="select"><![CDATA[
  724.         this._cachedInsertionPoint = undefined;
  725.  
  726.         // This additional complexity is here for the sidebars
  727.         var win = window;
  728.         while (true) {
  729.           win.document.commandDispatcher.updateCommands("focus");
  730.           if (win == window.top)
  731.             break;
  732.  
  733.           win = win.parent;
  734.         }
  735.       ]]></handler>
  736.       <handler event="draggesture"><![CDATA[
  737.         // XXXben ew.
  738.         if (event.target.localName == "treechildren")
  739.           nsDragAndDrop.startDrag(event, this);
  740.       ]]></handler>
  741.       <handler event="dragover"><![CDATA[
  742.         if (event.target.localName == "treechildren")
  743.           nsDragAndDrop.dragOver(event, this);
  744.       ]]></handler>
  745.     </handlers>
  746.   </binding>
  747.  
  748. </bindings>
  749.  
  750.