Bug 205378 - Meta bug for changes in bookmarks sorting code
r=jag, sr=sspitzer, a=sspitzer,asa

The CloneResource() has been back ported from Firebird, originally
implemented by Pierre Chanial.
This commit is contained in:
varga%netscape.com 2003-05-23 12:03:40 +00:00
Родитель beaec6185a
Коммит 1734eec58f
86 изменённых файлов: 2111 добавлений и 2251 удалений

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

@ -853,8 +853,8 @@ var BookmarksToolbarRDFObserver =
},
onChange: function (aDataSource, aSource, aProperty, aOldTarget, aNewTarget) {},
onMove: function (aDataSource, aOldSource, aNewSource, aProperty, aTarget) {},
beginUpdateBatch: function (aDataSource) {},
endUpdateBatch: function (aDataSource) {},
onBeginUpdateBatch: function (aDataSource) {},
onEndUpdateBatch: function (aDataSource) {},
_overflowTimerInEffect: false,
setOverflowTimeout: function (aSource, aProperty)

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

@ -609,13 +609,11 @@
default:
this.mOuter.saveSelection();
// Notify the datasource that we're about to begin a batch operation
//var observer = this.mOuter.tree.builder.QueryInterface(Components.interfaces.nsIRDFObserver);
//observer.beginUpdateBatch(this.db);
//BMDS.beginUpdateBatch();
BookmarksController.doCommand(aCommand, selection, target);
//observer.endUpdateBatch(this.db);
//BMDS.endUpdateBatch();
//var firstVisibleRow = this.mOuter.treeBoxObject.getFirstVisibleRow()
//this.mOuter.treeBoxObject.selection.currentIndex=-1;
//this.mOuter.tree.builder.rebuild();
// temporary hack: for an unknown reason, rebuilding cause a scroll to the bottom
// if the first visible row is not 0
//this.mOuter.treeBoxObject.scrollToRow(firstVisibleRow);
@ -678,8 +676,7 @@
//var firstVisibleRow = this.mOuter.treeBoxObject.getFirstVisibleRow()
this.mOuter.treeBoxObject.selection.selectEventsSuppressed = true;
// Notify the datasource that we're about to begin a batch operation
//var observer = this.mOuter.tree.builder.QueryInterface(Components.interfaces.nsIRDFObserver);
//observer.beginUpdateBatch(this.db);
//BMDS.beginUpdateBatch();
const kDSIID = Components.interfaces.nsIDragService;
const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
@ -687,9 +684,8 @@
BookmarksUtils.insertSelection("drag", selection, target);
else
BookmarksUtils.moveSelection ("drag", selection, target);
//observer.endUpdateBatch(this.db);
//BMDS.endUpdateBatch();
//this.mOuter.treeBoxObject.selection.currentIndex=-1;
//this.mOuter.treeBuilder.rebuild();
// temporary hack: for an unknown reason, rebuilding cause a scroll to the bottom
// if the first visible row is not 0
//this.mOuter.treeBoxObject.scrollToRow(firstVisibleRow);

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

@ -3395,9 +3395,9 @@ nsBookmarksService::ImportSystemBookmarks(nsIRDFResource* aParentFolder)
BookmarkParser parser;
parser.Init(ieFavoritesFile, mInner);
BeginUpdateBatch(this);
BeginUpdateBatch();
parser.Parse(aParentFolder, kNC_Bookmark);
EndUpdateBatch(this);
EndUpdateBatch();
#endif
return NS_OK;
@ -4526,9 +4526,9 @@ nsBookmarksService::ReadFavorites()
{
BookmarkParser parser;
parser.Init(ieFavoritesFile, mInner);
BeginUpdateBatch(this);
BeginUpdateBatch();
parser.Parse(kNC_IEFavoritesRoot, kNC_IEFavorite);
EndUpdateBatch(this);
EndUpdateBatch();
nsCOMPtr<nsIRDFLiteral> ieTitleLiteral;
rv = gRDF->GetLiteral(ieTitle.get(), getter_AddRefs(ieTitleLiteral));
@ -4703,9 +4703,9 @@ nsBookmarksService::LoadBookmarks()
parser.ParserFoundIEFavoritesRoot(&foundIERoot);
}
BeginUpdateBatch(this);
BeginUpdateBatch();
parser.Parse(kNC_BookmarksRoot, kNC_Bookmark);
EndUpdateBatch(this);
EndUpdateBatch();
mBookmarksAvailable = PR_TRUE;
PRBool foundPTFolder = PR_FALSE;
@ -5536,13 +5536,13 @@ nsBookmarksService::OnMove(nsIRDFDataSource* aDataSource,
}
NS_IMETHODIMP
nsBookmarksService::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
nsBookmarksService::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
if (mUpdateBatchNest++ == 0)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = 0; i < count; ++i) {
(void) mObservers[i]->BeginUpdateBatch(aDataSource);
(void) mObservers[i]->OnBeginUpdateBatch(this);
}
}
@ -5550,7 +5550,7 @@ nsBookmarksService::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
}
NS_IMETHODIMP
nsBookmarksService::EndUpdateBatch(nsIRDFDataSource* aDataSource)
nsBookmarksService::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
{
if (mUpdateBatchNest > 0)
{
@ -5561,7 +5561,7 @@ nsBookmarksService::EndUpdateBatch(nsIRDFDataSource* aDataSource)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = 0; i < count; ++i) {
(void) mObservers[i]->EndUpdateBatch(aDataSource);
(void) mObservers[i]->OnEndUpdateBatch(this);
}
}

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

@ -286,6 +286,14 @@ public:
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments);
NS_IMETHOD BeginUpdateBatch() {
return mInner->BeginUpdateBatch();
}
NS_IMETHOD EndUpdateBatch() {
return mInner->EndUpdateBatch();
}
// nsIRDFRemoteDataSource
NS_DECL_NSIRDFREMOTEDATASOURCE

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

@ -166,19 +166,13 @@ var downloadViewController = {
gDownloadManager.startBatchUpdate();
// Notify the datasource that we're about to begin a batch operation
var observer = gDownloadHistoryView.builder.QueryInterface(Components.interfaces.nsIRDFObserver);
var ds = gDownloadHistoryView.database;
observer.beginUpdateBatch(ds);
gDownloadManager.datasource.beginUpdateBatch();
for (i = 0; i <= selectedItems.length - 1; ++i) {
gDownloadManager.removeDownload(selectedItems[i].id);
}
gDownloadManager.datasource.endUpdateBatch();
gDownloadManager.endBatchUpdate();
observer.endUpdateBatch(ds);
var remote = gDownloadManager.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
remote.Flush();
gDownloadHistoryView.builder.rebuild();
var rowCount = gDownloadHistoryView.getRowCount();
if (selectedIndex > ( rowCount- 1))
selectedIndex = rowCount - 1;

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

@ -679,8 +679,12 @@ nsDownloadManager::StartBatchUpdate()
NS_IMETHODIMP
nsDownloadManager::EndBatchUpdate()
{
--mBatches;
return NS_OK;
nsresult rv = NS_OK;
if (--mBatches == 0) {
nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mDataSource);
rv = remote->Flush();
}
return rv;
}
NS_IMETHODIMP

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

