зеркало из https://github.com/mozilla/gecko-dev.git
317631 - d&d support for places view by adding nsINavHistoryResultViewObserver interface to allow command controller to handle controllery treeview events. r=bryner... also a whole heck of a lot of other places stuff. hook up search box. implement many more commands. d&d, copy paste, etc.
This commit is contained in:
Родитель
dd2d7ad71c
Коммит
17a4d6b415
|
@ -51,7 +51,51 @@ const SELECTION_IS_CHANGEABLE = 0x10;
|
|||
const SELECTION_IS_REMOVABLE = 0x20;
|
||||
const SELECTION_IS_MOVABLE = 0x40;
|
||||
|
||||
const TYPE_X_MOZ_PLACE = "text/x-moz-place";
|
||||
const TYPE_X_MOZ_URL = "text/x-moz-url";
|
||||
const TYPE_HTML = "text/html";
|
||||
const TYPE_UNICODE = "text/unicode";
|
||||
|
||||
function STACK(args) {
|
||||
var temp = arguments.callee.caller;
|
||||
while (temp) {
|
||||
LOG("NAME: " + temp.name);
|
||||
temp = temp.arguments.callee.caller;
|
||||
}
|
||||
}
|
||||
|
||||
var PlacesController = {
|
||||
_uri: function PC__uri(spec) {
|
||||
var ios =
|
||||
Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(spec, null, null);
|
||||
},
|
||||
|
||||
/**
|
||||
* The Global Transaction Manager
|
||||
* XXXben - this needs to move into a service, because it ain't global!
|
||||
*/
|
||||
__txmgr: null,
|
||||
get _txmgr() {
|
||||
if (!this.__txmgr) {
|
||||
this.__txmgr =
|
||||
Cc["@mozilla.org/transactionmanager;1"].
|
||||
createInstance(Ci.nsITransactionManager);
|
||||
}
|
||||
return this.__txmgr;
|
||||
},
|
||||
|
||||
__bms: null,
|
||||
get _bms() {
|
||||
if (!this.__bms) {
|
||||
this.__bms =
|
||||
Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
}
|
||||
return this.__bms;
|
||||
},
|
||||
|
||||
_activeView: null,
|
||||
get activeView() {
|
||||
return this._activeView;
|
||||
|
@ -63,6 +107,7 @@ var PlacesController = {
|
|||
|
||||
isCommandEnabled: function PC_isCommandEnabled(command) {
|
||||
LOG("isCommandEnabled: " + command);
|
||||
return document.getElementById(command).getAttribute("disabled") == "true";
|
||||
},
|
||||
|
||||
supportsCommand: function PC_supportsCommand(command) {
|
||||
|
@ -72,13 +117,134 @@ var PlacesController = {
|
|||
|
||||
doCommand: function PC_doCommand(command) {
|
||||
LOG("doCommand: " + command);
|
||||
|
||||
},
|
||||
|
||||
onEvent: function PC_onEvent(eventName) {
|
||||
LOG("onEvent: " + eventName);
|
||||
},
|
||||
|
||||
_setEnabled: function PC__setEnabled(command, enabled) {
|
||||
var command = document.getElementById(command);
|
||||
// Prevents excessive setAttributes
|
||||
var disabled = command.hasAttribute("disabled");
|
||||
if (enabled && disabled)
|
||||
command.removeAttribute("disabled");
|
||||
else if (!enabled && !disabled)
|
||||
command.setAttribute("disabled", "true");
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether or not the selection can be removed, either by the
|
||||
* delete or cut operations based on whether or not any of its contents
|
||||
* 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.
|
||||
*/
|
||||
_hasRemovableSelection: function PC__hasRemovableSelection() {
|
||||
var nodes = this._activeView.getSelectionNodes();
|
||||
for (var i = 0; i < nodes.length; ++i) {
|
||||
if (nodes[i].readonly)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not the clipboard contains data that the active
|
||||
* view can support in a paste operation.
|
||||
* @returns true if the clipboard contains data compatible with the active
|
||||
* view, false otherwise.
|
||||
*/
|
||||
_hasClipboardData: function PC__hasClipboardData() {
|
||||
var types = this._activeView.supportedDropTypes;
|
||||
var flavors =
|
||||
Cc["@mozilla.org/supports-array;1"].
|
||||
createInstance(Ci.nsISupportsArray);
|
||||
for (var i = 0; i < types.length; ++i) {
|
||||
var cstring =
|
||||
Cc["@mozilla.org/supports-cstring;1"].
|
||||
createInstance(Ci.nsISupportsCString);
|
||||
cstring.data = types[i];
|
||||
flavors.AppendElement(cstring);
|
||||
}
|
||||
|
||||
var clipboard =
|
||||
Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
|
||||
return clipboard.hasDataMatchingFlavors(flavors,
|
||||
Ci.nsIClipboard.kGlobalClipboard);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not the paste command is enabled, based on the
|
||||
* content of the clipboard and the selection within the active view.
|
||||
*/
|
||||
_canPaste: function PC__canPaste() {
|
||||
// XXXben: check selection to see if insertion point would suggest pasting
|
||||
// into an immutable container.
|
||||
// XXXben: check clipboard for leaf data when pasting into views that can
|
||||
// only take non-leaf data. This is going to be hard because the
|
||||
// clipboard apis are teh suck.
|
||||
return this._hasClipboardData();
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not a ResultNode is a Bookmark folder or not.
|
||||
* @param node
|
||||
* A NavHistoryResultNode
|
||||
* @returns true if the node is a Bookmark folder, false otherwise
|
||||
*/
|
||||
nodeIsFolder: function PC_nodeIsFolder(node) {
|
||||
return node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER;
|
||||
},
|
||||
|
||||
onCommandUpdate: function PC_onCommandUpdate() {
|
||||
if (!this._activeView) {
|
||||
// Initial command update, no view yet.
|
||||
return;
|
||||
}
|
||||
|
||||
// Select All
|
||||
this._setEnabled("placesCmd_select:all",
|
||||
this._activeView.getAttribute("seltype") != "single");
|
||||
// Show Info
|
||||
var hasSingleSelection = this._activeView.hasSingleSelection;
|
||||
this._setEnabled("placesCmd_show:info", hasSingleSelection);
|
||||
// Cut
|
||||
var removableSelection = this._hasRemovableSelection();
|
||||
this._setEnabled("placesCmd_edit:cut", removableSelection);
|
||||
this._setEnabled("placesCmd_edit:delete", removableSelection);
|
||||
// Copy
|
||||
this._setEnabled("placesCmd_edit:copy", this._activeView.hasSelection);
|
||||
// Paste
|
||||
this._setEnabled("placesCmd_edit:paste", this._canPaste());
|
||||
// Open
|
||||
var hasSelectedURL = this._activeView.selectedURLNode != null;
|
||||
this._setEnabled("placesCmd_open", hasSelectedURL);
|
||||
this._setEnabled("placesCmd_open:window", hasSelectedURL);
|
||||
this._setEnabled("placesCmd_open:tab", hasSelectedURL);
|
||||
|
||||
// We can open multiple links in tabs if there is either:
|
||||
// a) a single folder selected
|
||||
// b) many links or folders selected
|
||||
var singleFolderSelected = hasSingleSelection &&
|
||||
this.nodeIsFolder(this._activeView.selectedNode);
|
||||
this._setEnabled("placesCmd_open:tabs",
|
||||
singleFolderSelected || !hasSingleSelection);
|
||||
|
||||
var viewIsFolder = this.nodeIsFolder(this._activeView.getResult());
|
||||
// Persistent Sort
|
||||
this._setEnabled("placesCmd_sortby:name", viewIsFolder);
|
||||
// New Folder
|
||||
this._setEnabled("placesCmd_new:folder", viewIsFolder);
|
||||
// New Separator
|
||||
// ...
|
||||
this._setEnabled("placesCmd_new:separator", false);
|
||||
// Feed Reload
|
||||
this._setEnabled("placesCmd_reload", false);
|
||||
},
|
||||
|
||||
buildContextMenu: function PC_buildContextMenu(popup) {
|
||||
if (document.popupNode.hasAttribute("view")) {
|
||||
var view = document.popupNode.getAttribute("view");
|
||||
|
@ -86,10 +252,24 @@ var PlacesController = {
|
|||
}
|
||||
|
||||
// Determine availability/enabled state of commands
|
||||
// ...
|
||||
for (var i = 0; i < popup.childNodes.length; ++i) {
|
||||
var item = popup.childNodes[i];
|
||||
if (item.hasAttribute("command")) {
|
||||
var disabled = !this.isCommandEnabled(item.getAttribute("command"));
|
||||
item.setAttribute("disabled", disabled);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Select all links in the current view.
|
||||
*/
|
||||
selectAll: function() {
|
||||
this._activeView.selectAll();
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a Mouse event, determine which function should be used to load
|
||||
* the selected link. Modifiers may override the default settings and cause
|
||||
|
@ -124,24 +304,27 @@ var PlacesController = {
|
|||
* Loads the selected URL in a new tab.
|
||||
*/
|
||||
openLinkInNewTab: function PC_openLinkInNewTab() {
|
||||
var view = this._activeView;
|
||||
view.browserWindow.openNewTabWith(view.selectedURLNode.url, null, null);
|
||||
var node = this._activeView.selectedURLNode;
|
||||
if (node)
|
||||
this._activeView.browserWindow.openNewTabWith(node.url, null, null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads the selected URL in a new window.
|
||||
*/
|
||||
openLinkInNewWindow: function PC_openLinkInNewWindow() {
|
||||
var view = this._activeView;
|
||||
view.browserWindow.openNewWindowWith(view.selectedURLNode.url, null, null);
|
||||
var node = this._activeView.selectedURLNode;
|
||||
if (node)
|
||||
this._activeView.browserWindow.openNewWindowWith(node.url, null, null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads the selected URL in the current window, replacing the Places page.
|
||||
*/
|
||||
openLinkInCurrentWindow: function PC_openLinkInCurrentWindow() {
|
||||
var view = this._activeView;
|
||||
view.browserWindow.loadURI(view.selectedURLNode.url, null, null);
|
||||
var node = this._activeView.selectedURLNode;
|
||||
if (node)
|
||||
this._activeView.browserWindow.loadURI(node.url, null, null);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -191,41 +374,654 @@ var PlacesController = {
|
|||
var value = { value: bundle.getString("newFolderDefault") };
|
||||
if (ps.prompt(window, title, text, value, null, { })) {
|
||||
var ip = view.insertionPoint;
|
||||
LOG("Insertion Point = " + ip.toSource());
|
||||
|
||||
var bms =
|
||||
Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
LOG("Insert Folder: " + value.value + " into: " + ip.container + " at: " + ip.index);
|
||||
var folder = bms.createFolder(ip.container, value.value, ip.index);
|
||||
var txn = new PlacesCreateFolderTransaction(value.value, ip.container,
|
||||
ip.index);
|
||||
this._txmgr.doTransaction(txn);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the selection
|
||||
* @param txnName
|
||||
* An optional name for the transaction if this is being performed
|
||||
* as part of another operation.
|
||||
*/
|
||||
remove: function() {
|
||||
var bms =
|
||||
Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
var ios =
|
||||
Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
remove: function PC_remove(txnName) {
|
||||
var nodes = this._activeView.getSelectionNodes();
|
||||
var txns = [];
|
||||
for (var i = 0; i < nodes.length; ++i) {
|
||||
var node = nodes[i];
|
||||
if (node.folderId) {
|
||||
LOG("Remove Folder: " + node.folderId);
|
||||
bms.removeFolder(node.folderId);
|
||||
var index = this.getIndexOfNode(node);
|
||||
if (node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER) {
|
||||
txns.push(new PlacesRemoveFolderTransaction(node.folderId,
|
||||
node.parent.folderId,
|
||||
index));
|
||||
}
|
||||
else {
|
||||
LOG("Remove: " + node.url + " from: " + node.parent.folderId);
|
||||
bms.removeItem(node.parent.folderId, ios.newURI(node.url, null, null));
|
||||
txns.push(new PlacesRemoveItemTransaction(this._uri(node.url),
|
||||
node.parent.folderId,
|
||||
index));
|
||||
}
|
||||
}
|
||||
var txn = new PlacesAggregateTransaction(txnName || "RemoveItems", txns);
|
||||
this._txmgr.doTransaction(txn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the index of a node within its parent container
|
||||
* @param node
|
||||
* The node to look up
|
||||
* @returns The index of the node within its parent container, or -1 if the
|
||||
* node was not found.
|
||||
*/
|
||||
getIndexOfNode: function PC_getIndexOfNode(node) {
|
||||
var parent = node.parent;
|
||||
var cc = parent.childCount;
|
||||
for (var i = 0; i < cc && parent.getChild(i) != node; ++i);
|
||||
return i < cc ? i : -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* String-wraps a NavHistoryResultNode according to the rules of the specified
|
||||
* content type.
|
||||
* @param node
|
||||
* The Result node to wrap (serialize)
|
||||
* @param type
|
||||
* The content type to serialize as
|
||||
* @returns A string serialization of the node
|
||||
*/
|
||||
wrapNode: function PC_wrapNode(node, type) {
|
||||
switch (type) {
|
||||
case TYPE_X_MOZ_PLACE:
|
||||
return node.folderId + "\n" + node.url + "\n" + node.parent.folderId + "\n" + this.getIndexOfNode(node);
|
||||
case TYPE_X_MOZ_URL:
|
||||
return node.url + "\n" + node.title;
|
||||
case TYPE_HTML:
|
||||
return "<A HREF=\"" + node.url + "\">" + node.title + "</A>";
|
||||
}
|
||||
// case TYPE_UNICODE:
|
||||
return node.url;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unwraps data from the Clipboard or the current Drag Session.
|
||||
* @param blob
|
||||
* A blob (string) of data, in some format we potentially know how
|
||||
* to parse.
|
||||
* @param type
|
||||
* The content type of the blob.
|
||||
* @returns An array of objects representing each item contained by the source.
|
||||
*/
|
||||
unwrapNodes: function PC_unwrapNodes(blob, type) {
|
||||
var parts = blob.split("\n");
|
||||
var nodes = [];
|
||||
for (var i = 0; i < parts.length; ++i) {
|
||||
var data = { };
|
||||
switch (type) {
|
||||
case TYPE_X_MOZ_PLACE:
|
||||
nodes.push({ folderId: parseInt(parts[i++]),
|
||||
uri: parts[i] ? this._uri(parts[i++]) : null,
|
||||
parent: parseInt(parts[i++]),
|
||||
index: parseInt(parts[i]) });
|
||||
break;
|
||||
case TYPE_X_MOZ_URL:
|
||||
nodes.push({ uri: this._uri(parts[i++]),
|
||||
title: parts[i] });
|
||||
break;
|
||||
case TYPE_UNICODE:
|
||||
nodes.push({ uri: this._uri(parts[i]) });
|
||||
break;
|
||||
default:
|
||||
LOG("Cannot unwrap data of type " + type);
|
||||
throw Cr.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a transaction for copying a leaf item from one container to another.
|
||||
* @param uri
|
||||
* The URI of the item being copied
|
||||
* @param container
|
||||
* The container being copied into
|
||||
* @param index
|
||||
* The index within the container the item is copied to
|
||||
* @returns A nsITransaction object that performs the copy.
|
||||
*/
|
||||
_getItemCopyTransaction: function (uri, container, index) {
|
||||
var itemTitle = this._bms.getItemTitle(uri);
|
||||
var createTxn = new PlacesCreateItemTransaction(uri, container, index);
|
||||
var editTxn = new PlacesEditItemTransaction(uri, { title: itemTitle });
|
||||
return new PlacesAggregateTransaction("ItemCopy", [createTxn, editTxn]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a Transaction for the drop or paste of a blob of data into
|
||||
* a container.
|
||||
* @param data
|
||||
* The unwrapped data blob of dropped or pasted data.
|
||||
* @param type
|
||||
* The content type of the data
|
||||
* @param container
|
||||
* The container the data was dropped or pasted into
|
||||
* @param index
|
||||
* The index within the container the item was dropped or pasted at
|
||||
* @param copy
|
||||
* The drag action was copy, so don't move folders or links.
|
||||
* @retunrs An object implementing nsITransaction that can perform
|
||||
* the move/insert.
|
||||
*/
|
||||
makeTransaction: function PC_makeTransaction(data, type, container,
|
||||
index, copy) {
|
||||
switch (type) {
|
||||
case TYPE_X_MOZ_PLACE:
|
||||
if (data.folderId > 0) {
|
||||
// Place is a folder.
|
||||
if (copy)
|
||||
return this._getFolderCopyTransaction(data.folderId, container, index);
|
||||
return new PlacesMoveFolderTransaction(data.folderId, data.parent,
|
||||
data.index, container,
|
||||
index);
|
||||
}
|
||||
if (copy)
|
||||
return this._getItemCopyTransaction(data.uri, container, index);
|
||||
return new PlacesMoveItemTransaction(data.uri, data.parent,
|
||||
data.index, container,
|
||||
index);
|
||||
case TYPE_X_MOZ_URL:
|
||||
// Creating and Setting the title is a two step process, so create
|
||||
// a transaction for each then aggregate them.
|
||||
var createTxn =
|
||||
new PlacesCreateItemTransaction(data.uri, container, index);
|
||||
var editTxn =
|
||||
new PlacesEditItemTransaction(data.uri, { title: data.title });
|
||||
return new PlacesAggregateTransaction("DropMozURLItem", [createTxn, editTxn]);
|
||||
case TYPE_UNICODE:
|
||||
// Creating and Setting the title is a two step process, so create
|
||||
// a transaction for each then aggregate them.
|
||||
var createTxn =
|
||||
new PlacesCreateItemTransaction(data.uri, container, index);
|
||||
var editTxn =
|
||||
new PlacesEditItemTransaction(data.uri, { title: data.uri });
|
||||
return new PlacesAggregateTransaction("DropItem", [createTxn, editTxn]);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy Bookmarks and Folders to the clipboard
|
||||
*/
|
||||
copy: function() {
|
||||
var nodes = this._activeView.getCopyableSelection();
|
||||
|
||||
var xferable =
|
||||
Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
var foundFolder = false, foundLink = false;
|
||||
var placeString = htmlString = unicodeString = "";
|
||||
for (var i = 0; i < nodes.length; ++i) {
|
||||
var node = nodes[i];
|
||||
var self = this;
|
||||
function generateChunk(type) {
|
||||
var suffix = i < (nodes.length - 1) ? "\n" : "";
|
||||
return self.wrapNode(node, type) + suffix;
|
||||
}
|
||||
placeString += generateChunk(TYPE_X_MOZ_PLACE);
|
||||
mozURLString += generateChunk(TYPE_X_MOZ_URL);
|
||||
htmlString += generateChunk(TYPE_HTML);
|
||||
unicodeString += generateChunk(TYPE_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a string in a nsISupportsString wrapper
|
||||
* @param str
|
||||
* The string to wrap
|
||||
* @returns A nsISupportsString object containing a string.
|
||||
*/
|
||||
function wrapString(str) {
|
||||
var s =
|
||||
Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
s.data = str;
|
||||
return s;
|
||||
}
|
||||
|
||||
if (unicodeString != "") {
|
||||
xferable.addDataFlavor(TYPE_X_MOZ_PLACE);
|
||||
xferable.setTransferData(TYPE_X_MOZ_PLACE, wrapString(placeString),
|
||||
placeString.length * 2);
|
||||
xferable.addDataFlavor(TYPE_X_MOZ_URL);
|
||||
xferable.setTransferData(TYPE_X_MOZ_URL, wrapString(mozURLString),
|
||||
mozURLString.length * 2);
|
||||
xferable.addDataFlavor(TYPE_HTML);
|
||||
xferable.setTransferData(TYPE_HTML, wrapString(htmlString),
|
||||
htmlString.length * 2);
|
||||
xferable.addDataFlavor(TYPE_UNICODE);
|
||||
xferable.setTransferData(TYPE_UNICODE, wrapString(unicodeString),
|
||||
unicodeString.length * 2);
|
||||
|
||||
var clipboard =
|
||||
Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
|
||||
clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cut Bookmarks and Folders to the clipboard
|
||||
*/
|
||||
cut: function() {
|
||||
this.copy();
|
||||
this.remove("Cut");
|
||||
},
|
||||
|
||||
/**
|
||||
* Paste Bookmarks and Folders from the clipboard
|
||||
*/
|
||||
paste: function() {
|
||||
var xferable =
|
||||
Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
xferable.addDataFlavor(TYPE_X_MOZ_PLACE);
|
||||
xferable.addDataFlavor(TYPE_X_MOZ_URL);
|
||||
xferable.addDataFlavor(TYPE_UNICODE);
|
||||
|
||||
var clipboard =
|
||||
Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
|
||||
clipboard.getData(xferable, Ci.nsIClipboard.kGlobalClipboard);
|
||||
|
||||
var data = { }, type = { };
|
||||
xferable.getAnyTransferData(type, data, { });
|
||||
data = data.value.QueryInterface(Ci.nsISupportsString).data;
|
||||
data = this.unwrapNodes(data, type.value);
|
||||
|
||||
LOG("NODES: " + data);
|
||||
|
||||
var ip = this._activeView.insertionPoint;
|
||||
var transactions = [];
|
||||
for (var i = 0; i < data.length; ++i)
|
||||
transactions.push(this.makeTransaction(data[i], type.value,
|
||||
ip.container, ip.index, true));
|
||||
var txn = new PlacesAggregateTransaction("Paste", transactions);
|
||||
this._txmgr.doTransaction(txn);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
var PlacesControllerDragHelper = {
|
||||
/**
|
||||
* @returns The current active drag session. Returns null if there is none.
|
||||
*/
|
||||
_getSession: function VO__getSession() {
|
||||
var dragService =
|
||||
Cc["@mozilla.org/widget/dragservice;1"].
|
||||
getService(Ci.nsIDragService);
|
||||
return dragService.getCurrentSession();
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not the data currently being dragged can be dropped
|
||||
* on the specified view.
|
||||
* @param view
|
||||
* An object implementing the AVI
|
||||
* @returns true if the data being dragged is of a type supported by the view
|
||||
* it is being dragged over, false otherwise.
|
||||
*/
|
||||
canDrop: function PCDH_canDrop(view) {
|
||||
var session = this._getSession();
|
||||
if (session) {
|
||||
var types = view.supportedDropTypes;
|
||||
for (var i = 0; i < types.length; ++i) {
|
||||
if (session.isDataFlavorSupported(types[i]))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a transaction for copying (recursively nesting to include children)
|
||||
* a folder and its contents from one folder to another.
|
||||
* @param data
|
||||
* Unwrapped dropped folder data
|
||||
* @param container
|
||||
* The container we are copying into
|
||||
* @param index
|
||||
* The index in the destination container to insert the new items
|
||||
* @returns A nsITransaction object that will perform the copy.
|
||||
*/
|
||||
_getFolderCopyTransaction:
|
||||
function PC__getFolderCopyTransaction(data, container, index) {
|
||||
var transactions = [];
|
||||
function createTransactions(folderId, container, index) {
|
||||
var bms = PlacesController.bms;
|
||||
var folderTitle = bms.getFolderTitle(folderId);
|
||||
|
||||
var createTxn =
|
||||
new PlacesCreateFolderTransaction(folderTitle, container, index);
|
||||
transactions.push(createTxn);
|
||||
|
||||
var kids = bms.getFolderChildren(folderId, bms.ALL_CHILDREN);
|
||||
var cc = kids.childCount;
|
||||
for (var i = 0; i < cc; ++i) {
|
||||
var node = kids.getChild(i);
|
||||
if (node.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER)
|
||||
createTransactions(node.folderId, folderId, i);
|
||||
else {
|
||||
var uri = PlacesController._uri(node.url);
|
||||
transactions.push(this._getItemCopyTransaction(uri, container,
|
||||
index));
|
||||
}
|
||||
}
|
||||
}
|
||||
createTransactions(data.id, container, index);
|
||||
return new PlacesAggregateTransaction("FolderCopy", transactions);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a Transeferable object that can be filled with data of types
|
||||
* supported by a view.
|
||||
* @param view
|
||||
* An object implementing the AVI that supplies a list of
|
||||
* supported droppable content types
|
||||
* @returns An object implementing nsITransferable that can receive data
|
||||
* dropped onto a view.
|
||||
*/
|
||||
_initTransferable: function PCDH__initTransferable(view) {
|
||||
var xferable =
|
||||
Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
var types = view.supportedDropTypes;
|
||||
for (var j = 0; j < types.length; ++j)
|
||||
xferable.addDataFlavor(types[j]);
|
||||
return xferable;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles the drop of one or more items onto a view.
|
||||
* @param view
|
||||
* The AVI-implementing object that received the drop.
|
||||
* @param container
|
||||
* The container the drop was into
|
||||
* @param index
|
||||
* The index within the container the item was dropped at
|
||||
*/
|
||||
onDrop: function PCDH_onDrop(view, container, index) {
|
||||
var session = this._getSession();
|
||||
if (!session)
|
||||
return;
|
||||
|
||||
var copy = session.dragAction & Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
var transactions = [];
|
||||
var xferable = this._initTransferable(view);
|
||||
for (var i = 0; i < session.numDropItems; ++i) {
|
||||
session.getData(xferable, i);
|
||||
|
||||
var data = { }, flavor = { };
|
||||
xferable.getAnyTransferData(flavor, data, { });
|
||||
data.value.QueryInterface(Ci.nsISupportsString);
|
||||
|
||||
// There's only ever one in the D&D case.
|
||||
var unwrapped = PlacesController.unwrapNodes(data.value.data,
|
||||
flavor.value)[0];
|
||||
transactions.push(PlacesController.makeTransaction(unwrapped,
|
||||
flavor.value, container, index, copy));
|
||||
}
|
||||
var txn = new PlacesAggregateTransaction("DropItems", transactions);
|
||||
PlacesController._txmgr.doTransaction(txn);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Method and utility stubs for Place Edit Transactions
|
||||
*/
|
||||
function PlacesBaseTransaction() {
|
||||
}
|
||||
PlacesBaseTransaction.prototype = {
|
||||
_bms: Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService),
|
||||
|
||||
redoTransaction: function PIT_redoTransaction() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
get isTransient() {
|
||||
return false;
|
||||
},
|
||||
|
||||
merge: function PIT_merge(transaction) {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs several Places Transactions in a single batch.
|
||||
*/
|
||||
function PlacesAggregateTransaction(name, transactions) {
|
||||
this._transactions = transactions;
|
||||
this._name = name;
|
||||
}
|
||||
PlacesAggregateTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function() {
|
||||
LOG("== " + this._name + " (Aggregate) ==============");
|
||||
this._bms.beginUpdateBatch();
|
||||
for (var i = 0; i < this._transactions.length; ++i)
|
||||
this._transactions[i].doTransaction();
|
||||
this._bms.endUpdateBatch();
|
||||
LOG("== " + this._name + " (Aggregate Ends) =========");
|
||||
},
|
||||
|
||||
undoTransaction: function() {
|
||||
LOG("== UN" + this._name + " (UNAggregate) ============");
|
||||
this._bms.beginUpdateBatch();
|
||||
for (var i = 0; i < this._transactions.length; ++i)
|
||||
this._transactions[i].undoTransaction();
|
||||
this._bms.endUpdateBatch();
|
||||
LOG("== UN" + this._name + " (UNAggregate Ends) =======");
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a new Folder
|
||||
*/
|
||||
function PlacesCreateFolderTransaction(name, container, index) {
|
||||
this._name = name;
|
||||
this._container = container;
|
||||
this._index = index;
|
||||
this._id = null;
|
||||
}
|
||||
PlacesCreateFolderTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PCFT_doTransaction() {
|
||||
LOG("Create Folder: " + this._name + " in: " + this._container + "," + this._index);
|
||||
this._id = this._bms.createFolder(this._container, this._name, this._index);
|
||||
},
|
||||
|
||||
undoTransaction: function PCFT_undoTransaction() {
|
||||
LOG("UNCreate Folder: " + this._name + " from: " + this._container + "," + this._index);
|
||||
this._bms.removeFolder(this._id);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new Item
|
||||
*/
|
||||
function PlacesCreateItemTransaction(uri, container, index) {
|
||||
this._uri = uri;
|
||||
this._container = container;
|
||||
this._index = index;
|
||||
}
|
||||
PlacesCreateItemTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PCIT_doTransaction() {
|
||||
LOG("Create Item: " + this._uri.spec + " in: " + this._container + "," + this._index);
|
||||
this._bms.insertItem(this._container, this._uri, this._index);
|
||||
},
|
||||
|
||||
undoTransaction: function PCIT_undoTransaction() {
|
||||
LOG("UNCreate Item: " + this._uri.spec + " from: " + this._container + "," + this._index);
|
||||
this._bms.removeItem(this._container, this._uri);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Move a Folder
|
||||
*/
|
||||
function PlacesMoveFolderTransaction(id, oldContainer, oldIndex, newContainer, newIndex) {
|
||||
this._id = id;
|
||||
this._oldContainer = oldContainer;
|
||||
this._oldIndex = oldIndex;
|
||||
this._newContainer = newContainer;
|
||||
this._newIndex = newIndex;
|
||||
}
|
||||
PlacesMoveFolderTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PMFT_doTransaction() {
|
||||
LOG("Move Folder: " + this._id + " from: " + this._oldContainer + "," + this._oldIndex + " to: " + this._newContainer + "," + this._newIndex);
|
||||
this._bms.moveFolder(this._id, this._newContainer, this._newIndex);
|
||||
},
|
||||
|
||||
undoTransaction: function PMFT_undoTransaction() {
|
||||
LOG("UNMove Folder: " + this._id + " from: " + this._oldContainer + "," + this._oldIndex + " to: " + this._newContainer + "," + this._newIndex);
|
||||
this._bms.moveFolder(this._id, this._oldContainer, this._oldIndex);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Move an Item
|
||||
*/
|
||||
function PlacesMoveItemTransaction(uri, oldContainer, oldIndex, newContainer, newIndex) {
|
||||
this._uri = uri;
|
||||
this._oldContainer = oldContainer;
|
||||
this._oldIndex = oldIndex;
|
||||
this._newContainer = newContainer;
|
||||
this._newIndex = newIndex;
|
||||
}
|
||||
PlacesMoveItemTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PMIT_doTransaction() {
|
||||
LOG("Move Item: " + this._uri.spec + " from: " + this._oldContainer + "," + this._oldIndex + " to: " + this._newContainer + "," + this._newIndex);
|
||||
this._bms.removeItem(this._oldContainer, this._uri);
|
||||
this._bms.insertItem(this._newContainer, this._uri, this._newIndex);
|
||||
},
|
||||
|
||||
undoTransaction: function PMIT_undoTransaction() {
|
||||
LOG("UNMove Item: " + this._uri.spec + " from: " + this._oldContainer + "," + this._oldIndex + " to: " + this._newContainer + "," + this._newIndex);
|
||||
this._bms.removeItem(this._newContainer, this._uri);
|
||||
this._bms.insertItem(this._oldContainer, this._uri, this._oldIndex);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a Folder
|
||||
*/
|
||||
function PlacesRemoveFolderTransaction(id, oldContainer, oldIndex) {
|
||||
this._id = id;
|
||||
this._oldContainer = oldContainer;
|
||||
this._oldIndex = oldIndex;
|
||||
this._oldFolderTitle = null;
|
||||
}
|
||||
PlacesRemoveFolderTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PRFT_doTransaction() {
|
||||
LOG("Remove Folder: " + this._id + " from: " + this._oldContainer + "," + this._oldIndex);
|
||||
this._oldFolderTitle = this._bms.getFolderTitle(this._id);
|
||||
this._bms.removeFolder(this._id);
|
||||
},
|
||||
|
||||
undoTransaction: function PRFT_undoTransaction() {
|
||||
LOG("UNRemove Folder: " + this._id + " from: " + this._oldContainer + "," + this._oldIndex);
|
||||
this._id = this._bms.createFolder(this._oldContainer, this._oldFolderTitle, this._oldIndex);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an Item
|
||||
*/
|
||||
function PlacesRemoveItemTransaction(uri, oldContainer, oldIndex) {
|
||||
this._uri = uri;
|
||||
this._oldContainer = oldContainer;
|
||||
this._oldIndex = oldIndex;
|
||||
}
|
||||
PlacesRemoveItemTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PRIT_doTransaction() {
|
||||
LOG("Remove Item: " + this._uri.spec + " from: " + this._oldContainer + "," + this._oldIndex);
|
||||
this._bms.removeItem(this._oldContainer, this._uri);
|
||||
},
|
||||
|
||||
undoTransaction: function PRIT_undoTransaction() {
|
||||
LOG("UNRemove Item: " + this._uri.spec + " from: " + this._oldContainer + "," + this._oldIndex);
|
||||
this._bms.insertItem(this._oldContainer, this._uri, this._oldIndex);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Edit a Folder
|
||||
*/
|
||||
function PlacesEditFolderTransaction(id, oldAttributes, newAttributes) {
|
||||
this._id = id;
|
||||
this._oldAttributes = oldAttributes;
|
||||
this._newAttributes = newAttributes;
|
||||
}
|
||||
PlacesEditFolderTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PEFT_doTransaction() {
|
||||
LOG("Edit Folder: " + this._id + " oldAttrs: " + this._oldAttributes.toSource() + " newAttrs: " + this._newAttributes.toSource());
|
||||
// Use Bookmarks and Annotation Services to perform these operations.
|
||||
},
|
||||
|
||||
undoTransaction: function PEFT_undoTransaction() {
|
||||
LOG("UNEdit Folder: " + this._id + " oldAttrs: " + this._oldAttributes.toSource() + " newAttrs: " + this._newAttributes.toSource());
|
||||
// Use Bookmarks and Annotation Services to perform these operations.
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Edit an Item
|
||||
*/
|
||||
function PlacesEditItemTransaction(uri, newAttributes) {
|
||||
this._uri = uri;
|
||||
this._newAttributes = newAttributes;
|
||||
this._oldAttributes = { };
|
||||
}
|
||||
PlacesEditItemTransaction.prototype = {
|
||||
__proto__: PlacesBaseTransaction.prototype,
|
||||
|
||||
doTransaction: function PEIT_doTransaction() {
|
||||
LOG("Edit Item: " + this._uri.spec + " oldAttrs: " + this._oldAttributes.toSource() + " newAttrs: " + this._newAttributes.toSource());
|
||||
for (var p in this._newAttributes) {
|
||||
if (p == "title") {
|
||||
this._oldAttributes[p] = this._bms.getItemTitle(this._uri);
|
||||
this._bms.setItemTitle(this._uri, this._newAttributes[p]);
|
||||
}
|
||||
else {
|
||||
// Use Annotation Service
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
undoTransaction: function PEIT_undoTransaction() {
|
||||
LOG("UNEdit Item: " + this._uri.spec + " oldAttrs: " + this._oldAttributes.toSource() + " newAttrs: " + this._newAttributes.toSource());
|
||||
for (var p in this._newAttributes) {
|
||||
if (p == "title")
|
||||
this._bms.setItemTitle(this._uri, this._oldAttributes[p]);
|
||||
else {
|
||||
// Use Annotation Service
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
AVI rules:
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
display: -moz-box;
|
||||
}
|
||||
|
||||
#searchFilter {
|
||||
-moz-binding: url("chrome://browser/content/places/places.xml#textbox-timed-arbitrary");
|
||||
}
|
||||
|
||||
tree {
|
||||
-moz-binding: url("chrome://browser/content/places/places.xml#places-tree");
|
||||
}
|
||||
|
@ -11,3 +15,6 @@ button {
|
|||
-moz-binding: url("chrome://browser/content/places/places.xml#command-button");
|
||||
}
|
||||
|
||||
.filterList {
|
||||
-moz-binding: url("chrome://browser/content/places/places.xml#filter-button");
|
||||
}
|
||||
|
|
|
@ -57,6 +57,14 @@ var PlacesUIHook = {
|
|||
}
|
||||
catch (e) {
|
||||
}
|
||||
|
||||
// Stop the browser from handling certain types of events.
|
||||
function onDragEvent(event) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
window.addEventListener("draggesture", onDragEvent, false);
|
||||
window.addEventListener("dragover", onDragEvent, false);
|
||||
window.addEventListener("dragdrop", onDragEvent, false);
|
||||
},
|
||||
|
||||
uninit: function PUIH_uninit() {
|
||||
|
@ -98,6 +106,9 @@ var PlacesPage = {
|
|||
this._places.controllers.appendController(PlacesController);
|
||||
this._content.controllers.appendController(PlacesController);
|
||||
|
||||
this._places.supportedDropTypes = ["text/x-moz-place"];
|
||||
this._content.supportedDropTypes = ["text/x-moz-place", "text/x-moz-url"];
|
||||
|
||||
// Hook the browser UI
|
||||
PlacesUIHook.init(this._content);
|
||||
|
||||
|
@ -106,12 +117,9 @@ var PlacesPage = {
|
|||
|
||||
// Attach the Places model to the Place View
|
||||
// XXXben - move this to an attribute/property on the tree view
|
||||
const BS = Ci.nsINavBookmarksService;
|
||||
this._bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].getService(BS);
|
||||
var children = this._bmsvc.getFolderChildren(this._bmsvc.placesRoot,
|
||||
BS.FOLDER_CHILDREN |
|
||||
BS.QUERY_CHILDREN);
|
||||
this._places.view = children.QueryInterface(Ci.nsITreeView);
|
||||
var bms = PlacesController._bms;
|
||||
this._places.loadFolder(bms.placesRoot,
|
||||
bms.FOLDER_CHILDREN | bms.QUERY_CHILDREN);
|
||||
},
|
||||
|
||||
uninit: function PP_uninit() {
|
||||
|
@ -130,12 +138,20 @@ var PlacesPage = {
|
|||
applyFilter: function PP_applyFilter(filterString) {
|
||||
var searchFilter = document.getElementById("searchFilter");
|
||||
var collectionName = searchFilter.getAttribute("collection");
|
||||
if (collectionName == "collection") {
|
||||
alert("Search Only This Collection Not Yet Supported");
|
||||
this.setFilterCollection("all");
|
||||
}
|
||||
else if (collectionName == "all") {
|
||||
switch (collectionName) {
|
||||
case "collection":
|
||||
var folder = this._content.getResult().folderId;
|
||||
this._content.applyFilter(filterString, true, folder);
|
||||
break;
|
||||
case "bookmarks":
|
||||
this._content.applyFilter(filterString, true, 0);
|
||||
break;
|
||||
case "history":
|
||||
this._content.applyFilter(filterString, false, 0);
|
||||
break;
|
||||
case "all":
|
||||
this._content.filterString = filterString;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -143,38 +159,34 @@ var PlacesPage = {
|
|||
* Called when a place folder is selected in the left pane.
|
||||
*/
|
||||
placeSelected: function PP_placeSelected(event) {
|
||||
var resultView = event.target.view;
|
||||
resultView.QueryInterface(Components.interfaces.nsINavHistoryResult);
|
||||
|
||||
var folder = resultView.nodeForTreeIndex(resultView.selection.currentIndex);
|
||||
var view;
|
||||
if (folder.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER) {
|
||||
view = this._bmsvc.getFolderChildren(folder.folderId, Ci.nsINavBookmarksService.ALL_CHILDREN);
|
||||
} else {
|
||||
var queries = folder.getQueries({ });
|
||||
var history = Cc["@mozilla.org/browser/nav-history;1"].getService(Ci.nsINavHistory);
|
||||
view = history.executeQueries(queries, queries.length, folder.queryOptions).QueryInterface(Ci.nsITreeView);
|
||||
var node = this._places.selectedNode;
|
||||
if (PlacesController.nodeIsFolder(node))
|
||||
this._content.loadFolder(node.folderId);
|
||||
else {
|
||||
var queries = node.getQueries({ });
|
||||
this._content.load(queries, node.queryOptions);
|
||||
}
|
||||
this._content.view = view;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the Places UI when the content of the right tree changes.
|
||||
*/
|
||||
onContentChanged: function PP_onContentChanged() {
|
||||
var result = this._content.view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
var queries = result.getSourceQueries({ });
|
||||
var query = queries[0];
|
||||
var panelID = "commands_history";
|
||||
if (query.onlyBookmarked) {
|
||||
var filterButtonID = "filterList_history";
|
||||
var isBookmarks = PlacesController.nodeIsFolder(this._content.getResult());
|
||||
if (isBookmarks) {
|
||||
// if (query.annotation == "feed") {
|
||||
panelID = "commands_bookmark";
|
||||
filterButtonID = "filterList_bookmark";
|
||||
}
|
||||
var commands = document.getElementById("commands");
|
||||
commands.selectedPanel = document.getElementById(panelID);
|
||||
var commandBar = document.getElementById("commandBar");
|
||||
commandBar.selectedPanel = document.getElementById(panelID);
|
||||
var filterCollectionDeck = document.getElementById("filterCollectionDeck");
|
||||
filterCollectionDeck.selectedPanel = document.getElementById(filterButtonID);
|
||||
|
||||
// Hide the Calendar for Bookmark queries.
|
||||
document.getElementById("historyCalendar").hidden = query.onlyBookmarked;
|
||||
document.getElementById("historyCalendar").hidden = isBookmarks;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
<binding id="textbox-timed-arbitrary"
|
||||
extends="chrome://global/content/bindings/textbox.xml#timed-textbox">
|
||||
<content>
|
||||
<xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context">
|
||||
<children/>
|
||||
<xul:hbox class="textbox-input-box" flex="1" xbl:inherits="context">
|
||||
<html:input class="textbox-input" flex="1" anonid="input"
|
||||
xbl:inherits="onfocus,onblur,value,type,maxlength,disabled,size,readonly,tabindex,accesskey"/>
|
||||
</xul:hbox>
|
||||
|
@ -21,7 +21,7 @@
|
|||
</binding>
|
||||
|
||||
<binding id="places-tree" extends="chrome://global/content/bindings/tree.xml#tree">
|
||||
<implementation>
|
||||
<implementation implements="nsINavHistoryResultViewObserver">
|
||||
<constructor><![CDATA[
|
||||
this._places =
|
||||
Cc["@mozilla.org/browser/nav-history;1"].
|
||||
|
@ -57,34 +57,83 @@
|
|||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<method name="getResult">
|
||||
<body><![CDATA[
|
||||
try {
|
||||
return this.view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- overriding -->
|
||||
<property name="view">
|
||||
<getter><![CDATA[
|
||||
return this.treeBoxObject.view;
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
// Make sure the last result doesn't hold a reference to us anymore
|
||||
var result = this.getResult();
|
||||
if (result)
|
||||
result.removeObserver(this._viewObserver);
|
||||
this.treeBoxObject.view = val;
|
||||
this.getResult().addObserver(this._viewObserver);
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<method name="getBestOptions">
|
||||
<body><![CDATA[
|
||||
// Get the best set of grouping options to use, either reuse the
|
||||
// existing ones or create new ones.
|
||||
var options = this.getResult().sourceQueryOptions;
|
||||
if (!options)
|
||||
options = this._places.getNewQueryOptions();
|
||||
return options;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<property name="filterString">
|
||||
<getter><![CDATA[
|
||||
this.view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
var queries = this.view.getSourceQueries({ });
|
||||
var queries = this.getResult().getSourceQueries({ });
|
||||
if (queries[i].hasSearchTerms)
|
||||
return queries[i].searchTerms;
|
||||
return null;
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
// preserve grouping
|
||||
this.view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
var options = this.view.sourceQueryOptions;
|
||||
if (!options)
|
||||
options = this._places.getNewQueryOptions();
|
||||
|
||||
var query = this._places.getNewQuery();
|
||||
query.searchTerms = val;
|
||||
|
||||
this.load([query], options);
|
||||
this.load([query], this.getBestOptions());
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<method name="applyFilter">
|
||||
<parameter name="filterString"/>
|
||||
<parameter name="onlyBookmarks"/>
|
||||
<parameter name="folderRestrict"/>
|
||||
<body><![CDATA[
|
||||
// preserve grouping
|
||||
var options = this.getResult().sourceQueryOptions;
|
||||
if (!options)
|
||||
options = this._places.getNewQueryOptions();
|
||||
|
||||
var query = this._places.getNewQuery();
|
||||
query.searchTerms = filterString;
|
||||
query.onlyBookmarked = onlyBookmarks;
|
||||
//if (onlyBookmarks)
|
||||
// query.setFolders(folderRestrict, folderRestrict.length);
|
||||
this.load([query], this.getBestOptions());
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<property name="queryString">
|
||||
<getter><![CDATA[
|
||||
this.view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
var queries = this.view.getSourceQueries({ });
|
||||
var options = this.view.sourceQueryOptions;
|
||||
var result = this.getResult();
|
||||
var queries = result.getSourceQueries({ });
|
||||
var options = result.sourceQueryOptions;
|
||||
|
||||
const NH = Ci.nsINavHistory;
|
||||
return this._places.queriesToQueryString(queries, queries.length,
|
||||
|
@ -98,6 +147,21 @@
|
|||
]]></setter>
|
||||
</property>
|
||||
|
||||
<method name="loadFolder">
|
||||
<parameter name="folderId"/>
|
||||
<parameter name="filterOptions"/>
|
||||
<body><![CDATA[
|
||||
var bms =
|
||||
Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
var filterOptions = filterOptions || bms.ALL_CHILDREN;
|
||||
var result = bms.getFolderChildren(folderId, filterOptions);
|
||||
result.QueryInterface(Ci.nsITreeView);
|
||||
this.view = result;
|
||||
this._fireEvent("reloaded");
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="load">
|
||||
<parameter name="queries"/>
|
||||
<parameter name="options"/>
|
||||
|
@ -110,24 +174,27 @@
|
|||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<property name="hasSelection">
|
||||
<getter><![CDATA[
|
||||
return this.view.selection.count >= 1;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<property name="hasSingleSelection">
|
||||
<getter><![CDATA[
|
||||
return this.view.selection.count == 1;
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<method name="getSelectionNodes">
|
||||
<body><![CDATA[
|
||||
var result = this.view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
var selection = this.view.selection;
|
||||
var rc = selection.getRangeCount();
|
||||
var nodes = [];
|
||||
var result = this.getResult();
|
||||
for (var i = 0; i < rc; ++i) {
|
||||
var min = { }, max = { };
|
||||
selection.getRangeAt(i, min, max);
|
||||
|
@ -139,6 +206,14 @@
|
|||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<method name="getCopyableSelection">
|
||||
<body><![CDATA[
|
||||
return this.getSelectionNodes();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<property name="selectedNode">
|
||||
<getter><![CDATA[
|
||||
var view = this.view;
|
||||
|
@ -149,11 +224,11 @@
|
|||
var min = { }, max = { };
|
||||
selection.getRangeAt(0, min, max);
|
||||
|
||||
var result = view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
return result.nodeForTreeIndex(min.value);
|
||||
return this.getResult().nodeForTreeIndex(min.value);
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<property name="selectedURLNode">
|
||||
<getter><![CDATA[
|
||||
var view = this.view;
|
||||
|
@ -168,11 +243,11 @@
|
|||
if (view.isContainer(min.value) || view.isSeparator(min.value))
|
||||
return null;
|
||||
|
||||
var result = view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
return result.nodeForTreeIndex(min.value);
|
||||
return this.getResult().nodeForTreeIndex(min.value);
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<property name="insertionPoint">
|
||||
<getter><![CDATA[
|
||||
var view = this.view;
|
||||
|
@ -181,7 +256,7 @@
|
|||
var min = { }, max = { };
|
||||
selection.getRangeAt(rc - 1, min, max);
|
||||
|
||||
var result = view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
var result = this.getResult();
|
||||
var container = result;
|
||||
// When there's no selection, assume the container is the container
|
||||
// the view is populated from (i.e. the result's folderId).
|
||||
|
@ -208,11 +283,22 @@
|
|||
]]></getter>
|
||||
</property>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<property name="browserWindow" onget="return this._browserWindow"/>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<field name="supportedDropTypes">null</field>
|
||||
|
||||
<!-- AVI Method -->
|
||||
<method name="selectAll">
|
||||
<body><![CDATA[
|
||||
this.view.selection.selectAll();
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_getTransferData">
|
||||
<body><![CDATA[
|
||||
var result = this.view.QueryInterface(Ci.nsINavHistoryResult);
|
||||
var result = this.getResult();
|
||||
var selection = this.view.selection;
|
||||
if (selection.count == 0)
|
||||
return null;
|
||||
|
@ -226,9 +312,17 @@
|
|||
var node = result.nodeForTreeIndex(j);
|
||||
|
||||
var data = new TransferData();
|
||||
data.addDataForFlavour("text/x-moz-url", node.url + "\n" + node.title);
|
||||
data.addDataForFlavour("text/html", "<A HREF=\"" + node.url + "\">" + node.title + "</A>");
|
||||
data.addDataForFlavour("text/unicode", node.url);
|
||||
function addData(type) {
|
||||
var s =
|
||||
Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
s.data = PlacesController.wrapNode(node, type);
|
||||
data.addDataForFlavour(type, s);
|
||||
}
|
||||
addData(TYPE_X_MOZ_PLACE);
|
||||
addData(TYPE_X_MOZ_URL);
|
||||
addData(TYPE_HTML);
|
||||
addData(TYPE_UNICODE);
|
||||
dataSet.push(data);
|
||||
}
|
||||
}
|
||||
|
@ -243,6 +337,7 @@
|
|||
if (this._self.getAttribute("sortActive") == "true")
|
||||
throw Components.results.NS_OK;
|
||||
xferData.data = this._self._getTransferData();
|
||||
// XXXben - the drag wrapper should do this automatically.
|
||||
if (event.ctrlKey)
|
||||
dragAction.action = Ci.nsIDragService.DRAGDROP_ACTION_COPY;
|
||||
},
|
||||
|
@ -256,19 +351,71 @@
|
|||
|
||||
},
|
||||
|
||||
_flavorSet: null,
|
||||
getSupportedFlavours: function() {
|
||||
var flavorSet = new FlavourSet();
|
||||
flavorSet.appendFlavour("application/x-moz-file", "nsIFile");
|
||||
flavorSet.appendFlavour("text/x-moz-url");
|
||||
flavorSet.appendFlavour("text/unicode");
|
||||
return flavorSet;
|
||||
if (!this._flavorSet) {
|
||||
this._flavorSet = new FlavourSet();
|
||||
for (var i = 0; i < this._self.supportedDropTypes.length; ++i)
|
||||
this._flavorSet.appendFlavour(this._self.supportedDropTypes[i]);
|
||||
}
|
||||
return this._flavorSet;
|
||||
}
|
||||
})]]></field>
|
||||
|
||||
<field name="_viewObserver"><![CDATA[
|
||||
({
|
||||
_self: this,
|
||||
|
||||
canDrop: function VO_canDrop() {
|
||||
return PlacesControllerDragHelper.canDrop(this._self);
|
||||
},
|
||||
|
||||
onDrop: function VO_onDrop(index, orientation) {
|
||||
LOG("VO: onDrop: " + index + ", orientation: " + orientation);
|
||||
|
||||
// We are responsible for translating the |index| and |orientation|
|
||||
// parameters into a container id and index within the container,
|
||||
// since this information is specific to the tree view.
|
||||
const NHRVO = Ci.nsINavHistoryResultViewObserver;
|
||||
var result = this._self.getResult();
|
||||
var view = this._self.view;
|
||||
var node = result.nodeForTreeIndex(index);
|
||||
var destContainer = null;
|
||||
var destIndex = -1;
|
||||
// If we're dropping _on_ a container, the container is the container
|
||||
// we dropped on, otherwise it's the parent of the drop target.
|
||||
if (view.isContainer(index) && orientation == NHRVO.DROP_ON)
|
||||
destContainer = node.folderId;
|
||||
else {
|
||||
var destIndex = PlacesController.getIndexOfNode(node);
|
||||
// For non leaves, or when not dropping _on_ a container, drop after
|
||||
// by default (i.e. when dropping after a container, or ON AND AFTER
|
||||
// a leaf node).
|
||||
if (orientation != NHRVO.DROP_BEFORE)
|
||||
++destIndex;
|
||||
destContainer = node.parent.folderId;
|
||||
}
|
||||
PlacesControllerDragHelper.onDrop(this._self, destContainer,
|
||||
destIndex);
|
||||
},
|
||||
|
||||
// XXXben we will probably have to implement this to refresh Live
|
||||
// Bookmarks.
|
||||
onToggleOpenState: function VO_onToggleOpenState(index) { },
|
||||
onCycleHeader: function VO_onCycleHeader(column) { },
|
||||
onCycleCell: function VO_onCycleCell(row, column) { },
|
||||
onSelectionChanged: function VO_onSelectionChanged() { },
|
||||
onPerformAction: function VO_onPerformAction(action) { },
|
||||
onPerformActionOnRow: function VO_onPerformActionOnRow(action, row) { },
|
||||
onPerformActionOnCell: function VO_onPerformActionOnCell(action, row, column) { },
|
||||
})
|
||||
]]></field>
|
||||
|
||||
</implementation>
|
||||
<handlers>
|
||||
<handler event="focus"><![CDATA[
|
||||
PlacesController.activeView = this;
|
||||
document.commandDispatcher.updateCommands("focus");
|
||||
]]></handler>
|
||||
<handler event="select"><![CDATA[
|
||||
document.commandDispatcher.updateCommands("select");
|
||||
|
@ -309,6 +456,14 @@
|
|||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="filter-button" extends="chrome://global/content/bindings/button.xml#menu">
|
||||
<handlers>
|
||||
<handler event="command"><![CDATA[
|
||||
PlacesPage.setFilterCollection(event.target.getAttribute("value"));
|
||||
]]></handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
<binding id="calendar">
|
||||
<content>
|
||||
<xul:vbox class="calendar-box">
|
||||
|
|
|
@ -24,13 +24,19 @@
|
|||
<stringbundle id="brandBundle" src="chrome://branding/locale/brand.properties"/>
|
||||
</stringbundleset>
|
||||
|
||||
<commandset id="placesCommands">
|
||||
<commandset id="placesCommands"
|
||||
commandupdater="true" events="focus,select"
|
||||
oncommandupdate="PlacesController.onCommandUpdate()">
|
||||
<command id="placesCmd_find" label="&cmd.find.label;" accesskey="&cmd.find.accesskey;"/>
|
||||
<command id="placesCmd_export" label="&cmd.export.label;" accesskey="&cmd.export.accesskey;"/>
|
||||
<command id="placesCmd_import"/>
|
||||
<command id="placesCmd_select:all" label="&cmd.select_all.label;" accesskey="&cmd.select_all.accesskey;"/>
|
||||
<command id="placesCmd_select:all"
|
||||
label="&cmd.select_all.label;" accesskey="&cmd.select_all.accesskey;"
|
||||
oncommand="PlacesController.selectAll();"/>
|
||||
<commandset readonly="true">
|
||||
<command id="placesCmd_edit:copy" label="&cmd.edit_copy.label;" accesskey="&cmd.edit_copy.accesskey;"/>
|
||||
<command id="placesCmd_edit:copy"
|
||||
label="&cmd.edit_copy.label;" accesskey="&cmd.edit_copy.accesskey;"
|
||||
oncommand="PlacesController.copy();"/>
|
||||
<command id="placesCmd_show:info"
|
||||
#ifdef XP_WIN
|
||||
label="&cmd.show_infoWin.label;" accesskey="&cmd.show_infoWin.accesskey;"/>
|
||||
|
@ -39,8 +45,12 @@
|
|||
#endif
|
||||
</commandset>
|
||||
<commandset>
|
||||
<command id="placesCmd_edit:cut" label="&cmd.edit_cut.label;" accesskey="&cmd.edit_cut.accesskey;"/>
|
||||
<command id="placesCmd_edit:paste" label="&cmd.edit_paste.label;" accesskey="&cmd.edit_paste.accesskey;"/>
|
||||
<command id="placesCmd_edit:cut"
|
||||
label="&cmd.edit_cut.label;" accesskey="&cmd.edit_cut.accesskey;"
|
||||
oncommand="PlacesController.cut();"/>
|
||||
<command id="placesCmd_edit:paste"
|
||||
label="&cmd.edit_paste.label;" accesskey="&cmd.edit_paste.accesskey;"
|
||||
oncommand="PlacesController.paste();"/>
|
||||
<command id="placesCmd_edit:delete"
|
||||
label="&cmd.edit_delete.label;" accesskey="&cmd.edit_delete.accesskey;"
|
||||
oncommand="PlacesController.remove();"/>
|
||||
|
@ -123,7 +133,7 @@
|
|||
<tree id="placesList" class="placesTree" flex="1"
|
||||
hidecolumnpicker="true" context="placesContext"
|
||||
onselect="PlacesPage.placeSelected(event);"
|
||||
singleclick="true">
|
||||
singleclick="true" seltype="single">
|
||||
<treecols>
|
||||
<treecol id="title" flex="1" primary="true" hideheader="true"/>
|
||||
</treecols>
|
||||
|
@ -142,16 +152,28 @@
|
|||
<textbox id="searchFilter" flex="3" style="width: 0px;" timeout="500"
|
||||
oncommand="PlacesPage.applyFilter(this.value);"
|
||||
collection="all" persist="collection">
|
||||
<button type="menu" id="filterCollection">
|
||||
<menupopup oncommand="PlacesPage.setFilterCollection(event.target.getAttribute('value'));">
|
||||
<menuitem label="&search.collection.label;"
|
||||
accesskey="&search.collection.accesskey;"
|
||||
type="radio" name="collection" value="collection"/>
|
||||
<menuitem label="&search.all.label;"
|
||||
accesskey="&search.all.accesskey;"
|
||||
<deck id="filterCollectionDeck">
|
||||
<button type="menu" class="filterList" id="filterList_history">
|
||||
<menupopup>
|
||||
<menuitem label="&search.history.label;" accesskey="&search.history.accesskey;"
|
||||
type="radio" name="collection" value="history"
|
||||
checked="true" default="true"/>
|
||||
<menuitem label="&search.all.label;" accesskey="&search.all.accesskey;"
|
||||
type="radio" name="collection" value="all"/>
|
||||
</menupopup>
|
||||
</button>
|
||||
<button type="menu" class="filterList" id="filterList_bookmark">
|
||||
<menupopup>
|
||||
<menuitem label="&search.collection.label;" accesskey="&search.collection.accesskey;"
|
||||
type="radio" name="collection" value="collection"/>
|
||||
<menuitem label="&search.bookmarks.label;" accesskey="&search.bookmarks.accesskey;"
|
||||
type="radio" name="collection" value="bookmarks"
|
||||
checked="true" default="true"/>
|
||||
<menuitem label="&search.all.label;" accesskey="&search.all.accesskey;"
|
||||
type="radio" name="collection" value="all"/>
|
||||
</menupopup>
|
||||
</button>
|
||||
</deck>
|
||||
</textbox>
|
||||
<button id="showAdvancedSearch"
|
||||
label="&advancedSearch.label;" accesskey="&advancedSearch.accesskey;"
|
||||
|
@ -170,7 +192,7 @@
|
|||
<treechildren id="placeContentChildren" view="placeContent" flex="1"/>
|
||||
</tree>
|
||||
<hbox>
|
||||
<deck id="commands" flex="1">
|
||||
<deck id="commandBar" flex="1">
|
||||
<hbox class="commands" id="commands_bookmark" flex="1">
|
||||
<button id="newFolder" view="placeContent" command="placesCmd_new:folder"/>
|
||||
<spacer flex="1"/>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
browser.jar:
|
||||
% overlay chrome://browser/content/browser.xul chrome://browser/content/places/browserShim.xul
|
||||
* content/browser/places/places.xul (content/places.xul)
|
||||
* content/browser/places/places.js (content/places.js)
|
||||
* content/browser/places/places.xml (content/places.xml)
|
||||
* content/browser/places/places.css (content/places.css)
|
||||
* content/browser/places/controller.js (content/controller.js)
|
||||
* content/browser/places/browserShim.js (content-shim/browserShim.js)
|
||||
* content/browser/places/browserShim.xul (content-shim/browserShim.xul)
|
||||
content/browser/places/places.js (content/places.js)
|
||||
content/browser/places/places.xml (content/places.xml)
|
||||
content/browser/places/places.css (content/places.css)
|
||||
content/browser/places/controller.js (content/controller.js)
|
||||
content/browser/places/draghelper.xml (content/draghelper.xml)
|
||||
content/browser/places/browserShim.js (content-shim/browserShim.js)
|
||||
content/browser/places/browserShim.xul (content-shim/browserShim.xul)
|
||||
|
||||
classic.jar:
|
||||
skin/classic/browser/places/places.css (skin-win/places.css)
|
||||
|
|
|
@ -114,6 +114,14 @@
|
|||
"Current Collection Only">
|
||||
<!ENTITY search.collection.accesskey
|
||||
"C">
|
||||
<!ENTITY search.bookmarks.label
|
||||
"All Bookmarks">
|
||||
<!ENTITY search.bookmarks.accesskey
|
||||
"B">
|
||||
<!ENTITY search.history.label
|
||||
"All History">
|
||||
<!ENTITY search.history.accesskey
|
||||
"H">
|
||||
<!ENTITY search.all.label
|
||||
"All Bookmarks and History">
|
||||
<!ENTITY search.all.accesskey
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
interface nsINavHistoryQuery;
|
||||
interface nsINavHistoryQueryOptions;
|
||||
interface nsITreeColumn;
|
||||
|
||||
[scriptable, uuid(acae2b2d-5fcd-4419-b1bc-b7dc92a1836c)]
|
||||
interface nsINavHistoryResultNode : nsISupports
|
||||
|
@ -135,6 +136,71 @@ interface nsINavHistoryResultNode : nsISupports
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Allows clients of the HistoryResult to define domain specific handling
|
||||
* of specific nsITreeView methods that the HistoryResult does not implement.
|
||||
*/
|
||||
[scriptable, uuid(b34d5ca4-ce8e-49a6-9201-a59ae2128d2c)]
|
||||
interface nsINavHistoryResultViewObserver : nsISupports
|
||||
{
|
||||
const long DROP_BEFORE = -1;
|
||||
const long DROP_ON = 0;
|
||||
const long DROP_AFTER = 1;
|
||||
/**
|
||||
* Methods used by the drag feedback code to determine if a drag is allowable at
|
||||
* the current location. To get the behavior where drops are only allowed on
|
||||
* items, such as the mailNews folder pane, always return false whe
|
||||
* the orientation is not DROP_ON.
|
||||
*/
|
||||
boolean canDrop(in long index, in long orientation);
|
||||
|
||||
/**
|
||||
* Called when the user drops something on this view. The |orientation| param
|
||||
* specifies before/on/after the given |row|.
|
||||
*/
|
||||
void onDrop(in long row, in long orientation);
|
||||
|
||||
/**
|
||||
* Called when an item is opened or closed.
|
||||
*/
|
||||
void onToggleOpenState (in long index);
|
||||
|
||||
/**
|
||||
* Called when a header is clicked.
|
||||
*/
|
||||
void onCycleHeader(in nsITreeColumn column);
|
||||
|
||||
/**
|
||||
* Called when a cell in a non-selectable cycling column (e.g.
|
||||
* unread/flag/etc.) is clicked.
|
||||
*/
|
||||
void onCycleCell(in long row, in nsITreeColumn column);
|
||||
|
||||
/**
|
||||
* Called when selection in the tree changes
|
||||
*/
|
||||
void onSelectionChanged();
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on the selection.
|
||||
* The tree will automatically invoke this method when certain keys
|
||||
* are pressed. For example, when the DEL key is pressed, performAction
|
||||
* will be called with the "delete" string.
|
||||
*/
|
||||
void onPerformAction(in wstring action);
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on a specific row.
|
||||
*/
|
||||
void onPerformActionOnRow(in wstring action, in long row);
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on a specific cell.
|
||||
*/
|
||||
void onPerformActionOnCell(in wstring action, in long row, in nsITreeColumn column);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The result of a history/bookmark query.
|
||||
*
|
||||
|
@ -200,8 +266,18 @@ interface nsINavHistoryResult : nsINavHistoryResultNode
|
|||
* This gives you the original options used to display this result.
|
||||
*/
|
||||
readonly attribute nsINavHistoryQueryOptions sourceQueryOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a Tree Builder Observer to handle Tree View methods that the
|
||||
* HistoryResult object does not implement.
|
||||
*/
|
||||
void addObserver(in nsINavHistoryResultViewObserver observer);
|
||||
|
||||
/**
|
||||
* Remove a tree builder observer.
|
||||
*/
|
||||
void removeObserver(in nsINavHistoryResultViewObserver observer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Similar to nsIRDFObserver for history. Note that we don't pass the data
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
interface nsINavHistoryQuery;
|
||||
interface nsINavHistoryQueryOptions;
|
||||
interface nsITreeColumn;
|
||||
|
||||
[scriptable, uuid(acae2b2d-5fcd-4419-b1bc-b7dc92a1836c)]
|
||||
interface nsINavHistoryResultNode : nsISupports
|
||||
|
@ -135,6 +136,71 @@ interface nsINavHistoryResultNode : nsISupports
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Allows clients of the HistoryResult to define domain specific handling
|
||||
* of specific nsITreeView methods that the HistoryResult does not implement.
|
||||
*/
|
||||
[scriptable, uuid(b34d5ca4-ce8e-49a6-9201-a59ae2128d2c)]
|
||||
interface nsINavHistoryResultViewObserver : nsISupports
|
||||
{
|
||||
const long DROP_BEFORE = -1;
|
||||
const long DROP_ON = 0;
|
||||
const long DROP_AFTER = 1;
|
||||
/**
|
||||
* Methods used by the drag feedback code to determine if a drag is allowable at
|
||||
* the current location. To get the behavior where drops are only allowed on
|
||||
* items, such as the mailNews folder pane, always return false whe
|
||||
* the orientation is not DROP_ON.
|
||||
*/
|
||||
boolean canDrop(in long index, in long orientation);
|
||||
|
||||
/**
|
||||
* Called when the user drops something on this view. The |orientation| param
|
||||
* specifies before/on/after the given |row|.
|
||||
*/
|
||||
void onDrop(in long row, in long orientation);
|
||||
|
||||
/**
|
||||
* Called when an item is opened or closed.
|
||||
*/
|
||||
void onToggleOpenState (in long index);
|
||||
|
||||
/**
|
||||
* Called when a header is clicked.
|
||||
*/
|
||||
void onCycleHeader(in nsITreeColumn column);
|
||||
|
||||
/**
|
||||
* Called when a cell in a non-selectable cycling column (e.g.
|
||||
* unread/flag/etc.) is clicked.
|
||||
*/
|
||||
void onCycleCell(in long row, in nsITreeColumn column);
|
||||
|
||||
/**
|
||||
* Called when selection in the tree changes
|
||||
*/
|
||||
void onSelectionChanged();
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on the selection.
|
||||
* The tree will automatically invoke this method when certain keys
|
||||
* are pressed. For example, when the DEL key is pressed, performAction
|
||||
* will be called with the "delete" string.
|
||||
*/
|
||||
void onPerformAction(in wstring action);
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on a specific row.
|
||||
*/
|
||||
void onPerformActionOnRow(in wstring action, in long row);
|
||||
|
||||
/**
|
||||
* A command API that can be used to invoke commands on a specific cell.
|
||||
*/
|
||||
void onPerformActionOnCell(in wstring action, in long row, in nsITreeColumn column);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The result of a history/bookmark query.
|
||||
*
|
||||
|
@ -200,8 +266,18 @@ interface nsINavHistoryResult : nsINavHistoryResultNode
|
|||
* This gives you the original options used to display this result.
|
||||
*/
|
||||
readonly attribute nsINavHistoryQueryOptions sourceQueryOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a Tree Builder Observer to handle Tree View methods that the
|
||||
* HistoryResult object does not implement.
|
||||
*/
|
||||
void addObserver(in nsINavHistoryResultViewObserver observer);
|
||||
|
||||
/**
|
||||
* Remove a tree builder observer.
|
||||
*/
|
||||
void removeObserver(in nsINavHistoryResultViewObserver observer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Similar to nsIRDFObserver for history. Note that we don't pass the data
|
||||
|
|
|
@ -41,20 +41,22 @@ treechildren::-moz-tree-image(title, container) {
|
|||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(title, container, menu-root) {
|
||||
treechildren::-moz-tree-image(title, open) {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(title, container, menu-root),
|
||||
treechildren::-moz-tree-image(title, container, open, menu-root) {
|
||||
list-style-image: url("chrome://browser/skin/places/icons.png") !important;
|
||||
-moz-image-region: rect(0px, 16px, 17px, 0px);
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(title, container, toolbar-root) {
|
||||
treechildren::-moz-tree-image(title, container, toolbar-root),
|
||||
treechildren::-moz-tree-image(title, container, open, toolbar-root) {
|
||||
list-style-image: url("chrome://browser/skin/places/icons.png") !important;
|
||||
-moz-image-region: rect(17px, 16px, 32px, 0px);
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(title, open) {
|
||||
-moz-image-region: rect(16px, 32px, 32px, 16px);
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(title, separator) {
|
||||
list-style-image: none;
|
||||
width: 0px !important;
|
||||
|
@ -92,14 +94,18 @@ treechildren::-moz-tree-cell-text(title, separator, selected, focus) {
|
|||
|
||||
/* Search Bar */
|
||||
#searchFilter {
|
||||
-moz-binding: url("chrome://browser/content/places/places.xml#textbox-timed-arbitrary");
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#filterCollection {
|
||||
#searchFilter .textbox-input-box {
|
||||
padding: 2px 2px 3px 4px;
|
||||
}
|
||||
|
||||
.filterList {
|
||||
-moz-appearance: none;
|
||||
background-color: transparent;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
margin: 2px;
|
||||
padding: 0px;
|
||||
min-width: 0px;
|
||||
width: 16px;
|
||||
|
@ -108,6 +114,11 @@ treechildren::-moz-tree-cell-text(title, separator, selected, focus) {
|
|||
-moz-user-focus: ignore;
|
||||
}
|
||||
|
||||
.filterList .button-box {
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* Calendar */
|
||||
#historyCalendar {
|
||||
margin: 0px 0px 7px 6px;
|
||||
|
|
|
@ -251,6 +251,8 @@ protected:
|
|||
nsCOMArray<nsINavHistoryQuery> mSourceQueries;
|
||||
nsCOMPtr<nsINavHistoryQueryOptions> mSourceOptions;
|
||||
|
||||
nsCOMArray<nsINavHistoryResultViewObserver> mObservers;
|
||||
|
||||
// for locale-specific date formatting and string sorting
|
||||
nsCOMPtr<nsILocale> mLocale;
|
||||
nsCOMPtr<nsICollation> mCollation;
|
||||
|
|
|
@ -65,8 +65,6 @@
|
|||
#include "prtime.h"
|
||||
#include "prprf.h"
|
||||
|
||||
#define S(x) nsINavHistoryResult::##x
|
||||
|
||||
// emulate string comparison (used for sorting) for PRTime and int
|
||||
inline PRInt32 ComparePRTime(PRTime a, PRTime b)
|
||||
{
|
||||
|
@ -616,6 +614,23 @@ nsNavHistoryResult::GetSourceQueryOptions(nsINavHistoryQueryOptions** aOptions)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryResult::AddObserver(nsINavHistoryResultViewObserver* aObserver)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aObserver);
|
||||
|
||||
if (mObservers.IndexOf(aObserver) != -1)
|
||||
return NS_OK;
|
||||
return mObservers.AppendObject(aObserver) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistoryResult::RemoveObserver(nsINavHistoryResultViewObserver* aObserver)
|
||||
{
|
||||
mObservers.RemoveObject(aObserver);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryResult::SetTreeSortingIndicator
|
||||
//
|
||||
|
@ -1102,7 +1117,12 @@ NS_IMETHODIMP nsNavHistoryResult::IsSorted(PRBool *_retval)
|
|||
NS_IMETHODIMP nsNavHistoryResult::CanDrop(PRInt32 index, PRInt32 orientation,
|
||||
PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE;
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
mObservers[i]->CanDrop(index, orientation, _retval);
|
||||
if (*_retval)
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1113,7 +1133,10 @@ NS_IMETHODIMP nsNavHistoryResult::CanDrop(PRInt32 index, PRInt32 orientation,
|
|||
|
||||
NS_IMETHODIMP nsNavHistoryResult::Drop(PRInt32 row, PRInt32 orientation)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnDrop(row, orientation);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1275,6 +1298,11 @@ NS_IMETHODIMP nsNavHistoryResult::ToggleOpenState(PRInt32 index)
|
|||
{
|
||||
if (index < 0 || index >= mVisibleElements.Count())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnToggleOpenState(index);
|
||||
|
||||
nsNavHistoryResultNode* curNode = VisibleElementAt(index);
|
||||
if (curNode->mExpanded) {
|
||||
// collapse
|
||||
|
@ -1313,6 +1341,10 @@ NS_IMETHODIMP nsNavHistoryResult::ToggleOpenState(PRInt32 index)
|
|||
|
||||
NS_IMETHODIMP nsNavHistoryResult::CycleHeader(nsITreeColumn *col)
|
||||
{
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnCycleHeader(col);
|
||||
|
||||
PRInt32 colIndex;
|
||||
col->GetIndex(&colIndex);
|
||||
|
||||
|
@ -1352,13 +1384,19 @@ NS_IMETHODIMP nsNavHistoryResult::CycleHeader(nsITreeColumn *col)
|
|||
/* void selectionChanged (); */
|
||||
NS_IMETHODIMP nsNavHistoryResult::SelectionChanged()
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnSelectionChanged();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void cycleCell (in long row, in nsITreeColumn col); */
|
||||
NS_IMETHODIMP nsNavHistoryResult::CycleCell(PRInt32 row, nsITreeColumn *col)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnCycleCell(row, col);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* boolean isEditable (in long row, in nsITreeColumn col); */
|
||||
|
@ -1382,22 +1420,30 @@ NS_IMETHODIMP nsNavHistoryResult::SetCellText(PRInt32 row, nsITreeColumn *col, c
|
|||
/* void performAction (in wstring action); */
|
||||
NS_IMETHODIMP nsNavHistoryResult::PerformAction(const PRUnichar *action)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnPerformAction(action);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void performActionOnRow (in wstring action, in long row); */
|
||||
NS_IMETHODIMP nsNavHistoryResult::PerformActionOnRow(const PRUnichar *action, PRInt32 row)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnPerformActionOnRow(action, row);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void performActionOnCell (in wstring action, in long row, in nsITreeColumn col); */
|
||||
NS_IMETHODIMP nsNavHistoryResult::PerformActionOnCell(const PRUnichar *action, PRInt32 row, nsITreeColumn *col)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
PRInt32 count = mObservers.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i)
|
||||
mObservers[i]->OnPerformActionOnCell(action, row, col);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavHistoryResult::GetColumnType
|
||||
//
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче