home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 May / PCWorld_2003-05_cd.bin / Komunik / phoenix / chrome / toolkit.jar / content / global / nsTreeController.js < prev    next >
Text File  |  2002-08-05  |  10KB  |  321 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Netscape Public License
  6.  * Version 1.1 (the "License"); you may not use this file except in
  7.  * compliance with the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/NPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is mozilla.org code.
  16.  *
  17.  * The Initial Developer of the Original Code is 
  18.  * Netscape Communications Corporation.
  19.  * Portions created by the Initial Developer are Copyright (C) 1998
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Blake Ross <blaker@netscape.com> (Original Author)
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or 
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the NPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the NPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. // helper routines, for doing rdf-based cut/copy/paste/etc
  40. // this needs to be more generic!
  41.  
  42. const nsTransferable_contractid = "@mozilla.org/widget/transferable;1";
  43. const clipboard_contractid = "@mozilla.org/widget/clipboard;1";
  44. const rdf_contractid = "@mozilla.org/rdf/rdf-service;1";
  45. const supportswstring_contractid = "@mozilla.org/supports-string;1";
  46. const rdfc_contractid = "@mozilla.org/rdf/container;1";
  47.  
  48. const nsISupportsString = Components.interfaces.nsISupportsString;
  49. const nsIClipboard = Components.interfaces.nsIClipboard;
  50. const nsITransferable = Components.interfaces.nsITransferable;
  51. const nsIRDFLiteral = Components.interfaces.nsIRDFLiteral;
  52. const nsIRDFContainer = Components.interfaces.nsIRDFContainer;
  53.  
  54. var gRDF;
  55. var gClipboard;
  56.  
  57. function isContainer(tree, index)
  58. {
  59.   return tree.treeBoxObject.view.isContainer(index);
  60. }
  61.  
  62. function isContainerOpen(tree, index)
  63. {
  64.   return tree.treeBoxObject.view.isContainerOpen(index);
  65. }
  66.  
  67. function nsTreeController_SetTransferData(transferable, flavor, text)
  68. {
  69.   if (!text)
  70.     return;
  71.   var textData = Components.classes[supportswstring_contractid].createInstance(nsISupportsString);
  72.   textData.data = text;
  73.  
  74.   transferable.addDataFlavor(flavor);
  75.   transferable.setTransferData(flavor, textData, text.length*2);
  76. }
  77.  
  78. function nsTreeController_copy()
  79. {
  80.   var rangeCount = this.treeSelection.getRangeCount();
  81.   if (rangeCount < 1)
  82.     return false;
  83.    
  84.   // Build a url that encodes all the select nodes 
  85.   // as well as their parent nodes
  86.   var url = "";
  87.   var text = "";
  88.   var html = "";
  89.   var min = new Object();
  90.   var max = new Object();
  91.  
  92.   for (var i = rangeCount - 1; i >= 0; --i) {
  93.     this.treeSelection.getRangeAt(i, min, max);
  94.     for (var k = max.value; k >= min.value; --k) {
  95.       // If one of the selected items is
  96.       // a container, ignore it.
  97.       if (isContainer(this.tree, k))
  98.         continue;
  99.       var pageUrl  = this.treeView.getCellText(k, "URL");        
  100.       var pageName = this.treeView.getCellText(k, "Name");
  101.  
  102.       url += "ID:{" + pageUrl + "};";
  103.       url += "NAME:{" + pageName + "};";
  104.  
  105.       text += pageUrl + "\r";
  106.       html += "<a href='" + pageUrl + "'>";
  107.       if (pageName) html += pageName;
  108.         html += "</a><p>";
  109.     } 
  110.   }
  111.  
  112.   if (!url)
  113.     return false;
  114.  
  115.   // get some useful components
  116.   var trans = Components.classes[nsTransferable_contractid].createInstance(nsITransferable);
  117.   
  118.   if (!gClipboard)
  119.     gClipboard = Components.classes[clipboard_contractid].getService(Components.interfaces.nsIClipboard);
  120.  
  121.   gClipboard.emptyClipboard(nsIClipboard.kGlobalClipboard);
  122.  
  123.   this.SetTransferData(trans, "text/unicode", text);
  124.   this.SetTransferData(trans, "moz/bookmarkclipboarditem", url);
  125.   this.SetTransferData(trans, "text/html", html);
  126.  
  127.   gClipboard.setData(trans, null, nsIClipboard.kGlobalClipboard);
  128.   return true;
  129. }
  130.  
  131. function nsTreeController_cut()
  132. {
  133.   if (this.copy()) {
  134.     this.doDelete();
  135.     return true;            // copy succeeded, don't care if delete failed
  136.   }
  137.   return false;             // copy failed, so did cut
  138. }
  139.  
  140. function nsTreeController_selectAll()
  141. {
  142.   this.treeSelection.selectAll();
  143. }
  144.  
  145. function nsTreeController_delete()
  146. {  
  147.   var rangeCount = this.treeSelection.getRangeCount();
  148.   if (rangeCount < 1)
  149.     return false;      
  150.   
  151.   var datasource = this.tree.database;
  152.   var dsEnum = datasource.GetDataSources(); 
  153.   dsEnum.getNext();
  154.   var ds = dsEnum.getNext();
  155.  
  156.   var count = this.treeSelection.count;
  157.   
  158.   // XXX 9 is a random number, just looking for a sweetspot
  159.   // don't want to rebuild tree content for just a few items
  160.   if (count > 9)
  161.     ds.QueryInterface(Components.interfaces.nsIBrowserHistory).startBatchUpdate();
  162.  
  163.   var min = new Object(); 
  164.   var max = new Object();
  165.   var dirty = false;
  166.   for (var i = rangeCount - 1; i >= 0; --i) {
  167.     this.treeSelection.getRangeAt(i, min, max);
  168.     for (var k = max.value; k >= min.value; --k) {
  169.       if (!gRDF)
  170.         gRDF = Components.classes[rdf_contractid].getService(Components.interfaces.nsIRDFService);
  171.  
  172.       var IDRes = this.treeBuilder.getResourceAtIndex(k);
  173.       if (!IDRes)
  174.         continue;
  175.  
  176.       var root = this.tree.getAttribute('ref');
  177.       var parentIDRes;
  178.       try {
  179.         parentIDRes = this.treeBuilder.getResourceAtIndex(this.treeView.getParentIndex(k));
  180.       }
  181.       catch(ex) {
  182.         parentIDRes = gRDF.GetResource(root);
  183.       }
  184.       if (!parentIDRes)
  185.         continue;
  186.       
  187.       // otherwise remove the parent/child assertion then
  188.       var containment = gRDF.GetResource("http://home.netscape.com/NC-rdf#child");
  189.       ds.QueryInterface(Components.interfaces.nsIRDFDataSource).Unassert(parentIDRes, containment, IDRes);
  190.       dirty = true;
  191.     }
  192.   }
  193.  
  194.   if (dirty) {    
  195.     if (count > 9) {
  196.       ds.QueryInterface(Components.interfaces.nsIBrowserHistory).endBatchUpdate();
  197.       this.tree.builder.rebuild();
  198.     }
  199.  
  200.     try {
  201.       var remote = datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  202.       remote.Flush();
  203.     } catch (ex) {
  204.     }
  205.   }
  206.   if (max.value) {
  207.     var newIndex = max.value - (max.value - min.value);
  208.     if (newIndex >= this.treeView.rowCount)
  209.       --newIndex;
  210.     this.treeSelection.select(newIndex);
  211.   }
  212.   return true;
  213. }
  214.  
  215. function nsTreeController(tree)
  216. {
  217.   this._tree = tree;
  218.   tree.controllers.appendController(this);
  219. }
  220.  
  221. nsTreeController.prototype = 
  222. {
  223.   _treeSelection: null,
  224.   _treeView: null,
  225.   _treeBuilder: null,
  226.   _treeBoxObject: null,
  227.   _tree: null,
  228.   get tree()
  229.   {
  230.     return this._tree;
  231.   },
  232.   get treeBoxObject()
  233.   {
  234.     if (this._treeBoxObject)
  235.       return this._treeBoxObject;
  236.     return this._treeBoxObject = this.tree.treeBoxObject;
  237.   },
  238.   get treeView()
  239.   {
  240.     if (this._treeView)
  241.       return this._treeView;
  242.     return this._treeView = this.tree.treeBoxObject.view;
  243.   },
  244.   get treeSelection()
  245.   {
  246.     if (this._treeSelection)
  247.       return this._treeSelection;
  248.     return this._treeSelection = this.tree.treeBoxObject.view.selection;
  249.   },
  250.   get treeBuilder()
  251.   {
  252.     if (this._treeBuilder)
  253.       return this._treeBuilder;
  254.     return this._treeBuilder = this.tree.builder.
  255.                                    QueryInterface(Components.interfaces.nsIXULTreeBuilder);
  256.   },
  257.   SetTransferData : nsTreeController_SetTransferData,
  258.  
  259.   supportsCommand: function(command)
  260.   {
  261.     switch(command)
  262.     {
  263.       case "cmd_cut":
  264.       case "cmd_copy":
  265.       case "cmd_delete":
  266.       case "cmd_selectAll":
  267.         return true;
  268.       default:
  269.         return false;
  270.     }
  271.   },
  272.  
  273.   isCommandEnabled: function(command)
  274.   {
  275.     var haveCommand;
  276.     switch (command)
  277.     {
  278.       // commands which do not require selection              
  279.       case "cmd_selectAll":
  280.         var treeView = this.treeView;
  281.         return (treeView.rowCount !=  treeView.selection.count);
  282.                 
  283.       // these commands require selection
  284.       case "cmd_cut":
  285.         haveCommand = (this.cut != undefined);
  286.         break;
  287.       case "cmd_copy":
  288.         haveCommand = (this.copy != undefined);
  289.         break;
  290.       case "cmd_delete":
  291.         haveCommand = (this.doDelete != undefined);
  292.         break;
  293.     }
  294.         
  295.     // if we get here, then we have a command that requires selection
  296.     var haveSelection = (this.treeSelection.count);
  297.     return (haveCommand && haveSelection);
  298.   },
  299.  
  300.   doCommand: function(command)
  301.   {
  302.     switch(command)
  303.     {
  304.       case "cmd_cut":
  305.         return this.cut();
  306.       case "cmd_copy":
  307.         return this.copy();
  308.       case "cmd_delete":
  309.         return this.doDelete();        
  310.       case "cmd_selectAll":
  311.         return this.selectAll();
  312.     }
  313.     return false;
  314.   },
  315.   copy: nsTreeController_copy,
  316.   cut: nsTreeController_cut,
  317.   doDelete: nsTreeController_delete,
  318.   selectAll: nsTreeController_selectAll
  319. }
  320.  
  321.