Bug 405938 - problems when import/exporting of saved searches (r=mano, a=mconnor)

This commit is contained in:
dietrich%mozilla.com 2008-04-25 23:37:26 +00:00
Родитель 7dcd98e254
Коммит 4e84f21e7c
2 изменённых файлов: 341 добавлений и 14 удалений

Просмотреть файл

@ -1047,8 +1047,12 @@ var PlacesUtils = {
});
var batch = {
_utils: this,
nodes: nodes[0].children,
runBatched: function restore_runBatched() {
var searchIds = [];
var folderIdMap = [];
this.nodes.forEach(function(node) {
var root = node.root;
// FIXME support folders other than known roots
@ -1079,23 +1083,34 @@ var PlacesUtils = {
if (container != this.tagsFolderId)
this.bookmarks.removeFolderChildren(container);
else {
// remove tags via the tagging service
var tags = this.tagging.allTags;
var uris = [];
tags.forEach(function(aTag) {
var tagURIs = this.tagging.getURIsForTag(aTag);
for (let i in tagURIs)
this.tagging.untagURI(tagURIs[i], [aTag]);
}, this);
// remove tags via the tagging service
var tags = this.tagging.allTags;
var uris = [];
tags.forEach(function(aTag) {
var tagURIs = this.tagging.getURIsForTag(aTag);
for (let i in tagURIs)
this.tagging.untagURI(tagURIs[i], [aTag]);
}, this);
}
}
// insert the data into the db
node.children.forEach(function(child) {
var index = child.index;
this.importJSONNode(child, container, index);
var [folders, searches] = this.importJSONNode(child, container, index);
folderIdMap = folderIdMap.concat(folders);
searchIds = searchIds.concat(searches);
}, this);
}, PlacesUtils);
}, this._utils);
// fixup imported place: uris that contain folders
searchIds.forEach(function(aId) {
var oldURI = this.bookmarks.getBookmarkURI(aId);
var uri = this._fixupQuery(this.bookmarks.getBookmarkURI(aId),
folderIdMap);
if (!uri.equals(oldURI))
this.bookmarks.changeBookmarkURI(aId, uri);
}, this._utils);
}
};
@ -1111,9 +1126,13 @@ var PlacesUtils = {
* The container the data was dropped or pasted into
* @param aIndex
* The index within the container the item was dropped or pasted at
* @returns an array containing of maps of old folder ids to new folder ids,
* and an array of saved search ids that need to be fixed up.
* eg: [[[oldFolder1, newFolder1]], [search1]]
*/
importJSONNode: function PU_importJSONNode(aData, aContainer, aIndex) {
// create item
var folderIdMap = [];
var searchIds = [];
var id = -1;
switch (aData.type) {
case this.TYPE_X_MOZ_PLACE_CONTAINER:
@ -1122,7 +1141,7 @@ var PlacesUtils = {
aData.children.forEach(function(aChild) {
this.tagging.tagURI(this._uri(aChild.uri), [aData.title]);
}, this);
return;
return [folderIdMap, searchIds];
}
}
else if (aData.livemark && aData.annos) {
@ -1146,10 +1165,13 @@ var PlacesUtils = {
}
else {
id = this.bookmarks.createFolder(aContainer, aData.title, aIndex);
folderIdMap.push([aData.id, id]);
// process children
if (aData.children) {
aData.children.every(function(aChild, aIndex) {
this.importJSONNode(aChild, id, aIndex);
var [folderIds, searches] = this.importJSONNode(aChild, id, aIndex);
folderIdMap = folderIdMap.concat(folderIds);
searchIds = searchIds.concat(searches);
return true;
}, this);
}
@ -1166,6 +1188,8 @@ var PlacesUtils = {
}
if (aData.charset)
this.history.setCharsetForURI(this._uri(aData.uri), aData.charset);
if (aData.uri.match(/^place:/))
searchIds.push(id);
break;
case this.TYPE_X_MOZ_PLACE_SEPARATOR:
id = this.bookmarks.insertSeparator(aContainer, aIndex);
@ -1180,6 +1204,45 @@ var PlacesUtils = {
if (aData.annos)
this.setAnnotationsForItem(id, aData.annos);
}
return [folderIdMap, searchIds];
},
/**
* Replaces imported folder ids with their local counterparts in a place: URI.
*
* @param aURI
* A place: URI with folder ids.
* @param aFolderIdMap
* An array mapping old folder id to new folder ids.
* @returns the fixed up URI if all matched. If some matched, it returns
* the URI with only the matching folders included. If none matched it
* returns the input URI unchanged.
*/
_fixupQuery: function PU__fixupQuery(aQueryURI, aFolderIdMap) {
var queries = {};
var options = {};
this.history.queryStringToQueries(aQueryURI.spec, queries, {}, options);
var fixedQueries = [];
queries.value.forEach(function(aQuery) {
var folders = aQuery.getFolders({});
var newFolders = [];
aFolderIdMap.forEach(function(aMapping) {
if (folders.indexOf(aMapping[0]) != -1)
newFolders.push(aMapping[1]);
});
if (newFolders.length)
aQuery.setFolders(newFolders, newFolders.length);
fixedQueries.push(aQuery);
});
var stringURI = this.history.queriesToQueryString(fixedQueries,
fixedQueries.length,
options.value);
return this._uri(stringURI);
},
/**
@ -1275,7 +1338,9 @@ var PlacesUtils = {
(concreteId != aPlacesNode.itemId && !aResolveShortcuts))) {
aJSNode.type = self.TYPE_X_MOZ_PLACE;
aJSNode.uri = aPlacesNode.uri;
aJSNode.concreteId = concreteId;
// folder shortcut
if (aIsUICommand)
aJSNode.concreteId = concreteId;
return;
}
else if (aJSNode.id != -1) { // bookmark folder

Просмотреть файл

@ -0,0 +1,262 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** 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 Bug 384370 code.
*
* The Initial Developer of the Original Code is Mozilla Corp.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dietrich Ayala <dietrich@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
Components.utils.import("resource://gre/modules/utils.js");
var tests = [];
/*
Backup/restore tests example:
var myTest = {
populate: function () { ... add bookmarks ... },
validate: function () { ... query for your bookmarks ... }
}
this.push(myTest);
*/
/*
test summary:
- create folders with content
- create a query bookmark for those folders
- backs up bookmarks
- restores bookmarks
- confirms that the query has the new ids for the same folders
scenarios:
- 1 folder (folder shortcut)
- n folders (single query)
- n folders (multiple queries)
*/
const DEFAULT_INDEX = PlacesUtils.bookmarks.DEFAULT_INDEX;
var test = {
_testRootId: null,
_testRootTitle: "test root",
_folderIds: [],
_bookmarkURIs: [],
_count: 3,
populate: function populate() {
// folder to hold this test
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.toolbarFolderId);
this._testRootId =
PlacesUtils.bookmarks.createFolder(PlacesUtils.toolbarFolderId,
this._testRootTitle, DEFAULT_INDEX);
// create test folders each with a bookmark
for (var i = 0; i < this._count; i++) {
var folderId =
PlacesUtils.bookmarks.createFolder(this._testRootId, "folder" + i, DEFAULT_INDEX);
this._folderIds.push(folderId)
var bookmarkURI = uri("http://" + i);
PlacesUtils.bookmarks.insertBookmark(folderId, bookmarkURI,
DEFAULT_INDEX, "bookmark" + i);
this._bookmarkURIs.push(bookmarkURI);
}
// create a query URI with 1 folder (ie: folder shortcut)
this._queryURI1 = uri("place:folder=" + this._folderIds[0] + "&queryType=1");
this._queryTitle1 = "query1";
PlacesUtils.bookmarks.insertBookmark(this._testRootId, this._queryURI1,
DEFAULT_INDEX, this._queryTitle1);
// create a query URI with _count folders
this._queryURI2 = uri("place:folder=" + this._folderIds.join("&folder=") + "&queryType=1");
this._queryTitle2 = "query2";
PlacesUtils.bookmarks.insertBookmark(this._testRootId, this._queryURI2,
DEFAULT_INDEX, this._queryTitle2);
// create a query URI with _count queries (each with a folder)
// first get a query object for each folder
var queries = this._folderIds.map(function(aFolderId) {
var query = PlacesUtils.history.getNewQuery();
query.setFolders([aFolderId], 1);
return query;
});
var options = PlacesUtils.history.getNewQueryOptions();
options.queryType = options.QUERY_TYPE_BOOKMARKS;
this._queryURI3 =
uri(PlacesUtils.history.queriesToQueryString(queries, queries.length, options));
this._queryTitle3 = "query3";
PlacesUtils.bookmarks.insertBookmark(this._testRootId, this._queryURI3,
DEFAULT_INDEX, this._queryTitle3);
},
clean: function () {},
validate: function validate() {
// Throw a wrench in the works by inserting some new bookmarks,
// ensuring folder ids won't be the same, when restoring.
for (var i = 0; i < 10; i++) {
PlacesUtils.bookmarks.
insertBookmark(PlacesUtils.bookmarksMenuFolderId, uri("http://aaaa"+i), DEFAULT_INDEX, "");
}
var toolbar =
PlacesUtils.getFolderContents(PlacesUtils.toolbarFolderId,
false, true).root;
do_check_true(toolbar.childCount, 1);
var folderNode = toolbar.getChild(0);
do_check_eq(folderNode.type, folderNode.RESULT_TYPE_FOLDER);
do_check_eq(folderNode.title, this._testRootTitle);
folderNode.QueryInterface(Ci.nsINavHistoryQueryResultNode);
folderNode.containerOpen = true;
// |_count| folders + the query node
do_check_eq(folderNode.childCount, this._count+3);
for (var i = 0; i < this._count; i++) {
var subFolder = folderNode.getChild(i);
do_check_eq(subFolder.title, "folder"+i);
subFolder.QueryInterface(Ci.nsINavHistoryContainerResultNode);
subFolder.containerOpen = true;
do_check_eq(subFolder.childCount, 1);
var child = subFolder.getChild(0);
do_check_eq(child.title, "bookmark"+i);
do_check_true(uri(child.uri).equals(uri("http://" + i)))
}
// validate folder shortcut
this.validateQueryNode1(folderNode.getChild(this._count));
// validate folders query
this.validateQueryNode2(folderNode.getChild(this._count + 1));
// validate multiple queries query
this.validateQueryNode3(folderNode.getChild(this._count + 2));
// clean up
folderNode.containerOpen = false;
toolbar.containerOpen = false;
},
validateQueryNode1: function validateQueryNode1(aNode) {
do_check_eq(aNode.title, this._queryTitle1);
do_check_true(PlacesUtils.nodeIsFolder(aNode));
aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
aNode.containerOpen = true;
do_check_eq(aNode.childCount, 1);
var child = aNode.getChild(0);
do_check_true(uri(child.uri).equals(uri("http://0")))
do_check_eq(child.title, "bookmark0")
aNode.containerOpen = false;
},
validateQueryNode2: function validateQueryNode2(aNode) {
do_check_eq(aNode.title, this._queryTitle2);
do_check_true(PlacesUtils.nodeIsQuery(aNode));
aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
aNode.containerOpen = true;
do_check_eq(aNode.childCount, this._count);
for (var i = 0; i < aNode.childCount; i++) {
var child = aNode.getChild(i);
do_check_true(uri(child.uri).equals(uri("http://" + i)))
do_check_eq(child.title, "bookmark" + i)
}
aNode.containerOpen = false;
},
validateQueryNode3: function validateQueryNode3(aNode) {
do_check_eq(aNode.title, this._queryTitle3);
do_check_true(PlacesUtils.nodeIsQuery(aNode));
aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
aNode.containerOpen = true;
do_check_eq(aNode.childCount, this._count);
for (var i = 0; i < aNode.childCount; i++) {
var child = aNode.getChild(i);
do_check_true(uri(child.uri).equals(uri("http://" + i)))
do_check_eq(child.title, "bookmark" + i)
}
aNode.containerOpen = false;
}
}
tests.push(test);
function run_test() {
do_check_eq(typeof PlacesUtils, "object");
// make json file
var jsonFile = dirSvc.get("ProfD", Ci.nsILocalFile);
jsonFile.append("bookmarks.json");
if (jsonFile.exists())
jsonFile.remove(false);
jsonFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
if (!jsonFile.exists())
do_throw("couldn't create file: bookmarks.exported.json");
// populate db
tests.forEach(function(aTest) {
aTest.populate();
// sanity
aTest.validate();
});
// export json to file
try {
PlacesUtils.backupBookmarksToFile(jsonFile);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
// clean
tests.forEach(function(aTest) {
aTest.clean();
});
// restore json file
try {
PlacesUtils.restoreBookmarksFromJSONFile(jsonFile);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
// validate
tests.forEach(function(aTest) {
aTest.validate();
});
// clean up
jsonFile.remove(false);
}