/*
* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "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 CGlxtnVolumeDatabase
*
*/
/**
* @internal reviewed 31/07/2007 by Simon Brooks
*/
#include "glxtnvolumedatabase.h"
#include <glxtracer.h>
#include <glxpanic.h>
#include <s32file.h>
#include "glxtnfileinfo.h"
#include "mglxtnvolumedatabaseobserver.h"
#include <glxlog.h>
_LIT(KGlxCreateTableIds, "CREATE TABLE Ids (MediaId UNSIGNED INTEGER NOT NULL, ThumbId UNSIGNED INTEGER NOT NULL)");
_LIT(KGlxCreateTableItems, "CREATE TABLE Items (Uri VARCHAR NOT NULL, ThumbId UNSIGNED INTEGER NOT NULL, FileSize INTEGER, ModTime TIME)");
_LIT(KGlxCreateTableThumbnails, "CREATE TABLE Thumbnails (ThumbId UNSIGNED INTEGER NOT NULL, Width INTEGER NOT NULL, Height INTEGER NOT NULL, Format INTEGER NOT NULL, ImageData LONG VARBINARY NOT NULL)");
_LIT(KGlxCreateIndexIds, "CREATE UNIQUE INDEX IdIndex ON Ids (MediaId)");
_LIT(KGlxCreateIndexItems, "CREATE UNIQUE INDEX ItemIndex ON Items (ThumbId ASC)");
_LIT(KGlxCreateIndexThumbnails, "CREATE UNIQUE INDEX ThumbnailIndex ON Thumbnails (ThumbId, Width, Height)");
_LIT(KGlxCreateIndexThumbIds, "CREATE UNIQUE INDEX ThumbIdIndex ON Ids (ThumbId)");
_LIT(KGlxTableIds, "Ids");
_LIT(KGlxTableItems, "Items");
_LIT(KGlxTableThumbnails, "Thumbnails");
_LIT(KGlxIndexItems, "ItemIndex");
_LIT(KGlxIndexThumbIds, "ThumbIdIndex");
const TInt KGlxColIdMediaId = 1;
const TInt KGlxColIdThumbId = 2;
const TInt KGlxColItemUri = 1;
const TInt KGlxColItemId = 2;
const TInt KGlxColItemFileSize = 3;
const TInt KGlxColItemModTime = 4;
const TInt KGlxColThumbnailId = 1;
const TInt KGlxColThumbnailWidth = 2;
const TInt KGlxColThumbnailHeight = 3;
const TInt KGlxColThumbnailFormat = 4;
const TInt KGlxColThumbnailData = 5;
_LIT(KGlxQueryThumbIdFromIds, "SELECT * FROM Ids WHERE MediaId = ");
_LIT(KGlxQueryThumbIdFromItems, "SELECT * FROM Items WHERE Uri = ");
_LIT(KGlxQueryThumbnail, "SELECT * FROM Thumbnails WHERE ThumbId = %d AND Width = %d AND Height = %d");
_LIT(KGlxQueryAvailable, "SELECT ThumbId, Width, Height FROM Thumbnails WHERE ThumbId = %d AND Width = %d AND Height = %d");
_LIT(KGlxQueryItems, "SELECT * FROM Items WHERE ThumbId = %d");
_LIT(KGlxDeleteId, "DELETE FROM Ids WHERE MediaId = %d");
_LIT(KGlxDeleteThumbnails, "DELETE FROM Thumbnails WHERE ThumbId = %d");
_LIT(KGlxDeleteItem, "DELETE FROM Items WHERE ThumbId = %d");
const TInt KGlxTIntMaxDigits = 11;
const TUint KGlxFirstThumbnailId = 1;
// -----------------------------------------------------------------------------
// NewL
// -----------------------------------------------------------------------------
//
CGlxtnVolumeDatabase* CGlxtnVolumeDatabase::NewLC(
MGlxtnVolumeDatabaseObserver& aObserver, RFs& aFs, const TDesC& aPath)
{
TRACER("CGlxtnVolumeDatabase* CGlxtnVolumeDatabase::NewLC( MGlxtnVolumeDatabaseObserver& aObserver, RFs& aFs, const TDesC& aPath)");
CGlxtnVolumeDatabase* self =
new (ELeave) CGlxtnVolumeDatabase(aObserver, aFs);
CleanupStack::PushL(self);
self->ConstructL(aPath);
return self;
}
// -----------------------------------------------------------------------------
// Constructor
// -----------------------------------------------------------------------------
//
CGlxtnVolumeDatabase::CGlxtnVolumeDatabase(
MGlxtnVolumeDatabaseObserver& aObserver,
RFs& aFs)
: CActive(EPriorityStandard),
iObserver(aObserver), iFs(aFs), iState(EStateIdle)
{
TRACER("CGlxtnVolumeDatabase::CGlxtnVolumeDatabase( MGlxtnVolumeDatabaseObserver& aObserver, RFs& aFs)");
}
// -----------------------------------------------------------------------------
// ConstructL
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::ConstructL(const TDesC& aPath)
{
TRACER("void CGlxtnVolumeDatabase::ConstructL(const TDesC& aPath)");
iDrive = aPath.Left(KMaxDriveName);
TRAPD(error, OpenDbL(iFs, aPath));
GLX_LOG_INFO1("CGlxtnVolumeDatabase::ConstructL OpenDbL TRAP error = %d", error);
if ( KErrNone != error )
{
iDatabase.Close();
delete iStore;
iStore = NULL;
CreateDbL(iFs, aPath);
}
CActiveScheduler::Add(this);
}
// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CGlxtnVolumeDatabase::~CGlxtnVolumeDatabase()
{
TRACER("CGlxtnVolumeDatabase::~CGlxtnVolumeDatabase()");
Cancel();
iView.Close();
iTable.Close();
iDbUpdater.Close();
iDatabase.Close();
delete iStore;
}
// -----------------------------------------------------------------------------
// Drive
// -----------------------------------------------------------------------------
//
const TDesC& CGlxtnVolumeDatabase::Drive() const
{
TRACER("TDesC& CGlxtnVolumeDatabase::Drive()");
return iDrive;
}
// -----------------------------------------------------------------------------
// GetThumbnailIdL
// Look up thumbnail ID from Ids table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::GetThumbnailIdL( const TGlxMediaId& aMediaId )
{
TRACER("void CGlxtnVolumeDatabase::GetThumbnailIdL( const TGlxMediaId& aMediaId )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("CGlxtnVolumeDatabase::GetThumbnailIdL() Media Id= %d",aMediaId.Value());
HBufC* sql = HBufC::NewLC(
KGlxQueryThumbIdFromIds().Length() + KGlxTIntMaxDigits );
*sql = KGlxQueryThumbIdFromIds;
sql->Des().AppendNum( aMediaId.Value() );
EvaluateQueryL( *sql );
iState = EStateGettingIdFromMediaId;
CleanupStack::PopAndDestroy(sql);
}
// -----------------------------------------------------------------------------
// GetThumbnailIdL
// Look up thumbnail ID from Items table. If not found, add new record.
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::GetThumbnailIdL(const CGlxtnFileInfo* aInfo)
{
TRACER("void CGlxtnVolumeDatabase::GetThumbnailIdL(const CGlxtnFileInfo* aInfo)");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
iInfo = aInfo;
HBufC* uri = QuoteSqlStringLC(iInfo->FilePath());
HBufC* sql = HBufC::NewLC(
KGlxQueryThumbIdFromItems().Length() + uri->Length());
*sql = KGlxQueryThumbIdFromItems;
sql->Des().Append(*uri);
EvaluateQueryL( *sql );
iState = EStateGettingIdFromFilename;
CleanupStack::PopAndDestroy(sql);
CleanupStack::PopAndDestroy(uri);
}
// -----------------------------------------------------------------------------
// GetThumbnailIdL
// Retrieve the thumbnail id to be assigned to the next thumbnail that gets stored in the database.
// -----------------------------------------------------------------------------
//
TGlxtnThumbnailId CGlxtnVolumeDatabase::GetThumbnailId()
{
GLX_LOG_ENTRY_EXIT("void CGlxtnVolumeDatabase::GetThumbnailIdL()");
TGlxtnThumbnailId thumbId( iNextThumbId );
iNextThumbId++;
GLX_LOG_INFO1("CGlxtnVolumeDatabase::InitializeThumbIdL iNextThumbId=%d", iNextThumbId);
return thumbId;
}
// -----------------------------------------------------------------------------
// StoreThumbnailIdL
// Add record to Ids table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::StoreThumbnailIdL( const TGlxMediaId& aMediaId,
const TGlxtnThumbnailId& aThumbId )
{
TRACER("void CGlxtnVolumeDatabase::StoreThumbnailIdL( const TGlxMediaId& aMediaId, const TGlxtnThumbnailId& aThumbId )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("StoreThumbnailIdL():- Media Id = %d",aMediaId.Value());
GLX_LOG_INFO1("StoreThumbnailIdL():- aThumbId = %d",aThumbId.Value());
RDbTable table;
CleanupClosePushL(table);
User::LeaveIfError( table.Open(
iDatabase, KGlxTableIds, RDbRowSet::EInsertOnly ) );
table.InsertL();
table.SetColL( KGlxColIdMediaId, aMediaId.Value() );
table.SetColL( KGlxColIdThumbId, aThumbId.Value() );
table.PutL();
GLX_LOG_INFO2("StoreThumbnailIdL():- Added media id [%d] and thumb id [%d] to Ids table. ", aMediaId.Value(), aThumbId.Value());
CleanupStack::PopAndDestroy(&table);
iObserver.HandleThumbnailIdStoredL();
}
void CGlxtnVolumeDatabase::StoreItemsL( const TGlxtnThumbnailId& aThumbId, const CGlxtnFileInfo* aInfo )
{
__ASSERT_ALWAYS(aInfo, Panic(EGlxPanicNullPointer));
GLX_LOG_ENTRY_EXIT("void CGlxtnVolumeDatabase::StoreItemsL()");
GLX_LOG_INFO1("StoreItemsL():- ThumbId Id = %d",aThumbId.Value());
RDbTable table;
CleanupClosePushL(table);
User::LeaveIfError(table.Open(iDatabase, KGlxTableItems, RDbRowSet::EUpdatable));
User::LeaveIfError(table.SetIndex(KGlxIndexItems));
TGlxtnThumbnailId thumbId( aThumbId );
HBufC* sql = HBufC::NewLC( KGlxQueryItems().Length() + KGlxTIntMaxDigits);
sql->Des().Format( KGlxQueryItems, thumbId.Value());
RDbView view;
CleanupClosePushL(view);
User::LeaveIfError(view.Prepare(
iDatabase, *sql, RDbRowSet::EReadOnly ) );
view.EvaluateAll();
if (view.IsEmptyL())
{
GLX_LOG_INFO("StoreItemsL() - Add a new record");
table.InsertL();
table.SetColL( KGlxColItemUri, aInfo->FilePath() );
table.SetColL( KGlxColItemId, thumbId.Value() );
table.SetColL( KGlxColItemFileSize, aInfo->iFileSize );
table.SetColL( KGlxColItemModTime, aInfo->iFileTime );
table.PutL();
}
CleanupStack::PopAndDestroy(&view);
CleanupStack::PopAndDestroy(sql);
CleanupStack::PopAndDestroy(&table);
}
// -----------------------------------------------------------------------------
// GetThumbnailL
// Look up thumbnail from Thumbnails table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::GetThumbnailL( const TGlxtnThumbnailId& aThumbId,
const TSize& aSize )
{
TRACER("void CGlxtnVolumeDatabase::GetThumbnailL( const TGlxtnThumbnailId& aThumbId, const TSize& aSize )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("GetThumbnailL():- ThumbId Id = %d",aThumbId.Value());
GLX_LOG_INFO2("GetThumbnailL Width=%d, Height=%d", aSize.iWidth, aSize.iHeight);
HBufC* sql = HBufC::NewLC( KGlxQueryThumbnail().Length()
+ 3 * KGlxTIntMaxDigits);
sql->Des().Format( KGlxQueryThumbnail,
aThumbId.Value(), aSize.iWidth, aSize.iHeight );
EvaluateQueryL( *sql );
iState = EStateGettingThumbnail;
CleanupStack::PopAndDestroy(sql);
}
// -----------------------------------------------------------------------------
// CheckAvailableL
// Check if thumbnail is in Thumbnails table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::CheckAvailableL( const TGlxtnThumbnailId& aThumbId,
const TSize& aSize )
{
TRACER("void CGlxtnVolumeDatabase::CheckAvailableL( const TGlxtnThumbnailId& aThumbId, const TSize& aSize )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("CheckAvailableL():- ThumbId = %d", aThumbId.Value());
HBufC* sql = HBufC::NewLC( KGlxQueryAvailable().Length()
+ 3 * KGlxTIntMaxDigits);
sql->Des().Format( KGlxQueryAvailable,
aThumbId.Value(), aSize.iWidth, aSize.iHeight );
EvaluateQueryL( *sql );
iState = EStateCheckingAvailability;
CleanupStack::PopAndDestroy(sql);
}
// -----------------------------------------------------------------------------
// StoreThumbnailL
// Add record to Thumbnails table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::StoreThumbnailL( const TGlxtnThumbnailId& aThumbId,
const TSize& aSize,
TGlxImageDataFormat aFormat,
const TDesC8& aData )
{
TRACER("void CGlxtnVolumeDatabase::StoreThumbnailL( const TGlxtnThumbnailId& aThumbId, const TSize& aSize, TGlxImageDataFormat aFormat, const TDesC8& aData )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("StoreThumbnailL():- aThumbId = %d",aThumbId.Value());
GLX_LOG_INFO2("StoreThumbnailL Width=%d, Height=%d", aSize.iWidth, aSize.iHeight);
RDbTable table;
CleanupClosePushL(table);
User::LeaveIfError( table.Open(
iDatabase, KGlxTableThumbnails, RDbRowSet::EInsertOnly ) );
table.InsertL();
table.SetColL( KGlxColThumbnailId, aThumbId.Value() );
table.SetColL( KGlxColThumbnailWidth, aSize.iWidth );
table.SetColL( KGlxColThumbnailHeight, aSize.iHeight );
table.SetColL( KGlxColThumbnailFormat, aFormat );
table.SetColL( KGlxColThumbnailData, aData );
table.PutL();
CleanupStack::PopAndDestroy(&table);
iObserver.HandleThumbnailStored();
}
// -----------------------------------------------------------------------------
// DeleteFromIdsL
// Delete from IDs table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::DeleteIdL( const TGlxMediaId& aMediaId )
{
TRACER("void CGlxtnVolumeDatabase::DeleteIdL( const TGlxMediaId& aMediaId )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("DeleteIdL():- Media Id = %d",aMediaId.Value());
HBufC* sql = HBufC::NewLC( KGlxDeleteId().Length() + KGlxTIntMaxDigits);
sql->Des().Format( KGlxDeleteId, aMediaId.Value() );
UpdateDataL( *sql );
iState = EStateDeletingId;
CleanupStack::PopAndDestroy(sql);
}
// -----------------------------------------------------------------------------
// DeleteThumbnailsL
// Delete Thumbnails from Thumbnail table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::DeleteThumbnailsL(
const TGlxtnThumbnailId& aThumbId )
{
TRACER("void CGlxtnVolumeDatabase::DeleteThumbnailsL( const TGlxtnThumbnailId& aThumbId )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("DeleteThumbnailsL():- aThumbId = %d",aThumbId.Value());
HBufC* sql = HBufC::NewLC(KGlxDeleteThumbnails().Length() +
KGlxTIntMaxDigits);
sql->Des().Format( KGlxDeleteThumbnails, aThumbId.Value() );
UpdateDataL( *sql );
iState = EStateDeletingThumbnails;
CleanupStack::PopAndDestroy(sql);
}
// -----------------------------------------------------------------------------
// DeleteItemL
// Delete Item from Items table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::DeleteItemL( const TGlxtnThumbnailId& aThumbId )
{
TRACER("void CGlxtnVolumeDatabase::DeleteItemL( const TGlxtnThumbnailId& aThumbId )");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
GLX_LOG_INFO1("DeleteItemL():- aThumbId = %d",aThumbId.Value());
HBufC* sql = HBufC::NewLC( KGlxDeleteItem().Length() + KGlxTIntMaxDigits);
sql->Des().Format( KGlxDeleteItem, aThumbId.Value() );
UpdateDataL( *sql );
iState = EStateDeletingItem;
CleanupStack::PopAndDestroy(sql);
}
// -----------------------------------------------------------------------------
// CleanupDatabaseL
// Clean from database entries that do not have a corresponding media file
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::CleanupDatabaseL()
{
TRACER("void CGlxtnVolumeDatabase::CleanupDatabaseL()");
if ( EStateIdle != iState )
{
User::Leave(KErrNotReady);
}
User::LeaveIfError( iTable.Open(
iDatabase, KGlxTableItems, RDbRowSet::EUpdatable ) );
iTable.BeginningL();
SetActive();
TRequestStatus* ts = &iStatus;
User::RequestComplete(ts, KErrNone);
iState = EStateCleaning;
}
// -----------------------------------------------------------------------------
// CleanupRowL
// Test entry in one row in Items table to see if file is available. If it is
// not, delete this row and start process of deleting corresponding entries
// from Ids table and Thumbnails table
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::CleanupRowL()
{
TRACER("void CGlxtnVolumeDatabase::CleanupRowL()");
// Get filename
iTable.GetL();
TPtrC filename = iTable.ColDes(KGlxColItemUri);
// check if file exists
TTime time(0);
TInt err = iFs.Modified(filename, time);
GLX_LOG_INFO1("void CGlxtnVolumeDatabase::CleanupRowL() New Time = %Ld",time.Int64());
TTime modifiedTime(0);
modifiedTime = iTable.ColTime(KGlxColItemModTime);
GLX_LOG_INFO1("void CGlxtnVolumeDatabase::CleanupRowL() modifiedTime (from thumb Db) = %Ld",modifiedTime.Int64());
if(err == KErrNone && (modifiedTime.Int64() == time.Int64()))
{
GLX_LOG_INFO("void CGlxtnVolumeDatabase::CleanupRowL() DBmodTime and FileModTime Same");
//yes, file exists and not modified, so complete to go to next row
SetActive();
TRequestStatus* ts = &iStatus;
User::RequestComplete(ts, KErrNone);
iState = EStateCleaning;
}
else
{
GLX_LOG_INFO("void CGlxtnVolumeDatabase::CleanupRowL() DBmodTime and FileModTime NOT Same");
TUint thumbId = iTable.ColUint( KGlxColItemId );
if (err != KErrNone)
{
GLX_LOG_INFO1("void CGlxtnVolumeDatabase::CleanupRowL() DBmodTime and FileModTime NOT Same But err = %d", err);
// Problem accessing file, so delete database entries
// First delete row in Items table
// Delete the row (entry in Items)
iTable.DeleteL();
}
else
{
// file modified, so update the modified time in items table
iTable.UpdateL();
iTable.SetColL(KGlxColItemModTime, time);
iTable.PutL();
}
// Now delete from Thumbnails
HBufC* sql = HBufC::NewLC(KGlxDeleteThumbnails().Length() +
KGlxTIntMaxDigits);
sql->Des().Format( KGlxDeleteThumbnails, thumbId );
UpdateDataL( *sql );
iState = EStateCleaningDeletingThumbnails;
CleanupStack::PopAndDestroy(sql);
}
}
// -----------------------------------------------------------------------------
// DoCancel
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::DoCancel()
{
TRACER("void CGlxtnVolumeDatabase::DoCancel()");
iView.Cancel();
iTable.Close();
iDbUpdater.Close();
iState = EStateIdle;
}
// -----------------------------------------------------------------------------
// RunL
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::RunL()
{
TRACER("void CGlxtnVolumeDatabase::RunL()");
User::LeaveIfError(iStatus.Int());
// Continue any database operations which aren't finished
switch ( iState )
{
case EStateGettingIdFromMediaId:
case EStateGettingIdFromFilename:
case EStateGettingThumbnail:
case EStateCheckingAvailability:
if ( iView.Unevaluated() )
{
iView.Evaluate(iStatus);
SetActive();
return;
}
break;
case EStateDeletingId:
case EStateDeletingThumbnails:
case EStateDeletingItem:
case EStateCleaningDeletingThumbnails:
if(iStatus.Int() != 0)
{
iDbUpdater.Next(iStatus);
SetActive();
return;
}
break;
case EStateCleaning:
// do nothing
break;
default:
Panic(EGlxPanicIllegalState);
break;
}
// Handle results of database operation
switch ( iState )
{
case EStateGettingIdFromMediaId:
{
TGlxtnThumbnailId thumbId;
if ( iView.FirstL() )
{
iView.GetL();
thumbId = iView.ColUint(KGlxColIdThumbId);
GLX_LOG_INFO1("RunL - EStateGettingIdFromMediaId IF (iView.FirstL()): ThumbId = %d", thumbId.Value());
}
else
{
GLX_LOG_INFO("RunL - EStateGettingIdFromMediaId (iView.FirstL()): ELSE -> thumbId not retrieved" );
}
iView.Close();
iState = EStateIdle;
iObserver.HandleThumbnailIdFromMediaIdL(thumbId);
}
break;
case EStateGettingIdFromFilename:
{
TGlxtnThumbnailId thumbId;
if ( iView.FirstL() )
{
iView.GetL();
thumbId = iView.ColUint(KGlxColItemId);
iView.Close();
GLX_LOG_INFO1("RunL - EStateGettingIdFromFilename IF (iView.FirstL()): ThumbId = %d", thumbId.Value());
}
else
{
iView.Close();
GLX_LOG_INFO("RunL - EStateGettingIdFromMediaId (iView.FirstL()): ELSE -> no Thumbnail Yet. So DoAddItemL() being called" );
thumbId = DoAddItemL();
GLX_LOG_INFO1("RunL - EStateGettingIdFromMediaId (iView.FirstL()): ELSE -> ThumbId = %d", thumbId.Value());
}
iState = EStateIdle;
iInfo = NULL;
GLX_LOG_INFO1("RunL - EStateGettingIdFromFilename - aThumbId = %d", thumbId.Value());
iObserver.HandleThumbnailIdFromFilenameL(thumbId);
}
break;
case EStateGettingThumbnail:
if ( iView.FirstL() )
{
iView.GetL();
TGlxImageDataFormat format = static_cast<TGlxImageDataFormat>(
iView.ColInt(KGlxColThumbnailFormat));
TInt size = iView.ColSize(KGlxColThumbnailData);
GLX_LOG_INFO("RunL: Reading Thumbnail from dB");
RDbColReadStream stream;
stream.OpenLC(iView, KGlxColThumbnailData);
HBufC8* data = HBufC8::NewLC(size);
TPtr8 ptr(data->Des());
// Need to specify amount to read, as the HBufC8 can be bigger
// than requested
stream.ReadL(ptr, size);
CleanupStack::Pop(data);
CleanupStack::PopAndDestroy(&stream);
iView.Close();
iState = EStateIdle;
iObserver.HandleThumbnail(format, data);
}
else
{
iView.Close();
iState = EStateIdle;
GLX_LOG_INFO("RunL: HandleDatabaseError - KErrNotFound");
iObserver.HandleDatabaseError(KErrNotFound);
}
break;
case EStateDeletingId:
iState = EStateIdle;
iDbUpdater.Close();
iObserver.HandleMediaIdDeletedL();
break;
case EStateDeletingThumbnails:
iState = EStateIdle;
iDbUpdater.Close();
iObserver.HandleThumbnailsDeletedL();
break;
case EStateDeletingItem:
iState = EStateIdle;
iDbUpdater.Close();
iObserver.HandleItemDeletedL();
break;
case EStateCheckingAvailability:
{
TInt result = KGlxThumbnailAvailable;
if ( iView.IsEmptyL() )
{
result = KGlxThumbnailNotAvailable;
}
iView.Close();
iState = EStateIdle;
GLX_LOG_INFO1("RunL - EStateCheckingAvailability - result = %d", result);
iObserver.HandleAvailabilityChecked(result);
}
break;
case EStateCleaningDeletingThumbnails:
iState = EStateCleaning;
iDbUpdater.Close(); // deliberate fall through to next row
case EStateCleaning:
if(iTable.NextL())
{
// next row
CleanupRowL();
}
else
{
// no more rows
iTable.Close();
iState = EStateIdle;
iObserver.HandleDatabaseCleanedL();
}
break;
default:
Panic(EGlxPanicIllegalState);
break;
}
}
// -----------------------------------------------------------------------------
// RunError
// -----------------------------------------------------------------------------
//
TInt CGlxtnVolumeDatabase::RunError(TInt aError)
{
TRACER("TInt CGlxtnVolumeDatabase::RunError(TInt aError)");
GLX_LOG_INFO2("RunL: HandleDatabaseError - iState=%d, error=%d",
iState, aError);
TInt error = aError;
iTable.Close();
iView.Close();
iDbUpdater.Close();
iInfo = NULL;
if (aError == KErrCorrupt)
{
error = KErrCorruptThumbnailDatabase;
}
else if (aError == KErrEof)
{
error = KErrEofThumbnailDatabase;
}
iObserver.HandleDatabaseError(error);
iState = EStateIdle;
return KErrNone;
}
// -----------------------------------------------------------------------------
// OpenDbL
// Open an existing database.
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::OpenDbL(RFs& aFs, const TDesC& aFilename)
{
TRACER("void CGlxtnVolumeDatabase::OpenDbL(RFs& aFs, const TDesC& aFilename)");
iStore = CFileStore::OpenL(aFs, aFilename, EFileRead | EFileWrite);
iDatabase.OpenL(iStore, iStore->Root());
User::LeaveIfError(iDatabase.Recover());
RDbTable tableIds;
CleanupClosePushL(tableIds);
// open and check the Ids table
User::LeaveIfError( tableIds.Open(
iDatabase, KGlxTableIds, RDbRowSet::EReadOnly ) );
User::LeaveIfError(tableIds.SetIndex(KGlxIndexThumbIds));
CleanupStack::PopAndDestroy(&tableIds);
}
// -----------------------------------------------------------------------------
// InitializeThumbIdL
// Initialize thumbnail identifier to the last known value plus one.
// -----------------------------------------------------------------------------
void CGlxtnVolumeDatabase::InitializeThumbIdL()
{
GLX_LOG_ENTRY_EXIT("void CGlxtnThumbnailDatabase::InitializeThumbIdL()");
// Get next available thumbnail ID (synchronous)
RDbTable tableIds;
CleanupClosePushL(tableIds);
// open and check the Ids table
User::LeaveIfError( tableIds.Open(
iDatabase, KGlxTableIds, RDbRowSet::EReadOnly ) );
User::LeaveIfError(tableIds.SetIndex(KGlxIndexThumbIds));
// Find highest thumbnail ID in use. New entries are added to the Items
// table first, and deleted from the Items table last, so all IDs in use
// will always be found there.
// Thumbnail IDs are only unique within a volume.
if ( tableIds.LastL() )
{
tableIds.GetL();
iNextThumbId = tableIds.ColUint(KGlxColIdThumbId) + 1;
}
else
{
// Database is empty
iNextThumbId = KGlxFirstThumbnailId;
}
GLX_LOG_INFO1("CGlxtnVolumeDatabase::InitializeThumbIdL iNextThumbId=%d", iNextThumbId);
CleanupStack::PopAndDestroy(&tableIds);
}
// -----------------------------------------------------------------------------
// CreateDbL
// Create a new database.
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::CreateDbL(RFs& aFs, const TDesC& aFilename)
{
TRACER("void CGlxtnVolumeDatabase::CreateDbL(RFs& aFs, const TDesC& aFilename)");
// Create database, overwriting any existing file
TInt err = aFs.MkDirAll(aFilename);
if ( err != KErrAlreadyExists )
{
User::LeaveIfError(err);
}
iStore = CPermanentFileStore::ReplaceL(aFs, aFilename,
EFileRead | EFileWrite);
iStore->SetTypeL(KPermanentFileStoreLayoutUid);
iStore->SetRootL(iDatabase.CreateL(iStore));
iStore->CommitL();
User::LeaveIfError(iDatabase.Execute(KGlxCreateTableIds));
User::LeaveIfError(iDatabase.Execute(KGlxCreateTableItems));
User::LeaveIfError(iDatabase.Execute(KGlxCreateTableThumbnails));
User::LeaveIfError(iDatabase.Execute(KGlxCreateIndexIds));
User::LeaveIfError(iDatabase.Execute(KGlxCreateIndexThumbIds));
User::LeaveIfError(iDatabase.Execute(KGlxCreateIndexItems));
User::LeaveIfError(iDatabase.Execute(KGlxCreateIndexThumbnails));
}
// -----------------------------------------------------------------------------
// DoAddItemL
// -----------------------------------------------------------------------------
//
TGlxtnThumbnailId CGlxtnVolumeDatabase::DoAddItemL()
{
TRACER("TGlxtnThumbnailId CGlxtnVolumeDatabase::DoAddItemL()");
__ASSERT_ALWAYS(iInfo, Panic(EGlxPanicNullPointer));
RDbTable table;
CleanupClosePushL(table);
User::LeaveIfError(table.Open(iDatabase, KGlxTableItems, RDbRowSet::EInsertOnly));
TGlxtnThumbnailId thumbId( iNextThumbId );
GLX_LOG_INFO1("TGlxtnThumbnailId CGlxtnVolumeDatabase::DoAddItemL() thumbId =%d", thumbId.Value());
table.InsertL();
table.SetColL( KGlxColItemUri, iInfo->FilePath() );
table.SetColL( KGlxColItemId, thumbId.Value() );
table.SetColL( KGlxColItemFileSize, iInfo->iFileSize );
table.SetColL( KGlxColItemModTime, iInfo->iFileTime );
table.PutL();
CleanupStack::PopAndDestroy(&table);
return thumbId;
}
// -----------------------------------------------------------------------------
// EvaluateQueryL
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::EvaluateQueryL( const TDbQuery &aQuery )
{
TRACER("void CGlxtnVolumeDatabase::EvaluateQueryL( const TDbQuery &aQuery )");
User::LeaveIfError( iView.Prepare(
iDatabase, aQuery, RDbRowSet::EReadOnly ) );
iView.Evaluate( iStatus );
SetActive();
}
// -----------------------------------------------------------------------------
// UpdateDataL
// -----------------------------------------------------------------------------
//
void CGlxtnVolumeDatabase::UpdateDataL( const TDesC& aSql )
{
TRACER("void CGlxtnVolumeDatabase::UpdateDataL( const TDesC& aSql )");
TInt result = iDbUpdater.Execute( iDatabase, aSql );
if ( result < KErrNone )
{
iDbUpdater.Close();
User::Leave( result );
}
// According to documentation a result of 0 should indicate complete
// but this does not seem to be the case
iDbUpdater.Next( iStatus );
SetActive();
}
// -----------------------------------------------------------------------------
// QuoteSqlStringLC
// -----------------------------------------------------------------------------
//
HBufC* CGlxtnVolumeDatabase::QuoteSqlStringLC(const TDesC& aText)
{
TRACER("HBufC* CGlxtnVolumeDatabase::QuoteSqlStringLC(const TDesC& aText)");
const TText quote('\'');
TInt length = aText.Length() + 2;
for ( TInt i = 0; i < aText.Length(); i++ )
{
if ( quote == aText[i] )
{
length++;
}
}
HBufC* text = HBufC::NewLC(length);
TPtr ptr(text->Des());
ptr.Append(quote);
for ( TInt i = 0; i < aText.Length(); i++ )
{
TText chr = aText[i];
ptr.Append(chr);
if ( quote == chr )
{
ptr.Append(quote);
}
}
ptr.Append(quote);
return text;
}