<?xml version="1.0"?>

<bindings id="outlinerBindings"
   xmlns="http://www.mozilla.org/xbl"
   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  
  <binding id="outliner-base">
    <resources>
      <stylesheet src="chrome://global/content/bindings/outliner.css"/>
      <stylesheet src="chrome://global/skin/outliner.css"/>
    </resources>
  </binding>

  <binding id="outliner" extends="chrome://global/content/bindings/outliner.xml#outliner-base">
    <content orient="vertical">
      <xul:box class="outliner-columns">
        <children includes="outlinercol|splitter"/>
        <xul:outlinercol class="outliner-columnpicker" fixed="true"/>
      </xul:box>
      <xul:outlinerrows class="outliner-rows" flex="1">
        <children/>
      </xul:outlinerrows>
    </content>
    
    <implementation>
      <property name="outlinerBoxObject"
                onget="return this.boxObject.QueryInterface(Components.interfaces.nsIOutlinerBoxObject);"
                readonly="true"/>
      <property name="currentIndex"
                onget="return this.outlinerBoxObject.selection.currentIndex;"
                onset="return this.outlinerBoxObject.selection.currentIndex=val;"/>
      <property name="selectionHead">
        -1
      </property>
      <property name="selectionTail">
        -1
      </property>
    </implementation>
    
    <handlers>
      <handler event="focus" action="this.outlinerBoxObject.focused = true;"/>
      <handler event="blur" action="this.outlinerBoxObject.focused = false;"/>
  
      <handler event="dragenter" action="this.outlinerBoxObject.onDragEnter(event);"/>
      <handler event="dragexit" action="this.outlinerBoxObject.onDragExit(event);"/>
      <handler event="dragover" action="this.outlinerBoxObject.onDragOver(event);"/>
      <handler event="dragdrop" action="this.outlinerBoxObject.onDragDrop(event);"/>

      <handler event="keypress" keycode="vk_enter">
        <![CDATA[
         if (this.currentIndex == -1)
           return;
         if (this.outlinerBoxObject.view.isContainer(this.currentIndex))
           this.outlinerBoxObject.view.toggleOpenState(this.currentIndex);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_return">
        <![CDATA[
         if (this.currentIndex == -1)
           return;
         if (this.outlinerBoxObject.view.isContainer(this.currentIndex))
           this.outlinerBoxObject.view.toggleOpenState(this.currentIndex);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_left">
        <![CDATA[
         if (this.currentIndex == -1)
           return;
         if (!this.outlinerBoxObject.view.isContainer(this.currentIndex))
           return;
         if (this.outlinerBoxObject.view.isContainerOpen(this.currentIndex))
           this.outlinerBoxObject.view.toggleOpenState(this.currentIndex);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_right">
        <![CDATA[
         if (this.currentIndex == -1)
           return;
         if (!this.outlinerBoxObject.view.isContainer(this.currentIndex))
           return;
         if (!this.outlinerBoxObject.view.isContainerOpen(this.currentIndex))
           this.outlinerBoxObject.view.toggleOpenState(this.currentIndex);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_up">
        <![CDATA[
         var c = this.currentIndex;
         if (c == -1 || c == 0)
           return;
         this.selectionHead = -1;
         this.selectionTail = -1;
         this.outlinerBoxObject.selection.timedSelect(c-1, 500);
         this.outlinerBoxObject.ensureRowIsVisible(c-1);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_down">
        <![CDATA[
         var c = this.currentIndex;
         try { if (c+1 == this.outlinerBoxObject.view.rowCount)
           return;
         } catch (e) {}
         this.selectionHead = -1;
         this.selectionTail = -1;
         this.outlinerBoxObject.selection.timedSelect(c+1, 500);
         this.outlinerBoxObject.ensureRowIsVisible(c+1);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_up" modifiers="shift">
        <![CDATA[
         var c = this.currentIndex;
         if (c == -1 || c == 0)
           return;
         if (c == this.selectionTail) {
           if (this.selectionHead < this.selectionTail) {
             this.outlinerBoxObject.selection.toggleSelect(c);
             this.currentIndex = c - 1;
           }
           else {
             this.outlinerBoxObject.selection.toggleSelect(c - 1);
           }
         }
         else {
           this.outlinerBoxObject.selection.clearSelection();
           this.selectionHead = c;
           this.outlinerBoxObject.selection.rangedSelect(c, c - 1, true);
         }
         this.selectionTail = c - 1;
         this.outlinerBoxObject.ensureRowIsVisible(c - 1);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_down" modifiers="shift">
        <![CDATA[
         var c = this.currentIndex;
         try { if (c+1 == this.outlinerBoxObject.view.rowCount)
           return;
         } catch (e) {}
         if (c == this.selectionTail) {
           if (this.selectionHead > this.selectionTail) {
             this.outlinerBoxObject.selection.toggleSelect(c);
             this.currentIndex = c + 1;
           }
           else
             this.outlinerBoxObject.selection.toggleSelect(c + 1);
         }
         else {
           this.outlinerBoxObject.selection.clearSelection();
           this.selectionHead = c;
           this.outlinerBoxObject.selection.rangedSelect(c, c + 1, true);
         }
         this.selectionTail = c + 1;
         this.outlinerBoxObject.ensureRowIsVisible(c + 1);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_up" modifiers="control">
        <![CDATA[
         var c = this.currentIndex;
         if (c == -1 || c == 0)
           return;
         this.currentIndex = c-1;
         this.outlinerBoxObject.ensureRowIsVisible(c-1);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_down" modifiers="control">
        <![CDATA[
         var c = this.currentIndex;
         try { if (c+1 == this.outlinerBoxObject.view.rowCount)
           return;
         } catch (e) {}
         this.currentIndex = c+1;
         this.outlinerBoxObject.ensureRowIsVisible(c+1);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_up">
        <![CDATA[
         var c = this.currentIndex;
         if (c == 0)
           return;
         this.selectionHead = -1;
         this.selectionTail = -1;
         var f = this.outlinerBoxObject.getFirstVisibleRow();
         var i = 0;
         if (f > 0) {
           var p = this.outlinerBoxObject.getPageCount();
           if (f - p >= 0)
             i = c - p;
           else
             i = c - f;
           this.outlinerBoxObject.scrollByPages(-1);
         }
         this.outlinerBoxObject.selection.timedSelect(i, 500);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_down">
        <![CDATA[
         var c = this.currentIndex;
         var l = this.outlinerBoxObject.view.rowCount - 1;
         if (c == l)
           return;
         this.selectionHead = -1;
         this.selectionTail = -1;
         var f = this.outlinerBoxObject.getFirstVisibleRow();
         var p = this.outlinerBoxObject.getPageCount();
         var i = l;
         var lastTopRowIndex = l - p;
         if (f <= lastTopRowIndex) {
           if (f + p <= lastTopRowIndex)
             i = c + p;
           else
             i = lastTopRowIndex + c - f + 1;
           this.outlinerBoxObject.scrollByPages(1);
         }
         this.outlinerBoxObject.selection.timedSelect(i, 500);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_up" modifiers="shift">
        <![CDATA[
         var c = this.currentIndex;
         if (c == 0)
           return;
         var f = this.outlinerBoxObject.getFirstVisibleRow();
         var i = 0;
         if (f > 0) {
           var p = this.outlinerBoxObject.getPageCount();
           if (f - p >= 0)
             i = c - p;
           else
             i = c - f;
           this.outlinerBoxObject.scrollByPages(-1);
         }
         if (c == this.selectionTail) {
           if (this.selectionHead < this.selectionTail) {
             if (i < this.selectionHead) {
               this.outlinerBoxObject.selection.clearRange(c, this.selectionHead + 1);
               this.outlinerBoxObject.selection.rangedSelect(this.selectionHead - 1, i, true);
             }
             else {
               this.outlinerBoxObject.selection.clearRange(c, i + 1);
               this.currentIndex = i;
             }
           }
           else
             this.outlinerBoxObject.selection.rangedSelect(c - 1, i, true);
         }
         else {
           this.outlinerBoxObject.selection.clearSelection();
           this.selectionHead = c;
           this.outlinerBoxObject.selection.rangedSelect(c, i, true);
         }
         this.selectionTail = i;
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_down" modifiers="shift">
        <![CDATA[
         var c = this.currentIndex;
         var l = this.outlinerBoxObject.view.rowCount - 1;
         if (c == l)
           return;
         var f = this.outlinerBoxObject.getFirstVisibleRow();
         var p = this.outlinerBoxObject.getPageCount();
         var i = l;
         var lastTopRowIndex = l - p;
         if (f <= lastTopRowIndex) {
           if (f + p <= lastTopRowIndex)
             i = c + p;
           else
             i = lastTopRowIndex + c - f + 1;
           this.outlinerBoxObject.scrollByPages(1);
         }
         if (c == this.selectionTail) {
           if (this.selectionHead > this.selectionTail) {
             if (i > this.selectionHead) {
               this.outlinerBoxObject.selection.clearRange(c, this.selectionHead - 1);
               this.outlinerBoxObject.selection.rangedSelect(this.selectionHead + 1, i, true);
             }
             else {
               this.outlinerBoxObject.selection.clearRange(c, i - 1);
               this.currentIndex = i;
             }
           }
           else
             this.outlinerBoxObject.selection.rangedSelect(c + 1, i, true);
         }
         else {
           this.outlinerBoxObject.selection.clearSelection();
           this.selectionHead = c;
           this.outlinerBoxObject.selection.rangedSelect(c, i, true);
         }
         this.selectionTail = i;
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_up" modifiers="control">
        <![CDATA[
         var c = this.currentIndex;
         if (c == 0)
           return;
         var f = this.outlinerBoxObject.getFirstVisibleRow();
         var i = 0;
         if (f > 0) {
           var p = this.outlinerBoxObject.getPageCount();
           if (f - p >= 0)
             i = c - p;
           else
             i = c - f;
           this.outlinerBoxObject.scrollByPages(-1);
         }
         this.currentIndex = i;
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_page_down" modifiers="control">
        <![CDATA[
         var c = this.currentIndex;
         var l = this.outlinerBoxObject.view.rowCount - 1;
         if (c == l)
           return;
         var f = this.outlinerBoxObject.getFirstVisibleRow();
         var p = this.outlinerBoxObject.getPageCount();
         var i = l;
         var lastTopRowIndex = l - p;
         if (f <= lastTopRowIndex) {
           if (f + p <= lastTopRowIndex)
             i = c + p;
           else
             i = lastTopRowIndex + c - f + 1;
           this.outlinerBoxObject.scrollByPages(1);
         }
         this.currentIndex = i;
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_home">
        <![CDATA[
         if (this.currentIndex == 0)
           return;
         this.selectionHead = -1;
         this.selectionTail = -1;
         this.outlinerBoxObject.selection.timedSelect(0, 500);
         this.outlinerBoxObject.ensureRowIsVisible(0);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_end">
        <![CDATA[
         var l = this.outlinerBoxObject.view.rowCount - 1;
         if (this.currentIndex == l)
           return;
         this.selectionHead = -1;
         this.selectionTail = -1;
         this.outlinerBoxObject.selection.timedSelect(l, 500);
         this.outlinerBoxObject.ensureRowIsVisible(l);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_home" modifiers="shift">
        <![CDATA[
         var c = this.currentIndex;
         if (c == 0)
           return;
         if (c != this.selectionTail) {
           this.outlinerBoxObject.selection.clearSelection();
           this.selectionHead = c;
         }
         this.outlinerBoxObject.selection.rangedSelect(c, 0, true);
         this.selectionTail = 0;
         this.outlinerBoxObject.ensureRowIsVisible(0);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_end" modifiers="shift">
        <![CDATA[
         var c = this.currentIndex;
         var l = this.outlinerBoxObject.view.rowCount - 1;
         if (c == l)
           return;
         if (c != this.selectionTail) {
           this.outlinerBoxObject.selection.clearSelection();
           this.selectionHead = c;
         }
         this.outlinerBoxObject.selection.rangedSelect(c, l, true);
         this.selectionTail = l;
         this.outlinerBoxObject.ensureRowIsVisible(l);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_home" modifiers="control">
        <![CDATA[
         if (this.currentIndex == 0)
           return;
         this.currentIndex = 0;
         this.outlinerBoxObject.ensureRowIsVisible(0);
        ]]>
      </handler>
      <handler event="keypress" keycode="vk_end" modifiers="control">
        <![CDATA[
         var l = this.outlinerBoxObject.view.rowCount - 1;
         if (this.currentIndex == l)
           return;
         this.currentIndex = l;
         this.outlinerBoxObject.ensureRowIsVisible(l);
        ]]>
      </handler>
      <handler event="keypress">
        <![CDATA[
         if (event.keyCode == ' ') {
           var c = this.currentIndex;
           if (!this.outlinerBoxObject.selection.isSelected(c))
             this.outlinerBoxObject.selection.toggleSelect(c);
         }
         ]]>
      </handler>
    </handlers>    
  </binding>

  <binding id="outlinerrows" extends="chrome://global/content/bindings/outliner.xml#outliner-base">
    <resources>
      <stylesheet src="chrome://global/content/bindings/outliner.css"/>
      <stylesheet src="chrome://global/skin/outliner.css"/>
    </resources>

    <content>
      <xul:box flex="1" class="outliner-bodybox">
        <children/>
      </xul:box>
      <xul:scrollbar align="vertical" class="outliner-scrollbar"/>
    </content>
  </binding>

  <binding id="outlinerbody" extends="chrome://global/content/bindings/outliner.xml#outliner-base">
    <handlers>
      <!-- If there is no modifier key, we select on mousedown, not
           click, so that drags work correctly. -->
      <handler event="mousedown">
      <![CDATA[
         if (!event.ctrlKey && !event.shiftKey && !event.metaKey) {
           var row = {};
           var col = {};
           var obj = {};
           var b = this.parentNode.outlinerBoxObject;
           b.getCellAt(event.clientX, event.clientY, row, col, obj);

           try {
             if (row.value >= b.view.rowCount) return;
           } catch (e) { return; }
           
		   if (obj.value != "twisty") {
		     var column = document.getElementById(col.value);
		     var cycler = column.getAttribute('cycler') == 'true';

		     if (cycler)
			   b.view.cycleCell(row.value, col.value);
		     else
			   if (!b.selection.isSelected(row.value))
			     b.selection.select(row.value);
		   }
         }
      ]]>
      </handler>

      <!-- On a click (up+down on the same item), deselect everything
           except this item. -->
      <handler event="click">
      <![CDATA[
         if (event.button != 0) return;
         var row = {};
         var col = {};
		 var obj = {};
         var b = this.parentNode.outlinerBoxObject;
         b.getCellAt(event.clientX, event.clientY, row, col, obj);

         try {
           if (row.value >= b.view.rowCount) return;
         } catch (e) { return; }

		 if (obj.value == "twisty") {
           b.view.toggleOpenState(row.value);
		   return;
		 }
         var augment = event.ctrlKey || event.metaKey;
         if (event.shiftKey) {
           b.selection.rangedSelect(-1, row.value, augment);
           b.selection.currentIndex = row.value;
         }
         else if (augment) {
           b.selection.toggleSelect(row.value);
           b.selection.currentIndex = row.value;
         }
         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 */

           var column = document.getElementById(col.value);
           var cycler = column.getAttribute('cycler') == 'true';

           if (!cycler && event.button == 0)
             b.selection.select(row.value);  
         }
      ]]>
      </handler>

      <!-- double-click -->
      <handler event="click" clickcount="2">
      <![CDATA[
           var row = {};
           var col = {};
		   var obj = {};
           var b = this.parentNode.outlinerBoxObject;
           b.getCellAt(event.clientX, event.clientY, row, col, obj);

           try {
             if (row.value >= b.view.rowCount) return;
           } catch (e) { return; }
		   var column = document.getElementById(col.value);
		   var cycler = column.getAttribute('cycler') == 'true';

		   if (!cycler && obj.value != "twisty" && b.view.isContainer(row.value))
             b.view.toggleOpenState(row.value);
      ]]>
      </handler>
    </handlers>
  </binding>

  <binding id="outlinercol" extends="chrome://global/content/bindings/outliner.xml#outliner-base">
    <content>
      <xul:box class="outlinercol-box" flex="1" autostretch="never">
        <xul:image class="outliner-image" inherits="src"/>
        <xul:text class="outlinercol-text" inherits="crop,value=label" flex="1" crop="right"/>
        <xul:image class="outlinercol-sortdirection"/>
      </xul:box>
    </content>
    <handlers>
      <handler event="click" button="0" action="if (event.originalTarget == this) { this.parentNode.outlinerBoxObject.view.cycleHeader(this.id, this); }"/>
    </handlers>
  </binding>

  <binding id="outlinercol-image" extends="chrome://global/content/bindings/outliner.xml#outliner-base">
    <content>
      <xul:box class="outlinercol-image-box" flex="1" autostretch="never">
        <xul:image class="outlinercol-icon" inherits="src"/>
      </xul:box>
    </content>
    <handlers>
      <handler event="click" button="0" action="this.parentNode.outlinerBoxObject.view.cycleHeader(this.id, this)"/>
    </handlers>
  </binding>

  <binding id="columnpicker" extends="chrome://global/content/bindings/outliner.xml#outliner-base">
    <content>
      <xul:menu class="outliner-colpicker-menu" autostretch="never" allowevents="true">
        <xul:image class="outliner-colpicker-icon"/>
        <xul:menupopup popupanchor="bottomright" popupalign="topright"
                  oncreate="this.parentNode.parentNode.buildPopup(this);"/>
      </xul:menu>
    </content>
    
    <implementation>
       <method name="buildPopup">
         <parameter name="aPopup"/>
         <body>
           <![CDATA[
             var popupChild = aPopup.firstChild;
             var firstTime = !popupChild ? true : false;
             var currCol = this.parentNode.parentNode.firstChild;
             var count = 0;

             while (currCol) {
               while (currCol && currCol.localName != "outlinercol")
                 currCol = currCol.nextSibling;
 
               if (currCol && (currCol != this)) {
                 // Construct an entry for each cell in the row.
                 if (firstTime) {
                     var columnName = currCol.getAttribute("label");
                     popupChild = document.createElement("menuitem");
                     popupChild.setAttribute("type", "checkbox");
                     popupChild.setAttribute("label", columnName);
                     if (columnName == "") {
                       var display = currCol.getAttribute("display");
                       popupChild.setAttribute("label", display);
                     }
                     popupChild.setAttribute("colid", currCol.id);
                     popupChild.setAttribute("oncommand",
                                             "this.parentNode.parentNode.parentNode.toggleColumnState(this);");
                     if (currCol.getAttribute("hidden") != "true")
                       popupChild.setAttribute("checked", "true");
                     aPopup.appendChild(popupChild);
                 }
              } 
              if (currCol) 
                currCol = currCol.nextSibling;
            }
           ]]>
        </body>
       </method>
       <method name="toggleColumnState">
         <parameter name="aPopup"/>
         <body>
           <![CDATA[
             var colid = aPopup.getAttribute("colid");
             var colNode = document.getElementById(colid);
             if (colNode) {
               var checkedState = aPopup.getAttribute("checked");
               if (checkedState == "true")
                 colNode.removeAttribute("hidden");
               else
                 colNode.setAttribute("hidden", "true");
             }
           ]]>
         </body>
       </method>         
     </implementation>    
   </binding>
</bindings>