@ -216,10 +216,6 @@ var PrivacyPanel = {
}
dlMgr.endBatchUpdate();
var rds = ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
if (rds)
rds.Flush();
return true;
},

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -287,6 +287,16 @@ nsChromeUIDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
return mComposite->DoCommand(aSources, aCommand, aArguments);
}
NS_IMETHODIMP
nsChromeUIDataSource::BeginUpdateBatch() {
return mComposite->BeginUpdateBatch();
}
NS_IMETHODIMP
nsChromeUIDataSource::EndUpdateBatch() {
return mComposite->EndUpdateBatch();
}
//////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
@ -299,7 +309,6 @@ nsChromeUIDataSource::OnAssert(nsIRDFDataSource* aDataSource,
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnAssert(this, aSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -313,7 +322,6 @@ nsChromeUIDataSource::OnUnassert(nsIRDFDataSource* aDataSource,
PRInt32 count = mObservers.Count();
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnUnassert(aDataSource, aSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -330,7 +338,6 @@ nsChromeUIDataSource::OnChange(nsIRDFDataSource* aDataSource,
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnChange(aDataSource, aSource, aProperty, aOldTarget, aNewTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -347,20 +354,29 @@ nsChromeUIDataSource::OnMove(nsIRDFDataSource* aDataSource,
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnMove(aDataSource, aOldSource, aNewSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
NS_IMETHODIMP
nsChromeUIDataSource::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
nsChromeUIDataSource::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnBeginUpdateBatch(aDataSource);
}
return NS_OK;
}
NS_IMETHODIMP
nsChromeUIDataSource::EndUpdateBatch(nsIRDFDataSource* aDataSource)
nsChromeUIDataSource::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnEndUpdateBatch(aDataSource);
}
return NS_OK;
}

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

@ -290,6 +290,7 @@ XUL_ATOM(dir, "dir")
XUL_ATOM(properties, "properties")
XUL_ATOM(resource, "resource")
XUL_ATOM(sort, "sort")
XUL_ATOM(sortLocked, "sortLocked")
XUL_ATOM(sortDirection, "sortDirection")
XUL_ATOM(sortActive, "sortActive")
XUL_ATOM(sortResource, "sortResource")

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

@ -1,2 +0,0 @@
nsIXULSortService.idl
nsIXULTemplateBuilder.idl

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

@ -31,6 +31,7 @@ MODULE = xultmpl
XPIDLSRCS = \
nsIXULSortService.idl \
nsIXULTemplateBuilder.idl \
nsIXULBuilderListener.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -0,0 +1,61 @@
/* -*- Mode: idl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jan Varga <varga@netscape.com>
*
* 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 ***** */
#include "nsISupports.idl"
interface nsIXULTemplateBuilder;
// An nsIXULBuilderListener object is a listener that will be notified
// when a template builder rebuilds its content.
[scriptable, uuid(ac46be8f-c863-4c23-84a2-d0fcc8dfa9f4)]
interface nsIXULBuilderListener: nsISupports {
/**
* Called before a template builder rebuilds its content.
* @param aBuilder the template builder that rebuilds the content.
*/
void willRebuild(in nsIXULTemplateBuilder aBuilder);
/**
* Called after a template builder has rebuilt its content.
* @param aBuilder the template builder that has rebuilt the content.
*/
void didRebuild(in nsIXULTemplateBuilder aBuilder);
};

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

@ -22,6 +22,7 @@
* Contributor(s):
* Chris Waterson <waterson@netscape.com>
* Ben Goodger <ben@netscape.com>
* Jan Varga <varga@netscape.com>
*
*
* Alternatively, the contents of this file may be used under the terms of
@ -43,6 +44,8 @@
#include "nsIRDFCompositeDataSource.idl"
#include "nsIRDFResource.idl"
interface nsIXULBuilderListener;
[ptr] native nsIContent_ptr(nsIContent);
[scriptable, uuid(fb744f8e-1dd1-11b2-a5d7-935c9ab60602)]
@ -77,6 +80,17 @@ interface nsIXULTemplateBuilder : nsISupports
* built.
*/
[noscript] void createContents(in nsIContent_ptr aElement);
/**
* Add a listener to this template builder. The template builder
* holds a strong reference to the listener.
*/
void addListener(in nsIXULBuilderListener aListener);
/**
* Remove a listener from this template builder.
*/
void removeListener(in nsIXULBuilderListener aListener);
};
/**

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

@ -130,7 +130,6 @@ class nsXULContentBuilder : public nsXULTemplateBuilder
{
public:
// nsIXULTemplateBuilder interface
NS_IMETHOD Rebuild();
NS_IMETHOD CreateContents(nsIContent* aElement);
// nsIDocumentObserver interface
@ -243,6 +242,9 @@ protected:
virtual nsresult
InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode);
virtual nsresult
RebuildAll();
virtual nsresult
CompileCondition(nsIAtom* aTag,
nsTemplateRule* aRule,
@ -288,9 +290,6 @@ protected:
*/
nsRDFSortState sortState;
nsresult
Rebuild(nsIContent* aElement);
virtual nsresult
ReplaceMatch(nsIRDFResource* aMember, const nsTemplateMatch* aOldMatch, nsTemplateMatch* aNewMatch);
@ -1671,77 +1670,6 @@ nsXULContentBuilder::GetElementFactory(PRInt32 aNameSpaceID, nsIElementFactory**
// nsIXULTemplateBuilder methods
//
nsresult
nsXULContentBuilder::Rebuild(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
nsresult rv;
// Next, see if it's a XUL element whose contents have never even
// been generated. If so, short-circuit and bail; there's nothing
// for us to "rebuild" yet. They'll get built correctly the next
// time somebody asks for them.
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
if (xulcontent) {
PRBool containerContentsBuilt = PR_FALSE;
xulcontent->GetLazyState(nsIXULContent::eContainerContentsBuilt, containerContentsBuilt);
if (! containerContentsBuilt)
return NS_OK;
}
// If we get here, then we've tried to generate content for this
// element. Remove it.
rv = RemoveGeneratedContent(aElement);
if (NS_FAILED(rv)) return rv;
if (aElement == mRoot) {
// Nuke the content support map and conflict set completely.
mContentSupportMap.Clear();
mTemplateMap.Clear();
mConflictSet.Clear();
rv = CompileRules();
if (NS_FAILED(rv)) return rv;
}
// Forces the XUL element to remember that it needs to
// re-generate its children next time around.
if (xulcontent) {
xulcontent->SetLazyState(nsIXULContent::eChildrenMustBeRebuilt);
xulcontent->ClearLazyState(nsIXULContent::eTemplateContentsBuilt);
xulcontent->ClearLazyState(nsIXULContent::eContainerContentsBuilt);
}
// Now, regenerate both the template- and container-generated
// contents for the current element...
nsCOMPtr<nsIContent> container;
PRInt32 newIndex;
CreateTemplateAndContainerContents(aElement, getter_AddRefs(container), &newIndex);
if (container) {
nsCOMPtr<nsIDocument> doc;
mRoot->GetDocument(*getter_AddRefs(doc));
NS_ASSERTION(doc != nsnull, "root element has no document");
if (! doc)
return NS_ERROR_UNEXPECTED;
doc->ContentAppended(container, newIndex);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULContentBuilder::Rebuild()
{
return Rebuild(mRoot);
}
NS_IMETHODIMP
nsXULContentBuilder::CreateContents(nsIContent* aElement)
{
@ -2078,6 +2006,75 @@ nsXULContentBuilder::InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode)
return NS_OK;
}
nsresult
nsXULContentBuilder::RebuildAll()
{
NS_PRECONDITION(mRoot != nsnull, "not initialized");
if (! mRoot)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIDocument> doc;
nsresult rv = mRoot->GetDocument(*getter_AddRefs(doc));
if (NS_FAILED(rv)) return rv;
// Bail out early if we are being torn down.
if (!doc)
return NS_OK;
// See if it's a XUL element whose contents have never even
// been generated. If so, short-circuit and bail; there's nothing
// for us to "rebuild" yet. They'll get built correctly the next
// time somebody asks for them.
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(mRoot);
if (xulcontent) {
PRBool containerContentsBuilt = PR_FALSE;
xulcontent->GetLazyState(nsIXULContent::eContainerContentsBuilt, containerContentsBuilt);
if (! containerContentsBuilt)
return NS_OK;
}
// If we get here, then we've tried to generate content for this
// element. Remove it.
rv = RemoveGeneratedContent(mRoot);
if (NS_FAILED(rv)) return rv;
// Nuke the content support map and conflict set completely.
mContentSupportMap.Clear();
mTemplateMap.Clear();
mConflictSet.Clear();
rv = CompileRules();
if (NS_FAILED(rv)) return rv;
// Forces the XUL element to remember that it needs to
// re-generate its children next time around.
if (xulcontent) {
xulcontent->SetLazyState(nsIXULContent::eChildrenMustBeRebuilt);
xulcontent->ClearLazyState(nsIXULContent::eTemplateContentsBuilt);
xulcontent->ClearLazyState(nsIXULContent::eContainerContentsBuilt);
}
// Now, regenerate both the template- and container-generated
// contents for the current element...
nsCOMPtr<nsIContent> container;
PRInt32 newIndex;
CreateTemplateAndContainerContents(mRoot, getter_AddRefs(container), &newIndex);
if (container) {
nsCOMPtr<nsIDocument> doc;
mRoot->GetDocument(*getter_AddRefs(doc));
NS_ASSERTION(doc != nsnull, "root element has no document");
if (! doc)
return NS_ERROR_UNEXPECTED;
doc->ContentAppended(container, newIndex);
}
return NS_OK;
}
nsresult
nsXULContentBuilder::CompileCondition(nsIAtom* aTag,
nsTemplateRule* aRule,

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

@ -226,6 +226,7 @@ nsXULContentUtils::GetElementResource(nsIContent* aElement, nsIRDFResource** aRe
nsresult
nsXULContentUtils::GetElementRefResource(nsIContent* aElement, nsIRDFResource** aResult)
{
*aResult = nsnull;
// Perform a reverse mapping from an element in the content model
// to an RDF resource. Check for a "ref" attribute first, then
// fallback on an "id" attribute.

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

@ -81,6 +81,7 @@
#include "nsIRDFContainerUtils.h"
#include "nsIXULDocument.h"
#include "nsIXULTemplateBuilder.h"
#include "nsIXULBuilderListener.h"
#include "nsIRDFNode.h"
#include "nsIRDFObserver.h"
#include "nsIRDFRemoteDataSource.h"
@ -151,7 +152,6 @@ PRLogModuleInfo* gXULTemplateLog;
nsXULTemplateBuilder::nsXULTemplateBuilder(void)
: mDB(nsnull),
mRoot(nsnull),
mTimer(nsnull),
mUpdateBatchNest(0),
mRulesCompiled(PR_FALSE),
mFlags(0),
@ -227,6 +227,22 @@ nsXULTemplateBuilder::GetDatabase(nsIRDFCompositeDataSource** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateBuilder::Rebuild()
{
for (PRInt32 i = mListeners.Count() - 1; i >= 0; --i) {
mListeners[i]->WillRebuild(this);
}
nsresult rv = RebuildAll();
for (PRInt32 i = mListeners.Count() - 1; i >= 0; --i) {
mListeners[i]->DidRebuild(this);
}
return rv;
}
NS_IMETHODIMP
nsXULTemplateBuilder::Init(nsIContent* aElement)
{
@ -241,6 +257,26 @@ nsXULTemplateBuilder::CreateContents(nsIContent* aElement)
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateBuilder::AddListener(nsIXULBuilderListener* aListener)
{
NS_ENSURE_ARG(aListener);
mListeners.AppendObject(aListener);
return NS_OK;
}
NS_IMETHODIMP
nsXULTemplateBuilder::RemoveListener(nsIXULBuilderListener* aListener)
{
NS_ENSURE_ARG(aListener);
mListeners.RemoveObject(aListener);
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsIDocumentOberver interface
@ -613,7 +649,7 @@ nsXULTemplateBuilder::OnMove(nsIRDFDataSource* aDataSource,
NS_IMETHODIMP
nsXULTemplateBuilder::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
nsXULTemplateBuilder::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
mUpdateBatchNest++;
return NS_OK;
@ -621,10 +657,12 @@ nsXULTemplateBuilder::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
NS_IMETHODIMP
nsXULTemplateBuilder::EndUpdateBatch(nsIRDFDataSource* aDataSource)
nsXULTemplateBuilder::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
{
if (mUpdateBatchNest > 0)
--mUpdateBatchNest;
NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
if (--mUpdateBatchNest == 0) {
Rebuild();
}
return NS_OK;
}

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

@ -52,7 +52,6 @@
#include "nsIRDFDataSource.h"
#include "nsIRDFObserver.h"
#include "nsIRDFService.h"
#include "nsITimer.h"
#include "nsIXULTemplateBuilder.h"
#include "nsConflictSet.h"
@ -60,6 +59,7 @@
#include "nsResourceSet.h"
#include "nsRuleNetwork.h"
#include "nsVoidArray.h"
#include "nsCOMArray.h"
#include "prlog.h"
#ifdef PR_LOGGING
@ -91,12 +91,8 @@ public:
NS_DECL_ISUPPORTS
// nsIXULTemplateBuilder interface
NS_IMETHOD GetRoot(nsIDOMElement** aResult);
NS_IMETHOD GetDatabase(nsIRDFCompositeDataSource** aResult);
NS_IMETHOD Rebuild() = 0; // must be implemented by subclasses
NS_IMETHOD Init(nsIContent* aElement);
NS_IMETHOD CreateContents(nsIContent* aElement);
NS_DECL_NSIXULTEMPLATEBUILDER
// nsISecurityCheckedComponent
NS_DECL_NSISECURITYCHECKEDCOMPONENT
@ -125,6 +121,9 @@ public:
virtual nsresult
InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode) = 0;
virtual nsresult
RebuildAll() = 0; // must be implemented by subclasses
/**
* Find the <template> tag that applies for this builder
*/
@ -311,7 +310,8 @@ protected:
nsCOMPtr<nsIContent> mRoot;
nsCOMPtr<nsIRDFDataSource> mCache;
nsCOMPtr<nsITimer> mTimer;
nsCOMArray<nsIXULBuilderListener> mListeners;
PRInt32 mUpdateBatchNest;

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

@ -92,9 +92,6 @@ public:
// nsITreeView
NS_DECL_NSITREEVIEW
// nsXULTemplateBuilder
NS_IMETHOD Rebuild();
NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument);
protected:
@ -119,6 +116,9 @@ protected:
virtual nsresult
InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode);
virtual nsresult
RebuildAll();
/**
* Override default behavior to additionally handle the <row>
* condition.
@ -407,60 +407,66 @@ nsXULTreeBuilder::Sort(nsIDOMElement* aElement)
if (! header)
return NS_ERROR_FAILURE;
nsAutoString sortLocked;
header->GetAttr(kNameSpaceID_None, nsXULAtoms::sortLocked, sortLocked);
if (sortLocked.Equals(NS_LITERAL_STRING("true")))
return NS_OK;
nsAutoString sort;
header->GetAttr(kNameSpaceID_None, nsXULAtoms::sort, sort);
if (!sort.IsEmpty()) {
// Grab the new sort variable
mSortVariable = mRules.LookupSymbol(sort.get());
if (sort.IsEmpty())
return NS_OK;
// Cycle the sort direction
nsAutoString dir;
header->GetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, dir);
// Grab the new sort variable
mSortVariable = mRules.LookupSymbol(sort.get());
if (dir == NS_LITERAL_STRING("ascending")) {
dir = NS_LITERAL_STRING("descending");
mSortDirection = eDirection_Descending;
}
else if (dir == NS_LITERAL_STRING("descending")) {
dir = NS_LITERAL_STRING("natural");
mSortDirection = eDirection_Natural;
}
else {
dir = NS_LITERAL_STRING("ascending");
mSortDirection = eDirection_Ascending;
}
// Cycle the sort direction
nsAutoString dir;
header->GetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, dir);
// Sort it
SortSubtree(mRows.GetRoot());
mRows.InvalidateCachedRow();
if (mBoxObject)
mBoxObject->Invalidate();
if (dir == NS_LITERAL_STRING("ascending")) {
dir = NS_LITERAL_STRING("descending");
mSortDirection = eDirection_Descending;
}
else if (dir == NS_LITERAL_STRING("descending")) {
dir = NS_LITERAL_STRING("natural");
mSortDirection = eDirection_Natural;
}
else {
dir = NS_LITERAL_STRING("ascending");
mSortDirection = eDirection_Ascending;
}
header->SetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, dir, PR_TRUE);
header->SetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, NS_LITERAL_STRING("true"), PR_TRUE);
// Sort it.
SortSubtree(mRows.GetRoot());
mRows.InvalidateCachedRow();
if (mBoxObject)
mBoxObject->Invalidate();
// Unset sort attribute(s) on the other columns
nsCOMPtr<nsIContent> parentContent;
header->GetParent(*getter_AddRefs(parentContent));
if (parentContent) {
nsCOMPtr<nsIAtom> parentTag;
parentContent->GetTag(*getter_AddRefs(parentTag));
if (parentTag == nsXULAtoms::treecols) {
PRInt32 numChildren;
parentContent->ChildCount(numChildren);
for (int i = 0; i < numChildren; ++i) {
nsCOMPtr<nsIContent> childContent;
nsCOMPtr<nsIAtom> childTag;
parentContent->ChildAt(i, *getter_AddRefs(childContent));
if (childContent) {
childContent->GetTag(*getter_AddRefs(childTag));
if (childTag == nsXULAtoms::treecol && childContent != header) {
childContent->UnsetAttr(kNameSpaceID_None,
nsXULAtoms::sortDirection, PR_TRUE);
childContent->UnsetAttr(kNameSpaceID_None,
nsXULAtoms::sortActive, PR_TRUE);
}
header->SetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, dir, PR_TRUE);
header->SetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, NS_LITERAL_STRING("true"), PR_TRUE);
// Unset sort attribute(s) on the other columns
nsCOMPtr<nsIContent> parentContent;
header->GetParent(*getter_AddRefs(parentContent));
if (parentContent) {
nsCOMPtr<nsIAtom> parentTag;
parentContent->GetTag(*getter_AddRefs(parentTag));
if (parentTag == nsXULAtoms::treecols) {
PRInt32 numChildren;
parentContent->ChildCount(numChildren);
for (int i = 0; i < numChildren; ++i) {
nsCOMPtr<nsIContent> childContent;
nsCOMPtr<nsIAtom> childTag;
parentContent->ChildAt(i, *getter_AddRefs(childContent));
if (childContent) {
childContent->GetTag(*getter_AddRefs(childTag));
if (childTag == nsXULAtoms::treecol && childContent != header) {
childContent->UnsetAttr(kNameSpaceID_None,
nsXULAtoms::sortDirection, PR_TRUE);
childContent->UnsetAttr(kNameSpaceID_None,
nsXULAtoms::sortActive, PR_TRUE);
}
}
}
@ -1051,56 +1057,6 @@ nsXULTreeBuilder::PerformActionOnCell(const PRUnichar* action, PRInt32 row, cons
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsIXULTemplateBuilder methods
//
NS_IMETHODIMP
nsXULTreeBuilder::Rebuild()
{
NS_PRECONDITION(mRoot != nsnull, "not initialized");
if (! mRoot)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
PRInt32 count = mRows.Count();
mRows.Clear();
mConflictSet.Clear();
if (mBoxObject)
mBoxObject->RowCountChanged(0, -count);
rv = CompileRules();
if (NS_FAILED(rv)) return rv;
// Seed the rule network with assignments for the tree row
// variable
nsCOMPtr<nsIRDFResource> root;
nsXULContentUtils::GetElementRefResource(mRoot, getter_AddRefs(root));
mRows.SetRootResource(root);
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
const char* s = "(null)";
if (root)
root->GetValueConst(&s);
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
("xultemplate[%p] root=%s", this, s));
}
#endif
if (root)
OpenContainer(-1, root);
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsXULTemplateBuilder abstract methods
//
NS_IMETHODIMP
nsXULTreeBuilder::DocumentWillBeDestroyed(nsIDocument* aDocument)
@ -1371,6 +1327,58 @@ nsXULTreeBuilder::InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode)
return NS_OK;
}
nsresult
nsXULTreeBuilder::RebuildAll()
{
NS_PRECONDITION(mRoot != nsnull, "not initialized");
if (! mRoot)
return NS_ERROR_NOT_INITIALIZED;
nsCOMPtr<nsIDocument> doc;
nsresult rv = mRoot->GetDocument(*getter_AddRefs(doc));
if (NS_FAILED(rv)) return rv;
// Bail out early if we are being torn down.
if (!doc)
return NS_OK;
if (mBoxObject) {
mBoxObject->BeginUpdateBatch();
}
mRows.Clear();
mConflictSet.Clear();
rv = CompileRules();
if (NS_FAILED(rv)) return rv;
// Seed the rule network with assignments for the tree row
// variable
nsCOMPtr<nsIRDFResource> root;
nsXULContentUtils::GetElementRefResource(mRoot, getter_AddRefs(root));
mRows.SetRootResource(root);
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
const char* s = "(null)";
if (root)
root->GetValueConst(&s);
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
("xultemplate[%p] root=%s", this, s));
}
#endif
if (root)
OpenContainer(-1, root);
if (mBoxObject) {
mBoxObject->EndUpdateBatch();
}
return NS_OK;
}
nsresult
nsXULTreeBuilder::CompileCondition(nsIAtom* aTag,
nsTemplateRule* aRule,

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

@ -859,29 +859,29 @@ nsLDAPDataSource.prototype = {
}
},
beginUpdateBatch: function()
onBeginUpdateBatch: function()
{
if (DEBUG) {
dump("BeginUpdateBatch() called\n\n");
dump("onBeginUpdateBatch() called\n\n");
}
var iter = new ArrayEnumerator(this.mObserverList);
var nextObserver;
while ((nextObserver = iter.getNext()) != null) {
nextObserver.beginUpdateBatch(this);
nextObserver.onBeginUpdateBatch(this);
}
},
endUpdateBatch: function()
onEndUpdateBatch: function()
{
if (DEBUG) {
dump("EndUpdateBatch() called\n\n");
dump("onEndUpdateBatch() called\n\n");
}
var iter = new ArrayEnumerator(this.mObserverList);
var nextObserver;
while ((nextObserver = iter.getNext()) != null) {
nextObserver.endUpdateBatch(this);
nextObserver.onEndUpdateBatch(this);
}
},

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

@ -581,6 +581,24 @@ mozSqlResult::DoCommand(nsISupportsArray* aSources,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
mozSqlResult::BeginUpdateBatch()
{
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
mObservers[i]->OnBeginUpdateBatch(this);
}
return NS_OK;
}
NS_IMETHODIMP
mozSqlResult::EndUpdateBatch()
{
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
mObservers[i]->OnEndUpdateBatch(this);
}
return NS_OK;
}
NS_IMETHODIMP
mozSqlResult::GetLoaded(PRBool* aResult)

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

@ -551,6 +551,18 @@ mozSqlService::DoCommand(nsISupportsArray* aSources,
return mInner->DoCommand(aSources, aCommand, aArguments);
}
NS_IMETHODIMP
mozSqlService::BeginUpdateBatch()
{
return mInner->BeginUpdateBatch();
}
NS_IMETHODIMP
mozSqlService::EndUpdateBatch()
{
return mInner->EndUpdateBatch();
}
// nsIRDFRemoteDataSource
NS_IMETHODIMP

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

@ -173,6 +173,19 @@ interface nsITreeBoxObject : nsISupports
*/
void rowCountChanged(in long index, in long count);
/**
* Notify the tree that the view is about to perform a batch
* update, that is, add, remove or invalidate several rows at once.
* This must be followed by calling endUpdateBatch(), otherwise the tree
* will get out of sync.
*/
void beginUpdateBatch();
/**
* Notify the tree that the view has completed a batch update.
*/
void endUpdateBatch();
/**
* Drag handlers, installed from XBL, called when drags occur to handle painting
*/

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

@ -335,7 +335,8 @@ nsTreeBodyFrame::nsTreeBodyFrame(nsIPresShell* aPresShell)
mColumns(nsnull), mScrollbar(nsnull), mTopRowIndex(0), mRowHeight(0), mIndentation(0), mStringWidth(-1),
mFocused(PR_FALSE), mColumnsDirty(PR_TRUE), mDropAllowed(PR_FALSE), mHasFixedRowCount(PR_FALSE),
mVerticalOverflow(PR_FALSE), mImageGuard(PR_FALSE), mReflowCallbackPosted(PR_FALSE),
mDropRow(-1), mDropOrient(-1), mScrollLines(0), mTimer(nsnull), mValueArray(~PRInt32(0))
mDropRow(-1), mDropOrient(-1), mScrollLines(0), mTimer(nsnull), mValueArray(~PRInt32(0)),
mUpdateBatchNest(0), mCountBeforeUpdate(-1)
{
NS_NewISupportsArray(getter_AddRefs(mScratchArray));
}
@ -886,6 +887,8 @@ NS_IMETHODIMP nsTreeBodyFrame::GetPageCount(PRInt32 *_retval)
NS_IMETHODIMP nsTreeBodyFrame::Invalidate()
{
if (mUpdateBatchNest)
return NS_OK;
if (!mRect.IsEmpty()) {
nsLeafBoxFrame::Invalidate(mPresContext, mRect, PR_FALSE);
}
@ -894,6 +897,8 @@ NS_IMETHODIMP nsTreeBodyFrame::Invalidate()
NS_IMETHODIMP nsTreeBodyFrame::InvalidateColumn(const PRUnichar *aColID)
{
if (mUpdateBatchNest)
return NS_OK;
nscoord currX = mInnerBox.x;
for (nsTreeColumn* currCol = mColumns; currCol && currX < mInnerBox.x+mInnerBox.width;
currCol = currCol->GetNext()) {
@ -910,6 +915,8 @@ NS_IMETHODIMP nsTreeBodyFrame::InvalidateColumn(const PRUnichar *aColID)
NS_IMETHODIMP nsTreeBodyFrame::InvalidateRow(PRInt32 aIndex)
{
if (mUpdateBatchNest)
return NS_OK;
if (aIndex < mTopRowIndex || aIndex > mTopRowIndex + mPageCount + 1)
return NS_OK;
@ -921,6 +928,8 @@ NS_IMETHODIMP nsTreeBodyFrame::InvalidateRow(PRInt32 aIndex)
NS_IMETHODIMP nsTreeBodyFrame::InvalidateCell(PRInt32 aIndex, const PRUnichar *aColID)
{
if (mUpdateBatchNest)
return NS_OK;
if (aIndex < mTopRowIndex || aIndex > mTopRowIndex + mPageCount + 1)
return NS_OK;
@ -944,6 +953,8 @@ NS_IMETHODIMP nsTreeBodyFrame::InvalidateCell(PRInt32 aIndex, const PRUnichar *a
NS_IMETHODIMP nsTreeBodyFrame::InvalidatePrimaryCell(PRInt32 aIndex)
{
if (mUpdateBatchNest)
return NS_OK;
if (aIndex < mTopRowIndex || aIndex > mTopRowIndex + mPageCount + 1)
return NS_OK;
@ -970,6 +981,8 @@ NS_IMETHODIMP nsTreeBodyFrame::InvalidatePrimaryCell(PRInt32 aIndex)
NS_IMETHODIMP nsTreeBodyFrame::InvalidateRange(PRInt32 aStart, PRInt32 aEnd)
{
if (mUpdateBatchNest)
return NS_OK;
if (aStart == aEnd)
return InvalidateRow(aStart);
@ -1058,6 +1071,8 @@ nsresult nsTreeBodyFrame::CheckVerticalOverflow()
NS_IMETHODIMP nsTreeBodyFrame::InvalidateScrollbar()
{
if (mUpdateBatchNest)
return NS_OK;
if (!EnsureScrollbar() || !mView)
return NS_OK;
@ -1695,6 +1710,9 @@ nsTreeBodyFrame::CreateTimer(const nsILookAndFeel::nsMetricID aID,
NS_IMETHODIMP nsTreeBodyFrame::RowCountChanged(PRInt32 aIndex, PRInt32 aCount)
{
if (mUpdateBatchNest)
return NS_OK;
if (aCount == 0 || !mView)
return NS_OK; // Nothing to do.
@ -1738,9 +1756,10 @@ NS_IMETHODIMP nsTreeBodyFrame::RowCountChanged(PRInt32 aIndex, PRInt32 aCount)
}
else if (mTopRowIndex >= aIndex) {
// This is a full-blown invalidate.
if (mTopRowIndex + mPageCount > rowCount - 1)
if (mTopRowIndex + mPageCount > rowCount - 1) {
mTopRowIndex = PR_MAX(0, rowCount - 1 - mPageCount);
UpdateScrollbar();
UpdateScrollbar();
}
Invalidate();
}
}
@ -1752,6 +1771,40 @@ NS_IMETHODIMP nsTreeBodyFrame::RowCountChanged(PRInt32 aIndex, PRInt32 aCount)
return NS_OK;
}
NS_IMETHODIMP nsTreeBodyFrame::BeginUpdateBatch()
{
if (mUpdateBatchNest++ == 0) {
if (mView) {
mView->GetRowCount(&mCountBeforeUpdate);
}
}
return NS_OK;
}
NS_IMETHODIMP nsTreeBodyFrame::EndUpdateBatch()
{
NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
if (--mUpdateBatchNest == 0) {
if (mView) {
Invalidate();
PRInt32 countAfterUpdate;
mView->GetRowCount(&countAfterUpdate);
if (mCountBeforeUpdate != countAfterUpdate) {
if (mTopRowIndex + mPageCount > countAfterUpdate - 1) {
mTopRowIndex = PR_MAX(0, countAfterUpdate - 1 - mPageCount);
UpdateScrollbar();
}
InvalidateScrollbar();
CheckVerticalOverflow();
}
}
}
return NS_OK;
}
void
nsTreeBodyFrame::PrefillPropertyArray(PRInt32 aRowIndex, nsTreeColumn* aCol)
{

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

@ -526,6 +526,8 @@ protected: // Data Members
PRPackedBool mVerticalOverflow;
PRInt16 mUpdateBatchNest;
// A guard that prevents us from recursive painting.
PRPackedBool mImageGuard;
@ -548,4 +550,6 @@ protected: // Data Members
// A value array used to keep track of all spring loaded folders.
nsValueArray mValueArray;
PRInt32 mCountBeforeUpdate;
}; // class nsTreeBodyFrame

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

@ -424,6 +424,22 @@ NS_IMETHODIMP nsTreeBoxObject::RowCountChanged(PRInt32 aIndex, PRInt32 aDelta)
return NS_OK;
}
NS_IMETHODIMP nsTreeBoxObject::BeginUpdateBatch()
{
nsITreeBoxObject* body = GetTreeBody();
if (body)
return body->BeginUpdateBatch();
return NS_OK;
}
NS_IMETHODIMP nsTreeBoxObject::EndUpdateBatch()
{
nsITreeBoxObject* body = GetTreeBody();
if (body)
return body->EndUpdateBatch();
return NS_OK;
}
NS_IMETHODIMP nsTreeBoxObject::OnDragEnter(nsIDOMEvent* inEvent)
{
nsITreeBoxObject* body = GetTreeBody();

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

@ -523,3 +523,14 @@ NS_IMETHODIMP nsAbRDFDataSource::DoCommand
return NS_RDF_NO_VALUE;
}
NS_IMETHODIMP
nsAbRDFDataSource::BeginUpdateBatch()
{
return NS_OK;
}
NS_IMETHODIMP
nsAbRDFDataSource::EndUpdateBatch()
{
return NS_OK;
}

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

@ -308,6 +308,20 @@ nsMsgRDFDataSource::DoCommand(nsISupportsArray *aSources, nsIRDFResource *aComma
return NS_RDF_NO_VALUE;
}
/* void BeginUpdateBatch (); */
NS_IMETHODIMP
nsMsgRDFDataSource::BeginUpdateBatch()
{
return NS_OK;
}
/* void EndUpdateBatch (); */
NS_IMETHODIMP
nsMsgRDFDataSource::EndUpdateBatch()
{
return NS_OK;
}
/* XPCOM Shutdown observer */
NS_IMETHODIMP

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

@ -582,3 +582,15 @@ nsSoundDatasource::RemoveObserver(nsIRDFObserver *n)
mObservers->RemoveElement(n);
return NS_OK;
}
NS_IMETHODIMP
nsSoundDatasource::BeginUpdateBatch()
{
return NS_OK;
}
NS_IMETHODIMP
nsSoundDatasource::EndUpdateBatch()
{
return NS_OK;
}

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

@ -724,6 +724,24 @@ nsSubscribeDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
return(NS_ERROR_NOT_IMPLEMENTED);
}
NS_IMETHODIMP
nsSubscribeDataSource::BeginUpdateBatch()
{
return NS_OK;
}
NS_IMETHODIMP
nsSubscribeDataSource::EndUpdateBatch()
{
return NS_OK;
}
NS_IMETHODIMP
nsSubscribeDataSource::GetSources(nsIRDFResource *aProperty, nsIRDFNode *aTarget, PRBool aTruthValue, nsISimpleEnumerator **_retval)
{

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

@ -422,3 +422,15 @@ NS_IMETHODIMP nsSmtpDataSource::GetAllCmds(nsIRDFResource *aSource, nsISimpleEnu
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void beginUpdateBatch (); */
NS_IMETHODIMP nsSmtpDataSource::BeginUpdateBatch()
{
return NS_OK;
}
/* void endUpdateBatch (); */
NS_IMETHODIMP nsSmtpDataSource::EndUpdateBatch()
{
return NS_OK;
}

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

@ -235,9 +235,8 @@ pref("browser.fixup.alternate.enabled", true);
pref("browser.fixup.alternate.prefix", "www.");
pref("browser.fixup.alternate.suffix", ".com");
// Default bookmark sorting
pref("browser.bookmarks.sort.direction", "descending");
pref("browser.bookmarks.sort.resource", "rdf:http://home.netscape.com/NC-rdf#Name");
// Bookmarks prefs
pref("browser.bookmarks.confirm_sorting", true);
//Internet Search
pref("browser.search.defaultenginename", "chrome://communicator-region/locale/region.properties");

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

@ -1,16 +0,0 @@
nsIRDFCompositeDataSource.idl
nsIRDFContainer.idl
nsIRDFContainerUtils.idl
nsIRDFDataSource.idl
nsIRDFLiteral.idl
nsIRDFNode.idl
nsIRDFObserver.idl
nsIRDFInMemoryDataSource.idl
nsIRDFPurgeableDataSource.idl
nsIRDFRemoteDataSource.idl
nsIRDFResource.idl
nsIRDFService.idl
nsIRDFXMLParser.idl
nsIRDFXMLSerializer.idl
nsIRDFXMLSink.idl
nsIRDFXMLSource.idl

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

@ -39,6 +39,7 @@ XPIDLSRCS = \
nsIRDFNode.idl \
nsIRDFObserver.idl \
nsIRDFInMemoryDataSource.idl \
nsIRDFPropagatableDataSource.idl \
nsIRDFPurgeableDataSource.idl \
nsIRDFRemoteDataSource.idl \
nsIRDFResource.idl \

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

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jan Varga <varga@netscape.com>
*
* 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
@ -217,5 +218,18 @@ interface nsIRDFDataSource : nsISupports
* Equivalent to enumerating ArcLabelsOut and comparing for the specified arc.
*/
boolean hasArcOut(in nsIRDFResource aSource, in nsIRDFResource aArc);
};
/**
* Notify observers that the datasource is about to send several
* notifications at once.
* This must be followed by calling endUpdateBatch(), otherwise
* viewers will get out of sync.
*/
void beginUpdateBatch();
/**
* Notify observers that the datasource has completed issuing
* a notification group.
*/
void endUpdateBatch();
};

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

@ -114,7 +114,7 @@ interface nsIRDFObserver : nsISupports {
* @param aDataSource the datasource that is going to
* be issuing the notifications.
*/
void beginUpdateBatch(in nsIRDFDataSource aDataSource);
void onBeginUpdateBatch(in nsIRDFDataSource aDataSource);
/**
* This method is called when a datasource has completed
@ -122,7 +122,5 @@ interface nsIRDFObserver : nsISupports {
* @param aDataSource the datasource that has finished
* issuing a group of notifications
*/
void endUpdateBatch(in nsIRDFDataSource aDataSource);
void onEndUpdateBatch(in nsIRDFDataSource aDataSource);
};

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

@ -0,0 +1,60 @@
/* -*- Mode: idl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corp.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jan Varga <varga@netscape.com>
*
* 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 ***** */
#include "nsISupports.idl"
/**
* An nsIRDFPropagatableDataSource provides an ability to suppress
* synchronization notifications.
*/
[scriptable, uuid(5a9b4770-9fcb-4307-a12e-4b6708e78b97)]
interface nsIRDFPropagatableDataSource: nsISupports {
/**
* Set this value to <code>true</code> to enable synchronization
* notifications.
*
* Set this value to <code>false</code> to disable synchronization
* notifications.
*
* By default, this value is <code>true</code>.
*/
attribute boolean propagateChanges;
};

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

@ -32,10 +32,8 @@ REQUIRES = xpcom \
string \
rdfutil \
necko \
layout \
content \
htmlparser \
js \
unicharutil \
$(NULL)

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

@ -1343,6 +1343,24 @@ CompositeDataSourceImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSource
return(NS_OK);
}
NS_IMETHODIMP
CompositeDataSourceImpl::BeginUpdateBatch()
{
for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
mDataSources[i]->BeginUpdateBatch();
}
return NS_OK;
}
NS_IMETHODIMP
CompositeDataSourceImpl::EndUpdateBatch()
{
for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
mDataSources[i]->EndUpdateBatch();
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
// nsIRDFCompositeDataSource methods
// XXX rvg We should make this take an additional argument specifying where
@ -1443,7 +1461,6 @@ CompositeDataSourceImpl::OnAssert(nsIRDFDataSource* aDataSource,
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
mObservers[i]->OnAssert(this, aSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -1475,7 +1492,6 @@ CompositeDataSourceImpl::OnUnassert(nsIRDFDataSource* aDataSource,
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
mObservers[i]->OnUnassert(this, aSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -1497,7 +1513,6 @@ CompositeDataSourceImpl::OnChange(nsIRDFDataSource* aDataSource,
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
mObservers[i]->OnChange(this, aSource, aProperty,
aOldTarget, aNewTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -1519,20 +1534,17 @@ CompositeDataSourceImpl::OnMove(nsIRDFDataSource* aDataSource,
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
mObservers[i]->OnMove(this, aOldSource, aNewSource,
aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
NS_IMETHODIMP
CompositeDataSourceImpl::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
CompositeDataSourceImpl::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
PRInt32 nest = mUpdateBatchNest++;
if (nest == 0) {
if (mUpdateBatchNest++ == 0) {
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
mObservers[i]->BeginUpdateBatch(this);
// XXX ignore return value?
mObservers[i]->OnBeginUpdateBatch(this);
}
}
return NS_OK;
@ -1540,18 +1552,12 @@ CompositeDataSourceImpl::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
NS_IMETHODIMP
CompositeDataSourceImpl::EndUpdateBatch(nsIRDFDataSource* aDataSource)
CompositeDataSourceImpl::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
{
PRInt32 nest = --mUpdateBatchNest;
if (nest < 0) {
NS_ERROR("badly nested update batch");
mUpdateBatchNest = 0;
return NS_ERROR_UNEXPECTED;
}
if (nest == 0) {
NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
if (--mUpdateBatchNest == 0) {
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
mObservers[i]->EndUpdateBatch(this);
// XXX ignore return value?
mObservers[i]->OnEndUpdateBatch(this);
}
}
return NS_OK;

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

@ -62,6 +62,7 @@
#include "nsIRDFNode.h"
#include "nsIRDFObserver.h"
#include "nsIRDFInMemoryDataSource.h"
#include "nsIRDFPropagatableDataSource.h"
#include "nsIRDFPurgeableDataSource.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
@ -283,6 +284,7 @@ class InMemoryResourceEnumeratorImpl;
class InMemoryDataSource : public nsIRDFDataSource,
public nsIRDFInMemoryDataSource,
public nsIRDFPropagatableDataSource,
public nsIRDFPurgeableDataSource
{
protected:
@ -339,6 +341,9 @@ public:
// nsIRDFInMemoryDataSource methods
NS_DECL_NSIRDFINMEMORYDATASOURCE
// nsIRDFPropagatableDataSource methods
NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
// nsIRDFPurgeableDataSource methods
NS_DECL_NSIRDFPURGEABLEDATASOURCE
@ -396,6 +401,7 @@ public:
// This datasource's monitor object.
PRLock* mLock;
#endif
PRBool mPropagateChanges;
};
//----------------------------------------------------------------------
@ -885,6 +891,7 @@ InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
#ifdef MOZ_THREADSAFE_RDF
mLock = nsnull;
#endif
mPropagateChanges = PR_TRUE;
}
@ -982,6 +989,9 @@ InMemoryDataSource::AggregatedQueryInterface(REFNSIID aIID, void** aResult)
else if (aIID.Equals(NS_GET_IID(nsIRDFInMemoryDataSource))) {
*aResult = NS_STATIC_CAST(nsIRDFInMemoryDataSource*, this);
}
else if (aIID.Equals(NS_GET_IID(nsIRDFPropagatableDataSource))) {
*aResult = NS_STATIC_CAST(nsIRDFPropagatableDataSource*, this);
}
else if (aIID.Equals(NS_GET_IID(nsIRDFPurgeableDataSource))) {
*aResult = NS_STATIC_CAST(nsIRDFPurgeableDataSource*, this);
}
@ -1389,7 +1399,7 @@ InMemoryDataSource::Assert(nsIRDFResource* aSource,
}
// notify observers
for (PRInt32 i = (PRInt32)mNumObservers - 1; i >= 0; --i) {
for (PRInt32 i = (PRInt32)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
nsIRDFObserver* obs = mObservers[i];
// XXX this should never happen, but it does, and we can't figure out why.
@ -1541,7 +1551,7 @@ InMemoryDataSource::Unassert(nsIRDFResource* aSource,
}
// Notify the world
for (PRInt32 i = PRInt32(mNumObservers) - 1; i >= 0; --i) {
for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
nsIRDFObserver* obs = mObservers[i];
// XXX this should never happen, but it does, and we can't figure out why.
@ -1595,7 +1605,7 @@ InMemoryDataSource::Change(nsIRDFResource* aSource,
}
// Notify the world
for (PRInt32 i = PRInt32(mNumObservers) - 1; i >= 0; --i) {
for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
nsIRDFObserver* obs = mObservers[i];
// XXX this should never happen, but it does, and we can't figure out why.
@ -1649,7 +1659,7 @@ InMemoryDataSource::Move(nsIRDFResource* aOldSource,
}
// Notify the world
for (PRInt32 i = PRInt32(mNumObservers) - 1; i >= 0; --i) {
for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
nsIRDFObserver* obs = mObservers[i];
// XXX this should never happen, but it does, and we can't figure out why.
@ -1843,6 +1853,27 @@ InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
return NS_OK;
}
NS_IMETHODIMP
InMemoryDataSource::BeginUpdateBatch()
{
for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
nsIRDFObserver* obs = mObservers[i];
obs->OnBeginUpdateBatch(this);
}
return NS_OK;
}
NS_IMETHODIMP
InMemoryDataSource::EndUpdateBatch()
{
for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
nsIRDFObserver* obs = mObservers[i];
obs->OnEndUpdateBatch(this);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
// nsIRDFInMemoryDataSource methods
@ -1899,6 +1930,23 @@ InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
}
////////////////////////////////////////////////////////////////////////
// nsIRDFPropagatableDataSource methods
NS_IMETHODIMP
InMemoryDataSource::GetPropagateChanges(PRBool* aPropagateChanges)
{
*aPropagateChanges = mPropagateChanges;
return NS_OK;
}
NS_IMETHODIMP
InMemoryDataSource::SetPropagateChanges(PRBool aPropagateChanges)
{
mPropagateChanges = aPropagateChanges;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
// nsIRDFPurgeableDataSource methods
@ -1999,7 +2047,7 @@ InMemoryDataSource::Sweep()
#endif
if (!(as->mHashEntry))
{
for (PRInt32 i = PRInt32(mNumObservers) - 1; i >= 0; --i) {
for (PRInt32 i = PRInt32(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
nsIRDFObserver* obs = mObservers[i];
// XXXbz other loops over mObservers null-check |obs| here!
obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget);

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

@ -70,6 +70,7 @@
#include "nsIRDFContainer.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFInMemoryDataSource.h"
#include "nsIRDFPropagatableDataSource.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsRDFCID.h"
@ -542,16 +543,12 @@ RDFContainerImpl::Renumber(PRInt32 aStartIndex, PRInt32 aIncrement)
i = count; // we're one-indexed.
}
// Note: once we begin batch updates, don't exit this method until
// ending batch updates, otherwise viewers will get out of sync
nsCOMPtr<nsIRDFObserver> dsObs;
if (mDataSource)
{
dsObs = do_QueryInterface(mDataSource);
if (dsObs)
{
dsObs->BeginUpdateBatch(mDataSource);
}
// Note: once we disable notifications, don't exit this method until
// enabling notifications
nsCOMPtr<nsIRDFPropagatableDataSource> propagatable =
do_QueryInterface(mDataSource);
if (propagatable) {
propagatable->SetPropagateChanges(PR_FALSE);
}
PRBool err = PR_FALSE;
@ -647,9 +644,10 @@ RDFContainerImpl::Renumber(PRInt32 aStartIndex, PRInt32 aIncrement)
}
}
// Note: MUST end update batching before exiting this method
// otherwise viewers will get out of sync
if (dsObs) dsObs->EndUpdateBatch(mDataSource);
// Note: MUST enable notifications before exiting this method
if (propagatable) {
propagatable->SetPropagateChanges(PR_TRUE);
}
if (err == PR_TRUE) return(rv);
@ -771,5 +769,3 @@ RDFContainerImpl::GetNextValue(nsIRDFResource** aResult)
return NS_OK;
}

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

@ -450,11 +450,7 @@ RDFContainerUtilsImpl::MakeContainer(nsIRDFDataSource* aDataSource, nsIRDFResour
rv = aDataSource->Assert(aResource, kRDF_instanceOf, aType, PR_TRUE);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIRDFLiteral> nextVal;
rv = gRDFService->GetLiteral(NS_LITERAL_STRING("1").get(), getter_AddRefs(nextVal));
if (NS_FAILED(rv)) return rv;
rv = aDataSource->Assert(aResource, kRDF_nextVal, nextVal, PR_TRUE);
rv = aDataSource->Assert(aResource, kRDF_nextVal, kOne, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}

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

@ -45,11 +45,9 @@
*/
#include <stdlib.h> // XXX for atoi(), maybe this should go into nsCRT?
#include "nsCRT.h"
#include "nsIURL.h"
#include "nsString.h"
#include "nsRDFParserUtils.h"
#include "jsapi.h" // for JSVERSION_* and JS_VersionToString
// XXX This totally sucks. I wish that mozilla/base had this code.
PRUnichar

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

@ -45,11 +45,6 @@
#ifndef nsRDFParserUtils_h__
#define nsRDFParserUtils_h__
#include "nscore.h"
#include "jspubtd.h"
class nsIURI;
class nsString;
class nsRDFParserUtils {
public:
static PRUnichar
@ -64,6 +59,4 @@ public:
nsString& aValue);
};
#endif // nsRDFPasrserUtils_h__

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

@ -363,6 +363,14 @@ public:
return mInner->DoCommand(aSources, aCommand, aArguments);
}
NS_IMETHOD BeginUpdateBatch() {
return mInner->BeginUpdateBatch();
}
NS_IMETHOD EndUpdateBatch() {
return mInner->EndUpdateBatch();
}
// nsIRDFRemoteDataSource interface
NS_DECL_NSIRDFREMOTEDATASOURCE

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

@ -287,6 +287,16 @@ nsChromeUIDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
return mComposite->DoCommand(aSources, aCommand, aArguments);
}
NS_IMETHODIMP
nsChromeUIDataSource::BeginUpdateBatch() {
return mComposite->BeginUpdateBatch();
}
NS_IMETHODIMP
nsChromeUIDataSource::EndUpdateBatch() {
return mComposite->EndUpdateBatch();
}
//////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
@ -299,7 +309,6 @@ nsChromeUIDataSource::OnAssert(nsIRDFDataSource* aDataSource,
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnAssert(this, aSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -313,7 +322,6 @@ nsChromeUIDataSource::OnUnassert(nsIRDFDataSource* aDataSource,
PRInt32 count = mObservers.Count();
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnUnassert(aDataSource, aSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -330,7 +338,6 @@ nsChromeUIDataSource::OnChange(nsIRDFDataSource* aDataSource,
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnChange(aDataSource, aSource, aProperty, aOldTarget, aNewTarget);
// XXX ignore return value?
}
return NS_OK;
}
@ -347,20 +354,29 @@ nsChromeUIDataSource::OnMove(nsIRDFDataSource* aDataSource,
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnMove(aDataSource, aOldSource, aNewSource, aProperty, aTarget);
// XXX ignore return value?
}
return NS_OK;
}
NS_IMETHODIMP
nsChromeUIDataSource::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
nsChromeUIDataSource::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnBeginUpdateBatch(aDataSource);
}
return NS_OK;
}
NS_IMETHODIMP
nsChromeUIDataSource::EndUpdateBatch(nsIRDFDataSource* aDataSource)
nsChromeUIDataSource::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = count - 1; i >= 0; --i) {
mObservers[i]->OnEndUpdateBatch(aDataSource);
}
return NS_OK;
}

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

@ -1104,6 +1104,22 @@ FileSystemDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
NS_IMETHODIMP
FileSystemDataSource::BeginUpdateBatch()
{
return NS_OK;
}
NS_IMETHODIMP
FileSystemDataSource::EndUpdateBatch()
{
return NS_OK;
}
nsresult
NS_NewRDFFileSystemDataSource(nsIRDFDataSource **result)
{

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

@ -214,6 +214,14 @@ public:
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments);
NS_IMETHOD BeginUpdateBatch() {
return mInner->BeginUpdateBatch();
}
NS_IMETHOD EndUpdateBatch() {
return mInner->EndUpdateBatch();
}
NS_IMETHOD GetLoaded(PRBool* _result);
NS_IMETHOD Init(const char *uri);
NS_IMETHOD Flush();

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

@ -105,6 +105,12 @@ class nsRDFDOMDataSource : public nsISupports {
/* void DoCommand (in nsISupportsArray aSources, in nsIRDFResource aCommand, in nsISupportsArray aArguments); */
NS_IMETHOD DoCommand(nsISupportsArray * aSources, nsIRDFResource *aCommand, nsISupportsArray * aArguments) = 0;
/* void beginUpdateBatch (); */
NS_IMETHOD BeginUpdateBatch() = 0;
/* void endUpdateBatch (); */
NS_IMETHOD EndUpdateBatch() = 0;
};
#endif /* __gen_nsRDFDOMDataSource_h__ */

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

@ -120,6 +120,12 @@ public:
/* void DoCommand (in nsISupportsArray aSources, in nsIRDFResource aCommand, in nsISupportsArray aArguments); */
NS_IMETHOD DoCommand(nsISupportsArray * aSources, nsIRDFResource *aCommand, nsISupportsArray * aArguments);
/* void beginUpdateBatch (); */
NS_IMETHOD BeginUpdateBatch();
/* void endUpdateBatch (); */
NS_IMETHOD EndUpdateBatch();
private:
char *mURI;
nsIRDFDataSource* mDataSource;
@ -446,6 +452,20 @@ nsRDFDataSourceDataSource::DoCommand(nsISupportsArray * aSources, nsIRDFResource
return NS_RDF_NO_VALUE;
}
/* void beginUpdateBatch (); */
NS_IMETHODIMP
nsRDFDataSourceDataSource::BeginUpdateBatch()
{
return NS_OK;
}
/* void endUpdateBatch (); */
NS_IMETHODIMP
nsRDFDataSourceDataSource::EndUpdateBatch()
{
return NS_OK;
}
nsresult
NS_NewRDFDataSourceDataSource(nsISupports *, const nsIID& iid,
void ** result)

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

@ -239,13 +239,13 @@ Observer::OnMove(nsIRDFDataSource* aDataSource,
}
NS_IMETHODIMP
Observer::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
Observer::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
return NS_OK;
}
NS_IMETHODIMP
Observer::EndUpdateBatch(nsIRDFDataSource* aDataSource)
Observer::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
{
return NS_OK;
}

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

@ -63,21 +63,6 @@ interface nsIBrowserHistory : nsISupports
*/
void removePage(in string aURL);
/**
* startBatchUpdate
* Signals the beginning of some kind of batch update (e.g. delete).
* Observers won't be notified until there are no batches in progress
* (a startBatchUpdate call should always be followed by one to
* endBatchUpdate).
*/
void startBatchUpdate();
/**
* endBatchUpdate
* Signals the end of a batch update.
*/
void endBatchUpdate();
/**
* removePagesFromHost
* Remove all pages from the given host.

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

@ -1104,7 +1104,7 @@ nsGlobalHistory::RemoveMatchingRows(rowMatchCallback aMatchFunc,
err = mTable->GetCount(mEnv, &count);
if (err != 0) return NS_ERROR_FAILURE;
StartBatchUpdate();
BeginUpdateBatch();
// Begin the batch.
int marker;
@ -1164,7 +1164,7 @@ nsGlobalHistory::RemoveMatchingRows(rowMatchCallback aMatchFunc,
err = mTable->EndBatchChangeHint(mEnv, &marker);
NS_ASSERTION(err == 0, "error ending batch");
EndBatchUpdate();
EndUpdateBatch();
return ( err == 0) ? NS_OK : NS_ERROR_FAILURE;
}
@ -2194,6 +2194,66 @@ nsGlobalHistory::GetAllResources(nsISimpleEnumerator** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsGlobalHistory::BeginUpdateBatch()
{
nsresult rv = NS_OK;
++mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->OnBeginUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
NS_IMETHODIMP
nsGlobalHistory::EndUpdateBatch()
{
nsresult rv = NS_OK;
--mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->OnEndUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
////////////////////////////////////////////////////////////////////////
@ -2235,66 +2295,6 @@ nsGlobalHistory::FlushTo(const char* aURI)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsGlobalHistory::StartBatchUpdate()
{
nsresult rv = NS_OK;
++mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->BeginUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
NS_IMETHODIMP
nsGlobalHistory::EndBatchUpdate()
{
nsresult rv = NS_OK;
--mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->EndUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
//----------------------------------------------------------------------
//
// nsGlobalHistory

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

@ -626,11 +626,9 @@ function LoadBookmarksCallback()
// loads the services
initServices();
initBMService();
var hasRead = BMSVC.readBookmarks();
BMSVC.readBookmarks();
var bt = document.getElementById("bookmarks-ptf");
if (bt) {
if (hasRead)
bt.builder.rebuild();
bt.database.AddObserver(BookmarksToolbarRDFObserver);
}
window.addEventListener("resize", BookmarksToolbar.resizeFunc, false);

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

@ -21,6 +21,7 @@
*
* Contributor(s):
* Ben Goodger <ben@netscape.com>
* Jan Varga <varga@netscape.com>
*
* 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
@ -52,8 +53,12 @@ interface nsIBookmarksService : nsISupports
const unsigned long BOOKMARK_SEARCH_TYPE = 1;
const unsigned long BOOKMARK_FIND_TYPE = 2;
const long SORT_DESCENDING = -1;
const long SORT_ASCENDING = 1;
boolean readBookmarks();
boolean isBookmarked(in string aURL);
boolean isBookmarkedResource(in nsIRDFResource aSource);
void addBookmarkImmediately(in string aURI, in wstring aTitle, in long bmType, in wstring docCharset);
@ -65,6 +70,12 @@ interface nsIBookmarksService : nsISupports
nsIRDFResource createGroupInContainer(in wstring aName, in nsIRDFResource aParentFolder,
in long aIndex);
void sortFolder(in nsIRDFResource aFolder,
in nsIRDFResource aProperty,
in long aDirection,
in boolean aFoldersFirst,
in boolean aRecurse);
nsIRDFResource createBookmark(in wstring aName,
in string aURL,
in wstring aShortcutURL,
@ -80,6 +91,8 @@ interface nsIBookmarksService : nsISupports
nsIRDFResource createSeparator();
nsIRDFResource cloneResource(in nsIRDFResource aSource);
void updateBookmarkIcon(in string aURL, in wstring aIconURL);
void removeBookmarkIcon(in string aURL, in wstring aIconURL);

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

@ -35,7 +35,7 @@
*
* ***** END LICENSE BLOCK ***** */
var NC_NS, RDF_NS, XUL_NS, NC_NS_CMD;
var NC_NS, WEB_NS, RDF_NS, XUL_NS, NC_NS_CMD;
// definition of the services frequently used for bookmarks
var kRDFContractID;
@ -68,10 +68,15 @@ var kWINDOWContractID;
var kWINDOWIID;
var WINDOWSVC;
var kDSContractID;
var kDSIID;
var DS;
// should be moved in a separate file
function initServices()
{
NC_NS = "http://home.netscape.com/NC-rdf#";
WEB_NS = "http://home.netscape.com/WEB-rdf#";
RDF_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
NC_NS_CMD = NC_NS + "command?cmd=";
@ -84,7 +89,7 @@ function initServices()
kRDFCContractID = "@mozilla.org/rdf/container;1";
kRDFCIID = Components.interfaces.nsIRDFContainer;
RDFC = Components.classes[kRDFCContractID].getService(kRDFCIID);
RDFC = Components.classes[kRDFCContractID].createInstance(kRDFCIID);
kRDFCUContractID = "@mozilla.org/rdf/container-utils;1";
kRDFCUIID = Components.interfaces.nsIRDFContainerUtils;
@ -103,6 +108,9 @@ function initServices()
kWINDOWIID = Components.interfaces.nsIWindowMediator;
WINDOWSVC = Components.classes[kWINDOWContractID].getService(kWINDOWIID);
kDSContractID = "@mozilla.org/widget/dragservice;1";
kDSIID = Components.interfaces.nsIDragService;
DS = Components.classes[kDSContractID].getService(kDSIID);
}
function initBMService()
@ -110,12 +118,8 @@ function initBMService()
kBMSVCIID = Components.interfaces.nsIBookmarksService;
BMDS = RDF.GetDataSource("rdf:bookmarks");
BMSVC = BMDS.QueryInterface(kBMSVCIID);
BookmarkInsertTransaction.prototype.RDFC = RDFC;
BookmarkInsertTransaction.prototype.BMDS = BMDS;
BookmarkRemoveTransaction.prototype.RDFC = RDFC;
BookmarkRemoveTransaction.prototype.BMDS = BMDS;
BookmarkImportTransaction.prototype.RDFC = RDFC;
BookmarkImportTransaction.prototype.BMDS = BMDS;
BookmarkTransaction.prototype.RDFC = RDFC;
BookmarkTransaction.prototype.BMDS = BMDS;
}
/**
@ -277,27 +281,27 @@ var BookmarksCommand = {
break;
case "Bookmark":
commands = ["bm_open", "bm_openinnewwindow", "bm_openinnewtab", "bm_separator",
"bm_newfolder", "bm_separator",
"bm_newfolder", "bm_sortfolder", "bm_sortfolderbyname", "bm_separator",
"bm_cut", "bm_copy", "bm_paste", "bm_movebookmark", "bm_separator",
"bm_rename", "bm_delete", "bm_separator",
"bm_properties"];
break;
case "Folder":
commands = ["bm_expandfolder", "bm_managefolder", "bm_separator",
"bm_newfolder", "bm_separator",
"bm_newfolder", "bm_sortfolder", "bm_sortfolderbyname", "bm_separator",
"bm_cut", "bm_copy", "bm_paste", "bm_movebookmark", "bm_separator",
"bm_rename", "bm_delete", "bm_separator",
"bm_properties"];
break;
case "FolderGroup":
commands = ["bm_open", "bm_expandfolder", "bm_separator",
"bm_newfolder", "bm_separator",
"bm_newfolder", "bm_sortfolder", "bm_sortfolderbyname", "bm_separator",
"bm_cut", "bm_copy", "bm_paste", "bm_movebookmark", "bm_separator",
"bm_rename", "bm_delete", "bm_separator",
"bm_properties"];
break;
case "PersonalToolbarFolder":
commands = ["bm_newfolder", "bm_separator",
commands = ["bm_newfolder", "bm_sortfolder", "bm_sortfolderbyname", "bm_separator",
"bm_cut", "bm_copy", "bm_paste", "bm_movebookmark", "bm_separator",
"bm_rename", "bm_delete", "bm_separator",
"bm_properties"];
@ -472,10 +476,7 @@ var BookmarksCommand = {
// since data are ended by \n, remove the last empty node
items.pop();
for (var i=0; i<items.length; ++i) {
var resource = RDF.GetResource(items[i]);
name = BookmarksUtils.getProperty(resource, NC_NS+"Name");
url = BookmarksUtils.getProperty(resource, NC_NS+"URL" );
items[i] = BookmarksUtils.createBookmark(name, url, null, null);
items[i] = RDF.GetResource(items[i]);
}
break;
case "text/x-moz-url":
@ -493,7 +494,7 @@ var BookmarksCommand = {
var selection = {item: items, parent:Array(items.length), length: items.length};
BookmarksUtils.checkSelection(selection);
BookmarksUtils.insertSelection("paste", selection, aTarget, true);
BookmarksUtils.insertSelection("paste", selection, aTarget);
},
deleteBookmark: function (aSelection)
@ -703,8 +704,46 @@ var BookmarksCommand = {
var selection = RDF.GetResource("NC:BookmarksRoot");
var args = [{ property: NC_NS+"URL", literal: fileName}];
this.doBookmarksCommand(selection, NC_NS_CMD+"export", args);
}
},
sortFolderByName: function(aSelection)
{
var folder;
var type = aSelection.type[0];
if (type == "Bookmark")
folder = RDF.GetResource(aSelection.parent[0].Value);
else {
folder = RDF.GetResource(aSelection.item[0].Value);
}
var property = RDF.GetResource(NC_NS + "Name");
BMDS.sortFolder(folder, property, kBMSVCIID.SORT_ASCENDING, true, false);
},
sortFolder: function(aSelection)
{
var folder;
var type = aSelection.type[0];
if (type == "Bookmark")
folder = RDF.GetResource(aSelection.parent[0].Value);
else {
folder = RDF.GetResource(aSelection.item[0].Value);
}
var sortOptions = { accepted : false };
openDialog("chrome://communicator/content/bookmarks/sortFolder.xul",
"sortFolder",
"centerscreen,chrome,dependent,resizable=no,modal=yes",
sortOptions);
if (sortOptions.accepted) {
var property = BookmarksUtils.getResource(sortOptions.sortBy);
var direction = sortOptions.sortOrder == "ascending"
? kBMSVCIID.SORT_ASCENDING : kBMSVCIID.SORT_DESCENDING;
var foldersFirst = sortOptions.sortFoldersFirst;
var recurse = sortOptions.sortRecursively;
BMDS.sortFolder(folder, property, direction, foldersFirst, recurse);
}
}
}
/////////////////////////////////////////////////////////////////////////////
@ -741,6 +780,8 @@ var BookmarksController = {
case "cmd_bm_import":
case "cmd_bm_export":
case "cmd_bm_movebookmark":
case "cmd_bm_sortfolderbyname":
case "cmd_bm_sortfolder":
isCommandSupported = true;
break;
default:
@ -753,9 +794,6 @@ var BookmarksController = {
isCommandEnabled: function (aCommand, aSelection, aTarget)
{
if (aTarget.parent.Value == "NC:BookmarksTopRoot")
return false;
var item0, type0;
var length = aSelection.length;
if (length != 0) {
@ -766,10 +804,11 @@ var BookmarksController = {
switch(aCommand) {
case "cmd_undo":
case "cmd_redo":
case "cmd_bm_undo":
return BMSVC.transactionManager.numberOfUndoItems > 0;
case "cmd_redo":
case "cmd_bm_redo":
return true;
return BMSVC.transactionManager.numberOfRedoItems > 0;
case "cmd_bm_paste":
if (!BookmarksUtils.isValidTargetContainer(aTarget.parent))
return false;
@ -793,8 +832,6 @@ var BookmarksController = {
case "cmd_bm_copy":
return length > 0;
case "cmd_bm_cut":
// disabling cut for now since we don't clone folders
return false;
case "cmd_bm_delete":
return length > 0 && aSelection.containsMutable && !aSelection.containsPTF;
case "cmd_bm_selectAll":
@ -815,6 +852,8 @@ var BookmarksController = {
return BookmarksUtils.isValidTargetContainer(aTarget.parent);
case "cmd_bm_properties":
case "cmd_bm_rename":
case "cmd_bm_sortfolderbyname":
case "cmd_bm_sortfolder":
return length == 1;
case "cmd_bm_setnewbookmarkfolder":
if (length != 1)
@ -831,7 +870,7 @@ var BookmarksController = {
return item0 != "NC:NewSearchFolder" &&
(type0 == "Folder" || type0 == "PersonalToolbarFolder");
case "cmd_bm_movebookmark":
return length > 0;
return length > 0 && !aSelection.containsRF;
default:
return false;
}
@ -905,6 +944,12 @@ var BookmarksController = {
case "cmd_bm_export":
BookmarksCommand.exportBookmarks();
break;
case "cmd_bm_sortfolderbyname":
BookmarksCommand.sortFolderByName(aSelection);
break;
case "cmd_bm_sortfolder":
BookmarksCommand.sortFolder(aSelection);
break;
default:
dump("Bookmark command "+aCommand+" not handled!\n");
}
@ -919,7 +964,9 @@ var BookmarksController = {
"cmd_bm_setpersonaltoolbarfolder",
"cmd_bm_setnewbookmarkfolder",
"cmd_bm_setnewsearchfolder", "cmd_bm_movebookmark",
"cmd_bm_managefolder"];
"cmd_bm_managefolder",
"cmd_bm_sortfolder", "cmd_bm_sortfolderbyname",
"cmd_undo", "cmd_redo", "cmd_bm_undo", "cmd_bm_redo"];
for (var i = 0; i < commands.length; ++i) {
var enabled = this.isCommandEnabled(commands[i], aSelection, aTarget);
var commandNode = document.getElementById(commands[i]);
@ -1032,6 +1079,17 @@ var BookmarksUtils = {
}
},
getResource: function (aName)
{
if (aName == "LastModifiedDate" ||
aName == "LastVisitDate") {
return RDF.GetResource(WEB_NS + aName);
}
else {
return RDF.GetResource(NC_NS + aName);
}
},
/////////////////////////////////////////////////////////////////////////////
// Determine the rdf:type property for the given resource.
resolveType: function (aResource)
@ -1103,36 +1161,6 @@ var BookmarksUtils = {
}
return null;
},
/////////////////////////////////////////////////////////////////////////////
// Returns a cloned folder a aFolder (with a different uri). folderType and
// other properties are recursively dropped except the 'folder group' one.
cloneFolder: function (aFolder)
{
var rName = this.getProperty(aFolder, NC_NS+"Name");
var newFolder;
if (this.isFolderGroup(aFolder))
newFolder = BMSVC.createGroup(rName);
else
newFolder = BMSVC.createFolder(rName);
// Now need to append kiddies.
try {
RDFC.Init(BMDS, aFolder);
var elts = RDFC.GetElements();
RDFC.Init(BMDS, newFolder);
while (elts.hasMoreElements()) {
var curr = elts.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
if (RDFCU.IsContainer(BMDS, curr))
curr = BookmarksUtils.cloneFolder(curr);
RDFC.AppendElement(curr);
}
}
catch (e) {
}
return newFolder;
},
/////////////////////////////////////////////////////////////////////////////
// Caches frequently used informations about the selection
@ -1148,6 +1176,7 @@ var BookmarksUtils = {
aSelection.isValid = new Array(aSelection.length);
aSelection.containsMutable = false;
aSelection.containsPTF = false;
aSelection.containsRF = false;
var index, item, parent, type, protocol, isContainer, isImmutable, isValid;
for (var i=0; i<aSelection.length; ++i) {
item = aSelection.item[i];
@ -1158,8 +1187,10 @@ var BookmarksUtils = {
protocol == "find" || protocol == "file";
isValid = true;
isImmutable = false;
if (item == "NC:BookmarksRoot")
if (item.Value == "NC:BookmarksRoot") {
isImmutable = true;
aSelection.containsRF = true;
}
else if (type != "Bookmark" && type != "BookmarkSeparator" &&
type != "Folder" && type != "FolderGroup" &&
type != "PersonalToolbarFolder")
@ -1184,20 +1215,13 @@ var BookmarksUtils = {
isSelectionValidForInsertion: function (aSelection, aTarget, aAction)
{
var isValid = new Array(aSelection.length);
for (var i=0; i<aSelection.length; ++i)
isValid[i] = false;
if (!BookmarksUtils.isValidTargetContainer(aTarget.parent, aSelection))
if (!BookmarksUtils.isValidTargetContainer(aTarget.parent, aSelection)) {
var isValid = new Array(aSelection.length);
for (var i=0; i<aSelection.length; ++i)
isValid[i] = false;
return isValid;
for (i=0; i<aSelection.length; ++i) {
if (!aSelection.isValid[i])
continue;
if (!BookmarksUtils.isChildOfContainer(aSelection.item[i], aTarget.parent) ||
aAction == "move" && aSelection.parent[i] == aTarget.parent ||
aSelection.isContainer[i])
isValid[i] = true;
}
return isValid;
return aSelection.isValid;
},
isSelectionValidForDeletion: function (aSelection)
@ -1236,6 +1260,8 @@ var BookmarksUtils = {
{
if (!aFolder)
return false;
if (aFolder.Value == "NC:BookmarksTopRoot")
return false;
if (aFolder.Value == "NC:BookmarksRoot")
return true;
@ -1311,7 +1337,7 @@ var BookmarksUtils = {
// kPrefSvc.setBoolPref("browser.bookmarks.import_system_favorites", false);
//}
insertSelection: function (aAction, aSelection, aTarget, aDoCopy)
insertSelection: function (aAction, aSelection, aTarget)
{
var transaction = new BookmarkInsertTransaction(aAction);
transaction.item = new Array(aSelection.length);
@ -1325,15 +1351,9 @@ var BookmarksUtils = {
for (var i=0; i<aSelection.length; ++i) {
var rSource = aSelection.item[i];
// disabling cloneFolder for now
if (aDoCopy && aSelection.isContainer[i]) {
transaction.isValid[i]=false;
SOUND.beep();
}
if (transaction.isValid[i]) {
if (aDoCopy && aSelection.isContainer[i])
rSource = BookmarksUtils.cloneFolder(rSource);
if (BMSVC.isBookmarkedResource(rSource))
rSource = BMSVC.cloneResource(rSource);
transaction.item [i] = rSource;
transaction.parent[i] = aTarget.parent;
transaction.index [i] = index++;
@ -1557,6 +1577,30 @@ var BookmarksUtils = {
}
function BookmarkTransaction()
{
}
BookmarkTransaction.prototype = {
BATCH_LIMIT : 8,
RDFC : null,
BMDS : null,
beginUpdateBatch: function()
{
if (this.item.length > this.BATCH_LIMIT) {
this.BMDS.beginUpdateBatch();
}
},
endUpdateBatch: function()
{
if (this.item.length > this.BATCH_LIMIT) {
this.BMDS.endUpdateBatch();
}
}
}
function BookmarkInsertTransaction (aAction)
{
this.wrappedJSObject = this;
@ -1570,29 +1614,34 @@ function BookmarkInsertTransaction (aAction)
BookmarkInsertTransaction.prototype =
{
__proto__: BookmarkTransaction.prototype,
isTransient: false,
RDFC : RDFC,
BMDS : BMDS,
doTransaction: function ()
{
this.beginUpdateBatch();
for (var i=0; i<this.item.length; ++i) {
if (this.isValid[i]) {
this.RDFC.Init(this.BMDS, this.parent[i]);
this.RDFC.InsertElementAt(this.item[i], this.index[i], true);
}
}
this.endUpdateBatch();
},
undoTransaction: function ()
{
this.beginUpdateBatch();
// XXXvarga Can't use |RDFC| here because it's being "reused" elsewhere.
var container = Components.classes[kRDFCContractID].createInstance(kRDFCIID);
for (var i=this.item.length-1; i>=0; i--) {
if (this.isValid[i]) {
this.RDFC.Init(this.BMDS, this.parent[i]);
this.RDFC.RemoveElementAt(this.index[i], true);
container.Init(this.BMDS, this.parent[i]);
container.RemoveElementAt(this.index[i], true);
}
}
this.endUpdateBatch();
},
redoTransaction: function ()
@ -1621,29 +1670,32 @@ function BookmarkRemoveTransaction (aAction)
BookmarkRemoveTransaction.prototype =
{
__proto__: BookmarkTransaction.prototype,
isTransient: false,
RDFC : RDFC,
BMDS : BMDS,
doTransaction: function ()
{
this.beginUpdateBatch();
for (var i=0; i<this.item.length; ++i) {
if (this.isValid[i]) {
this.RDFC.Init(this.BMDS, this.parent[i]);
this.RDFC.RemoveElementAt(this.index[i], false);
}
}
this.endUpdateBatch();
},
undoTransaction: function ()
{
this.beginUpdateBatch();
for (var i=this.item.length-1; i>=0; i--) {
if (this.isValid[i]) {
this.RDFC.Init(this.BMDS, this.parent[i]);
this.RDFC.InsertElementAt(this.item[i], this.index[i], false);
}
}
this.endUpdateBatch();
},
redoTransaction: function ()
@ -1671,13 +1723,30 @@ function BookmarkMoveTransaction (aAction, aSelection, aTarget)
BookmarkMoveTransaction.prototype =
{
__proto__: BookmarkTransaction.prototype,
isTransient: false,
beginUpdateBatch: function()
{
if (this.selection.length > this.BATCH_LIMIT) {
this.BMDS.beginUpdateBatch();
}
},
endUpdateBatch: function()
{
if (this.selection.length > this.BATCH_LIMIT) {
this.BMDS.endUpdateBatch();
}
},
doTransaction: function ()
{
this.beginUpdateBatch();
BookmarksUtils.removeSelection("move", this.selection);
BookmarksUtils.insertSelection("move", this.selection, this.target);
this.endUpdateBatch();
},
undoTransaction : function () {},
@ -1703,10 +1772,9 @@ function BookmarkImportTransaction (aAction)
BookmarkImportTransaction.prototype =
{
__proto__: BookmarkTransaction.prototype,
isTransient: false,
RDFC : RDFC,
BMDS : BMDS,
doTransaction: function ()
{
@ -1714,22 +1782,26 @@ BookmarkImportTransaction.prototype =
undoTransaction: function ()
{
this.beginUpdateBatch();
for (var i=this.item.length-1; i>=0; i--) {
if (this.isValid[i]) {
this.RDFC.Init(this.BMDS, this.parent[i]);
this.RDFC.RemoveElementAt(this.index[i], true);
}
}
this.endUpdateBatch();
},
redoTransaction: function ()
{
this.beginUpdateBatch();
for (var i=0; i<this.item.length; ++i) {
if (this.isValid[i]) {
this.RDFC.Init(this.BMDS, this.parent[i]);
this.RDFC.InsertElementAt(this.item[i], this.index[i], true);
}
}
this.endUpdateBatch();
},
merge : function (aTransaction) {return false},

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

@ -54,23 +54,21 @@ function Startup()
// always open the bookmark top root folder
if (!bookmarksView.treeBoxObject.view.isContainerOpen(0))
bookmarksView.treeBoxObject.view.toggleOpenState(0);
// XXXvarga this should go away once bug 200067 is fixed.
if (!bookmarksView.treeBoxObject.view.isContainerEmpty(0))
rowIndex = 1;
}
bookmarksView.treeBoxObject.scrollToRow(rowIndex);
bookmarksView.treeBoxObject.selection.select(rowIndex);
windowNode.setAttribute("title", titleString);
document.getElementById("CommandUpdate_Bookmarks").setAttribute("commandupdater","true");
bookmarksView.tree.focus();
}
function Shutdown ()
function Shutdown()
{
// Store current window position and size in window attributes (for persistence).
var win = document.getElementById("bookmark-window");
win.setAttribute("x", screenX);
@ -79,94 +77,6 @@ function Shutdown ()
win.setAttribute("width", outerWidth);
}
var gConstructedViewMenuSortItems = false;
function fillViewMenu(aEvent)
{
var adjacentElement = document.getElementById("fill-before-this-node");
var popupElement = aEvent.target;
var bookmarksView = document.getElementById("bookmarks-view");
var columns = bookmarksView.columns;
if (!gConstructedViewMenuSortItems) {
for (var i = 0; i < columns.length; ++i) {
var accesskey = columns[i].accesskey;
var menuitem = document.createElement("menuitem");
var name = BookmarksUtils.getLocaleString("SortMenuItem", columns[i].label);
menuitem.setAttribute("label", name);
menuitem.setAttribute("accesskey", columns[i].accesskey);
menuitem.setAttribute("resource", columns[i].resource);
menuitem.setAttribute("id", "sortMenuItem:" + columns[i].resource);
menuitem.setAttribute("checked", columns[i].sortActive);
menuitem.setAttribute("name", "sortSet");
menuitem.setAttribute("type", "radio");
popupElement.insertBefore(menuitem, adjacentElement);
}
gConstructedViewMenuSortItems = true;
}
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
if (gConstructedViewMenuSortItems) {
var resource = bookmarksSortPrefs.getCharPref("resource");
var element = document.getElementById("sortMenuItem:" + resource);
if (element)
element.setAttribute("checked", "true");
}
var sortAscendingMenu = document.getElementById("ascending");
var sortDescendingMenu = document.getElementById("descending");
var noSortMenu = document.getElementById("natural");
sortAscendingMenu.setAttribute("checked", "false");
sortDescendingMenu.setAttribute("checked", "false");
noSortMenu.setAttribute("checked", "false");
var direction = bookmarksSortPrefs.getCharPref("direction");
if (direction == "natural")
sortAscendingMenu.setAttribute("checked", "true");
else if (direction == "ascending")
sortDescendingMenu.setAttribute("checked", "true");
else
noSortMenu.setAttribute("checked", "true");
}
function onViewMenuSortItemSelected(aEvent)
{
var resource = aEvent.target.getAttribute("resource");
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
switch (resource) {
case "":
break;
case "direction":
var dirn = bookmarksSortPrefs.getCharPref("direction");
if (aEvent.target.id == "ascending")
bookmarksSortPrefs.setCharPref("direction", "natural");
else if (aEvent.target.id == "descending")
bookmarksSortPrefs.setCharPref("direction", "ascending");
else
bookmarksSortPrefs.setCharPref("direction", "descending");
break;
default:
bookmarksSortPrefs.setCharPref("resource", resource);
var direction = bookmarksSortPrefs.getCharPref("direction");
if (direction == "descending")
bookmarksSortPrefs.setCharPref("direction", "natural");
break;
}
aEvent.preventCapture();
}
var gConstructedColumnsMenuItems = false;
function fillColumnsMenu(aEvent)
{

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

@ -113,6 +113,15 @@
<key id="bm_key_find"
key="&edit.find.keybinding;"
command="cmd_bm_find" modifiers="accel"/>
<key id="bm_key_sortFolder"
key="&edit.sortFolder.keybinding;"
command="cmd_bm_sortfolder" modifiers="accel"/>
<key id="bm_key_sortFolderByName"
key="&edit.sortFolderByName.keybinding;"
command="cmd_bm_sortfolderbyname" modifiers="accel"/>
<key id="bm_key_properties"
key="&edit.properties.keybinding;"
command="cmd_bm_properties" modifiers="accel"/>
@ -140,8 +149,8 @@
</menu>
<menu id="menu_Edit">
<menupopup>
<menuitem id="menu_undo" disabled="true"/>
<menuitem id="menu_redo" disabled="true"/>
<menuitem id="menu_undo"/>
<menuitem id="menu_redo"/>
<menuseparator/>
<menuitem id="menu_bm_cut"
label="&cutCmd.label;" accesskey="&cutCmd.accesskey;"
@ -164,36 +173,35 @@
accesskey="&command.moveBookmark.accesskey;"
command="cmd_bm_movebookmark"/>
<menuseparator/>
<menuitem observes="cmd_bm_properties" key="bm_key_properties"
label="&command.properties.label;"
accesskey="&command.properties.accesskey;" />
<menuitem label="&command.sortFolder.label;"
accesskey="&command.sortFolder.accesskey;"
key="bm_key_sortFolder"
command="cmd_bm_sortfolder"/>
<menuitem label="&command.sortFolderByName.label;"
accesskey="&command.sortFolderByName.accesskey;"
key="bm_key_sortFolderByName"
command="cmd_bm_sortfolderbyname"/>
<menuseparator/>
<menuitem label="&command.properties.label;"
accesskey="&command.properties.accesskey;"
key="bm_key_properties"
command="cmd_bm_properties" />
</menupopup>
</menu>
<menu id="menu_View">
<menupopup onpopupshowing="fillViewMenu(event)"
oncommand="onViewMenuSortItemSelected(event);">
<menupopup>
<menuitem id="viewCommandToolbar" type="checkbox" class="menuitem-iconic"
label="&menuitem.view.command.toolbar.label;"
accesskey="&menuitem.view.command.toolbar.accesskey;"
oncommand="goToggleToolbar('command-toolbar', 'viewCommandToolbar'); event.preventBubble();"
persist="checked"/>
<menuseparator id="fill-after-this-node"/>
<menuitem id="natural" label="&menuitem.view.unsorted.label;"
accesskey="&menuitem.view.unsorted.accesskey;"
type="radio"
resource="direction" name="sortSet"/>
<menuseparator id="fill-before-this-node"/>
<menuitem id="ascending" label="&menuitem.view.ascending.label;"
accesskey="&menuitem.view.ascending.accesskey;"
type="radio"
resource="direction" name="sortDirectionSet"/>
<menuitem id="descending" label="&menuitem.view.descending.label;"
accesskey="&menuitem.view.descending.accesskey;"
type="radio"
resource="direction" name="sortDirectionSet"/>
<menuseparator/>
<menu id="descending" label="&menuitem.view.show_columns.label;"
checked="true"/>
<menuitem id="viewCommandSearchbar" type="checkbox" class="menuitem-iconic"
label="&menuitem.view.command.searchbar.label;"
accesskey="&menuitem.view.command.searchbar.accesskey;"
oncommand="goToggleToolbar('bookmarks-search', 'viewCommandSearchbar'); event.preventBubble();"
checked="true"/>
<menu label="&menuitem.view.show_columns.label;"
accesskey="&menuitem.view.show_columns.accesskey;">
<menupopup id="columnsPopup" onpopupshowing="fillColumnsMenu(event);"
oncommand="onViewMenuColumnItemSelected(event);"/>

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

@ -424,10 +424,8 @@ var BookmarksMenuDNDObserver = {
menuTarget.removeChild(menuTarget.lastChild.previousSibling);
}
// disabling ctrl-DND for now bookmarks are not cloned
if (aDragSession.dragAction & kCopyAction)
SOUND.beep();
//BookmarksUtils.insertSelection("drag", selection, selTarget, true);
BookmarksUtils.insertSelection("drag", selection, selTarget);
else
BookmarksUtils.moveSelection("drag", selection, selTarget);
@ -788,8 +786,13 @@ var BookmarksToolbarRDFObserver =
},
onChange: function (aDataSource, aSource, aProperty, aOldTarget, aNewTarget) {},
onMove: function (aDataSource, aOldSource, aNewSource, aProperty, aTarget) {},
beginUpdateBatch: function (aDataSource) {},
endUpdateBatch: function (aDataSource) {},
onBeginUpdateBatch: function (aDataSource) {},
onEndUpdateBatch: function (aDataSource) {
if (this._overflowTimerInEffect)
return;
this._overflowTimerInEffect = true;
setTimeout(BookmarksToolbar.resizeFunc, 0);
},
_overflowTimerInEffect: false,
setOverflowTimeout: function (aSource, aProperty)

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

@ -53,6 +53,8 @@
<command id="cmd_bm_import" oncommand="goDoCommand('cmd_bm_import');"/>
<command id="cmd_bm_export" oncommand="goDoCommand('cmd_bm_export');"/>
<command id="cmd_bm_movebookmark" oncommand="goDoCommand('cmd_bm_movebookmark');"/>
<command id="cmd_bm_sortfolder" oncommand="goDoCommand('cmd_bm_sortfolder');"/>
<command id="cmd_bm_sortfolderbyname" oncommand="goDoCommand('cmd_bm_sortfolderbyname');"/>
<command id="cmd_bm_cut" oncommand="goDoCommand('cmd_bm_cut');"/>
<command id="cmd_bm_copy" oncommand="goDoCommand('cmd_bm_copy');"/>

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

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0"?>
<!-- -*- Mode: HTML; indent-tabs-mode: nil; -*- -->
<!--
@ -51,24 +51,28 @@
BMSVC.readBookmarks();
// We implement nsIController
// Add controllers and listeners.
this.tree.controllers.appendController(this.controller);
var olb = document.getAnonymousElementByAttribute(this, "anonid", "bookmarks-tree");
olb = olb.builder.QueryInterface(Components.interfaces.nsIXULTreeBuilder);
olb.addObserver(this.builderObserver);
// XXXvarga this observer should go away once bug 120071 is fixed.
this.treeBuilder.addObserver(this.builderObserver);
this.tree.builder.addListener(this.builderListener);
BMSVC.transactionManager.AddListener(this.transactionListener);
// Load column settings from persisted attribute
var colinfostr = this.getAttribute("colinfo");
var colinfo = colinfostr.split(" ");
for (var i = 0; i < colinfo.length; ++i) {
if (colinfo[i] == "") continue;
var querymarker = colinfo[i].indexOf("?");
var anonid = colinfo[i].substring(4, querymarker);
var col = document.getAnonymousElementByAttribute(this, "id", anonid);
if (!anonid || !col) break;
var attrstring = colinfo[i].substr(querymarker + 1);
var attrpairs = attrstring.split("&");
@ -77,30 +81,19 @@
col.setAttribute(pair[0], pair[1]);
}
}
// Load sort data from preferences
this.refreshSort();
// Observe for changes in sort from other concurrent UI
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var prefs = prefSvc.getBranch(null);
const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranchInternal;
var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
bookmarksPrefsInternal.addObserver(this.sortChangedObserver.domain,
this.sortChangedObserver, false);
]]></constructor>
<destructor><![CDATA[
// Remove controllers and listeners.
BMSVC.transactionManager.RemoveListener(this.transactionListener);
this.tree.builder.removeListener(this.builderListener);
this.treeBuilder.removeObserver(this.builderObserver);
this.tree.controllers.removeController(this.controller);
// Save column settings and sort info to persisted attribute
var persistString = "";
var sortResource = NC_NS + "Name";
var sortDirection = "none";
var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
var child = treecols.firstChild;
@ -110,33 +103,14 @@
formatString = formatString.replace(/%1%/, child.getAttribute("id"));
formatString = formatString.replace(/%2%/, child.getAttribute("width"));
formatString = formatString.replace(/%3%/, child.getAttribute("hidden"));
// While we're walking the columns, if we discover the column that represents the
// field sorted by, save the resource associated with that column so that we
// can save that in prefs (see below)
if (child.getAttribute("sortActive") == "true") {
sortResource = child.getAttribute("sort");
sortDirection = child.getAttribute("sortDirection");
}
formatString = formatString.replace(/%6%/, child.getAttribute("ordinal"));
persistString += formatString;
}
}
child = child.nextSibling;
}
this.setAttribute("colinfo", persistString);
document.persist(this.id, "colinfo");
// Unhook the sort change observer for this tree
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var prefs = prefSvc.getBranch(null);
const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranchInternal;
var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
bookmarksPrefsInternal.removeObserver(this.sortChangedObserver.domain,
this.sortChangedObserver);
document.persist(this.id, "colinfo");
]]></destructor>
<property name="db">
@ -145,64 +119,6 @@
]]></getter>
</property>
<field name="sortChangedObserver">
<![CDATA[
({
outer: this,
domain: "browser.bookmarks.sort",
observe: function BMOL_sortChangedObserver(aSubject, aTopic, aPrefName)
{
if (aTopic != "nsPref:changed") return;
if (aPrefName.substr(0, this.domain.length) != this.domain) return;
this.outer.refreshSort();
}
})
]]>
</field>
<field name="sorted">false</field>
<method name="refreshSort">
<body>
<![CDATA[
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
// This ensures that we don't sort twice in the tree that is clicked on
// as a result of 1) the click and 2) the pref listener.
if (!this.sorted) {
try {
var sortResource = bookmarksSortPrefs.getCharPref("resource");
var sortDirection = bookmarksSortPrefs.getCharPref("direction");
// Walk the columns, when we find a column with a sort resource that matches the supplied
// data, stop and make sure it's sort active.
var treecols = document.getAnonymousElementByAttribute(this, "anonid", "treecols");
var child = treecols.firstChild;
while (child) {
if (child.localName != "splitter") {
if (child.getAttribute("sort") == sortResource) {
child.setAttribute("sortActive", "true");
child.setAttribute("sortDirection", sortDirection);
this.treeBuilder.sort(child, false);
break;
}
}
child = child.nextSibling;
}
}
catch (e) {
dump("error in refresh sort:"+e)
}
}
this.sorted = false;
]]>
</body>
</method>
<property name="columns">
<getter>
<![CDATA[
@ -215,8 +131,6 @@
var obj = {
label: child.getAttribute("label"),
accesskey: child.getAttribute("accesskey"),
resource: child.getAttribute("sort"),
sortActive: child.getAttribute("sortActive") == "true",
hidden: child.getAttribute("hidden")
}
cols.push(obj);
@ -377,95 +291,51 @@
</method>
<!--
This function saves the current selection state before the tree is rebuilt
following a command execution. This allows us to remember which item(s)
was/were selected so that the user does not need to constantly refocus the
tree to perform a sequence of commands.
This function saves the current selection state before the tree is
rebuilt.
-->
<field name="_savedSelection">[]</field>
<method name="saveSelection">
<body><![CDATA[
this._savedSelection = [];
var selection = this.treeBoxObject.view.selection;
var rangeCount = selection.getRangeCount();
var ranges = [];
var min = {}; var max = {};
for (var i = 0; i < rangeCount; ++i) {
selection.getRangeAt(i, min, max);
ranges.push({min: min.value, max: max.value});
if (selection) {
var rangeCount = selection.getRangeCount();
var min = {}; var max = {};
for (var i = 0; i < rangeCount; ++i) {
selection.getRangeAt(i, min, max);
for (var j = min.value; j <= max.value; ++j) {
var resource = this.treeBuilder.getResourceAtIndex(j);
this._savedSelection.push(resource);
}
}
}
this._savedSelection = ranges;
]]></body>
</method>
<!--
This function restores the selection appropriately after a command executes.
This is necessary because most commands trigger a rebuild of the tree which
destroys the selection. The restoration of selection is handled in three
different ways depending on the type of command that has been executed:
1) Commands that remove rows:
The row immediately after the first range in the selection is selected,
if there is no row immediately after the first range the item before it
is selected
2) Commands that insert rows:
The newly inserted rows are selected
3) Commands that do not change the row count
The row(s) that was/were operated on remain selected.
The calls to save/restore are placed in the doCommand method and thus all
commands must pass through this gate. The result is that this method becomes
the POLICY CENTER FOR POST-VIEW/EDIT SELECTION CHANGES.
This function restores the selection appropriately after the tree has
been rebuilt.
-->
<method name="restoreSelection">
<parameter name="aCommand"/>
<body><![CDATA[
var oldRanges = this._savedSelection;
var newRanges = [];
var selection = this.treeBoxObject.view.selection;
if (selection) {
selection.selectEventsSuppressed = true;
switch(aCommand) {
// [Category 1] - Commands that remove rows
case "cmd_bm_cut":
case "cmd_bm_delete":
// Since rows have been removed, the row immediately after the first range
// in the original selection now has the index of the first item in the first
// range.
var nextRow = oldRanges[0].min;
newRanges.push({min: nextRow, max: nextRow});
break;
// [Category 2] - Commands that insert rows
case "cmd_bm_paste":
case "cmd_bm_import":
case "cmd_bm_movebookmark":
case "cmd_bm_newbookmark":
case "cmd_bm_newfolder":
case "cmd_bm_newseparator":
// [Category 2 bis] - Temporary hack
case "cmd_undo":
case "cmd_redo":
// All items inserted will be selected. The implementation of this model
// is left to |preUpdateTreeSelection|, called when an insert transaction is
// executed, and |updateTreeSelection| called here.
this.updateTreeSelection();
break;
// [Category 3] - Commands that do not alter the row count
case "cmd_bm_copy":
case "cmd_bm_properties":
case "cmd_bm_rename":
case "cmd_bm_setnewbookmarkfolder":
case "cmd_bm_setpersonaltoolbarfolder":
case "cmd_bm_setnewsearchfolder":
case "cmd_bm_export":
default:
// The selection is unchanged.
newRanges = oldRanges;
break;
selection.clearSelection();
for (var i = 0; i < this._savedSelection.length; ++i) {
var index = this.treeBuilder.getIndexOfResource(this._savedSelection[i]);
if (index >= 0) {
selection.toggleSelect(index);
}
}
selection.selectEventsSuppressed = false;
}
var newSelection = this.treeBoxObject.view.selection;
for (i = 0; i < newRanges.length; ++i)
newSelection.rangedSelect(newRanges[i].min, newRanges[i].max, true);
]]></body>
</method>
<field name="_itemToBeToggled"> []</field>
<field name="_parentToBeToggled">[]</field>
<method name="preUpdateTreeSelection">
@ -488,7 +358,7 @@
this.treeBoxObject.selection.clearSelection();
for (var i=0; i<this._itemToBeToggled.length; ++i) {
index = this.treeBuilder.getIndexOfResource(this._itemToBeToggled[i]);
if (index != -1 && !this.treeBoxObject.selection.isSelected(index))
if (index >=0)
this.treeBoxObject.selection.toggleSelect(index);
}
]]></body>
@ -572,14 +442,44 @@
]]></body>
</method>
<method name="sortBookmarks">
<parameter name="aColumn"/>
<parameter name="aReverse"/>
<body><![CDATA[
var confirmed;
if (PREF.getBoolPref("browser.bookmarks.confirm_sorting")) {
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var title = BookmarksUtils.getLocaleString("confirm_sorting_title");
var message = BookmarksUtils.getLocaleString("confirm_sorting_message");
var checkMessage = BookmarksUtils.getLocaleString("confirm_sorting_check_message");
var checkValue = {};
confirmed = promptService.confirmCheck(window, title, message,
checkMessage, checkValue);
if (checkValue.value) {
PREF.setBoolPref("browser.bookmarks.confirm_sorting", false);
}
}
else {
confirmed = true;
}
if (confirmed) {
var folder = RDF.GetResource("NC:BookmarksRoot");
var property = BookmarksUtils.getResource(aColumn);
var direction =
aReverse ? kBMSVCIID.SORT_DESCENDING : kBMSVCIID.SORT_ASCENDING;
var foldersFirst = aColumn == "Name";
BMDS.sortFolder(folder, property, direction, foldersFirst, true);
}
]]></body>
</method>
<!-- observer -->
<field name="DNDObserver" readonly="true"><![CDATA[
({
mOuter: this,
onDragStart: function (aEvent, aXferData, aDragAction)
{
if (this.mOuter.tree.getAttribute("sortActive") == "true")
throw Components.results.NS_OK;
var selection = this.mOuter._selection;
aXferData.data = BookmarksUtils.getXferDataFromSelection(selection);
const kDSIID = Components.interfaces.nsIDragService;
@ -608,33 +508,46 @@
{
var selection = this.mOuter._selection;
var target = this.mOuter._target;
this.mOuter.treeBoxObject.selection.selectEventsSuppressed = true;
switch (aCommand) {
case "cmd_bm_selectAll":
this.mOuter.treeBoxObject.selection.selectAll();
break;
case "cmd_bm_expandfolder":
this.mOuter.treeBoxObject.view.toggleOpenState(this.mOuter.currentIndex);
break;
default:
// Notify the datasource that we're about to begin a batch operation
var observer = this.mOuter.tree.builder.QueryInterface(Components.interfaces.nsIRDFObserver);
observer.beginUpdateBatch(this.db);
BookmarksController.doCommand(aCommand, selection, target);
observer.endUpdateBatch(this.db);
this.mOuter.saveSelection();
var firstVisibleRow = this.mOuter.treeBoxObject.getFirstVisibleRow()
this.mOuter.treeBoxObject.selection.currentIndex=-1;
this.mOuter.tree.builder.rebuild();
// temporary hack: for an unknown reason, rebuilding cause a scroll to the bottom
// if the first visible row is not 0
this.mOuter.treeBoxObject.scrollToRow(firstVisibleRow);
this.mOuter.restoreSelection(aCommand);
// Commands that insert rows
case "cmd_bm_newfolder":
case "cmd_bm_newbookmark":
case "cmd_bm_newseparator":
case "cmd_bm_import":
case "cmd_bm_movebookmark":
case "cmd_bm_paste":
// XXXvarga undo/redo can insert or remove rows.
case "cmd_undo":
case "cmd_redo":
// All items inserted will be selected. The implementation of
// this model is left to |preUpdateTreeSelection|, called when
// an insert transaction is executed, and |updateTreeSelection|
// called here.
BookmarksController.doCommand(aCommand, selection, target);
this.mOuter.updateTreeSelection();
break;
// Commands that remove rows
case "cmd_bm_cut":
case "cmd_bm_delete":
// Since rows have been removed, the row immediately after the
// first range in the original selection now has the index of
// the first item in the first range.
var s = this.mOuter.treeBoxObject.selection;
rangeMin = {};
rangeMax = {};
s.getRangeAt(0, rangeMin, rangeMax);
BookmarksController.doCommand(aCommand, selection, target);
s.select(rangeMin.value);
break;
case "cmd_bm_expandfolder":
this.mOuter.treeBoxObject.view.toggleOpenState(this.mOuter.currentIndex);
break;
case "cmd_bm_selectAll":
this.mOuter.treeBoxObject.selection.selectAll();
break;
default:
BookmarksController.doCommand(aCommand, selection, target);
}
this.mOuter.treeBoxObject.selection.selectEventsSuppressed = false;
}
})
]]></field>
@ -659,10 +572,21 @@
mOuter: this,
canDropOn: function(index)
{
return true;
var dragSession = DS.getCurrentSession();
if (!dragSession)
return false;
var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
return !selection.containsRF;
},
canDropBeforeAfter: function(index, before)
{
var dragSession = DS.getCurrentSession();
if (!dragSession)
return false;
var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
if (selection.containsRF)
return false;
if (index != 0)
return true;
if (this.mOuter.getRowResource(index).Value != "NC:BookmarksRoot")
@ -671,8 +595,7 @@
},
onDrop: function(row, orientation)
{
var dragService = Components.classes["@mozilla.org/widget/dragservice;1"].getService().QueryInterface(Components.interfaces.nsIDragService);
var dragSession = dragService.getCurrentSession();
var dragSession = DS.getCurrentSession();
if (!dragSession)
return;
var selection = BookmarksUtils.getSelectionFromXferData(dragSession);
@ -689,10 +612,8 @@
}
const kDSIID = Components.interfaces.nsIDragService;
const kCopyAction = kDSIID.DRAGDROP_ACTION_COPY + kDSIID.DRAGDROP_ACTION_LINK;
// disabling ctrl-DND for now bookmarks are not cloned
if (dragSession.dragAction & kCopyAction)
SOUND.beep();
//BookmarksUtils.insertSelection("drag", selection, target, true);
BookmarksUtils.insertSelection("drag", selection, target);
else
BookmarksUtils.moveSelection ("drag", selection, target);
},
@ -710,19 +631,7 @@
}
},
onCycleHeader: function (aColumnID, aHeaderElement)
{
const kPrefSvcContractID = "@mozilla.org/preferences;1";
const kPrefSvcIID = Components.interfaces.nsIPrefService;
var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
var bookmarksSortPrefs = prefSvc.getBranch("browser.bookmarks.sort.");
// Sorted! http://www.sorted.org.nz/
this.mOuter.sorted = true;
bookmarksSortPrefs.setCharPref("resource", aHeaderElement.getAttribute("sort"));
bookmarksSortPrefs.setCharPref("direction", aHeaderElement.getAttribute("sortDirection"));
},
onCycleHeader: function (aColumnID, aHeaderElement) {},
onSelectionChanged: function ()
{
@ -757,8 +666,23 @@
})
]]></field>
<!-- nsIXULBuilderListener -->
<field name="builderListener"><![CDATA[
({
mOuter: this,
willRebuild: function(aBuilder) {
this.mOuter.saveSelection();
},
didRebuild: function(aBuilder) {
this.mOuter.restoreSelection();
}
})
]]></field>
<!-- nsITransactionManager listener -->
<field name="bookmarkTreeTransactionListener"><![CDATA[
<field name="transactionListener"><![CDATA[
({
mOuter: this,
@ -862,42 +786,43 @@
</treechildren>
</rule>
</template>
<treecols anonid="treecols">
<treecol id="Name" label="&treecol.name.label;" flex="1" primary="true"
class="sortDirectionIndicator"
persist="width hidden ordinal"
sort="rdf:http://home.netscape.com/NC-rdf#Name"
sortActive="true" sortDirection="none"/>
<treecols anonid="treecols" onclick="if (event.target.localName == 'treecol') this.parentNode.parentNode.parentNode.sortBookmarks(event.target.id, event.ctrlKey || event.metaKey)">
<treecol id="Name" flex="1" primary="true"
label="&treecol.name.label;"
tooltiptext="&treecol.name.tooltip;"
sort="rdf:http://home.netscape.com/NC-rdf#Name"
sortActive="true" sortLocked="true"
persist="width hidden ordinal"/>
<splitter class="tree-splitter" />
<treecol id="URL" label="&treecol.url.label;"
flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#URL"
persist="width hidden ordinal" />
<treecol id="URL" flex="1"
label="&treecol.url.label;"
tooltiptext="&treecol.url.tooltip;"
persist="width hidden ordinal"/>
<splitter class="tree-splitter" />
<treecol id="ShortcutURL" label="&treecol.shortcut.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
persist="hidden width ordinal"
sort="rdf:http://home.netscape.com/NC-rdf#ShortcutURL"/>
<treecol id="ShortcutURL" flex="1" hidden="true"
label="&treecol.shortcut.label;"
tooltiptext="&treecol.shortcut.tooltip;"
persist="hidden width ordinal"/>
<splitter class="tree-splitter"/>
<treecol id="Description" label="&treecol.description.label;"
flex="1" class="sortDirectionIndicator"
persist="hidden width ordinal"
sort="rdf:http://home.netscape.com/NC-rdf#Description"/>
<treecol id="Description" flex="1"
label="&treecol.description.label;"
tooltiptext="&treecol.description.tooltip;"
persist="hidden width ordinal"/>
<splitter class="tree-splitter"/>
<treecol id="AddDate" label="&treecol.addedon.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/NC-rdf#BookmarkAddDate"
persist="width hidden ordinal" />
<treecol id="BookmarkAddDate" flex="1" hidden="true"
label="&treecol.addedon.label;"
tooltiptext="&treecol.addedon.tooltip;"
persist="width hidden ordinal"/>
<splitter class="tree-splitter" />
<treecol id="LastModDate" label="&treecol.lastmod.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/WEB-rdf#LastModifiedDate"
persist="width hidden ordinal" />
<treecol id="LastModifiedDate" flex="1" hidden="true"
label="&treecol.lastmod.label;"
tooltiptext="&treecol.lastmod.tooltip;"
persist="width hidden ordinal"/>
<splitter class="tree-splitter" />
<treecol id="LastVisitDate" label="&treecol.lastvisit.label;"
hidden="true" flex="1" class="sortDirectionIndicator"
sort="rdf:http://home.netscape.com/WEB-rdf#LastVisitDate"
persist="width hidden ordinal" />
<treecol id="LastVisitDate" flex="1" hidden="true"
label="&treecol.lastvisit.label;"
tooltiptext="&treecol.lastvisit.tooltip;"
persist="width hidden ordinal"/>
</treecols>
</tree>
<statusbar class="chromeclass-status" xbl:inherits="hidden=hidestatusbar" hidden="false">
@ -906,13 +831,6 @@
</vbox>
</xbl:content>
<implementation>
<constructor>
// Adding the transaction listener
BMSVC.transactionManager.AddListener(this.bookmarkTreeTransactionListener);
</constructor>
<destructor>
BMSVC.transactionManager.RemoveListener(this.bookmarkTreeTransactionListener);
</destructor>
<field name="clickCount">2</field>
</implementation>
</binding>
@ -963,7 +881,7 @@
<treecols anonid="treecols">
<treecol id="Name" flex="1" primary="true" hideheader="true"
sort="rdf:http://home.netscape.com/NC-rdf#Name"
sortActive="true" sortDirection="none"/>
sortActive="true" sortLocked="true"/>
</treecols>
</tree>
</xbl:content>
@ -993,7 +911,7 @@
<treecols anonid="treecols">
<treecol id="Name" flex="1" primary="true" hideheader="true"
sort="rdf:http://home.netscape.com/NC-rdf#Name"
sortActive="true" sortDirection="none"/>
sortActive="true" sortLocked="true"/>
</treecols>
</tree>
</xbl:content>

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

@ -33,11 +33,14 @@ comm.jar:
content/communicator/bookmarks/bm-panel.js
content/communicator/bookmarks/findBookmark.xul
content/communicator/bookmarks/findBookmark.js
content/communicator/bookmarks/sortFolder.xul
content/communicator/bookmarks/sortFolder.js
en-US.jar:
locale/en-US/communicator/bookmarks/addBookmark.dtd (locale/en-US/addBookmark.dtd)
locale/en-US/communicator/bookmarks/bm-props.dtd (locale/en-US/bm-props.dtd)
locale/en-US/communicator/bookmarks/bookmarks.dtd (locale/en-US/bookmarks.dtd)
locale/en-US/communicator/bookmarks/bookmarks.properties (locale/en-US/bookmarks.properties)
locale/en-US/communicator/bookmarks/bookmarks.properties (locale/en-US/bookmarks.properties)
locale/en-US/communicator/bookmarks/bookmarksOverlay.dtd (locale/en-US/bookmarksOverlay.dtd)
locale/en-US/communicator/bookmarks/findBookmark.dtd (locale/en-US/findBookmark.dtd)
locale/en-US/communicator/bookmarks/sortFolder.dtd (locale/en-US/sortFolder.dtd)

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

@ -57,17 +57,19 @@
<!ENTITY command.moveBookmark.accesskey "M">
<!ENTITY command.addBookmark.label "Add...">
<!ENTITY command.manageBookmarks.label "Manage">
<!ENTITY command.sortFolder.label "Sort Folder...">
<!ENTITY command.sortFolder.accesskey "S">
<!ENTITY edit.sortFolder.keybinding "S">
<!ENTITY command.sortFolderByName.label "Sort Folder by Name">
<!ENTITY command.sortFolderByName.accesskey "N">
<!ENTITY edit.sortFolderByName.keybinding "N">
<!ENTITY menuitem.view.command.toolbar.label "Toolbar">
<!ENTITY menuitem.view.command.toolbar.accesskey "t">
<!ENTITY menuitem.view.unsorted.label "Unsorted">
<!ENTITY menuitem.view.unsorted.accesskey "u">
<!ENTITY menuitem.view.ascending.label "A > Z Sort Order">
<!ENTITY menuitem.view.ascending.accesskey "a">
<!ENTITY menuitem.view.descending.label "Z > A Sort Order">
<!ENTITY menuitem.view.descending.accesskey "z">
<!ENTITY menuitem.view.command.searchbar.label "Search bar">
<!ENTITY menuitem.view.command.searchbar.accesskey "S">
<!ENTITY menuitem.view.show_columns.label "Show columns">
<!ENTITY menuitem.view.show_columns.accesskey "S">
<!ENTITY menuitem.view.show_columns.accesskey "c">
<!ENTITY menuitem.newbookmarkfolder.label "Set as New Bookmark Folder">
<!ENTITY menuitem.newbookmarkfolder.accesskey "b">
<!ENTITY menuitem.newinternetsearchfolder.label "Set as New Internet Search Folder">
@ -77,18 +79,25 @@
<!ENTITY treecol.name.label "Name">
<!ENTITY treecol.name.accesskey "n">
<!ENTITY treecol.name.tooltip "Click to sort by name">
<!ENTITY treecol.url.label "Location">
<!ENTITY treecol.url.accesskey "l">
<!ENTITY treecol.url.tooltip "Click to sort by location">
<!ENTITY treecol.shortcut.label "Keyword">
<!ENTITY treecol.shortcut.accesskey "k">
<!ENTITY treecol.addedon.label "Added">
<!ENTITY treecol.addedon.accesskey "a">
<!ENTITY treecol.lastmod.label "Last Modified">
<!ENTITY treecol.lastmod.accesskey "m">
<!ENTITY treecol.lastvisit.label "Last Visited">
<!ENTITY treecol.lastvisit.accesskey "b">
<!ENTITY treecol.shortcut.tooltip "Click to sort by keyword">
<!ENTITY treecol.description.label "Description">
<!ENTITY treecol.description.accesskey "d">
<!ENTITY treecol.description.tooltip "Click to sort by description">
<!ENTITY treecol.addedon.label "Added">
<!ENTITY treecol.addedon.accesskey "a">
<!ENTITY treecol.addedon.tooltip "Click to sort by added">
<!ENTITY treecol.lastmod.label "Last Modified">
<!ENTITY treecol.lastmod.accesskey "m">
<!ENTITY treecol.lastmod.tooltip "Click to sort by last modified">
<!ENTITY treecol.lastvisit.label "Last Visited">
<!ENTITY treecol.lastvisit.accesskey "b">
<!ENTITY treecol.lastvisit.tooltip "Click to sort by last visit">
<!ENTITY bookmarksWindowTitle.label "Bookmark Manager">

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

@ -41,6 +41,8 @@ cmd_bm_selectAll = Select All
cmd_bm_rename = Rename...
cmd_bm_renamebookmark2 = Change Location...
cmd_bm_properties = Properties
cmd_bm_sortfolderbyname = Sort Folder by Name
cmd_bm_sortfolder = Sort Folder...
cmd_bm_openinnewwindow = Open in New Window
cmd_bm_openinnewtab = Open in New Tab
@ -90,3 +92,6 @@ EnterExport = Export bookmark file:
search_button_label = Find
confirm_sorting_title = Confirm
confirm_sorting_message = If you sort this list, you will not be able to Undo it. Are you sure you want to sort the list?
confirm_sorting_check_message = Don't ask me this again

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

@ -0,0 +1,20 @@
<!ENTITY window.title "Sort Folder">
<!ENTITY sortOptions.label "Sort options">
<!ENTITY description.label "&brandShortName; can sort individual folders. Use these options to customize the sorting for this Folder.">
<!ENTITY sortBy.label "Sort by:">
<!ENTITY sortBy.name.label "Name">
<!ENTITY sortBy.url.label "Location">
<!ENTITY sortBy.shortcutUrl.label "Keyword">
<!ENTITY sortBy.description.label "Description">
<!ENTITY sortBy.bookmarkAddDate.label "Added">
<!ENTITY sortBy.lastModifiedDate.label "Last Modified">
<!ENTITY sortBy.lastVisitDate.label "Last Visited">
<!ENTITY sortOrder.label "Sort order:">
<!ENTITY sortOrder.ascending.label "A > Z">
<!ENTITY sortOrder.descending.label "Z > A">
<!ENTITY sortFoldersFirst.label "Sort folders first">
<!ENTITY sortRecursively.label "Sort recursively">

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

@ -0,0 +1,51 @@
/* ***** 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 mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jan Varga <varga@netscape.com>
*
* 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 ***** */
function onAccept() {
var sortOptions = window.arguments[0];
sortOptions.accepted = true;
sortOptions.sortBy = document.getElementById("sortBy").value;
sortOptions.sortOrder = document.getElementById("sortOrder").value;
sortOptions.sortFoldersFirst = document.getElementById("sortFoldersFirst").checked;
sortOptions.sortRecursively = document.getElementById("sortRecursively").checked;
}
function onSortByChanged() {
var sortBy = document.getElementById("sortBy");
var sortFoldersFirst = document.getElementById("sortFoldersFirst");
sortFoldersFirst.checked = sortBy.value == "Name";
}

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

@ -0,0 +1,113 @@
<?xml version="1.0"?>
<!-- ***** 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 mozilla.org code.
-
- The Initial Developer of the Original Code is
- Netscape Communications Corp.
- Portions created by the Initial Developer are Copyright (C) 2003
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Jan Varga <varga@netscape.com>
-
- 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 LGPL or the GPL. 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 ***** -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE dialog [
<!ENTITY % brandDTD SYSTEM "chrome://global/locale/brand.dtd" >
%brandDTD;
<!ENTITY % sortFolderDTD SYSTEM "chrome://communicator/locale/bookmarks/sortFolder.dtd">
%sortFolderDTD;
]>
<dialog id="sortFolder"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&window.title;"
style="width: 30em;"
buttons="accept,cancel"
ondialogaccept="return onAccept();">
<script type="application/x-javascript" src="chrome://communicator/content/bookmarks/sortFolder.js"/>
<tabbox>
<tabs>
<tab label="&sortOptions.label;"/>
</tabs>
<tabpanels>
<vbox>
<separator class="thin"/>
<hbox align="start">
<image class="message-icon"/>
<separator class="thin" orient="vertical"/>
<description flex="1">
&description.label;
</description>
</hbox>
<separator class="thin"/>
<grid>
<columns>
<column/>
<column flex="1"/>
</columns>
<rows>
<row align="center">
<label value="&sortBy.label;"/>
<menulist id="sortBy" oncommand="onSortByChanged()">
<menupopup>
<menuitem value="Name" label="&sortBy.name.label;"/>
<menuitem value="URL" label="&sortBy.url.label;"/>
<menuitem value="ShortcutURL" label="&sortBy.shortcutUrl.label;"/>
<menuitem value="Description" label="&sortBy.description.label;"/>
<menuitem value="BookmarkAddDate" label="&sortBy.bookmarkAddDate.label;"/>
<menuitem value="LastModifiedDate" label="&sortBy.lastModifiedDate.label;"/>
<menuitem value="LastVisitDate" label="&sortBy.lastVisitDate.label;"/>
</menupopup>
</menulist>
</row>
<row align="center">
<label value="&sortOrder.label;"/>
<menulist id="sortOrder">
<menupopup>
<menuitem value="ascending" label="&sortOrder.ascending.label;"/>
<menuitem value="descending" label="&sortOrder.descending.label;"/>
</menupopup>
</menulist>
</row>
</rows>
</grid>
<separator class="thin"/>
<checkbox id="sortFoldersFirst" label="&sortFoldersFirst.label;"
checked="true"/>
<checkbox id="sortRecursively" label="&sortRecursively.label;"/>
<separator class="thin"/>
</vbox>
</tabpanels>
</tabbox>
</dialog>

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

@ -45,6 +45,7 @@ REQUIRES = xpcom \
windowwatcher \
unicharutil \
txmgr \
locale \
$(NULL)
CPPSRCS = nsBookmarksService.cpp

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

@ -85,6 +85,14 @@
#include "nsIPlatformCharset.h"
#include "nsIPref.h"
// for sorting
#include "nsCollationCID.h"
#include "nsILocaleService.h"
#include "nsICollation.h"
#include "nsVoidArray.h"
#include "nsUnicharUtils.h"
#ifdef XP_WIN
#include <SHLOBJ.H>
#include <INTSHCUT.H>
@ -123,6 +131,8 @@ nsIRDFResource *kWEB_LastPingModDate;
nsIRDFResource *kWEB_LastCharset;
nsIRDFResource *kWEB_LastPingContentLen;
nsIRDFLiteral *kTrueLiteral;
nsIRDFLiteral *kEmptyLiteral;
nsIRDFDate *kEmptyDate;
nsIRDFResource *kNC_Parent;
nsIRDFResource *kNC_BookmarkCommand_NewBookmark;
nsIRDFResource *kNC_BookmarkCommand_NewFolder;
@ -153,6 +163,7 @@ static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
static NS_DEFINE_CID(kPlatformCharsetCID, NS_PLATFORMCHARSET_CID);
static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
#define URINC_BOOKMARKS_TOPROOT_STRING "NC:BookmarksTopRoot"
#define URINC_BOOKMARKS_ROOT_STRING "NC:BookmarksRoot"
@ -174,6 +185,7 @@ PRInt32 gRefCnt=0;
nsIRDFService *gRDF;
nsIRDFContainerUtils *gRDFC;
nsICharsetAlias *gCharsetAlias;
nsICollation *gCollation;
PRBool gLoadedBookmarks = PR_FALSE;
PRBool gImportedSystemBookmarks = PR_FALSE;
@ -204,6 +216,18 @@ bm_AddRefGlobals()
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get charset alias service");
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsILocaleService> ls = do_GetService(NS_LOCALESERVICE_CONTRACTID);
if (ls) {
nsCOMPtr<nsILocale> locale;
ls->GetApplicationLocale(getter_AddRefs(locale));
if (locale) {
nsCOMPtr<nsICollationFactory> factory = do_CreateInstance(kCollationFactoryCID);
if (factory) {
factory->CreateCollation(locale, &gCollation);
}
}
}
gRDF->GetResource(NS_LITERAL_CSTRING(kURINC_BookmarksTopRoot),
&kNC_BookmarksTopRoot);
gRDF->GetResource(NS_LITERAL_CSTRING(kURINC_BookmarksRoot),
@ -276,6 +300,10 @@ bm_AddRefGlobals()
gRDF->GetLiteral(NS_LITERAL_STRING("true").get(), &kTrueLiteral);
gRDF->GetLiteral(NS_LITERAL_STRING("").get(), &kEmptyLiteral);
gRDF->GetDateLiteral(0, &kEmptyDate);
gRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=newbookmark"),
&kNC_BookmarkCommand_NewBookmark);
gRDF->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "command?cmd=newfolder"),
@ -327,6 +355,8 @@ bm_ReleaseGlobals()
gCharsetAlias = nsnull;
}
NS_IF_RELEASE(gCollation);
NS_IF_RELEASE(kNC_Bookmark);
NS_IF_RELEASE(kNC_BookmarkSeparator);
NS_IF_RELEASE(kNC_BookmarkAddDate);
@ -353,6 +383,8 @@ bm_ReleaseGlobals()
NS_IF_RELEASE(kWEB_LastVisitDate);
NS_IF_RELEASE(kNC_Parent);
NS_IF_RELEASE(kTrueLiteral);
NS_IF_RELEASE(kEmptyLiteral);
NS_IF_RELEASE(kEmptyDate);
NS_IF_RELEASE(kWEB_Schedule);
NS_IF_RELEASE(kWEB_ScheduleActive);
NS_IF_RELEASE(kWEB_Status);
@ -1574,6 +1606,71 @@ BookmarkParser::setFolderHint(nsIRDFResource *newSource, nsIRDFResource *objType
}
class SortInfo {
public:
SortInfo(PRInt32 aDirection, PRBool aFoldersFirst)
: mDirection(aDirection),
mFoldersFirst(aFoldersFirst) {
}
protected:
PRInt32 mDirection;
PRBool mFoldersFirst;
friend class nsBookmarksService;
};
class ElementInfo {
public:
ElementInfo(nsIRDFResource* aElement, nsIRDFNode* aNode, PRBool aIsFolder)
: mElement(aElement), mNode(aNode), mIsFolder(aIsFolder) {
}
protected:
nsCOMPtr<nsIRDFResource> mElement;
nsCOMPtr<nsIRDFNode> mNode;
PRBool mIsFolder;
friend class nsBookmarksService;
};
// Note, that elements are deleted only when the array goes away.
// Any call on this array that would result in an element being removed or
// replaced should make sure that the element gets deleted.
class ElementArray : public nsAutoVoidArray
{
public:
virtual ~ElementArray();
ElementInfo* ElementAt(PRInt32 aIndex) const {
return NS_STATIC_CAST(ElementInfo*, nsAutoVoidArray::ElementAt(aIndex));
}
ElementInfo* operator[](PRInt32 aIndex) const {
return ElementAt(aIndex);
}
void Clear();
};
ElementArray::~ElementArray()
{
Clear();
}
void
ElementArray::Clear()
{
PRInt32 index = Count();
while (--index >= 0)
{
ElementInfo* elementInfo = ElementAt(index);
delete elementInfo;
}
nsAutoVoidArray::Clear();
}
////////////////////////////////////////////////////////////////////////
// nsBookmarksService implementation
@ -2513,10 +2610,11 @@ nsBookmarksService::Release()
}
}
NS_IMPL_QUERY_INTERFACE8(nsBookmarksService,
NS_IMPL_QUERY_INTERFACE9(nsBookmarksService,
nsIBookmarksService,
nsIRDFDataSource,
nsIRDFRemoteDataSource,
nsIRDFPropagatableDataSource,
nsIRDFObserver,
nsIStreamListener,
nsIRequestObserver,
@ -2637,6 +2735,245 @@ nsBookmarksService::CreateGroupInContainer(const PRUnichar* aName,
return rv;
}
int
nsBookmarksService::Compare(const void* aElement1, const void* aElement2, void* aData)
{
const ElementInfo* elementInfo1 =
NS_STATIC_CAST(ElementInfo*, NS_CONST_CAST(void*, aElement1));
const ElementInfo* elementInfo2 =
NS_STATIC_CAST(ElementInfo*, NS_CONST_CAST(void*, aElement2));
SortInfo* sortInfo = (SortInfo*)aData;
if (sortInfo->mFoldersFirst) {
if (elementInfo1->mIsFolder) {
if (!elementInfo2->mIsFolder) {
return -1;
}
}
else {
if (elementInfo2->mIsFolder) {
return 1;
}
}
}
PRInt32 result = 0;
nsIRDFNode* node1 = elementInfo1->mNode;
nsIRDFNode* node2 = elementInfo2->mNode;
// Literals?
nsCOMPtr<nsIRDFLiteral> literal1 = do_QueryInterface(node1);
if (literal1) {
nsCOMPtr<nsIRDFLiteral> literal2 = do_QueryInterface(node2);
if (literal2) {
const PRUnichar* value1;
literal1->GetValueConst(&value1);
const PRUnichar* value2;
literal2->GetValueConst(&value2);
if (gCollation) {
gCollation->CompareString(kCollationCaseInSensitive,
nsDependentString(value1),
nsDependentString(value2),
&result);
}
else {
result = ::Compare(nsDependentString(value1),
nsDependentString(value2),
nsCaseInsensitiveStringComparator());
}
return result * sortInfo->mDirection;
}
}
// Dates?
nsCOMPtr<nsIRDFDate> date1 = do_QueryInterface(node1);
if (date1) {
nsCOMPtr<nsIRDFDate> date2 = do_QueryInterface(node2);
if (date2) {
PRTime value1;
date1->GetValue(&value1);
PRTime value2;
date2->GetValue(&value2);
PRInt64 delta;
LL_SUB(delta, value1, value2);
if (LL_IS_ZERO(delta))
result = 0;
else if (LL_GE_ZERO(delta))
result = 1;
else
result = -1;
return result * sortInfo->mDirection;
}
}
// Ack! Apples & oranges.
return 0;
}
nsresult
nsBookmarksService::Sort(nsIRDFResource* aFolder, nsIRDFResource* aProperty,
PRInt32 aDirection, PRBool aFoldersFirst,
PRBool aRecurse)
{
nsresult rv;
nsCOMPtr<nsIRDFContainer> container =
do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
if (NS_FAILED(rv))
return rv;
rv = container->Init(mInner, aFolder);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsISimpleEnumerator> elements;
rv = container->GetElements(getter_AddRefs(elements));
if (NS_FAILED(rv))
return rv;
ElementArray elementArray;
PRBool hasMore = PR_FALSE;
while (NS_SUCCEEDED(rv = elements->HasMoreElements(&hasMore)) &&
hasMore) {
nsCOMPtr<nsISupports> supports;
rv = elements->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFResource> element = do_QueryInterface(supports, &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFNode> node;
rv = mInner->GetTarget(element, aProperty, PR_TRUE, getter_AddRefs(node));
if (NS_FAILED(rv))
return rv;
if (!node) {
if (aProperty == kNC_BookmarkAddDate ||
aProperty == kWEB_LastModifiedDate ||
aProperty == kWEB_LastVisitDate) {
node = do_QueryInterface(kEmptyDate);
}
else {
node = do_QueryInterface(kEmptyLiteral);
}
}
PRBool isContainer;
rv = gRDFC->IsContainer(mInner, element, &isContainer);
if (NS_FAILED(rv))
return rv;
PRBool isGroup;
rv = mInner->HasAssertion(element, kNC_FolderGroup, kTrueLiteral,
PR_TRUE, &isGroup);
if (NS_FAILED(rv))
return rv;
ElementInfo* elementInfo = new ElementInfo(element, node,
isContainer && !isGroup);
if (!elementInfo)
return NS_ERROR_OUT_OF_MEMORY;
elementArray.AppendElement(elementInfo);
if (isContainer && aRecurse) {
rv = Sort(element, aProperty, aDirection, aFoldersFirst, aRecurse);
if (NS_FAILED(rv))
return rv;
}
}
SortInfo sortInfo(aDirection, aFoldersFirst);
elementArray.Sort(Compare, &sortInfo);
// XXXvarga If we ever make it so that ordinals are guaranteed to be unique,
// the code below can be significantly simplified.
for (PRInt32 j = elementArray.Count() - 1; j >= 0; --j) {
ElementInfo* elementInfo = elementArray[j];
PRInt32 oldIndex;
rv = gRDFC->IndexOf(mInner, aFolder, elementInfo->mElement, &oldIndex);
if (NS_FAILED(rv))
return rv;
// The old index is 1 based.
if (oldIndex != j + 1) {
nsCOMPtr<nsIRDFResource> oldOrdinal;
rv = gRDFC->IndexToOrdinalResource(oldIndex, getter_AddRefs(oldOrdinal));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFResource> newOrdinal;
rv = gRDFC->IndexToOrdinalResource(j + 1, getter_AddRefs(newOrdinal));
if (NS_FAILED(rv))
return rv;
// We need to find the correct element for the old ordinal,
// it happens that there are two elements with the same ordinal.
nsCOMPtr<nsISimpleEnumerator> elements;
rv = mInner->GetTargets(aFolder, oldOrdinal, PR_TRUE,
getter_AddRefs(elements));
PRBool hasMore = PR_FALSE;
while (NS_SUCCEEDED(rv = elements->HasMoreElements(&hasMore)) &&
hasMore) {
nsCOMPtr<nsISupports> supports;
rv = elements->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFNode> element = do_QueryInterface(supports);
if (element == elementInfo->mElement) {
rv = mInner->Unassert(aFolder, oldOrdinal, element);
if (NS_FAILED(rv))
return rv;
rv = mInner->Assert(aFolder, newOrdinal, element, PR_TRUE);
if (NS_FAILED(rv))
return rv;
break;
}
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsBookmarksService::SortFolder(nsIRDFResource* aFolder,
nsIRDFResource* aProperty,
PRInt32 aDirection,
PRBool aFoldersFirst,
PRBool aRecurse)
{
#ifdef DEBUG_varga
PRIntervalTime startTime = PR_IntervalNow();
#endif
BeginUpdateBatch();
SetPropagateChanges(PR_FALSE);
nsresult rv = Sort(aFolder, aProperty, aDirection, aFoldersFirst,
aRecurse);
SetPropagateChanges(PR_TRUE);
EndUpdateBatch();
#ifdef DEBUG_varga
PRIntervalTime endTime = PR_IntervalNow();
printf("Time spent in SortFolder(): %d msec\n", PR_IntervalToMilliseconds(endTime - startTime));
#endif
return rv;
}
NS_IMETHODIMP
nsBookmarksService::CreateBookmark(const PRUnichar* aName,
const char* aURL,
@ -2774,6 +3111,63 @@ nsBookmarksService::CreateSeparator(nsIRDFResource** aResult)
return rv;
}
NS_IMETHODIMP
nsBookmarksService::CloneResource(nsIRDFResource* aSource,
nsIRDFResource** aResult)
{
nsCOMPtr<nsIRDFResource> newResource;
nsresult rv = gRDF->GetAnonymousResource(getter_AddRefs(newResource));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISimpleEnumerator> arcs;
rv = mInner->ArcLabelsOut(aSource, getter_AddRefs(arcs));
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasMore = PR_FALSE;
while (NS_SUCCEEDED(arcs->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
rv = arcs->GetNext(getter_AddRefs(supports));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIRDFResource> property = do_QueryInterface(supports, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Don't duplicate the folder type.
// (NC:PersonalToolbarFolder, NC:NewBookmarkFolder, etc...)
PRBool isFolderType;
rv = property->EqualsNode(kNC_FolderType, &isFolderType);
NS_ENSURE_SUCCESS(rv, rv);
if (isFolderType)
continue;
nsCOMPtr<nsIRDFNode> target;
rv = mInner->GetTarget(aSource, property, PR_TRUE, getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
// Test if the arc points to a child.
PRBool isOrdinal;
rv = gRDFC->IsOrdinalProperty(property, &isOrdinal);
NS_ENSURE_SUCCESS(rv, rv);
if (isOrdinal) {
nsCOMPtr<nsIRDFResource> oldChild = do_QueryInterface(target);
nsCOMPtr<nsIRDFResource> newChild;
rv = CloneResource(oldChild, getter_AddRefs(newChild));
NS_ENSURE_SUCCESS(rv, rv);
rv = mInner->Assert(newResource, property, newChild, PR_TRUE);
}
else {
rv = mInner->Assert(newResource, property, target, PR_TRUE);
}
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ADDREF(*aResult = newResource);
return NS_OK;
}
NS_IMETHODIMP
nsBookmarksService::AddBookmarkImmediately(const char *aURI,
const PRUnichar *aTitle,
@ -2803,8 +3197,8 @@ nsBookmarksService::AddBookmarkImmediately(const char *aURI,
getter_AddRefs(bookmark));
}
nsresult
nsBookmarksService::IsBookmarkedInternal(nsIRDFResource *bookmark, PRBool *isBookmarkedFlag)
NS_IMETHODIMP
nsBookmarksService::IsBookmarkedResource(nsIRDFResource *bookmark, PRBool *isBookmarkedFlag)
{
if (!bookmark) return NS_ERROR_UNEXPECTED;
if (!isBookmarkedFlag) return NS_ERROR_UNEXPECTED;
@ -2868,7 +3262,7 @@ nsBookmarksService::IsBookmarked(const char* aURL, PRBool* aIsBookmarked)
if (NS_FAILED(rv))
return rv;
return IsBookmarkedInternal(bookmark, aIsBookmarked);
return IsBookmarkedResource(bookmark, aIsBookmarked);
}
NS_IMETHODIMP
@ -3123,7 +3517,7 @@ nsBookmarksService::GetSynthesizedType(nsIRDFResource *aNode, nsIRDFNode **aType
{
*aType = kNC_Folder;
}
else if (NS_SUCCEEDED(rv = IsBookmarkedInternal(aNode,
else if (NS_SUCCEEDED(rv = IsBookmarkedResource(aNode,
&isBookmarkedFlag)) && (isBookmarkedFlag == PR_TRUE))
{
*aType = kNC_Bookmark;
@ -3367,9 +3761,9 @@ nsBookmarksService::ImportSystemBookmarks(nsIRDFResource* aParentFolder)
BookmarkParser parser;
parser.Init(ieFavoritesFile, mInner);
BeginUpdateBatch(this);
BeginUpdateBatch();
parser.Parse(aParentFolder, kNC_Bookmark);
EndUpdateBatch(this);
EndUpdateBatch();
#endif
return NS_OK;
@ -4167,16 +4561,10 @@ nsBookmarksService::getFolderViaHint(nsIRDFResource *objType, PRBool fallbackFla
if ((rv != NS_RDF_NO_VALUE) && (oldSource))
{
const char *uri = nsnull;
oldSource->GetValueConst(&uri);
if (uri)
{
PRBool isBookmarkedFlag = PR_FALSE;
if (NS_SUCCEEDED(rv = IsBookmarked(uri, &isBookmarkedFlag)) &&
(isBookmarkedFlag == PR_TRUE))
{
*folder = oldSource;
}
PRBool isBookmarkedFlag = PR_FALSE;
if (NS_SUCCEEDED(rv = IsBookmarkedResource(oldSource, &isBookmarkedFlag)) &&
isBookmarkedFlag) {
*folder = oldSource;
}
}
@ -4422,6 +4810,24 @@ nsBookmarksService::FlushTo(const char *aURI)
}
////////////////////////////////////////////////////////////////////////
// nsIRDFPropagatableDataSource
NS_IMETHODIMP
nsBookmarksService::GetPropagateChanges(PRBool* aPropagateChanges)
{
nsCOMPtr<nsIRDFPropagatableDataSource> propagatable = do_QueryInterface(mInner);
return propagatable->GetPropagateChanges(aPropagateChanges);
}
NS_IMETHODIMP
nsBookmarksService::SetPropagateChanges(PRBool aPropagateChanges)
{
nsCOMPtr<nsIRDFPropagatableDataSource> propagatable = do_QueryInterface(mInner);
return propagatable->SetPropagateChanges(aPropagateChanges);
}
////////////////////////////////////////////////////////////////////////
// Implementation methods
@ -4496,9 +4902,9 @@ nsBookmarksService::ReadFavorites()
{
BookmarkParser parser;
parser.Init(ieFavoritesFile, mInner);
BeginUpdateBatch(this);
BeginUpdateBatch();
parser.Parse(kNC_IEFavoritesRoot, kNC_IEFavorite);
EndUpdateBatch(this);
EndUpdateBatch();
nsCOMPtr<nsIRDFLiteral> ieTitleLiteral;
rv = gRDF->GetLiteral(ieTitle.get(), getter_AddRefs(ieTitleLiteral));
@ -4673,9 +5079,9 @@ nsBookmarksService::LoadBookmarks()
parser.ParserFoundIEFavoritesRoot(&foundIERoot);
}
BeginUpdateBatch(this);
BeginUpdateBatch();
parser.Parse(kNC_BookmarksRoot, kNC_Bookmark);
EndUpdateBatch(this);
EndUpdateBatch();
mBookmarksAvailable = PR_TRUE;
PRBool foundPTFolder = PR_FALSE;
@ -5411,7 +5817,7 @@ nsBookmarksService::CanAccept(nsIRDFResource* aSource,
nsresult rv;
PRBool isBookmarkedFlag = PR_FALSE, canAcceptFlag = PR_FALSE, isOrdinal;
if (NS_SUCCEEDED(rv = IsBookmarkedInternal(aSource, &isBookmarkedFlag)) &&
if (NS_SUCCEEDED(rv = IsBookmarkedResource(aSource, &isBookmarkedFlag)) &&
(isBookmarkedFlag == PR_TRUE) &&
(NS_SUCCEEDED(rv = gRDFC->IsOrdinalProperty(aProperty, &isOrdinal))))
{
@ -5450,7 +5856,6 @@ nsBookmarksService::OnAssert(nsIRDFDataSource* aDataSource,
{
if (mUpdateBatchNest != 0) return NS_OK;
PRInt32 count = mObservers.Count();
for (PRInt32 i = 0; i < count; ++i)
{
@ -5514,13 +5919,13 @@ nsBookmarksService::OnMove(nsIRDFDataSource* aDataSource,
}
NS_IMETHODIMP
nsBookmarksService::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
nsBookmarksService::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
{
if (mUpdateBatchNest++ == 0)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = 0; i < count; ++i) {
(void) mObservers[i]->BeginUpdateBatch(aDataSource);
(void) mObservers[i]->OnBeginUpdateBatch(this);
}
}
@ -5528,18 +5933,15 @@ nsBookmarksService::BeginUpdateBatch(nsIRDFDataSource* aDataSource)
}
NS_IMETHODIMP
nsBookmarksService::EndUpdateBatch(nsIRDFDataSource* aDataSource)
nsBookmarksService::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
{
if (mUpdateBatchNest > 0)
{
--mUpdateBatchNest;
}
NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
if (mUpdateBatchNest == 0)
if (--mUpdateBatchNest == 0)
{
PRInt32 count = mObservers.Count();
for (PRInt32 i = 0; i < count; ++i) {
(void) mObservers[i]->EndUpdateBatch(aDataSource);
(void) mObservers[i]->OnEndUpdateBatch(this);
}
}

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

@ -40,6 +40,7 @@
#include "nsIRDFDataSource.h"
#include "nsIRDFRemoteDataSource.h"
#include "nsIRDFPropagatableDataSource.h"
#include "nsIStreamListener.h"
#include "nsIRDFObserver.h"
#include "nsISupportsArray.h"
@ -69,6 +70,7 @@ class nsIOutputStream;
class nsBookmarksService : public nsIBookmarksService,
public nsIRDFDataSource,
public nsIRDFRemoteDataSource,
public nsIRDFPropagatableDataSource,
public nsIStreamListener,
public nsIRDFObserver,
public nsIObserver,
@ -172,14 +174,18 @@ protected:
void AnnotateBookmarkSchedule(nsIRDFResource* aSource,
PRBool scheduleFlag);
nsresult IsBookmarkedInternal(nsIRDFResource *bookmark,
PRBool *isBookmarkedFlag);
nsresult InsertResource(nsIRDFResource* aResource,
nsIRDFResource* aParentFolder, PRInt32 aIndex);
nsresult getLocaleString(const char *key, nsString &str);
static int PR_CALLBACK
Compare(const void* aElement1, const void* aElement2, void* aData);
nsresult
Sort(nsIRDFResource* aFolder, nsIRDFResource* aProperty,
PRInt32 aDirection, PRBool aFoldersFirst, PRBool aRecurse);
nsresult LoadBookmarks();
nsresult initDatasource();
@ -289,9 +295,20 @@ public:
nsIRDFResource* aCommand,
nsISupportsArray/*<nsIRDFResource>*/* aArguments);
NS_IMETHOD BeginUpdateBatch() {
return mInner->BeginUpdateBatch();
}
NS_IMETHOD EndUpdateBatch() {
return mInner->EndUpdateBatch();
}
// nsIRDFRemoteDataSource
NS_DECL_NSIRDFREMOTEDATASOURCE
// nsIRDFPropagatableDataSource
NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
// nsIRDFObserver
NS_DECL_NSIRDFOBSERVER
};

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

@ -97,8 +97,8 @@ var RDF_observer =
onChange: function(ds, src, prop, old_target, new_target) { },
onMove: function(ds, old_src, new_src, prop, target) { },
beginUpdateBatch: function(ds) { },
endUpdateBatch: function(ds) { }
onBeginUpdateBatch: function(ds) { },
onEndUpdateBatch: function(ds) { }
};
function

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

@ -1315,6 +1315,18 @@ nsHTTPIndex::DoCommand(nsISupportsArray *aSources, nsIRDFResource *aCommand,
return(rv);
}
NS_IMETHODIMP
nsHTTPIndex::BeginUpdateBatch()
{
return mInner->BeginUpdateBatch();
}
NS_IMETHODIMP
nsHTTPIndex::EndUpdateBatch()
{
return mInner->EndUpdateBatch();
}
NS_IMETHODIMP
nsHTTPIndex::GetAllCmds(nsIRDFResource *aSource, nsISimpleEnumerator **_retval)
{

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

@ -262,23 +262,17 @@ var downloadViewController = {
selectedItems = getSelectedItems();
// Figure out where to place the selection after deletion
var newSelectionPos = gDownloadView.contentView.getIndexOfItem(selectedItems[0]);
gDownloadManager.startBatchUpdate();
// Notify the datasource that we're about to begin a batch operation
var observer = gDownloadView.builder.QueryInterface(Components.interfaces.nsIRDFObserver);
var ds = gDownloadView.database;
observer.beginUpdateBatch(ds);
var ds = window.arguments[0];
ds.beginUpdateBatch();
for (i = 0; i <= selectedItems.length - 1; ++i) {
gDownloadManager.removeDownload(selectedItems[i].id);
}
ds.endUpdateBatch();
gDownloadManager.endBatchUpdate();
observer.endUpdateBatch(ds);
var remote = window.arguments[0].QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
remote.Flush();
gDownloadView.builder.rebuild();
// If there's nothing on the panel now, skip setting the selection
if (gDownloadView.treeBoxObject.view && gDownloadView.treeBoxObject.view.rowCount > 0) {
// Select the item that replaced the first deleted one

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

@ -678,8 +678,12 @@ nsDownloadManager::StartBatchUpdate()
NS_IMETHODIMP
nsDownloadManager::EndBatchUpdate()
{
--mBatches;
return NS_OK;
nsresult rv = NS_OK;
if (--mBatches == 0) {
nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mDataSource);
rv = remote->Flush();
}
return rv;
}
NS_IMETHODIMP

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

@ -63,21 +63,6 @@ interface nsIBrowserHistory : nsISupports
*/
void removePage(in string aURL);
/**
* startBatchUpdate
* Signals the beginning of some kind of batch update (e.g. delete).
* Observers won't be notified until there are no batches in progress
* (a startBatchUpdate call should always be followed by one to
* endBatchUpdate).
*/
void startBatchUpdate();
/**
* endBatchUpdate
* Signals the end of a batch update.
*/
void endBatchUpdate();
/**
* removePagesFromHost
* Remove all pages from the given host.

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

@ -223,14 +223,12 @@ nsHistoryController.prototype =
if (!gGlobalHistory)
gGlobalHistory = Components.classes["@mozilla.org/browser/global-history;1"].getService(Components.interfaces.nsIBrowserHistory);
gGlobalHistory.removePagesFromHost(gLastHostname, false)
gHistoryTree.builder.rebuild();
return true;
case "cmd_deleteByDomain":
if (!gGlobalHistory)
gGlobalHistory = Components.classes["@mozilla.org/browser/global-history;1"].getService(Components.interfaces.nsIBrowserHistory);
gGlobalHistory.removePagesFromHost(gLastDomain, true)
gHistoryTree.builder.rebuild();
return true;
default:

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

@ -1102,7 +1102,7 @@ nsGlobalHistory::RemoveMatchingRows(rowMatchCallback aMatchFunc,
err = mTable->GetCount(mEnv, &count);
if (err != 0) return NS_ERROR_FAILURE;
StartBatchUpdate();
BeginUpdateBatch();
// Begin the batch.
int marker;
@ -1162,7 +1162,7 @@ nsGlobalHistory::RemoveMatchingRows(rowMatchCallback aMatchFunc,
err = mTable->EndBatchChangeHint(mEnv, &marker);
NS_ASSERTION(err == 0, "error ending batch");
EndBatchUpdate();
EndUpdateBatch();
return ( err == 0) ? NS_OK : NS_ERROR_FAILURE;
}
@ -2171,6 +2171,65 @@ nsGlobalHistory::GetAllResources(nsISimpleEnumerator** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsGlobalHistory::BeginUpdateBatch()
{
nsresult rv = NS_OK;
++mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->OnBeginUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
NS_IMETHODIMP
nsGlobalHistory::EndUpdateBatch()
{
nsresult rv = NS_OK;
--mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->OnEndUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
////////////////////////////////////////////////////////////////////////
@ -2212,66 +2271,6 @@ nsGlobalHistory::FlushTo(const char *aURI)
return(NS_ERROR_NOT_IMPLEMENTED);
}
NS_IMETHODIMP
nsGlobalHistory::StartBatchUpdate()
{
nsresult rv = NS_OK;
++mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->BeginUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
NS_IMETHODIMP
nsGlobalHistory::EndBatchUpdate()
{
nsresult rv = NS_OK;
--mBatchesInProgress;
// we could call mObservers->EnumerateForwards() here
// to save the addref/release on each observer, but
// it's unlikely that anyone but the tree builder
// is observing us
if (mObservers) {
PRUint32 count;
rv = mObservers->Count(&count);
if (NS_FAILED(rv)) return rv;
for (PRInt32 i = 0; i < PRInt32(count); ++i) {
nsIRDFObserver* observer = NS_STATIC_CAST(nsIRDFObserver*, mObservers->ElementAt(i));
NS_ASSERTION(observer != nsnull, "null ptr");
if (! observer)
continue;
rv = observer->EndUpdateBatch(this);
NS_RELEASE(observer);
}
}
return rv;
}
//----------------------------------------------------------------------
//
// nsGlobalHistory

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

@ -1993,3 +1993,12 @@ NS_IMETHODIMP nsCharsetMenu::DoCommand(nsISupportsArray* aSources,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsCharsetMenu::BeginUpdateBatch()
{
return mInner->BeginUpdateBatch();
}
NS_IMETHODIMP nsCharsetMenu::EndUpdateBatch()
{
return mInner->EndUpdateBatch();
}

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

@ -974,3 +974,19 @@ RelatedLinksHandlerImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSource
{
return mInner->DoCommand(aSources, aCommand, aArguments);
}
NS_IMETHODIMP
RelatedLinksHandlerImpl::BeginUpdateBatch()
{
return mInner->BeginUpdateBatch();
}
NS_IMETHODIMP
RelatedLinksHandlerImpl::EndUpdateBatch()
{
return mInner->EndUpdateBatch();
}

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

@ -110,11 +110,11 @@ var RDF_observer =
{
},
beginUpdateBatch : function(ds)
onBeginUpdateBatch : function(ds)
{
},
endUpdateBatch : function(ds)
onEndUpdateBatch : function(ds)
{
}
}

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

@ -2343,6 +2343,18 @@ InternetSearchDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSourc
return(NS_OK);
}
NS_IMETHODIMP
InternetSearchDataSource::BeginUpdateBatch()
{
return mInner->BeginUpdateBatch();
}
NS_IMETHODIMP
InternetSearchDataSource::EndUpdateBatch()
{
return mInner->EndUpdateBatch();
}
NS_IMETHODIMP
InternetSearchDataSource::AddSearchEngine(const char *engineURL, const char *iconURL,
const PRUnichar *suggestedTitle, const PRUnichar *suggestedCategory)

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

@ -986,3 +986,19 @@ LocalSearchDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
{
return(NS_ERROR_NOT_IMPLEMENTED);
}
NS_IMETHODIMP
LocalSearchDataSource::BeginUpdateBatch()
{
return NS_OK;
}
NS_IMETHODIMP
LocalSearchDataSource::EndUpdateBatch()
{
return NS_OK;
}

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

@ -144,11 +144,11 @@ var panels_observer = {
onMove : function(ds,old_src,new_src,prop,target) {
//debug ("observer: move");
},
beginUpdateBatch : function(ds) {
//debug ("observer: beginUpdateBatch");
onBeginUpdateBatch : function(ds) {
//debug ("observer: onBeginUpdateBatch");
},
endUpdateBatch : function(ds) {
//debug ("observer: endUpdateBatch");
onEndUpdateBatch : function(ds) {
//debug ("observer: onEndUpdateBatch");
}
};

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

@ -691,11 +691,11 @@ var panel_observer = {
onMove : function(ds,old_src,new_src,prop,target) {
//debug ("observer: move");
},
beginUpdateBatch : function(ds) {
//debug ("observer: beginUpdateBatch");
onBeginUpdateBatch : function(ds) {
//debug ("observer: onBeginUpdateBatch");
},
endUpdateBatch : function(ds) {
//debug ("observer: endUpdateBatch");
onEndUpdateBatch : function(ds) {
//debug ("observer: onEndUpdateBatch");
}
};

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

@ -575,3 +575,18 @@ NS_IMETHODIMP nsWindowDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResou
return NS_OK;
}
/* void beginUpdateBatch (); */
NS_IMETHODIMP nsWindowDataSource::BeginUpdateBatch()
{
if (mInner)
return mInner->BeginUpdateBatch();
return NS_OK;
}
/* void endUpdateBatch (); */
NS_IMETHODIMP nsWindowDataSource::EndUpdateBatch()
{
if (mInner)
return mInner->EndUpdateBatch();
return NS_OK;
}

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

@ -149,16 +149,18 @@ function nsTreeController_delete()
return false;
var datasource = this.tree.database;
var dsEnum = datasource.GetDataSources();
var dsEnum = datasource.GetDataSources();
dsEnum.getNext();
var ds = dsEnum.getNext();
var ds = dsEnum.getNext()
.QueryInterface(Components.interfaces.nsIRDFDataSource);
var count = this.treeSelection.count;
// XXX 9 is a random number, just looking for a sweetspot
// don't want to rebuild tree content for just a few items
if (count > 9)
ds.QueryInterface(Components.interfaces.nsIBrowserHistory).startBatchUpdate();
if (count > 9) {
ds.beginUpdateBatch();
}
var min = new Object();
var max = new Object();
@ -186,17 +188,16 @@ function nsTreeController_delete()
// otherwise remove the parent/child assertion then
var containment = gRDF.GetResource("http://home.netscape.com/NC-rdf#child");
ds.QueryInterface(Components.interfaces.nsIRDFDataSource).Unassert(parentIDRes, containment, IDRes);
ds.Unassert(parentIDRes, containment, IDRes);
dirty = true;
}
}
if (dirty) {
if (count > 9) {
ds.QueryInterface(Components.interfaces.nsIBrowserHistory).endBatchUpdate();
this.tree.builder.rebuild();
}
if (count > 9) {
ds.endUpdateBatch();
}
if (dirty) {
try {
var remote = datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
remote.Flush();