diff --git a/mozilla/xpfe/global/resources/content/nsOutlinerController.js b/mozilla/xpfe/global/resources/content/nsOutlinerController.js new file mode 100644 index 00000000000..ae3a8eb1979 --- /dev/null +++ b/mozilla/xpfe/global/resources/content/nsOutlinerController.js @@ -0,0 +1,449 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape 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/NPL/ + * + * 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 Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Peter Annema + * Blake Ross + * Alec Flett + */ + +// helper routines, for doing rdf-based cut/copy/paste/etc + +const NC_NS = "http://home.netscape.com/NC-rdf#"; +const RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; +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 separatorUri = NC_NS + "BookmarkSeparator"; +const supportswstring_contractid = "@mozilla.org/supports-wstring;1"; +const rdfc_contractid = "@mozilla.org/rdf/container;1"; + +// some oft-used interfaces +const nsISupportsWString = Components.interfaces.nsISupportsWString; +const nsIClipboard = Components.interfaces.nsIClipboard; +const nsITransferable = Components.interfaces.nsITransferable; +const nsIRDFLiteral = Components.interfaces.nsIRDFLiteral; +const nsIRDFContainer = Components.interfaces.nsIRDFContainer; + +var Clipboard = Components.classes[clipboard_contractid].getService(Components.interfaces.nsIClipboard); +var RDF = Components.classes[rdf_contractid].getService(Components.interfaces.nsIRDFService); + +var nameResource = RDF.GetResource(NC_NS + "Name"); +var typeRes = RDF.GetResource(RDF_NS + "type"); +var bmTypeRes = RDF.GetResource(NC_NS + "Bookmark"); +// this is a hack for now - just assume containment +var containment = RDF.GetResource(NC_NS + "child"); + +function isContainer(node) +{ + return node.getAttribute("container") == "true"; +} + +function getWStringData(wstring, len) +{ + wstring = wstring.QueryInterface(nsISupportsWString); + var result = wstring.data.substring(0, len/2); + return result; +} + +function nsTreeController_SetTransferData(transferable, flavor, text) +{ + if (!text) return; + var textData = Components.classes[supportswstring_contractid].createInstance(nsISupportsWString); + textData.data = text; + + transferable.addDataFlavor(flavor); + transferable.setTransferData(flavor, textData, text.length*2); +} + +function nsTreeController_copy(tree) +{ + var select_list = tree.selectedItems; + if (!select_list) return false; + if (select_list.length < 1) return false; + + var datasource = tree.database; + + // Build a url that encodes all the select nodes + // as well as their parent nodes + var url = ""; + var text = ""; + var html = ""; + + for (var nodeIndex = 0; nodeIndex < select_list.length; nodeIndex++) + { + var node = select_list[nodeIndex]; + if (!node) continue; + + // for now just use the .id attribute.. at some point we should support + // the #URL property for anonymous resources (see bookmarks.js) + //var ID = getAbsoluteID("bookmarksTree", node); + var ID = node.id; + + var IDRes = RDF.GetResource(ID); + + var nameNode = datasource.GetTarget(IDRes, nameResource, true); + nameNode = + nameNode.QueryInterface(nsIRDFLiteral); + + var theName = nameNode.Value; + + url += "ID:{" + ID + "};"; + url += "NAME:{" + theName + "};"; + + if (isContainer(node)) + { + // gack, need to generalize this + var type = node.getAttribute("type"); + if (type == seperatorUri) + { + // Note: can't encode separators in text, just html + html += "

"; + } + else + { + text += ID + "\r"; + + html += ""; + if (theName) html += theName; + html += "

