diff -r e1e28b0273b0 -r 93fff7023be8 EngSrc/IEImageList.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EngSrc/IEImageList.cpp Fri Oct 15 10:18:29 2010 +0900 @@ -0,0 +1,679 @@ +/* +* Copyright (c) 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: Juha Kauppinen, Mika Hokkanen +* +* Description: Photo Browser +* +*/ + +// INCLUDE FILES + +#include +#include +#include +#include +#include +#include "IEImageList.h" +#include "IEImageData.h" +#include "IEEngineImp.h" +#include "IEEngineUtils.h" +#include "ImageMonitorAO.h" +#include "IEFileLoader.h" +#ifdef _S60_5x_ACCELEROMETER_ +#include "IESensorMonitor.h" +#endif + +#define LATETHUMBCHECK +//#define GROUP_FOLDERS_BY_NAME +#define CHECK_IF_IMAGE_IS_VISIBLE + +_LIT(KDatabaseFileName, "photobrowser.db"); +_LIT8(KDatabaseId, "IMGC0008"); +const TInt KNumOfDrives = 3; + +EXPORT_C CIEImageList* CIEImageList::NewL( + RArray& aImageData, + CIEFileLoader* aCallback) + { + CIEImageList* self = new (ELeave) CIEImageList(aImageData, aCallback); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CIEImageList::CIEImageList( + RArray& aImageData, + CIEFileLoader* aCallback) : + iCallback(aCallback), + iImageDataList(aImageData), + iGridMode(EGridModeTime) + { + for (TInt i = 0;i < KNumOfDrives;i++) + iDatabaseChanged[i] = EFalse; + } + +void CIEImageList::ConstructL() + { + User::LeaveIfError(iCritical.CreateLocal()); + } + +EXPORT_C CIEImageList::~CIEImageList() + { + iCritical.Close(); + } + +EXPORT_C void CIEImageList::SetGridMode(TGridMode aGridMode) + { + if (iGridMode != aGridMode) + { + iGridMode = aGridMode; + iCritical.Wait(); + Rearrange(0); + iCritical.Signal(); + } + } + +EXPORT_C TGridMode CIEImageList::GetGridMode() const + { + return iGridMode; + } + +EXPORT_C void CIEImageList::SetChanged(TDesC& aPath) + { + TImageListDrive drive = EImageListDriveC; + TRAPD(err, drive = GetPathDriveL(aPath)); + if (err == KErrNone) + { + iDatabaseChanged[drive] = ETrue; + } + } + +void CIEImageList::SetChanged(CImageData* aImageData) + { + TFileName fileName; + aImageData->GetFileName(fileName, EFullSize); + SetChanged(fileName); + } + +CImageData* CIEImageList::CreateImageDataL( + const TFileName& aFileName, + const TTime& aTime, + const TReal orientation) + { + DP0_IMAGIC(_L("CIEImageList::CreateImageDataL++")); + + // Create new image data instance + CImageData* imageData = CImageData::NewL( +#ifdef LATETHUMBCHECK + /*EFullSize|*/ESize512x512|ESize128x128|ESize32x32 +#endif + ); + + imageData->SetCreatedTime(aTime); + imageData->SetFileNameL(aFileName); + imageData->SetOrientation(orientation); + +#ifdef _S60_5x_ACCELEROMETER_ + // Portrait + if(iCallback->DeviceOrientation() == TSensrvOrientationData::EOrientationDisplayUp) + { + imageData->iGridData.iTargetRotationAngle = 90 + orientation; + } + // Landscape + else//(iCallback->DeviceOrientation() == TSensrvOrientationData::EOrientationDisplayRightUp) + { + imageData->iGridData.iTargetRotationAngle = orientation; + } + imageData->iGridData.iRotationAngle = orientation; +#else + imageData->iGridData.iRotationAngle = orientation; + imageData->iGridData.iTargetRotationAngle = orientation; +#endif + + DP1_IMAGIC(_L("CIEImageList::AddImageL - filename: %S"), &aFileName); + +#ifndef LATETHUMBCHECK + //Check and mark to imageData which thumbnails exists + CheckCreatedThumbnails(*imageData); +#endif + + DP0_IMAGIC(_L("CIEImageList::CreateImageDataL--")); + return imageData; + } + +TBool CIEImageList::IsImageBefore(CImageData* aNewImageData, TInt aIndex) const + { + if (aIndex >= iImageDataList.Count()) + return ETrue; + + // Use folder grouping + if (iGridMode != EGridModeTime) + { + TFileName newPath, path; + aNewImageData->GetPath(newPath); + iImageDataList[aIndex]->GetPath(path); + +#ifdef GROUP_FOLDERS_BY_NAME + // Folders are sorted by name + if (newPath > path) // TODO: should trim drive + base path (e.g. C:\data\) + return ETrue; + if (newPath < path) + return EFalse; +#else + + if (iGridMode == EGridModePeople) + { + return (iImageDataList[aIndex]->iPersonId > + aNewImageData->iPersonId); + } + else if (iGridMode == EGridModeFolder && aIndex > 0) + { + // Current image path is not same + if (path != newPath) + { + TFileName prevPath; + iImageDataList[aIndex - 1]->GetPath(prevPath); + + // Previous image path is same, add after that + if (newPath == prevPath) + return ETrue; + + // Compare only against the first image in the folder + if (path == prevPath) + return EFalse; + } + } +#endif + } + + // Compare times + return (aNewImageData->GetCreatedTime() > iImageDataList[aIndex]->GetCreatedTime()); + } + +TInt CIEImageList::GetNewImageIndex(CImageData* aImageData) const + { + TInt index = 0; + while(index < iImageDataList.Count()) + { + if(IsImageBefore(aImageData, index)) + { + break; + } + index++; + } + return index; + } + +void CIEImageList::Rearrange(TInt aStartIndex) + { + for (TInt i = aStartIndex;i < iImageDataList.Count();i++) + { + CImageData* imageData = iImageDataList[i]; + iImageDataList.Remove(i); + TInt newIndex = GetNewImageIndex(imageData); + iImageDataList.Insert(imageData, newIndex); + } + } + +EXPORT_C void CIEImageList::AddImage(CImageData* aImageData) + { + DP0_IMAGIC(_L("CIEImageList::AddImageL++")); + + iCritical.Wait(); + + // Insert image to list + TInt index = GetNewImageIndex(aImageData); + iImageDataList.Insert(aImageData, index); + + // Need to resort all items if use time based folder sort +#ifndef GROUP_FOLDERS_BY_NAME + if (iGridMode != EGridModeTime) + { + Rearrange(index + 1); + } +#endif + + // Image is not added as last image + if (index < iImageDataList.Count() - 1) + { + // Mark database as changed + SetChanged(aImageData); + + // Inform UI + //iCallback->ImageListChanged(index, ETrue); + } + + iCallback->ImageListChanged(index, ETrue); + + iCritical.Signal(); + + DP0_IMAGIC(_L("CIEImageList::AddImageL-- tmpImageData")); + } + +#ifdef IMAGIC_DATABASE + +void CIEImageList::GetDatabaseFileName(TFileName& aFileName, TImageListDrive aDrive) + { + switch (aDrive) + { + case EImageListDriveC: + aFileName.Copy(PathInfo::PhoneMemoryRootPath()); + break; + + case EImageListDriveE: + aFileName.Copy(PathInfo::MemoryCardRootPath()); + break; + + case EImageListDriveF: + aFileName.Copy(KRootPathFDrive); + break; + + default: + return; + } + + aFileName.Append(KDatabaseFileName); + } + +EXPORT_C void CIEImageList::ReadDatabaseL() + { + DP0_IMAGIC(_L("CIEImageList::ReadDatabaseL++")); + + RFileReadStream readStreams[KNumOfDrives]; + TBool openStreams[KNumOfDrives]; + CImageData* imageDatas[KNumOfDrives]; + RFs fs; + + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + // Open databases + for (TInt i = 0;i < KNumOfDrives;i++) + { + openStreams[i] = EFalse; + imageDatas[i] = NULL; + + TFileName databaseFileName; + GetDatabaseFileName(databaseFileName, TImageListDrive(i)); + if (readStreams[i].Open(fs, databaseFileName, EFileShareAny) == KErrNone) + { + // Check file validity and version + TUint8 buf[8]; + TPtr8 ptr(buf, sizeof(buf)); + readStreams[i].ReadL(ptr, KDatabaseId.iTypeLength); + if (ptr.Compare(KDatabaseId) != 0) + readStreams[i].Close(); + else + openStreams[i] = ETrue; + } + } + + // Read databases + while(iCallback->ImageFinderState() == CIEFileLoader::EImageFinderRunning) + { + // Read image datas from each database + TBool endOfData = ETrue; + for(TInt i = 0;i < KNumOfDrives;i++) + { + // Database is open and no image data is left + if (imageDatas[i] == NULL && openStreams[i]) + { + TRAPD(err, imageDatas[i] = ReadImageDataL(readStreams[i], fs)); + if (err != KErrNone || imageDatas[i] == NULL) + { + openStreams[i] = EFalse; + readStreams[i].Close(); + } + } + + if (imageDatas[i]) + endOfData = EFalse; + } + + if (endOfData) + break; + + // Pick the most leftmost image + TInt index = -1; + for (TInt i = 0;i < KNumOfDrives;i++) + { + if (imageDatas[i] && + (index < 0 || + IsImageBefore(imageDatas[i], index))) + index = i; + } + + // Add image to list + if (index >= 0) + { + AddImage(imageDatas[index]); + imageDatas[index] = NULL; + } + } + + CleanupStack::Pop(); + fs.Close(); + + DP0_IMAGIC(_L("CIEImageList::ReadDatabaseL--")); + } + +CImageData* CIEImageList::ReadImageDataL(RFileReadStream& readStream, RFs& aFs) + { + TUint8 buf[KMaxFileName * 2]; + TPtr8 ptr(buf, sizeof(buf)); + TFileName fileName; + TTime fileTime, createdTime; + TSize size; + TInt faces; + TUint16 orientation; + CImageData* imageData = NULL; + + // Read until get valid image data + while (imageData == NULL) { + + // Read file name (1 byte length, unicode name) + TInt len = readStream.ReadUint8L(); + + // End of list + if (len == 0) + return NULL; + + readStream.ReadL(ptr, len * 2); + TPtrC16 ptr16((const TUint16*)buf, len); + fileName.Copy(ptr16); + + // Read file time + readStream.ReadL(ptr, sizeof(TTime)); + fileTime = *(TTime*)ptr.Ptr(); + + // Read created time + readStream.ReadL(ptr, sizeof(TTime)); + createdTime = *(TTime*)ptr.Ptr(); + + // Read orientation (in 90 degrees angles) + orientation = readStream.ReadUint8L() * 90L; + + // Read resolution + size.iWidth = readStream.ReadUint32L(); + size.iHeight = readStream.ReadUint32L(); + + // Read number of faces + faces = readStream.ReadInt8L(); + + TInt personId = readStream.ReadInt32L(); + + // Check that no multiple entries + if ((imageData = GetImageData(fileName)) != NULL) + { + imageData = NULL; + continue; + } + + // Check if image exist and not be hidden + TInt error = KErrNone; + TBool visible = ETrue; +#ifdef CHECK_IF_IMAGE_IS_VISIBLE + + TRAP(error, visible = IsImageViewableL(fileName, aFs)); +#endif + if (error == KErrNone && visible) + { + // Create image data object + imageData = CreateImageDataL( + fileName, + createdTime, + orientation); + + if (imageData) + { + imageData->SetFileTime(fileTime); + imageData->SetSize(size); + imageData->SetNumberOfFaces(faces); + imageData->iPersonId = personId; + //imageData->SetImageReady(EFullSize, ETrue); + } + } + else + { + // Delete thumbnails if file could not be read + if (error != KErrNone) + CIEEngineUtils::DeleteThumbnails(fileName, aFs); + SetChanged(fileName); + } + } + + return imageData; + } + +EXPORT_C void CIEImageList::WriteDatabaseL() + { + DP0_IMAGIC(_L("CIEImageList::WriteDatabaseL++")); + + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + for (TInt i = 0;i < KNumOfDrives;i++) + { + if (iDatabaseChanged[i]) + { + TRAP_IGNORE(WriteDatabaseL(TImageListDrive(i), fs)); + iDatabaseChanged[i] = EFalse; + } + } + + CleanupStack::Pop(); // fs + fs.Close(); + + DP0_IMAGIC(_L("CIEImageList::WriteDatabaseL--")); + } + +void CIEImageList::WriteDatabaseL(TImageListDrive aDrive, RFs& aFs) + { + TUint8 buf[sizeof(TUint32)]; + TPtr8 ptr(buf, sizeof(buf)); + RFile f; + + TFileName path, fileName; + GetDatabaseFileName(fileName, aDrive); + + TParse parser; + parser.Set(fileName, NULL, NULL); + path = parser.DriveAndPath(); + TRAP_IGNORE(BaflUtils::EnsurePathExistsL(aFs, path)); + + if (f.Replace( + aFs, + fileName, + EFileWrite) != KErrNone) + return; + + CleanupClosePushL(f); + + f.SetAtt(KEntryAttHidden, 0); + + RFileWriteStream writeStream(f); + CleanupClosePushL(writeStream); + + writeStream.WriteL(KDatabaseId); + + for (TInt32 i = 0;i < iImageDataList.Count();i++) + { + TFileName fileName; + TImageListDrive drive = EImageListDriveC; + iImageDataList[i]->GetFileName(fileName, EFullSize); + + // Write only files that belong to this drive + TRAPD(err, drive = GetPathDriveL(fileName)); + if (err != KErrNone || drive != aDrive) + continue; + + // Write file name + writeStream.WriteUint8L(fileName.Length()); + writeStream.WriteL(fileName, fileName.Length()); + + // Write file time + TTime fileTime = iImageDataList[i]->GetFileTime(); + TPtrC8 fileTimeptr((const TUint8 *)&fileTime, sizeof(TTime)); + writeStream.WriteL(fileTimeptr); + + // Write created time + TTime createdTime = iImageDataList[i]->GetCreatedTime(); + TPtrC8 createdTimeptr((const TUint8 *)&createdTime, sizeof(TTime)); + writeStream.WriteL(createdTimeptr); + + // Write orientation (in 90 degrees) + writeStream.WriteUint8L(iImageDataList[i]->GetOrientation() / 90); + + // Write size + writeStream.WriteUint32L(iImageDataList[i]->GetSize().iWidth); + writeStream.WriteUint32L(iImageDataList[i]->GetSize().iHeight); + + // Write number of faces + writeStream.WriteInt8L(iImageDataList[i]->GetNumberOfFaces()); + writeStream.WriteInt32L(iImageDataList[i]->iPersonId); + } + + // End of stream notification + writeStream.WriteUint8L(0); + + writeStream.Close(); + + CleanupStack::PopAndDestroy(); // write stream + CleanupStack::PopAndDestroy(); // f + } +#endif + +EXPORT_C TBool CIEImageList::IsImageViewableL(TDesC& aFileName, RFs& aFs) const + { + TUint att; + //if(!IsFileExist(fileName)) + TInt error = aFs.Att(aFileName, att); + if (error != KErrNone) + User::Leave(error); + + return ((att & KEntryAttHidden) == KEntryAttHidden) ? EFalse : ETrue; + } + +EXPORT_C TInt CIEImageList::GetImageIndex(CImageData* aImageData) + { + for (TInt i = 0;i < iImageDataList.Count();i++) + { + if (aImageData == iImageDataList[i]) + return i; + } + return -1; + } + +EXPORT_C CImageData* CIEImageList::GetImageData(const TFileName& aFileName) + { + CImageData* imageData = NULL; + iCritical.Wait(); + + for (TInt i = 0;i < iImageDataList.Count();i++) + { + TFileName fileName; + iImageDataList[i]->GetFileName(fileName, EFullSize); + if (fileName.Compare(aFileName) == 0) + { + imageData = iImageDataList[i]; + break; + } + } + + iCritical.Signal(); + + return imageData; + } + +EXPORT_C void CIEImageList::RemoveNonExistImagesL(TDesC* aPath, RFs& aFs) + { + DP0_IMAGIC(_L("CIEImageList::RemoveNonExistImagesL++")); + + TInt i = 0; + while (i < iImageDataList.Count()) + { + iCritical.Wait(); + + // File may not exist + TBool bRemove = !iImageDataList[i]->IsImageReady(EFullSize); + + // Start of path must be same + if (bRemove && aPath) { + TFileName path; + iImageDataList[i]->GetPath(path); + bRemove = (aPath->Compare(path) == 0); + } + + iCritical.Signal(); + + // Remove from list + if (bRemove) + { + Remove(i, aFs); + if (aPath) + SetChanged(*aPath); + } + else + { + i++; + } + } + + DP0_IMAGIC(_L("CIEImageList::RemoveNonExistImagesL--")); + } + +CIEImageList::TImageListDrive CIEImageList::GetPathDriveL(TDesC& aPath) + { + TParse parser; + parser.Set(aPath, NULL, NULL); + TPtrC drive = parser.Drive(); + const TPtrC drives[] = { _L("C:"), _L("E:"), _L("F:") }; + + for (TInt i = 0;i < sizeof(drives) / sizeof(TPtrC);i++) + { + if (drive.Compare(drives[i]) == 0) + { + return TImageListDrive(i); + } + } + + User::Leave(KErrArgument); + return EImageListDriveC; + } + +EXPORT_C void CIEImageList::Remove(TInt aIndex, RFs& aFs) + { + TFileName fileName; + + if (aIndex < 0 || aIndex >= iImageDataList.Count()) + return; + + // Delete thumbnails if original file doesn't exist anymore + iImageDataList[aIndex]->GetFileName(fileName, EFullSize); + if(!BaflUtils::FileExists(aFs, fileName)) + CIEEngineUtils::DeleteThumbnails(fileName, aFs); + + iCritical.Wait(); + + // Remove from the list + CImageData* pRemovedImageData = iImageDataList[aIndex]; + iImageDataList.Remove(aIndex); + delete pRemovedImageData; + + iCritical.Signal(); + + SetChanged(fileName); + + iCallback->ImageListChanged(aIndex, EFalse); + }