зеркало из https://github.com/mozilla/pjs.git
fixes for:
#61140 - delete history.dat if it gets corrupted #56867 - implement "First Visited" #19370 - implement "Visit Count" #33697 - clean up nsGlobalHistory::OpenDB a bit more (doesn't fix the leak yet) sr=waterson
This commit is contained in:
Родитель
71a28304d6
Коммит
8fd8cdd782
|
@ -170,6 +170,9 @@
|
|||
class="treecell-indent treecell-bookmark"/>
|
||||
<treecell value="rdf:http://home.netscape.com/NC-rdf#URL" />
|
||||
<treecell value="rdf:http://home.netscape.com/NC-rdf#Date" />
|
||||
<treecell value="rdf:http://home.netscape.com/NC-rdf#FirstVisitDate" />
|
||||
<treecell value="rdf:http://home.netscape.com/NC-rdf#Referrer" />
|
||||
<treecell value="rdf:http://home.netscape.com/NC-rdf#VisitCount" />
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
|
@ -197,6 +200,27 @@
|
|||
|
||||
<splitter class="tree-splitter"/>
|
||||
|
||||
<treecol flex="1" id="FirstVisitDate"
|
||||
sortSeparators="true" persist="hidden width"
|
||||
resource="http://home.netscape.com/NC-rdf#FirstVisitDate"
|
||||
resource2="http://home.netscape.com/NC-rdf#Name"/>
|
||||
|
||||
<splitter class="tree-splitter"/>
|
||||
|
||||
<treecol flex="1" id="Referrer"
|
||||
sortSeparators="true" persist="hidden width"
|
||||
resource="http://home.netscape.com/NC-rdf#Referrer"
|
||||
resource2="http://home.netscape.com/NC-rdf#Name"/>
|
||||
|
||||
<splitter class="tree-splitter"/>
|
||||
|
||||
<treecol flex="1" id="VisitCount"
|
||||
sortSeparators="true" persist="hidden width"
|
||||
resource="http://home.netscape.com/NC-rdf#VisitCount"
|
||||
resource2="http://home.netscape.com/NC-rdf#Name"/>
|
||||
|
||||
<splitter class="tree-splitter"/>
|
||||
|
||||
<treecol persist="width" fixed="true" width="14" id="PopupColumn"/>
|
||||
</treecolgroup>
|
||||
|
||||
|
@ -214,6 +238,18 @@
|
|||
value="&tree.header.date.label;"
|
||||
onclick="return TriStateColumnSort('Date');"
|
||||
observes="Date"/>
|
||||
<treecell class="treecell-header sortDirectionIndicator"
|
||||
value="&tree.header.firstvisitdate.label;"
|
||||
onclick="return TriStateColumnSort('FirstVisitDate');"
|
||||
observes="FirstVisitDate"/>
|
||||
<treecell class="treecell-header sortDirectionIndicator"
|
||||
value="&tree.header.referrer.label;"
|
||||
onclick="return TriStateColumnSort('Referrer');"
|
||||
observes="Referrer"/>
|
||||
<treecell class="treecell-header sortDirectionIndicator"
|
||||
value="&tree.header.visitcount.label;"
|
||||
onclick="return TriStateColumnSort('VisitCount');"
|
||||
observes="VisitCount"/>
|
||||
<treecell class="treecell-header" allowevents="true" id="popupCell">
|
||||
<menu>
|
||||
<image class="treecell-popup-icon"/>
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
<!ENTITY findHisCmd.accesskey "f">
|
||||
<!ENTITY historyWindowTitle.label "History">
|
||||
<!ENTITY tree.header.name.label "Title">
|
||||
<!ENTITY tree.header.name.accesskey "t">
|
||||
<!ENTITY tree.header.url.label "URL">
|
||||
<!ENTITY tree.header.url.label "u">
|
||||
<!ENTITY tree.header.date.label "Last Visited">
|
||||
<!ENTITY tree.header.date.label "l">
|
||||
<!ENTITY tree.header.firstvisitdate.label "First Visited">
|
||||
<!ENTITY tree.header.referrer.label "Referrer">
|
||||
<!ENTITY tree.header.visitcount.label "Visit Count">
|
||||
<!ENTITY menuitem.view.unsorted.label "Unsorted">
|
||||
<!ENTITY menuitem.view.unsorted.accesskey "u">
|
||||
<!ENTITY menuitem.view.ascending.label "A > Z Sort Order">
|
||||
|
|
|
@ -63,6 +63,7 @@ PRInt32 nsGlobalHistory::gRefCnt;
|
|||
nsIRDFService* nsGlobalHistory::gRDFService;
|
||||
nsIRDFResource* nsGlobalHistory::kNC_Page;
|
||||
nsIRDFResource* nsGlobalHistory::kNC_Date;
|
||||
nsIRDFResource* nsGlobalHistory::kNC_FirstVisitDate;
|
||||
nsIRDFResource* nsGlobalHistory::kNC_VisitCount;
|
||||
nsIRDFResource* nsGlobalHistory::kNC_Name;
|
||||
nsIRDFResource* nsGlobalHistory::kNC_Referrer;
|
||||
|
@ -275,6 +276,7 @@ nsGlobalHistory::~nsGlobalHistory()
|
|||
|
||||
NS_IF_RELEASE(kNC_Page);
|
||||
NS_IF_RELEASE(kNC_Date);
|
||||
NS_IF_RELEASE(kNC_FirstVisitDate);
|
||||
NS_IF_RELEASE(kNC_VisitCount);
|
||||
NS_IF_RELEASE(kNC_Name);
|
||||
NS_IF_RELEASE(kNC_Referrer);
|
||||
|
@ -307,133 +309,22 @@ NS_IMPL_ISUPPORTS3(nsGlobalHistory, nsIGlobalHistory, nsIRDFDataSource, nsIRDFRe
|
|||
NS_IMETHODIMP
|
||||
nsGlobalHistory::AddPage(const char *aURL, const char *aReferrerURL, PRInt64 aDate)
|
||||
{
|
||||
NS_PRECONDITION(aURL != nsnull, "null ptr");
|
||||
if (! aURL)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
NS_PRECONDITION(mEnv != nsnull, "not initialized");
|
||||
if (! mEnv)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
NS_PRECONDITION(mStore != nsnull, "not initialized");
|
||||
if (! mStore)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
NS_PRECONDITION(mTable != nsnull, "not initialized");
|
||||
if (! mTable)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
NS_ENSURE_ARG_POINTER(aURL);
|
||||
NS_ENSURE_ARG_POINTER(mEnv);
|
||||
NS_ENSURE_ARG_POINTER(mStore);
|
||||
|
||||
nsresult rv;
|
||||
mdb_err err;
|
||||
|
||||
// Sanity check the URL
|
||||
PRInt32 len = PL_strlen(aURL);
|
||||
NS_ASSERTION(len != 0, "no URL");
|
||||
if (! len)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
rv = SaveLastPageVisited(aURL);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Okay, it's good. See if we've already got it in the database.
|
||||
mdbYarn yarn = { (void*) aURL, len, len, 0, 0, nsnull };
|
||||
|
||||
mdbOid rowId;
|
||||
nsMdbPtr<nsIMdbRow> row(mEnv);
|
||||
err = mStore->FindRow(mEnv, kToken_HistoryRowScope, kToken_URLColumn, &yarn,
|
||||
&rowId, getter_Acquires(row));
|
||||
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// For notifying observers, later...
|
||||
nsCOMPtr<nsIRDFResource> url;
|
||||
rv = gRDFService->GetResource(aURL, getter_AddRefs(url));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFDate> date;
|
||||
rv = gRDFService->GetDateLiteral(aDate, getter_AddRefs(date));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (row) {
|
||||
// Update last visit date. First get the old date so we can update observers...
|
||||
err = row->AliasCellYarn(mEnv, kToken_LastVisitDateColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
PRInt64 oldvalue;
|
||||
rv = CharsToPRInt64((const char*) yarn.mYarn_Buf, yarn.mYarn_Fill, &oldvalue);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFDate> olddate;
|
||||
rv = gRDFService->GetDateLiteral(aDate, getter_AddRefs(olddate));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// ...now set the new date.
|
||||
char buf[64];
|
||||
PRInt64ToChars(aDate, buf, sizeof(buf));
|
||||
|
||||
yarn.mYarn_Buf = (void*) buf;
|
||||
yarn.mYarn_Fill = yarn.mYarn_Size = PL_strlen(buf);
|
||||
|
||||
err = row->AddColumn(mEnv, kToken_LastVisitDateColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Notify observers
|
||||
rv = NotifyChange(url, kNC_Date, olddate, date);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
else {
|
||||
// Create a new row
|
||||
rowId.mOid_Scope = kToken_HistoryRowScope;
|
||||
rowId.mOid_Id = mdb_id(-1);
|
||||
|
||||
err = mTable->NewRow(mEnv, &rowId, getter_Acquires(row));
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Set the URL. 'yarn' is already set up to go.
|
||||
err = row->AddColumn(mEnv, kToken_URLColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Set the referrer, if one is provided
|
||||
if (aReferrerURL) {
|
||||
len = PL_strlen(aReferrerURL);
|
||||
yarn.mYarn_Buf = (void*) aReferrerURL;
|
||||
yarn.mYarn_Fill = yarn.mYarn_Size = len;
|
||||
|
||||
err = row->AddColumn(mEnv, kToken_ReferrerColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Notify observers
|
||||
nsCOMPtr<nsIRDFResource> referrer;
|
||||
rv = gRDFService->GetResource(aReferrerURL, getter_AddRefs(referrer));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NotifyAssert(url, kNC_Referrer, referrer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// Set the date.
|
||||
char buf[64];
|
||||
PRInt64ToChars(aDate, buf, sizeof(buf));
|
||||
|
||||
yarn.mYarn_Buf = (void*) buf;
|
||||
yarn.mYarn_Fill = yarn.mYarn_Size = PL_strlen(buf);
|
||||
|
||||
err = row->AddColumn(mEnv, kToken_LastVisitDateColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Notify observers
|
||||
rv = NotifyAssert(url, kNC_Date, date);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NotifyAssert(kNC_HistoryRoot, kNC_child, url);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
rv = AddPageToDatabase(aURL, aReferrerURL, aDate);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// We'd like to do a "small commit" here, but, unfortunately, we're
|
||||
// leaking the _entire_ history service :-(. So just do a "large"
|
||||
// commit for now.
|
||||
mdb_err err;
|
||||
err = mStore->SmallCommit(mEnv);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
|
@ -459,6 +350,209 @@ nsGlobalHistory::AddPage(const char *aURL, const char *aReferrerURL, PRInt64 aDa
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::AddPageToDatabase(const char *aURL,
|
||||
const char *aReferrerURL,
|
||||
PRInt64 aDate)
|
||||
{
|
||||
mdb_err err;
|
||||
nsresult rv;
|
||||
|
||||
// Sanity check the URL
|
||||
PRInt32 len = PL_strlen(aURL);
|
||||
NS_ASSERTION(len != 0, "no URL");
|
||||
if (! len)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
// For notifying observers, later...
|
||||
nsCOMPtr<nsIRDFResource> url;
|
||||
rv = gRDFService->GetResource(aURL, getter_AddRefs(url));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFDate> date;
|
||||
rv = gRDFService->GetDateLiteral(aDate, getter_AddRefs(date));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mdbYarn yarn = { (void*) aURL, len, len, 0, 0, nsnull };
|
||||
mdbOid rowId;
|
||||
nsMdbPtr<nsIMdbRow> row(mEnv);
|
||||
err = mStore->FindRow(mEnv, kToken_HistoryRowScope, kToken_URLColumn,
|
||||
&yarn, &rowId, getter_Acquires(row));
|
||||
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
if (row) {
|
||||
|
||||
// update the database, and get the old info back
|
||||
PRInt64 oldDate;
|
||||
PRInt32 oldCount;
|
||||
AddExistingPageToDatabase(row, aDate, &oldDate, &oldCount);
|
||||
|
||||
// Notify observers
|
||||
|
||||
// visit date
|
||||
nsCOMPtr<nsIRDFDate> oldDateLiteral;
|
||||
rv = gRDFService->GetDateLiteral(oldDate, getter_AddRefs(oldDateLiteral));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NotifyChange(url, kNC_Date, oldDateLiteral, date);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// visit count
|
||||
nsCOMPtr<nsIRDFInt> oldCountLiteral;
|
||||
rv = gRDFService->GetIntLiteral(oldCount, getter_AddRefs(oldCountLiteral));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFInt> newCountLiteral;
|
||||
rv = gRDFService->GetIntLiteral(oldCount+1,
|
||||
getter_AddRefs(newCountLiteral));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NotifyChange(url, kNC_VisitCount, oldCountLiteral, newCountLiteral);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
}
|
||||
else {
|
||||
AddNewPageToDatabase(aURL, aReferrerURL, aDate);
|
||||
|
||||
// Notify observers
|
||||
rv = NotifyAssert(url, kNC_Date, date);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NotifyAssert(kNC_HistoryRoot, kNC_child, url);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::AddExistingPageToDatabase(nsIMdbRow *row,
|
||||
PRInt64 aDate,
|
||||
PRInt64 *aOldDate,
|
||||
PRInt32 *aOldCount)
|
||||
{
|
||||
|
||||
mdb_err err;
|
||||
nsresult rv;
|
||||
// Update last visit date.
|
||||
// First get the old date so we can update observers...
|
||||
mdbYarn yarn;
|
||||
err = row->AliasCellYarn(mEnv, kToken_LastVisitDateColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
rv = CharsToPRInt64((const char*) yarn.mYarn_Buf, yarn.mYarn_Fill, aOldDate);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get the old count, so we can update it
|
||||
err = row->AliasCellYarn(mEnv, kToken_VisitCountColumn, &yarn);
|
||||
if (err == 0 && yarn.mYarn_Buf)
|
||||
*aOldCount = atoi((char *)yarn.mYarn_Buf);
|
||||
else
|
||||
*aOldCount = 1; // assume we've visited at least once
|
||||
|
||||
// ...now set the new date.
|
||||
SetRowValue(row, kToken_LastVisitDateColumn, aDate);
|
||||
SetRowValue(row, kToken_VisitCountColumn, (*aOldCount) + 1);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::AddNewPageToDatabase(const char *aURL,
|
||||
const char *aReferrerURL,
|
||||
PRInt64 aDate)
|
||||
{
|
||||
mdb_err err;
|
||||
|
||||
// Create a new row
|
||||
mdbOid rowId;
|
||||
rowId.mOid_Scope = kToken_HistoryRowScope;
|
||||
rowId.mOid_Id = mdb_id(-1);
|
||||
|
||||
NS_PRECONDITION(mTable != nsnull, "not initialized");
|
||||
if (! mTable)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
nsMdbPtr<nsIMdbRow> row(mEnv);
|
||||
err = mTable->NewRow(mEnv, &rowId, getter_Acquires(row));
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Set the URL
|
||||
SetRowValue(row, kToken_URLColumn, aURL);
|
||||
|
||||
// Set the referrer, if one is provided
|
||||
if (aReferrerURL)
|
||||
SetRowValue(row, kToken_ReferrerColumn, aReferrerURL);
|
||||
|
||||
// Set the date.
|
||||
SetRowValue(row, kToken_LastVisitDateColumn, aDate);
|
||||
SetRowValue(row, kToken_FirstVisitDateColumn, aDate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::SetRowValue(nsIMdbRow *aRow, mdb_column aCol, PRInt64 aValue)
|
||||
{
|
||||
mdb_err err;
|
||||
char buf[64];
|
||||
PRInt64ToChars(aValue, buf, sizeof(buf));
|
||||
|
||||
mdbYarn yarn;
|
||||
yarn.mYarn_Buf = (void*) buf;
|
||||
yarn.mYarn_Fill = yarn.mYarn_Size = PL_strlen(buf);
|
||||
err = aRow->AddColumn(mEnv, aCol, &yarn);
|
||||
|
||||
if ( err != 0 ) return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::SetRowValue(nsIMdbRow *aRow, mdb_column aCol,
|
||||
const PRUnichar* aValue)
|
||||
{
|
||||
mdb_err err;
|
||||
|
||||
mdbYarn yarn;
|
||||
yarn.mYarn_Buf = (void*) aValue;
|
||||
yarn.mYarn_Fill = yarn.mYarn_Size = (nsCRT::strlen(aValue) * sizeof(PRUnichar));
|
||||
|
||||
err = aRow->AddColumn(mEnv, aCol, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::SetRowValue(nsIMdbRow *aRow, mdb_column aCol,
|
||||
const char* aValue)
|
||||
{
|
||||
mdb_err err;
|
||||
PRInt32 len = PL_strlen(aValue);
|
||||
mdbYarn yarn = { (void*) aValue, len, len, 0, 0, nsnull };
|
||||
err = aRow->AddColumn(mEnv, aCol, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::SetRowValue(nsIMdbRow *aRow, mdb_column aCol, PRInt32 aValue)
|
||||
{
|
||||
mdb_err err;
|
||||
|
||||
nsCAutoString buf; buf.AppendInt(aValue);
|
||||
mdbYarn yarn = { (void *)buf.GetBuffer(), buf.Length(), buf.Length(), 0, 0, nsnull };
|
||||
|
||||
err = aRow->AddColumn(mEnv, aCol, &yarn);
|
||||
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGlobalHistory::SetPageTitle(const char *aURL, const PRUnichar *aTitle)
|
||||
|
@ -501,12 +595,7 @@ nsGlobalHistory::SetPageTitle(const char *aURL, const PRUnichar *aTitle)
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// Now poke in the new title
|
||||
yarn.mYarn_Buf = (void*) aTitle;
|
||||
yarn.mYarn_Fill = yarn.mYarn_Size = (nsCRT::strlen(aTitle) * sizeof(PRUnichar));
|
||||
|
||||
err = row->AddColumn(mEnv, kToken_NameColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
SetRowValue(row, kToken_NameColumn, aTitle);
|
||||
|
||||
// ...and update observers
|
||||
nsCOMPtr<nsIRDFResource> url;
|
||||
|
@ -780,6 +869,7 @@ nsGlobalHistory::GetSource(nsIRDFResource* aProperty,
|
|||
}
|
||||
}
|
||||
else if ((aProperty == kNC_Date) ||
|
||||
(aProperty == kNC_FirstVisitDate) ||
|
||||
(aProperty == kNC_VisitCount) ||
|
||||
(aProperty == kNC_Name) ||
|
||||
(aProperty == kNC_Referrer)) {
|
||||
|
@ -838,7 +928,8 @@ nsGlobalHistory::GetSources(nsIRDFResource* aProperty,
|
|||
void* value = nsnull;
|
||||
PRInt32 len = 0;
|
||||
|
||||
if (aProperty == kNC_Date) {
|
||||
if (aProperty == kNC_Date ||
|
||||
aProperty == kNC_FirstVisitDate) {
|
||||
nsCOMPtr<nsIRDFDate> date = do_QueryInterface(aTarget);
|
||||
if (date) {
|
||||
PRInt64 n;
|
||||
|
@ -856,11 +947,25 @@ nsGlobalHistory::GetSources(nsIRDFResource* aProperty,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PL_strcpy(buf, NS_STATIC_CAST(char*, value));
|
||||
col = kToken_LastVisitDateColumn;
|
||||
if (aProperty == kNC_Date)
|
||||
col = kToken_LastVisitDateColumn;
|
||||
else
|
||||
col = kToken_FirstVisitDateColumn;
|
||||
}
|
||||
}
|
||||
else if (aProperty == kNC_VisitCount) {
|
||||
NS_NOTYETIMPLEMENTED("sorry");
|
||||
nsCOMPtr<nsIRDFInt> countLiteral = do_QueryInterface(aTarget);
|
||||
if (countLiteral) {
|
||||
PRInt32 intValue;
|
||||
rv = countLiteral->GetValue(&intValue);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoString valueStr; valueStr.AppendInt(intValue);
|
||||
value = valueStr.ToNewUnicode();
|
||||
len = nsCRT::strlen((PRUnichar*)value);
|
||||
col = kToken_VisitCountColumn;
|
||||
}
|
||||
|
||||
}
|
||||
else if (aProperty == kNC_Name) {
|
||||
nsCOMPtr<nsIRDFLiteral> name = do_QueryInterface(aTarget);
|
||||
|
@ -951,6 +1056,7 @@ nsGlobalHistory::GetTarget(nsIRDFResource* aSource,
|
|||
return CallQueryInterface(isupports, aTarget);
|
||||
}
|
||||
else if ((aProperty == kNC_Date) ||
|
||||
(aProperty == kNC_FirstVisitDate) ||
|
||||
(aProperty == kNC_VisitCount) ||
|
||||
(aProperty == kNC_Name) ||
|
||||
(aProperty == kNC_Referrer) ||
|
||||
|
@ -974,9 +1080,14 @@ nsGlobalHistory::GetTarget(nsIRDFResource* aSource,
|
|||
|
||||
// ...and then depending on the property they want, we'll pull the
|
||||
// cell they want out of it.
|
||||
if (aProperty == kNC_Date) {
|
||||
if (aProperty == kNC_Date ||
|
||||
aProperty == kNC_FirstVisitDate) {
|
||||
// Last visit date
|
||||
err = row->AliasCellYarn(mEnv, kToken_LastVisitDateColumn, &yarn);
|
||||
|
||||
if (aProperty == kNC_Date)
|
||||
err = row->AliasCellYarn(mEnv, kToken_LastVisitDateColumn, &yarn);
|
||||
else
|
||||
err = row->AliasCellYarn(mEnv, kToken_FirstVisitDateColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
PRInt64 i;
|
||||
|
@ -990,9 +1101,21 @@ nsGlobalHistory::GetTarget(nsIRDFResource* aSource,
|
|||
return CallQueryInterface(date, aTarget);
|
||||
}
|
||||
else if (aProperty == kNC_VisitCount) {
|
||||
// Visit count
|
||||
NS_NOTYETIMPLEMENTED("sorry");
|
||||
rv = NS_ERROR_NOT_IMPLEMENTED;
|
||||
err = row->AliasCellYarn(mEnv, kToken_VisitCountColumn, &yarn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
PRInt32 visitCount;
|
||||
if (yarn.mYarn_Buf)
|
||||
visitCount = atoi((char *)yarn.mYarn_Buf);
|
||||
else
|
||||
visitCount = 1; // assume we've visited at least once
|
||||
|
||||
nsCOMPtr<nsIRDFInt> visitCountLiteral;
|
||||
rv = gRDFService->GetIntLiteral(visitCount,
|
||||
getter_AddRefs(visitCountLiteral));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return CallQueryInterface(visitCountLiteral, aTarget);
|
||||
}
|
||||
else if (aProperty == kNC_Name) {
|
||||
// Site name (i.e., page title)
|
||||
|
@ -1053,7 +1176,8 @@ nsGlobalHistory::GetTargets(nsIRDFResource* aSource,
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aTruthValue) {
|
||||
if ((aSource == kNC_HistoryRoot) && (aProperty == kNC_child) && (aTruthValue)) {
|
||||
if ((aSource == kNC_HistoryRoot) &&
|
||||
(aProperty == kNC_child) && (aTruthValue)) {
|
||||
URLEnumerator* result = new URLEnumerator(kToken_URLColumn);
|
||||
if (! result)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -1067,6 +1191,7 @@ nsGlobalHistory::GetTargets(nsIRDFResource* aSource,
|
|||
return NS_OK;
|
||||
}
|
||||
else if ((aProperty == kNC_Date) ||
|
||||
(aProperty == kNC_FirstVisitDate) ||
|
||||
(aProperty == kNC_VisitCount) ||
|
||||
(aProperty == kNC_Name) ||
|
||||
(aProperty == kNC_Referrer)) {
|
||||
|
@ -1240,6 +1365,7 @@ nsGlobalHistory::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, PRBool
|
|||
// If the URL is in the history, then it'll have all the
|
||||
// appropriate attributes.
|
||||
*result = (aArc == kNC_Date ||
|
||||
aArc == kNC_FirstVisitDate ||
|
||||
aArc == kNC_VisitCount ||
|
||||
aArc == kNC_Name ||
|
||||
aArc == kNC_Referrer);
|
||||
|
@ -1290,6 +1416,7 @@ nsGlobalHistory::ArcLabelsOut(nsIRDFResource* aSource,
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
array->AppendElement(kNC_Date);
|
||||
array->AppendElement(kNC_FirstVisitDate);
|
||||
array->AppendElement(kNC_VisitCount);
|
||||
array->AppendElement(kNC_Name);
|
||||
array->AppendElement(kNC_Referrer);
|
||||
|
@ -1427,6 +1554,8 @@ nsGlobalHistory::Init()
|
|||
|
||||
gRDFService->GetResource(NC_NAMESPACE_URI "Page", &kNC_Page);
|
||||
gRDFService->GetResource(NC_NAMESPACE_URI "Date", &kNC_Date);
|
||||
gRDFService->GetResource(NC_NAMESPACE_URI "FirstVisitDate",
|
||||
&kNC_FirstVisitDate);
|
||||
gRDFService->GetResource(NC_NAMESPACE_URI "VisitCount", &kNC_VisitCount);
|
||||
gRDFService->GetResource(NC_NAMESPACE_URI "Name", &kNC_Name);
|
||||
gRDFService->GetResource(NC_NAMESPACE_URI "Referrer", &kNC_Referrer);
|
||||
|
@ -1439,11 +1568,10 @@ nsGlobalHistory::Init()
|
|||
|
||||
// register this as a named data source with the RDF service
|
||||
rv = gRDFService->RegisterDataSource(this, PR_FALSE);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "somebody already created & registered the history data source");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = OpenDB();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1456,7 +1584,7 @@ nsGlobalHistory::OpenDB()
|
|||
|
||||
nsCOMPtr <nsIFile> historyFile;
|
||||
rv = NS_GetSpecialDirectory(NS_APP_HISTORY_50_FILE, getter_AddRefs(historyFile));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
static NS_DEFINE_CID(kMorkCID, NS_MORK_CID);
|
||||
nsCOMPtr<nsIMdbFactoryFactory> factoryfactory;
|
||||
|
@ -1464,15 +1592,14 @@ nsGlobalHistory::OpenDB()
|
|||
nsnull,
|
||||
NS_GET_IID(nsIMdbFactoryFactory),
|
||||
getter_AddRefs(factoryfactory));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Leaving XPCOM, entering MDB. They may look like XPCOM interfaces,
|
||||
// but they're not. The 'factory' is an interface; however, it isn't
|
||||
// reference counted. So no, this isn't a leak.
|
||||
nsIMdbFactory* factory;
|
||||
rv = factoryfactory->GetMdbFactory(&factory);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create mork factory factory");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mdb_err err;
|
||||
|
||||
|
@ -1480,106 +1607,128 @@ nsGlobalHistory::OpenDB()
|
|||
NS_ASSERTION((err == 0), "unable to create mdb env");
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
nsIMdbHeap* dbHeap = 0;
|
||||
mdb_bool dbFrozen = mdbBool_kFalse; // not readonly, we want modifiable
|
||||
PRBool exists;
|
||||
|
||||
nsXPIDLCString filePath;
|
||||
rv = historyFile->GetPath(getter_Copies(filePath));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
rv = OpenExistingFile(factory, filePath);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
||||
// we couldn't open the file, so it's either corrupt or doesn't exist.
|
||||
// attempt to delete the file, but ignore the error
|
||||
historyFile->Delete(PR_FALSE);
|
||||
|
||||
rv = historyFile->Exists(&exists);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = OpenNewFile(factory, filePath);
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
mdb_bool canopen = 0;
|
||||
mdbYarn outfmt = { nsnull, 0, 0, 0, 0, nsnull };
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsMdbPtr<nsIMdbFile> oldFile(mEnv); // ensures file is released
|
||||
err = factory->OpenOldFile(mEnv, dbHeap, filePath,
|
||||
dbFrozen, getter_Acquires(oldFile));
|
||||
nsresult
|
||||
nsGlobalHistory::OpenExistingFile(nsIMdbFactory *factory, const char *filePath)
|
||||
{
|
||||
|
||||
if ((err != 0) || !oldFile) return NS_ERROR_FAILURE;
|
||||
mdb_err err;
|
||||
nsresult rv;
|
||||
mdb_bool canopen = 0;
|
||||
mdbYarn outfmt = { nsnull, 0, 0, 0, 0, nsnull };
|
||||
|
||||
err = factory->CanOpenFilePort(mEnv, oldFile, // the file to investigate
|
||||
&canopen, &outfmt);
|
||||
nsIMdbHeap* dbHeap = 0;
|
||||
mdb_bool dbFrozen = mdbBool_kFalse; // not readonly, we want modifiable
|
||||
nsMdbPtr<nsIMdbFile> oldFile(mEnv); // ensures file is released
|
||||
err = factory->OpenOldFile(mEnv, dbHeap, filePath,
|
||||
dbFrozen, getter_Acquires(oldFile));
|
||||
|
||||
// XXX possible that format out of date, in which case we should
|
||||
// just re-write the file.
|
||||
if ((err != 0) || !canopen) return NS_ERROR_FAILURE;
|
||||
NS_ENSURE_TRUE((err == 0) && oldFile, NS_ERROR_FAILURE);
|
||||
|
||||
nsIMdbThumb* thumb = nsnull;
|
||||
mdbOpenPolicy policy = { { 0, 0 }, 0, 0 };
|
||||
err = factory->CanOpenFilePort(mEnv, oldFile, // the file to investigate
|
||||
&canopen, &outfmt);
|
||||
|
||||
err = factory->OpenFileStore(mEnv, dbHeap, oldFile, &policy, &thumb);
|
||||
if ((err != 0) || !thumb) return NS_ERROR_FAILURE;
|
||||
// XXX possible that format out of date, in which case we should
|
||||
// just re-write the file.
|
||||
NS_ENSURE_TRUE((err == 0) && canopen, NS_ERROR_FAILURE);
|
||||
|
||||
mdb_count total;
|
||||
mdb_count current;
|
||||
mdb_bool done;
|
||||
mdb_bool broken;
|
||||
nsIMdbThumb* thumb = nsnull;
|
||||
mdbOpenPolicy policy = { { 0, 0 }, 0, 0 };
|
||||
|
||||
do {
|
||||
err = thumb->DoMore(mEnv, &total, ¤t, &done, &broken);
|
||||
} while ((err == 0) && !broken && !done);
|
||||
err = factory->OpenFileStore(mEnv, dbHeap, oldFile, &policy, &thumb);
|
||||
|
||||
if ((err == 0) && done) {
|
||||
err = factory->ThumbToOpenStore(mEnv, thumb, &mStore);
|
||||
}
|
||||
NS_ENSURE_TRUE((err == 0) && thumb, NS_ERROR_FAILURE);
|
||||
|
||||
thumb->CutStrongRef(mEnv);
|
||||
thumb = nsnull;
|
||||
mdb_count total;
|
||||
mdb_count current;
|
||||
mdb_bool done;
|
||||
mdb_bool broken;
|
||||
|
||||
if ((err != 0) || !done) return NS_ERROR_FAILURE;
|
||||
do {
|
||||
err = thumb->DoMore(mEnv, &total, ¤t, &done, &broken);
|
||||
} while ((err == 0) && !broken && !done);
|
||||
|
||||
rv = CreateTokens();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mdbOid oid = { kToken_HistoryRowScope, 1 };
|
||||
err = mStore->GetTable(mEnv, &oid, &mTable);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
if ((err == 0) && done) {
|
||||
err = factory->ThumbToOpenStore(mEnv, thumb, &mStore);
|
||||
}
|
||||
else {
|
||||
|
||||
nsMdbPtr<nsIMdbFile> newFile(mEnv); // ensures file is released
|
||||
err = factory->CreateNewFile(mEnv, dbHeap, filePath,
|
||||
getter_Acquires(newFile));
|
||||
thumb->CutStrongRef(mEnv);
|
||||
thumb = nsnull;
|
||||
|
||||
if ((err != 0) || !newFile) return NS_ERROR_FAILURE;
|
||||
NS_ENSURE_TRUE((err == 0) && done, NS_ERROR_FAILURE);
|
||||
|
||||
mdbOpenPolicy policy = { { 0, 0 }, 0, 0 };
|
||||
err = factory->CreateNewFileStore(mEnv, dbHeap, newFile, &policy, &mStore);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
rv = CreateTokens();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = CreateTokens();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Create the one and only table in the history db
|
||||
err = mStore->NewTable(mEnv, kToken_HistoryRowScope, kToken_HistoryKind, PR_TRUE, nsnull, &mTable);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Force a commit now to get it written out.
|
||||
nsMdbPtr<nsIMdbThumb> thumb(mEnv);
|
||||
err = mStore->LargeCommit(mEnv, getter_Acquires(thumb));
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
mdb_count total;
|
||||
mdb_count current;
|
||||
mdb_bool done;
|
||||
mdb_bool broken;
|
||||
|
||||
do {
|
||||
err = thumb->DoMore(mEnv, &total, ¤t, &done, &broken);
|
||||
} while ((err == 0) && !broken && !done);
|
||||
|
||||
if ((err != 0) || !done) return NS_ERROR_FAILURE;
|
||||
|
||||
|
||||
}
|
||||
mdbOid oid = { kToken_HistoryRowScope, 1 };
|
||||
err = mStore->GetTable(mEnv, &oid, &mTable);
|
||||
NS_ENSURE_TRUE(err == 0, NS_ERROR_FAILURE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::OpenNewFile(nsIMdbFactory *factory, const char *filePath)
|
||||
{
|
||||
nsresult rv;
|
||||
mdb_err err;
|
||||
|
||||
nsIMdbHeap* dbHeap = 0;
|
||||
nsMdbPtr<nsIMdbFile> newFile(mEnv); // ensures file is released
|
||||
err = factory->CreateNewFile(mEnv, dbHeap, filePath,
|
||||
getter_Acquires(newFile));
|
||||
|
||||
if ((err != 0) || !newFile) return NS_ERROR_FAILURE;
|
||||
|
||||
mdbOpenPolicy policy = { { 0, 0 }, 0, 0 };
|
||||
err = factory->CreateNewFileStore(mEnv, dbHeap, newFile, &policy, &mStore);
|
||||
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
rv = CreateTokens();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create the one and only table in the history db
|
||||
err = mStore->NewTable(mEnv, kToken_HistoryRowScope, kToken_HistoryKind, PR_TRUE, nsnull, &mTable);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
// Force a commit now to get it written out.
|
||||
nsMdbPtr<nsIMdbThumb> thumb(mEnv);
|
||||
err = mStore->LargeCommit(mEnv, getter_Acquires(thumb));
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
mdb_count total;
|
||||
mdb_count current;
|
||||
mdb_bool done;
|
||||
mdb_bool broken;
|
||||
|
||||
do {
|
||||
err = thumb->DoMore(mEnv, &total, ¤t, &done, &broken);
|
||||
} while ((err == 0) && !broken && !done);
|
||||
|
||||
if ((err != 0) || !done) return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGlobalHistory::CreateTokens()
|
||||
|
@ -1605,6 +1754,12 @@ nsGlobalHistory::CreateTokens()
|
|||
err = mStore->StringToToken(mEnv, "LastVisitDate", &kToken_LastVisitDateColumn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
err = mStore->StringToToken(mEnv, "FirstVisitDate", &kToken_FirstVisitDateColumn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
err = mStore->StringToToken(mEnv, "VisitCount", &kToken_VisitCountColumn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
err = mStore->StringToToken(mEnv, "Name", &kToken_NameColumn);
|
||||
if (err != 0) return NS_ERROR_FAILURE;
|
||||
|
||||
|
|
|
@ -105,6 +105,8 @@ protected:
|
|||
|
||||
// Implementation Methods
|
||||
nsresult OpenDB();
|
||||
nsresult OpenExistingFile(nsIMdbFactory *factory, const char *filePath);
|
||||
nsresult OpenNewFile(nsIMdbFactory *factory, const char *filePath);
|
||||
nsresult CreateTokens();
|
||||
nsresult CloseDB();
|
||||
|
||||
|
@ -121,13 +123,33 @@ protected:
|
|||
nsresult NotifyUnassert(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode* aValue);
|
||||
nsresult NotifyChange(nsIRDFResource* aSource, nsIRDFResource* aProperty, nsIRDFNode* aOldValue, nsIRDFNode* aNewValue);
|
||||
|
||||
nsresult AddPageToDatabase(const char *aURL,
|
||||
const char *aReferrerURL,
|
||||
PRInt64 aDate);
|
||||
nsresult AddExistingPageToDatabase(nsIMdbRow *row,
|
||||
PRInt64 aDate,
|
||||
PRInt64 *aOldDate,
|
||||
PRInt32 *aOldCount);
|
||||
|
||||
nsresult AddNewPageToDatabase(const char *aURL,
|
||||
const char *aReferrerURL,
|
||||
PRInt64 aDate);
|
||||
|
||||
nsresult SetRowValue(nsIMdbRow *aRow, mdb_column aCol, PRInt64 aValue);
|
||||
nsresult SetRowValue(nsIMdbRow *aRow, mdb_column aCol, PRInt32 aValue);
|
||||
nsresult SetRowValue(nsIMdbRow *aRow, mdb_column aCol, const char *aValue);
|
||||
nsresult SetRowValue(nsIMdbRow *aRow, mdb_column aCol, const PRUnichar *aValue);
|
||||
|
||||
nsCOMPtr<nsISupportsArray> mObservers;
|
||||
|
||||
mdb_scope kToken_HistoryRowScope;
|
||||
mdb_kind kToken_HistoryKind;
|
||||
|
||||
mdb_column kToken_URLColumn;
|
||||
mdb_column kToken_ReferrerColumn;
|
||||
mdb_column kToken_LastVisitDateColumn;
|
||||
mdb_column kToken_FirstVisitDateColumn;
|
||||
mdb_column kToken_VisitCountColumn;
|
||||
mdb_column kToken_NameColumn;
|
||||
|
||||
// pseudo-constants. although the global history really is a
|
||||
|
@ -136,6 +158,7 @@ protected:
|
|||
static nsIRDFService* gRDFService;
|
||||
static nsIRDFResource* kNC_Page; // XXX do we need?
|
||||
static nsIRDFResource* kNC_Date;
|
||||
static nsIRDFResource* kNC_FirstVisitDate;
|
||||
static nsIRDFResource* kNC_VisitCount;
|
||||
static nsIRDFResource* kNC_Name;
|
||||
static nsIRDFResource* kNC_Referrer;
|
||||
|
|
Загрузка…
Ссылка в новой задаче