"; + } + } + } + + if (url == "") return false; + + // get some useful components + var trans = Components.classes[nsTransferable_contractid].createInstance(nsITransferable); + + Clipboard.emptyClipboard(nsIClipboard.kGlobalClipboard); + + this.SetTransferData(trans, "moz/bookmarkclipboarditem", url); + this.SetTransferData(trans, "text/unicode", text); + this.SetTransferData(trans, "text/html", html); + + Clipboard.setData(trans, null, nsIClipboard.kGlobalClipboard); + return true; +} + +function nsTreeController_cut(tree) +{ + if (this.copy(tree)) { + this.doDelete(tree); + return true; // copy succeeded, don't care if delete failed + } else + return false; // copy failed, so did cut +} + +function nsOutlinerController_selectAll(outlinerNode) +{ + alert('hey'); + outlinerNode.outlinerBoxObject.view.selection.selectAll(); +} + +function nsTreeController_paste(tree) +{ + var select_list = tree.selectedItems; + if (!select_list) return false; + if (select_list.length != 1) return false; + + var datasource = tree.database; + + var pasteNodeID = select_list[0].id; + var isContainerFlag = isContainer(select_list[0]); + + + var trans_uri = "@mozilla.org/widget/transferable;1"; + var trans = Components.classes[nsTransferable_contractid].createInstance(nsITransferable); + trans.addDataFlavor("moz/bookmarkclipboarditem"); + + Clipboard.getData(trans, nsIClipboard.kGlobalClipboard); + var data = new Object(); + var dataLen = new Object(); + trans.getTransferData("moz/bookmarkclipboarditem", data, dataLen); + + var url = getWStringData(data.value, dataLen.value); + if (!url) return false; + + var strings = url.split(";"); + if (!strings) return false; + + var RDFC = Components.classes[rdfc_contractid].getService(nsIRDFContainer); + + var nameRes = RDF.GetResource(NC_NS + "Name"); + if (!nameRes) return false; + + pasteNodeRes = RDF.GetResource(pasteNodeID); + if (!pasteNodeRes) return false; + + var pasteContainerRes = null; + var pasteNodeIndex = -1; + if (isContainerFlag == true) + { + pasteContainerRes = pasteNodeRes; + } + else + { + var parID = select_list[0].parentNode.parentNode.getAttribute("ref"); + if (!parID) { + parID = select_list[0].parentNode.parentNode.getAttribute("id"); + } + if (!parID) return false; + pasteContainerRes = RDF.GetResource(parID); + if (!pasteContainerRes) return false; + } + RDFC.Init(datasource, pasteContainerRes); + + if (isContainerFlag == false) + { + pasteNodeIndex = RDFC.IndexOf(pasteNodeRes); + if (pasteNodeIndex < 0) return false; // how did that happen? + } + + var dirty = false; + for (var x=0; x 0) + { + continue; + } + + // assert the name into the DS + if (theName) + { + var NameLiteral = RDF.GetLiteral(theName); + datasource.Assert(IDRes, nameRes, NameLiteral, true); + dirty = true; + } + + // add the element at the appropriate location + if (isContainerFlag == true) + { + RDFC.AppendElement(IDRes); + } + else + { + RDFC.InsertElementAt(IDRes, pasteNodeIndex++, true); + } + dirty = true; + + // make sure appropriate bookmark type is set + var bmTypeNode = datasource.GetTarget( IDRes, typeRes, true ); + if (!bmTypeNode) + { + // set default bookmark type + datasource.Assert(IDRes, typeRes, bmTypeRes, true); + } + } + + if (dirty) + { + var remote = datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource); + if (remote) + { + remote.Flush(); + } + } + return true; +} + +function nsTreeController_delete(tree) +{ + // this should eventually be a parameter to this function + var promptFlag = false; + + if (!tree) return false; + var select_list = tree.selectedItems; + if (!select_list) return false; + if (select_list.length < 1) return false; + + var datasource = tree.database; + + if (promptFlag == true) + { + var deleteStr = ''; + if (select_list.length == 1) { + deleteStr = get_localized_string("DeleteItem"); + } else { + deleteStr = get_localized_string("DeleteItems"); + } + var ok = confirm(deleteStr); + if (!ok) return false; + } + + var RDFC = Components.classes[rdfc_contractid].getService(nsIRDFContainer); + + + var dirty = false; + + // note: backwards delete so that we handle odd deletion cases such as + // deleting a child of a folder as well as the folder itself + for (var nodeIndex=select_list.length-1; nodeIndex>=0; nodeIndex--) + { + var node = select_list[nodeIndex]; + if (!node) continue; + var ID = node.id; + if (!ID) continue; + + // XXX - make tree templates flag special folders as read-only + // don't allow deletion of various "special" folders + if ((ID == "NC:BookmarksRoot") || (ID == "NC:IEFavoritesRoot")) + { + continue; + } + + var parentID = node.parentNode.parentNode.getAttribute("ref"); + if (!parentID) + parentID = node.parentNode.parentNode.id; + if (!parentID) continue; + + var IDRes = RDF.GetResource(ID); + if (!IDRes) continue; + var parentIDRes = RDF.GetResource(parentID); + if (!parentIDRes) continue; + + try { + // first try a container-based approach + RDFC.Init(datasource, parentIDRes); + RDFC.RemoveElement(IDRes, true); + } catch (ex) { + // nope! just remove the parent/child assertion then + datasource.Unassert(parentIDRes, containment, IDRes); + + } + dirty = true; + } + + if (dirty == true) + { + try { + var remote = datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource); + remote.Flush(); + } catch (ex) { + } + } + + return true; + +} + +function nsTreeController(tree) +{ + this.treeId = tree.id; + tree.controllers.appendController(this); +} + +nsTreeController.prototype = +{ + // store the tree's Id, rather than the tree, + // to avoid holding a strong ref + treeId: null, + getTree : function() + { + return document.getElementById(this.treeId); + }, + SetTransferData : nsTreeController_SetTransferData, + + supportsCommand: function(command) + { + switch(command) + { + case "cmd_cut": + case "cmd_copy": + case "cmd_paste": + 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_paste": + return (this.doPaste != undefined); + + case "cmd_selectAll": + // we can always select all + return true; + + // 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 tree = this.getTree(); + var haveSelection = (tree.selectedItems.length > 0); + return (haveCommand && haveSelection); + }, + doCommand: function(command) + { + switch(command) + { + case "cmd_cut": + return this.cut(this.getTree()); + + case "cmd_copy": + return this.copy(this.getTree()); + + case "cmd_paste": + return this.paste(this.getTree()); + + case "cmd_delete": + return this.doDelete(this.getTree()); + + case "cmd_selectAll": + return this.selectAll(this.getTree()); + } + return false; + }, + copy: nsTreeController_copy, + cut: nsTreeController_cut, + paste: nsTreeController_paste, + doDelete: nsTreeController_delete + selectAll: nsTreeController_selectAll +} +