fix for bug #371827: places bookmarks need additional metadate for lastModified and dateAdded.

fix for bug #381209:  don't write out ID attributes to bookmarks.html, as it will confuse Firefox 2.

patch by dietrich, sspitzer.  r=mano,dietrich,sspitzer
This commit is contained in:
sspitzer%mozilla.org 2007-05-19 00:40:57 +00:00
Родитель ffe74a9a39
Коммит 785bb1ccbf
17 изменённых файлов: 772 добавлений и 117 удалений

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

@ -398,10 +398,10 @@
<treecol label="&col.url.label;" id="url" flex="5"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.lastvisit.label;" id="date" flex="1"
<treecol label="&col.lastvisit.label;" id="date" flex="1"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.visitcount.label;" id="visitCount" flex="1" hidden="true"
<treecol label="&col.visitcount.label;" id="visitCount" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.keyword.label;" id="keyword" flex="1" hidden="true"
@ -409,6 +409,12 @@
<splitter class="tree-splitter"/>
<treecol label="&col.description.label;" id="description" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.dateadded.label;" id="dateAdded" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
<splitter class="tree-splitter"/>
<treecol label="&col.lastmodified.label;" id="lastModified" flex="1" hidden="true"
persist="width hidden ordinal sortActive sortDirection"/>
</treecols>
<treechildren id="placeContentChildren" view="placeContent" flex="1"/>
</tree>

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

