<?xml version="1.0"?>

<bindings id="treeBindings"
   xmlns="http://www.mozilla.org/xbl"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  
  <binding id="treeitem">
    <implementation>
      <method name="toggleOpenState">
        <body>
          <![CDATA[
            if ((this.getAttribute('container') == 'true') &&
                 (this.getAttribute('empty') != 'true')) {
               if (this.getAttribute('open') == 'true')
                 this.removeAttribute('open');
               else this.setAttribute('open', 'true');
            }
          ]]>
        </body>
      </method>
     <method name="open">
       <body>
          <![CDATA[
            if ((this.getAttribute('container') == 'true') &&
                 (this.getAttribute('empty') != 'true')) {
               if (this.getAttribute('open') != 'true')
                 this.setAttribute('open', 'true');
            }
          ]]>
        </body>
     </method>
     <method name="close">
       <body>
          <![CDATA[
            if ((this.getAttribute('container') == 'true') &&
                 (this.getAttribute('empty') != 'true')) {
               if (this.getAttribute('open') == 'true')
                 this.removeAttribute('open');
            }
          ]]>
        </body>
     </method>    
   </implementation>
  </binding>     

  <binding id="treecell-indented-folder">
    <content autostretch="never">
      <xul:treeindentation/>
      <xul:image class="tree-cell-twisty" twisty="true" allowevents="true"/>
      <xul:image class="tree-cell-primary-icon" inherits="src"/>
      <xul:text class="tree-cell-text" inherits="crop,value,align" flex="1" crop="right"/>
    </content>
  </binding>
  
  <binding id="treecell-indented-leaf">
    <content autostretch="never">
      <xul:treeindentation/>
      <xul:image class="tree-cell-primary-icon" inherits="src"/>
      <xul:text class="tree-cell-text" inherits="crop,value,align" flex="1" crop="right"/>
    </content>
  </binding>

  <binding id="treecell-text" extends="xul:text">
    <content crop="right"/>
  </binding>

  <binding id="treecell">
    <content autostretch="never">
       <xul:text class="tree-cell-text" inherits="crop,value,align" flex="1" crop="right"/>
    </content>
  </binding>

  <binding id="treecell-align-right">
    <content autostretch="never">
      <xul:spring flex="5"/>
      <xul:text class="tree-cell-text" inherits="crop,value,align" flex="1" crop="right"/>
    </content>
  </binding>

  <binding id="treecell-iconic">
    <content autostretch="never">
      <xul:image class="tree-cell-icon" inherits="src"/>
      <xul:text class="tree-cell-text" inherits="crop,value,align" flex="1" crop="right"/>
    </content>
  </binding>

  <binding id="treecell-image">
    <content autostretch="never">
      <xul:image class="tree-cell-image" inherits="src"/>
    </content>
  </binding>
 
  <binding id="treecell-header">
    <content autostretch="never">
      <xul:image class="tree-header-image" inherits="src"/>
      <xul:text class="tree-header-text" inherits="crop,value" flex="1" crop="right"/>
      <xul:image class="tree-header-sortdirection"/>
    </content>
  </binding>
  
  <binding id="tree">
    <content>
      <children/>
      <xul:treerows class="tree-container-treerows" inherits="dragover,dragdroptree">
        <children includes="treehead|treechildren"/>
      </xul:treerows> 
    </content>
    <implementation>
      <property name="selectedIndex"
                onget="return (this.selectedItems.length > 0 ? this.getIndexOfItem(this.selectedItems[0]) : -1)"
                onset="if(val>=0){var item=this.getItemAtIndex(val); if(item) this.selectItem(item);} else this.clearItemSelection();"
                />
      <property name="treeBoxObject"
                onget="return this.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);"
                readonly="true"/>
      <property name="isUpSelection">
        0
      </property>
      <property name="isDownSelection">
        0
      </property>
      <method name="getNextItem">
        <parameter name="startItem"/>
        <parameter name="delta"/>
        <body>
          return this.treeBoxObject.getNextItem(startItem, delta);
        </body>
      </method>
      <method name="getPreviousItem">
        <parameter name="startItem"/>
        <parameter name="delta"/>
        <body>
          return this.treeBoxObject.getPreviousItem(startItem, delta);
        </body>
      </method>
      <method name="getIndexOfItem">
        <parameter name="item"/>
        <body>
          return this.treeBoxObject.getIndexOfItem(item);
        </body>
      </method>
      <method name="getItemAtIndex">
        <parameter name="index"/>
        <body>
          return this.treeBoxObject.getItemAtIndex(index);
        </body>
      </method>
      <method name="ensureIndexIsVisible">
        <parameter name="index"/>
        <body>
          return this.treeBoxObject.ensureIndexIsVisible(index);
        </body>
      </method>
      <method name="ensureElementIsVisible">
        <parameter name="element"/>
        <body>
          return this.ensureIndexIsVisible(this.treeBoxObject.getIndexOfItem(element));
        </body>
      </method>
      <method name="scrollToIndex">
        <parameter name="index"/>
        <body>
          return this.treeBoxObject.scrollToIndex(index);
        </body>
      </method>
      <method name="getNumberOfVisibleRows">
        <body>
          return this.treeBoxObject.getNumberOfVisibleRows();
        </body>
      </method>
      <method name="getIndexOfFirstVisibleRow">
        <body>
          return this.treeBoxObject.getIndexOfFirstVisibleRow();
        </body>
      </method>
      <method name="getRowCount">
        <body>
          return this.treeBoxObject.getRowCount();
        </body>
      </method>
    </implementation>
    <handlers>
      <handler event="keypress" keycode="vk_enter">
        <![CDATA[
         if (event.target != this || selectedItems.length != 1)
           return;
         this.selectedItems[0].toggleOpenState();
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_return">
        <![CDATA[
         if (event.target != this || selectedItems.length != 1)
           return;
         this.selectedItems[0].toggleOpenState();
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_left">
        <![CDATA[
         if (event.target != this || this.selectedItems.length != 1)
           return;
         if (this.selectedItems[0].getAttribute("open") != "true") {
           var el = this.selectedItems[0].parentNode.parentNode 
           if ( el && (el.tagName != "tree") ) this.selectItem(el);
         }
         else {
           var el = this.selectedItems[0];
           el.close();
         }
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_right">
        <![CDATA[
         if (event.target != this || this.selectedItems.length != 1)
           return;
         this.selectedItems[0].open();
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_up">
        <![CDATA[
         if (event.target != this || this.selectedItems.length < 1)
           return;
         this.isUpSelection=0;
         this.isDownSelection=0;
         var n = this.getPreviousItem(this.selectedItems[this.selectedItems.length-1], 1);
         if (n) {
           this.ensureIndexIsVisible(this.getIndexOfItem(n));
           this.timedSelect(n, 500);
         }
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_down">
        <![CDATA[
         if (event.target != this)
           return;

         if (this.selectedItems.length == 0) {
           var n = this.getItemAtIndex(0);
         }
         else {
           this.isUpSelection=0;
           this.isDownSelection=0;
           var n = this.getNextItem(this.selectedItems[this.selectedItems.length-1], 1);
         }

         if (n) {
           this.ensureIndexIsVisible(this.getIndexOfItem(n));
           this.timedSelect(n, 500);
         }
        ]]>
      </handler>
      <handler event="keypress" modifiers="shift" keycode="vk_up">
        <![CDATA[
         var l=this.selectedItems.length;
         if (event.target != this || l < 1 || this.getAttribute("multiple") != "true")
           return;
         var n = this.getPreviousItem(this.selectedItems[l-1], 1);
         if (n) {
           this.ensureElementIsVisible(n);
           if ( this.isDownSelection) {
             if ( l > 1 )
               this.removeItemFromSelection(this.selectedItems[l-1]);
             if ( l <= 2 )
               this.isDownSelection=0;
	   }
           else {
             this.addItemToSelection(n);
             this.isUpSelection=1;
           }
         }
        ]]>
      </handler>
      <handler event="keypress" modifiers="shift" keycode="vk_down">
        <![CDATA[
         var l=this.selectedItems.length;
         if (event.target != this || l < 1 || this.getAttribute("multiple") != "true")
           return;
         var n = this.getNextItem(this.selectedItems[l-1], 1);
         if (n) {
           this.ensureElementIsVisible(n);
           if ( this.isUpSelection) {
             if ( l > 1 )
	       this.removeItemFromSelection(this.selectedItems[l-1]);
             if ( l <= 2 )
               this.isUpSelection=0;
           }
           else {
             this.addItemToSelection(n);
             this.isDownSelection=1;
           }
         }
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_up">
        <![CDATA[
         var l = this.selectedItems.length;
         if (event.target != this || l < 1)
           return;
         this.isUpSelection=0;
         this.isDownSelection=0;
         var i = this.getIndexOfFirstVisibleRow();
         if ( i == 0 )
           var n=this.getItemAtIndex(0);
         else {
           var v = this.getNumberOfVisibleRows();
           n = this.getPreviousItem(this.selectedItems[l-1], v);
           var newIndex = i - v;
           if ( ! n || newIndex < 0 ) {
             newIndex=0;
             n=this.getItemAtIndex(this.getIndexOfItem(this.selectedItems[l-1]) - i);
           }
           this.scrollToIndex(newIndex);
         }
         this.timedSelect(n, 500);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_down">
        <![CDATA[
         var l = this.selectedItems.length;
         if (event.target != this || l < 1)
           return;
         this.isUpSelection=0;
         this.isDownSelection=0;
         var i = this.getIndexOfFirstVisibleRow();
         var v = this.getNumberOfVisibleRows();
         var count = this.getRowCount();
         if ( i >= count - v )
           var n=this.getItemAtIndex(count - 1);
         else {
           n = this.getNextItem(this.selectedItems[l-1], v);
           var newIndex = i + v;
           if ( ! n || newIndex > count - v ) {
             newIndex = count - v;
             n = this.getItemAtIndex(newIndex + this.getIndexOfItem(this.selectedItems[l-1]) - i);
           }
           this.scrollToIndex(newIndex);
         }
         this.timedSelect(n, 500);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_home">
        <![CDATA[
         if (event.target != this || this.selectedItems.length < 1)
           return;
         this.isUpSelection=0;
         this.isDownSelection=0;
         this.scrollToIndex(0);
         this.selectItem(this.getItemAtIndex(0));
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_end">
        <![CDATA[
         if (event.target != this || this.selectedItems.length < 1)
           return;
         this.isUpSelection=0;
         this.isDownSelection=0;
         var count = this.getRowCount();
         this.ensureIndexIsVisible(count-1);
         this.selectItem(this.getItemAtIndex(count-1));
        ]]>
      </handler>
    </handlers>    
  </binding>

  <binding id="treerows">
    <content outer="true"/>
    <handlers>
      <!-- If there is no modifier key, we select on mousedown, not
           click, so that drags work correctly. -->
      <handler event="mousedown">
      <![CDATA[
         if (event.originalTarget.localName == 'treecell' && !event.ctrlKey && !event.shiftKey && !event.metaKey) {
           var isSelected = event.target.parentNode.parentNode.getAttribute("selected");
           if (!isSelected) {
             parentNode.selectItem(event.originalTarget.parentNode.parentNode);
           }
           parentNode.currentItem = event.originalTarget.parentNode.parentNode;
         }
      ]]>
      </handler>

      <!-- On a click (up+down on the same item), deselect everything
           except this item. -->
      <handler event="click">
      <![CDATA[
         var t = event.originalTarget;
         if (t.localName == 'treecell') {
           if (event.ctrlKey || event.metaKey) {
             parentNode.toggleItemSelection(t.parentNode.parentNode);
             parentNode.currentItem = t.parentNode.parentNode;
           }
           else if (event.shiftKey) {
             parentNode.selectItemRange(null, t.parentNode.parentNode);
             parentNode.currentItem = t.parentNode.parentNode;
           }
           else {
             /* We want to deselect all the selected items except what was
                clicked, UNLESS it was a right-click.  We have to do this
                in click rather than mousedown so that you can drag a
                selected group of items */

             if (event.button == 1) {
               var selectedItems = parentNode.selectedItems;
               var didSuppressSelect = false;
               var i = 0;
               while (i < selectedItems.length) {
                 if (selectedItems[i] != t.parentNode.parentNode) {
                   if (!didSuppressSelect) {
                     parentNode.suppressOnSelect = true;
                     didSuppressSelect = true;
                   }
                   parentNode.removeItemFromSelection(selectedItems[i]);
                 }
                 else
                   i++;
               }
               if (didSuppressSelect)
                 parentNode.suppressOnSelect = false;
             }
           }
         }
      ]]>
      </handler>

      <!-- double-click -->
      <handler event="click" clickcount="2">
      <![CDATA[
         if (event.originalTarget.localName == 'treecell') {
           var n = event.originalTarget.parentNode.parentNode;
           n.toggleOpenState();
         }
      ]]>
      </handler>

      <!-- normal, single click -->
      <handler event="click">
      <![CDATA[
         try {
           if (event.originalTarget.getAttribute('twisty') == 'true') {
             var n = event.originalTarget.parentNode.parentNode.parentNode;
             n.toggleOpenState();
            }
         } catch (e) {}
      ]]>
      </handler>
      
    </handlers>
  </binding>
 
  <binding id="listbox" extends="xul:tree">
    <content>
      <xul:cols>
        <xul:col flex="1"/>
      </xul:cols>
      <xul:treerows>
        <xul:treerows>
          <children includes="listhead"/>
          <xul:treechildren>
            <children/>
          </xul:treechildren>
        </xul:treerows>
      </xul:treerows> 
    </content>    
  </binding>

  <binding id="listhead" extends="xul:treehead">
    <content>
      <xul:treerow>
        <xul:treecell inherits="value" class="listcell-header"/>
      </xul:treerow>
    </content>
  </binding>

  <binding id="listitem" extends="xul:treeitem">
    <content>
      <xul:treerow>
        <xul:treecell inherits="value" class="listcell-text"/>
      </xul:treerow>
    </content>
  </binding>

</bindings>

