1354 lines
32 KiB
C++
1354 lines
32 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (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/NPL/
|
|
*
|
|
* 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 Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
|
* Netscape Communications Corporation. All Rights Reserved.
|
|
*/
|
|
|
|
|
|
#include "nsISessionHistory.h"
|
|
#include "nsVoidArray.h"
|
|
//#include "nsIDocumentLoaderObserver.h"
|
|
#include "nsIWebShell.h"
|
|
#include "prmem.h"
|
|
#include "nsString.h"
|
|
#include "nsIFactory.h"
|
|
#include "nsCRT.h"
|
|
#include "nscore.h"
|
|
|
|
// Interface ID for nsIHistoryEntry
|
|
#define NS_IHISTORY_ENTRY_IID \
|
|
{ 0x68e73d53, 0x12eb, 0x11d3, { 0xbd, 0xc0, 0x0, 0x50, 0x4, 0xa, 0x9b, 0x44 } \
|
|
}
|
|
|
|
/* Define Class IDs */
|
|
static NS_DEFINE_IID(kWebShellCID, NS_WEB_SHELL_CID);
|
|
|
|
|
|
/* Define Interface IDs */
|
|
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
|
static NS_DEFINE_IID(kISessionHistoryIID, NS_ISESSION_HISTORY_IID);
|
|
static NS_DEFINE_IID(kIHistoryEntryIID, NS_IHISTORY_ENTRY_IID);
|
|
|
|
|
|
// Advance declarations
|
|
class nsHistoryEntry;
|
|
|
|
static nsHistoryEntry * GenerateTree(nsIWebShell * aWebShell,nsHistoryEntry *aparent, nsISessionHistory * aSHist);
|
|
|
|
#define APP_DEBUG 0
|
|
|
|
class nsHistoryEntry
|
|
{
|
|
public:
|
|
// static const nsIID& GetIID() { static nsIID iid = NS_IHISTORY_ENTRY_IID; return iid; }
|
|
|
|
//ctor
|
|
nsHistoryEntry();
|
|
~nsHistoryEntry();
|
|
|
|
//nsISupports
|
|
// NS_DECL_ISUPPORTS
|
|
|
|
/**
|
|
* Create the History data structures for the current URL. This method
|
|
* will also generate the history tree for the URL if it contains frames
|
|
*/
|
|
nsresult Create(nsIWebShell * aWebShell, nsHistoryEntry * aParent, nsISessionHistory * aSHist);
|
|
|
|
/**
|
|
* Load the entry in the content Area
|
|
*/
|
|
PRBool Load(nsIWebShell * aPrevEntry, PRBool aIsReload);
|
|
|
|
/**
|
|
* Destroy the historyentry
|
|
*/
|
|
nsresult DestroyChildren();
|
|
|
|
/**
|
|
* Get the Title of the page
|
|
*/
|
|
nsresult GetTitle(const PRUnichar ** aName);
|
|
|
|
/**
|
|
* Set the title of the page
|
|
*/
|
|
nsresult SetTitle(const PRUnichar * aName);
|
|
|
|
/**
|
|
* Get the URL of the page
|
|
*/
|
|
nsresult GetURL(const PRUnichar ** aURL);
|
|
|
|
/**
|
|
* Set the URL of the page
|
|
*/
|
|
nsresult SetURL(const PRUnichar * aURL);
|
|
|
|
/**
|
|
* Get the webshell of the page
|
|
*/
|
|
nsresult GetWebShell(nsIWebShell *& aName);
|
|
|
|
/**
|
|
* Set the webshell of the page
|
|
*/
|
|
nsresult SetWebShell(nsIWebShell * aName);
|
|
|
|
/**
|
|
* Get the History State of the page
|
|
*/
|
|
nsresult GetHistoryState(nsISupports ** aResult);
|
|
|
|
/**
|
|
* Set the History State of the page
|
|
*/
|
|
nsresult SetHistoryState(nsISupports * aState);
|
|
|
|
/**
|
|
* Add a child
|
|
*/
|
|
nsresult AddChild(nsHistoryEntry * aChild);
|
|
|
|
/**
|
|
* Get the child count
|
|
*/
|
|
PRInt32 GetChildCnt();
|
|
|
|
/**
|
|
* Get the child at a given index
|
|
*/
|
|
nsresult GetChildAt(PRInt32 aIndex, nsHistoryEntry *& aResult);
|
|
|
|
/**
|
|
* Set parent
|
|
*/
|
|
nsresult SetParent(nsHistoryEntry * aParent);
|
|
|
|
/**
|
|
* Get parent
|
|
*/
|
|
nsresult GetParent(nsHistoryEntry *& aResult);
|
|
|
|
/**
|
|
* Set the SessionHistory ID
|
|
*/
|
|
nsresult SetSessionHistoryID(nsISessionHistory * aSessionHistory);
|
|
|
|
/**
|
|
* Get a handle to the history entry for a Webshell
|
|
*/
|
|
|
|
nsHistoryEntry * GetHistoryForWS(nsIWebShell * aWS);
|
|
|
|
/**
|
|
* Get the handle to the root of the document structure. If the
|
|
* page contains a frame set, this will return handle to the
|
|
* topmost url that contains the outermost frameset.
|
|
*/
|
|
nsHistoryEntry * GetRootDoc();
|
|
|
|
|
|
nsIWebShell * mWS; //Webshell corresponding to this history entry
|
|
nsString * mURL; // URL for this history entry
|
|
nsString * mTitle; // Name of the document
|
|
nsVoidArray mChildren; // children list
|
|
PRInt32 mChildCount; // # of children
|
|
nsHistoryEntry * mParent;
|
|
nsISupports * mHistoryState; // History state as saved by the layout
|
|
nsISessionHistory * mHistoryList; // The handle to the session History to
|
|
// which this entry belongs
|
|
};
|
|
|
|
nsHistoryEntry::nsHistoryEntry()
|
|
{
|
|
mChildCount = 0;
|
|
mWS = nsnull;
|
|
mHistoryList = nsnull;
|
|
mParent = nsnull;
|
|
mURL = nsnull;
|
|
mTitle = nsnull;
|
|
mHistoryState = nsnull;
|
|
|
|
|
|
// NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsHistoryEntry::~nsHistoryEntry()
|
|
{
|
|
if (mTitle)
|
|
delete mTitle;
|
|
if (mURL)
|
|
delete mURL;
|
|
NS_IF_RELEASE(mWS);
|
|
NS_IF_RELEASE(mHistoryList);
|
|
NS_IF_RELEASE(mHistoryState);
|
|
|
|
DestroyChildren();
|
|
}
|
|
|
|
//NS_IMPL_ADDREF(nsHistoryEntry)
|
|
//NS_IMPL_RELEASE(nsHistoryEntry)
|
|
|
|
nsresult
|
|
nsHistoryEntry::DestroyChildren() {
|
|
|
|
PRInt32 i, n;
|
|
|
|
n = mChildren.Count();
|
|
for (i = 0; i < n; i++) {
|
|
nsHistoryEntry* child = (nsHistoryEntry *) mChildren.ElementAt(i);
|
|
child->SetParent(nsnull);
|
|
delete child;
|
|
mChildCount--;
|
|
}
|
|
mChildren.Clear();
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsHistoryEntry::GetURL(const PRUnichar** aURL)
|
|
{
|
|
*aURL = mURL->GetUnicode();
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::SetURL(const PRUnichar* aURL)
|
|
{
|
|
|
|
if (mURL)
|
|
delete mURL;
|
|
mURL = new nsString(aURL);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::GetWebShell(nsIWebShell *& aResult)
|
|
{
|
|
aResult = mWS;
|
|
NS_IF_ADDREF(mWS);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::SetWebShell(nsIWebShell * aWebShell)
|
|
{
|
|
mWS = aWebShell;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::GetHistoryState(nsISupports ** aResult)
|
|
{
|
|
*aResult = mHistoryState;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::SetHistoryState(nsISupports * aState)
|
|
{
|
|
mHistoryState = aState;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::GetTitle(const PRUnichar** aTitle)
|
|
{
|
|
if (mTitle)
|
|
*aTitle = mTitle->GetUnicode();
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::SetTitle(const PRUnichar* aTitle)
|
|
{
|
|
|
|
if (mTitle)
|
|
delete mTitle;
|
|
if (aTitle)
|
|
mTitle = new nsString(aTitle);
|
|
return NS_OK;
|
|
}
|
|
|
|
PRInt32
|
|
nsHistoryEntry::GetChildCnt()
|
|
{
|
|
return mChildCount;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::GetChildAt(PRInt32 aIndex, nsHistoryEntry *& aResult)
|
|
{
|
|
if (PRUint32(aIndex) >= PRUint32(mChildren.Count())) {
|
|
aResult = nsnull;
|
|
}
|
|
else {
|
|
aResult = (nsHistoryEntry*) mChildren.ElementAt(aIndex);
|
|
// NS_IF_ADDREF(aResult);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsHistoryEntry::SetSessionHistoryID(nsISessionHistory * aHistoryListID)
|
|
{
|
|
NS_IF_RELEASE(mHistoryList);
|
|
mHistoryList = aHistoryListID;
|
|
NS_ADDREF(aHistoryListID);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsHistoryEntry::SetParent(nsHistoryEntry* aParent)
|
|
{
|
|
// NS_IF_RELEASE(mParent);
|
|
mParent = aParent;
|
|
// NS_IF_ADDREF(aParent);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsHistoryEntry::GetParent(nsHistoryEntry *& aParent)
|
|
{
|
|
|
|
aParent = mParent;
|
|
// NS_IF_ADDREF(mParent);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsHistoryEntry::AddChild(nsHistoryEntry* aChild)
|
|
{
|
|
NS_PRECONDITION(nsnull != aChild, "null ptr");
|
|
if (nsnull == aChild) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
mChildren.AppendElement(aChild);
|
|
mChildCount++;
|
|
aChild->SetParent(this);
|
|
// NS_ADDREF(aChild);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a historyentry for the given webshell. If the
|
|
* webshell has children, this method recursively goes down
|
|
* the tree and creates entries for the children too.
|
|
*/
|
|
|
|
nsresult
|
|
nsHistoryEntry::Create(nsIWebShell * aWebShell, nsHistoryEntry * aParent, nsISessionHistory * aSHist) {
|
|
|
|
const PRUnichar * url = nsnull;
|
|
|
|
|
|
// Get the webshell's url.
|
|
aWebShell->GetURL(&url);
|
|
// save the webshell's URL in the history entry
|
|
SetURL(url);
|
|
|
|
|
|
//Save the webshell id
|
|
SetWebShell(aWebShell);
|
|
|
|
if (APP_DEBUG) printf("SessionHistory::Create Creating Historyentry %x for webshell %x, parent entry = %x\n", (unsigned int)this, (unsigned int)aWebShell, (unsigned int) aParent);
|
|
|
|
if (aParent)
|
|
aParent->AddChild(this);
|
|
|
|
// Save the handle to the window's history list
|
|
SetSessionHistoryID(aSHist);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsHistoryEntry *
|
|
GenerateTree(nsIWebShell * aWebShell, nsHistoryEntry * aParent, nsISessionHistory * aSHist) {
|
|
|
|
nsHistoryEntry * hEntry = nsnull;
|
|
|
|
hEntry = new nsHistoryEntry;
|
|
|
|
if (!hEntry) {
|
|
NS_ASSERTION(PR_FALSE, "Could not create a History Entry. Out of memory");
|
|
return (nsHistoryEntry *)nsnull;
|
|
}
|
|
|
|
hEntry->Create(aWebShell, aParent, aSHist);
|
|
|
|
// If the webshell has children, go thro' the child list and create
|
|
// the history tree for the children recursively.
|
|
|
|
PRInt32 cnt = 0;
|
|
aWebShell->GetChildCount(cnt);
|
|
if (cnt > 0) {
|
|
for (int i=0; i<cnt; i++) {
|
|
nsIWebShell * childWS = nsnull;
|
|
//nsHistoryEntry * hChild = nsnull;
|
|
|
|
aWebShell->ChildAt(i, childWS);
|
|
if (childWS) {
|
|
GenerateTree(childWS, hEntry, aSHist);
|
|
}
|
|
}
|
|
}
|
|
return hEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the historyentry corresponding to a WebShell */
|
|
nsHistoryEntry *
|
|
nsHistoryEntry::GetHistoryForWS(nsIWebShell * aWebShell) {
|
|
nsIWebShell * cWS = nsnull;
|
|
nsHistoryEntry * result = nsnull;
|
|
|
|
|
|
/* Get the webshell for the current entry */
|
|
GetWebShell(cWS);
|
|
|
|
if (cWS == aWebShell) {
|
|
return this;
|
|
}
|
|
|
|
PRInt32 cnt = GetChildCnt();
|
|
if (cnt > 0) {
|
|
for(int i=0; i<cnt; i++) {
|
|
|
|
nsHistoryEntry * child = nsnull;
|
|
GetChildAt(i, child);
|
|
if (child) {
|
|
result = child->GetHistoryForWS(aWebShell);
|
|
}
|
|
if (result)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (nsHistoryEntry *) result;
|
|
|
|
} /* Get subtree for WS */
|
|
|
|
|
|
/* Load the history item in the window */
|
|
PRBool
|
|
nsHistoryEntry::Load(nsIWebShell * aPrevEntry, PRBool aIsReload) {
|
|
|
|
nsHistoryEntry * cur=nsnull;
|
|
PRBool urlChanged = PR_FALSE;
|
|
int i = 0;
|
|
//nsIWebShell * pWS = nsnull, *cWS=nsnull;
|
|
nsIWebShell *prev=nsnull;
|
|
PRBool result = PR_FALSE;
|
|
nsString* cSURL=nsnull, * pSURL=nsnull;
|
|
const PRUnichar * pURL=nsnull, * cURL=nsnull;
|
|
|
|
cur = this;
|
|
prev = aPrevEntry;
|
|
|
|
if (prev) {
|
|
prev->GetURL(&pURL);
|
|
pSURL = new nsString(pURL);
|
|
|
|
}
|
|
if (cur) {
|
|
cur->GetURL(&cURL);
|
|
cSURL = new nsString(cURL);
|
|
}
|
|
|
|
|
|
// NS_ADDREF(aPrevEntry);
|
|
|
|
if (!cur || !prev) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
//Compare the URLs
|
|
{
|
|
if ((*pSURL) == cURL)
|
|
urlChanged = PR_FALSE;
|
|
else
|
|
urlChanged = PR_TRUE;
|
|
} // compareURLs
|
|
|
|
|
|
/* The URL to be loaded in it */
|
|
cur->GetURL(&cURL);
|
|
|
|
if (urlChanged || aIsReload) {
|
|
if (prev) {
|
|
PRBool isInSHist=PR_FALSE, isLoadingDoc=PR_FALSE;
|
|
prev->GetIsInSHist(isInSHist);
|
|
mHistoryList->GetLoadingFlag(isLoadingDoc);
|
|
|
|
if ((isInSHist && isLoadingDoc) || aIsReload) {
|
|
if (APP_DEBUG) printf("SessionHistory::Load Loading URL %s in webshell %x\n", cSURL->ToNewCString(), (unsigned int) prev);
|
|
|
|
/* Get the child count of the webshell for a later use */
|
|
PRInt32 ccount=0;
|
|
prev->GetChildCount(ccount);
|
|
nsISupports * historyObject = nsnull;
|
|
GetHistoryState(&historyObject);
|
|
prev->LoadURL(cURL, nsnull, PR_FALSE, (nsLoadFlags) (aIsReload?nsIChannel::LOAD_NORMAL:LOAD_HISTORY), 0, historyObject);
|
|
if (aIsReload && (ccount > 0)) {
|
|
/* If this is a reload, on a page with frames, you want to return
|
|
* true so that consecutive calls by the frame children in to
|
|
* session History will get compared properly. We must fall into
|
|
* this case only for top level webshells with frame children.
|
|
*/
|
|
if (APP_DEBUG) printf("Returning from Load(). Located a webshell with frame children\n");
|
|
return PR_TRUE;
|
|
}
|
|
}
|
|
else if (!isInSHist && isLoadingDoc) {
|
|
prev->SetURL(cURL);
|
|
}
|
|
}
|
|
}
|
|
else if (!urlChanged ) {
|
|
/* Mark the changed flag to false. This is used in the end to determine
|
|
* whether we are done with the whole loading process for this history
|
|
*/
|
|
if (APP_DEBUG) printf("SessionHistory::Load URLs in webshells %x & %x match \n", (unsigned int) mWS, (unsigned int) prev);
|
|
}
|
|
|
|
/* Make sure the child windows are in par */
|
|
|
|
PRInt32 cnt=0, ccnt=0, pcnt=0;
|
|
ccnt = cur->GetChildCnt();
|
|
prev->GetChildCount(pcnt);
|
|
|
|
/* If the current entry to be loaded and the one on page don't have
|
|
* the same # of children, maybe the one on screen is is in the process of
|
|
* building. Don't compare the children.
|
|
*/
|
|
cnt = ccnt;
|
|
if (pcnt < ccnt)
|
|
cnt = pcnt;
|
|
|
|
for (i=0; i<cnt; i++){
|
|
nsHistoryEntry *cChild=nsnull;
|
|
nsIWebShell * pChild=nsnull;
|
|
|
|
cur->GetChildAt(i, cChild); // historyentry
|
|
prev->ChildAt(i, pChild); //webshell
|
|
|
|
result = cChild->Load(pChild, PR_FALSE);
|
|
if (result)
|
|
break;
|
|
}
|
|
if (ccnt != pcnt)
|
|
result = PR_TRUE;
|
|
|
|
|
|
// NS_IF_RELEASE(aPrevEntry);
|
|
|
|
return result;
|
|
} /* Load */
|
|
|
|
|
|
nsHistoryEntry *
|
|
nsHistoryEntry::GetRootDoc(void) {
|
|
|
|
nsHistoryEntry * top= this;
|
|
|
|
for (;;) {
|
|
nsHistoryEntry* parent;
|
|
top->GetParent(parent);
|
|
if (parent == nsnull)
|
|
break;
|
|
top = parent;
|
|
}
|
|
// NS_ADDREF(top);
|
|
return top;
|
|
}
|
|
|
|
|
|
class nsSessionHistory: public nsISessionHistory
|
|
{
|
|
|
|
public:
|
|
nsSessionHistory();
|
|
|
|
//nsISupports
|
|
NS_DECL_ISUPPORTS
|
|
|
|
//nsISessionHistory interfaces
|
|
|
|
|
|
/**
|
|
* Go forward in history
|
|
*/
|
|
NS_IMETHOD GoForward(nsIWebShell * prev);
|
|
|
|
/**
|
|
* Go Back in History
|
|
*/
|
|
NS_IMETHOD GoBack(nsIWebShell * prev);
|
|
|
|
/**
|
|
* Reload the current history entry
|
|
*/
|
|
#ifdef NECKO
|
|
NS_IMETHOD Reload(nsIWebShell * aPrev, nsLoadFlags aReloadFlags);
|
|
#else
|
|
NS_IMETHOD Reload(nsIWebShell * aPrev, nsURLReloadType aReloadType);
|
|
#endif
|
|
|
|
/**
|
|
* whether you can go forward in History
|
|
*/
|
|
NS_IMETHOD canForward(PRBool &aResult);
|
|
|
|
/**
|
|
* whether you can go back in History
|
|
*/
|
|
NS_IMETHOD canBack(PRBool &aResult);
|
|
|
|
/**
|
|
* Add a new URL to the History List
|
|
*/
|
|
NS_IMETHOD add(nsIWebShell * aWebShell);
|
|
|
|
/**
|
|
* Go to a particular point in the history list
|
|
*/
|
|
NS_IMETHOD Goto(PRInt32 aHistoryIndex, nsIWebShell * prev, PRBool aIsReload);
|
|
|
|
/**
|
|
* Get the length of the History list
|
|
*/
|
|
NS_IMETHOD getHistoryLength(PRInt32 & aResult);
|
|
|
|
/**
|
|
* Get the index of the current document in the history list
|
|
*/
|
|
NS_IMETHOD getCurrentIndex(PRInt32 & aResult);
|
|
|
|
/**
|
|
* Make a clone of the Session History. This will
|
|
* make a deep copy of the Session history data structures.
|
|
* This is used when you create a navigator window from the
|
|
* current browser window
|
|
*/
|
|
// NS_IMETHOD cloneHistory(nsISessionHistory * aSessionHistory);
|
|
|
|
/**
|
|
* Set the flag whether a history entry is in the middle of loading a
|
|
* doc. See comments below for details
|
|
*/
|
|
NS_IMETHOD SetLoadingFlag(PRBool aFlag);
|
|
|
|
/**
|
|
* Get the flag whether a history entry is in the middle of loading a
|
|
* doc. See comments below for details
|
|
*/
|
|
NS_IMETHOD GetLoadingFlag(PRBool &aFlag);
|
|
|
|
/**
|
|
* Set the historyentry that is in the middle of loading a doc
|
|
*/
|
|
NS_IMETHOD SetLoadingHistoryEntry(nsHistoryEntry * aHistoryEntry);
|
|
|
|
|
|
/**
|
|
* Get the URL of the index
|
|
*/
|
|
NS_IMETHOD GetURLForIndex(PRInt32 aIndex, const PRUnichar ** aURL);
|
|
|
|
|
|
/**
|
|
* Set the URL of the index
|
|
*/
|
|
NS_IMETHOD SetURLForIndex(PRInt32 aIndex, const PRUnichar * aURL);
|
|
|
|
|
|
/**
|
|
* Get the title of the index
|
|
*/
|
|
NS_IMETHOD GetTitleForIndex(PRInt32 aIndex, const PRUnichar ** aTitle);
|
|
|
|
|
|
/**
|
|
* Set the Title of the index
|
|
*/
|
|
|
|
NS_IMETHOD SetTitleForIndex(PRInt32 aIndex, const PRUnichar * aTitle);
|
|
|
|
/**
|
|
* Get the History object of the index
|
|
*/
|
|
NS_IMETHOD GetHistoryObjectForIndex(PRInt32 aIndex, nsISupports ** aState);
|
|
|
|
|
|
/**
|
|
* Set the History state of the index
|
|
*/
|
|
|
|
NS_IMETHOD SetHistoryObjectForIndex(PRInt32 aIndex, nsISupports * aState);
|
|
protected:
|
|
|
|
virtual ~nsSessionHistory();
|
|
|
|
private:
|
|
PRInt32 mHistoryLength;
|
|
PRInt32 mHistoryCurrentIndex;
|
|
nsVoidArray mHistoryEntries;
|
|
// PRBool mIsBackOrForward;
|
|
|
|
/** Following member is used to identify whether we are in the
|
|
* middle of loading a history document. The mIsLoadingDoc flag is
|
|
* used to determine whether the document that is curently loaded
|
|
* in the window s'd go to the end of the historylist or to be
|
|
* handed over to the current history entry (mIndexOfHistoryInLoad)
|
|
* that is in the process of loading. The current history entry
|
|
* being loaded uses this new historyentry to decide whether the
|
|
* document is completely in par with the one in history. If not, it
|
|
* will initiate further loads. When the document currently loaded is
|
|
* completely on par with the one in history, it will clear the
|
|
* mIsLoadingDoc flag. Any new URL loaded from then on, will go to the
|
|
* end of the history list. Note: these members are static.
|
|
*/
|
|
PRBool mIsLoadingDoc;
|
|
nsHistoryEntry * mHistoryEntryInLoad;
|
|
|
|
|
|
};
|
|
|
|
|
|
nsSessionHistory::nsSessionHistory()
|
|
{
|
|
mHistoryLength = 0;
|
|
mHistoryCurrentIndex = -1;
|
|
mIsLoadingDoc = 0;
|
|
mHistoryEntryInLoad = (nsHistoryEntry *) nsnull;
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
|
|
nsSessionHistory::~nsSessionHistory()
|
|
{
|
|
|
|
// Delete all HistoryEntries
|
|
|
|
for(int i=0; i<mHistoryLength; i++) {
|
|
nsHistoryEntry * hEntry = (nsHistoryEntry *)mHistoryEntries[i];
|
|
if (hEntry)
|
|
delete hEntry;
|
|
//NS_IF_RELEASE(hEntry);
|
|
}
|
|
mHistoryLength=0;
|
|
mHistoryCurrentIndex=-1;
|
|
|
|
}
|
|
|
|
//ISupports...
|
|
NS_IMPL_ISUPPORTS(nsSessionHistory, kISessionHistoryIID);
|
|
|
|
/**
|
|
* Called to a new page is visited either through link click or
|
|
* by typing in the urlbar.
|
|
*/
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::add(nsIWebShell * aWebShell)
|
|
{
|
|
//nsresult rv = NS_OK;
|
|
nsHistoryEntry * hEntry = nsnull;
|
|
nsIWebShell * parent = nsnull;
|
|
|
|
if (!aWebShell) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
aWebShell->GetParent(parent);
|
|
|
|
if (!parent) {
|
|
if(mIsLoadingDoc) {
|
|
/* We are currently loading a history entry. Pass it to
|
|
* Load() to check if the URLs match. Load() will take care
|
|
* of differences in URL
|
|
*/
|
|
|
|
nsresult ret = mHistoryEntryInLoad->Load(aWebShell, PR_FALSE);
|
|
if (!ret) {
|
|
/* The URL in the webshell exactly matches with the
|
|
* one in history. Clear all flags and return.
|
|
*/
|
|
|
|
mIsLoadingDoc = PR_FALSE;
|
|
mHistoryEntryInLoad = (nsHistoryEntry *)nsnull;
|
|
}
|
|
return NS_OK;
|
|
} // mIsLoadingDoc
|
|
|
|
hEntry = new nsHistoryEntry();
|
|
if (!hEntry) {
|
|
NS_ASSERTION(PR_FALSE, "nsSessionHistory::add Low memory");
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
hEntry->Create(aWebShell, nsnull, this);
|
|
|
|
/* Set the flag in webshell that indicates that it has been
|
|
* added to session History
|
|
*/
|
|
aWebShell->SetIsInSHist(PR_TRUE);
|
|
|
|
// Add the URL to the history
|
|
if ((mHistoryLength - (mHistoryCurrentIndex+1)) > 0) {
|
|
/* We are somewhere in the middle of the history and a
|
|
* new page was visited. Purge all entries from the current index
|
|
* till the end of the list and append the current page to the
|
|
* list
|
|
*/
|
|
|
|
for(int i=mHistoryLength-1; i>mHistoryCurrentIndex; i--) {
|
|
nsHistoryEntry * hEntry2 = (nsHistoryEntry *)mHistoryEntries.ElementAt(i);
|
|
//NS_IF_RELEASE(hEntry2);
|
|
delete hEntry2;
|
|
mHistoryEntries.RemoveElementAt(i);
|
|
mHistoryLength--;
|
|
}
|
|
}
|
|
|
|
mHistoryEntries.AppendElement((void *)hEntry);
|
|
mHistoryLength++;
|
|
mHistoryCurrentIndex++;
|
|
return NS_OK;
|
|
} // (!mParent)
|
|
|
|
else {
|
|
|
|
/* This is a frame webshell. Check if it is a new frame. If so,
|
|
* append to the existing history entry. Else, create a
|
|
* new tree to record the change in URL
|
|
*/
|
|
|
|
PRBool inSHist = PR_TRUE;
|
|
|
|
aWebShell->GetIsInSHist(inSHist);
|
|
|
|
if (!inSHist) {
|
|
|
|
nsHistoryEntry * curEntry=nsnull, * newEntry=nsnull,
|
|
* parentEntry=nsnull;
|
|
|
|
if (!mIsLoadingDoc) {
|
|
/*This is a newly created frame. Just add it to the current entry */
|
|
|
|
// Get a handle to the parent of the new frame WS;
|
|
nsIWebShell * parentWS = nsnull;
|
|
aWebShell->GetParent(parentWS);
|
|
|
|
curEntry = (nsHistoryEntry *) mHistoryEntries.ElementAt(mHistoryCurrentIndex);
|
|
// Get the history entry corresponding to the parentWS
|
|
if (curEntry)
|
|
parentEntry = curEntry->GetHistoryForWS(parentWS);
|
|
|
|
// Create a new HistoryEntry for the frame & init values
|
|
newEntry = new nsHistoryEntry();
|
|
if (!newEntry) {
|
|
NS_ASSERTION(PR_FALSE, "nsSessionHistory::add Low memory");
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
newEntry->Create(aWebShell, parentEntry, this);
|
|
aWebShell->SetIsInSHist(PR_TRUE);
|
|
|
|
if (parentWS)
|
|
NS_RELEASE(parentWS);
|
|
} // !mIsLoadingDoc
|
|
else {
|
|
|
|
/* We are in the middle of loading a page. Pass it on to Load
|
|
* to check if we are loading the right page
|
|
*/
|
|
PRBool ret=PR_TRUE;
|
|
|
|
nsIWebShell * root=nsnull;
|
|
aWebShell->GetRootWebShell(root);
|
|
if (!root) {
|
|
NS_ASSERTION(0,"nsSessionHistory::add Couldn't get root webshell");
|
|
return NS_OK;
|
|
}
|
|
ret = mHistoryEntryInLoad->Load(root, PR_FALSE);
|
|
if (!ret) {
|
|
/* The page in the webshel matches exactly with the one in history.
|
|
* Clear all flags and return.
|
|
*/
|
|
|
|
mIsLoadingDoc = PR_FALSE;
|
|
mHistoryEntryInLoad = (nsHistoryEntry *)nsnull;
|
|
} //!ret
|
|
aWebShell->SetIsInSHist(PR_TRUE);
|
|
if (root)
|
|
NS_RELEASE(root);
|
|
}
|
|
} // !InSHist
|
|
else {
|
|
/* THis page is in history. May be the frame page changed. */
|
|
if (!mIsLoadingDoc) {
|
|
/* We are not in the middle of loading a history entry. Add this
|
|
* to the history entry
|
|
*/
|
|
nsIWebShell * root = nsnull;
|
|
nsHistoryEntry * newEntry = nsnull;
|
|
|
|
aWebShell->GetRootWebShell(root);
|
|
|
|
if (root)
|
|
newEntry = GenerateTree(root, nsnull, this);
|
|
if (newEntry) {
|
|
if ((mHistoryLength - (mHistoryCurrentIndex+1)) > 0) {
|
|
/* We are somewhere in the middle of the history and a
|
|
* new page was visited. Purge all entries from the current
|
|
* index till the end of the list and append the current
|
|
* page to the list
|
|
*/
|
|
|
|
for(int i=mHistoryLength-1; i>mHistoryCurrentIndex; i--) {
|
|
nsHistoryEntry * hiEntry = (nsHistoryEntry *)mHistoryEntries.ElementAt(i);
|
|
//NS_IF_RELEASE(hiEntry);
|
|
delete hiEntry;
|
|
mHistoryEntries.RemoveElementAt(i);
|
|
mHistoryLength--;
|
|
}
|
|
}
|
|
mHistoryEntries.AppendElement((void *)newEntry);
|
|
mHistoryLength++;
|
|
mHistoryCurrentIndex++;
|
|
return NS_OK;
|
|
} //newEntry
|
|
if (root)
|
|
NS_RELEASE(root);
|
|
} // (!mIsLoadingDoc)
|
|
else {
|
|
|
|
/* We are in the middle of loading a history entry.
|
|
* Send it to Load() for Comparison purposes
|
|
*/
|
|
nsIWebShell * root=nsnull;
|
|
aWebShell->GetRootWebShell(root);
|
|
if (!root) {
|
|
NS_ASSERTION(0, "nsSessionHistory::add, Couldn't get root webshell");
|
|
return NS_OK;
|
|
}
|
|
nsresult ret = mHistoryEntryInLoad->Load(root, PR_FALSE);
|
|
if (!ret) {
|
|
/* The page in webshell matches exactly with the one in history.
|
|
* Clear all flags and return.
|
|
*/
|
|
|
|
mIsLoadingDoc = PR_FALSE;
|
|
mHistoryEntryInLoad = (nsHistoryEntry *)nsnull;
|
|
|
|
} //!ret
|
|
if (root)
|
|
NS_RELEASE(root);
|
|
} //else for (!mIsloadingDoc)
|
|
} // else for (!InSHist)
|
|
}
|
|
if (parent)
|
|
NS_RELEASE(parent);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::Goto(PRInt32 aGotoIndex, nsIWebShell * prev, PRBool aIsReload)
|
|
{
|
|
PRBool result = PR_FALSE;
|
|
|
|
if ((aGotoIndex < 0) || (aGotoIndex >= mHistoryLength))
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsHistoryEntry * hCurrentEntry = nsnull;
|
|
|
|
//get a handle to the current page to be passed to nsHistoryEntry
|
|
// as the previous page.
|
|
hCurrentEntry = (nsHistoryEntry *) mHistoryEntries.ElementAt(aGotoIndex);
|
|
|
|
// Set the flag that indicates that we are currently
|
|
// traversing with it the history
|
|
mIsLoadingDoc = PR_TRUE;
|
|
mHistoryEntryInLoad = hCurrentEntry;
|
|
|
|
//Load the page
|
|
const PRUnichar * url;
|
|
hCurrentEntry->GetURL(&url);
|
|
nsString urlString(url);
|
|
if (APP_DEBUG) printf("nsSessionHistory::Goto, Trying to load URL %s\n", urlString.ToNewCString());
|
|
|
|
if (hCurrentEntry != nsnull)
|
|
result = hCurrentEntry->Load(prev, aIsReload);
|
|
if (!result) {
|
|
mIsLoadingDoc = PR_FALSE;
|
|
mHistoryEntryInLoad = (nsHistoryEntry *) nsnull;
|
|
}
|
|
|
|
#if 0
|
|
if (aIsReload) {
|
|
prev->LoadURL(urlString.GetUnicode(), nsnull, PR_FALSE);
|
|
}
|
|
else {
|
|
if (hCurrentEntry != nsnull)
|
|
result = hCurrentEntry->Load(prev);
|
|
}
|
|
|
|
if (!result) {
|
|
mIsLoadingDoc = PR_FALSE;
|
|
mHistoryEntryInLoad = (nsHistoryEntry *) nsnull;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
|
|
|
|
mHistoryCurrentIndex = aGotoIndex;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
#ifdef NECKO
|
|
nsSessionHistory::Reload(nsIWebShell * aPrev, nsLoadFlags aReloadFlags)
|
|
#else
|
|
nsSessionHistory::Reload(nsIWebShell * aPrev, nsURLReloadType aReloadType)
|
|
#endif
|
|
{
|
|
|
|
// Call goto with the Reload flag set to true
|
|
Goto(mHistoryCurrentIndex, aPrev, PR_TRUE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::GoBack(nsIWebShell * aPrev)
|
|
{
|
|
//nsHistoryEntry * hEntry=nsnull;
|
|
|
|
if (mHistoryCurrentIndex <= 0)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
Goto((mHistoryCurrentIndex -1), aPrev, PR_FALSE);
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::GoForward(nsIWebShell * aPrev)
|
|
{
|
|
if (mHistoryCurrentIndex == mHistoryLength-1)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
Goto((mHistoryCurrentIndex+1), aPrev, PR_FALSE);
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::SetLoadingFlag(PRBool aFlag)
|
|
{
|
|
mIsLoadingDoc = aFlag;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::GetLoadingFlag(PRBool &aFlag)
|
|
{
|
|
aFlag = mIsLoadingDoc;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::SetLoadingHistoryEntry(nsHistoryEntry * aHistoryEntry)
|
|
{
|
|
mHistoryEntryInLoad = aHistoryEntry;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::canForward(PRBool & aResult)
|
|
{
|
|
if (mHistoryCurrentIndex == mHistoryLength-1)
|
|
aResult = PR_FALSE;
|
|
else
|
|
aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::canBack(PRBool & aResult)
|
|
{
|
|
if (mHistoryCurrentIndex == 0)
|
|
aResult = PR_FALSE;
|
|
else
|
|
aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::getHistoryLength(PRInt32 & aResult)
|
|
{
|
|
aResult=mHistoryLength;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::getCurrentIndex(PRInt32 & aResult)
|
|
{
|
|
aResult = mHistoryCurrentIndex;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::GetURLForIndex(PRInt32 aIndex, const PRUnichar** aURL)
|
|
{
|
|
|
|
nsHistoryEntry * hist=nsnull;
|
|
|
|
if (aIndex < 0 || aIndex >= mHistoryLength)
|
|
{
|
|
if (APP_DEBUG) printf("nsSessionHistory::GetURLForIndex Returning error in GetURL for Index\n");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
hist = (nsHistoryEntry *) mHistoryEntries.ElementAt(aIndex);
|
|
|
|
|
|
if (hist)
|
|
hist->GetURL(aURL);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::SetURLForIndex(PRInt32 aIndex, const PRUnichar* aURL)
|
|
{
|
|
|
|
nsHistoryEntry * hist=nsnull;
|
|
|
|
if (aIndex < 0 || aIndex >= mHistoryLength)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
hist = (nsHistoryEntry *) mHistoryEntries.ElementAt(aIndex);
|
|
|
|
hist->SetURL(aURL);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::GetTitleForIndex(PRInt32 aIndex, const PRUnichar** aTitle)
|
|
{
|
|
|
|
nsHistoryEntry * hist=nsnull;
|
|
|
|
if (aIndex < 0 || aIndex >= mHistoryLength)
|
|
{
|
|
if (APP_DEBUG) printf("nsSessionHistory::GetTitleForIndex Returning error in GetURL for Index\n");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
hist = (nsHistoryEntry *) mHistoryEntries.ElementAt(aIndex);
|
|
|
|
if (hist)
|
|
hist->GetTitle(aTitle);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::SetTitleForIndex(PRInt32 aIndex, const PRUnichar* aTitle)
|
|
{
|
|
|
|
nsHistoryEntry * hist=nsnull;
|
|
|
|
if (aIndex < 0 || aIndex >= mHistoryLength)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
hist = (nsHistoryEntry *) mHistoryEntries.ElementAt(aIndex);
|
|
|
|
hist->SetTitle(aTitle);
|
|
nsString title(aTitle);
|
|
if(APP_DEBUG) printf("Setting title %s for index %d\n", title.ToNewCString(), aIndex);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::GetHistoryObjectForIndex(PRInt32 aIndex, nsISupports** aState)
|
|
{
|
|
|
|
nsHistoryEntry * hist=nsnull;
|
|
|
|
if (aIndex < 0 || aIndex >= mHistoryLength)
|
|
{
|
|
if (APP_DEBUG) printf("nsSessionHistory::GetURLForIndex Returning error in GetURL for Index\n");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
hist = (nsHistoryEntry *) mHistoryEntries.ElementAt(aIndex);
|
|
|
|
|
|
if (hist)
|
|
hist->GetHistoryState(aState);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsSessionHistory::SetHistoryObjectForIndex(PRInt32 aIndex, nsISupports* aState)
|
|
{
|
|
|
|
nsHistoryEntry * hist=nsnull;
|
|
|
|
if (aIndex < 0 || aIndex >= mHistoryLength)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
hist = (nsHistoryEntry *) mHistoryEntries.ElementAt(aIndex);
|
|
|
|
hist->SetHistoryState(aState);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_EXPORT nsresult NS_NewSessionHistory(nsISessionHistory** aResult)
|
|
{
|
|
if (nsnull == aResult) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
*aResult = new nsSessionHistory();
|
|
if (nsnull == *aResult) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
NS_ADDREF(*aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
#if 0
|
|
NS_IMETHODIMP
|
|
cloneHistory(nsISessionHistory * aSessionHistory) {
|
|
|
|
return NS_OK;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Factory code for creating nsSessionHistory
|
|
|
|
class nsSessionHistoryFactory : public nsIFactory
|
|
{
|
|
public:
|
|
nsSessionHistoryFactory();
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIFactory methods
|
|
NS_IMETHOD CreateInstance(nsISupports *aOuter,
|
|
const nsIID &aIID,
|
|
void **aResult);
|
|
|
|
NS_IMETHOD LockFactory(PRBool aLock);
|
|
protected:
|
|
virtual ~nsSessionHistoryFactory();
|
|
};
|
|
|
|
|
|
nsSessionHistoryFactory::nsSessionHistoryFactory()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsresult
|
|
nsSessionHistoryFactory::LockFactory(PRBool aLock)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
nsSessionHistoryFactory::~nsSessionHistoryFactory()
|
|
{
|
|
NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction");
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(nsSessionHistoryFactory, kIFactoryIID);
|
|
|
|
|
|
nsresult
|
|
nsSessionHistoryFactory::CreateInstance(nsISupports *aOuter,
|
|
const nsIID &aIID,
|
|
void **aResult)
|
|
{
|
|
nsresult rv;
|
|
nsSessionHistory* inst;
|
|
|
|
if (aResult == NULL) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
*aResult = NULL;
|
|
if (nsnull != aOuter) {
|
|
rv = NS_ERROR_NO_AGGREGATION;
|
|
goto done;
|
|
}
|
|
|
|
|
|
NS_NEWXPCOM(inst, nsSessionHistory);
|
|
if (inst == NULL) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
goto done;
|
|
}
|
|
|
|
NS_ADDREF(inst);
|
|
rv = inst->QueryInterface(aIID, aResult);
|
|
NS_RELEASE(inst);
|
|
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
|
|
extern "C" NS_APPSHELL nsresult
|
|
NS_NewSessionHistoryFactory(nsIFactory** aFactory)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsIFactory* inst = new nsSessionHistoryFactory();
|
|
if (nsnull == inst) {
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
else {
|
|
NS_ADDREF(inst);
|
|
}
|
|
*aFactory = inst;
|
|
return rv;
|
|
}
|