diff --git a/browser/components/places/content/controller.js b/browser/components/places/content/controller.js index 4c4013e5138..6aedea4ed41 100755 --- a/browser/components/places/content/controller.js +++ b/browser/components/places/content/controller.js @@ -186,6 +186,7 @@ PlacesController.prototype = { return PlacesUtils.tm.numberOfRedoItems > 0; case "cmd_cut": case "cmd_delete": + case "placesCmd_moveBookmarks": return !this.rootNodeIsSelected() && !this._selectionOverlapsSystemArea() && this._hasRemovableSelection(); @@ -340,6 +341,9 @@ PlacesController.prototype = { case "placesCmd_show:info": this.showBookmarkPropertiesForSelection(); break; + case "placesCmd_moveBookmarks": + this.moveSelectedBookmarks(); + break; #endif } }, @@ -371,16 +375,15 @@ PlacesController.prototype = { * are non-removable. We don't need to worry about recursion here since it * is a policy decision that a removable item not be placed inside a non- * removable item. - * @returns true if the selection contains no nodes that cannot be removed, - * false otherwise. + * @returns true if the there's a selection which has no nodes that cannot be removed, + * false otherwise. */ _hasRemovableSelection: function PC__hasRemovableSelection() { - var v = this._view; - NS_ASSERT(v, "No active view - cannot paste!"); - if (!v) + if (!this._view.hasSelection) return false; - var nodes = v.getSelectionNodes(); - var root = v.getResult().root; + + var nodes = this._view.getSelectionNodes(); + var root = this._view.getResult().root; for (var i = 0; i < nodes.length; ++i) { var parent = nodes[i].parent || root; @@ -396,11 +399,9 @@ PlacesController.prototype = { if (PlacesUtils.nodeIsFolder(parent)) { var readOnly = PlacesUtils.bookmarks.getFolderReadonly(asFolder(parent).folderId); if (readOnly) - return !readOnly; + return false; } } - if (!v.hasSelection) - return !PlacesUtils.nodeIsReadOnly(root); return true; }, @@ -433,12 +434,8 @@ PlacesController.prototype = { * Determines whether or not nodes can be inserted relative to the selection. */ _canInsert: function PC__canInsert() { - var v = this._view; - NS_ASSERT(v, "No active view - cannot insert!"); - if (!v) - return false; - var nodes = v.getSelectionNodes(); - var root = v.getResult().root; + var nodes = this._view.getSelectionNodes(); + var root = this._view.getResult().root; for (var i = 0; i < nodes.length; ++i) { var parent = nodes[i].parent || root; if (PlacesUtils.nodeIsReadOnly(parent)) @@ -1114,6 +1111,15 @@ PlacesController.prototype = { PlacesUtils.tm.doTransaction(txn); }, + /** + * Opens a dialog for moving the selected nodes. + */ + moveSelectedBookmarks: function PC_moveBookmarks() { + window.openDialog("chrome://browser/content/places/moveBookmarks.xul", + "", "chrome, modal", + this._view.getSelectionNodes(), PlacesUtils.tm); + }, + /** * Creates a set of transactions for the removal of a range of items. A range is * an array of adjacent nodes in a view. @@ -2046,6 +2052,7 @@ function goUpdatePlacesCommands() { goUpdateCommand("placesCmd_new:bookmark"); goUpdateCommand("placesCmd_new:separator"); goUpdateCommand("placesCmd_show:info"); + goUpdateCommand("placesCmd_moveBookmarks"); // XXXmano todo: sort and livemarks commands handling #endif } diff --git a/browser/components/places/content/moveBookmarks.js b/browser/components/places/content/moveBookmarks.js new file mode 100644 index 00000000000..356d62d4f0f --- /dev/null +++ b/browser/components/places/content/moveBookmarks.js @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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 Places Move Bookmarks Dialog. + * + * The Initial Developer of the Original Code is Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Asaf Romano + * + * 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 ***** */ + +var gMoveBookmarksDialog = { + _nodes: null, + _tm: null, + + _foldersTree: null, + get foldersTree() { + if (!this._foldersTree) + this._foldersTree = document.getElementById("foldersTree"); + + return this._foldersTree; + }, + + init: function() { + this._nodes = window.arguments[0]; + this._tm = window.arguments[1]; + }, + + onOK: function MBD_onOK(aEvent) { + var selectedNode = this.foldersTree.selectedNode; + if (!selectedNode) { + // XXXmano: the old dialog defaults to the the "Bookmarks" root folder + // for some reason. I'm pretty sure we don't want to that yet in Places, + // at least not until we make that folder node visible in the tree, if we + // ever do so + return; + } + var selectedFolderID = asFolder(selectedNode).folderId; + + var transactions = []; + for (var i=0; i < this._nodes.length; i++) { + var parentId = asFolder(this._nodes[i].parent).folderId; + + // Nothing to do if the node is already under the selected folder + if (parentId == selectedFolderID) + continue; + + var nodeIndex = PlacesUtils.getIndexOfNode(this._nodes[i]); + if (PlacesUtils.nodeIsFolder(this._nodes[i])) { + // Disallow moving a folder into itself + if (asFolder(this._nodes[i]).folderId != selectedFolderID) { + transactions.push(new + PlacesMoveFolderTransaction(asFolder(this._nodes[i]).folderId, + parentId, nodeIndex, + selectedFolderID, -1)); + } + } + else if (PlacesUtils.nodeIsBookmark(this._nodes[i])) { + transactions.push(new + PlacesMoveItemTransaction(PlacesUtils._uri(this._nodes[i].uri), + parentId, nodeIndex, + selectedFolderID, -1)); + } + else if (PlacesUtils.nodeIsSeparator(this._nodes[i])) { + // See makeTransaction in utils.js + var removeTxn = + new PlacesRemoveSeparatorTransaction(parentId, nodeIndex); + var createTxn = + new PlacesCreateSeparatorTransaction(selectedFolderID, -1); + transactions.push(new + PlacesAggregateTransaction("SeparatorMove", [removeTxn, createTxn])); + } + } + + if (transactions.length != 0) { + var txn = new PlacesAggregateTransaction("Move Items", transactions); + this._tm.doTransaction(txn); + } + }, + + newFolder: function MBD_newFolder() { + // The command is disabled when the tree is not focused + this.foldersTree.focus(); + goDoCommand("placesCmd_new:folder"); + } +}; diff --git a/browser/components/places/content/moveBookmarks.xul b/browser/components/places/content/moveBookmarks.xul new file mode 100644 index 00000000000..413fcff9cd8 --- /dev/null +++ b/browser/components/places/content/moveBookmarks.xul @@ -0,0 +1,84 @@ + + +# ***** 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 Places Organizer. +# +# The Initial Developer of the Original Code is Google Inc. +# Portions created by the Initial Developer are Copyright (C) 2005-2006 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Asaf Romano +# +# 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 ***** + + + + + + + + + %moveBookmarksDTD; +]> + + + +