home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2005 October / Gamestar_77_2005-10_dvd.iso / Programy / nsb-install-8-0.exe / chrome / browser.jar / content / browser / bookmarks / bookmarksTree.xml < prev    next >
Encoding:
Extensible Markup Language  |  2005-07-29  |  40.5 KB  |  988 lines

  1. <?xml version="1.0"?>  
  2.  
  3.  
  4. <!DOCTYPE window [
  5.   <!ENTITY % bookmarksDTD SYSTEM "chrome://browser/locale/bookmarks/bookmarks.dtd" >
  6.   %bookmarksDTD;
  7. ]>
  8.  
  9. <bindings id="bookmarksBindings" 
  10.           xmlns="http://www.mozilla.org/xbl" 
  11.           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 
  12.           xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  13.           xmlns:xbl="http://www.mozilla.org/xbl">
  14.  
  15.   <binding id="bookmarks-tree">
  16.     <implementation>
  17.       <constructor><![CDATA[
  18.         // This function only reads in the bookmarks from disk if they have not already been read.
  19.         initServices();
  20.         initBMService();
  21.  
  22.         BMSVC.readBookmarks();
  23.         
  24.         // We implement nsIController
  25.         this.tree.controllers.appendController(this.controller);
  26.         var olb = document.getAnonymousElementByAttribute(this, "anonid", "bookmarks-tree");
  27.         olb = olb.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
  28.         olb.addObserver(this.builderObserver);
  29.  
  30.         // Load column settings from persisted attribute
  31.         var colinfostr = this.getAttribute("colinfo");
  32.         var colinfo = colinfostr.split(" ");
  33.         for (var i = 0; i < colinfo.length; ++i) {
  34.           if (colinfo[i] == "") continue;
  35.  
  36.           var querymarker = colinfo[i].indexOf("?");
  37.           var anonid = colinfo[i].substring(4, querymarker);
  38.           var col = document.getAnonymousElementByAttribute(this, "id", anonid);
  39.  
  40.           if (!anonid || !col) break;
  41.  
  42.           var attrstring = colinfo[i].substr(querymarker + 1);
  43.  
  44.           var attrpairs = attrstring.split("&");
  45.           for (var j = 0; j < attrpairs.length; ++j) {
  46.             var pair = attrpairs[j].split("=");
  47.             col.setAttribute(pair[0], pair[1]);
  48.           }
  49.         }
  50.         
  51.         // Load sort data from preferences
  52.         this.refreshSort();
  53.         
  54.         // Observe for changes in sort from other concurrent UI
  55.         const kPrefSvcContractID = "@mozilla.org/preferences-service;1";
  56.         const kPrefSvcIID = Components.interfaces.nsIPrefService;
  57.         var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
  58.         var prefs = prefSvc.getBranch(null);
  59.         const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranchInternal;
  60.         var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
  61.         bookmarksPrefsInternal.addObserver(this.sortChangedObserver.domain, 
  62.                                            this.sortChangedObserver, false);
  63.       ]]></constructor>
  64.       <destructor><![CDATA[
  65.         
  66.         this.treeBuilder.removeObserver(this.builderObserver);
  67.         this.tree.controllers.removeController(this.controller);
  68.  
  69.         // Save column settings and sort info to persisted attribute
  70.         var persistString = "";
  71.         
  72.         var sortResource = NC_NS + "Name";
  73.         var sortDirection = "none";
  74.  
  75.         var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
  76.         var child = treecols.firstChild;
  77.         while (child) {
  78.           if (child.localName != "splitter") {
  79.             var formatString = " col:%1%?width=%2%&hidden=%3%&ordinal=%6%";
  80.             formatString = formatString.replace(/%1%/, child.getAttribute("id"));
  81.             formatString = formatString.replace(/%2%/, child.getAttribute("width"));
  82.             formatString = formatString.replace(/%3%/, child.getAttribute("hidden"));
  83.  
  84.             // While we're walking the columns, if we discover the column that represents the
  85.             // field sorted by, save the resource associated with that column so that we 
  86.             // can save that in prefs (see below)
  87.             if (child.getAttribute("sortActive") == "true") {
  88.               sortResource = child.getAttribute("sort");
  89.               sortDirection = child.getAttribute("sortDirection");
  90.             }
  91.             formatString = formatString.replace(/%6%/, child.getAttribute("ordinal"));
  92.             persistString += formatString;
  93.           }
  94.           child = child.nextSibling;
  95.         }
  96.         this.setAttribute("colinfo", persistString);
  97.         
  98.         document.persist(this.id, "colinfo");
  99.         
  100.         // Unhook the sort change observer for this tree
  101.         const kPrefSvcContractID = "@mozilla.org/preferences-service;1";
  102.         const kPrefSvcIID = Components.interfaces.nsIPrefService;
  103.         var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
  104.         var prefs = prefSvc.getBranch(null);
  105.         const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranchInternal;
  106.         var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
  107.         bookmarksPrefsInternal.removeObserver(this.sortChangedObserver.domain, 
  108.                                               this.sortChangedObserver);
  109.  
  110.       ]]></destructor>
  111.  
  112.       <property name="db">
  113.         <getter><![CDATA[
  114.           return this.tree.database;
  115.         ]]></getter>
  116.       </property>      
  117.       
  118.       <field name="sortChangedObserver">
  119.       <![CDATA[
  120.       ({
  121.         outer: this,
  122.         domain: "browser.bookmarks.sort",
  123.         observe: function BMOL_sortChangedObserver(aSubject, aTopic, aPrefName) 
  124.         {
  125.           if (aTopic != "nsPref:changed") return;
  126.           if (aPrefName.substr(0, this.domain.length) != this.domain) return;
  127.                     
  128.           this.outer.refreshSort();
  129.         }      
  130.       })
  131.       ]]>
  132.       </field>
  133.       
  134.       <field name="sorted">false</field>
  135.       <method name="refreshSort">
  136.         <body>
  137.         <![CDATA[
  138.           const kPrefSvcContractID = "@mozilla.org/preferences-service;1";
  139.           const kPrefSvcIID = Components.interfaces.nsIPrefService;
  140.           var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
  141.           var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
  142.           
  143.           // This ensures that we don't sort twice in the tree that is clicked on 
  144.           // as a result of 1) the click and 2) the pref listener. 
  145.           if (!this.sorted) {
  146.             try {
  147.               var sortResource = bookmarksSortPrefs.getCharPref("resource");
  148.               var sortDirection = bookmarksSortPrefs.getCharPref("direction");
  149.           
  150.               // Walk the columns, when we find a column with a sort resource that matches the supplied
  151.               // data, stop and make sure it's sort active. 
  152.               var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
  153.               var child = treecols.firstChild;
  154.               while (child) {
  155.                 if (child.localName != "splitter") {
  156.                   if (child.getAttribute("sort") == sortResource) {
  157.                     child.setAttribute("sortActive", "true");
  158.                     child.setAttribute("sortDirection", sortDirection);
  159.                     this.treeBuilder.sort(child, false);
  160.                     break;
  161.                   }
  162.                 }          
  163.                 child = child.nextSibling;
  164.               }
  165.             }
  166.             catch (e) {
  167.               dump("error in refresh sort:"+e)
  168.             }
  169.           }
  170.  
  171.           this.sorted = false;
  172.         ]]>
  173.         </body>
  174.       </method>
  175.       
  176.       <property name="columns">
  177.         <getter>
  178.         <![CDATA[
  179.           var cols = [];
  180.         
  181.           var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
  182.           var child = treecols.firstChild;
  183.           while (child) {
  184.             if (child.localName != "splitter") {
  185.               var obj = {
  186.                 label: child.getAttribute("label"),
  187.                 accesskey: child.getAttribute("accesskey"),
  188.                 resource: child.getAttribute("sort"),
  189.                 sortActive: child.getAttribute("sortActive") == "true",
  190.                 hidden: child.getAttribute("hidden")
  191.               }
  192.               cols.push(obj);
  193.             }
  194.             child = child.nextSibling;
  195.           }
  196.  
  197.           return cols;
  198.         ]]>
  199.         </getter>
  200.       </property>
  201.       
  202.       <method name="toggleColumnVisibility">
  203.         <parameter name="aColumnResource"/>
  204.         <body>
  205.         <![CDATA[
  206.           var elt = document.getAnonymousElementByAttribute(this, "sort", aColumnResource);
  207.           if (elt)
  208.             elt.setAttribute("hidden", elt.getAttribute("hidden") != "true");
  209.         ]]>
  210.         </body>
  211.       </method>      
  212.  
  213.       <property name="tree">
  214.         <getter><![CDATA[
  215.           return document.getAnonymousElementByAttribute(this, "anonid", "bookmarks-tree");
  216.         ]]></getter>
  217.       </property>
  218.  
  219.       <property name="treeBoxObject">
  220.         <getter><![CDATA[
  221.           return this.tree.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);
  222.         ]]></getter>
  223.       </property>
  224.  
  225.       <property name="treeBuilder">
  226.         <getter><![CDATA[
  227.           return this.tree.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
  228.         ]]></getter>
  229.       </property>
  230.  
  231.       <property name="type">
  232.         <getter><![CDATA[
  233.           if (!this._type) {
  234.             var type = this.getAttribute("type");
  235.             if (!type)
  236.               type = "multi-column";
  237.             this._type = type;
  238.           }
  239.           return this._type;
  240.         ]]></getter>
  241.       </property>
  242.  
  243.       <property name="currentIndex">
  244.         <getter><![CDATA[
  245.           return this.treeBoxObject.selection.currentIndex;
  246.         ]]></getter>
  247.       </property>
  248.     
  249.       <property name="currentResource">
  250.         <getter><![CDATA[
  251.           return this.treeBuilder.getResourceAtIndex(this.currentIndex);
  252.         ]]></getter>
  253.       </property>
  254.  
  255.       <method name="getRowResource">
  256.         <parameter name="aRow"/>
  257.         <body><![CDATA[
  258.           if (aRow != -1)
  259.             return this.treeBuilder.getResourceAtIndex(aRow);
  260.           else
  261.             return this.getRootResource();
  262.         ]]></body>
  263.       </method>
  264.  
  265.       <method name="getParentResource">
  266.         <parameter name="aRow"/>
  267.         <body><![CDATA[
  268.           if (aRow != -1) {
  269.             var parentIndex = this.treeBoxObject.view.getParentIndex(aRow);
  270.             return this.getRowResource(parentIndex);
  271.           }
  272.           return this.getRootResource(); // assume its parent is the root
  273.         ]]></body>
  274.       </method>
  275.  
  276.       <method name="getRootResource">
  277.         <body><![CDATA[
  278.           var tree = document.getAnonymousElementByAttribute(this, "anonid", "bookmarks-tree");
  279.           return RDF.GetResource(tree.ref);
  280.         ]]></body>
  281.       </method>
  282.  
  283.       <method name="selectResource">
  284.         <parameter name="aResource"/>
  285.         <body><![CDATA[
  286.           var index = this.treeBuilder.getIndexOfResource(aResource);
  287.           if (index != -1) {
  288.             if (!this.treeBoxObject.selection.isSelected(index))
  289.               this.treeBoxObject.selection.toggleSelect(index);
  290.             return;
  291.           }
  292.          
  293.           var chain = BMSVC.getParentChain(aResource);
  294.           //dump("Chain:"+chain.length+"\n");
  295.           for (var i=0; i<chain.length; i++) {
  296.             var rParent = chain.queryElementAt(i, kRDFRSCIID);
  297.             index = this.treeBuilder.getIndexOfResource(rParent);
  298.             //dump(i+":"+BookmarksUtils.getProperty(rParent, NC_NS+"Name")+", index:"+index+"\n");
  299.             if (index == -1)
  300.               continue;
  301.  
  302.             if (!this.treeBoxObject.view.isContainerOpen(index))
  303.               this.treeBoxObject.view.toggleOpenState(index);
  304.           }
  305.           if (index == -1)
  306.             return;
  307.  
  308.           index = this.treeBuilder.getIndexOfResource(aResource);
  309.           if (index != -1)
  310.             this.treeBoxObject.selection.toggleSelect(index);
  311.         ]]></body>
  312.       </method>
  313.  
  314.       <method name="focus">
  315.         <body>
  316.           this.tree.focus();
  317.         </body>
  318.       </method>
  319.  
  320.       <field name="_selection">null</field>
  321.       <field name="_target">   null</field>
  322.  
  323.       <method name="getTreeSelection">
  324.         <body><![CDATA[
  325.           var selection        = {};
  326.           selection.item       = [];
  327.           selection.parent     = [];
  328.           selection.isExpanded = [];
  329.           var rangeCount = this.treeBoxObject.selection.getRangeCount();
  330.           // workaround for bug 171547: if rowCount==0, rangeCount==1
  331.           if (this.treeBuilder.rowCount > 0)
  332.           for (var k = 0; k < rangeCount; ++k) {
  333.             var rangeMin = {};
  334.             var rangeMax = {};
  335.             this.treeBoxObject.selection.getRangeAt(k, rangeMin, rangeMax);
  336.             for (var i = rangeMin.value; i <= rangeMax.value; ++i) {
  337.               var selectedItem   = this.getRowResource(i);
  338.               var selectedParent = this.getParentResource(i);
  339.               var isExpanded     = this.treeBoxObject.view.isContainerOpen(i);
  340.               selection.item  .push(selectedItem);
  341.               selection.parent.push(selectedParent);
  342.               selection.isExpanded.push(isExpanded);
  343.             }
  344.           }
  345.           selection.length = selection.item.length;
  346.           BookmarksUtils.checkSelection(selection);
  347.           return selection;
  348.         ]]></body>
  349.       </method>
  350.  
  351.       <method name="getTreeTarget">
  352.         <parameter name="aItem"/>
  353.         <parameter name="aParent"/>
  354.         <parameter name="aOrientation"/>
  355.         <body><![CDATA[
  356.  
  357.           if (!aParent || aParent.Value == "NC:BookmarksTopRoot")
  358.             return BookmarksUtils.getTargetFromFolder(RDF.GetResource("NC:BookmarksRoot"))
  359.  
  360.           if (aOrientation == BookmarksUtils.DROP_ON)
  361.             return BookmarksUtils.getTargetFromFolder(aItem);
  362.  
  363.           RDFC.Init(this.db, aParent);
  364.           var index = RDFC.IndexOf(aItem);
  365.           if (aOrientation == BookmarksUtils.DROP_AFTER)
  366.             ++index;
  367.           return { parent: aParent, index: index };
  368.         ]]></body>
  369.       </method>
  370.  
  371.       # This function saves the current selection state before the tree is rebuilt
  372.       # following a command execution. This allows us to remember which item(s)
  373.       # was/were selected so that the user does not need to constantly refocus the 
  374.       # tree to perform a sequence of commands. 
  375.       <field name="_savedSelection">[]</field>
  376.       <method name="saveSelection">
  377.         <body><![CDATA[
  378.           var selection = this.treeBoxObject.view.selection;
  379.           var rangeCount = selection.getRangeCount();
  380.           var ranges = [];
  381.           var min = {}; var max = {};
  382.           for (var i = 0; i < rangeCount; ++i) {
  383.             selection.getRangeAt(i, min, max);
  384.             ranges.push({min: min.value, max: max.value});
  385.           }
  386.           this._savedSelection = ranges;
  387.         ]]></body>
  388.       </method>
  389.       
  390.       # This function restores the selection appropriately after a command executes. 
  391.       # This is necessary because most commands trigger a rebuild of the tree which
  392.       # destroys the selection. The restoration of selection is handled in three 
  393.       # different ways depending on the type of command that has been executed:
  394.       #  1) Commands that remove rows:
  395.       #       The row immediately after the first range in the selection is selected, 
  396.       #       if there is no row immediately after the first range the item before it
  397.       #       is selected
  398.       #  2) Commands that insert rows:
  399.       #       The newly inserted rows are selected
  400.       #  3) Commands that do not change the row count 
  401.       #       The row(s) that was/were operated on remain selected.
  402.       # 
  403.       # The calls to save/restore are placed in the doCommand method and thus all
  404.       # commands must pass through this gate. The result is that this method becomes
  405.       # the POLICY CENTER FOR POST-VIEW/EDIT SELECTION CHANGES.
  406.       <method name="restoreSelection">
  407.         <parameter name="aCommand"/>
  408.         <body><![CDATA[ 
  409.           var oldRanges = this._savedSelection;
  410.           var newRanges = [];
  411.  
  412.           switch(aCommand) {
  413.           // [Category 1] - Commands that remove rows
  414.           case "cmd_cut":
  415.           case "cmd_delete":
  416.             // Since rows have been removed, the row immediately after the first range 
  417.             // in the original selection now has the index of the first item in the first
  418.             // range. 
  419.             var nextRow = oldRanges[0].min;
  420.             var maxCount = this.treeBoxObject.view.rowCount;
  421.             if (nextRow >= maxCount)
  422.               nextRow = maxCount-1;
  423.             if (nextRow >= 0)
  424.               newRanges.push({min: nextRow, max: nextRow});
  425.             break;
  426.           // [Category 2] - Commands that insert rows
  427.           case "cmd_paste":
  428.           case "cmd_bm_import":
  429.           case "cmd_bm_movebookmark":
  430.           case "cmd_bm_newbookmark":
  431.           case "cmd_bm_newfolder":
  432.           case "cmd_bm_newseparator":
  433.           case "cmd_undo": //XXXpch: doesn't work for insert
  434.           case "cmd_redo": //XXXpch: doesn't work for remove
  435.             // All items inserted will be selected. The implementation of this model
  436.             // is left to |preUpdateTreeSelection|, called when an insert transaction is
  437.             // executed, and |updateTreeSelection| called here. 
  438.             this.updateTreeSelection();
  439.             break;
  440.           // [Category 3] - Commands that do not alter the row count
  441.           case "cmd_copy":
  442.           case "cmd_bm_properties":
  443.           case "cmd_bm_rename":
  444.           case "cmd_bm_setpersonaltoolbarfolder":
  445.           case "cmd_bm_export":
  446.           default:
  447.             // The selection is unchanged.
  448.             return;
  449.           }
  450.           
  451.           var newSelection = this.treeBoxObject.view.selection;
  452.           for (i = 0; i < newRanges.length; ++i)
  453.             newSelection.rangedSelect(newRanges[i].min, newRanges[i].max, true);
  454.         ]]></body>
  455.       </method>
  456.  
  457.       <field name="_itemToBeToggled">  []</field>
  458.       // keep track of the items that we will select
  459.       // because we can not select rows during a batch.
  460.       <method name="preUpdateTreeSelection">
  461.         <parameter name="aTxn"/>
  462.         <parameter name="aDo"/>
  463.         <body><![CDATA[
  464.           aTxn = aTxn.wrappedJSObject;
  465.           var type = aTxn.type;
  466.           // Skip transactions that aggregates nested "insert" or "remove" transactions.
  467.           if ((type == "insert") && aDo || (type == "remove") && !aDo)
  468.             this._itemToBeToggled = aTxn.item;
  469.         ]]></body>
  470.       </method>
  471.  
  472.       <method name="updateTreeSelection">
  473.         <body><![CDATA[
  474.           this.treeBoxObject.selection.clearSelection();
  475.           for (var i=0; i<this._itemToBeToggled.length; ++i) {
  476.             index = this.treeBuilder.getIndexOfResource(this._itemToBeToggled[i]);
  477.             if (index != -1 && !this.treeBoxObject.selection.isSelected(index))
  478.               this.treeBoxObject.selection.toggleSelect(index);
  479.           }
  480.         ]]></body>
  481.       </method>
  482.  
  483.       <method name="createTreeContextMenu">
  484.         <parameter name="aEvent"/>
  485.         <body><![CDATA[
  486.           var selection = this._selection;
  487.           var target    = this._target;
  488.           BookmarksCommand.createContextMenu(aEvent, selection);
  489.           this.onCommandUpdate();
  490.         ]]></body>
  491.       </method>
  492.  
  493.       <method name="openItemClick">
  494.         <parameter name="aEvent"/>
  495.         <parameter name="aClickCount"/>
  496.         <body><![CDATA[
  497.           if (aEvent.button == 2 || aEvent.originalTarget.localName != "treechildren")
  498.             return;
  499.           if (aClickCount != this.clickCount && aEvent.button != 1)
  500.             return;
  501.  
  502.           var row = {};
  503.           var col = {};
  504.           var obj = {};
  505.           this.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY, row, col, obj);
  506.           row = row.value;
  507.  
  508.           if (row == -1 || obj.value == "twisty")
  509.             return;
  510.           var modifKey = aEvent.shiftKey || aEvent.ctrlKey || aEvent.altKey || 
  511.                          aEvent.metaKey  || aEvent.button == 1;
  512.           if (this.clickCount == 2 && !modifKey &&
  513.               this.treeBoxObject.view.isContainer(row))
  514.             return;
  515.  
  516.           if (this.clickCount == 2 && modifKey) {
  517.             this.treeBoxObject.selection.select(row);
  518.             this._selection = this.getTreeSelection();
  519.           }
  520.           var selection = this._selection;
  521.  
  522.           if (selection.isContainer[0]) {
  523.             if (this.clickCount == 1 && !modifKey) {
  524.               this.treeBoxObject.view.toggleOpenState(row);
  525.               //XXXpch: broken since we have single IDs
  526.               //if (selection.protocol[0] != "file")
  527.                 return;
  528.             }
  529.           }
  530.           var browserTarget = whereToOpenLink(aEvent);
  531.           BookmarksCommand.openBookmark(selection, browserTarget, this.db);
  532.           // give focus back to this; openBookmark/openLocation steals it and gives it
  533.           // to the browser content.  This is to make things like cut/copy/etc. behave sanely
  534.           // in the bookmarks sidebar.
  535.           this.focus();
  536.         ]]></body>
  537.       </method>
  538.  
  539.       <method name="openItemKey">
  540.         <body><![CDATA[
  541.           if (this._selection.length != 1) {
  542.             return;
  543.           }
  544.           if (!this._selection.isContainer[0])
  545.             BookmarksCommand.openBookmark(this._selection, "current", this.db)
  546.         ]]></body>
  547.       </method>
  548.  
  549.       <method name="searchBookmarks">
  550.       <parameter name="aInput"/>
  551.         <body><![CDATA[
  552.           if(!this.originalRef)
  553.               this.originalRef = this.tree.getAttribute("ref");
  554.  
  555.           if (!aInput)
  556.             this.tree.setAttribute("ref", this.originalRef);
  557.           else
  558.             this.tree.setAttribute("ref",
  559.                                    "find:datasource=rdf:bookmarks&match=http://home.netscape.com/NC-rdf#Name&method=contains&text=" + encodeURIComponent(aInput));
  560.         ]]></body>
  561.       </method>
  562.  
  563.       <!-- observer -->
  564.       <field name="DNDObserver" readonly="true"><![CDATA[
  565.       ({
  566.         mOuter: this,
  567.         onDragStart: function (aEvent, aXferData, aDragAction)
  568.         {
  569.           if (this.mOuter.tree.getAttribute("sortActive") == "true")
  570.             throw Components.results.NS_OK; 
  571.           var selection = this.mOuter._selection;
  572.           aXferData.data = BookmarksUtils.getXferDataFromSelection(selection);
  573.           if (aEvent.ctrlKey)
  574.             aDragAction.action = kDSIID.DRAGDROP_ACTION_COPY;
  575.         }
  576.       })
  577.       ]]></field>      
  578.         
  579.       <!-- nsIController -->
  580.       <field name="controller" readonly="true"><![CDATA[
  581.       ({
  582.         mOuter: this,
  583.         
  584.         supportsCommand: BookmarksController.supportsCommand,
  585.         
  586.         isCommandEnabled: function (aCommand)
  587.         {
  588.           // warning: this is not the called function in BookmarksController.onCommandUpdate
  589.           var selection = this.mOuter._selection;
  590.           var target    = this.mOuter._target;
  591.           return BookmarksController.isCommandEnabled(aCommand, selection, target)
  592.         },
  593.  
  594.         doCommand: function (aCommand)
  595.         {
  596.           var selection = this.mOuter._selection;
  597.           var target    = this.mOuter._target;
  598.           this.mOuter.treeBoxObject.selection.selectEventsSuppressed = true;
  599.           this.mOuter._itemToBeToggled = [];
  600.           
  601.           switch (aCommand) {
  602.           case "cmd_selectAll":
  603.             this.mOuter.treeBoxObject.selection.selectAll();
  604.             break;
  605.           case "cmd_bm_expandfolder":
  606.             this.mOuter.treeBoxObject.view.toggleOpenState(this.mOuter.currentIndex);
  607.             break;
  608.           default:
  609.             this.mOuter.saveSelection();
  610.             BookmarksController.doCommand(aCommand, selection, target);
  611.             this.mOuter.restoreSelection(aCommand);
  612.           }
  613.           this.mOuter.treeBoxObject.selection.selectEventsSuppressed = false;
  614.         }
  615.       })
  616.       ]]></field>
  617.  
  618.       <method name="onCommandUpdate">
  619.         <body><![CDATA[
  620.           var selection = this._selection;
  621.           var target    = this._target;
  622.           BookmarksController.onCommandUpdate(selection, target);
  623.         ]]></body>
  624.       </method>
  625.  
  626.       <method name="selectionChanged">
  627.         <parameter name="aEvent"/>
  628.         <body><![CDATA[
  629.         ]]></body>
  630.       </method>
  631.  
  632.       <!-- nsIXULTreeBuilderObserver -->
  633.       <field name="builderObserver"><![CDATA[
  634.       ({
  635.         mOuter: this,
  636.  
  637.         canDropOn: function(index)
  638.         {
  639.           var dragSession = DS.getCurrentSession();
  640.           if (!dragSession)
  641.             return false;
  642.  
  643.           var rsrc = this.mOuter.getRowResource(index);
  644.  
  645.           // we can only test for kCopyAction if the source is a bookmark
  646.           var checkCopy = dragSession.isDataFlavorSupported("moz/rdfitem");
  647.           const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
  648.           if (!checkCopy || dragSession.dragAction & kCopyAction) {
  649.               return true;
  650.           } else {
  651.               var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
  652.               // we can't drop into Livemarks, file:/find: URIs, etc.
  653.               if (!BookmarksUtils.isValidTargetContainer (rsrc, selection))
  654.                   return false;
  655.               return true;
  656.           }
  657.         },
  658.  
  659.         canDropBeforeAfter: function(index, before)
  660.         {
  661.           var dragSession = DS.getCurrentSession();
  662.           if (!dragSession)
  663.             return false;
  664.  
  665.           var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
  666.           var rsrc = this.mOuter.getRowResource(index);
  667.           var rsrcParent = this.mOuter.getParentResource(index);
  668.  
  669.           var rtype = BookmarksUtils.resolveType(rsrc);
  670.           var rptype = BookmarksUtils.resolveType(rsrcParent);
  671.  
  672.           if (!BookmarksUtils.isValidTargetContainer (rsrcParent, selection))
  673.               return false;
  674.  
  675.           if (index != 0)
  676.             return true;
  677.           if (rsrc.Value != "NC:BookmarksRoot")
  678.             return true;
  679.           return before? false:this.mOuter.treeBoxObject.view.isContainerOpen(0)
  680.         },
  681.  
  682.         onDrop: function(row, orientation)
  683.         {
  684.           var dragSession = DS.getCurrentSession();
  685.           if (!dragSession)
  686.             return;
  687.           //var date = Date.now();
  688.           var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
  689.           var rItem     = this.mOuter.getRowResource(row);
  690.           var rParent   = this.mOuter.getParentResource(row);
  691.           var target;
  692.           if (orientation == BookmarksUtils.DROP_AFTER            &&
  693.               this.mOuter.treeBoxObject.view.isContainer(row)     &&
  694.               this.mOuter.treeBoxObject.view.isContainerOpen(row) &&
  695.              !this.mOuter.treeBoxObject.view.isContainerEmpty(row))
  696.             target = { parent: rItem, index: 1 };
  697.           else {
  698.             target = this.mOuter.getTreeTarget(rItem, rParent, orientation);
  699.           }
  700.           this.mOuter.treeBoxObject.selection.selectEventsSuppressed = true;
  701.           this.mOuter._itemToBeToggled = [];
  702.  
  703.           // we can only test for kCopyAction if the source is a bookmark
  704.           var checkCopy = dragSession.isDataFlavorSupported("moz/rdfitem");
  705.           const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
  706.  
  707.           // doCopy defaults to true; check if we should make it false.
  708.           // we make it false only if all the selection items have valid parent
  709.           // bookmark DS containers (i.e. aren't generated via aggregation)
  710.           var doCopy = true;
  711.           if (checkCopy && !(dragSession.dragAction & kCopyAction))
  712.             doCopy = BookmarksUtils.shouldCopySelection("drag", selection);
  713.  
  714.           if (doCopy)
  715.             BookmarksUtils.insertAndCheckSelection("drag", selection, target);
  716.           else
  717.             BookmarksUtils.moveAndCheckSelection  ("drag", selection, target);
  718.  
  719.           if (this.mOuter._itemToBeToggled.length > 0)
  720.             this.mOuter.updateTreeSelection();
  721.           // use of a timer to speedup
  722.           var This = this.mOuter;
  723.           setTimeout( function (){This.treeBoxObject.selection.selectEventsSuppressed = false}, 100)
  724.           //dump("DND time:"+(Date.now()-date)+"\n")
  725.         },
  726.  
  727.         onToggleOpenState: function (aRow)
  728.         {
  729.           // update the open attribute of the selection
  730.           var selection = this.mOuter._selection;
  731.           if (!selection)
  732.             return;
  733.           var resource = this.mOuter.getRowResource(aRow);
  734.           for (var i=0; i<selection.length; ++i) {
  735.             if (selection.item[i] == resource) {
  736.               selection.isExpanded[i] = !selection.isExpanded[i];
  737.               break;
  738.             }
  739.           }
  740.         },
  741.         
  742.         onCycleHeader: function (aColumnID, aHeaderElement)
  743.         {
  744.           const kPrefSvcContractID = "@mozilla.org/preferences-service;1";
  745.           const kPrefSvcIID = Components.interfaces.nsIPrefService;
  746.           var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
  747.           var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
  748.           
  749.           // Sorted! http://www.sorted.org.nz/
  750.           this.mOuter.sorted = true;
  751.  
  752.           bookmarksSortPrefs.setCharPref("resource", aHeaderElement.getAttribute("sort"));
  753.           bookmarksSortPrefs.setCharPref("direction", aHeaderElement.getAttribute("sortDirection"));
  754.         },
  755.     
  756.         onSelectionChanged: function ()
  757.         {
  758.           //dump("ONSELECTION CHANGED\n");
  759.           var selection = this.mOuter.getTreeSelection();
  760.           this.mOuter._selection = selection;
  761.           this.mOuter._target    = this.mOuter.getTreeTarget(selection.item[0], selection.parent[0], BookmarksUtils.DROP_BEFORE);
  762.           this.mOuter.onCommandUpdate();
  763.         },
  764.         
  765.         onCycleCell          : function (aItemIndex, aColumnID)          {},
  766.         isEditable           : function (aItemIndex, aColumnID)          {},
  767.         onSetCellText        : function (aItemIndex, aColumnID, aValue)  {},
  768.         onPerformAction      : function (aAction)                        {},
  769.         onPerformActionOnRow : function (aAction, aItemIndex)            {},
  770.         onPerformActionOnCell: function (aAction, aItemIndex, aColumnID) {}
  771.  
  772.       })
  773.       ]]></field>
  774.  
  775.       <!-- nsITransactionManager listener -->
  776.       <field name="bookmarkTreeTransactionListener"><![CDATA[
  777.       ({
  778.  
  779.         mOuter: this,
  780.  
  781.         willDo: function (aTxmgr, aTxn) {},
  782.         didDo : function (aTxmgr, aTxn) {
  783.           this.mOuter.preUpdateTreeSelection(aTxn, true);
  784.         },
  785.         willUndo: function (aTxmgr, aTxn) {},
  786.         didUndo : function (aTxmgr, aTxn) {
  787.           this.mOuter.preUpdateTreeSelection(aTxn, false);
  788.         },
  789.         willRedo: function (aTxmgr, aTxn) {},
  790.         didRedo : function (aTxmgr, aTxn) {
  791.           this.mOuter.preUpdateTreeSelection(aTxn, true);
  792.         },
  793.         didMerge       : function (aTxmgr, aTxn) {},
  794.         didBeginBatch  : function (aTxmgr, aTxn) {},
  795.         didEndBatch    : function (aTxmgr, aTxn) {},
  796.         willMerge      : function (aTxmgr, aTxn) {},
  797.         willBeginBatch : function (aTxmgr, aTxn) {},
  798.         willEndBatch   : function (aTxmgr, aTxn) {}
  799.       })
  800.       ]]></field>
  801.     </implementation>
  802.   </binding>
  803.  
  804.   <!-- Full Bookmarks Tree, multi-columned -->
  805.   <!-- Localize column labels! -->
  806.   <binding id="bookmarks-tree-full" extends="chrome://browser/content/bookmarks/bookmarksTree.xml#bookmarks-tree">
  807.     <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl"
  808.                  contextmenu="_child">
  809.       <!-- XXXben need focus event handler for cmd update -->
  810.       <!-- context menu -->
  811.       <menupopup onpopupshowing="this.parentNode.createTreeContextMenu(event);"
  812.                  onpopuphidden="if (content) content.focus()"
  813.                  onclick="event.preventBubble();"
  814.                  onkeypress="event.preventBubble();"/>
  815.       <vbox flex="1">
  816.         <tree anonid="bookmarks-tree" flex="1" class="plain" enableColumnDrag="true"
  817.                   datasources="rdf:bookmarks rdf:files rdf:localsearch" ref="NC:BookmarksTopRoot" flags="dont-build-content"
  818.                   onkeypress="if (event.keyCode == 13) this.parentNode.parentNode.openItemKey();"
  819.                   onclick="this.parentNode.parentNode.openItemClick(event, 1);"
  820.                   ondblclick="this.parentNode.parentNode.openItemClick(event, 2);"
  821.                   ondraggesture="if (event.originalTarget.localName == 'treechildren') nsDragAndDrop.startDrag(event, this.parentNode.parentNode.DNDObserver);"
  822.                   onselect="this.treeBoxObject.view.selectionChanged();">
  823.           <template xmlns:nc="http://home.netscape.com/NC-rdf#">
  824.             <rule rdf:type="http://home.netscape.com/NC-rdf#BookmarkSeparator">
  825.               <treechildren>
  826.                 <treeitem uri="rdf:*">
  827.                   <treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type separator">
  828.                     <treecell properties="separator" label="rdf:http://home.netscape.com/NC-rdf#Name"/>
  829.                   </treerow>
  830.                 </treeitem>
  831.               </treechildren>
  832.             </rule>
  833.             <rule>
  834.               <treechildren>
  835.                 <treeitem uri="rdf:*">
  836.                   <treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
  837.                     <treecell src="rdf:http://home.netscape.com/NC-rdf#Icon"
  838.                               label="rdf:http://home.netscape.com/NC-rdf#Name"/>
  839.                     <treecell label="rdf:http://home.netscape.com/NC-rdf#URL" />
  840.                     <treecell label="rdf:http://home.netscape.com/NC-rdf#ShortcutURL" />
  841.                     <treecell label="rdf:http://home.netscape.com/NC-rdf#Description" />
  842.                     <treecell label="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate" />
  843.                     <treecell label="rdf:http://home.netscape.com/WEB-rdf#LastModifiedDate" />
  844.                     <treecell label="rdf:http://home.netscape.com/WEB-rdf#LastVisitDate"/>
  845.                   </treerow>
  846.                 </treeitem>
  847.               </treechildren>
  848.             </rule>
  849.           </template>
  850.           <treecols anonid="treecols">
  851.             <treecol id="Name" label="&treecol.name.label;" flex="1" primary="true" 
  852.                           class="sortDirectionIndicator" 
  853.                           persist="width hidden ordinal" 
  854.                           sort="rdf:http://home.netscape.com/NC-rdf#Name"
  855.                           sortActive="true" sortDirection="none"/>
  856.             <splitter class="tree-splitter" />
  857.             <treecol id="URL" label="&treecol.url.label;" 
  858.                           flex="1" class="sortDirectionIndicator" 
  859.                           sort="rdf:http://home.netscape.com/NC-rdf#URL" 
  860.                           persist="width hidden ordinal" />
  861.             <splitter class="tree-splitter" />
  862.             <treecol id="ShortcutURL" label="&treecol.shortcut.label;" 
  863.                           hidden="true" flex="1" class="sortDirectionIndicator" 
  864.                           persist="hidden width ordinal" 
  865.                           sort="rdf:http://home.netscape.com/NC-rdf#ShortcutURL"/>
  866.             <splitter class="tree-splitter"/>
  867.             <treecol id="Description" label="&treecol.description.label;" 
  868.                           flex="1" class="sortDirectionIndicator" 
  869.                           persist="hidden width ordinal" 
  870.                           sort="rdf:http://home.netscape.com/NC-rdf#Description"/>
  871.             <splitter class="tree-splitter"/>
  872.             <treecol id="AddDate" label="&treecol.addedon.label;" 
  873.                           hidden="true" flex="1" class="sortDirectionIndicator" 
  874.                           sort="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate" 
  875.                           persist="width hidden ordinal" />
  876.             <splitter class="tree-splitter" />
  877.             <treecol id="LastModDate" label="&treecol.lastmod.label;" 
  878.                           hidden="true" flex="1" class="sortDirectionIndicator" 
  879.                           sort="rdf:http://home.netscape.com/WEB-rdf#LastModifiedDate" 
  880.                           persist="width hidden ordinal" />
  881.             <splitter class="tree-splitter" />
  882.             <treecol id="LastVisitDate" label="&treecol.lastvisit.label;" 
  883.                           hidden="true" flex="1" class="sortDirectionIndicator" 
  884.                           sort="rdf:http://home.netscape.com/WEB-rdf#LastVisitDate" 
  885.                           persist="width hidden ordinal" />
  886.           </treecols>
  887.         </tree>
  888.       </vbox>
  889.     </xbl:content>
  890.     <implementation>
  891.       <constructor>
  892.         // Adding the transaction listener
  893.         BMSVC.transactionManager.AddListener(this.bookmarkTreeTransactionListener);
  894.       </constructor>  
  895.       <destructor>
  896.         BMSVC.transactionManager.RemoveListener(this.bookmarkTreeTransactionListener);
  897.       </destructor>  
  898.       <field name="clickCount">2</field>
  899.     </implementation>
  900.   </binding>
  901.  
  902.   <!-- Single column tree -->
  903.   <binding id="bookmarks-tree-name" extends="chrome://browser/content/bookmarks/bookmarksTree.xml#bookmarks-tree">
  904.     <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 
  905.                  xmlns:xbl="http://www.mozilla.org/xbl" contextmenu="_child">
  906.       <!-- context menu -->
  907.       <menupopup xbl:inherits="onpopupshowing"
  908.                  onpopupshowing="this.parentNode.createTreeContextMenu(event);"
  909.                  onpopuphidden="if (content) content.focus()"
  910.                  onclick="event.preventBubble();"
  911.                  onkeypress="event.preventBubble();"/>
  912.       <tree anonid="bookmarks-tree" flex="1" class="plain" hidecolumnpicker="true"
  913.                 datasources="rdf:bookmarks rdf:files rdf:localsearch" ref="NC:BookmarksRoot" flags="dont-build-content"
  914.                 onselect="this.parentNode.treeBoxObject.view.selectionChanged();" seltype="single">
  915.         <template xmlns:nc="http://home.netscape.com/NC-rdf#">
  916.           <rule rdf:type="http://home.netscape.com/NC-rdf#BookmarkSeparator">
  917.             <treechildren>
  918.               <treeitem uri="rdf:*">
  919.                 <treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type separator">
  920.                   <treecell properties="separator" label="rdf:http://home.netscape.com/NC-rdf#Name"/>
  921.                 </treerow>
  922.               </treeitem>
  923.             </treechildren>
  924.           </rule>
  925.           <rule>
  926.             <treechildren>
  927.               <treeitem uri="rdf:*">
  928.                 <treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
  929.                   <treecell src="rdf:http://home.netscape.com/NC-rdf#Icon"
  930.                             label="rdf:http://home.netscape.com/NC-rdf#Name"/>
  931.                 </treerow>
  932.               </treeitem>
  933.             </treechildren>
  934.           </rule>
  935.         </template>
  936.         <treecols anonid="treecols">
  937.           <treecol id="Name" flex="1" primary="true" hideheader="true"
  938.                    sort="rdf:http://home.netscape.com/NC-rdf#Name"
  939.                    sortActive="true" sortDirection="none"/>
  940.         </treecols>
  941.       </tree>
  942.     </xbl:content>
  943.     <implementation>
  944.       <field name="clickCount">1</field>
  945.     </implementation>
  946.   </binding>
  947.  
  948.   <!-- Tree with folders only -->
  949.   <binding id="bookmarks-tree-folders" extends="chrome://browser/content/bookmarks/bookmarksTree.xml#bookmarks-tree">
  950.     <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl">
  951.       <tree anonid="bookmarks-tree" class="bookmarksTree" flex="1" hidecolumnpicker="true"
  952.             xbl:inherits="rows,seltype"
  953.             datasources="rdf:bookmarks rdf:files rdf:localsearch" ref="NC:BookmarksTopRoot" flags="dont-build-content"
  954.             onselect="this.parentNode.treeBoxObject.view.selectionChanged();">
  955.         <template>
  956.           <!-- I don't want these things to appear at all, but that's not an option -->
  957.           <rule rdf:type="http://home.netscape.com/NC-rdf#Livemark">
  958.             <treechildren>
  959.               <treeitem uri="rdf:*">
  960.                 <treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
  961.                   <treecell label="rdf:http://home.netscape.com/NC-rdf#Name" />
  962.                 </treerow>
  963.               </treeitem>
  964.             </treechildren>
  965.           </rule>
  966.           <rule iscontainer="true">
  967.             <treechildren>
  968.               <treeitem uri="rdf:*">
  969.                 <treerow properties="rdf:http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf:http://home.netscape.com/NC-rdf#loading rdf:http://home.netscape.com/WEB-rdf#status">
  970.                   <treecell label="rdf:http://home.netscape.com/NC-rdf#Name" />
  971.                 </treerow>
  972.               </treeitem>
  973.             </treechildren>
  974.           </rule>
  975.         </template>
  976.         <treecols anonid="treecols">
  977.           <treecol id="Name" flex="1" primary="true" hideheader="true"
  978.                    sort="rdf:http://home.netscape.com/NC-rdf#Name"
  979.                    sortActive="true" sortDirection="none"/>
  980.         </treecols>
  981.       </tree>
  982.     </xbl:content>
  983.     <implementation>
  984.       <field name="clickCount">2</field>
  985.     </implementation>
  986.   </binding>
  987. </bindings>
  988.