/* -*- Mode: Java; 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 mozilla.org code. * * 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): * Blake Ross (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 ***** */ // helper routines, for doing rdf-based cut/copy/paste/etc // this needs to be more generic! const nsTransferable_contractid = "@mozilla.org/widget/transferable;1"; const clipboard_contractid = "@mozilla.org/widget/clipboard;1"; const rdf_contractid = "@mozilla.org/rdf/rdf-service;1"; const supportswstring_contractid = "@mozilla.org/supports-string;1"; const rdfc_contractid = "@mozilla.org/rdf/container;1"; const nsISupportsString = Components.interfaces.nsISupportsString; const nsIClipboard = Components.interfaces.nsIClipboard; const nsITransferable = Components.interfaces.nsITransferable; const nsIRDFLiteral = Components.interfaces.nsIRDFLiteral; const nsIRDFContainer = Components.interfaces.nsIRDFContainer; var gRDF; var gClipboard; function isContainer(tree, index) { return tree.treeBoxObject.view.isContainer(index); } function isContainerOpen(tree, index) { return tree.treeBoxObject.view.isContainerOpen(index); } function nsTreeController_SetTransferData(transferable, flavor, text) { if (!text) return; var textData = Components.classes[supportswstring_contractid].createInstance(nsISupportsString); textData.data = text; transferable.addDataFlavor(flavor); transferable.setTransferData(flavor, textData, text.length*2); } function nsTreeController_copy() { var rangeCount = this.treeSelection.getRangeCount(); if (rangeCount < 1) return false; // Build a url that encodes all the select nodes // as well as their parent nodes var url = ""; var text = ""; var html = ""; var min = new Object(); var max = new Object(); for (var i = rangeCount - 1; i >= 0; --i) { this.treeSelection.getRangeAt(i, min, max); for (var k = max.value; k >= min.value; --k) { // If one of the selected items is // a container, ignore it. if (isContainer(this.tree, k)) continue; var col = this.tree.columns["URL"]; var pageUrl = this.treeView.getCellText(k, col); col = this.tree.columns["Name"]; var pageName = this.treeView.getCellText(k, col); url += "ID:{" + pageUrl + "};"; url += "NAME:{" + pageName + "};"; text += pageUrl + "\r"; html += ""; if (pageName) html += pageName; html += "

"; } } if (!url) return false; // get some useful components var trans = Components.classes[nsTransferable_contractid].createInstance(nsITransferable); if (!gClipboard) gClipboard = Components.classes[clipboard_contractid].getService(Components.interfaces.nsIClipboard); gClipboard.emptyClipboard(nsIClipboard.kGlobalClipboard); this.SetTransferData(trans, "text/unicode", text); this.SetTransferData(trans, "moz/bookmarkclipboarditem", url); this.SetTransferData(trans, "text/html", html); gClipboard.setData(trans, null, nsIClipboard.kGlobalClipboard); return true; } function nsTreeController_cut() { if (this.copy()) { this.doDelete(); return true; // copy succeeded, don't care if delete failed } return false; // copy failed, so did cut } function nsTreeController_selectAll() { this.treeSelection.selectAll(); } function nsTreeController_delete() { var rangeCount = this.treeSelection.getRangeCount(); if (rangeCount < 1) return false; var datasource = this.tree.database; var dsEnum = datasource.GetDataSources(); dsEnum.getNext(); var ds = dsEnum.getNext() .QueryInterface(Components.interfaces.nsIRDFDataSource); var count = this.treeSelection.count; // XXX 9 is a random number, just looking for a sweetspot // don't want to rebuild tree content for just a few items if (count > 9) { ds.beginUpdateBatch(); } var min = new Object(); var max = new Object(); var dirty = false; for (var i = rangeCount - 1; i >= 0; --i) { this.treeSelection.getRangeAt(i, min, max); for (var k = max.value; k >= min.value; --k) { if (!gRDF) gRDF = Components.classes[rdf_contractid].getService(Components.interfaces.nsIRDFService); var IDRes = this.treeBuilder.getResourceAtIndex(k); if (!IDRes) continue; var root = this.tree.getAttribute('ref'); var parentIDRes; try { parentIDRes = this.treeBuilder.getResourceAtIndex(this.treeView.getParentIndex(k)); } catch(ex) { parentIDRes = gRDF.GetResource(root); } if (!parentIDRes) continue; // otherwise remove the parent/child assertion then var containment = gRDF.GetResource("http://home.netscape.com/NC-rdf#child"); ds.Unassert(parentIDRes, containment, IDRes); dirty = true; } } if (count > 9) { ds.endUpdateBatch(); } if (dirty) { try { var remote = datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource); remote.Flush(); } catch (ex) { } } if (max.value) { var newIndex = max.value - (max.value - min.value); if (newIndex >= this.treeView.rowCount) --newIndex; this.treeSelection.select(newIndex); } return true; } function nsTreeController(tree) { this._tree = tree; tree.controllers.appendController(this); } nsTreeController.prototype = { _treeSelection: null, _treeView: null, _treeBuilder: null, _treeBoxObject: null, _tree: null, get tree() { return this._tree; }, get treeBoxObject() { if (this._treeBoxObject) return this._treeBoxObject; return this._treeBoxObject = this.tree.treeBoxObject; }, get treeView() { if (this._treeView) return this._treeView; return this._treeView = this.tree.treeBoxObject.view; }, get treeSelection() { if (this._treeSelection) return this._treeSelection; return this._treeSelection = this.tree.treeBoxObject.view.selection; }, get treeBuilder() { if (this._treeBuilder) return this._treeBuilder; return this._treeBuilder = this.tree.builder. QueryInterface(Components.interfaces.nsIXULTreeBuilder); }, SetTransferData : nsTreeController_SetTransferData, supportsCommand: function(command) { switch(command) { case "cmd_cut": case "cmd_copy": case "cmd_delete": case "cmd_selectAll": return true; default: return false; } }, isCommandEnabled: function(command) { var haveCommand; switch (command) { // commands which do not require selection case "cmd_selectAll": var treeView = this.treeView; return (treeView.rowCount != treeView.selection.count); // these commands require selection case "cmd_cut": haveCommand = (this.cut != undefined); break; case "cmd_copy": haveCommand = (this.copy != undefined); break; case "cmd_delete": haveCommand = (this.doDelete != undefined); break; } // if we get here, then we have a command that requires selection var haveSelection = (this.treeSelection.count); return (haveCommand && haveSelection); }, doCommand: function(command) { switch(command) { case "cmd_cut": return this.cut(); case "cmd_copy": return this.copy(); case "cmd_delete": return this.doDelete(); case "cmd_selectAll": return this.selectAll(); } return false; }, copy: nsTreeController_copy, cut: nsTreeController_cut, doDelete: nsTreeController_delete, selectAll: nsTreeController_selectAll }