browserutilities/recenturlstore/RecentUrlSrc/RecentUrlStore.cpp
author Kiiskinen Klaus (Nokia-D-MSW/Tampere) <klaus.kiiskinen@nokia.com>
Mon, 30 Mar 2009 12:54:55 +0300
changeset 0 dd21522fd290
child 16 a359256acfc6
permissions -rw-r--r--
Revision: 200911 Kit: 200912

/*
* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*      Implementation of RecentUrlStore
*
*
*/



// INCLUDE FILES
#include "RecentUrlStore.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES

// CONSTANTS

// MACROS

// LOCAL CONSTANTS AND MACROS
_LIT(KRecentUrlDBFile, "c:\\private\\%08x\\RecentUrlStore.db");

_LIT(KSQLInsertVersion, "INSERT INTO dbversion (dbver) VALUES ('1.0')");

/*
*    Database columns:
*       History - counter used to order the urls latest first
*       Url - url of visited page
*/
_LIT(KVersionTableSQL, "CREATE TABLE dbversion(dbver CHAR(10))");
_LIT(KRecentUrlTableSQL, "CREATE TABLE recenturl(history COUNTER, domain VARCHAR(50), url VARCHAR(250), title VARCHAR(250))");
const TUint KDomainSize = 50;
const TUint KUrlSize = 250;
const TUint KTitleSize = 250;

_LIT(KIndex1SQL, "CREATE INDEX updateidx ON recenturl (history)");

_LIT(KSQLInsert, "INSERT INTO recenturl (domain,url,title) VALUES ('%S','%S', '%S')");
_LIT(KSQLDelete, "DELETE FROM recenturl WHERE url = '%S'");
_LIT(KSQLSelect, "SELECT url,title FROM recenturl WHERE domain LIKE '%S*' OR url LIKE '*://%S*' ORDER BY history desc");
_LIT(KSQLSelectAll, "SELECT url,title FROM recenturl ORDER BY history desc");
const TUint KUrlCol = 1;
const TUint KTitleCol = 2;

const TUint KMaxRows = 100;

_LIT(KDomainDelim, "."); // domain starts after first '.' and ends after second '.'

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

// ============================= FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CRecentUrlStore::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
EXPORT_C CRecentUrlStore * CRecentUrlStore::NewL ()
    {
    CRecentUrlStore* self = new (ELeave) CRecentUrlStore();
    self->ConstructL();
    return self;

    }

// -----------------------------------------------------------------------------
// CRecentUrlStore::CRecentUrlStore
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
CRecentUrlStore::CRecentUrlStore():
	iFirstTimeOpened(ETrue)
	{

	}

// -----------------------------------------------------------------------------
// CRecentUrlStore::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
void CRecentUrlStore::ConstructL()
    {
    
    // Create the file name from UID
	RProcess myProcess;	
	TBuf <256>buf;    
    buf.Format(KRecentUrlDBFile, myProcess.Identity());
	iRecentUrlDBFile = buf.AllocL();

	User::LeaveIfError(iDbSession.Connect());
	
    }
    
//-----------------------------------------------------------------------------
// CRecentUrlStore Destructor
//-----------------------------------------------------------------------------
CRecentUrlStore::~CRecentUrlStore()
    {
	iDbSession.Close();
	delete iRecentUrlDBFile;
    }

    
//-----------------------------------------------------------------------------
// CRecentUrlStore::GetData
// params aUrl - Url filter
// Returns matching urls.
//-----------------------------------------------------------------------------
EXPORT_C TInt CRecentUrlStore::GetData (CDesCArray& aUrls, CDesCArray& aTitles, const TDesC& aUrl)
    {
    RDbNamedDatabase dataBase;
    TInt err = OpenDatabase(dataBase);
    if (err == KErrNone)
    	{
    	TRAP(err, GetDataL(dataBase, aUrls, aTitles, aUrl));
    	dataBase.Close();
    	}
    return err;
    }
//-----------------------------------------------------------------------------
// CRecentUrlStore::GetData
// params aUrl - Url filter
// Returns matching urls.
//-----------------------------------------------------------------------------
void CRecentUrlStore::GetDataL (RDbNamedDatabase& aDataBase, 
			CDesCArray& aUrls, CDesCArray& aTitles, const TDesC& aUrl)
    {
	
    TInt rowCount(0);

	// select values from the database filtered by url
	if (aUrl.Length())
		{
		HBufC* domain = aUrl.AllocLC();
		domain->Des().LowerCase();
		iSQLStatement.Format(KSQLSelect, domain, domain);
		CleanupStack::PopAndDestroy();
		}
	else
		{
		iSQLStatement.Format(KSQLSelectAll);
		}
	

    RDbView view;
    
    TInt err = view.Prepare(aDataBase, TDbQuery(iSQLStatement));
    if (err == KErrNone)
    	{
    	err = view.EvaluateAll();
    	if (err == KErrNone)
    		{
    		view.FirstL();
    		// loop through rows and build the list
    		while (view.AtRow() && rowCount++ < KMaxRows)
    			{
    			view.GetL();
				aUrls.AppendL(view.ColDes(KUrlCol));
				aTitles.AppendL(view.ColDes(KTitleCol));
    			view.NextL();
    			}
    		/*
    		* This loop will keep the number of rows in the database at a reasonable size by
    		* deleting old rows (deletes rows beyond KMaxRows).  Should be at most 1 row deleted.
    		* Its more efficiant to delete it here than in the SaveData because in this function
    		* we already have the list and know its size
    		*/
    		while (view.AtRow())
    			{
    			view.GetL();
    			iSQLStatement.Format(KSQLDelete, &aUrl);
				aDataBase.Execute(iSQLStatement);
    			view.NextL();
    			}
       		}
    	}
    view.Close();
    }