@ -387,7 +387,35 @@ PlacesTreeView.prototype = {
aShowThisOne.value = aTop.time < aNext.time;
return true;
},
_convertPRTimeToString: function PTV__convertPRTimeToString(aTime) {
var timeInMilliseconds = aTime / 1000; // PRTime is in microseconds
var timeObj = new Date(timeInMilliseconds);
// Check if it is today and only display the time. Only bother
// checking for today if it's within the last 24 hours, since
// computing midnight is not really cheap. Sometimes we may get dates
// in the future, so always show those.
var ago = new Date(Date.now() - timeInMilliseconds);
var dateFormat = Ci.nsIScriptableDateFormat.dateFormatShort;
if (ago > -10000 && ago < (1000 * 24 * 60 * 60)) {
var midnight = new Date(timeInMilliseconds);
midnight.setHours(0);
midnight.setMinutes(0);
midnight.setSeconds(0);
midnight.setMilliseconds(0);
if (timeInMilliseconds > midnight.getTime())
dateFormat = Ci.nsIScriptableDateFormat.dateFormatNone;
}
return (this._dateService.FormatDateTime("", dateFormat,
Ci.nsIScriptableDateFormat.timeFormatNoSeconds,
timeObj.getFullYear(), timeObj.getMonth() + 1,
timeObj.getDate(), timeObj.getHours(),
timeObj.getMinutes(), timeObj.getSeconds()));
},
COLUMN_TYPE_UNKNOWN: 0,
COLUMN_TYPE_TITLE: 1,
COLUMN_TYPE_URI: 2,
@ -395,6 +423,8 @@ PlacesTreeView.prototype = {
COLUMN_TYPE_VISITCOUNT: 4,
COLUMN_TYPE_KEYWORD: 5,
COLUMN_TYPE_DESCRIPTION: 6,
COLUMN_TYPE_DATEADDED: 7,
COLUMN_TYPE_LASTMODIFIED: 8,
_getColumnType: function PTV__getColumnType(aColumn) {
switch (aColumn.id) {
@ -410,6 +440,10 @@ PlacesTreeView.prototype = {
return this.COLUMN_TYPE_KEYWORD;
case "description":
return this.COLUMN_TYPE_DESCRIPTION;
case "dateAdded":
return this.COLUMN_TYPE_DATEADDED;
case "lastModified":
return this.COLUMN_TYPE_LASTMODIFIED;
}
return this.COLUMN_TYPE_UNKNOWN;
},
@ -421,9 +455,9 @@ PlacesTreeView.prototype = {
case Ci.nsINavHistoryQueryOptions.SORT_BY_TITLE_DESCENDING:
return [this.COLUMN_TYPE_TITLE, true];
case Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_ASCENDING:
return [this.COLUMN_TYPE_DATA, false];
return [this.COLUMN_TYPE_DATE, false];
case Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING:
return [this.COLUMN_TYPE_DATA, true];
return [this.COLUMN_TYPE_DATE, true];
case Ci.nsINavHistoryQueryOptions.SORT_BY_URI_ASCENDING:
return [this.COLUMN_TYPE_URI, false];
case Ci.nsINavHistoryQueryOptions.SORT_BY_URI_DESCENDING:
@ -443,6 +477,14 @@ PlacesTreeView.prototype = {
case Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_DESCENDING:
if (this._result.sortingAnnotation == DESCRIPTION_ANNO)
return [this.COLUMN_TYPE_DESCRIPTION, true];
case Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_ASCENDING:
return [this.COLUMN_TYPE_DATEADDED, false];
case Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING:
return [this.COLUMN_TYPE_DATEADDED, true];
case Ci.nsINavHistoryQueryOptions.SORT_BY_LASTMODIFIED_ASCENDING:
return [this.COLUMN_TYPE_LASTMODIFIED, false];
case Ci.nsINavHistoryQueryOptions.SORT_BY_LASTMODIFIED_DESCENDING:
return [this.COLUMN_TYPE_LASTMODIFIED, true];
}
return [this.COLUMN_TYPE_UNKNOWN, false];
},
@ -976,7 +1018,6 @@ PlacesTreeView.prototype = {
case this.COLUMN_TYPE_URI:
if (PlacesUtils.nodeIsURI(node))
return node.uri;
return "";
case this.COLUMN_TYPE_DATE:
if (node.time == 0 || !PlacesUtils.nodeIsURI(node)) {
@ -987,33 +1028,8 @@ PlacesTreeView.prototype = {
// Only show this for URI-based items.
return "";
}
if (this._getRowSessionStatus(aRow) != this.SESSION_STATUS_CONTINUE) {
var nodeTime = node.time / 1000; // PRTime is in microseconds
var nodeTimeObj = new Date(nodeTime);
// Check if it is today and only display the time. Only bother
// checking for today if it's within the last 24 hours, since
// computing midnight is not really cheap. Sometimes we may get dates
// in the future, so always show those.
var ago = new Date(Date.now() - nodeTime);
var dateFormat = Ci.nsIScriptableDateFormat.dateFormatShort;
if (ago > -10000 && ago < (1000 * 24 * 60 * 60)) {
var midnight = new Date(nodeTime);
midnight.setHours(0);
midnight.setMinutes(0);
midnight.setSeconds(0);
midnight.setMilliseconds(0);
if (nodeTime > midnight.getTime())
dateFormat = Ci.nsIScriptableDateFormat.dateFormatNone;
}
return (this._dateService.FormatDateTime("", dateFormat,
Ci.nsIScriptableDateFormat.timeFormatNoSeconds,
nodeTimeObj.getFullYear(), nodeTimeObj.getMonth() + 1,
nodeTimeObj.getDate(), nodeTimeObj.getHours(),
nodeTimeObj.getMinutes(), nodeTimeObj.getSeconds()));
}
if (this._getRowSessionStatus(aRow) != this.SESSION_STATUS_CONTINUE)
return this._convertPRTimeToString(node.time);
return "";
case this.COLUMN_TYPE_VISITCOUNT:
return node.accessCount;
@ -1025,7 +1041,14 @@ PlacesTreeView.prototype = {
const annos = PlacesUtils.annotations;
if (annos.itemHasAnnotation(node.itemId, DESCRIPTION_ANNO))
return annos.getItemAnnotationString(node.itemId, DESCRIPTION_ANNO)
return "";
case this.COLUMN_TYPE_DATEADDED:
if (node.dateAdded)
return this._convertPRTimeToString(node.dateAdded);
return "";
case this.COLUMN_TYPE_LASTMODIFIED:
if (node.lastModified)
return this._convertPRTimeToString(node.lastModified);
return "";
}
return "";
@ -1161,6 +1184,26 @@ PlacesTreeView.prototype = {
newSort = NHQO.SORT_BY_ANNOTATION_ASCENDING;
newSortingAnnotation = DESCRIPTION_ANNO;
}
break;
case this.COLUMN_TYPE_DATEADDED:
if (oldSort == NHQO.SORT_BY_DATEADDED_ASCENDING)
newSort = NHQO.SORT_BY_DATEADDED_DESCENDING;
else if (allowTriState &&
oldSort == NHQO.SORT_BY_DATEADDED_DESCENDING)
newSort = NHQO.SORT_BY_NONE;
else
newSort = NHQO.SORT_BY_DATEADDED_ASCENDING;
break;
case this.COLUMN_TYPE_LASTMODIFIED:
if (oldSort == NHQO.SORT_BY_LASTMODIFIED_ASCENDING)
newSort = NHQO.SORT_BY_LASTMODIFIED_DESCENDING;
else if (allowTriState &&
oldSort == NHQO.SORT_BY_LASTMODIFIED_DESCENDING)
newSort = NHQO.SORT_BY_NONE;
else
newSort = NHQO.SORT_BY_LASTMODIFIED_ASCENDING;
break;
default:
throw Cr.NS_ERROR_INVALID_ARG;

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

@ -63,7 +63,7 @@
* ICON_URI is new for places bookmarks.html, it refers to the original
* URI of the favicon so we don't have to make up favicon URLs.
* Text of the <a> container is the name of the bookmark
* Ignored: ADD_DATE, LAST_VISIT, LAST_MODIFIED, ID
* Ignored: LAST_VISIT, ID (writing out non-RDF IDs can confuse Firefox 2)
* Bookmark comment := dd
* This affects the previosly added bookmark
* Separator := hr
@ -116,10 +116,12 @@ static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
#define KEY_ICON_URI_LOWER "icon_uri"
#define KEY_SHORTCUTURL_LOWER "shortcuturl"
#define KEY_POST_DATA_LOWER "post_data"
#define KEY_ID_LOWER "id"
#define KEY_ITEM_ID_LOWER "item_id"
#define KEY_NAME_LOWER "name"
#define KEY_MICSUM_GEN_URI_LOWER "micsum_gen_uri"
#define KEY_GENERATED_TITLE "generated_title"
#define KEY_GENERATED_TITLE_LOWER "generated_title"
#define KEY_DATE_ADDED_LOWER "add_date"
#define KEY_LAST_MODIFIED_LOWER "last_modified"
#define LOAD_IN_SIDEBAR_ANNO NS_LITERAL_CSTRING("bookmarkProperties/loadInSidebar")
#define DESCRIPTION_ANNO NS_LITERAL_CSTRING("bookmarkProperties/description")
@ -149,7 +151,10 @@ public:
mContainerID(aID),
mContainerNesting(0),
mLastContainerType(Container_Normal),
mInDescription(PR_FALSE)
mInDescription(PR_FALSE),
mPreviousId(0),
mPreviousDateAdded(0),
mPreviousLastModifiedDate(0)
{
}
@ -217,6 +222,11 @@ public:
// Contains the id of an imported, or newly created bookmark.
PRInt64 mPreviousId;
// Contains the date-added and last-modified-date of an imported item.
// Used to override the values set by insertItem, createFolder, etc.
PRTime mPreviousDateAdded;
PRTime mPreviousLastModifiedDate;
};
/**
@ -392,6 +402,11 @@ protected:
NS_ASSERTION(mFrames.Length() > 0, "Asking for frame when there are none!");
return mFrames[mFrames.Length() - 1];
}
BookmarkImportFrame& PreviousFrame()
{
NS_ASSERTION(mFrames.Length() > 1, "Asking for frame when there are not enough!");
return mFrames[mFrames.Length() - 2];
}
nsresult NewFrame();
nsresult PopFrame();
@ -400,6 +415,7 @@ protected:
nsresult SetFaviconForFolder(PRInt64 aFolder, const nsACString& aFavicon);
PRInt64 ConvertImportedIdToInternalId(const nsCString& aId);
PRTime ConvertImportedDateToInternalDate(const nsACString& aDate);
#ifdef DEBUG_IMPORT
// prints spaces for indenting to the current frame depth
@ -493,13 +509,15 @@ BookmarkContentSink::OpenContainer(const nsIParserNode& aNode)
NS_IMETHODIMP
BookmarkContentSink::CloseContainer(const nsHTMLTag aTag)
{
BookmarkImportFrame& frame = CurFrame();
// see the comment for the definition of mInDescription. Basically, we commit
// any text in mPreviousText to the description of the node/folder if there
// is any.
BookmarkImportFrame& frame = CurFrame();
if (frame.mInDescription) {
frame.mPreviousText.Trim(kWhitespace); // important!
if (!frame.mPreviousText.IsEmpty()) {
PRInt64 itemId = !frame.mPreviousLink ?
frame.mContainerID : frame.mPreviousId;
@ -513,6 +531,29 @@ BookmarkContentSink::CloseContainer(const nsHTMLTag aTag)
nsIAnnotationService::EXPIRE_NEVER);
}
frame.mPreviousText.Truncate();
// Set last-modified a 2nd time for all items with descriptions
// we need to set last-modified as the *last* step in processing
// any item type in the bookmarks.html file, so that we do
// not overwrite the imported value. for items without descriptions,
// setting this value after setting the item title is that
// last point at which we can save this value before it gets reset.
// for items with descriptions, it must set after that point.
// however, at the point at which we set the title, there's no way
// to determine if there will be a description following,
// so we need to set the last-modified-date at both places.
PRTime lastModified;
if (!frame.mPreviousLink) {
lastModified = PreviousFrame().mPreviousLastModifiedDate;
} else {
lastModified = frame.mPreviousLastModifiedDate;
}
if (itemId > 0 && lastModified > 0) {
rv = mBookmarksService->SetItemLastModified(itemId, lastModified);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetItemLastModified failed");
}
}
frame.mInDescription = PR_FALSE;
}
@ -693,9 +734,15 @@ BookmarkContentSink::HandleHeadBegin(const nsIParserNode& node)
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_PLACESROOT_LOWER)) {
frame.mLastContainerType = BookmarkImportFrame::Container_Places;
break;
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_ID_LOWER)) {
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_ITEM_ID_LOWER)) {
frame.mLastContainerId =
ConvertImportedIdToInternalId(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_DATE_ADDED_LOWER)) {
frame.mPreviousDateAdded =
ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_LAST_MODIFIED_LOWER)) {
frame.mPreviousLastModifiedDate =
ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
}
}
}
@ -737,7 +784,7 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
// mPreviousText will hold our link text, clear it so that can be appended to
frame.mPreviousText.Truncate();
// get the attributes we care about
nsAutoString href;
nsAutoString feedUrl;
@ -747,9 +794,12 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
nsAutoString keyword;
nsAutoString postData;
nsAutoString webPanel;
nsAutoString id;
nsAutoString itemId;
nsAutoString micsumGenURI;
nsAutoString generatedTitle;
nsAutoString dateAdded;
nsAutoString lastModified;
PRInt32 attrCount = node.GetAttributeCount();
for (PRInt32 i = 0; i < attrCount; i ++) {
const nsAString& key = node.GetKeyAt(i);
@ -769,12 +819,16 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
postData = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_WEB_PANEL_LOWER)) {
webPanel = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_ID_LOWER)) {
id = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_ITEM_ID_LOWER)) {
itemId = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_MICSUM_GEN_URI_LOWER)) {
micsumGenURI = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_GENERATED_TITLE)) {
} else if (key.LowerCaseEqualsLiteral(KEY_GENERATED_TITLE_LOWER)) {
generatedTitle = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_DATE_ADDED_LOWER)) {
dateAdded = node.GetValueAt(i);
} else if (key.LowerCaseEqualsLiteral(KEY_LAST_MODIFIED_LOWER)) {
lastModified = node.GetValueAt(i);
}
}
href.Trim(kWhitespace);
@ -785,9 +839,11 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
keyword.Trim(kWhitespace);
postData.Trim(kWhitespace);
webPanel.Trim(kWhitespace);
id.Trim(kWhitespace);
itemId.Trim(kWhitespace);
micsumGenURI.Trim(kWhitespace);
generatedTitle.Trim(kWhitespace);
dateAdded.Trim(kWhitespace);
lastModified.Trim(kWhitespace);
// For feeds, get the feed URL. If it is invalid, it will leave mPreviousFeed
// NULL and we'll continue trying to create it as a normal bookmark.
@ -816,8 +872,13 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
}
}
// if there's a pre-existing Places bookmark id, use it
frame.mPreviousId = ConvertImportedIdToInternalId(NS_ConvertUTF16toUTF8(id));
// if there's a pre-existing Places bookmark ITEM_ID, use it
frame.mPreviousId = ConvertImportedIdToInternalId(NS_ConvertUTF16toUTF8(itemId));
// Save last-modified-date, for setting after all the bookmark properties have been set.
if (!lastModified.IsEmpty()) {
frame.mPreviousLastModifiedDate = ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(lastModified));
}
// if there is a feedURL, this is a livemark, which is a special case
// that we handle in HandleLinkEnd(): don't create normal bookmarks
@ -838,6 +899,17 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
rv = mBookmarksService->InsertItem(frame.mContainerID, frame.mPreviousLink,
mBookmarksService->DEFAULT_INDEX, &frame.mPreviousId);
NS_ASSERTION(NS_SUCCEEDED(rv), "InsertItem failed");
// set the date added value, if we have it
// important: this has to happen after InsertItem
// so that we set the imported value
if (!dateAdded.IsEmpty()) {
PRTime convertedDateAdded = ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(dateAdded));
if (convertedDateAdded) {
rv = mBookmarksService->SetItemDateAdded(frame.mPreviousId, convertedDateAdded);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetItemDateAdded failed");
}
}
}
// save the favicon, ignore errors
@ -940,11 +1012,6 @@ BookmarkContentSink::HandleLinkEnd()
}
if (!isLivemark) {
#ifdef DEBUG_IMPORT
PrintNesting();
printf("Creating livemark '%s' %lld\n",
NS_ConvertUTF16toUTF8(frame.mPreviousText).get(), frame.mPreviousId);
#endif
if (mIsImportDefaults) {
rv = mLivemarkService->CreateLivemarkFolderOnly(mBookmarksService,
frame.mContainerID,
@ -963,16 +1030,32 @@ BookmarkContentSink::HandleLinkEnd()
&frame.mPreviousId);
NS_ASSERTION(NS_SUCCEEDED(rv), "CreateLivemark failed!");
}
#ifdef DEBUG_IMPORT
PrintNesting();
printf("Creating livemark '%s' %lld\n",
NS_ConvertUTF16toUTF8(frame.mPreviousText).get(), frame.mPreviousId);
#endif
}
}
else if (frame.mPreviousLink) {
#ifdef DEBUG_IMPORT
PrintNesting();
printf("Creating bookmark '%s'\n",
NS_ConvertUTF16toUTF8(frame.mPreviousText).get());
printf("Creating bookmark '%s' %lld\n",
NS_ConvertUTF16toUTF8(frame.mPreviousText).get(), frame.mPreviousId);
#endif
mBookmarksService->SetItemTitle(frame.mPreviousId, frame.mPreviousText);
}
// Set last-modified-date for bookmarks and livemarks here so that the
// imported date overrides the date from the call to that sets the description
// that we made above.
if (frame.mPreviousId > 0 && frame.mPreviousLastModifiedDate > 0) {
rv = mBookmarksService->SetItemLastModified(frame.mPreviousId, frame.mPreviousLastModifiedDate);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetItemLastModified failed");
// Note: don't clear mPreviousLastModifiedDate, because if this item has a
// description, we'll need to set it again.
}
frame.mPreviousText.Truncate();
}
@ -987,17 +1070,17 @@ BookmarkContentSink::HandleSeparator(const nsIParserNode& aNode)
// check for pre-existing id
PRInt64 id = 0;
nsAutoString idAttr;
nsAutoString itemIdAttr;
PRInt32 attrCount = aNode.GetAttributeCount();
for (PRInt32 i = 0; i < attrCount; i ++) {
const nsAString& key = aNode.GetKeyAt(i);
if (key.LowerCaseEqualsLiteral(KEY_ID_LOWER)) {
idAttr = aNode.GetValueAt(i);
if (key.LowerCaseEqualsLiteral(KEY_ITEM_ID_LOWER)) {
itemIdAttr = aNode.GetValueAt(i);
}
}
idAttr.Trim(kWhitespace);
id = ConvertImportedIdToInternalId(NS_ConvertUTF16toUTF8(idAttr));
itemIdAttr.Trim(kWhitespace);
id = ConvertImportedIdToInternalId(NS_ConvertUTF16toUTF8(itemIdAttr));
// check id validity
if (id > 0) {
@ -1040,6 +1123,11 @@ BookmarkContentSink::HandleSeparator(const nsIParserNode& aNode)
if (!name.IsEmpty())
mBookmarksService->SetItemTitle(itemId, name);
// Note: we do not need to import ADD_DATE or LAST_MODIFIED for separators
// because pre-Places bookmarks does not support them.
// and we can't write them out because attributes other than NAME make Firefox 2.x
// crash/hang - see bug #381129
}
}
@ -1142,6 +1230,18 @@ BookmarkContentSink::NewFrame()
printf("\n");
#endif
BookmarkImportFrame& frame = CurFrame();
if (frame.mPreviousDateAdded > 0) {
nsresult rv = mBookmarksService->SetItemDateAdded(ourID, frame.mPreviousDateAdded);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetItemDateAdded failed");
frame.mPreviousDateAdded = 0;
}
if (frame.mPreviousLastModifiedDate > 0) {
nsresult rv = mBookmarksService->SetItemLastModified(ourID, frame.mPreviousLastModifiedDate);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetItemLastModified failed");
// don't clear last-modified, in case there's a description
}
if (!mFrames.AppendElement(BookmarkImportFrame(ourID)))
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
@ -1211,7 +1311,7 @@ BookmarkContentSink::SetFaviconForURI(nsIURI* aPageURI, nsIURI* aIconURI,
faviconSpec.AssignLiteral("http://www.mozilla.org/2005/made-up-favicon/");
faviconSpec.AppendInt(serialNumber);
faviconSpec.AppendLiteral("-");
faviconSpec.AppendInt(PR_Now());
faviconSpec.AppendInt(PR_Now()); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = NS_NewURI(getter_AddRefs(faviconURI), faviconSpec);
NS_ENSURE_SUCCESS(rv, rv);
serialNumber ++;
@ -1295,11 +1395,11 @@ BookmarkContentSink::SetFaviconForFolder(PRInt64 aFolder,
return faviconService->SetFaviconUrlForPage(folderURI, faviconURI);
}
// Converts a string id (legacy rdf or contemporary) into an int id
// Converts a string id (ITEM_ID) into an int id
PRInt64
BookmarkContentSink::ConvertImportedIdToInternalId(const nsCString& aId) {
PRInt64 intId = 0;
if (aId.IsEmpty() || Substring(aId, 0, 4).Equals(NS_LITERAL_CSTRING("rdf:"), CaseInsensitiveCompare))
if (aId.IsEmpty())
return intId;
nsresult rv;
intId = aId.ToInteger(&rv);
@ -1308,6 +1408,22 @@ BookmarkContentSink::ConvertImportedIdToInternalId(const nsCString& aId) {
return intId;
}
// Converts a string date in seconds to an int date in microseconds
PRTime
BookmarkContentSink::ConvertImportedDateToInternalDate(const nsACString& aDate) {
PRTime convertedDate = 0;
if (!aDate.IsEmpty()) {
nsresult rv;
convertedDate = aDate.ToInteger(&rv);
if (NS_SUCCEEDED(rv)) {
convertedDate *= 1000000; // in bookmarks.html this value is in seconds, not microseconds
}
else {
convertedDate = 0;
}
}
return convertedDate;
}
// SyncChannelStatus
//
@ -1363,9 +1479,11 @@ static const char kFeedURIAttribute[] = " FEEDURL=\"";
static const char kWebPanelAttribute[] = " WEB_PANEL=\"true\"";
static const char kKeywordAttribute[] = " SHORTCUTURL=\"";
static const char kPostDataAttribute[] = " POST_DATA=\"";
static const char kIdAttribute[] = " ID=\"";
static const char kItemIdAttribute[] = " ITEM_ID=\"";
static const char kNameAttribute[] = " NAME=\"";
static const char kMicsumGenURIEquals[] = " MICSUM_GEN_URI=\"";
static const char kMicsumGenURIAttribute[] = " MICSUM_GEN_URI=\"";
static const char kDateAddedAttribute[] = " ADD_DATE=\"";
static const char kLastModifiedAttribute[] = " LAST_MODIFIED=\"";
// WriteContainerPrologue
//
@ -1491,6 +1609,27 @@ WriteFaviconAttribute(const nsACString& aURI, nsIOutputStream* aOutput)
return NS_OK;
}
// WriteDateAttribute
//
// This writes the '{attr value=}"{time in seconds}"' attribute for
// an item.
static nsresult
WriteDateAttribute(const char aAttributeStart[], PRInt32 aLength, PRTime aAttributeValue, nsIOutputStream* aOutput)
{
// write attribute start
PRUint32 dummy;
nsresult rv = aOutput->Write(aAttributeStart, aLength, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
// write attribute value
nsCAutoString dateInSeconds;
aAttributeValue/= 1000000; // in bookmarks.html this value is in seconds, not microseconds
dateInSeconds.AppendInt(aAttributeValue); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(dateInSeconds.get(), dateInSeconds.Length(), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
return aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
}
// nsPlacesImportExportService::WriteContainer
//
@ -1537,6 +1676,26 @@ nsPlacesImportExportService::WriteContainerHeader(PRInt64 aFolder, const nsACStr
rv = aOutput->Write(kContainerIntro, sizeof(kContainerIntro)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
// write ADD_DATE
PRTime dateAdded = 0;
rv = mBookmarksService->GetItemDateAdded(aFolder, &dateAdded);
NS_ENSURE_SUCCESS(rv, rv);
if (dateAdded) {
rv = WriteDateAttribute(kDateAddedAttribute, sizeof(kDateAddedAttribute)-1, dateAdded, aOutput);
NS_ENSURE_SUCCESS(rv, rv);
}
// write LAST_MODIFIED
PRTime lastModified = 0;
rv = mBookmarksService->GetItemLastModified(aFolder, &lastModified);
NS_ENSURE_SUCCESS(rv, rv);
if (lastModified) {
rv = WriteDateAttribute(kLastModifiedAttribute, sizeof(kLastModifiedAttribute)-1, lastModified, aOutput);
NS_ENSURE_SUCCESS(rv, rv);
}
PRInt64 placesRoot;
rv = mBookmarksService->GetPlacesRoot(&placesRoot);
NS_ENSURE_SUCCESS(rv,rv);
@ -1560,13 +1719,13 @@ nsPlacesImportExportService::WriteContainerHeader(PRInt64 aFolder, const nsACStr
rv = aOutput->Write(kToolbarFolderAttribute, sizeof(kToolbarFolderAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
}
// id
rv = aOutput->Write(kIdAttribute, sizeof(kIdAttribute)-1, &dummy);
// write id as ITEM_ID as non-rdf IDs can confuse Firefox 2
rv = aOutput->Write(kItemIdAttribute, sizeof(kItemIdAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString id;
id.AppendInt(aFolder);
rv = aOutput->Write(id.get(), id.Length(), &dummy);
nsCAutoString itemIdAttr;
itemIdAttr.AppendInt(aFolder); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(itemIdAttr.get(), itemIdAttr.Length(), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
@ -1692,6 +1851,26 @@ nsPlacesImportExportService::WriteItem(nsINavHistoryResultNode* aItem,
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
// write ADD_DATE
PRTime dateAdded = 0;
rv = aItem->GetDateAdded(&dateAdded);
NS_ENSURE_SUCCESS(rv, rv);
if (dateAdded) {
rv = WriteDateAttribute(kDateAddedAttribute, sizeof(kDateAddedAttribute)-1, dateAdded, aOutput);
NS_ENSURE_SUCCESS(rv, rv);
}
// write LAST_MODIFIED
PRTime lastModified = 0;
rv = aItem->GetLastModified(&lastModified);
NS_ENSURE_SUCCESS(rv, rv);
if (lastModified) {
rv = WriteDateAttribute(kLastModifiedAttribute, sizeof(kLastModifiedAttribute)-1, lastModified, aOutput);
NS_ENSURE_SUCCESS(rv, rv);
}
// ' ICON="..."'
rv = WriteFaviconAttribute(uri, aOutput);
NS_ENSURE_SUCCESS(rv, rv);
@ -1701,12 +1880,12 @@ nsPlacesImportExportService::WriteItem(nsINavHistoryResultNode* aItem,
rv = aItem->GetItemId(&itemId);
NS_ENSURE_SUCCESS(rv, rv);
// write id
rv = aOutput->Write(kIdAttribute, sizeof(kIdAttribute)-1, &dummy);
// write id as ITEM_ID as non-rdf IDs can confuse Firefox 2
rv = aOutput->Write(kItemIdAttribute, sizeof(kItemIdAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString id;
id.AppendInt(itemId);
rv = aOutput->Write(id.get(), id.Length(), &dummy);
nsCAutoString itemIdAttr;
itemIdAttr.AppendInt(itemId); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(itemIdAttr.get(), itemIdAttr.Length(), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
@ -1775,7 +1954,7 @@ nsPlacesImportExportService::WriteItem(nsINavHistoryResultNode* aItem,
NS_ENSURE_SUCCESS(rv, rv);
// write out generator URI
rv = aOutput->Write(kMicsumGenURIEquals, sizeof(kMicsumGenURIEquals)-1, &dummy);
rv = aOutput->Write(kMicsumGenURIAttribute, sizeof(kMicsumGenURIAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
rv = WriteEscapedUrl(spec, aOutput);
NS_ENSURE_SUCCESS(rv, rv);
@ -1868,12 +2047,12 @@ nsPlacesImportExportService::WriteLivemark(PRInt64 aFolderId, const nsACString&
NS_ENSURE_SUCCESS(rv, rv);
}
// write id
rv = aOutput->Write(kIdAttribute, sizeof(kIdAttribute)-1, &dummy);
// write id as ITEM_ID as non-rdf IDs can confuse Firefox 2
rv = aOutput->Write(kItemIdAttribute, sizeof(kItemIdAttribute)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString id;
id.AppendInt(aFolderId);
rv = aOutput->Write(id.get(), id.Length(), &dummy);
nsCAutoString itemIdAttr;
itemIdAttr.AppendInt(aFolderId); // casting from PRInt64 -> PRInt32, data loss, fix me
rv = aOutput->Write(itemIdAttr.get(), itemIdAttr.Length(), &dummy);
NS_ENSURE_SUCCESS(rv, rv);
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
@ -1925,7 +2104,7 @@ nsPlacesImportExportService::WriteSeparator(nsINavHistoryResultNode* aItem,
NS_ENSURE_SUCCESS(rv, rv);
// Note: we can't write the separator ID or anything else other than NAME
// because it makes Firefox 2.x crash/hang - see bug 381129
// because it makes Firefox 2.x crash/hang - see bug #381129
nsAutoString title;
rv = mBookmarksService->GetItemTitle(itemId, title);

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

@ -24,7 +24,7 @@
<DT><A HREF="http://en-US.www.mozilla.com/en-US/firefox/community/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" ID="rdf:#$42iCK1">Get Involved</A>
<DT><A HREF="http://en-US.www.mozilla.com/en-US/firefox/about/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" ID="rdf:#$52iCK1">About Us</A>
</DL><p>
<DT><H3 ADD_DATE="1177541020" LAST_MODIFIED="1177541047" ID="rdf:#$74Gpx2">test</H3>
<DT><H3 ADD_DATE="1177541020" LAST_MODIFIED="1177541050" ID="rdf:#$74Gpx2">test</H3>
<DD>folder test comment
<DL><p>
<DT><A HREF="http://test/post" ADD_DATE="1177375336" LAST_MODIFIED="1177375423" SHORTCUTURL="test" WEB_PANEL="true" POST_DATA="hidden1%3Dbar&amp;text1%3D%25s" LAST_CHARSET="ISO-8859-1" ID="rdf:#$pYFe7">test post keyword</A>

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

@ -196,7 +196,6 @@ function testCanonicalBookmarks(aFolder) {
toolbar.containerOpen = true;
do_check_eq(toolbar.childCount, 2);
// livemark
var livemark = toolbar.getChild(1);
// title
@ -216,6 +215,12 @@ function testCanonicalBookmarks(aFolder) {
var testFolder = rootNode.getChild(5);
do_check_eq(testFolder.type, testFolder.RESULT_TYPE_FOLDER);
do_check_eq(testFolder.title, "test");
// add date
do_check_eq(bmsvc.getItemDateAdded(testFolder.itemId)/1000000, 1177541020);
// last modified
do_check_eq(bmsvc.getItemLastModified(testFolder.itemId)/1000000, 1177541050);
testFolder = testFolder.QueryInterface(Ci.nsINavHistoryQueryResultNode);
do_check_eq(testFolder.hasChildren, true);
// folder description
@ -243,7 +248,11 @@ function testCanonicalBookmarks(aFolder) {
do_check_true(annosvc.itemHasAnnotation(testBookmark1.itemId,
LOAD_IN_SIDEBAR_ANNO));
// add date
do_check_eq(testBookmark1.dateAdded/1000000, 1177375336);
// last modified
do_check_eq(testBookmark1.lastModified/1000000, 1177375423);
// post data
var pageURI = iosvc.newURI(testBookmark1.uri, "", null);
do_check_true(annosvc.pageHasAnnotation(pageURI, POST_DATA_ANNO));

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

@ -207,6 +207,10 @@
"Keyword">
<!ENTITY col.description.label
"Description">
<!ENTITY col.dateadded.label
"Added">
<!ENTITY col.lastmodified.label
"Last Modified">
<!ENTITY search.label
"Search:">

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

@ -170,7 +170,7 @@ interface nsINavBookmarkObserver : nsISupports
* folders. A URI in history can be contained in one or more such folders.
*/
[scriptable, uuid(d0dcc4b9-3f41-4489-aec5-117f8ed26a68)]
[scriptable, uuid(5e44a4e2-5db6-412a-b153-c732c9c62fd5)]
interface nsINavBookmarksService : nsISupports
{
/**
@ -354,6 +354,24 @@ interface nsINavBookmarksService : nsISupports
*/
AString getItemTitle(in long long aItemId);
/**
* Set the date added time for an item.
*/
void setItemDateAdded(in long long aItemId, in PRTime aDateAdded);
/**
* Get the date added time for an item.
*/
PRTime getItemDateAdded(in long long aItemId);
/**
* Set the last modified time for an item.
*/
void setItemLastModified(in long long aItemId, in PRTime aLastModified);
/**
* Get the last modified time for an item.
*/
PRTime getItemLastModified(in long long aItemId);
/**
* Get the URI for a bookmark item.
*/

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

@ -49,7 +49,7 @@ interface nsINavHistoryResult;
interface nsITreeColumn;
interface nsIWritablePropertyBag;
[scriptable, uuid(2cce631e-d7dd-4162-a05b-e8ecfbc34367)]
[scriptable, uuid(ff6f0168-f3f6-4f3a-9dfb-810a8eb4e545)]
interface nsINavHistoryResultNode : nsISupports
{
/**
@ -163,6 +163,18 @@ interface nsINavHistoryResultNode : nsISupports
* set to -1.
*/
readonly attribute PRInt64 itemId;
/**
* If the node is an item (bookmark, folder or a separator) this value is the
* time that the item was created. For other nodes, this value is 0.
*/
readonly attribute PRTime dateAdded;
/**
* If the node is an item (bookmark, folder or a separator) this value is the
* time that the item was last modified. For other nodes, this value is 0.
*/
readonly attribute PRTime lastModified;
};
@ -990,8 +1002,13 @@ interface nsINavHistoryQueryOptions : nsISupports
const unsigned short SORT_BY_VISITCOUNT_DESCENDING = 8;
const unsigned short SORT_BY_KEYWORD_ASCENDING = 9;
const unsigned short SORT_BY_KEYWORD_DESCENDING = 10;
const unsigned short SORT_BY_ANNOTATION_ASCENDING = 11;
const unsigned short SORT_BY_ANNOTATION_DESCENDING = 12;
const unsigned short SORT_BY_DATEADDED_ASCENDING = 11;
const unsigned short SORT_BY_DATEADDED_DESCENDING = 12;
const unsigned short SORT_BY_LASTMODIFIED_ASCENDING = 13;
const unsigned short SORT_BY_LASTMODIFIED_DESCENDING = 14;
const unsigned short SORT_BY_ANNOTATION_ASCENDING = 15;
const unsigned short SORT_BY_ANNOTATION_DESCENDING = 16;
/**
* "URI" results, one for each URI visited in the range. Individual result

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

@ -56,9 +56,9 @@ const PRInt32 nsNavBookmarks::kFindBookmarksIndex_Position = 4;
const PRInt32 nsNavBookmarks::kFindBookmarksIndex_Title = 5;
// These columns sit to the right of the kGetInfoIndex_* columns.
const PRInt32 nsNavBookmarks::kGetChildrenIndex_Position = 9;
const PRInt32 nsNavBookmarks::kGetChildrenIndex_Type = 10;
const PRInt32 nsNavBookmarks::kGetChildrenIndex_ForeignKey = 11;
const PRInt32 nsNavBookmarks::kGetChildrenIndex_Position = 11;
const PRInt32 nsNavBookmarks::kGetChildrenIndex_Type = 12;
const PRInt32 nsNavBookmarks::kGetChildrenIndex_ForeignKey = 13;
const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_ID = 0;
const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_URI = 1;
@ -68,6 +68,8 @@ const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_PlaceID = 4;
const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Parent = 5;
const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Type = 6;
const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_FolderType = 7;
const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_DateAdded = 8;
const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_LastModified = 9;
nsNavBookmarks* nsNavBookmarks::sInstance = nsnull;
@ -144,7 +146,9 @@ nsNavBookmarks::Init()
NS_LITERAL_CSTRING("SELECT h.id, h.url, a.title, "
"h.rev_host, h.visit_count, "
"(SELECT MAX(visit_date) FROM moz_historyvisits WHERE place_id = h.id), "
"f.url, null, a.id, a.position, a.type, a.fk "
"f.url, null, a.id, "
"a.dateAdded, a.lastModified, "
"a.position, a.type, a.fk "
"FROM moz_bookmarks a "
"LEFT JOIN moz_places h ON a.fk = h.id "
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
@ -171,7 +175,7 @@ nsNavBookmarks::Init()
// get bookmark/folder/separator properties
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT b.id, (SELECT url from moz_places WHERE id = b.fk), b.title, b.position, b.fk, b.parent, b.type, b.folder_type "
"SELECT b.id, (SELECT url from moz_places WHERE id = b.fk), b.title, b.position, b.fk, b.parent, b.type, b.folder_type, b.dateAdded, b.lastModified "
"FROM moz_bookmarks b "
"WHERE b.id = ?1"),
getter_AddRefs(mDBGetItemProperties));
@ -243,7 +247,6 @@ nsNavBookmarks::Init()
return NS_OK;
}
// nsNavBookmarks::InitTables
//
// All commands that initialize the schema of the DB go in here. This is
@ -267,7 +270,9 @@ nsNavBookmarks::InitTables(mozIStorageConnection* aDBConn)
"position INTEGER, "
"title LONGVARCHAR, "
"keyword_id INTEGER, "
"folder_type TEXT)"));
"folder_type TEXT, "
"dateAdded INTEGER, "
"lastModified INTEGER)"));
NS_ENSURE_SUCCESS(rv, rv);
// this index will make it faster to determine if a given item is
@ -869,7 +874,7 @@ nsNavBookmarks::InsertItem(PRInt64 aFolder, nsIURI *aItem, PRInt32 aIndex, PRInt
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString buffer;
buffer.AssignLiteral("INSERT INTO moz_bookmarks (fk, type, parent, position) VALUES (");
buffer.AssignLiteral("INSERT INTO moz_bookmarks (fk, type, parent, position, dateAdded) VALUES (");
buffer.AppendInt(childID);
buffer.AppendLiteral(", ");
buffer.AppendInt(TYPE_BOOKMARK);
@ -877,6 +882,8 @@ nsNavBookmarks::InsertItem(PRInt64 aFolder, nsIURI *aItem, PRInt32 aIndex, PRInt
buffer.AppendInt(aFolder);
buffer.AppendLiteral(", ");
buffer.AppendInt(index);
buffer.AppendLiteral(", ");
buffer.AppendInt(PR_Now());
buffer.AppendLiteral(")");
rv = dbConn->ExecuteSimpleSQL(buffer);
@ -995,16 +1002,16 @@ nsNavBookmarks::CreateFolderWithID(PRInt64 aFolder, PRInt64 aParent,
nsCOMPtr<mozIStorageStatement> statement;
if (aFolder == -1) {
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks (title, type, parent, position, folder_type) VALUES (?1, ?2, ?3, ?4, null)"),
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks (title, type, parent, position, folder_type, dateAdded) VALUES (?1, ?2, ?3, ?4, null, ?5)"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks (id, title, type, parent, position, folder_type) VALUES (?5, ?1, ?2, ?3, ?4, null)"),
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks (id, title, type, parent, position, folder_type, dateAdded) VALUES (?6, ?1, ?2, ?3, ?4, null, ?5)"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(4, aFolder);
rv = statement->BindInt64Parameter(5, aFolder);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1016,6 +1023,8 @@ nsNavBookmarks::CreateFolderWithID(PRInt64 aFolder, PRInt64 aParent,
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt32Parameter(3, index);
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(4, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
@ -1094,7 +1103,7 @@ nsNavBookmarks::InsertSeparator(PRInt64 aParent, PRInt32 aIndex,
nsCOMPtr<mozIStorageStatement> statement;
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks "
"(type, parent, position) VALUES (?1, ?2, ?3)"),
"(type, parent, position, dateAdded) VALUES (?1, ?2, ?3, ?4)"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
@ -1104,6 +1113,8 @@ nsNavBookmarks::InsertSeparator(PRInt64 aParent, PRInt32 aIndex,
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt32Parameter(2, index);
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(3, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
@ -1522,6 +1533,98 @@ nsNavBookmarks::GetChildFolder(PRInt64 aFolder, const nsAString& aSubFolder,
return statement->GetInt64(0, _result);
}
NS_IMETHODIMP
nsNavBookmarks::SetItemDateAdded(PRInt64 aItemId, PRTime aDateAdded)
{
mozIStorageConnection *dbConn = DBConn();
mozStorageTransaction transaction(dbConn, PR_FALSE);
nsCOMPtr<mozIStorageStatement> statement;
nsresult rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET dateAdded = ?1 WHERE id = ?2"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(0, aDateAdded);
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(1, aItemId);
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
// note, we are not notifying the observers
// that the item has changed.
return NS_OK;
}
NS_IMETHODIMP
nsNavBookmarks::GetItemDateAdded(PRInt64 aItemId, PRTime *aDateAdded)
{
NS_ENSURE_ARG_POINTER(aDateAdded);
mozStorageStatementScoper scope(mDBGetItemProperties);
nsresult rv = mDBGetItemProperties->BindInt64Parameter(0, aItemId);
NS_ENSURE_SUCCESS(rv, rv);
PRBool results;
rv = mDBGetItemProperties->ExecuteStep(&results);
NS_ENSURE_SUCCESS(rv, rv);
if (!results)
return NS_ERROR_INVALID_ARG; // invalid item id
return mDBGetItemProperties->GetInt64(kGetItemPropertiesIndex_DateAdded, aDateAdded);
}
NS_IMETHODIMP
nsNavBookmarks::SetItemLastModified(PRInt64 aItemId, PRTime aLastModified)
{
mozIStorageConnection *dbConn = DBConn();
mozStorageTransaction transaction(dbConn, PR_FALSE);
nsCOMPtr<mozIStorageStatement> statement;
nsresult rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET lastModified = ?1 WHERE id = ?2"),
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(0, aLastModified);
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(1, aItemId);
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
// note, we are not notifying the observers
// that the item has changed.
return NS_OK;
}
NS_IMETHODIMP
nsNavBookmarks::GetItemLastModified(PRInt64 aItemId, PRTime *aLastModified)
{
NS_ENSURE_ARG_POINTER(aLastModified);
mozStorageStatementScoper scope(mDBGetItemProperties);
nsresult rv = mDBGetItemProperties->BindInt64Parameter(0, aItemId);
NS_ENSURE_SUCCESS(rv, rv);
PRBool results;
rv = mDBGetItemProperties->ExecuteStep(&results);
NS_ENSURE_SUCCESS(rv, rv);
if (!results)
return NS_ERROR_INVALID_ARG; // invalid item id
return mDBGetItemProperties->GetInt64(kGetItemPropertiesIndex_LastModified, aLastModified);
}
NS_IMETHODIMP
nsNavBookmarks::SetItemTitle(PRInt64 aItemId, const nsAString &aTitle)
{
@ -1543,10 +1646,12 @@ nsNavBookmarks::SetItemTitle(PRInt64 aItemId, const nsAString &aTitle)
rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
rv = SetItemLastModified(aItemId, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, NS_LITERAL_CSTRING("title"),
PR_FALSE, NS_ConvertUTF16toUTF8(aTitle)));
return NS_OK;
}
@ -1904,6 +2009,9 @@ nsNavBookmarks::ChangeBookmarkURI(PRInt64 aBookmarkId, nsIURI *aNewURI)
rv = aNewURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
rv = SetItemLastModified(aBookmarkId, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
// Pass the new URI to OnItemChanged.
ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver,
OnItemChanged(aBookmarkId, NS_LITERAL_CSTRING("uri"), PR_FALSE, spec))
@ -2100,11 +2208,15 @@ nsNavBookmarks::SetKeywordForBookmark(PRInt64 aBookmarkId, const nsAString& aKey
rv = updateKeywordStmnt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
transaction.Commit();
rv = SetItemLastModified(aBookmarkId, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
// Pass the new keyword to OnItemChanged.
ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver,
OnItemChanged(aBookmarkId, NS_LITERAL_CSTRING("keyword"),
PR_FALSE, NS_ConvertUTF16toUTF8(aKeyword)))
return NS_OK;
}
@ -2354,8 +2466,12 @@ nsNavBookmarks::OnPageAnnotationSet(nsIURI* aPage, const nsACString& aName)
NS_IMETHODIMP
nsNavBookmarks::OnItemAnnotationSet(PRInt64 aItemId, const nsACString& aName)
{
nsresult rv = SetItemLastModified(aItemId, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString()));
return NS_OK;
}
@ -2368,8 +2484,12 @@ nsNavBookmarks::OnPageAnnotationRemoved(nsIURI* aPage, const nsACString& aName)
NS_IMETHODIMP
nsNavBookmarks::OnItemAnnotationRemoved(PRInt64 aItemId, const nsACString& aName)
{
{
nsresult rv = SetItemLastModified(aItemId, PR_Now());
NS_ENSURE_SUCCESS(rv, rv);
ENUMERATE_WEAKARRAY(mObservers, nsINavBookmarkObserver,
OnItemChanged(aItemId, aName, PR_TRUE, EmptyCString()));
return NS_OK;
}

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

@ -190,6 +190,8 @@ private:
static const PRInt32 kGetItemPropertiesIndex_Parent;
static const PRInt32 kGetItemPropertiesIndex_Type;
static const PRInt32 kGetItemPropertiesIndex_FolderType;
static const PRInt32 kGetItemPropertiesIndex_DateAdded;
static const PRInt32 kGetItemPropertiesIndex_LastModified;
nsCOMPtr<mozIStorageStatement> mDBGetRedirectDestinations;

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

@ -208,6 +208,8 @@ const PRInt32 nsNavHistory::kGetInfoIndex_VisitDate = 5;
const PRInt32 nsNavHistory::kGetInfoIndex_FaviconURL = 6;
const PRInt32 nsNavHistory::kGetInfoIndex_SessionId = 7;
const PRInt32 nsNavHistory::kGetInfoIndex_ItemId = 8;
const PRInt32 nsNavHistory::kGetInfoIndex_ItemDateAdded = 9;
const PRInt32 nsNavHistory::kGetInfoIndex_ItemLastModified = 10;
const PRInt32 nsNavHistory::kAutoCompleteIndex_URL = 0;
const PRInt32 nsNavHistory::kAutoCompleteIndex_Title = 1;
@ -385,7 +387,7 @@ nsNavHistory::Init()
//
#define PLACES_SCHEMA_VERSION 4
#define PLACES_SCHEMA_VERSION 5
nsresult
nsNavHistory::InitDB(PRBool *aDoImport)
@ -488,13 +490,13 @@ nsNavHistory::InitDB(PRBool *aDoImport)
NS_ENSURE_SUCCESS(rv, rv);
}
// Migrate bookmarks tables up to V4
if (DBSchemaVersion < 4) {
// Migrate bookmarks tables up to V5
if (DBSchemaVersion < 5) {
rv = ForceMigrateBookmarksDB(mDBConn);
NS_ENSURE_SUCCESS(rv, rv);
}
// XXX Upgrades >V4 must add migration code here.
// XXX Upgrades >V5 must add migration code here.
} else {
// Downgrading
@ -502,9 +504,9 @@ nsNavHistory::InitDB(PRBool *aDoImport)
// XXX Need to prompt user or otherwise notify of
// potential dataloss when downgrading.
// XXX Downgrades from >V4 must add migration code here.
// XXX Downgrades from >V5 must add migration code here.
// Downgrade v1,2,4
// Downgrade v1,2,4,5
// V3 had no backwards incompatible changes.
if (DBSchemaVersion > 2) {
// perform downgrade to v2
@ -780,7 +782,7 @@ nsNavHistory::InitStatements()
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT b.fk, h.url, b.title, h.rev_host, h.visit_count, "
"(SELECT MAX(visit_date) FROM moz_historyvisits WHERE place_id = b.fk), "
"f.url, null, null "
"f.url, null, null, b.dateAdded, b.lastModified "
"FROM moz_bookmarks b "
"JOIN moz_places h ON b.fk = h.id "
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
@ -2067,7 +2069,7 @@ nsNavHistory::GetQueryResults(const nsCOMArray<nsNavHistoryQuery>& aQueries,
queryString = NS_LITERAL_CSTRING(
"SELECT b.fk, h.url, b.title, h.rev_host, h.visit_count, "
"(SELECT MAX(visit_date) FROM moz_historyvisits WHERE place_id = b.fk), "
"f.url, null, b.id "
"f.url, null, b.id, b.dateAdded, b.lastModified "
"FROM moz_bookmarks b "
"JOIN moz_places h ON b.fk = h.id "
"LEFT OUTER JOIN moz_historyvisits v ON b.fk = v.place_id "
@ -2133,13 +2135,13 @@ nsNavHistory::GetQueryResults(const nsCOMArray<nsNavHistoryQuery>& aQueries,
// a sort by date here (see the IDL definition for maxResults). We'll
// still do the official sort by title later.
if (aOptions->MaxResults() > 0)
queryString += NS_LITERAL_CSTRING(" ORDER BY 6 DESC"); // v.vist_date
queryString += NS_LITERAL_CSTRING(" ORDER BY 6 DESC"); // v.visit_date
break;
case nsINavHistoryQueryOptions::SORT_BY_DATE_ASCENDING:
queryString += NS_LITERAL_CSTRING(" ORDER BY 6 ASC"); // v.vist_date
queryString += NS_LITERAL_CSTRING(" ORDER BY 6 ASC"); // v.visit_date
break;
case nsINavHistoryQueryOptions::SORT_BY_DATE_DESCENDING:
queryString += NS_LITERAL_CSTRING(" ORDER BY 6 DESC"); // v.vist_date
queryString += NS_LITERAL_CSTRING(" ORDER BY 6 DESC"); // v.visit_date
break;
case nsINavHistoryQueryOptions::SORT_BY_URI_ASCENDING:
queryString += NS_LITERAL_CSTRING(" ORDER BY 2 ASC"); // h.url
@ -3931,6 +3933,8 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
if (NS_SUCCEEDED(aRow->GetIsNull(kGetInfoIndex_ItemId, &isNull)) &&
!isNull) {
(*aResult)->mItemId = aRow->AsInt64(kGetInfoIndex_ItemId);
(*aResult)->mDateAdded = aRow->AsInt64(kGetInfoIndex_ItemDateAdded);
(*aResult)->mLastModified = aRow->AsInt64(kGetInfoIndex_ItemLastModified);
}
NS_ADDREF(*aResult);
return NS_OK;

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

@ -221,6 +221,8 @@ public:
static const PRInt32 kGetInfoIndex_RevHost;
static const PRInt32 kGetInfoIndex_VisitCount;
static const PRInt32 kGetInfoIndex_ItemId;
static const PRInt32 kGetInfoIndex_ItemDateAdded;
static const PRInt32 kGetInfoIndex_ItemLastModified;
// select a history row by URL, with visit date info (extra work)
mozIStorageStatement* DBGetURLPageInfoFull()

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

@ -116,6 +116,8 @@ nsNavHistoryResultNode::nsNavHistoryResultNode(
mFaviconURI(aIconURI),
mBookmarkIndex(-1),
mItemId(-1),
mDateAdded(0),
mLastModified(0),
mIndentLevel(-1),
mViewIndex(-1)
{
@ -595,6 +597,14 @@ nsNavHistoryContainerResultNode::GetSortingComparator(PRUint16 aSortType)
return &SortComparison_AnnotationLess;
case nsINavHistoryQueryOptions::SORT_BY_ANNOTATION_DESCENDING:
return &SortComparison_AnnotationGreater;
case nsINavHistoryQueryOptions::SORT_BY_DATEADDED_ASCENDING:
return &SortComparison_DateAddedLess;
case nsINavHistoryQueryOptions::SORT_BY_DATEADDED_DESCENDING:
return &SortComparison_DateAddedGreater;
case nsINavHistoryQueryOptions::SORT_BY_LASTMODIFIED_ASCENDING:
return &SortComparison_LastModifiedLess;
case nsINavHistoryQueryOptions::SORT_BY_LASTMODIFIED_DESCENDING:
return &SortComparison_LastModifiedGreater;
default:
NS_NOTREACHED("Bad sorting type");
return nsnull;
@ -789,6 +799,48 @@ PRInt32 PR_CALLBACK nsNavHistoryContainerResultNode::SortComparison_DateGreater(
return -nsNavHistoryContainerResultNode::SortComparison_DateLess(a, b, closure);
}
// nsNavHistoryContainerResultNode::SortComparison_DateAdded*
//
PRInt32 PR_CALLBACK nsNavHistoryContainerResultNode::SortComparison_DateAddedLess(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure)
{
PRInt32 value = ComparePRTime(a->mDateAdded, b->mDateAdded);
if (value == 0) {
value = SortComparison_StringLess(NS_ConvertUTF8toUTF16(a->mTitle),
NS_ConvertUTF8toUTF16(b->mTitle));
if (value == 0)
value = nsNavHistoryContainerResultNode::SortComparison_Bookmark(a, b, closure);
}
return value;
}
PRInt32 PR_CALLBACK nsNavHistoryContainerResultNode::SortComparison_DateAddedGreater(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure)
{
return -nsNavHistoryContainerResultNode::SortComparison_DateAddedLess(a, b, closure);
}
// nsNavHistoryContainerResultNode::SortComparison_LastModified*
//
PRInt32 PR_CALLBACK nsNavHistoryContainerResultNode::SortComparison_LastModifiedLess(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure)
{
PRInt32 value = ComparePRTime(a->mLastModified, b->mLastModified);
if (value == 0) {
value = SortComparison_StringLess(NS_ConvertUTF8toUTF16(a->mTitle),
NS_ConvertUTF8toUTF16(b->mTitle));
if (value == 0)
value = nsNavHistoryContainerResultNode::SortComparison_Bookmark(a, b, closure);
}
return value;
}
PRInt32 PR_CALLBACK nsNavHistoryContainerResultNode::SortComparison_LastModifiedGreater(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure)
{
return -nsNavHistoryContainerResultNode::SortComparison_LastModifiedLess(a, b, closure);
}
// nsNavHistoryContainerResultNode::SortComparison_URI*
//
@ -2515,6 +2567,7 @@ nsNavHistoryQueryResultNode::OnItemChanged(PRInt64 aItemId,
NS_NOTREACHED("Everything observers should not get OnItemChanged, but should get the corresponding history notifications instead");
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnItemVisited(PRInt64 aItemId,
PRInt64 aVisitId, PRTime aTime)
@ -3121,6 +3174,27 @@ nsNavHistoryFolderResultNode::OnItemChanged(PRInt64 aItemId,
NS_NOTREACHED("Unknown bookmark property changing.");
}
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_UNEXPECTED);
PRTime lastModified;
nsresult rv = bookmarks->GetItemLastModified(aItemId, &lastModified);
if (NS_SUCCEEDED(rv)) {
node->mLastModified = lastModified;
}
else {
node->mLastModified = 0;
}
PRTime dateAdded;
rv = bookmarks->GetItemDateAdded(aItemId, &dateAdded);
if (NS_SUCCEEDED(rv)) {
node->mDateAdded = dateAdded;
}
else {
node->mDateAdded = 0;
}
nsNavHistoryResult* result = GetResult();
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
@ -3144,7 +3218,6 @@ nsNavHistoryFolderResultNode::OnItemChanged(PRInt64 aItemId,
return NS_OK;
}
// nsNavHistoryFolderResultNode::OnItemVisited (nsINavBookmarkObserver)
//
// Update visit count and last visit time and refresh.
@ -3738,7 +3811,6 @@ nsNavHistoryResult::OnItemChanged(PRInt64 aItemId,
return NS_OK;
}
// nsNavHistoryResult::OnItemVisited (nsINavBookmarkObserver)
NS_IMETHODIMP

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

@ -225,7 +225,12 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult, NS_NAVHISTORYRESULT_IID)
NS_IMETHOD GetBookmarkIndex(PRInt32* aIndex) \
{ *aIndex = mBookmarkIndex; return NS_OK; } \
NS_IMETHOD GetItemId(PRInt64* aId) \
{ *aId= mItemId; return NS_OK; }
{ *aId= mItemId; return NS_OK; } \
NS_IMETHOD GetDateAdded(PRTime* aDateAdded) \
{ *aDateAdded = mDateAdded; return NS_OK; } \
NS_IMETHOD GetLastModified(PRTime* aLastModified) \
{ *aLastModified = mLastModified; return NS_OK; }
// This is used by the base classes instead of
// NS_FORWARD_NSINAVHISTORYRESULTNODE(nsNavHistoryResultNode) because they
@ -365,6 +370,8 @@ public:
nsCString mFaviconURI;
PRInt32 mBookmarkIndex;
PRInt64 mItemId;
PRTime mDateAdded;
PRTime mLastModified;
// The indent level of this node. The root node will have a value of -1. The
// root's children will have a value of 0, and so on.
@ -578,6 +585,14 @@ public:
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure);
PR_STATIC_CALLBACK(int) SortComparison_AnnotationGreater(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure);
PR_STATIC_CALLBACK(int) SortComparison_DateAddedLess(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure);
PR_STATIC_CALLBACK(int) SortComparison_DateAddedGreater(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure);
PR_STATIC_CALLBACK(int) SortComparison_LastModifiedLess(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure);
PR_STATIC_CALLBACK(int) SortComparison_LastModifiedGreater(
nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure);
// finding children: THESE DO NOT ADDREF
nsNavHistoryResultNode* FindChildURI(nsIURI* aURI, PRUint32* aNodeIndex)

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

@ -136,18 +136,44 @@ function run_test() {
do_check_eq(bmsvc.getItemType(testRoot), bmsvc.TYPE_FOLDER);
// insert a bookmark
// the time before we insert, in microseconds
var beforeInsert = Date.now() * 1000;
do_check_true(beforeInsert > 0);
var newId = bmsvc.insertItem(testRoot, uri("http://google.com/"), bmsvc.DEFAULT_INDEX);
do_check_eq(observer._itemAddedId, newId);
do_check_eq(observer._itemAddedParent, testRoot);
do_check_eq(observer._itemAddedIndex, testStartIndex);
do_check_eq(bmsvc.getBookmarkURI(newId).spec, "http://google.com/");
var dateAdded = bmsvc.getItemDateAdded(newId);
// dateAdded can equal beforeInsert
do_check_true(dateAdded >= beforeInsert);
// after just inserting, modified should not be set
var lastModified = bmsvc.getItemLastModified(newId);
do_check_eq(lastModified, 0);
// the time before we set the title, in microseconds
var beforeSetTitle = Date.now() * 1000;
do_check_true(beforeSetTitle >= beforeInsert);
// set bookmark title
bmsvc.setItemTitle(newId, "Google");
do_check_eq(observer._itemChangedId, newId);
do_check_eq(observer._itemChangedProperty, "title");
do_check_eq(observer._itemChangedValue, "Google");
// check that dateAdded hasn't changed
var dateAdded2 = bmsvc.getItemDateAdded(newId);
do_check_eq(dateAdded2, dateAdded);
// check lastModified after we set the title
var lastModified2 = bmsvc.getItemLastModified(newId);
do_check_true(lastModified2 > lastModified);
do_check_true(lastModified2 >= dateAdded);
do_check_true(lastModified2 >= beforeSetTitle);
// get item title
var title = bmsvc.getItemTitle(newId);
do_check_eq(title, "Google");
@ -298,14 +324,24 @@ function run_test() {
var tmpFolder = bmsvc.createFolder(testRoot, "tmp", 2);
do_check_eq(bmsvc.getItemIndex(tmpFolder), 2);
// test setKeywordForURI
// test setKeywordForBookmark
var kwTestItemId = bmsvc.insertItem(testRoot, uri("http://keywordtest.com"), bmsvc.DEFAULT_INDEX);
try {
var dateAdded = bmsvc.getItemDateAdded(kwTestItemId);
// after just inserting, modified should not be set
var lastModified = bmsvc.getItemLastModified(kwTestItemId);
do_check_eq(lastModified, 0);
bmsvc.setKeywordForBookmark(kwTestItemId, "bar");
var lastModified2 = bmsvc.getItemLastModified(kwTestItemId);
do_check_true(lastModified2 > lastModified);
do_check_true(lastModified2 >= dateAdded);
} catch(ex) {
do_throw("setKeywordForBookmark: " + ex);
}
var lastModified3 = bmsvc.getItemLastModified(kwTestItemId);
// test getKeywordForBookmark
var k = bmsvc.getKeywordForBookmark(kwTestItemId);
do_check_eq("bar", k);
@ -411,7 +447,18 @@ function run_test() {
// test change bookmark uri
var newId10 = bmsvc.insertItem(testRoot, uri("http://foo10.com/"), bmsvc.DEFAULT_INDEX);
var dateAdded = bmsvc.getItemDateAdded(newId10);
// after just inserting, modified should not be set
var lastModified = bmsvc.getItemLastModified(newId10);
do_check_eq(lastModified, 0);
bmsvc.changeBookmarkURI(newId10, uri("http://foo11.com/"));
// check that lastModified is set after we change the bookmark uri
var lastModified2 = bmsvc.getItemLastModified(newId10);
do_check_true(lastModified2 > lastModified);
do_check_true(lastModified2 >= dateAdded);
do_check_eq(observer._itemChangedId, newId10);
do_check_eq(observer._itemChangedProperty, "uri");
do_check_eq(observer._itemChangedValue, "http://foo11.com/");
@ -486,6 +533,76 @@ function run_test() {
do_throw("bookmarks query: " + ex);
}
// test dateAdded and lastModified properties
// for a search query
try {
var options = histsvc.getNewQueryOptions();
options.excludeQueries = 1;
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
var query = histsvc.getNewQuery();
query.onlyBookmarked = true;
query.searchTerms = "ZZZXXXYYY";
var result = histsvc.executeQuery(query, options);
var rootNode = result.root;
rootNode.containerOpen = true;
var cc = rootNode.childCount;
do_check_eq(cc, 1);
var node = rootNode.getChild(0);
do_check_eq(typeof node.dateAdded, "number");
do_check_true(node.dateAdded > 0);
do_check_eq(typeof node.lastModified, "number");
do_check_true(node.lastModified > 0);
rootNode.containerOpen = false;
}
catch(ex) {
do_throw("bookmarks query: " + ex);
}
// test dateAdded and lastModified properties
// for a folder query
try {
var options = histsvc.getNewQueryOptions();
options.setGroupingMode([Ci.nsINavHistoryQueryOptions.GROUP_BY_FOLDER], 1);
var query = histsvc.getNewQuery();
query.setFolders([testRoot], 1);
var result = histsvc.executeQuery(query, options);
var rootNode = result.root;
rootNode.containerOpen = true;
var cc = rootNode.childCount;
for (var i = 0; i < cc; i++) {
var node = rootNode.getChild(i);
if (node.type == node.RESULT_TYPE_URI) {
do_check_eq(typeof node.dateAdded, "number");
do_check_true(node.dateAdded > 0);
do_check_eq(typeof node.lastModified, "number");
do_check_true(node.lastModified > 0);
break;
}
}
rootNode.containerOpen = false;
}
catch(ex) {
do_throw("bookmarks query: " + ex);
}
// check setItemLastModified() and setItemDateAdded()
var newId14 = bmsvc.insertItem(testRoot, uri("http://bar.tld/"), bmsvc.DEFAULT_INDEX);
var dateAdded = bmsvc.getItemDateAdded(newId14);
var lastModified = bmsvc.getItemLastModified(newId14);
do_check_eq(lastModified, 0);
do_check_true(dateAdded > lastModified);
bmsvc.setItemLastModified(newId14, 1234);
var fakeLastModified = bmsvc.getItemLastModified(newId14);
do_check_eq(fakeLastModified, 1234);
bmsvc.setItemDateAdded(newId14, 4321);
var fakeDateAdded = bmsvc.getItemDateAdded(newId14);
do_check_eq(fakeDateAdded, 4321);
// ensure that removing an item removes its annotations
do_check_true(annosvc.itemHasAnnotation(newId3, "test-annotation"));
bmsvc.removeItem(newId3);
@ -500,8 +617,30 @@ function run_test() {
}
function testSimpleFolderResult() {
// the time before we create a folder, in microseconds
var beforeCreate = Date.now() * 1000;
do_check_true(beforeCreate > 0);
// create a folder
var parent = bmsvc.createFolder(root, "test", bmsvc.DEFAULT_INDEX);
var dateCreated = bmsvc.getItemDateAdded(parent);
do_check_true(dateCreated > 0);
// dateCreated can equal beforeCreate
do_check_true(dateCreated >= beforeCreate);
// the time before we insert, in microseconds
var beforeInsert = Date.now() * 1000;
do_check_true(beforeInsert > 0);
// insert a separator
var sep = bmsvc.insertSeparator(parent, bmsvc.DEFAULT_INDEX);
var dateAdded = bmsvc.getItemDateAdded(sep);
do_check_true(dateAdded > 0);
// dateAdded can equal beforeInsert
do_check_true(dateAdded >= beforeInsert);
var item = bmsvc.insertItem(parent, uri("about:blank"), bmsvc.DEFAULT_INDEX);
bmsvc.setItemTitle(item, "test bookmark");
var folder = bmsvc.createFolder(parent, "test folder", bmsvc.DEFAULT_INDEX);

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

@ -115,13 +115,28 @@ function run_test() {
// string item-annotation
try {
var lastModified = bmsvc.getItemLastModified(testItemId);
// verify that lastModified is 0 before we set the annotation
do_check_eq(lastModified, 0);
annosvc.setItemAnnotationString(testItemId, testAnnoName, testAnnoVal, 0, 0);
var lastModified2 = bmsvc.getItemLastModified(testItemId);
// verify that setting the annotation updates the last modified time
do_check_true(lastModified2 > lastModified);
} catch(ex) {
do_throw("unable to add item annotation");
}
do_check_eq(annoObserver.ITEM_lastSet_Id, testItemId);
do_check_eq(annoObserver.ITEM_lastSet_AnnoName, testAnnoName);
try {
var lastModified = bmsvc.getItemLastModified(testItemId);
var annoVal = annosvc.getItemAnnotationString(testItemId, testAnnoName);
// verify the anno value
do_check_eq(testAnnoVal, annoVal);
} catch(ex) {
do_throw("unable to get item annotation");
}
// test getPagesWithAnnotation
var uri2 = uri("http://www.tests.tld");
annosvc.setPageAnnotationString(uri2, testAnnoName, testAnnoVal, 0, 0);
@ -318,7 +333,14 @@ function run_test() {
// test annotation removal
annosvc.removePageAnnotation(testURI, int32Key);
annosvc.setItemAnnotationString(testItemId, testAnnoName, testAnnoVal, 0, 0);
// verify that removing an annotation updates the last modified date
var lastModified3 = bmsvc.getItemLastModified(testItemId);
annosvc.removeItemAnnotation(testItemId, int32Key);
var lastModified4 = bmsvc.getItemLastModified(testItemId);
do_check_true(lastModified4 >= lastModified3);
do_check_eq(annoObserver.PAGE_lastRemoved_URI, testURI.spec);
do_check_eq(annoObserver.PAGE_lastRemoved_AnnoName, int32Key);
do_check_eq(annoObserver.ITEM_lastRemoved_Id, testItemId);

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

@ -145,6 +145,9 @@ function run_test() {
// id1 precedes id2 per title-descending fallback
checkOrder(id3, id1, id2);
// XXXtodo: test dateAdded sort
// XXXtodo: test lastModified sort
// test live update
annosvc.setItemAnnotationString(id1, "testAnno", "c", 0, 0);
checkOrder(id1, id3, id2);