2006-06-15 22:35:48 +00:00
////////////////////////////////////////////////////////////////////////////////
///
/// ItemTreeView
/// -- handles the link between an individual tree and the data layer
/// -- displays only items (no collections, no hierarchy)
///
////////////////////////////////////////////////////////////////////////////////
/ *
* Constructor the the ItemTreeView object
* /
2006-05-31 20:29:46 +00:00
Scholar . ItemTreeView = function ( itemGroup )
2006-05-30 16:37:51 +00:00
{
2006-06-09 14:42:53 +00:00
this . _itemGroup = itemGroup ;
2006-05-30 16:37:51 +00:00
this . _treebox = null ;
2006-06-06 22:43:58 +00:00
this . _savedSelection = null ;
2006-06-01 17:54:41 +00:00
this . refresh ( ) ;
2006-06-01 20:03:53 +00:00
this . _unregisterID = Scholar . Notifier . registerItemTree ( this ) ;
2006-06-01 18:50:16 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Called by the tree itself
* /
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . setTree = function ( treebox )
{
if ( this . _treebox )
return ;
this . _treebox = treebox ;
2006-06-12 12:43:20 +00:00
if ( ! this . isSorted ( ) )
{
this . cycleHeader ( this . _treebox . columns . getNamedColumn ( 'firstCreator' ) ) ;
}
else
{
this . sort ( ) ;
}
2006-06-09 14:42:53 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Reload the rows from the data access methods
* ( doesn ' t call the tree . invalidate methods , etc . )
* /
2006-06-01 18:50:16 +00:00
Scholar . ItemTreeView . prototype . refresh = function ( )
{
this . _dataItems = new Array ( ) ;
this . rowCount = 0 ;
var newRows = this . _itemGroup . getChildItems ( ) ;
for ( var i = 0 ; i < newRows . length ; i ++ )
2006-06-06 20:33:49 +00:00
if ( newRows [ i ] )
this . _showItem ( newRows [ i ] , i + 1 ) ; //item ref, before row
2006-06-01 18:50:16 +00:00
this . _refreshHashMap ( ) ;
}
2006-06-15 22:35:48 +00:00
/ *
* Called by Scholar . Notifier on any changes to items in the data layer
* /
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . notify = function ( action , type , ids )
2006-06-01 18:50:16 +00:00
{
2006-06-09 14:42:53 +00:00
var madeChanges = false ;
this . selection . selectEventsSuppressed = true ;
this . saveSelection ( ) ;
if ( ( action == 'remove' && ! this . _itemGroup . isLibrary ( ) ) || ( action == 'delete' && this . _itemGroup . isLibrary ( ) ) )
{
ids = Scholar . flattenArguments ( ids ) ;
//Since a remove involves shifting of rows, we have to do it in order
//sort the ids by row
var rows = new Array ( ) ;
for ( var i = 0 , len = ids . length ; i < len ; i ++ )
if ( action == 'delete' || ! this . _itemGroup . ref . hasItem ( ids [ i ] ) )
rows . push ( this . _itemRowMap [ ids [ i ] ] ) ;
if ( rows . length > 0 )
{
rows . sort ( function ( a , b ) { return a - b } ) ;
for ( var i = 0 , len = rows . length ; i < len ; i ++ )
{
var row = rows [ i ] ;
this . _hideItem ( row - i ) ;
this . _treebox . rowCountChanged ( row - i , - 1 ) ;
}
madeChanges = true ;
}
}
else if ( action == 'modify' ) //must check for null because it could legitimately be 0
{
2006-06-17 00:57:50 +00:00
if ( this . _itemRowMap [ ids ] != null )
2006-06-09 14:42:53 +00:00
{
this . _treebox . invalidateRow ( row ) ;
madeChanges = true ;
}
}
else if ( action == 'add' )
{
var item = Scholar . Items . get ( ids ) ;
if ( ( this . _itemGroup . isLibrary ( ) || item . inCollection ( this . _itemGroup . ref . getID ( ) ) ) && this . _itemRowMap [ ids ] == null )
{
this . _showItem ( item , this . rowCount ) ;
this . _treebox . rowCountChanged ( this . rowCount - 1 , 1 ) ;
madeChanges = true ;
}
}
if ( madeChanges )
{
if ( this . isSorted ( ) )
{
this . sort ( ) ; //this also refreshes the hash map
this . _treebox . invalidate ( ) ;
}
else if ( action != 'modify' ) //no need to update this if we just modified
{
this . _refreshHashMap ( ) ;
}
if ( action == 'add' )
2006-06-17 00:57:50 +00:00
{
2006-06-09 14:42:53 +00:00
this . selection . select ( this . _itemRowMap [ item . getID ( ) ] ) ;
2006-06-17 00:57:50 +00:00
this . _treebox . ensureRowIsVisible ( this . _itemRowMap [ item . getID ( ) ] ) ;
}
2006-06-09 14:42:53 +00:00
else
2006-06-17 00:57:50 +00:00
{
2006-06-09 14:42:53 +00:00
this . rememberSelection ( ) ;
2006-06-17 00:57:50 +00:00
}
2006-06-09 14:42:53 +00:00
}
this . selection . selectEventsSuppressed = false ;
2006-05-30 16:37:51 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Unregisters view from Scholar . Notifier ( called on window close )
* /
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . unregister = function ( )
2006-05-30 16:37:51 +00:00
{
2006-06-09 14:42:53 +00:00
Scholar . Notifier . unregisterItemTree ( this . _unregisterID ) ;
2006-05-30 16:37:51 +00:00
}
2006-06-15 22:35:48 +00:00
////////////////////////////////////////////////////////////////////////////////
///
/// nsITreeView functions
/// http://www.xulplanet.com/references/xpcomref/ifaces/nsITreeView.html
///
////////////////////////////////////////////////////////////////////////////////
2006-05-30 16:37:51 +00:00
Scholar . ItemTreeView . prototype . getCellText = function ( row , column )
{
var obj = this . _getItemAtRow ( row ) ;
2006-06-12 12:43:20 +00:00
var val ;
2006-06-16 15:27:22 +00:00
if ( column . id == "numNotes" )
{
var c = obj . numNotes ( ) ;
if ( c ) //don't display '0'
val = c ;
}
else if ( column . id != "typeIcon" )
{
2006-06-12 12:43:20 +00:00
val = obj . getField ( column . id ) ;
2006-06-16 15:27:22 +00:00
}
2006-05-31 17:50:33 +00:00
if ( column . id == 'dateAdded' || column . id == 'dateModified' ) //this is not so much that we will use this format for date, but a simple template for later revisions.
{
2006-06-06 19:53:27 +00:00
val = new Date ( Date . parse ( val . replace ( /-/g , "/" ) ) ) . toLocaleString ( ) ;
2006-05-31 17:50:33 +00:00
}
return val ;
2006-05-30 16:37:51 +00:00
}
2006-06-09 16:36:18 +00:00
Scholar . ItemTreeView . prototype . getImageSrc = function ( row , col )
{
2006-06-12 12:43:20 +00:00
if ( col . id == 'typeIcon' )
2006-06-09 16:36:18 +00:00
{
2006-06-25 04:35:11 +00:00
var itemType = Scholar . ItemTypes . getName ( this . _getItemAtRow ( row ) . getType ( ) ) ;
2006-06-09 16:36:18 +00:00
return "chrome://scholar/skin/treeitem-" + itemType + ".png" ;
}
}
2006-06-05 15:49:11 +00:00
Scholar . ItemTreeView . prototype . isSorted = function ( )
{
for ( var i = 0 , len = this . _treebox . columns . count ; i < len ; i ++ )
if ( this . _treebox . columns . getColumnAt ( i ) . element . getAttribute ( 'sortActive' ) )
return true ;
return false ;
}
2006-05-30 16:37:51 +00:00
Scholar . ItemTreeView . prototype . cycleHeader = function ( column )
{
2006-06-05 15:49:11 +00:00
for ( var i = 0 , len = this . _treebox . columns . count ; i < len ; i ++ )
{
col = this . _treebox . columns . getColumnAt ( i ) ;
if ( column != col )
{
col . element . removeAttribute ( 'sortActive' ) ;
col . element . removeAttribute ( 'sortDirection' ) ;
}
else
{
col . element . setAttribute ( 'sortActive' , true ) ;
col . element . setAttribute ( 'sortDirection' , col . element . getAttribute ( 'sortDirection' ) == 'descending' ? 'ascending' : 'descending' ) ;
}
}
2006-06-06 22:43:58 +00:00
this . selection . selectEventsSuppressed = true ;
this . saveSelection ( ) ;
2006-06-05 15:49:11 +00:00
this . sort ( ) ;
2006-06-06 22:43:58 +00:00
this . rememberSelection ( ) ;
this . selection . selectEventsSuppressed = false ;
this . _treebox . invalidate ( ) ;
2006-06-05 15:49:11 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Sort the items by the currently sorted column .
* Simply uses Array . sort ( ) function , and refreshes the hash map .
* /
2006-06-05 15:49:11 +00:00
Scholar . ItemTreeView . prototype . sort = function ( )
{
var column = this . _treebox . columns . getSortedColumn ( )
var order = column . element . getAttribute ( 'sortDirection' ) == 'descending' ;
2006-06-12 12:43:20 +00:00
if ( column . id == 'typeIcon' )
2006-05-30 16:37:51 +00:00
{
function columnSort ( a , b )
{
2006-06-25 04:35:11 +00:00
var typeA = Scholar . getString ( 'itemTypes.' + Scholar . ItemTypes . getName ( a . getType ( ) ) ) ;
var typeB = Scholar . getString ( 'itemTypes.' + Scholar . ItemTypes . getName ( b . getType ( ) ) ) ;
2006-06-12 12:43:20 +00:00
return ( typeA > typeB ) ? - 1 : ( typeA < typeB ) ? 1 : 0 ;
2006-05-30 16:37:51 +00:00
}
}
2006-06-16 16:30:03 +00:00
else if ( column . id == 'numNotes' )
{
function columnSort ( a , b )
{
return b . numNotes ( ) - a . numNotes ( ) ;
}
}
2006-05-30 16:37:51 +00:00
else
{
function columnSort ( a , b )
{
2006-06-20 14:36:49 +00:00
var fieldA = a . getField ( column . id ) ;
var fieldB = b . getField ( column . id ) ;
if ( typeof fieldA == 'string' )
{
fieldA = fieldA . toLowerCase ( ) ;
fieldB = fieldB . toLowerCase ( ) ;
}
return ( fieldA > fieldB ) ? - 1 : ( fieldA < fieldB ) ? 1 : 0 ;
2006-05-30 16:37:51 +00:00
}
}
2006-06-16 16:30:03 +00:00
function doSort ( a , b )
{
var s = columnSort ( a , b ) ;
if ( s )
return s ;
else
return secondarySort ( a , b ) ;
}
2006-06-15 22:35:48 +00:00
function oppositeSort ( a , b )
2006-06-12 12:43:20 +00:00
{
2006-06-16 16:30:03 +00:00
return ( doSort ( a , b ) * - 1 ) ;
}
function secondarySort ( a , b )
{
return ( a . getField ( 'dateModified' ) > b . getField ( 'dateModified' ) ) ? - 1 : ( a . getField ( 'dateModified' ) < b . getField ( 'dateModified' ) ) ? 1 : 0 ;
2006-06-12 12:43:20 +00:00
}
if ( order )
2006-06-15 22:35:48 +00:00
this . _dataItems . sort ( oppositeSort ) ;
2006-06-12 12:43:20 +00:00
else
2006-06-16 16:30:03 +00:00
this . _dataItems . sort ( doSort ) ;
2006-06-12 12:43:20 +00:00
2006-05-30 16:37:51 +00:00
this . _refreshHashMap ( ) ;
2006-06-05 15:49:11 +00:00
2006-05-30 16:37:51 +00:00
}
2006-06-15 22:35:48 +00:00
////////////////////////////////////////////////////////////////////////////////
///
/// Additional functions for managing data in the tree
///
////////////////////////////////////////////////////////////////////////////////
/ *
* Delete the selection
* /
2006-05-30 16:37:51 +00:00
Scholar . ItemTreeView . prototype . deleteSelection = function ( )
{
if ( this . selection . count == 0 )
return ;
//create an array of selected items
2006-06-02 15:27:52 +00:00
var items = new Array ( ) ;
2006-05-30 16:37:51 +00:00
var start = new Object ( ) ;
var end = new Object ( ) ;
for ( var i = 0 , len = this . selection . getRangeCount ( ) ; i < len ; i ++ )
{
this . selection . getRangeAt ( i , start , end ) ;
for ( var j = start . value ; j <= end . value ; j ++ )
2006-06-02 15:27:52 +00:00
items . push ( this . _getItemAtRow ( j ) ) ;
2006-05-30 16:37:51 +00:00
}
//iterate and erase...
this . _treebox . beginUpdateBatch ( ) ;
2006-06-02 15:27:52 +00:00
for ( var i = 0 ; i < items . length ; i ++ )
2006-05-30 16:37:51 +00:00
{
2006-06-01 16:40:43 +00:00
if ( this . _itemGroup . isLibrary ( ) ) //erase item from DB
2006-06-02 15:27:52 +00:00
items [ i ] . erase ( ) ;
2006-06-01 16:40:43 +00:00
else if ( this . _itemGroup . isCollection ( ) )
2006-06-02 15:27:52 +00:00
this . _itemGroup . ref . removeItem ( items [ i ] . getID ( ) ) ;
2006-06-01 16:40:43 +00:00
2006-06-02 14:11:23 +00:00
/ * D i s a b l e d f o r n o w ( n o t i f i e r )
2006-05-30 16:37:51 +00:00
//remove row from tree:
this . _hideItem ( rows [ i ] - i ) ;
2006-06-02 12:59:58 +00:00
this . _treebox . rowCountChanged ( rows [ i ] - i , - 1 ) ; * /
2006-05-30 16:37:51 +00:00
}
this . _treebox . endUpdateBatch ( ) ;
}
2006-06-15 22:35:48 +00:00
/ *
* Set the search filter on the view
* /
2006-06-01 16:40:43 +00:00
Scholar . ItemTreeView . prototype . searchText = function ( search )
{
2006-06-06 22:43:58 +00:00
this . selection . selectEventsSuppressed = true ;
this . saveSelection ( ) ;
2006-06-06 20:33:49 +00:00
this . _itemGroup . setSearch ( search ) ;
var oldCount = this . rowCount ;
this . refresh ( ) ;
this . _treebox . rowCountChanged ( 0 , this . rowCount - oldCount ) ;
2006-06-06 22:43:58 +00:00
this . sort ( ) ;
this . rememberSelection ( ) ;
this . selection . selectEventsSuppressed = false ;
2006-06-06 20:33:49 +00:00
this . _treebox . invalidate ( ) ;
2006-06-01 16:40:43 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Called by various view functions to show a row
*
* item : reference to the Item
* beforeRow : row index to insert new row before
* /
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . _showItem = function ( item , beforeRow )
{
this . _dataItems . splice ( beforeRow , 0 , item ) ; this . rowCount ++ ;
2006-06-01 17:54:41 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Called by view to hide specified row
* /
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . _hideItem = function ( row )
2006-06-01 17:54:41 +00:00
{
2006-06-09 14:42:53 +00:00
this . _dataItems . splice ( row , 1 ) ; this . rowCount -- ;
2006-06-01 17:54:41 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Returns a reference to the item at row ( see Scholar . Item in data _access . js )
* /
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . _getItemAtRow = function ( row )
2006-06-01 17:54:41 +00:00
{
2006-06-09 14:42:53 +00:00
return this . _dataItems [ row ] ;
}
2006-06-07 16:19:56 +00:00
2006-06-09 15:52:40 +00:00
/ *
2006-06-15 22:35:48 +00:00
* Create hash map of item ids to row indexes
2006-06-09 15:52:40 +00:00
* /
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . _refreshHashMap = function ( )
2006-06-09 15:52:40 +00:00
{
2006-06-09 14:42:53 +00:00
this . _itemRowMap = new Array ( ) ;
for ( var i = 0 ; i < this . rowCount ; i ++ )
this . _itemRowMap [ this . _getItemAtRow ( i ) . getID ( ) ] = i ;
2006-06-02 12:59:58 +00:00
}
2006-06-15 22:35:48 +00:00
/ *
* Saves the ids of currently selected items for later
* /
2006-06-06 22:43:58 +00:00
Scholar . ItemTreeView . prototype . saveSelection = function ( )
{
this . _savedSelection = new Array ( ) ;
var start = new Object ( ) ;
var end = new Object ( ) ;
for ( var i = 0 , len = this . selection . getRangeCount ( ) ; i < len ; i ++ )
{
this . selection . getRangeAt ( i , start , end ) ;
for ( var j = start . value ; j <= end . value ; j ++ )
this . _savedSelection . push ( this . _getItemAtRow ( j ) . getID ( ) ) ;
}
}
2006-06-15 22:35:48 +00:00
/ *
* Sets the selection based on saved selection ids ( see above )
* /
2006-06-06 22:43:58 +00:00
Scholar . ItemTreeView . prototype . rememberSelection = function ( )
{
this . selection . clearSelection ( ) ;
for ( var i = 0 ; i < this . _savedSelection . length ; i ++ )
{
if ( this . _itemRowMap [ this . _savedSelection [ i ] ] != null )
this . selection . toggleSelect ( this . _itemRowMap [ this . _savedSelection [ i ] ] ) ;
}
}
2006-06-15 22:35:48 +00:00
////////////////////////////////////////////////////////////////////////////////
///
/// Drag-and-drop functions:
/// for nsDragAndDrop.js + nsTransferable.js
///
////////////////////////////////////////////////////////////////////////////////
2006-06-09 14:42:53 +00:00
2006-06-15 22:35:48 +00:00
/ *
* Begin a drag
* /
2006-06-08 18:42:55 +00:00
Scholar . ItemTreeView . prototype . onDragStart = function ( evt , transferData , action )
{
transferData . data = new TransferData ( ) ;
this . saveSelection ( ) ;
transferData . data . addDataForFlavour ( "scholar/item" , this . _savedSelection ) ;
}
2006-06-15 22:35:48 +00:00
/ *
* Called by nsDragAndDrop . js for any sort of drop on the tree
* /
2006-06-08 18:42:55 +00:00
Scholar . ItemTreeView . prototype . getSupportedFlavours = function ( )
{
var flavors = new FlavourSet ( ) ;
flavors . appendFlavour ( "scholar/item" ) ;
2006-06-14 15:51:05 +00:00
flavors . appendFlavour ( "text/x-moz-url" ) ;
2006-06-08 18:42:55 +00:00
return flavors ;
}
2006-06-15 22:35:48 +00:00
/ *
* Called by nsDragAndDrop . js for any sort of drop on the tree
* /
2006-06-14 15:51:05 +00:00
Scholar . ItemTreeView . prototype . onDrop = function ( evt , data , session )
{
var dataType = data . flavour . contentType ;
if ( dataType == 'scholar/item' )
{
2006-06-15 22:35:48 +00:00
var ids = data . data . split ( ',' ) ;
2006-06-14 15:51:05 +00:00
for ( var i = 0 ; i < ids . length ; i ++ )
this . _itemGroup . ref . addItem ( ids [ i ] ) ;
}
else if ( dataType == 'text/x-moz-url' )
{
2006-06-15 22:35:48 +00:00
var url = data . data . split ( "\n" ) [ 0 ] ;
/ * W A I T I N G F O R I N G E S T E R S U P P O R T
var newItem = Scholar . Ingester . scrapeURL ( url ) ;
if ( newItem )
this . _itemGroup . ref . addItem ( newItem . getID ( ) ) ;
* /
2006-06-14 15:51:05 +00:00
}
}
2006-06-08 18:42:55 +00:00
Scholar . ItemTreeView . prototype . onDragOver = function ( evt , dropdata , session ) { }
2006-06-09 14:42:53 +00:00
2006-06-15 22:35:48 +00:00
////////////////////////////////////////////////////////////////////////////////
///
/// Functions for nsITreeView that we have to stub out.
///
////////////////////////////////////////////////////////////////////////////////
2006-06-09 14:42:53 +00:00
2006-06-16 15:15:42 +00:00
Scholar . ItemTreeView . prototype . getParentIndex = function ( row ) { return - 1 ; }
2006-06-09 14:42:53 +00:00
Scholar . ItemTreeView . prototype . isSeparator = function ( row ) { return false ; }
Scholar . ItemTreeView . prototype . isContainer = function ( row ) { return false ; }
Scholar . ItemTreeView . prototype . getLevel = function ( row ) { return 0 ; }
Scholar . ItemTreeView . prototype . getRowProperties = function ( row , prop ) { }
Scholar . ItemTreeView . prototype . getColumnProperties = function ( col , prop ) { }
2006-06-09 16:36:18 +00:00
Scholar . ItemTreeView . prototype . getCellProperties = function ( row , col , prop ) { }