//-----------------------------------------------------------------------------
// CRecentUrlStore::DeleteData
// Deletes a single row from the database.
//-----------------------------------------------------------------------------
EXPORT_C void CRecentUrlStore::DeleteData (const TDesC& aUrl)
    {
    RDbNamedDatabase dataBase;
    if (OpenDatabase(dataBase) == KErrNone)
    	{
		iSQLStatement.Format(KSQLDelete, &aUrl);
		dataBase.Execute(iSQLStatement);
    	dataBase.Close();
    	}
    }

//-----------------------------------------------------------------------------
// CRecentUrlStore::SaveDataL
// Save the url in store.
//-----------------------------------------------------------------------------
EXPORT_C void CRecentUrlStore::SaveData (const TDesC& aUrl, const TDesC& aTitle)
	{
	RDbNamedDatabase dataBase;
	TInt urlLength (aUrl.Length());
	
	// shouldn't happen but if it's too long for the data store just skip it!
	if (urlLength > KUrlSize)
		{
		return;
		}
	
	if (OpenDatabase(dataBase) == KErrNone)
		{
		// find the point where the domain starts and ends
		TInt domainLength(urlLength);
		TInt domainStart(0);
		
		TInt startPos = aUrl.Find(KDomainDelim);
		if (startPos != KErrNotFound)
			{
			domainStart = startPos + (KDomainDelim().Length()); // first char after delim
			TInt len = aUrl.Right(urlLength - domainStart).Find(KDomainDelim);
			if (len > 0) // ignore delim following delim.  we don't want an empty string
				{
				domainLength = len;
				}
			else
				{
				domainLength -= domainStart;
				}
			}
			
		// make sure it's not too big for the data store
		domainLength = (domainLength > KDomainSize) ? KDomainSize : domainLength;
		TInt titleLength = (aTitle.Length() > KTitleSize) ? KTitleSize : aTitle.Length();
			
		HBufC* domain = aUrl.Mid(domainStart,domainLength).AllocLC();
		domain->Des().LowerCase();
		HBufC* title = aTitle.Left(titleLength).AllocLC();

		// delete and re-insert
		iSQLStatement.Format(KSQLDelete, &aUrl);
		dataBase.Execute(iSQLStatement);
		iSQLStatement.Format(KSQLInsert, domain, &aUrl, title);
		CleanupStack::PopAndDestroy(2); // domain, title
		
		dataBase.Execute(iSQLStatement);
		dataBase.Close();
		}
	}
	
//-----------------------------------------------------------------------------
// CRecentUrlStore::ClearData
// Clear the store.
//-----------------------------------------------------------------------------
EXPORT_C void CRecentUrlStore::ClearData ()
	{
	// the quickest way to clear the data is to re-create it
	TRAP_IGNORE(CreateDatabaseL());
	}


// private
//-----------------------------------------------------------------------------
// CRecentUrlStore::DeleteOldRowsL
//-----------------------------------------------------------------------------
void CRecentUrlStore::DeleteOldRowsL (RDbNamedDatabase& aDataBase)
    {
	
    TInt rowCount(0);

	iSQLStatement.Format(KSQLSelectAll);
	
    RDbView view;
    
    TInt err = view.Prepare(aDataBase, TDbQuery(iSQLStatement));
    if (err == KErrNone)
    	{
    	err = view.EvaluateAll();
    	if (err == KErrNone)
    		{
    		view.FirstL();
    		// loop through rows we want to keep
    		while (view.AtRow() && rowCount++ < KMaxRows)
    			{
    			view.NextL();
    			}
    		// delete the rows that are old
    		while (view.AtRow())
    			{
    			view.DeleteL();
    			view.NextL();
    			}
       		}
    	}
    view.Close();
    }

//-----------------------------------------------------------------------------
// CRecentUrlStore::OpenDatabase
// Open the data store.
//-----------------------------------------------------------------------------
TInt CRecentUrlStore::OpenDatabase(RDbNamedDatabase& aDataBase)
	{
	TInt error = KErrNone;
	// open the database - create if it doesn't exist
	error = aDataBase.Open(iDbSession, *iRecentUrlDBFile);
	// compact it once during our session
	if (error == KErrNone && iFirstTimeOpened)
		{
		TRAP_IGNORE(DeleteOldRowsL(aDataBase));
		aDataBase.Compact();
		iFirstTimeOpened = EFalse;
		}
		
	if (error != KErrNone)
		{
		TRAP(error,CreateDatabaseL());
		if (error == KErrNone)
			{
			error = aDataBase.Open(iDbSession, *iRecentUrlDBFile);
			}
		}
	return error;
	}

//-----------------------------------------------------------------------------
// CRecentUrlStore::CreateDatabaseL
// Create the data store.
//-----------------------------------------------------------------------------
void CRecentUrlStore::CreateDatabaseL()
	{
	RDbNamedDatabase dataBase;
	User::LeaveIfError(dataBase.Replace(iDbSession, *iRecentUrlDBFile));
	    	
	CleanupClosePushL(dataBase);
	User::LeaveIfError(dataBase.Execute(KVersionTableSQL));
	User::LeaveIfError(dataBase.Execute(KRecentUrlTableSQL));
	User::LeaveIfError(dataBase.Execute(KIndex1SQL));
	User::LeaveIfError(dataBase.Execute(KSQLInsertVersion));
	CleanupStack::PopAndDestroy();//dataBase	    
    
	}
	
//  End of File