RetroZilla/extensions/cview/resources/content/tree-utils.js
2015-10-20 23:03:22 -04:00

1248 lines
33 KiB
JavaScript

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is The JavaScript Debugger.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert Ginda, <rginda@netscape.com>, original author
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* BasicOView provides functionality of tree whose elements have no children.
* Usage:
* var myTree = new BasicOView()
* myTree.setColumnNames (["col 1", "col 2"]);
* myTree.data = [["row 1, col 1", "row 1, col 2"],
* ["row 2, col 1", "row 2, col 2"]];
* { override get*Properties, etc, as suits your purpose. }
*
* treeBoxObject.view = myTree;
*
* You'll need to make the appropriate myTree.tree.invalidate calls
* when myTree.data changes.
*/
function BasicOView()
{}
/* functions *you* should call to initialize and maintain the tree state */
/* scroll the line specified by |line| to the center of the tree */
BasicOView.prototype.centerLine =
function bov_ctrln (line)
{
var first = this.tree.getFirstVisibleRow();
var last = this.tree.getLastVisibleRow();
this.scrollToRow(line - total / 2);
}
/* call this to set the association between column names and data columns */
BasicOView.prototype.setColumnNames =
function bov_setcn (aryNames)
{
this.columnNames = new Object();
for (var i = 0; i < aryNames.length; ++i)
this.columnNames[aryNames[i]] = i;
}
/*
* scroll the source so |line| is at either the top, center, or bottom
* of the view, delepding on the value of |align|.
*
* line is the one based target line.
* if align is negative, the line will be scrolled to the top, if align is
* zero the line will be centered, and if align is greater than 0 the line
* will be scrolled to the bottom. 0 is the default.
*/
BasicOView.prototype.scrollTo =
function bov_scrollto (line, align)
{
var headerRows = 1;
var first = this.tree.getFirstVisibleRow();
var last = this.tree.getLastVisibleRow();
var viz = last - first - headerRows; /* total number of visible rows */
/* all rows are visible, nothing to scroll */
if (first == 0 && last > this.rowCount)
{
dd ("scrollTo: view does not overflow");
return;
}
/* tree lines are 0 based, we accept one based lines, deal with it */
--line;
/* safety clamp */
if (line < 0)
line = 0;
if (line > this.rowCount)
line = this.rowCount;
if (align < 0)
{
if (line > this.rowCount - viz) /* overscroll, can't put a row from */
line = this.rowCount - viz; /* last page at the top. */
this.tree.scrollToRow(line);
return;
}
else if (align > 0)
{
if (line < viz) /* underscroll, can't put a row from the first page at */
line = 0; /* the bottom. */
else
line = line - total_viz + headerRows;
this.tree.scrollToRow(line);
}
else
{
var half_viz = viz / 2;
/* lines past this line can't be centered without causing the tree
* to show more rows than we have. */
var lastCenterable = this.rowCount - half_viz;
if (line > lastCenterable)
line = lastCenterable;
/* lines before this can't be centered without causing the tree
* to attempt to display negative rows. */
else if (line < half_viz)
line = half_viz;
this.tree.scrollToRow(line - half_viz);
}
}
/*
* functions the tree will call to retrieve the list state (nsITreeView.)
*/
BasicOView.prototype.rowCount = 0;
BasicOView.prototype.selection = null;
BasicOView.prototype.getCellProperties =
function bov_cellprops (row, col, properties)
{}
BasicOView.prototype.getColumnProperties =
function bov_colprops (col, properties)
{}
BasicOView.prototype.getRowProperties =
function bov_rowprops (index, properties)
{}
BasicOView.prototype.isContainer =
function bov_isctr (index)
{
return false;
}
BasicOView.prototype.isContainerOpen =
function bov_isctropen (index)
{
return false;
}
BasicOView.prototype.isContainerEmpty =
function bov_isctrempt (index)
{
return false;
}
BasicOView.prototype.isSeparator =
function bov_iscontainer (index)
{
return false;
}
BasicOView.prototype.isSorted =
function bov_issorted (index)
{
return false;
}
BasicOView.prototype.canDrop =
function bov_drop (index, orientation)
{
return false;
}
BasicOView.prototype.drop =
function bov_drop (index, orientation)
{
return false;
}
BasicOView.prototype.getParentIndex =
function bov_getpi (index)
{
return 0;
}
BasicOView.prototype.hasNextSibling =
function bov_hasnxtsib (rowIndex, afterIndex)
{
return (afterIndex < (this.rowCount - 1));
}
BasicOView.prototype.getLevel =
function bov_getlvl (index)
{
return 0;
}
BasicOView.prototype.getImageSrc =
function bov_getimgsrc (row, col)
{
}
BasicOView.prototype.getProgressMode =
function bov_getprgmode (row, col)
{
}
BasicOView.prototype.getCellValue =
function bov_getcellval (row, col)
{
}
BasicOView.prototype.getCellText =
function bov_getcelltxt (row, col)
{
if (!this.columnNames)
return "";
var colName = this.columnNames[col.id];
if (typeof colName == "undefined")
return "";
return this.data[row][colName];
}
BasicOView.prototype.setTree =
function bov_seto (tree)
{
this.tree = tree;
}
BasicOView.prototype.toggleOpenState =
function bov_toggleopen (index)
{
}
BasicOView.prototype.cycleHeader =
function bov_cyclehdr (col)
{
}
BasicOView.prototype.selectionChanged =
function bov_selchg ()
{
}
BasicOView.prototype.cycleCell =
function bov_cyclecell (row, col)
{
}
BasicOView.prototype.isEditable =
function bov_isedit (row, col)
{
return false;
}
BasicOView.prototype.setCellValue =
function bov_setct (row, col, value)
{
}
BasicOView.prototype.setCellText =
function bov_setct (row, col, value)
{
}
BasicOView.prototype.performAction =
function bov_pact (action)
{
}
BasicOView.prototype.performActionOnRow =
function bov_pactrow (action)
{
}
BasicOView.prototype.performActionOnCell =
function bov_pactcell (action)
{
}
/*
* record for the TreeOView. these things take care of keeping the TreeOView
* properly informed of changes in value and child count. you shouldn't have
* to maintain tree state at all.
*
* |share| should be an otherwise empty object to store cache data.
* you should use the same object as the |share| for the TreeOView that you
* indend to contain these records.
*
*/
function TreeOViewRecord(share)
{
this._share = share;
this.visualFootprint = 1;
this.isHidden = true; /* records are considered hidden until they are
* inserted into a live tree */
}
/*
* walk the parent tree to find our tree container. return null if there is
* none
*/
TreeOViewRecord.prototype.findContainerTree =
function tovr_gettree ()
{
var parent = this.parentRecord
while (parent)
{
if ("_treeView" in parent)
return parent._treeView;
parent = parent.parentRecord
}
return null;
}
/* count the number of parents, not including the root node */
TreeOViewRecord.prototype.__defineGetter__("level", tovr_getLevel);
function tovr_getLevel ()
{
var rv = 0;
var parentRecord = this.parentRecord;
while ("parentRecord" in parentRecord &&
(parentRecord = parentRecord.parentRecord)) ++rv;
return rv;
}
/*
* associates a property name on this record, with a column in the tree. This
* method will set up a get/set pair for the property name you specify which
* will take care of updating the tree when the value changes. DO NOT try
* to change your mind later. Do not attach a different name to the same colID,
* and do no rename the colID. You have been warned.
*/
TreeOViewRecord.prototype.setColumnPropertyName =
function tovr_setcol (colID, propertyName)
{
function tovr_getValueShim ()
{
return this._colValues[colID];
}
function tovr_setValueShim (newValue)
{
this._colValues[colID] = newValue;
/* XXX this.invalidate(); */
return newValue;
}
if (!("_colValues" in this))
this._colValues = new Object();
if (typeof propertyName == "function")
{
this._colValues.__defineGetter__(colID, propertyName);
}
else
{
this.__defineGetter__(propertyName, tovr_getValueShim);
this.__defineSetter__(propertyName, tovr_setValueShim);
}
}
/*
* set the default sort column and resort.
*/
TreeOViewRecord.prototype.setSortColumn =
function tovr_setcol (colID, dir)
{
//dd ("setting sort column to " + colID);
this._share.sortColumn = colID;
this._share.sortDirection = (typeof dir == "undefined") ? 1 : dir;
this.resort();
}
/*
* set the default sort direction. 1 is ascending, -1 is descending, 0 is no
* sort. setting this to 0 will *not* recover the natural insertion order,
* it will only affect newly added items.
*/
TreeOViewRecord.prototype.setSortDirection =
function tovr_setdir (dir)
{
this._share.sortDirection = dir;
}
/*
* invalidate this row in the tree
*/
TreeOViewRecord.prototype.invalidate =
function tovr_invalidate()
{
var tree = this.findContainerTree();
if (tree)
{
var row = this.calculateVisualRow();
if (row != -1)
tree.tree.invalidateRow(row);
}
}
/*
* invalidate any data in the cache.
*/
TreeOViewRecord.prototype.invalidateCache =
function tovr_killcache()
{
this._share.rowCache = new Object();
this._share.lastComputedIndex = -1;
this._share.lastIndexOwner = null;
}
/*
* default comparator function for sorts. if you want a custom sort, override
* this method. We declare tovr_sortcmp as a top level function, instead of
* a function expression so we can refer to it later.
*/
TreeOViewRecord.prototype.sortCompare = tovr_sortcmp;
function tovr_sortcmp (a, b)
{
var sc = a._share.sortColumn;
var sd = a._share.sortDirection;
a = a[sc];
b = b[sc];
if (a < b)
return -1 * sd;
if (a > b)
return 1 * sd;
return 0;
}
/*
* this method will cause all child records to be resorted. any records
* with the default sortCompare method will be sorted by the colID passed to
* setSortColumn.
*
* the local parameter is used internally to control whether or not the
* sorted rows are invalidated. don't use it yourself.
*/
TreeOViewRecord.prototype.resort =
function tovr_resort (leafSort)
{
if (!("childData" in this) || this.childData.length < 1 ||
(this.childData[0].sortCompare == tovr_sortcmp &&
!("sortColumn" in this._share) || this._share.sortDirection == 0))
{
/* if we have no children, or we have the default sort compare and no
* sort flags, then just exit */
return;
}
this.childData.sort(this.childData[0].sortCompare);
for (var i = 0; i < this.childData.length; ++i)
{
this.childData[i].childIndex = i;
if ("isContainerOpen" in this.childData[i] &&
this.childData[i].isContainerOpen)
this.childData[i].resort(true);
else
this.childData[i].sortIsInvalid = true;
}
if (!leafSort)
{
this.invalidateCache();
var tree = this.findContainerTree();
if (tree && tree.tree)
{
var rowIndex = this.calculateVisualRow();
/*
dd ("invalidating " + rowIndex + " - " +
(rowIndex + this.visualFootprint - 1));
*/
tree.tree.invalidateRange (rowIndex,
rowIndex + this.visualFootprint - 1);
}
}
/*
else
dd("not a leafSort");
*/
delete this.sortIsInvalid;
}
/*
* call this to indicate that this node may have children at one point. make
* sure to call it before adding your first child.
*/
TreeOViewRecord.prototype.reserveChildren =
function tovr_rkids ()
{
if (!("childData" in this))
this.childData = new Array();
if (!("isContainerOpen" in this))
this.isContainerOpen = false;
}
/*
* add a child to the end of the child list for this record. takes care of
* updating the tree as well.
*/
TreeOViewRecord.prototype.appendChild =
function tovr_appchild (child)
{
if (!(child instanceof TreeOViewRecord))
throw Components.results.NS_ERROR_INVALID_PARAM;
var changeStart = (this.childData.length > 0) ?
this.childData[this.childData.length - 1].calculateVisualRow() :
this.calculateVisualRow();
child.isHidden = false;
child.parentRecord = this;
child.childIndex = this.childData.length;
this.childData.push(child);
if ("isContainerOpen" in this && this.isContainerOpen)
{
if (this.calculateVisualRow() >= 0)
{
this.resort(true); /* resort, don't invalidate. we're going to do
* that in the onVisualFootprintChanged call. */
}
this.onVisualFootprintChanged(changeStart, child.visualFootprint);
}
}
/*
* add a list of children to the end of the child list for this record.
* faster than multiple appendChild() calls.
*/
TreeOViewRecord.prototype.appendChildren =
function tovr_appchild (children, skipResort)
{
var changeStart = (this.childData.length > 0) ?
this.childData[this.childData.length - 1].calculateVisualRow() :
this.calculateVisualRow();
var start = this.childData.length;
var delta = 0;
var len = children.length;
for (var i = 0; i < len; ++i)
{
var child = children[i];
child.isHidden = false;
child.parentRecord = this;
this.childData[start + i] = child;
child.childIndex = i;
delta += child.visualFootprint;
}
if ("isContainerOpen" in this && this.isContainerOpen)
{
if (!skipResort && this.calculateVisualRow() >= 0)
{
this.resort(true); /* resort, don't invalidate. we're going to do
* that in the onVisualFootprintChanged call. */
}
this.onVisualFootprintChanged(changeStart, delta);
}
}
/*
* remove a child from this record. updates the tree too. DONT call this with
* an index not actually contained by this record.
*/
TreeOViewRecord.prototype.removeChildAtIndex =
function tovr_remchild (index)
{
for (var i = index + 1; i < this.childData.length; ++i)
--this.childData[i].childIndex;
var fpDelta = -this.childData[index].visualFootprint;
var changeStart = this.childData[index].calculateVisualRow();
this.childData[index].childIndex = -1;
delete this.childData[index].parentRecord;
arrayRemoveAt (this.childData, index);
this.invalidateCache();
this.onVisualFootprintChanged (changeStart, fpDelta);
}
/*
* hide this record and all descendants.
*/
TreeOViewRecord.prototype.hide =
function tovr_hide ()
{
if (this.isHidden)
return;
/* get the row before hiding */
var row = this.calculateVisualRow();
this.invalidateCache();
this.isHidden = true;
/* go right to the parent so we don't muck with our own visualFoorptint
* record, we'll need it to be correct if we're ever unHidden. */
this.parentRecord.onVisualFootprintChanged (row, -this.visualFootprint);
}
/*
* unhide this record and all descendants.
*/
TreeOViewRecord.prototype.unHide =
function tovr_uhide ()
{
if (!this.isHidden)
return;
this.isHidden = false;
this.invalidateCache();
var row = this.calculateVisualRow();
this.parentRecord.onVisualFootprintChanged (row, this.visualFootprint);
}
/*
* open this record, exposing it's children. DONT call this method if the record
* has no children.
*/
TreeOViewRecord.prototype.open =
function tovr_open ()
{
if (this.isContainerOpen)
return;
if ("onPreOpen" in this)
this.onPreOpen();
this.isContainerOpen = true;
var delta = 0;
for (var i = 0; i < this.childData.length; ++i)
{
if (!this.childData[i].isHidden)
delta += this.childData[i].visualFootprint;
}
this.resort(true);
this.visualFootprint += delta;
if ("parentRecord" in this)
this.parentRecord.onVisualFootprintChanged(this.calculateVisualRow(),
delta);
}
/*
* close this record, hiding it's children. DONT call this method if the record
* has no children, or if it is already closed.
*/
TreeOViewRecord.prototype.close =
function tovr_close ()
{
if (!this.isContainerOpen)
return;
this.isContainerOpen = false;
var delta = 1 - this.visualFootprint;
this.visualFootprint += delta;
if (this.parentRecord)
this.parentRecord.onVisualFootprintChanged(this.calculateVisualRow(),
delta);
if (this.onPostClose)
this.onPostClose();
}
/*
* called when a node above this one grows or shrinks. we need to adjust
* our own visualFootprint to match the change, and pass the message on.
*/
TreeOViewRecord.prototype.onVisualFootprintChanged =
function tovr_vpchange (start, amount)
{
/* if we're not hidden, but this notification came from a hidden node
* (start == -1), ignore it, it doesn't affect us. */
if (start == -1 && !this.isHidden)
{
//dd ("vfp change (" + amount + ") from hidden node ignored.");
return;
}
this.visualFootprint += amount;
if ("parentRecord" in this)
this.parentRecord.onVisualFootprintChanged(start, amount);
}
/*
* calculate the "visual" row for this record. If the record isn't actually
* visible return -1.
* eg.
* Name Visual Row
* node1 0
* node11 1
* node12 2
* node2 3
* node21 4
* node3 5
*/
TreeOViewRecord.prototype.calculateVisualRow =
function tovr_calcrow ()
{
/* if this is the second time in a row that someone asked us, fetch the last
* result from the cache. */
if (this._share.lastIndexOwner == this)
return this._share.lastComputedIndex;
var vrow;
/* if this is an uninserted or hidden node, or... */
if (!("parentRecord" in this) || (this.isHidden) ||
/* if parent isn't open, or... */
(!this.parentRecord.isContainerOpen) ||
/* parent isn't visible */
((vrow = this.parentRecord.calculateVisualRow()) == -1))
{
/* then we're not visible, return -1 */
//dd ("cvr: returning -1");
return -1;
}
/* parent is the root node XXX parent is not visible */
if (vrow == null)
vrow = 0;
else
/* parent is not the root node, add one for the space they take up. */
++vrow;
/* add in the footprint for all of the earlier siblings */
for (var i = 0; i < this.childIndex; ++i)
{
if (!this.parentRecord.childData[i].isHidden)
vrow += this.parentRecord.childData[i].visualFootprint;
}
/* save this calculation to the cache. */
this._share.lastIndexOwner = this;
this._share.lastComputedIndex = vrow;
//@DEBUG-cvr dd ("cvr: returning " + vrow);
return vrow;
}
/*
* locates the child record for the visible row |targetRow|. DO NOT call this
* with a targetRow less than this record's visual row, or greater than this
* record's visual row + the number of visible children it has.
*/
TreeOViewRecord.prototype.locateChildByVisualRow =
function tovr_find (targetRow, myRow)
{
if (targetRow in this._share.rowCache)
return this._share.rowCache[targetRow];
else if (0) {
/* XXX take this out later */
if (typeof myRow == "undefined")
myRow = this.calculateVisualRow();
else
{
ASSERT (myRow == this.calculateVisualRow(), "someone lied to me, " +
myRow + " != " + this.calculateVisualRow());
}
if (targetRow < myRow || targetRow > myRow + this.visualFootprint)
{
ASSERT (0, "I don't contain visual row " + targetRow + ", only " +
myRow + "..." + (myRow + this.visualFootprint));
return null;
}
}
/* if this is true, we *are* the index */
if (targetRow == myRow)
return (this._share.rowCache[targetRow] = this);
/* otherwise, we've got to search the kids */
var childStart = myRow; /* childStart represents the starting visual row
* for the child we're examining. */
for (var i = 0; i < this.childData.length; ++i)
{
var child = this.childData[i];
/* ignore hidden children */
if (child.isHidden)
continue;
/* if this kid is the targetRow, we're done */
if (childStart == targetRow)
return (this._share.rowCache[targetRow] = child);
/* if this kid contains the index, ask *it* to find the record */
else if (targetRow <= childStart + child.visualFootprint) {
/* this *has* to succeed */
var rv = child.locateChildByVisualRow(targetRow, childStart + 1);
//XXXASSERT (rv, "Can't find a row that *has* to be there.");
/* don't cache this, the previous call to locateChildByVisualRow
* just did. */
return rv;
}
/* otherwise, get ready to ask the next kid */
childStart += child.visualFootprint;
}
if (0) {
/* XXX take this out later */
ASSERT (0, "locateChildByVisualRow() failed. Asked for row " + targetRow +
", record only contains " + myRow + "..." +
(myRow + this.visualFootprint));
}
return null;
}
/* TOLabelRecords can be used to drop a label into an arbitrary place in an
* arbitrary tree. normally, specializations of TreeOViewRecord are tied to
* a specific tree because of implementation details. TOLabelRecords are
* specially designed (err, hacked) to work around these details. this makes
* them slower, but more generic.
*
* we set up a getter for _share that defers to the parent object. this lets
* TOLabelRecords work in any tree.
*/
function TOLabelRecord (columnName, label, property)
{
this.setColumnPropertyName (columnName, "label");
this.label = label;
this.property = property;
}
TOLabelRecord.prototype = new TreeOViewRecord (null);
TOLabelRecord.prototype.__defineGetter__("_share", tolr_getshare);
function tolr_getshare()
{
if (this.parentRecord)
return this.parentRecord._share;
else
{
ASSERT (0, "TOLabelRecord cannot be the root of a visible tree.");
return null;
}
}
/* TORootRecord is used internally by TreeOView, you probably don't need to make
* any of these */
function TORootRecord (tree, share)
{
this._share = share;
this._treeView = tree;
this.visualFootprint = 0;
this.isHidden = false;
this.reserveChildren();
this.isContainerOpen = true;
}
/* no cache passed in here, we set it in the TORootRecord contructor instead. */
TORootRecord.prototype = new TreeOViewRecord (null);
TORootRecord.prototype.open =
TORootRecord.prototype.close =
function torr_notimplemented()
{
/* don't do this on a root node */
}
TORootRecord.prototype.calculateVisualRow =
function torr_calcrow ()
{
return null;
}
TORootRecord.prototype.resort =
function torr_resort ()
{
if (!("childData" in this) || this.childData.length < 1 ||
(this.childData[0].sortCompare == tovr_sortcmp &&
!("sortColumn" in this._share) || this._share.sortDirection == 0))
{
/* if we have no children, or we have the default sort compare but we're
* missing a sort flag, then just exit */
return;
}
this.childData.sort(this.childData[0].sortCompare);
for (var i = 0; i < this.childData.length; ++i)
{
this.childData[i].childIndex = i;
if ("isContainerOpen" in this.childData[i] &&
this.childData[i].isContainerOpen)
this.childData[i].resort(true);
else
this.childData[i].sortIsInvalid = true;
}
if ("_treeView" in this && "tree" in this._treeView)
{
/*
dd ("root node: invalidating 0 - " + this.visualFootprint +
" for sort");
*/
this.invalidateCache();
this._treeView.tree.invalidateRange (0, this.visualFootprint);
}
}
TORootRecord.prototype.locateChildByVisualRow =
function torr_find (targetRow)
{
if (targetRow in this._share.rowCache)
return this._share.rowCache[targetRow];
var childStart = -1; /* childStart represents the starting visual row
* for the child we're examining. */
for (var i = 0; i < this.childData.length; ++i)
{
var child = this.childData[i];
/* ignore hidden children */
if (child.isHidden)
continue;
/* if this kid is the targetRow, we're done */
if (childStart == targetRow)
return (this._share.rowCache[targetRow] = child);
/* if this kid contains the index, ask *it* to find the record */
else if (targetRow <= childStart + child.visualFootprint) {
/* this *has* to succeed */
var rv = child.locateChildByVisualRow(targetRow, childStart + 1);
//XXXASSERT (rv, "Can't find a row that *has* to be there.");
/* don't cache this, the previous call to locateChildByVisualRow
* just did. */
return rv;
}
/* otherwise, get ready to ask the next kid */
childStart += child.visualFootprint;
}
return null;
}
TORootRecord.prototype.onVisualFootprintChanged =
function torr_vfpchange (start, amount)
{
this.invalidateCache();
this.visualFootprint += amount;
if ("_treeView" in this && "tree" in this._treeView)
{
if (amount != 0)
this._treeView.tree.rowCountChanged (start, amount);
else
this._treeView.tree.invalidateRow (start);
}
}
/*
* TreeOView provides functionality of tree whose elements have multiple
* levels of children.
*/
function TreeOView(share)
{
this.childData = new TORootRecord(this, share);
this.childData.invalidateCache();
}
/* functions *you* should call to initialize and maintain the tree state */
/* scroll the line specified by |line| to the center of the tree */
TreeOView.prototype.centerLine =
function bov_ctrln (line)
{
var first = this.tree.getFirstVisibleRow();
var last = this.tree.getLastVisibleRow();
this.scrollToRow(line - total / 2);
}
/*
* functions the tree will call to retrieve the list state (nsITreeView.)
*/
TreeOView.prototype.__defineGetter__("rowCount", tov_getRowCount);
function tov_getRowCount ()
{
return this.childData.visualFootprint;
}
TreeOView.prototype.isContainer =
function tov_isctr (index)
{
var row = this.childData.locateChildByVisualRow (index);
/*
ASSERT(row, "bogus row");
var rv = Boolean(row && row.childData);
dd ("isContainer: row " + index + " returning " + rv);
return rv;
*/
return Boolean(row && row.childData);
}
TreeOView.prototype.__defineGetter__("selectedIndex", tov_getsel);
function tov_getsel()
{
if (this.tree.view.selection.getRangeCount() < 1)
return -1;
var min = new Object();
this.tree.view.selection.getRangeAt(0, min, {});
return min.value;
}
TreeOView.prototype.__defineSetter__("selectedIndex", tov_setsel);
function tov_setsel(i)
{
this.tree.view.selection.timedSelect (i, 500);
return i;
}
TreeOView.prototype.scrollTo = BasicOView.prototype.scrollTo;
TreeOView.prototype.isContainerOpen =
function tov_isctropen (index)
{
var row = this.childData.locateChildByVisualRow (index);
/*
ASSERT(row, "bogus row");
var rv = Boolean(row && row.isContainerOpen);
dd ("isContainerOpen: row " + index + " returning " + rv);
return rv;
*/
return row && row.isContainerOpen;
}
TreeOView.prototype.toggleOpenState =
function tov_toggleopen (index)
{
var row = this.childData.locateChildByVisualRow (index);
//ASSERT(row, "bogus row");
if (row)
{
if (row.isContainerOpen)
row.close();
else
row.open();
}
}
TreeOView.prototype.isContainerEmpty =
function tov_isctrempt (index)
{
var row = this.childData.locateChildByVisualRow (index);
/*
ASSERT(row, "bogus row");
var rv = Boolean(row && (row.childData.length == 0));
dd ("isContainerEmpty: row " + index + " returning " + rv);
return rv;
*/
return !row || !row.childData;
}
TreeOView.prototype.getParentIndex =
function tov_getpi (index)
{
var row = this.childData.locateChildByVisualRow (index);
//ASSERT(row, "bogus row " + index);
var rv = row.parentRecord.calculateVisualRow();
//dd ("getParentIndex: row " + index + " returning " + rv);
return (rv != null) ? rv : -1;
}
TreeOView.prototype.hasNextSibling =
function tov_hasnxtsib (rowIndex, afterIndex)
{
var row = this.childData.locateChildByVisualRow (rowIndex);
/*
ASSERT(row, "bogus row");
rv = Boolean(row.childIndex < row.parentRecord.childData.length - 1);
dd ("hasNextSibling: row " + rowIndex + ", after " + afterIndex +
" returning " + rv);
return rv;
*/
return row.childIndex < row.parentRecord.childData.length - 1;
}
TreeOView.prototype.getLevel =
function tov_getlvl (index)
{
var row = this.childData.locateChildByVisualRow (index);
/*
ASSERT(row, "bogus row");
var rv = row.level;
dd ("getLevel: row " + index + " returning " + rv);
return rv;
*/
if (!row)
return 0;
return row.level;
}
TreeOView.prototype.getImageSrc =
function tov_getimgsrc (index, col)
{
}
TreeOView.prototype.getProgressMode =
function tov_getprgmode (index, col)
{
}
TreeOView.prototype.getCellValue =
function tov_getcellval (index, col)
{
}
TreeOView.prototype.getCellText =
function tov_getcelltxt (index, col)
{
var row = this.childData.locateChildByVisualRow (index);
//ASSERT(row, "bogus row " + index);
if (row._colValues)
return row._colValues[col.id];
else
return null;
}
TreeOView.prototype.getCellProperties =
function tov_cellprops (row, col, properties)
{}
TreeOView.prototype.getColumnProperties =
function tov_colprops (col, properties)
{}
TreeOView.prototype.getRowProperties =
function tov_rowprops (index, properties)
{}
TreeOView.prototype.isSeparator =
function tov_isseparator (index)
{
return false;
}
TreeOView.prototype.isSorted =
function tov_issorted (index)
{
return false;
}
TreeOView.prototype.canDrop =
function tov_dropon (index, orientation)
{
var row = this.childData.locateChildByVisualRow (index);
//ASSERT(row, "bogus row " + index);
return (row && ("canDrop" in row) && row.canDropOn(orientation));
}
TreeOView.prototype.drop =
function tov_drop (index, orientation)
{
var row = this.childData.locateChildByVisualRow (index);
//ASSERT(row, "bogus row " + index);
return (row && ("drop" in row) && row.drop(orientation));
}
TreeOView.prototype.setTree =
function tov_seto (tree)
{
this.tree = tree;
}
TreeOView.prototype.cycleHeader =
function tov_cyclehdr (col)
{
}
TreeOView.prototype.selectionChanged =
function tov_selchg ()
{
}
TreeOView.prototype.cycleCell =
function tov_cyclecell (row, col)
{
}
TreeOView.prototype.isEditable =
function tov_isedit (row, col)
{
return false;
}
TreeOView.prototype.setCellValue =
function tov_setct (row, col, value)
{
}
TreeOView.prototype.setCellText =
function tov_setct (row, col, value)
{
}
TreeOView.prototype.performAction =
function tov_pact (action)
{
}
TreeOView.prototype.performActionOnRow =
function tov_pactrow (action)
{
}
TreeOView.prototype.performActionOnCell =
function tov_pactcell (action)
{
}