зеркало из https://github.com/mozilla/pjs.git
Bug 324430 - Allow stopping Places results updates when they are unused, r=dietrich
This commit is contained in:
Родитель
32010e23da
Коммит
a3c22656f4
|
@ -452,6 +452,7 @@
|
|||
<menupopup id="goPopup"
|
||||
type="places"
|
||||
onpopupshowing="HistoryMenu.onPopupShowing(this);"
|
||||
onpopuphidden="HistoryMenu.onPopupHidden(this);"
|
||||
place="place:redirectsMode=2&sort=4&maxResults=10"
|
||||
tooltip="btTooltip">
|
||||
<menuitem id="historyMenuBack"
|
||||
|
|
|
@ -600,13 +600,21 @@ var HistoryMenu = {
|
|||
document.getElementById("endHistorySeparator").hidden =
|
||||
resultNode.childCount == 0;
|
||||
|
||||
if (!wasOpen)
|
||||
resultNode.containerOpen = false;
|
||||
|
||||
// HistoryMenu.toggleRecentlyClosedTabs, HistoryMenu.toggleRecentlyClosedWindows
|
||||
// are defined in browser.js
|
||||
this.toggleRecentlyClosedTabs();
|
||||
this.toggleRecentlyClosedWindows();
|
||||
},
|
||||
|
||||
/**
|
||||
* popuphidden handler for the history menu.
|
||||
* @param aMenuPopup
|
||||
* XULNode for the history menupopup
|
||||
*/
|
||||
onPopupHidden: function PHM_onPopupHidden(aMenuPopup) {
|
||||
var resultNode = aMenuPopup.getResultNode();
|
||||
if (resultNode.containerOpen)
|
||||
resultNode.containerOpen = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -538,6 +538,7 @@
|
|||
<destructor><![CDATA[
|
||||
this._resultNode = null;
|
||||
if (this._result) {
|
||||
this._result.root.containerOpen = false;
|
||||
this._result.viewer = null;
|
||||
this._result = null;
|
||||
}
|
||||
|
@ -719,6 +720,8 @@
|
|||
// object which is already set for this viewer. At that point,
|
||||
// we should do nothing.
|
||||
if (this._self._result != val) {
|
||||
if (this._self._result)
|
||||
this._self._result.root.containerOpen = false;
|
||||
this._built = false;
|
||||
this._self._containerNodesMap = [];
|
||||
this._self._resultNode = val.root;
|
||||
|
|
|
@ -478,6 +478,8 @@
|
|||
// object which is already set for this viewer. At that point,
|
||||
// we should do nothing.
|
||||
if (this._self._result != val) {
|
||||
if (this._self._result)
|
||||
this._self._result.root.containerOpen = false;
|
||||
this._self._containerNodesMap = [];
|
||||
this._self._result = val;
|
||||
if (val) // this calls _rebuild through invalidateContainer
|
||||
|
|
|
@ -57,8 +57,10 @@
|
|||
// Note: unsetting the result's viewer also unsets
|
||||
// the viewer's reference to our treeBoxObject.
|
||||
var result = this.getResult();
|
||||
if (result)
|
||||
if (result) {
|
||||
result.viewer = null;
|
||||
result.root.containerOpen = false;
|
||||
}
|
||||
this.view = null;
|
||||
]]></destructor>
|
||||
|
||||
|
@ -119,8 +121,14 @@
|
|||
<parameter name="queries"/>
|
||||
<parameter name="options"/>
|
||||
<body><![CDATA[
|
||||
var result = PlacesUtils.history.executeQueries(queries, queries.length,
|
||||
options);
|
||||
// Cleanup old result if exists.
|
||||
var oldResult = this.getResult();
|
||||
if (oldResult)
|
||||
oldResult.root.containerOpen = false;
|
||||
|
||||
var result = PlacesUtils.history
|
||||
.executeQueries(queries, queries.length,
|
||||
options);
|
||||
var callback;
|
||||
if (this.flatList) {
|
||||
var onOpenFlatContainer = this.onOpenFlatContainer;
|
||||
|
|
|
@ -808,6 +808,8 @@ PlacesTreeView.prototype = {
|
|||
// object which is already set for this viewer. At that point,
|
||||
// we should do nothing.
|
||||
if (this._result != val) {
|
||||
if (this._result)
|
||||
this._result.root.containerOpen = false;
|
||||
this._result = val;
|
||||
this._finishInit();
|
||||
}
|
||||
|
|
|
@ -685,6 +685,7 @@ placesRemoveItemTransaction.prototype = {
|
|||
this._transactions
|
||||
.push(new placesRemoveItemTransaction(contents.getChild(i).itemId));
|
||||
}
|
||||
contents.containerOpen = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -988,7 +989,8 @@ placesSortFolderByNameTransactions.prototype = {
|
|||
doTransaction: function PSSFBN_doTransaction() {
|
||||
this._oldOrder = [];
|
||||
|
||||
var contents = PlacesUtils.getFolderContents(this._folderId, false, false).root;
|
||||
var contents =
|
||||
PlacesUtils.getFolderContents(this._folderId, false, false).root;
|
||||
var count = contents.childCount;
|
||||
|
||||
// sort between separators
|
||||
|
@ -1017,6 +1019,8 @@ placesSortFolderByNameTransactions.prototype = {
|
|||
else
|
||||
preSep.push(item);
|
||||
}
|
||||
contents.containerOpen = false;
|
||||
|
||||
if (preSep.length > 0) {
|
||||
preSep.sort(sortingMethod);
|
||||
newOrder = newOrder.concat(preSep);
|
||||
|
|
|
@ -614,6 +614,13 @@ interface nsINavHistoryResult : nsISupports
|
|||
/**
|
||||
* This is the root of the results. Remember that you need to open all
|
||||
* containers for their contents to be valid.
|
||||
*
|
||||
* When a result goes out of scope it will continue to observe changes till
|
||||
* it is cycle collected. While the result waits to be collected it will stay
|
||||
* in memory, and continue to update itself, potentially causing unwanted
|
||||
* additional work. When you close the root node the result will stop
|
||||
* observing changes, so it is good practice to close the root node when you
|
||||
* are done with a result, since that will avoid unwanted performance hits.
|
||||
*/
|
||||
readonly attribute nsINavHistoryContainerResultNode root;
|
||||
};
|
||||
|
|
|
@ -499,7 +499,8 @@ nsNavHistoryContainerResultNode::CloseContainer(PRBool aUpdateView)
|
|||
|
||||
// recursively close all child containers
|
||||
for (PRInt32 i = 0; i < mChildren.Count(); i ++) {
|
||||
if (mChildren[i]->IsContainer() && mChildren[i]->GetAsContainer()->mExpanded)
|
||||
if (mChildren[i]->IsContainer() &&
|
||||
mChildren[i]->GetAsContainer()->mExpanded)
|
||||
mChildren[i]->GetAsContainer()->CloseContainer(PR_FALSE);
|
||||
}
|
||||
|
||||
|
@ -508,17 +509,25 @@ nsNavHistoryContainerResultNode::CloseContainer(PRBool aUpdateView)
|
|||
nsresult rv;
|
||||
if (IsDynamicContainer()) {
|
||||
// notify dynamic containers that we are closing
|
||||
nsCOMPtr<nsIDynamicContainer> svc = do_GetService(mDynamicContainerType.get(), &rv);
|
||||
nsCOMPtr<nsIDynamicContainer> svc =
|
||||
do_GetService(mDynamicContainerType.get(), &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
svc->OnContainerNodeClosed(this);
|
||||
}
|
||||
|
||||
nsNavHistoryResult* result = GetResult();
|
||||
if (aUpdateView) {
|
||||
nsNavHistoryResult* result = GetResult();
|
||||
NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
|
||||
if (result->GetView())
|
||||
result->GetView()->ContainerClosed(this);
|
||||
}
|
||||
|
||||
// If this is the root container of a result, we can tell the result to stop
|
||||
// observing changes, otherwise the result will stay in memory and updates
|
||||
// itself till it is cycle collected.
|
||||
if (result->mRootNode == this)
|
||||
result->StopObserving();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2376,12 +2385,17 @@ nsNavHistoryQueryResultNode::FillChildren()
|
|||
|
||||
PRUint16 sortType = GetSortType();
|
||||
|
||||
// The default SORT_BY_NONE sorts by the bookmark index (position),
|
||||
// which we do not have for history queries
|
||||
if (mOptions->QueryType() != nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY ||
|
||||
sortType != nsINavHistoryQueryOptions::SORT_BY_NONE) {
|
||||
// once we've computed all tree stats, we can sort, because containers will
|
||||
// then have proper visit counts and dates
|
||||
if (mResult->mNeedsToApplySortingMode) {
|
||||
// We should repopulate container and then apply sortingMode. To avoid
|
||||
// sorting 2 times we simply do that here.
|
||||
mResult->SetSortingMode(mResult->mSortingMode);
|
||||
}
|
||||
else if (mOptions->QueryType() != nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY ||
|
||||
sortType != nsINavHistoryQueryOptions::SORT_BY_NONE) {
|
||||
// The default SORT_BY_NONE sorts by the bookmark index (position),
|
||||
// which we do not have for history queries.
|
||||
// Once we've computed all tree stats, we can sort, because containers will
|
||||
// then have proper visit counts and dates.
|
||||
SortComparator comparator = GetSortingComparator(GetSortType());
|
||||
if (comparator) {
|
||||
nsCAutoString sortingAnnotation;
|
||||
|
@ -3260,13 +3274,20 @@ nsNavHistoryFolderResultNode::FillChildren()
|
|||
// nodes and the result node pointers on the containers
|
||||
FillStats();
|
||||
|
||||
// once we've computed all tree stats, we can sort, because containers will
|
||||
// then have proper visit counts and dates
|
||||
SortComparator comparator = GetSortingComparator(GetSortType());
|
||||
if (comparator) {
|
||||
nsCAutoString sortingAnnotation;
|
||||
GetSortingAnnotation(sortingAnnotation);
|
||||
RecursiveSort(sortingAnnotation.get(), comparator);
|
||||
if (mResult->mNeedsToApplySortingMode) {
|
||||
// We should repopulate container and then apply sortingMode. To avoid
|
||||
// sorting 2 times we simply do that here.
|
||||
mResult->SetSortingMode(mResult->mSortingMode);
|
||||
}
|
||||
else {
|
||||
// once we've computed all tree stats, we can sort, because containers will
|
||||
// then have proper visit counts and dates
|
||||
SortComparator comparator = GetSortingComparator(GetSortType());
|
||||
if (comparator) {
|
||||
nsCAutoString sortingAnnotation;
|
||||
GetSortingAnnotation(sortingAnnotation);
|
||||
RecursiveSort(sortingAnnotation.get(), comparator);
|
||||
}
|
||||
}
|
||||
|
||||
// if we are limiting our results remove items from the end of the
|
||||
|
@ -3863,7 +3884,8 @@ nsNavHistoryResult::nsNavHistoryResult(nsNavHistoryContainerResultNode* aRoot) :
|
|||
mIsHistoryObserver(PR_FALSE),
|
||||
mIsBookmarkFolderObserver(PR_FALSE),
|
||||
mIsAllBookmarksObserver(PR_FALSE),
|
||||
mBatchInProgress(PR_FALSE)
|
||||
mBatchInProgress(PR_FALSE),
|
||||
mNeedsToApplySortingMode(PR_FALSE)
|
||||
{
|
||||
mRootNode->mResult = this;
|
||||
}
|
||||
|
@ -3874,6 +3896,33 @@ nsNavHistoryResult::~nsNavHistoryResult()
|
|||
mBookmarkFolderObservers.Enumerate(&RemoveBookmarkFolderObserversCallback, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
nsNavHistoryResult::StopObserving()
|
||||
{
|
||||
if (mIsBookmarkFolderObserver || mIsAllBookmarksObserver) {
|
||||
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
|
||||
if (bookmarks) {
|
||||
bookmarks->RemoveObserver(this);
|
||||
mIsBookmarkFolderObserver = PR_FALSE;
|
||||
mIsAllBookmarksObserver = PR_FALSE;
|
||||
}
|
||||
}
|
||||
if (mIsHistoryObserver) {
|
||||
nsNavHistory* history = nsNavHistory::GetHistoryService();
|
||||
if (history) {
|
||||
history->RemoveObserver(this);
|
||||
mIsHistoryObserver = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// We stop observing when root node is closed, but when reopening it result
|
||||
// will be out of sync. Ensure we will call FillChildren again in such a
|
||||
// case.
|
||||
if (mRootNode->IsQuery())
|
||||
mRootNode->GetAsQuery()->ClearChildren(PR_TRUE);
|
||||
else if (mRootNode->IsFolder())
|
||||
mRootNode->GetAsFolder()->ClearChildren(PR_TRUE);
|
||||
}
|
||||
|
||||
// nsNavHistoryResult::Init
|
||||
//
|
||||
|
@ -4117,6 +4166,12 @@ nsNavHistoryResult::SetSortingMode(PRUint16 aSortingMode)
|
|||
|
||||
mSortingMode = aSortingMode;
|
||||
|
||||
if (!mRootNode->mExpanded) {
|
||||
// Need to do this later when node will be expanded.
|
||||
mNeedsToApplySortingMode = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// actually do sorting
|
||||
nsNavHistoryContainerResultNode::SortComparator comparator =
|
||||
nsNavHistoryContainerResultNode::GetSortingComparator(aSortingMode);
|
||||
|
|
|
@ -155,6 +155,7 @@ public:
|
|||
void RemoveHistoryObserver(nsNavHistoryQueryResultNode* aNode);
|
||||
void RemoveBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode, PRInt64 aFolder);
|
||||
void RemoveAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode);
|
||||
void StopObserving();
|
||||
|
||||
// returns the view. NOT-ADDREFED. May be NULL if there is no view
|
||||
nsINavHistoryResultViewer* GetView() const
|
||||
|
@ -176,6 +177,10 @@ public:
|
|||
// One of nsNavHistoryQueryOptions.SORY_BY_* This is initialized to mOptions.sortingMode,
|
||||
// but may be overridden if the user clicks on one of the columns.
|
||||
PRUint16 mSortingMode;
|
||||
// If root node is closed and we try to apply a sortingMode, it would not
|
||||
// work. So we will apply it when the node will be reopened and populated.
|
||||
// This var states the fact we need to apply sortingMode in such a situation.
|
||||
PRBool mNeedsToApplySortingMode;
|
||||
|
||||
// The sorting annotation to be used for in SORT_BY_ANNOTATION_* modes
|
||||
nsCString mSortingAnnotation;
|
||||
|
|
|
@ -551,7 +551,11 @@ var PlacesUtils = {
|
|||
this.value += aStr;
|
||||
}
|
||||
};
|
||||
self.serializeNodeAsJSONToOutputStream(convertNode(aNode), writer, true, aForceCopy);
|
||||
var node = convertNode(aNode);
|
||||
self.serializeNodeAsJSONToOutputStream(node, writer, true, aForceCopy);
|
||||
// Convert node could pass an open container node.
|
||||
if (self.nodeIsContainer(node))
|
||||
node.containerOpen = false;
|
||||
return writer.value;
|
||||
case this.TYPE_X_MOZ_URL:
|
||||
function gatherDataUrl(bNode) {
|
||||
|
@ -564,7 +568,13 @@ var PlacesUtils = {
|
|||
// ignore containers and separators - items without valid URIs
|
||||
return "";
|
||||
}
|
||||
return gatherDataUrl(convertNode(aNode));
|
||||
var node = convertNode(aNode);
|
||||
var dataUrl = gatherDataUrl(node);
|
||||
// Convert node could pass an open container node.
|
||||
if (self.nodeIsContainer(node))
|
||||
node.containerOpen = false;
|
||||
return dataUrl;
|
||||
|
||||
|
||||
case this.TYPE_HTML:
|
||||
function gatherDataHtml(bNode) {
|
||||
|
@ -605,7 +615,12 @@ var PlacesUtils = {
|
|||
return "<HR>" + NEWLINE;
|
||||
return "";
|
||||
}
|
||||
return gatherDataHtml(convertNode(aNode));
|
||||
var node = convertNode(aNode);
|
||||
var dataHtml = gatherDataHtml(node);
|
||||
// Convert node could pass an open container node.
|
||||
if (self.nodeIsContainer(node))
|
||||
node.containerOpen = false;
|
||||
return dataHtml;
|
||||
}
|
||||
// case this.TYPE_UNICODE:
|
||||
function gatherDataText(bNode) {
|
||||
|
@ -634,7 +649,12 @@ var PlacesUtils = {
|
|||
return "";
|
||||
}
|
||||
|
||||
return gatherDataText(convertNode(aNode));
|
||||
var node = convertNode(aNode);
|
||||
var dataText = gatherDataText(node);
|
||||
// Convert node could pass an open container node.
|
||||
if (self.nodeIsContainer(node))
|
||||
node.containerOpen = false;
|
||||
return dataText;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче